[med-svn] [praat] 01/07: New upstream version 6.0.31

Rafael Laboissiere rafael at debian.org
Sat Aug 26 07:15:15 UTC 2017


This is an automated email from the git hooks/post-receive script.

rafael pushed a commit to branch master
in repository praat.

commit 233a559513a5d2dc5a0208d7a79fbc984071410b
Author: Rafael Laboissiere <rafael at debian.org>
Date:   Thu Aug 24 10:15:36 2017 -0300

    New upstream version 6.0.31
---
 EEG/EEG.cpp                                   |   20 +-
 EEG/ERP.cpp                                   |    2 +-
 EEG/ERPTier.cpp                               |    6 +-
 EEG/ERPWindow.cpp                             |    8 +-
 EEG/Makefile                                  |    6 +-
 FFNet/FFNet.cpp                               |   14 +-
 FFNet/FFNet.h                                 |    2 +-
 FFNet/FFNet_PatternList_ActivationList.cpp    |    6 +-
 FFNet/FFNet_PatternList_Categories.cpp        |    4 +-
 FFNet/Makefile                                |    6 +-
 LPC/Cepstrogram.cpp                           |    2 +-
 LPC/Cepstrum.cpp                              |   14 +-
 LPC/Cepstrumc.cpp                             |   28 +-
 LPC/Formant_extensions.cpp                    |    8 +-
 LPC/LPC.cpp                                   |    8 +-
 LPC/LPC_and_LineSpectralFrequencies.cpp       |    4 +-
 LPC/LPC_and_Tube.cpp                          |    6 +-
 LPC/LineSpectralFrequencies.cpp               |   10 +-
 LPC/Makefile                                  |    6 +-
 LPC/Sound_and_LPC.cpp                         |    2 +-
 LPC/Tube_def.h                                |    4 +-
 artsynth/Artword.cpp                          |   66 +-
 artsynth/Artword.h                            |   10 +-
 artsynth/ArtwordEditor.cpp                    |   11 +-
 artsynth/Artword_def.h                        |    6 +-
 artsynth/Makefile                             |    6 +-
 artsynth/Speaker.cpp                          |    2 +-
 artsynth/Speaker.h                            |    4 +-
 artsynth/Speaker_def.h                        |    2 +-
 artsynth/Speaker_to_Delta.cpp                 |   36 +-
 artsynth/praat_Artsynth.cpp                   |    2 +-
 contrib/ola/FeatureWeights.cpp                |   24 +-
 contrib/ola/KNN.cpp                           |   24 +-
 contrib/ola/KNN_prune.cpp                     |   18 +-
 contrib/ola/Makefile                          |    4 +-
 contrib/ola/Pattern_to_Categories_cluster.cpp |    6 +-
 dwsys/Collection_extensions.cpp               |    4 +-
 dwsys/Command.cpp                             |    2 +-
 dwsys/Command.h                               |    2 +-
 dwsys/Eigen.cpp                               |   10 +-
 dwsys/FileInMemory.cpp                        |    8 +-
 dwsys/Makefile                                |    5 +-
 dwsys/NUM2.cpp                                |  176 ++--
 dwsys/NUM2.h                                  |    6 +-
 dwsys/NUMcomplex.cpp                          |   10 +-
 dwsys/NUMfft_d.cpp                            |    2 -
 dwsys/NUMhuber.cpp                            |    2 +-
 dwsys/NUMlapack.cpp                           |    3 +-
 dwsys/NUMmathlib.cpp                          |  334 +++---
 dwsys/NUMstring.cpp                           |   10 +-
 dwsys/Permutation.cpp                         |    4 +-
 dwsys/SVD.cpp                                 |    2 +-
 dwtest/incompleteGamma.csv                    |   82 ++
 dwtest/test_detectSilences.praat              |   50 +
 dwtest/test_gammatonefilter.praat             |    8 +-
 dwtools/CC.cpp                                |   16 +-
 dwtools/CCA.cpp                               |    4 +-
 dwtools/CCA_and_Correlation.cpp               |    6 +-
 dwtools/CCs_to_DTW.cpp                        |    8 +-
 dwtools/Categories.cpp                        |    6 +-
 dwtools/Confusion.cpp                         |    2 +-
 dwtools/DTW.cpp                               |   27 +-
 dwtools/DTW_and_TextGrid.cpp                  |   10 +-
 dwtools/DataModeler.cpp                       |  176 ++--
 dwtools/Discriminant.cpp                      |   12 +-
 dwtools/EditDistanceTable.cpp                 |    2 +-
 dwtools/FilterBank.cpp                        |   59 +-
 dwtools/GaussianMixture.cpp                   |   24 +-
 dwtools/HMM.cpp                               |   36 +-
 dwtools/HMM_def.h                             |   12 +-
 dwtools/Intensity_extensions.cpp              |   66 +-
 dwtools/KlattGrid.cpp                         |   94 +-
 dwtools/KlattTable.cpp                        |    2 +-
 dwtools/Ltas_extensions.cpp                   |   12 +-
 dwtools/MDS.cpp                               |   24 +-
 dwtools/Makefile                              |    8 +-
 dwtools/Matrix_extensions.cpp                 |  127 +--
 dwtools/Minimizers.cpp                        |   14 +-
 dwtools/Minimizers.h                          |    4 +-
 dwtools/PCA.cpp                               |   29 +-
 dwtools/Pitch_extensions.cpp                  |   28 +-
 dwtools/Polygon_extensions.cpp                |    6 +-
 dwtools/Polynomial.cpp                        |  144 +--
 dwtools/Polynomial.h                          |    4 +-
 dwtools/SPINET.cpp                            |    2 +-
 dwtools/SSCP.cpp                              |   48 +-
 dwtools/SSCP.h                                |    2 +-
 dwtools/Sound_and_Spectrogram_extensions.cpp  |   18 +-
 dwtools/Sound_extensions.cpp                  |  107 +-
 dwtools/Spectrogram_extensions.cpp            |   90 +-
 dwtools/Spectrum_extensions.cpp               |    4 +-
 dwtools/SpeechSynthesizer.cpp                 |    2 +-
 dwtools/SpeechSynthesizer_and_TextGrid.cpp    |   20 +-
 dwtools/TableOfReal_extensions.cpp            |   60 +-
 dwtools/Table_extensions.cpp                  |  191 ++--
 dwtools/Table_extensions.h                    |    6 +-
 dwtools/TextGrid_and_PitchTier.cpp            |  337 ++++++
 dwtools/TextGrid_and_PitchTier.h              |   32 +
 dwtools/TextGrid_extensions.cpp               |   32 +-
 dwtools/VowelEditor.cpp                       |   57 +-
 dwtools/manual_dwtools.cpp                    |  137 ++-
 dwtools/praat_David_init.cpp                  |   97 +-
 dwtools/praat_KlattGrid_init.cpp              |    6 +-
 external/espeak/Makefile                      |    4 +-
 external/gsl/Makefile                         |    3 +-
 fon/AmplitudeTier.cpp                         |  167 +--
 fon/AmplitudeTier.h                           |    6 +-
 fon/AnyTier.cpp                               |    2 +-
 fon/AnyTier.h                                 |    4 +-
 fon/Cochleagram.cpp                           |   24 +-
 fon/Cochleagram.h                             |    8 +-
 fon/Distributions_and_Transition.cpp          |   13 +-
 fon/Excitation.cpp                            |    4 +-
 fon/ExperimentMFC.cpp                         |   10 +-
 fon/ExperimentMFC_def.h                       |    8 +-
 fon/Formant.cpp                               |   44 +-
 fon/FormantGrid.cpp                           |   16 +-
 fon/FormantTier.cpp                           |   34 +-
 fon/FormantTier_def.h                         |    4 +-
 fon/Formant_def.h                             |    4 +-
 fon/Function.cpp                              |    8 +-
 fon/FunctionEditor.cpp                        |    8 +-
 fon/Harmonicity.cpp                           |   40 +-
 fon/Intensity.cpp                             |    2 +-
 fon/LongSound.cpp                             |   18 +-
 fon/LongSound.h                               |    2 +-
 fon/Ltas.cpp                                  |   42 +-
 fon/Makefile                                  |    6 +-
 fon/ManipulationEditor.cpp                    |   26 +-
 fon/Manipulation_def.h                        |    4 +-
 fon/Matrix.cpp                                |  229 +++--
 fon/Matrix.h                                  |   32 +-
 fon/Matrix_and_Pitch.cpp                      |   51 +-
 fon/Matrix_and_PointProcess.cpp               |   18 +-
 fon/Matrix_and_PointProcess.h                 |   22 +-
 fon/Movie.cpp                                 |    8 +-
 fon/Photo.cpp                                 |    6 +-
 fon/Photo.h                                   |    4 +-
 fon/Pitch.cpp                                 |   76 +-
 fon/PitchEditor.cpp                           |   33 +-
 fon/PitchTier.cpp                             |    4 +-
 fon/PitchTier_to_PointProcess.cpp             |   10 +-
 fon/PitchTier_to_Sound.cpp                    |    6 +-
 fon/Pitch_AnyTier_to_PitchTier.cpp            |    4 +-
 fon/Pitch_Intensity.cpp                       |   12 +-
 fon/Pitch_def.h                               |    6 +-
 fon/Pitch_to_PointProcess.cpp                 |   30 +-
 fon/PointEditor.cpp                           |    4 +-
 fon/PointProcess.cpp                          |  152 +--
 fon/PointProcess.h                            |   22 +-
 fon/PointProcess_and_Sound.cpp                |   12 +-
 fon/Polygon.cpp                               |   16 +-
 fon/Praat_tests.cpp                           |  165 ++-
 fon/Praat_tests_enums.h                       |   17 +-
 fon/RealTier.cpp                              |   68 +-
 fon/RealTier.h                                |    4 +-
 fon/RealTierEditor.cpp                        |   30 +-
 fon/RealTierEditor.h                          |    6 +-
 fon/RunnerMFC.cpp                             |    4 +-
 fon/Sampled.cpp                               |  196 ++--
 fon/Sampled.h                                 |   15 +-
 fon/SampledXY.cpp                             |    8 +-
 fon/SampledXY.h                               |   17 +-
 fon/Sampled_def.h                             |    2 +-
 fon/Sound.cpp                                 |  226 ++--
 fon/Sound.h                                   |    4 +-
 fon/SoundEditor.cpp                           |   36 +-
 fon/SoundRecorder.cpp                         |   14 +-
 fon/Sound_and_Spectrum.cpp                    |   18 +-
 fon/Sound_audio.cpp                           |    2 +-
 fon/Sound_files.cpp                           |   50 +-
 fon/Sound_to_Cochleagram.cpp                  |   22 +-
 fon/Sound_to_Intensity.cpp                    |   12 +-
 fon/Sound_to_Pitch.cpp                        |  161 +--
 fon/Spectrogram.cpp                           |   16 +-
 fon/SpectrogramEditor.cpp                     |    2 +-
 fon/Spectrum.cpp                              |   42 +-
 fon/SpectrumEditor.cpp                        |    4 +-
 fon/TextGrid.cpp                              |   34 +-
 fon/TextGridEditor.cpp                        |   22 +-
 fon/TextGrid_Sound.cpp                        |    4 +-
 fon/TimeSoundAnalysisEditor.cpp               |   38 +-
 fon/TimeSoundEditor.cpp                       |   24 +-
 fon/Transition.cpp                            |    6 +-
 fon/Vector.cpp                                |   70 +-
 fon/VoiceAnalysis.cpp                         |  127 +--
 fon/WordList.cpp                              |    6 +-
 fon/manual_Script.cpp                         |   12 +-
 fon/manual_tutorials.cpp                      |    3 +
 fon/praat_Fon.cpp                             |   10 +-
 fon/praat_Matrix.cpp                          |    4 +-
 fon/praat_Sound.cpp                           |    6 +-
 fon/praat_Tiers.cpp                           |    3 +-
 gram/Makefile                                 |    6 +-
 gram/Network.cpp                              |   10 +-
 gram/OTGrammar.cpp                            |   39 +-
 gram/OTGrammar_def.h                          |    6 +-
 gram/OTMulti.cpp                              |   22 +-
 gram/OTMultiEditor.cpp                        |    2 +-
 gram/OTMulti_def.h                            |    6 +-
 gram/RBM_def.h                                |    4 +-
 main/Makefile                                 |    4 +-
 makefiles/makefile.defs.linux.nogui           |    4 +-
 num/Makefile                                  |    4 +-
 num/NUM.cpp                                   |   62 +-
 num/NUM.h                                     |  612 -----------
 num/NUMarrays.cpp                             |  130 +--
 num/NUMear.cpp                                |   48 +-
 num/NUMlinprog.cpp                            |   14 +-
 num/NUMrandom.cpp                             |    4 +-
 num/NUMsort.cpp                               |    5 +-
 stat/Distributions.cpp                        |   31 +-
 stat/LogisticRegression.cpp                   |   78 +-
 stat/LogisticRegression.h                     |    6 +-
 stat/Makefile                                 |    6 +-
 stat/Regression.cpp                           |    2 +-
 stat/Table.cpp                                |  713 ++++++-------
 stat/Table.h                                  |  108 +-
 stat/TableEditor.cpp                          |    4 +-
 stat/TableOfReal.cpp                          |  464 ++++-----
 stat/TableOfReal.h                            |   52 +-
 stat/Table_def.h                              |    2 +-
 stat/praat_Stat.cpp                           |    2 +-
 sys/ButtonEditor.cpp                          |    4 +-
 sys/Collection.cpp                            |   28 +-
 sys/Data.cpp                                  |   13 +-
 sys/Data.h                                    |   89 +-
 sys/DataEditor.cpp                            |   67 +-
 sys/DemoEditor.cpp                            |    4 +-
 sys/Editor.cpp                                |    4 +-
 sys/EditorM.h                                 |    6 +-
 sys/Formula.cpp                               |  971 +++++++++--------
 sys/Formula.h                                 |    2 +-
 sys/Graphics.h                                |    2 +-
 sys/GraphicsScreen.cpp                        |   28 +-
 sys/Graphics_colour.cpp                       |    2 +-
 sys/Graphics_grey.cpp                         |  132 ++-
 sys/Graphics_image.cpp                        |    6 +-
 sys/Graphics_record.cpp                       |   60 +-
 sys/Graphics_text.cpp                         |    2 +-
 sys/GuiFileSelect.cpp                         |   18 +-
 sys/GuiList.cpp                               |    1 -
 sys/GuiMenu.cpp                               |    2 +-
 sys/GuiMenuItem.cpp                           |    4 +-
 sys/GuiP.h                                    |    2 -
 sys/GuiScrollBar.cpp                          |   40 +-
 sys/HyperPage.cpp                             |    2 +-
 sys/Interpreter.cpp                           |   98 +-
 sys/Interpreter.h                             |    2 +-
 sys/Makefile                                  |    8 +-
 sys/ManPages.cpp                              |   26 +-
 sys/ManPagesM.h                               |   50 +-
 sys/Manual.cpp                                |    8 +-
 sys/MelderGui.cpp                             |    2 +-
 sys/Preferences.cpp                           |   14 +-
 sys/Preferences.h                             |    3 +-
 sys/Printer.cpp                               |    4 +-
 sys/ScriptEditor.cpp                          |   12 +-
 sys/Simple_def.h                              |    4 +-
 sys/Tensor.h                                  |   32 -
 sys/TextEditor.cpp                            |    2 +-
 sys/Thing.cpp                                 |    8 +-
 sys/Thing.h                                   |   42 +-
 sys/Ui.cpp                                    |   10 +-
 sys/UiFile.cpp                                |    4 +-
 sys/abcio.cpp                                 |  345 ++++---
 sys/abcio.h                                   |  149 ++-
 sys/complex.h                                 |    6 +-
 sys/enums_getValue.h                          |    6 +-
 sys/melder.cpp                                |    2 +-
 sys/melder.h                                  | 1371 ++++++++++++++++++++++---
 sys/melder_alloc.cpp                          |    6 +-
 sys/melder_atof.cpp                           |    7 +-
 sys/melder_audio.cpp                          |    5 +-
 sys/melder_audiofiles.cpp                     |  200 ++--
 sys/melder_console.cpp                        |    3 +-
 sys/melder_debug.cpp                          |   22 +-
 sys/melder_files.cpp                          |   25 +-
 sys/melder_ftoa.cpp                           |  108 +-
 sys/melder_info.cpp                           |    3 +-
 sys/melder_readtext.cpp                       |   11 +-
 sys/melder_strings.cpp                        |    3 +-
 sys/melder_sysenv.cpp                         |    3 +-
 sys/melder_textencoding.cpp                   |    8 +-
 sys/melder_token.cpp                          |    1 -
 sys/melder_writetext.cpp                      |   76 +-
 sys/motifEmulator.cpp                         |    8 +-
 sys/oo.h                                      |  258 ++---
 sys/oo_DESCRIPTION.h                          |  222 ++--
 sys/oo_READ_BINARY.h                          |    6 +-
 sys/oo_READ_TEXT.h                            |    6 +-
 sys/oo_WRITE_BINARY.h                         |    6 +-
 sys/oo_WRITE_TEXT.h                           |    6 +-
 sys/praat.cpp                                 |   71 +-
 sys/praat.h                                   |    6 +-
 sys/praat_actions.cpp                         |    2 +-
 sys/praat_menuCommands.cpp                    |    4 +-
 sys/praat_objectMenus.cpp                     |   16 +-
 sys/praat_picture.cpp                         |   20 +-
 sys/praat_script.cpp                          |   18 +-
 sys/praat_statistics.cpp                      |    5 +-
 sys/praat_version.h                           |    8 +-
 sys/sendpraat.c                               |    6 +-
 sys/tensor.cpp                                | 1251 ++++++++++++++++++++++
 sys/tensor.h                                  |  142 +++
 test/num/fisherQ.praat                        |    6 +-
 test/num/inner.praat                          |   22 +
 test/num/mean.R                               |   44 +
 test/num/mean.praat                           |  157 +++
 test/num/stdev.praat                          |   20 +
 test/num/sum.praat                            |   22 +
 test/script/arrays.praat                      |   67 --
 test/script/tensor.praat                      |  160 +++
 test/script/undefined.praat                   |   61 ++
 test/script/vectors.praat                     |    8 -
 315 files changed, 9341 insertions(+), 6010 deletions(-)

diff --git a/EEG/EEG.cpp b/EEG/EEG.cpp
index 5f0f8e3..7d14e0e 100644
--- a/EEG/EEG.cpp
+++ b/EEG/EEG.cpp
@@ -142,7 +142,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
 			trace (U"Channel <<", channelNames [ichannel], U">>");
 		}
 		bool hasLetters = str32equ (channelNames [numberOfChannels], U"EDF Annotations");
-		double samplingFrequency = NUMundefined;
+		double samplingFrequency = undefined;
 		for (long channel = 1; channel <= numberOfChannels; channel ++) {
 			fread (buffer, 1, 80, f); buffer [80] = '\0';   // transducer type
 		}
@@ -176,7 +176,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
 		for (long channel = 1; channel <= numberOfChannels; channel ++) {
 			fread (buffer, 1, 8, f); buffer [8] = '\0';   // number of samples in each data record
 			long numberOfSamplesInThisDataRecord = atol (buffer);
-			if (samplingFrequency == NUMundefined) {
+			if (isundef (samplingFrequency)) {
 				numberOfSamplesPerDataRecord = numberOfSamplesInThisDataRecord;
 				samplingFrequency = numberOfSamplesInThisDataRecord / durationOfDataRecord;
 			}
@@ -193,7 +193,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
 		his numberOfChannels = numberOfChannels;
 		autoSound me = Sound_createSimple (numberOfChannels, duration, samplingFrequency);
 		Melder_assert (my nx == numberOfSamplesPerDataRecord * numberOfDataRecords);
-		autoNUMvector <unsigned char> dataBuffer (0L, 3 * numberOfSamplesPerDataRecord - 1);
+		autoNUMvector <unsigned char> dataBuffer ((integer) 0, 3 * numberOfSamplesPerDataRecord - 1);
 		for (long record = 1; record <= numberOfDataRecords; record ++) {
 			for (long channel = 1; channel <= numberOfChannels; channel ++) {
 				double factor = channel == numberOfChannels ? 1.0 : physicalMinimum [channel] / digitalMinimum [channel];
@@ -234,7 +234,7 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
 		if (hasLetters) {
 			thee = TextGrid_create (0, duration, U"Mark Trigger", U"Mark Trigger");
 			autoMelderString letters;
-			double time = NUMundefined;
+			double time = undefined;
 			for (long i = 1; i <= my nx; i ++) {
 				unsigned long value = (long) my z [numberOfChannels] [i];
 				for (int byte = 1; byte <= numberOfStatusBits / 8; byte ++) {
@@ -244,18 +244,18 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
 						MelderString_appendCharacter (& letters, kar);
 					} else if (letters. string [0] != U'\0') {
 						if (letters. string [0] == U'+') {
-							if (NUMdefined (time)) {
+							if (isdefined (time)) {
 								try {
 									TextGrid_insertPoint (thee.get(), 1, time, U"");
 								} catch (MelderError) {
 									Melder_throw (U"Did not insert empty mark (", letters. string, U") on Mark tier.");
 								}
-								time = NUMundefined;   // defensive
+								time = undefined;   // defensive
 							}
 							time = Melder_atof (& letters. string [1]);
 							MelderString_empty (& letters);
 						} else {
-							if (! NUMdefined (time)) {
+							if (isundef (time)) {
 								Melder_throw (U"Undefined time for label at sample ", i, U".");
 							}
 							try {
@@ -272,15 +272,15 @@ autoEEG EEG_readFromBdfFile (MelderFile file) {
 							} catch (MelderError) {
 								Melder_throw (U"Did not insert mark (", letters. string, U") on Trigger tier.");
 							}
-							time = NUMundefined;   // crucial
+							time = undefined;   // crucial
 							MelderString_empty (& letters);
 						}
 					}
 				}
 			}
-			if (NUMdefined (time)) {
+			if (isdefined (time)) {
 				TextGrid_insertPoint (thee.get(), 1, time, U"");
-				time = NUMundefined;   // defensive
+				time = undefined;   // defensive
 			}
 		} else {
 			thee = TextGrid_create (0, duration,
diff --git a/EEG/ERP.cpp b/EEG/ERP.cpp
index ee4caae..eda8716 100644
--- a/EEG/ERP.cpp
+++ b/EEG/ERP.cpp
@@ -62,7 +62,7 @@ void ERP_drawChannel_number (ERP me, Graphics graphics, long channelNumber, doub
 	/*
 	 * Domain expressed in sample numbers.
 	 */
-	long ixmin, ixmax;
+	integer ixmin, ixmax;
 	Matrix_getWindowSamplesX (me, tmin, tmax, & ixmin, & ixmax);
 	/*
 	 * Automatic vertical range.
diff --git a/EEG/ERPTier.cpp b/EEG/ERPTier.cpp
index 33e0b86..1a09e43 100644
--- a/EEG/ERPTier.cpp
+++ b/EEG/ERPTier.cpp
@@ -1,6 +1,6 @@
 /* ERPTier.cpp
  *
- * Copyright (C) 2011-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 2011-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,8 +55,8 @@ long ERPTier_getChannelNumber (ERPTier me, const char32 *channelName) {
 }
 
 double ERPTier_getMean (ERPTier me, long pointNumber, long channelNumber, double tmin, double tmax) {
-	if (pointNumber < 1 || pointNumber > my points.size) return NUMundefined;
-	if (channelNumber < 1 || channelNumber > my numberOfChannels) return NUMundefined;
+	if (pointNumber < 1 || pointNumber > my points.size) return undefined;
+	if (channelNumber < 1 || channelNumber > my numberOfChannels) return undefined;
 	ERPPoint point = my points.at [pointNumber];
 	return Vector_getMean (point -> erp.get(), tmin, tmax, channelNumber);
 }
diff --git a/EEG/ERPWindow.cpp b/EEG/ERPWindow.cpp
index 77aa151..54259f5 100644
--- a/EEG/ERPWindow.cpp
+++ b/EEG/ERPWindow.cpp
@@ -201,7 +201,7 @@ void ERP_drawScalp (ERP me, Graphics graphics, double tmin, double tmax, double
 		for (long icol = 1; icol <= n; icol ++) {
 			double x = -1.0 + (icol - 1) * d;
 			if (x * x + y * y <= 1.0) {
-				double value = NUMundefined, sum = 0.0, weight = 0.0;
+				double value = undefined, sum = 0.0, weight = 0.0;
 				for (long ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
 					double dx = x - biosemiLocationData [ichan]. topX;
 					double dy = y - biosemiLocationData [ichan]. topY;
@@ -214,7 +214,7 @@ void ERP_drawScalp (ERP me, Graphics graphics, double tmin, double tmax, double
 					sum += mean [ichan] / distance;
 					weight += 1.0 / distance;
 				}
-				if (value == NUMundefined)
+				if (isundef (value))
 					value = ( sum == 0.0 ? 0.0 : sum / weight );
 				image [irow] [icol] = value;
 			}
@@ -304,7 +304,7 @@ void structERPWindow :: v_drawSelectionViewer () {
 		for (long icol = 1; icol <= n; icol ++) {
 			double x = -1.0 + (icol - 1) * d;
 			if (x * x + y * y <= 1.0) {
-				double value = NUMundefined, sum = 0.0, weight = 0.0;
+				double value = undefined, sum = 0.0, weight = 0.0;
 				for (long ichan = 1; ichan <= numberOfDrawableChannels; ichan ++) {
 					double dx = x - biosemiLocationData [ichan]. topX;
 					double dy = y - biosemiLocationData [ichan]. topY;
@@ -317,7 +317,7 @@ void structERPWindow :: v_drawSelectionViewer () {
 					sum += means [ichan] / distance;
 					weight += 1.0 / distance;
 				}
-				if (value == NUMundefined)
+				if (isundef (value))
 					value = ( sum == 0.0 ? 0.0 : sum / weight );
 				image [irow] [icol] = value;
 			}
diff --git a/EEG/Makefile b/EEG/Makefile
index e1441db..4437621 100644
--- a/EEG/Makefile
+++ b/EEG/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "EEG"
-# Paul Boersma, 24 August 2013
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../sys -I ../dwsys -I ../stat -I ../dwtools -I ../fon
+CPPFLAGS = -I ../kar -I ../sys -I ../dwsys -I ../stat -I ../dwtools -I ../fon
 
 OBJECTS = EEG.o EEGWindow.o ERPTier.o ERP.o ERPWindow.o \
    praat_EEG.o manual_EEG.o
@@ -22,4 +22,4 @@ libEEG.a: $(OBJECTS)
 	$(AR) cq libEEG.a $(OBJECTS)
 	$(RANLIB) libEEG.a
 
-$(OBJECTS): *.h ../num/NUM.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
+$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
diff --git a/FFNet/FFNet.cpp b/FFNet/FFNet.cpp
index 096dca9..8dc22bc 100644
--- a/FFNet/FFNet.cpp
+++ b/FFNet/FFNet.cpp
@@ -86,12 +86,12 @@ static void FFNet_checkLayerNumber (FFNet me, long layer) {
 	}
 }
 
-autostring32 FFNet_createNameFromTopology (FFNet me) {
+char32 * FFNet_createNameFromTopology (FFNet me) {
 	autoMelderString name;
-	MelderString_copy (&name, my nUnitsInLayer[0]);
-	for (long i = 1; i <= my nLayers; i++) {
-		MelderString_appendCharacter (&name, U'-');
-		MelderString_append (&name, my nUnitsInLayer[i]);
+	MelderString_copy (& name, my nUnitsInLayer [0]);
+	for (long i = 1; i <= my nLayers; i ++) {
+		MelderString_appendCharacter (& name, U'-');
+		MelderString_append (& name, my nUnitsInLayer [i]);
 	}
 	autostring32 naam = Melder_dup (name.string);
 	return naam.transfer();
@@ -288,7 +288,7 @@ double FFNet_getBias (FFNet me, long layer, long unit) {
 		long bias_unit = my wLast[node];
 		return my w[bias_unit];
 	} catch (MelderError) {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
@@ -582,7 +582,7 @@ long FFNet_getNumberOfUnitsInLayer (FFNet me, int layer) {
 }
 
 double FFNet_getMinimum (FFNet me) {
-	return my minimizer ? Minimizer_getMinimum (my minimizer.get()) : NUMundefined;
+	return ( my minimizer ? Minimizer_getMinimum (my minimizer.get()) : undefined );
 }
 
 void FFNet_drawTopology (FFNet me, Graphics g) {
diff --git a/FFNet/FFNet.h b/FFNet/FFNet.h
index 43f37c2..7be484c 100644
--- a/FFNet/FFNet.h
+++ b/FFNet/FFNet.h
@@ -122,7 +122,7 @@ void FFNet_init (FFNet me, long numberOfInputs, long nodesInLayer1, long nodesIn
 autoFFNet FFNet_create (long numberOfInputs, long numberInLayer1, long numberInLayer2,
 	long numberOfOutputs, bool outputsAreLinear);
 
-autostring32 FFNet_createNameFromTopology (FFNet me);
+char32 * FFNet_createNameFromTopology (FFNet me);
 /* Create names as <inputs>-<outputs>, <inputs>-<hidden>-<outputs>,
 	<inputs>-<hidden1>-<hidden2>-<outputs> for 1, 2 or 3 layer networks.
 */
diff --git a/FFNet/FFNet_PatternList_ActivationList.cpp b/FFNet/FFNet_PatternList_ActivationList.cpp
index 71c943e..6a10996 100644
--- a/FFNet/FFNet_PatternList_ActivationList.cpp
+++ b/FFNet/FFNet_PatternList_ActivationList.cpp
@@ -1,6 +1,6 @@
 /* FFNet_PatternList_ActivationList.cpp
  *
- * Copyright (C) 1994-2011,2015-2016 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 1994-2011,2015-2016 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -163,13 +163,13 @@ double FFNet_PatternList_ActivationList_getCosts_total (FFNet me, PatternList p,
 		}
 		return cost;
 	} catch (MelderError) {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
 double FFNet_PatternList_ActivationList_getCosts_average (FFNet me, PatternList p, ActivationList a, int costFunctionType) {
 	double costs = FFNet_PatternList_ActivationList_getCosts_total (me, p, a, costFunctionType);
-	return costs == NUMundefined ? NUMundefined : costs / p -> ny;
+	return ( isundef (costs) ? undefined : costs / p -> ny );
 }
 
 autoActivationList FFNet_PatternList_to_ActivationList (FFNet me, PatternList p, long layer) {
diff --git a/FFNet/FFNet_PatternList_Categories.cpp b/FFNet/FFNet_PatternList_Categories.cpp
index a36bde0..618d224 100644
--- a/FFNet/FFNet_PatternList_Categories.cpp
+++ b/FFNet/FFNet_PatternList_Categories.cpp
@@ -45,13 +45,13 @@ double FFNet_PatternList_Categories_getCosts_total (FFNet me, PatternList p, Cat
 		autoActivationList activation = FFNet_Categories_to_ActivationList (me, c);
 		return FFNet_PatternList_ActivationList_getCosts_total (me, p, activation.get(), costFunctionType);
 	} catch (MelderError) {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
 double FFNet_PatternList_Categories_getCosts_average (FFNet me, PatternList p, Categories c, int costFunctionType) {
 	double costs = FFNet_PatternList_Categories_getCosts_total (me, p, c, costFunctionType);
-	return costs == NUMundefined ? NUMundefined : costs / p -> ny;
+	return ( isundef (costs) ? undefined : costs / p -> ny );
 }
 
 void FFNet_PatternList_Categories_learnSD (FFNet me, PatternList p, Categories c, long maxNumOfEpochs, double tolerance, double learningRate, double momentum, int costFunctionType) {
diff --git a/FFNet/Makefile b/FFNet/Makefile
index 515adf9..c6d52d8 100644
--- a/FFNet/Makefile
+++ b/FFNet/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "FFNet"
-# David Weenink, 2 June 2017
+# David Weenink and Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../dwtools -I ../gram -I ../fon -I ../sys -I ../dwsys -I ../stat
+CPPFLAGS = -I ../kar -I ../sys -I ../dwtools -I ../fon -I ../dwsys -I ../stat -I ../gram
 
 OBJECTS = FFNet.o \
 	FFNet_Eigen.o FFNet_Matrix.o FFNet_PatternList.o \
@@ -25,4 +25,4 @@ libFFNet.a: $(OBJECTS)
 	$(AR) cq libFFNet.a $(OBJECTS)
 	$(RANLIB) libFFNet.a
 
-$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../dwtools/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h
+$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../dwtools/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h ../gram/*.h
diff --git a/LPC/Cepstrogram.cpp b/LPC/Cepstrogram.cpp
index 9117d60..0eba4ae 100644
--- a/LPC/Cepstrogram.cpp
+++ b/LPC/Cepstrogram.cpp
@@ -63,7 +63,7 @@ autoPowerCepstrogram PowerCepstrogram_create (double tmin, double tmax, long nt,
 void PowerCepstrogram_paint (PowerCepstrogram me, Graphics g, double tmin, double tmax, double qmin, double qmax, double dBmaximum, int autoscaling, double dynamicRangedB, double dynamicCompression, int garnish) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 	if (qmax <= qmin) { qmin = my ymin; qmax = my ymax; }
-	long itmin, itmax, ifmin, ifmax;
+	integer itmin, itmax, ifmin, ifmax;
 	if (! Matrix_getWindowSamplesX (me, tmin - 0.49999 * my dx, tmax + 0.49999 * my dx, & itmin, & itmax) ||
 		 ! Matrix_getWindowSamplesY (me, qmin - 0.49999 * my dy, qmax + 0.49999 * my dy, & ifmin, & ifmax)) {
 		return;
diff --git a/LPC/Cepstrum.cpp b/LPC/Cepstrum.cpp
index 109b5d3..e74d6de 100644
--- a/LPC/Cepstrum.cpp
+++ b/LPC/Cepstrum.cpp
@@ -38,7 +38,7 @@ double structCepstrum :: v_getValueAtSample (long isamp, long which, int units)
 		// dB's
 		return 20.0 * log10 (fabs(z[1][isamp]) + 1e-30);
 	}
-	return NUMundefined;
+	return undefined;
 }
 
 double structPowerCepstrum :: v_getValueAtSample (long isamp, long which, int units) {
@@ -49,7 +49,7 @@ double structPowerCepstrum :: v_getValueAtSample (long isamp, long which, int un
 		// dB's
 		return 10.0 * log10 (z[1][isamp] + 1e-30); // always positive
 	}
-	return NUMundefined;
+	return undefined;
 }
 
 autoCepstrum Cepstrum_create (double qmax, long nq) {
@@ -97,7 +97,7 @@ static void _Cepstrum_draw (Cepstrum me, Graphics g, double qmin, double qmax, d
 		qmin = my xmin; qmax = my xmax;
 	}
 
-	long imin, imax;
+	integer imin, imax;
 	if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
 		return;
 	}
@@ -149,7 +149,7 @@ void PowerCepstrum_drawTiltLine (PowerCepstrum me, Graphics g, double qmin, doub
 	}
 
 	if (dBminimum >= dBmaximum) { // autoscaling
-		long imin, imax;
+		integer imin, imax;
 		if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
 			return;
 		}
@@ -222,7 +222,7 @@ void PowerCepstrum_fitTiltLine (PowerCepstrum me, double qmin, double qmax, doub
 			qmin = my xmin; qmax = my xmax;
 		}
 
-		long imin, imax;
+		integer imin, imax;
 		if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
 			return;
 		}
@@ -386,10 +386,10 @@ static void Cepstrum_getZ (Cepstrum me, long imin, long imax, double peakdB, dou
 #endif
 
 double PowerCepstrum_getRNR (PowerCepstrum me, double pitchFloor, double pitchCeiling, double f0fractionalWidth) {
-	double rnr = NUMundefined;
+	double rnr = undefined;
 	double qmin = 1.0 / pitchCeiling, qmax = 1.0 / pitchFloor, peakdB, qpeak;
 	PowerCepstrum_getMaximumAndQuefrency (me, pitchFloor, pitchCeiling, 2, &peakdB, &qpeak);
-	long imin, imax;
+	integer imin, imax;
 	if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
 		return rnr;
 	}
diff --git a/LPC/Cepstrumc.cpp b/LPC/Cepstrumc.cpp
index 700e118..291e26d 100644
--- a/LPC/Cepstrumc.cpp
+++ b/LPC/Cepstrumc.cpp
@@ -107,7 +107,7 @@ static void regression (Cepstrumc me, long frame, double r[], long nr) {
 
 autoDTW Cepstrumc_to_DTW (Cepstrumc me, Cepstrumc thee, double wc, double wle, double wr, double wer, double dtr, int matchStart, int matchEnd, int constraint) {
 	try {
-		long nr = (long) floor (dtr / my dx);
+		integer nr = (integer) floor (dtr / my dx);
 
 		if (my maxnCoefficients != thy maxnCoefficients) {
 			Melder_throw (U"Cepstrumc orders must be equal.");
@@ -122,21 +122,21 @@ autoDTW Cepstrumc_to_DTW (Cepstrumc me, Cepstrumc thee, double wc, double wle, d
 			Melder_casual (U"Number of frames used for regression coefficients ", nr);
 		}
 		autoDTW him = DTW_create (my xmin, my xmax, my nx, my dx, my x1, thy xmin, thy xmax, thy nx, thy dx, thy x1);
-		autoNUMvector<double> ri (0L, my maxnCoefficients);
-		autoNUMvector<double> rj (0L, my maxnCoefficients);
+		autoNUMvector <double> ri ((integer) 0, my maxnCoefficients);
+		autoNUMvector <double> rj ((integer) 0, my maxnCoefficients);
 
 		// Calculate distance matrix
 
 		autoMelderProgress progress (U"");
-		for (long i = 1; i <= my nx; i++) {
-			Cepstrumc_Frame fi = & my frame[i];
+		for (long i = 1; i <= my nx; i ++) {
+			Cepstrumc_Frame fi = & my frame [i];
 			regression (me, i, ri.peek(), nr);
-			for (long j = 1; j <= thy nx; j++) {
-				Cepstrumc_Frame fj = & thy frame[j];
-				double d, dist = 0, distr = 0;
+			for (long j = 1; j <= thy nx; j ++) {
+				Cepstrumc_Frame fj = & thy frame [j];
+				real80 d, dist = 0, distr = 0;
 				if (wc != 0) { /* cepstral distance */
-					for (long k = 1; k <= fj -> nCoefficients; k++) {
-						d = fi -> c[k] - fj -> c[k];
+					for (long k = 1; k <= fj -> nCoefficients; k ++) {
+						d = fi -> c [k] - fj -> c [k];
 						dist += d * d;
 					}
 					dist *= wc;
@@ -144,15 +144,15 @@ autoDTW Cepstrumc_to_DTW (Cepstrumc me, Cepstrumc thee, double wc, double wle, d
 				// log energy distance
 				d = fi -> c[0] - fj -> c[0];
 				dist += wle * d * d;
-				if (wr != 0) { // regression distance
+				if (wr != 0) {   // regression distance
 					regression (thee, j, rj.peek(), nr);
-					for (long k = 1; k <= fj -> nCoefficients; k++) {
+					for (long k = 1; k <= fj -> nCoefficients; k ++) {
 						d = ri[k] - rj[k];
 						distr += d * d;
 					}
 					dist += wr * distr;
 				}
-				if (wer != 0) { // regression on c[0]: log(energy)
+				if (wer != 0) {   // regression on c[0]: log(energy)
 					if (wr == 0) {
 						regression (thee, j, rj.peek(), nr);
 					}
@@ -160,7 +160,7 @@ autoDTW Cepstrumc_to_DTW (Cepstrumc me, Cepstrumc thee, double wc, double wle, d
 					dist += wer * d * d;
 				}
 				dist /= wc + wle + wr + wer;
-				his z[i][j] = sqrt (dist); // prototype along y-direction
+				his z[i][j] = sqrt ((real) dist);   // prototype along y-direction
 			}
 			Melder_progress ( (double) i / my nx, U"Calculate distances: frame ",
 			                   i, U" from ", my nx, U".");
diff --git a/LPC/Formant_extensions.cpp b/LPC/Formant_extensions.cpp
index 7e7100b..42fe36f 100644
--- a/LPC/Formant_extensions.cpp
+++ b/LPC/Formant_extensions.cpp
@@ -46,7 +46,7 @@ void Formant_formula (Formant me, double tmin, double tmax, long formantmin, lon
 		double ymin = 2.0 * formantmin - 1.0, ymax = 2.0 * formantmax;
 		Matrix_formula_part (fb.get(), tmin, tmax, ymin, ymax, expression, interpreter, nullptr);
 		// Put results back in Formant
-		long ixmin, ixmax, iymin, iymax;
+		integer ixmin, ixmax, iymin, iymax;
 		(void) Matrix_getWindowSamplesX (fb.get(), tmin, tmax, & ixmin, & ixmax);
 		(void) Matrix_getWindowSamplesY (fb.get(), ymin, ymax, & iymin, & iymax);
 
@@ -63,7 +63,7 @@ void Formant_formula (Formant me, double tmin, double tmax, long formantmin, lon
 					frame -> formant[iformantto].frequency = frequency;
 					frame -> formant[iformantto].bandwidth = bandWidth;
 				} else {
-					frame -> formant[iformant].frequency = frame -> formant[iformant].bandwidth = 0;
+					frame -> formant[iformant].frequency = frame -> formant[iformant].bandwidth = 0.0;
 				}
 			}
 			// shift the (higher) formants down if necessary.
@@ -75,7 +75,7 @@ void Formant_formula (Formant me, double tmin, double tmax, long formantmin, lon
 					frame -> formant[iformantto].frequency = frequency;
 					frame -> formant[iformantto].bandwidth = bandWidth;
 				} else {
-					frame -> formant[iformant].frequency = frame -> formant[iformant].bandwidth = 0;
+					frame -> formant[iformant].frequency = frame -> formant[iformant].bandwidth = 0.0;
 				}
 			}
 			frame ->  nFormants = iformantto;
@@ -104,7 +104,7 @@ autoIntensityTier Formant_and_Spectrogram_to_IntensityTier (Formant me, Spectrog
 			if (iformant <= numberOfFormants) {
 				double f = frame -> formant[iformant].frequency;
 				value = Matrix_getValueAtXY (thee, time, f);
-				value = value == NUMundefined ? 0.0 : value;
+				value = isdefined (value) ? value : 0.0;
 			}
 			value = 10.0 * log10 ((value + 1e-30) / 4.0e-10); /* dB / Hz */
 			if (value != previousValue) {
diff --git a/LPC/LPC.cpp b/LPC/LPC.cpp
index 29ef4ff..71361c8 100644
--- a/LPC/LPC.cpp
+++ b/LPC/LPC.cpp
@@ -91,14 +91,14 @@ void LPC_drawGain (LPC me, Graphics g, double tmin, double tmax, double gmin, do
 		tmin = my xmin;
 		tmax = my xmax;
 	}
-	long itmin, itmax;
+	integer itmin, itmax;
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) {
 		return;
 	}
 	autoNUMvector<double> gain (itmin, itmax);
 
-	for (long iframe = itmin; iframe <= itmax; iframe++) {
-		gain[iframe] = my d_frames[iframe].gain;
+	for (integer iframe = itmin; iframe <= itmax; iframe ++) {
+		gain [iframe] = my d_frames [iframe]. gain;
 	}
 	if (gmax <= gmin) {
 		NUMvector_extrema (gain.peek(), itmin, itmax, & gmin, & gmax);
@@ -110,7 +110,7 @@ void LPC_drawGain (LPC me, Graphics g, double tmin, double tmax, double gmin, do
 
 	Graphics_setInner (g);
 	Graphics_setWindow (g, tmin, tmax, gmin, gmax);
-	for (long iframe = itmin; iframe <= itmax; iframe++) {
+	for (integer iframe = itmin; iframe <= itmax; iframe ++) {
 		double x = Sampled_indexToX (me, iframe);
 		Graphics_speckle (g, x, gain[iframe]);
 	}
diff --git a/LPC/LPC_and_LineSpectralFrequencies.cpp b/LPC/LPC_and_LineSpectralFrequencies.cpp
index 4bb89f9..198d254 100644
--- a/LPC/LPC_and_LineSpectralFrequencies.cpp
+++ b/LPC/LPC_and_LineSpectralFrequencies.cpp
@@ -177,7 +177,7 @@ static long Roots_fromPolynomial_grid (Roots me, Polynomial thee, double gridSiz
 		xmax = xmax > thy xmax ? thy xmax : xmax;
 		//double root = Polynomial_findOneRealRoot_nr (thee, xmin, xmax);
 		double root = Polynomial_findOneSimpleRealRoot_ridders (thee, xmin, xmax);
-		if (root != NUMundefined && (numberOfRootsFound == 0 || my v [numberOfRootsFound].re != root)) {
+		if (isdefined (root) && (numberOfRootsFound == 0 || my v [numberOfRootsFound].re != root)) {
 			my v [++numberOfRootsFound].re = root; // root not at border of interval
 			my v [numberOfRootsFound].im = 0.0;
 		}
@@ -215,7 +215,7 @@ static void LineSpectralFrequencies_Frame_initFromLPC_Frame_grid (LineSpectralFr
 		double xmax = roots -> v [half_order_g1 + 1 - i].re;
 		double xmin = i == half_order_g1 ? g1 -> xmin : roots -> v [half_order_g1 - i].re;
 		double root = Polynomial_findOneSimpleRealRoot_ridders (g2, xmin, xmax);
-		if (root != NUMundefined) {
+		if (isdefined (root)) {
 			my frequencies [2 * i] = acos (root / 2.0) / NUMpi * maximumFrequency;
 		} else { 
 			my numberOfFrequencies --;
diff --git a/LPC/LPC_and_Tube.cpp b/LPC/LPC_and_Tube.cpp
index db99a26..0cd363c 100644
--- a/LPC/LPC_and_Tube.cpp
+++ b/LPC/LPC_and_Tube.cpp
@@ -20,7 +20,7 @@
  djmw 20020612 GPL header
  djmw 20041020 struct Tube_Frame -> struct structTube_Frame; struct LPC_Frame -> struct structLPC_Frame;
  	struct Formant_Frame->struct structFormant_Frame
- djmw 20051005 Always make a VocalTract with length 0.01 m when wakita_length==NUMundefined.
+ djmw 20051005 Always make a VocalTract with length 0.01 m when isundef(wakita_length).
 */
 
 #include "LPC_and_Tube.h"
@@ -97,7 +97,7 @@ double LPC_Frame_getVTL_wakita (LPC_Frame me, double samplingPeriod, double refL
 	Tube_Frame rc = & rc_struct, af = & af_struct;
 	try {
 		long m = my nCoefficients;
-		double length, dlength = 0.001, wakita_length = NUMundefined;
+		double length, dlength = 0.001, wakita_length = undefined;
 		double varMin = 1e308;
 
 		memset (& lpc_struct, 0, sizeof (lpc_struct));
@@ -189,7 +189,7 @@ double LPC_Frame_getVTL_wakita (LPC_Frame me, double samplingPeriod, double refL
 		lpc -> destroy ();
 		rc -> destroy ();
 		af -> destroy ();
-		return NUMundefined;
+		return undefined;
 	}
 }
 
diff --git a/LPC/LineSpectralFrequencies.cpp b/LPC/LineSpectralFrequencies.cpp
index bc40069..46bf472 100644
--- a/LPC/LineSpectralFrequencies.cpp
+++ b/LPC/LineSpectralFrequencies.cpp
@@ -81,16 +81,16 @@ void LineSpectralFrequencies_drawFrequencies (LineSpectralFrequencies me, Graphi
 		tmin = my xmin;
 		tmax = my xmax;
 	}
-	long itmin, itmax;
+	integer itmin, itmax;
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) {
 		return;
 	}
 	if (fmax <= fmin) {
 		double f1max, f2min; 
 		autoNUMvector<double> f1 (itmin, itmax), f2 (itmin, itmax);
-		for (long iframe = itmin; iframe <= itmax; iframe++) {
-			f1[iframe] = my d_frames[iframe].frequencies[1];
-			f2[iframe] = my d_frames[iframe].frequencies[my d_frames[iframe].numberOfFrequencies];
+		for (integer iframe = itmin; iframe <= itmax; iframe ++) {
+			f1 [iframe] = my d_frames [iframe]. frequencies [1];
+			f2 [iframe] = my d_frames [iframe]. frequencies [my d_frames[iframe]. numberOfFrequencies];
 		}
 		NUMvector_extrema (f1.peek(), itmin, itmax, & fmin, & f1max);
 		NUMvector_extrema (f2.peek(), itmin, itmax, & f2min, & fmax);
@@ -102,7 +102,7 @@ void LineSpectralFrequencies_drawFrequencies (LineSpectralFrequencies me, Graphi
 
 	Graphics_setInner (g);
 	Graphics_setWindow (g, tmin, tmax, fmin, fmax);
-	for (long iframe = itmin; iframe <= itmax; iframe++) {
+	for (integer iframe = itmin; iframe <= itmax; iframe ++) {
 		LineSpectralFrequencies_Frame lsf = & my d_frames[iframe];
 		double x = Sampled_indexToX (me, iframe);
 		for (long ifreq = 1; ifreq <= lsf -> numberOfFrequencies; ifreq++) {
diff --git a/LPC/Makefile b/LPC/Makefile
index 2320ac0..6a58734 100644
--- a/LPC/Makefile
+++ b/LPC/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "LPC"
-# David Weenink, 20170602
+# David Weenink and Paul Boersma 2017-08-08
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../dwtools -I ../fon -I ../sys -I ../dwsys -I ../stat
+CPPFLAGS = -I ../kar -I ../dwtools -I ../fon -I ../sys -I ../dwsys -I ../stat
 
 OBJECTS = Cepstrum.o Cepstrumc.o Cepstrum_and_Spectrum.o \
 	Cepstrogram.o \
@@ -31,6 +31,6 @@ libLPC.a: $(OBJECTS)
 	$(AR) cq libLPC.a $(OBJECTS)
 	$(RANLIB) libLPC.a
 
-$(OBJECTS): *.h ../num/NUM.h ../dwtools/*.h ../fon/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h
+$(OBJECTS): *.h ../kar/*.h ../dwtools/*.h ../fon/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h
 
 
diff --git a/LPC/Sound_and_LPC.cpp b/LPC/Sound_and_LPC.cpp
index 17e56af..0985981 100644
--- a/LPC/Sound_and_LPC.cpp
+++ b/LPC/Sound_and_LPC.cpp
@@ -59,7 +59,7 @@ static void LPC_Frame_and_Sound_filter (LPC_Frame me, Sound thee, int channel) {
 
 void LPC_Frame_and_Sound_filterInverse (LPC_Frame me, Sound thee, int channel) {
 	double *x = thy z[channel];
-	autoNUMvector<double> y (0L, my nCoefficients);
+	autoNUMvector <double> y ((integer) 0, my nCoefficients);
 	for (long i = 1; i <= thy nx; i++) {
 		y[0] = x[i];
 		for (long j = 1; j <= my nCoefficients; j++) {
diff --git a/LPC/Tube_def.h b/LPC/Tube_def.h
index 150f505..4f0a721 100644
--- a/LPC/Tube_def.h
+++ b/LPC/Tube_def.h
@@ -20,7 +20,7 @@
 #define ooSTRUCT Tube_Frame
 oo_DEFINE_STRUCT (Tube_Frame)
 
-	oo_INT (nSegments)
+	oo_INT16 (nSegments)
 	oo_DOUBLE (length)
 	oo_DOUBLE_VECTOR (c, nSegments)
 	
@@ -31,7 +31,7 @@ oo_END_STRUCT (Tube_Frame)
 #define ooSTRUCT Tube
 oo_DEFINE_CLASS (Tube, Sampled)
 	
-	oo_INT (maxnSegments)
+	oo_INT16 (maxnSegments)
 	oo_STRUCT_VECTOR (Tube_Frame, frame, nx)
 
 	#if oo_DECLARING
diff --git a/artsynth/Artword.cpp b/artsynth/Artword.cpp
index 6ccd08a..232b0d3 100644
--- a/artsynth/Artword.cpp
+++ b/artsynth/Artword.cpp
@@ -1,6 +1,6 @@
 /* Artword.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -67,21 +67,23 @@ void Artword_setTarget (Artword me, int feature, double time, double target) {
 		Melder_assert (feature <= kArt_muscle_MAX);
 		ArtwordData f = & my data [feature];
 		Melder_assert (f -> numberOfTargets >= 2);
-		int insert = 1;
+		int32 insertionPosition = 1;   // should be able to go up to 32768
 		if (time < 0.0) time = 0.0;
 		if (time > my totalTime) time = my totalTime;
-		while (insert <= f -> numberOfTargets && f -> times [insert] < time)
-			insert ++;
-		Melder_assert (insert <= f -> numberOfTargets);   // can never insert past totalTime
-		if (f -> times [insert] != time) {
-			long numberOfTargets = f -> numberOfTargets;
-			NUMvector_insert <double> (& f -> times, 1, & numberOfTargets, insert);
+		while (insertionPosition <= f -> numberOfTargets && f -> times [insertionPosition] < time)
+			insertionPosition ++;
+		Melder_assert (insertionPosition <= f -> numberOfTargets);   // can never insert past totalTime
+		if (f -> times [insertionPosition] != time) {
+			if (f -> numberOfTargets == INT16_MAX)
+				Melder_throw (U"An Artword cannot have more than ", INT16_MAX, U" targets.");
+			integer numberOfTargets = f -> numberOfTargets;
+			NUMvector_insert <double> (& f -> times, 1, & numberOfTargets, insertionPosition);
 			numberOfTargets = f -> numberOfTargets;
-			NUMvector_insert <double> (& f -> targets, 1, & numberOfTargets, insert);
+			NUMvector_insert <double> (& f -> targets, 1, & numberOfTargets, insertionPosition);
 			f -> numberOfTargets ++;
 		}
-		f -> targets [insert] = target;
-		f -> times [insert] = time;
+		f -> targets [insertionPosition] = target;
+		f -> times [insertionPosition] = time;
 	} catch (MelderError) {
 		Melder_throw (me, U": target not set.");
 	}
@@ -90,29 +92,29 @@ void Artword_setTarget (Artword me, int feature, double time, double target) {
 double Artword_getTarget (Artword me, int feature, double time) {
 	ArtwordData f = & my data [feature];
 	double *times = f -> times, *targets = f -> targets;
-	int iTarget = f -> _iTarget;
-	if (! iTarget) iTarget = 1;
-	while (time > times [iTarget + 1] && iTarget < f -> numberOfTargets - 1)
-		iTarget ++;
-	while (time < times [iTarget] && iTarget > 1)
-		iTarget --;
-	f -> _iTarget = iTarget;
-	Melder_assert (iTarget > 0 && iTarget < f -> numberOfTargets);
-	return targets [iTarget] + (time - times [iTarget]) *
-		(targets [iTarget + 1] - targets [iTarget]) /
-		(times [iTarget + 1] - times [iTarget]);
+	int16 targetNumber = f -> _iTarget;
+	if (! targetNumber) targetNumber = 1;
+	while (time > times [targetNumber + 1] && targetNumber < f -> numberOfTargets - 1)
+		targetNumber ++;
+	while (time < times [targetNumber] && targetNumber > 1)
+		targetNumber --;
+	f -> _iTarget = targetNumber;
+	Melder_assert (targetNumber > 0 && targetNumber < f -> numberOfTargets);
+	return targets [targetNumber] + (time - times [targetNumber]) *
+		(targets [targetNumber + 1] - targets [targetNumber]) /
+		(times [targetNumber + 1] - times [targetNumber]);
 }
 
-void Artword_removeTarget (Artword me, int feature, int iTarget) {
+void Artword_removeTarget (Artword me, int feature, int16 targetNumber) {
 	ArtwordData f = & my data [feature];
-	Melder_assert (iTarget >= 1);
-	Melder_assert (iTarget <= f -> numberOfTargets);
-	if (iTarget == 1)
-		f -> targets [iTarget] = 0.0;
-	else if (iTarget == f -> numberOfTargets)
+	Melder_assert (targetNumber >= 1);
+	Melder_assert (targetNumber <= f -> numberOfTargets);
+	if (targetNumber == 1) {
+		f -> targets [targetNumber] = 0.0;
+	} else if (targetNumber == f -> numberOfTargets) {
 		f -> targets [f -> numberOfTargets] = 0.0;
-	else {
-		for (int i = iTarget; i < f -> numberOfTargets; i ++) {
+	} else {
+		for (int16 i = targetNumber; i < f -> numberOfTargets; i ++) {
 			f -> times [i] = f -> times [i + 1];
 			f -> targets [i] = f -> targets [i + 1];
 		}
@@ -128,13 +130,13 @@ void Artword_intoArt (Artword me, Art art, double time) {
 }
 
 void Artword_draw (Artword me, Graphics g, int feature, bool garnish) {
-	long numberOfTargets = my data [feature]. numberOfTargets;
+	int16 numberOfTargets = my data [feature]. numberOfTargets;
 	if (numberOfTargets > 0) {
 		autoNUMvector <double> x (1, numberOfTargets);
 		autoNUMvector <double> y (1, numberOfTargets);
 		Graphics_setInner (g);
 		Graphics_setWindow (g, 0, my totalTime, -1.0, 1.0);
-		for (int i = 1; i <= numberOfTargets; i ++) {
+		for (int16 i = 1; i <= numberOfTargets; i ++) {
 			x [i] = my data [feature]. times [i];
 			y [i] = my data [feature]. targets [i];
 		}
diff --git a/artsynth/Artword.h b/artsynth/Artword.h
index 6d37d8b..1380c40 100644
--- a/artsynth/Artword.h
+++ b/artsynth/Artword.h
@@ -2,7 +2,7 @@
 #define _Artword_h_
 /* Artword.h
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,11 +36,11 @@ void Artword_setDefault (Artword me, int feature);
 		rest unchanged;	
 */
 
-void Artword_setTarget (Artword me, int feature, double tim, double value);
+void Artword_setTarget (Artword me, int feature, double time, double value);
 
-double Artword_getTarget (Artword me, int feature, double tim);
+double Artword_getTarget (Artword me, int feature, double time);
 
-void Artword_removeTarget (Artword me, int feature, int iTarget);
+void Artword_removeTarget (Artword me, int feature, int16 targetNumber);
 /*
 	Function:
 		remove one target from the target list of "feature".
@@ -63,7 +63,7 @@ void Artword_removeTarget (Artword me, int feature, int iTarget);
 				self -> data [feature]. targets [i] == old self -> data [feature]. targets [i + 1];	
 */
 
-void Artword_intoArt (Artword me, Art art, double tim);
+void Artword_intoArt (Artword me, Art art, double time);
 /*
 	Function:
 		Linear interpolation between targets, into an existing Art.
diff --git a/artsynth/ArtwordEditor.cpp b/artsynth/ArtwordEditor.cpp
index 74bb546..fcda0f7 100644
--- a/artsynth/ArtwordEditor.cpp
+++ b/artsynth/ArtwordEditor.cpp
@@ -29,7 +29,7 @@ static void updateList (ArtwordEditor me) {
 	Artword artword = (Artword) my data;
 	ArtwordData a = & artword -> data [my feature];
 	GuiList_deleteAllItems (my list);
-	for (int i = 1; i <= a -> numberOfTargets; i ++) {
+	for (int16 i = 1; i <= a -> numberOfTargets; i ++) {
 		GuiList_insertItem (my list,
 			Melder_cat (Melder_single (a -> times [i]), U"  ", Melder_single (a -> targets [i])),
 			i);
@@ -42,10 +42,13 @@ static void gui_button_cb_removeTarget (ArtwordEditor me, GuiButtonEvent /* even
 	long numberOfSelectedPositions;
 	long *selectedPositions = GuiList_getSelectedPositions (my list, & numberOfSelectedPositions);   // BUG memory
 	if (selectedPositions) {
-		for (long ipos = numberOfSelectedPositions; ipos > 0; ipos --)
-			Artword_removeTarget (artword, my feature, selectedPositions [ipos]);
+		for (long ipos = numberOfSelectedPositions; ipos > 0; ipos --) {
+			long position = selectedPositions [ipos];
+			Melder_assert (position >= 1 && position <= INT16_MAX);
+			Artword_removeTarget (artword, my feature, (int16) position);   // guarded conversion
+		}
 	}
-	NUMvector_free <long> (selectedPositions, 1);
+	NUMvector_free (selectedPositions, 1);
 	updateList (me);
 	Editor_broadcastDataChanged (me);
 }
diff --git a/artsynth/Artword_def.h b/artsynth/Artword_def.h
index b2e0435..db24203 100644
--- a/artsynth/Artword_def.h
+++ b/artsynth/Artword_def.h
@@ -1,6 +1,6 @@
 /* Artword_def.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,12 +20,12 @@
 #define ooSTRUCT ArtwordData
 oo_DEFINE_STRUCT (ArtwordData)
 
-	oo_INT (numberOfTargets)
+	oo_INT16 (numberOfTargets)
 	oo_DOUBLE_VECTOR (targets, numberOfTargets)
 	oo_DOUBLE_VECTOR (times, numberOfTargets)
 
 	#if oo_DECLARING
-		oo_INT (_iTarget)
+		oo_INT16 (_iTarget)
 	#endif
 
 oo_END_STRUCT (ArtwordData)
diff --git a/artsynth/Makefile b/artsynth/Makefile
index 48afe0f..adacbb0 100644
--- a/artsynth/Makefile
+++ b/artsynth/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "artsynth"
-# Paul Boersma, 2 June 2017
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../sys -I ../fon -I ../stat
+CPPFLAGS = -I ../kar -I ../sys -I ../fon -I ../stat
 
 OBJECTS = Speaker.o Articulation.o Artword.o \
      Art_Speaker.o Art_Speaker_to_VocalTract.o Artword_Speaker.o Artword_Speaker_Sound.o \
@@ -25,5 +25,5 @@ libartsynth.a: $(OBJECTS)
 	$(AR) cq libartsynth.a $(OBJECTS)
 	$(RANLIB) libartsynth.a
 
-$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../fon/*.h ../stat/*.h
+$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../fon/*.h ../stat/*.h
 
diff --git a/artsynth/Speaker.cpp b/artsynth/Speaker.cpp
index d6d960a..05e6509 100644
--- a/artsynth/Speaker.cpp
+++ b/artsynth/Speaker.cpp
@@ -39,7 +39,7 @@
 
 Thing_implement (Speaker, Daata, 0);
 
-autoSpeaker Speaker_create (const char32 *kindOfSpeaker, int numberOfVocalCordMasses) {
+autoSpeaker Speaker_create (const char32 *kindOfSpeaker, int16 numberOfVocalCordMasses) {
 	autoSpeaker me = Thing_new (Speaker);
 
 	/* Supralaryngeal dimensions are taken from P. Mermelstein (1973):		*/
diff --git a/artsynth/Speaker.h b/artsynth/Speaker.h
index c86484a..17b2982 100644
--- a/artsynth/Speaker.h
+++ b/artsynth/Speaker.h
@@ -2,7 +2,7 @@
 #define _Speaker_h_
 /* Speaker.h
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 
 #include "Speaker_def.h"
 
-autoSpeaker Speaker_create (const char32 *kindOfSpeaker, int numberOfVocalCordMasses);
+autoSpeaker Speaker_create (const char32 *kindOfSpeaker, int16 numberOfVocalCordMasses);
 	/* Preconditions:								*/
 	/*    1 <= numberOfVocalCordMasses <= 2;					*/
 	/* Failures:									*/
diff --git a/artsynth/Speaker_def.h b/artsynth/Speaker_def.h
index 4b08d65..7464a9f 100644
--- a/artsynth/Speaker_def.h
+++ b/artsynth/Speaker_def.h
@@ -20,7 +20,7 @@
 #define ooSTRUCT Speaker_CordDimensions
 oo_DEFINE_STRUCT (Speaker_CordDimensions)
 
-	oo_INT (numberOfMasses)
+	oo_INT16 (numberOfMasses)
 	oo_DOUBLE (length)
 
 oo_END_STRUCT (Speaker_CordDimensions)
diff --git a/artsynth/Speaker_to_Delta.cpp b/artsynth/Speaker_to_Delta.cpp
index dc1f245..1c37aab 100644
--- a/artsynth/Speaker_to_Delta.cpp
+++ b/artsynth/Speaker_to_Delta.cpp
@@ -1,6 +1,6 @@
 /* Speaker_to_Delta.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,13 +25,12 @@ autoDelta Speaker_to_Delta (Speaker me) {
 	double f = my relativeSize * 1e-3;   // we shall use millimetres and grams
 	double xe [30], ye [30], xi [30], yi [30], xmm [30], ymm [30], dx, dy;
 	int closed [40];
-	int itube;
 	autoDelta thee = Delta_create (89);
 	Melder_assert (my cord.numberOfMasses == 1 || my cord.numberOfMasses == 2 || my cord.numberOfMasses == 10);
 
 	/* Lungs: tubes 1..23. */
 
-	for (itube = 1; itube <= 23; itube ++) {
+	for (int itube = 1; itube <= 23; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		t -> Dx = t -> Dxeq = 10.0 * f;
 		t -> Dy = t -> Dyeq = 100.0 * f;
@@ -45,7 +44,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 
 	/* Bronchi: tubes 24..29. */
 
-	for (itube = 24; itube <= 29; itube ++) {
+	for (int itube = 24; itube <= 29; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		t -> Dx = t -> Dxeq = 10.0 * f;
 		t -> Dy = t -> Dyeq = 15.0 * f;
@@ -58,7 +57,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 
 	/* Trachea: tubes 30..35; four of these may be replaced by conus elasticus (see below). */
 
-	for (itube = 30; itube <= 35; itube ++) {
+	for (int itube = 30; itube <= 35; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		t -> Dx = t -> Dxeq = 10.0 * f;
 		t -> Dy = t -> Dyeq = 15.0 * f;
@@ -77,21 +76,20 @@ autoDelta Speaker_to_Delta (Speaker me) {
 			{ 16, 120.0, 240.0,  320.0 }, { 17, 120.0, 240.0,  160.0 }, { 18, 120.0, 140.0,   80.0 },
 			{ 19,  70.0,  70.0,   40.0 }, { 20,  35.0,  35.0,   20.0 }, { 21,  18.0,  18.0,   10.0 },
 			{ 22,  12.0,  12.0,    5.0 }, { 23,  12.0,  12.0,    3.0 }, { 24,  18.0,   9.0,    2.0 },
-			{ 25,  18.0,  19.0,    2.0 }, { 0 } };
-		int i;
-		for (i = 0; data [i]. itube; i ++) {
+			{ 25,  18.0,  19.0,    2.0 }, { } };
+		for (int i = 0; data [i]. itube; i ++) {
 			Delta_Tube t = thy tube + data [i]. itube;
 			t -> Dy = t -> Dyeq = data [i]. Dy * f;
 			t -> Dz = t -> Dzeq = data [i]. Dz * f;
 			t -> parallel = data [i]. parallel;
 		}
-		for (itube = 26; itube <= 35; itube ++) {
+		for (int itube = 26; itube <= 35; itube ++) {
 			Delta_Tube t = thy tube + itube;
 			t -> Dy = t -> Dyeq = 11.0 * f;
 			t -> Dz = t -> Dzeq = 14.0 * f;
 			t -> parallel = 1;
 		}
-		for (itube = FIRST_TUBE; itube <= 18; itube ++) {
+		for (int itube = FIRST_TUBE; itube <= 18; itube ++) {
 			Delta_Tube t = thy tube + itube;
 			t -> Dx = t -> Dxeq = 10.0 * f;
 			t -> mass = 10.0 * my relativeSize * t -> Dx * t -> Dz;   // 10 mm
@@ -99,7 +97,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 			t -> k3 = 0.0;
 			t -> Brel = 1.0;
 		}
-		for (itube = 19; itube <= 35; itube ++) {
+		for (int itube = 19; itube <= 35; itube ++) {
 			Delta_Tube t = thy tube + itube;
 			t -> Dx = t -> Dxeq = 10.0 * f;
 			t -> mass = 3.0 * my relativeSize * t -> Dx * t -> Dz;   // 3 mm
@@ -187,7 +185,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 		thy tube [85]. Brel = 0.2;
 		thy tube [86]. Brel = 0.2;
 
-		for (itube = 79; itube <= 86; itube ++) {
+		for (int itube = 79; itube <= 86; itube ++) {
 			Delta_Tube t = thy tube + itube;
 			t -> mass = t -> Dx * t -> Dz / (30.0 * f);
 			t -> k3 = t -> k1 * (20.0 / t -> Dz) * (20.0 / t -> Dz);
@@ -201,7 +199,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 	 * Fill in the values of the glottal shunt only if we want to model it.
 	 */
 	if (my shunt.Dx != 0.0) {
-		for (itube = 87; itube <= 89; itube ++) {
+		for (int itube = 87; itube <= 89; itube ++) {
 			Delta_Tube t = thy tube + itube;
 			t -> Dx = t -> Dxeq = my shunt.Dx;
 			t -> Dy = t -> Dyeq = my shunt.Dy;
@@ -221,7 +219,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 
 	/* Pharynx and mouth: tubes 38..64. */
 
-	for (itube = 38; itube <= 64; itube ++) {
+	for (int itube = 38; itube <= 64; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		int i = itube - 37;
 		t -> Dx = t -> Dxeq = sqrt (( dx = xmm [i] - xmm [i + 1], dx * dx ) + ( dy = ymm [i] - ymm [i + 1], dy * dy ));
@@ -238,7 +236,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 
 	/* Nose: tubes 65..78. */
 
-	for (itube = 65; itube <= 78; itube ++) {
+	for (int itube = 65; itube <= 78; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		t -> Dx = t -> Dxeq = my nose.Dx;
 		t -> Dy = t -> Dyeq = my nose.weq [itube - 65];
@@ -254,7 +252,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 	 * every tube is connected on the left to the previous tube (index one lower).
 	 * This corresponds to a two-mass model of the vocal cords without shunt.
 	 */
-	for (itube = SMOOTH_LUNGS ? FIRST_TUBE : 1; itube <= thy numberOfTubes; itube ++) {
+	for (int itube = SMOOTH_LUNGS ? FIRST_TUBE : 1; itube <= thy numberOfTubes; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		t -> s1 = 5e6 * t -> Dx * t -> Dz;
 		t -> s3 = t -> s1 / (0.9e-3 * 0.9e-3);
@@ -304,7 +302,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 	} else {
 
 		/* Disconnect tubes 79..86 on both sides. */
-		for (itube = 79; itube <= 86; itube ++)
+		for (int itube = 79; itube <= 86; itube ++)
 			thy tube [itube]. left1 = thy tube [itube]. right1 = nullptr;
 	}
 
@@ -332,7 +330,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 	} else {
 
 		/* Disconnect tubes 87..89 on both sides. */
-		for (itube = 87; itube <= 89; itube ++)
+		for (int itube = 87; itube <= 89; itube ++)
 			thy tube [itube]. left1 = thy tube [itube]. right1 = nullptr;
 	}
 
@@ -350,7 +348,7 @@ autoDelta Speaker_to_Delta (Speaker me) {
 	thy tube [64]. right1 = nullptr;   // radiation at the lips
 	thy tube [78]. right1 = nullptr;   // radiation at the nostrils
 
-	for (itube = 1; itube <= thy numberOfTubes; itube ++) {
+	for (int itube = 1; itube <= thy numberOfTubes; itube ++) {
 		Delta_Tube t = thy tube + itube;
 		Melder_assert (! t->left1 || t->left1->right1 == t || t->left1->right2 == t);
 		Melder_assert (! t->left2 || t->left2->right1 == t);
diff --git a/artsynth/praat_Artsynth.cpp b/artsynth/praat_Artsynth.cpp
index bfb4f32..554e67a 100644
--- a/artsynth/praat_Artsynth.cpp
+++ b/artsynth/praat_Artsynth.cpp
@@ -226,7 +226,7 @@ FORM (NEW1_Speaker_create, U"Create a Speaker", U"Create Speaker...") {
 	OK
 DO
 	CREATE_ONE
-		autoSpeaker result = Speaker_create (kindOfSpeaker, Melder_atoi (numberOfTubesInGlottis));
+		autoSpeaker result = Speaker_create (kindOfSpeaker, (int16) Melder_atoi (numberOfTubesInGlottis));   // conversion OK because the values are 1, 2, 10
 	CREATE_ONE_END (name)
 }
 
diff --git a/contrib/ola/FeatureWeights.cpp b/contrib/ola/FeatureWeights.cpp
index 3590362..1bc2cb8 100644
--- a/contrib/ola/FeatureWeights.cpp
+++ b/contrib/ola/FeatureWeights.cpp
@@ -176,9 +176,9 @@ autoFeatureWeights FeatureWeights_computeWrapperInt
 	try {
 		double pivot = 0.5;
 		double range = 0.5;
-		autoNUMvector <double> results (0L, nseeds);
+		autoNUMvector <double> results ((integer) 0, nseeds);
 
-		autoThingVector <structFeatureWeights> cs (0L, nseeds);
+		autoThingVector <structFeatureWeights> cs ((integer) 0, nseeds);
 		for (long y = 0; y <= nseeds; y++) {
 			cs [y] = FeatureWeights_create (my input -> nx);
 		}
@@ -281,9 +281,9 @@ autoFeatureWeights FeatureWeights_computeWrapperExt
 	try {
 		double pivot = 0.5;
 		double range = 0.5;
-		autoNUMvector <double> results (0L, nseeds);
+		autoNUMvector <double> results ((integer) 0, nseeds);
 
-		autoThingVector <structFeatureWeights> cs (0L, nseeds);
+		autoThingVector <structFeatureWeights> cs ((integer) 0, nseeds);
 		for (long y = 0; y <= nseeds; y++) {
 			cs [y] = FeatureWeights_create (pp -> nx);
 		}
@@ -423,8 +423,8 @@ autoFeatureWeights FeatureWeights_computeRELIEF
 	// Normalization               //
 	/////////////////////////////////
 
-	autoNUMvector <double> min (0L, p->nx - 1);
-	autoNUMvector <double> max (0L, p->nx - 1);
+	autoNUMvector <double> min ((integer) 0, p->nx - 1);
+	autoNUMvector <double> max ((integer) 0, p->nx - 1);
 	for (long x = 1; x <= p -> nx; x ++) {
 		max [x] = p -> z [1] [x];   // BUG: this will just crash because of array index out of bounds
 		min [x] = max [x];
@@ -437,7 +437,7 @@ autoFeatureWeights FeatureWeights_computeRELIEF
 		}
 	}
 
-	autoNUMvector <double> alfa (0L, p -> nx - 1);
+	autoNUMvector <double> alfa ((integer) 0, p -> nx - 1);
 	for (long x = 1; x <= p -> nx; x ++) {
 		alfa [x] = max [x] - min [x];   // BUG: this will just crash because of array index out of bounds
 	}
@@ -456,10 +456,10 @@ autoFeatureWeights FeatureWeights_computeRELIEF
 	// Computing prior class probs //
 	/////////////////////////////////
 
-	autoNUMvector <double> priors (0L, c->size - 1);   // worst-case allocations
-	autoNUMvector <long> classes (0L, c->size - 1);//
-	autoNUMvector <long> enemies (0L, c->size - 1);//
-	autoNUMvector <long> friends (0L, c->size - 1);//
+	autoNUMvector <double> priors ((integer) 0, c->size - 1);   // worst-case allocations
+	autoNUMvector <long> classes ((integer) 0, c->size - 1);//
+	autoNUMvector <long> enemies ((integer) 0, c->size - 1);//
+	autoNUMvector <long> friends ((integer) 0, c->size - 1);//
 	long nclasses = FeatureWeights_computePriors (c, classes.peek(), priors.peek());
 	Melder_assert (nclasses >= 2);
 
@@ -473,7 +473,7 @@ autoFeatureWeights FeatureWeights_computeRELIEF
 		long nenemies = KNN_kUniqueEnemies (p.get(), p.get(), c, y, nclasses - 1, enemies.peek());
 
 		if (nfriends && nenemies) {
-			autoNUMvector <double> classps (0L, nenemies - 1);
+			autoNUMvector <double> classps ((integer) 0, nenemies - 1);
 			for (long eq = 0; eq < nenemies; eq ++) {
 				for (long iq = 0; iq < nclasses; iq ++) {
 					if (FeatureWeights_areFriends (c->at [enemies [eq]], c->at [classes [iq]])) {
diff --git a/contrib/ola/KNN.cpp b/contrib/ola/KNN.cpp
index bf6f8b7..cb4b6b5 100644
--- a/contrib/ola/KNN.cpp
+++ b/contrib/ola/KNN.cpp
@@ -473,8 +473,8 @@ void * KNN_classifyToTableOfRealAux
 
 {
     long ncategories = Categories_getSize (((KNN_input_ToTableOfReal_t *) input)->uniqueCategories);
-    autoNUMvector <long> indices (0L, ((KNN_input_ToTableOfReal_t *) input)->k);
-    autoNUMvector <double> distances (0L, ((KNN_input_ToTableOfReal_t *) input)->k);
+    autoNUMvector <long> indices ((integer) 0, ((KNN_input_ToTableOfReal_t *) input)->k);
+    autoNUMvector <double> distances ((integer) 0, ((KNN_input_ToTableOfReal_t *) input)->k);
 
     for (long y = ((KNN_input_ToTableOfReal_t *) input)->istart; y <= ((KNN_input_ToTableOfReal_t *) input)->istop; ++y)
     {
@@ -582,11 +582,11 @@ autoCategories KNN_classifyFold
 
     long ncollected;
     long ncategories;
-    autoNUMvector <long> indices (0L, k);
-    autoNUMvector <long> freqindices (0L, k);
-    autoNUMvector <double> distances (0L, k);
-    autoNUMvector <double> freqs (0L, k);
-    autoNUMvector <long> outputindices (0L, ps->ny);
+    autoNUMvector <long> indices ((integer) 0, k);
+    autoNUMvector <long> freqindices ((integer) 0, k);
+    autoNUMvector <double> distances ((integer) 0, k);
+    autoNUMvector <double> freqs ((integer) 0, k);
+    autoNUMvector <long> outputindices ((integer) 0, ps->ny);
     long noutputindices = 0;
 
     for (long y = begin; y <= end; ++y)
@@ -771,7 +771,7 @@ double KNN_modelSearch
 		double drate = rate / range;
 
 		soil best = {0, lround(dpivot), lround(dpivot)};
-		autoNUMvector <soil> field (0L, nseeds - 1);
+		autoNUMvector <soil> field ((integer) 0, nseeds - 1);
 
 		while (range > 0)
 		{
@@ -909,7 +909,7 @@ long KNN_kNeighboursSkip
     long dc = 0;
     long py = 1;
 
-    autoNUMvector <double> distances (0L, k - 1);
+    autoNUMvector <double> distances ((integer) 0, k - 1);
 
     Melder_assert (jy > 0 && jy <= j->ny);
     Melder_assert (k > 0 && k <= p->ny);
@@ -1137,7 +1137,7 @@ long KNN_kFriends
     long maxi;
     long dc = 0;
     long py = 1;
-    autoNUMvector <double> distances (0L, k - 1);
+    autoNUMvector <double> distances ((integer) 0, k - 1);
 
     Melder_assert (jy <= j->ny  && k <= p->ny && k > 0);
     Melder_assert (indices);
@@ -1233,8 +1233,8 @@ long KNN_friendsAmongkNeighbours
 )
 
 {
-    autoNUMvector <double> distances (0L, k - 1);
-    autoNUMvector <long> indices (0L, k - 1);
+    autoNUMvector <double> distances ((integer) 0, k - 1);
+    autoNUMvector <long> indices ((integer) 0, k - 1);
     long friends = 0;
 
     Melder_assert (jy > 0 && jy <= j->ny  && k <= p->ny && k > 0);
diff --git a/contrib/ola/KNN_prune.cpp b/contrib/ola/KNN_prune.cpp
index c5d6629..67adcd0 100644
--- a/contrib/ola/KNN_prune.cpp
+++ b/contrib/ola/KNN_prune.cpp
@@ -43,7 +43,7 @@ long KNN_prune_prune
 		return 0;
 	long removals = 0;
 	long ncandidates = 0;
-	autoNUMvector <long> candidates (0L, my nInstances - 1);
+	autoNUMvector <long> candidates ((integer) 0, my nInstances - 1);
 	if (my nInstances <= 1)
 		return 0;
 	for (long y = 1; y <= my nInstances; y ++) {
@@ -88,7 +88,7 @@ void KNN_prune_sort
 )
 {
 	long n = nindices;
-	autoNUMvector <long> h (0L, nindices - 1);
+	autoNUMvector <long> h ((integer) 0, nindices - 1);
 	for (long cc = 0; cc < nindices; ++ cc)
 		h [cc] = KNN_friendsAmongkNeighbours (p, p, c, indices [cc], k);
 	while (-- n) {   // insertion-sort, is heap-sort worth the effort?
@@ -128,7 +128,7 @@ long KNN_prune_kCoverage
 	Melder_assert (k > 0 && k <= p->ny);
 	long cc = 0;
 	autoFeatureWeights fws = FeatureWeights_create (p -> nx);
-	autoNUMvector <long> tempindices (0L, p -> ny - 1);
+	autoNUMvector <long> tempindices ((integer) 0, p -> ny - 1);
 	for (long yy = 1; yy <= p -> ny; yy ++) {
 		if (y != yy && FeatureWeights_areFriends (c->at [y], c->at [yy])) {
 			long n = KNN_kNeighboursSkip (p, p, fws.get(), yy, k, tempindices.peek(), y);
@@ -160,10 +160,10 @@ int KNN_prune_superfluous
 	if (y > p -> ny) y = p -> ny;   // safety belt
 	if (k > p -> ny) k = p -> ny;
 	autoFeatureWeights fws = FeatureWeights_create (p -> nx);
-	autoNUMvector <long> indices (0L, k - 1);
-	autoNUMvector <long> freqindices (0L, k - 1);
-	autoNUMvector <double> distances (0L, k - 1);
-	autoNUMvector <double> freqs (0L, k - 1);
+	autoNUMvector <long> indices ((integer) 0, k - 1);
+	autoNUMvector <long> freqindices ((integer) 0, k - 1);
+	autoNUMvector <double> distances ((integer) 0, k - 1);
+	autoNUMvector <double> freqs ((integer) 0, k - 1);
 	if (! KNN_kNeighboursSkip (p, p, fws.get(), y, k, indices.peek(), skipper)) return 0;
 	long ncategories = KNN_kIndicesToFrequenciesAndDistances (c, k, indices.peek(), distances.peek(), freqs.peek(), freqindices.peek());
 	int result = FeatureWeights_areFriends (c->at [y], c->at [freqindices [KNN_max (freqs.peek(), ncategories)]]);
@@ -187,7 +187,7 @@ int KNN_prune_critical
 	if (y > p -> ny) y = p -> ny;   // safety belt
 	if (k > p -> ny) k = p -> ny;
 	autoFeatureWeights fws = FeatureWeights_create (p -> nx);
-	autoNUMvector <long> indices (0L, k - 1);
+	autoNUMvector <long> indices ((integer) 0, k - 1);
 	long ncollected = KNN_kNeighboursSkip (p, p, fws.get(), y, k, indices.peek(), y);
 	for (long ic = 0; ic < ncollected; ic ++) {
 		if (! KNN_prune_superfluous (p, c, indices [ic], k, 0) || ! KNN_prune_superfluous (p, c, indices [ic], k, y)) {
@@ -213,7 +213,7 @@ int KNN_prune_noisy
 	if (y > p -> ny) y = p -> ny;   // safety belt
 	if (k > p -> ny) k = p -> ny;
 	autoFeatureWeights fws = FeatureWeights_create (p -> nx);
-	autoNUMvector <long> indices (0L, p->ny - 1);    // the coverage is not bounded by k but by n
+	autoNUMvector <long> indices ((integer) 0, p->ny - 1);    // the coverage is not bounded by k but by n
 	long reachability = KNN_kNeighboursSkip (p, p, fws.get(), y, k, indices.peek(), y);
 	long coverage = KNN_prune_kCoverage (p, c, y, k, indices.peek());
 	if (! KNN_prune_superfluous (p, c, y, k, 0) && reachability > coverage)
diff --git a/contrib/ola/Makefile b/contrib/ola/Makefile
index 097da2f..94eb0ac 100644
--- a/contrib/ola/Makefile
+++ b/contrib/ola/Makefile
@@ -4,7 +4,7 @@
 
 include ../../makefile.defs
 
-CPPFLAGS = -I ../../sys -I ../../kar -I ../../FFNet -I ../../dwtools -I ../../fon -I ../../dwsys -I ../../stat -I ../../num -I ../../external/gsl -D_DEBUG -D_REENTRANT
+CPPFLAGS = -I ../../kar -I ../../sys -I ../../FFNet -I ../../dwtools -I ../../fon -I ../../dwsys -I ../../stat -I ../../external/gsl -D_DEBUG -D_REENTRANT
 
 OBJECTS = KNN.o \
    KNN_threads.o Pattern_to_Categories_cluster.o KNN_prune.o FeatureWeights.o praat_contrib_Ola_KNN.o manual_KNN.o
@@ -23,4 +23,4 @@ libOla.a: $(OBJECTS)
 	$(AR) cq libOla.a $(OBJECTS)
 	$(RANLIB) libOla.a
 
-$(OBJECTS): *.h ../../sys/*.h ../../FFNet/*.h ../../dwtools/*.h ../../fon/*.h ../../dwsys/*.h ../../stat/*.h ../../num/*.h ../../external/gsl/*.h
+$(OBJECTS): *.h ../../kar/*.h ../../sys/*.h ../../FFNet/*.h ../../dwtools/*.h ../../fon/*.h ../../dwsys/*.h ../../stat/*.h ../../external/gsl/*.h
diff --git a/contrib/ola/Pattern_to_Categories_cluster.cpp b/contrib/ola/Pattern_to_Categories_cluster.cpp
index b4518cf..724beaa 100644
--- a/contrib/ola/Pattern_to_Categories_cluster.cpp
+++ b/contrib/ola/Pattern_to_Categories_cluster.cpp
@@ -61,11 +61,11 @@ autoCategories PatternList_to_Categories_cluster
 				s = (double) (p -> ny / k) / (double) (p -> ny / k + 1);
 
 		double progress = m;
-		autoNUMvector <double> sizes (0L, k);
-		autoNUMvector <long> seeds (0L, k);
+		autoNUMvector <double> sizes ((integer) 0, k);
+		autoNUMvector <long> seeds ((integer) 0, k);
 
 		autoPatternList centroids = PatternList_create (k, p -> nx);
-		autoNUMvector <double> beta (0L, centroids -> nx);
+		autoNUMvector <double> beta ((integer) 0, centroids -> nx);
 
 		do
 		{
diff --git a/dwsys/Collection_extensions.cpp b/dwsys/Collection_extensions.cpp
index 1057bda..9ae4387 100644
--- a/dwsys/Collection_extensions.cpp
+++ b/dwsys/Collection_extensions.cpp
@@ -1,6 +1,6 @@
 /* Collection_extensions.cpp
  *
- * Copyright (C) 1994-2011, 2015-2016 David Weenink
+ * Copyright (C) 1994-2011, 2015-2017 David Weenink
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -163,7 +163,7 @@ double OrderedOfString_getFractionDifferent (OrderedOfString me, OrderedOfString
 	long numberOfDifferences = OrderedOfString_getNumberOfDifferences (me, thee);
 
 	if (numberOfDifferences < 0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return my size == 0 ? 0.0 : (0.0 + numberOfDifferences) / my size;
 }
diff --git a/dwsys/Command.cpp b/dwsys/Command.cpp
index 10d26d8..94f8999 100644
--- a/dwsys/Command.cpp
+++ b/dwsys/Command.cpp
@@ -78,7 +78,7 @@ int CommandHistory_offright (CommandHistory me) {
 	return my size == 0 || my current == my size + 1;
 }
 
-char32 *CommandHistory_commandName (CommandHistory me, long offsetFromCurrent) {
+const char32 *CommandHistory_commandName (CommandHistory me, long offsetFromCurrent) {
 	long pos = my current + offsetFromCurrent;
 	return pos >= 1 && pos <= my size ? Thing_getName (my at [pos]) : nullptr;
 }
diff --git a/dwsys/Command.h b/dwsys/Command.h
index 207ba45..01af7de 100644
--- a/dwsys/Command.h
+++ b/dwsys/Command.h
@@ -77,7 +77,7 @@ int CommandHistory_offleft (CommandHistory me);
 int CommandHistory_offright (CommandHistory me);
 /*	return my size == 0 || my current == my size + 1; */
 
-char32 *CommandHistory_commandName (CommandHistory me, long offsetFromCurrent);
+const char32 * CommandHistory_commandName (CommandHistory me, long offsetFromCurrent);
 /* offsetFromCurrent may be zero, positive or negative. */
 /* References outside the list will return nullptr. */
 
diff --git a/dwsys/Eigen.cpp b/dwsys/Eigen.cpp
index ca88c70..401cb23 100644
--- a/dwsys/Eigen.cpp
+++ b/dwsys/Eigen.cpp
@@ -240,7 +240,7 @@ void Eigen_initFromSymmetricMatrix (Eigen me, double **a, long n) {
 	}
 
 	lwork = (long) floor (wt[0]);
-	autoNUMvector<double> work (0L, lwork);
+	autoNUMvector<double> work ((integer) 0, lwork);
 
 	(void) NUMlapack_dsyev (&jobz, &uplo, &n, &my eigenvectors[1][1], &n, &my eigenvalues[1], work.peek(), &lwork, &info);
 	if (info != 0) {
@@ -275,7 +275,7 @@ long Eigen_getNumberOfEigenvectors (Eigen me) {
 
 double Eigen_getEigenvectorElement (Eigen me, long ivec, long element) {
 	if (ivec > my numberOfEigenvalues || element < 1 || element > my dimension) {
-		return NUMundefined;
+		return undefined;
 	}
 	return my eigenvectors[ivec][element];
 }
@@ -292,7 +292,7 @@ double Eigen_getSumOfEigenvalues (Eigen me, long from, long to) {
 		to = my numberOfEigenvalues;
 	}
 	if (to > my numberOfEigenvalues || from > to) {
-		return NUMundefined;
+		return undefined;
 	}
 	double sum = 0.0;
 	for (long i = from; i <= to; i++) {
@@ -502,7 +502,7 @@ void Eigens_alignEigenvectors (OrderedOf<structEigen>* me) {
 static void Eigens_getAnglesBetweenSubspaces (Eigen me, Eigen thee, long ivec_from, long ivec_to, double *angles_degrees) {
 	long nvectors = ivec_to - ivec_from + 1;
 	for (long i = 1; i <= nvectors; i++) {
-		angles_degrees[i] = NUMundefined;
+		angles_degrees[i] = undefined;
 	}
 	long nmin = my numberOfEigenvalues < thy numberOfEigenvalues ? my numberOfEigenvalues : thy numberOfEigenvalues;
 
@@ -517,7 +517,7 @@ static void Eigens_getAnglesBetweenSubspaces (Eigen me, Eigen thee, long ivec_fr
 
 	/*
 		Algorithm 12.4.3 Golub & van Loan
-		Because we deal with eigenvectors we don't have to do the QR-decomposition,
+		Because we deal with eigenvectors we don't have to do the QR decomposition,
 			the columns in the Q's are the eigenvectors.
 		Compute C.
 	*/
diff --git a/dwsys/FileInMemory.cpp b/dwsys/FileInMemory.cpp
index abedf02..de15189 100644
--- a/dwsys/FileInMemory.cpp
+++ b/dwsys/FileInMemory.cpp
@@ -1,6 +1,6 @@
 /* FileInMemory.cpp
  *
- * Copyright (C) 2012-2013, 2015-2016 David Weenink
+ * Copyright (C) 2012-2013, 2015-2016 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -64,7 +64,7 @@ autoFileInMemory FileInMemory_create (MelderFile file) {
 		my d_data = NUMvector <char> (0, my d_numberOfBytes);   // includes room for a final null byte in case the file happens to contain text
 		MelderFile_open (file);
 		for (long i = 0; i < my d_numberOfBytes; i++) {
-			unsigned int number = bingetu1 (file -> filePointer);
+			unsigned int number = bingetu8 (file -> filePointer);
 			my d_data[i] = number;
 		}
 		my d_data[my d_numberOfBytes] = 0;   // one extra
@@ -123,7 +123,7 @@ int structFileInMemorySet :: s_compare_id (FileInMemory me, FileInMemory thee) {
 
 autoFileInMemorySet FileInMemorySet_createFromDirectoryContents (const char32 *dirpath, const char32 *fileGlobber) {
 	try {
-		structMelderDir parent { { 0 } };
+		structMelderDir parent { };
 		Melder_pathToDir (dirpath, &parent);
 		autoStrings thee = Strings_createAsFileList (Melder_cat (dirpath, U"/", fileGlobber));
 		if (thy numberOfStrings < 1) {
@@ -131,7 +131,7 @@ autoFileInMemorySet FileInMemorySet_createFromDirectoryContents (const char32 *d
 		}
 		autoFileInMemorySet me = FileInMemorySet_create ();
 		for (long i = 1; i <= thy numberOfStrings; i ++) {
-			structMelderFile file { 0 };
+			structMelderFile file { };
 			MelderDir_getFile (& parent, thy strings [i], & file);
 			autoFileInMemory fim = FileInMemory_create (& file);
 			my addItem_move (fim.move());
diff --git a/dwsys/Makefile b/dwsys/Makefile
index e6d3022..5d14436 100644
--- a/dwsys/Makefile
+++ b/dwsys/Makefile
@@ -1,9 +1,10 @@
 # makefile for library "dwsys".
 # David Weenink 20170531
+# Paul Boersma 2017-08-08
 
 include ../makefile.defs
 
-CPPFLAGS =  -I ../stat -I ../num -I ../sys -I ../external/gsl -I ../kar
+CPPFLAGS =  -I ../stat -I ../sys -I ../external/gsl -I ../kar
 
 all: libdwsys.a
 
@@ -30,5 +31,5 @@ libdwsys.a: $(OBJECTS) NUMmachar.o
 	$(AR) cq libdwsys.a $(OBJECTS)
 	$(RANLIB) libdwsys.a
 
-$(OBJECTS): *.h ../stat/*.h ../num/NUM.h ../sys/*.h ../external/gsl/*.h ../dwsys/*.h ../kar/*.h
+$(OBJECTS): *.h ../stat/*.h ../sys/*.h ../external/gsl/*.h ../dwsys/*.h ../kar/*.h
 
diff --git a/dwsys/NUM2.cpp b/dwsys/NUM2.cpp
index 8f79ba1..8fe53e6 100644
--- a/dwsys/NUM2.cpp
+++ b/dwsys/NUM2.cpp
@@ -1,6 +1,6 @@
 /* NUM2.cpp
  *
- * Copyright (C) 1993-2016 David Weenink
+ * Copyright (C) 1993-2017 David Weenink, Paul Boersma 2017
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -66,9 +66,6 @@
 #include "SVD.h"
 #include "Eigen.h"
 #include "NUMclapack.h"
-#ifndef _NUM_h_
-	#include "NUM.h"
-#endif
 #include "NUM2.h"
 #include "NUMmachar.h"
 #include "melder.h"
@@ -82,8 +79,7 @@
 #include "gsl_sf_trig.h"
 #include "gsl_poly.h"
 #include "gsl_cdf.h"
-
-#define my me ->
+#include "tensor.h"
 
 #undef MAX
 #undef MIN
@@ -211,6 +207,11 @@ void NUMnormalize (double **a, long nr, long nc, double norm) {
 	}
 }
 
+/*
+ * Standard deviations calculated by the corrected two-pass algorithm as decribed in
+ * Chan, Golub & LeVeque (1983), Algorithms for computing the sample variance: Analysis and recommendations, 
+ * The American Statistician 37: 242 - 247.
+ */
 void NUMstandardizeColumns (double **a, long rb, long re, long cb, long ce) {
 	long n = re - rb + 1;
 	if (n < 2) {
@@ -242,6 +243,22 @@ void NUMstandardizeColumns (double **a, long rb, long re, long cb, long ce) {
 	}
 }
 
+void NUMmatrix_standardizeRows (double **a, integer rb, integer re, integer cb, integer ce) {
+	integer n = ce - cb + 1;
+	if (n < 1) {
+		return;
+	}
+	for (integer i = rb; i <= re; i ++) {
+		double mean, stdev = undefined;
+		numvec x {& a [i][cb] - 1, n};
+		sum_mean_sumsq_variance_stdev_scalar (x, nullptr, & mean, nullptr, nullptr, & stdev);
+		stdev = isdefined (stdev) ? stdev : 1.0;
+		for (integer j = cb; j <= ce; j ++) {
+			a [i][j] = (a [i][j] - mean) / stdev;
+		}
+	}
+}
+
 void NUMstandardizeRows (double **a, long rb, long re, long cb, long ce) {
 	long n = ce - cb + 1;
 	if (n < 2) {
@@ -315,7 +332,7 @@ void NUMvector_avevar (double *a, long n, double *p_mean, double *p_var) {
 
 			var = (var - eps * eps / n);
 		} else {
-			var = NUMundefined;
+			var = undefined;
 		}
 		*p_var = var;
 	}
@@ -347,7 +364,7 @@ void NUMcolumn_avevar (double **a, long nr, long nc, long icol, double *p_mean,
 
 			var = (var - eps * eps / nr);
 		} else {
-			var = NUMundefined;
+			var = undefined;
 		}
 		*p_var = var;
 	}
@@ -390,9 +407,9 @@ void NUMcolumn2_avevar (double **a, long nr, long nc, long icol1, long icol2, do
 			var1 = (var1 - eps1 * eps1 / nr);
 			var2 = (var2 - eps2 * eps2 / nr);;
 		} else {
-			var1 = NUMundefined;
-			var2 = NUMundefined;
-			covar = NUMundefined;
+			var1 = undefined;
+			var2 = undefined;
+			covar = undefined;
 		}
 		if (p_var1) {
 			*p_var1 = var1;
@@ -442,7 +459,7 @@ void NUMcovarianceFromColumnCentredMatrix (double **x, long nrows, long ncols, l
 }
 
 double NUMmultivariateKurtosis (double **x, long nrows, long ncols, int method) {
-	double kurt = NUMundefined;
+	double kurt = undefined;
 	if (nrows < 5) {
 		return kurt;
 	}
@@ -545,8 +562,8 @@ void NUMlocate (double *xx, long n, double x, long *index) {
 	Kruskal's algorithm for monotone regression (and much simpler).
 	Regression is ascending
 */
-void NUMmonotoneRegression (const double x[], long n, double xs[]) {
-	double xt = NUMundefined; // Only to stop gcc complaining "may be used unitialized"
+void NUMmonotoneRegression (const double x [], long n, double xs []) {
+	double xt = undefined;   // only to stop gcc from complaining "may be used uninitialized"
 
 	for (long i = 1; i <= n; i++) {
 		xs[i] = x[i];
@@ -559,7 +576,8 @@ void NUMmonotoneRegression (const double x[], long n, double xs[]) {
 		double sum = xs[i];
 		long nt = 1;
 		for (long j = 1; j <= i - 1; j++) {
-			sum += xs[i - j]; nt++;
+			sum += xs[i - j];
+			nt ++;
 			xt = sum / nt; // i >= 2 -> xt always gets a value
 			if (j < i - 1 && xt >= xs[i - j - 1]) {
 				break;
@@ -1473,7 +1491,7 @@ double NUMwilksLambda (double *lambda, long from, long to) {
 double NUMfactln (int n) {
 	static double table[101];
 	if (n < 0) {
-		return NUMundefined;
+		return undefined;
 	}
 	if (n <= 1) {
 		return 0;
@@ -1499,7 +1517,7 @@ void NUMnrbis (void (*f) (double x, double *fx, double *dfx, void *closure), dou
 	}
 
 	if ((fl > 0.0 && fh > 0.0) || (fl < 0.0 && fh < 0.0)) {
-		*root = NUMundefined;
+		*root = undefined;
 		return;
 	}
 
@@ -1553,25 +1571,25 @@ double NUMridders (double (*f) (double x, void *closure), double x1, double x2,
 	/* There is still a problem with this implementation:
 		tol may be zero;
 	*/
-	double x3, x4, d, root = NUMundefined, tol;
+	double x3, x4, d, root = undefined, tol;
 	long itermax = 100;
 
 	double f1 = f (x1, closure);
 	if (f1 == 0.0) {
 		return x1;
 	}
-	if (f1 == NUMundefined) {
-		return NUMundefined;
+	if (isundef (f1)) {
+		return undefined;
 	}
 	double f2 = f (x2, closure);
 	if (f2 == 0.0) {
 		return x2;
 	}
-	if (f2 == NUMundefined) {
-		return NUMundefined;
+	if (isundef (f2)) {
+		return undefined;
 	}
-	if ( (f1 < 0.0 && f2 < 0.0) || (f1 > 0.0 && f2 > 0.0)) {
-		return NUMundefined;
+	if ((f1 < 0.0 && f2 < 0.0) || (f1 > 0.0 && f2 > 0.0)) {
+		return undefined;
 	}
 
 	for (long iter = 1; iter <= itermax; iter++) {
@@ -1580,8 +1598,8 @@ double NUMridders (double (*f) (double x, void *closure), double x1, double x2,
 		if (f3 == 0.0) {
 			return x3;
 		}
-		if (f3 == NUMundefined) {
-			return NUMundefined;
+		if (isundef (f3)) {
+			return undefined;
 		}
 
 		// New guess: x4 = x3 + (x3 - x1) * sign(f1 - f2) * f3 / sqrt(f3^2 - f1*f2)
@@ -1589,7 +1607,7 @@ double NUMridders (double (*f) (double x, void *closure), double x1, double x2,
 		d = f3 * f3 - f1 * f2;
 		if (d < 0.0) {
 			Melder_warning (U"d < 0 in ridders (iter = ", iter, U").");
-			return NUMundefined;
+			return undefined;
 		}
 
 		if (d == 0.0) {
@@ -1660,8 +1678,8 @@ double NUMridders (double (*f) (double x, void *closure), double x1, double x2,
 				if (f4 == 0.0) {
 					return root;
 				}
-				if (f4 == NUMundefined) {
-					return NUMundefined;
+				if (isundef (f4)) {
+					return undefined;
 				}
 				if ((f1 > f2) == (d > 0.0) /* pb: instead of x3 < x4 */) {
 					if (SIGN (f3, f4) != f3) {
@@ -1703,11 +1721,11 @@ double NUMlogNormalQ (double x, double zeta, double sigma) {
 
 double NUMstudentP (double t, double df) {
 	if (df < 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	double ib = NUMincompleteBeta (0.5 * df, 0.5, df / (df + t * t));
-	if (ib == NUMundefined) {
-		return NUMundefined;
+	if (isundef (ib)) {
+		return undefined;
 	}
 	ib *= 0.5;
 	return t < 0.0 ? ib : 1.0 - ib;
@@ -1715,11 +1733,11 @@ double NUMstudentP (double t, double df) {
 
 double NUMstudentQ (double t, double df) {
 	if (df < 1) {
-		return NUMundefined;
+		return undefined;
 	}
 	double ib = NUMincompleteBeta (0.5 * df, 0.5, df / (df + t * t));
-	if (ib == NUMundefined) {
-		return NUMundefined;
+	if (isundef (ib)) {
+		return undefined;
 	}
 	ib *= 0.5;
 	return t > 0.0 ? ib : 1.0 - ib;
@@ -1727,25 +1745,25 @@ double NUMstudentQ (double t, double df) {
 
 double NUMfisherP (double f, double df1, double df2) {
 	if (f < 0.0 || df1 < 1.0 || df2 < 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	double ib = NUMincompleteBeta (0.5 * df2, 0.5 * df1, df2 / (df2 + f * df1));
-	if (ib == NUMundefined) {
-		return NUMundefined;
+	if (isundef (ib)) {
+		return undefined;
 	}
 	return 1.0 - ib;
 }
 
 double NUMfisherQ (double f, double df1, double df2) {
 	if (f < 0.0 || df1 < 1.0 || df2 < 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	if (Melder_debug == 28) {
 		return NUMincompleteBeta (0.5 * df2, 0.5 * df1, df2 / (df2 + f * df1));
 	} else {
 		double result = gsl_cdf_fdist_Q (f, df1, df2);
 		if (isnan (result)) {
-			return NUMundefined;
+			return undefined;
 		}
 		return result;
 	}
@@ -1754,7 +1772,7 @@ double NUMfisherQ (double f, double df1, double df2) {
 double NUMinvGaussQ (double p) {
 	double pc = p;
 	if (p <= 0.0 || p >= 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	if (p > 0.5) {
 		pc = 1.0 - p;
@@ -1768,15 +1786,15 @@ double NUMinvGaussQ (double p) {
 static double studentQ_func (double x, void *voidParams) {
 	struct pdf1_struct *params = (struct pdf1_struct *) voidParams;
 	double q = NUMstudentQ (x, params -> df);
-	return q == NUMundefined ? NUMundefined : q - params -> p;
+	return ( isundef (q) ? undefined : q - params -> p );
 }
 
 double NUMinvStudentQ (double p, double df) {
 	struct pdf1_struct params;
-	double pc = p > 0.5 ? 1.0 - p : p, xmin, xmax = 1.0, x;
+	double pc = ( p > 0.5 ? 1.0 - p : p ), xmin, xmax = 1.0, x;
 
 	if (p < 0.0 || p >= 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 
 
@@ -1784,8 +1802,8 @@ double NUMinvStudentQ (double p, double df) {
 
 	for (;;) {
 		double q = NUMstudentQ (xmax, df);
-		if (q == NUMundefined) {
-			return NUMundefined;
+		if (isundef (q)) {
+			return undefined;
 		}
 		if (q < pc) {
 			break;
@@ -1793,24 +1811,24 @@ double NUMinvStudentQ (double p, double df) {
 		xmax *= 2.0;
 	}
 
-	xmin = xmax > 1.0 ? xmax / 2.0 : 0.0;
+	xmin = ( xmax > 1.0 ? xmax / 2.0 : 0.0 );
 
 	// Find zero of f(x) with Ridders' method.
 
 	params. df = df;
 	params. p = pc;
 	x = NUMridders (studentQ_func, xmin, xmax, & params);
-	if (x == NUMundefined) {
-		return NUMundefined;
+	if (isundef (x)) {
+		return undefined;
 	}
 
-	return p > 0.5 ? -x : x;
+	return ( p > 0.5 ? -x : x );
 }
 
 static double chiSquareQ_func (double x, void *voidParams) {
 	struct pdf1_struct *params = (struct pdf1_struct *) voidParams;
 	double q = NUMchiSquareQ (x, params -> df);
-	return q == NUMundefined ? NUMundefined : q - params -> p;
+	return ( isundef (q) ? undefined : q - params -> p );
 }
 
 double NUMinvChiSquareQ (double p, double df) {
@@ -1818,22 +1836,22 @@ double NUMinvChiSquareQ (double p, double df) {
 	double xmin, xmax = 1;
 
 	if (p < 0.0 || p >= 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 
 	// Bracket the function f(x) = NUMchiSquareQ (x, df) - p.
 
 	for (;;) {
 		double q = NUMchiSquareQ (xmax, df);
-		if (q == NUMundefined) {
-			return NUMundefined;
+		if (isundef (q)) {
+			return undefined;
 		}
 		if (q < p) {
 			break;
 		}
 		xmax *= 2.0;
 	}
-	xmin = xmax > 1.0 ? xmax / 2.0 : 0.0;
+	xmin = ( xmax > 1.0 ? xmax / 2.0 : 0.0 );
 
 	// Find zero of f(x) with Ridders' method.
 
@@ -1845,12 +1863,12 @@ double NUMinvChiSquareQ (double p, double df) {
 static double fisherQ_func (double x, void *voidParams) {
 	struct pdf2_struct *params = (struct pdf2_struct *) voidParams;
 	double q = NUMfisherQ (x, params -> df1, params -> df2);
-	return q == NUMundefined ? NUMundefined : q - params -> p;
+	return ( isundef (q) ? undefined : q - params -> p );
 }
 
 double NUMinvFisherQ (double p, double df1, double df2) {
 	if (p <= 0.0 || p > 1.0 || df1 < 1.0 || df2 < 1.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	if (Melder_debug == 29) {
 		//if (p == 1.0) return 0.0;
@@ -1866,14 +1884,14 @@ double NUMinvFisherQ (double p, double df1, double df2) {
 		params. df2 = df2;
 		for (;;) {
 			double q = NUMfisherQ (top, df1, df2);
-			if (q == NUMundefined) {
-				return NUMundefined;
+			if (isundef (q)) {
+				return undefined;
 			}
 			if (q < p) {
 				break;
 			}
 			if (top > 0.9e300) {
-				return NUMundefined;
+				return undefined;
 			}
 			top *= 1e9;
 		}
@@ -1884,13 +1902,13 @@ double NUMinvFisherQ (double p, double df1, double df2) {
 double NUMbeta2 (double z, double w) {
 	gsl_sf_result result;
 	int status = gsl_sf_beta_e (z, w, &result);
-	return status == GSL_SUCCESS ? result.val : NUMundefined;
+	return status == GSL_SUCCESS ? result.val : undefined;
 }
 
 double NUMlnBeta (double a, double b) {
 	gsl_sf_result result;
 	int status = gsl_sf_lnbeta_e (a, b, &result);
-	return status == GSL_SUCCESS ? result.val : NUMundefined;
+	return status == GSL_SUCCESS ? result.val : undefined;
 }
 
 double NUMnormalityTest_HenzeZirkler (double **data, long n, long p, double *beta, double *tnb, double *lnmu, double *lnvar) {
@@ -1901,9 +1919,9 @@ double NUMnormalityTest_HenzeZirkler (double **data, long n, long p, double *bet
 	double beta2 = *beta * *beta, beta4 = beta2 * beta2, beta8 = beta4 * beta4;
 	double gamma = 1.0 + 2.0 * beta2, gamma2 = gamma * gamma, gamma4 = gamma2 * gamma2;
 	double delta = 1.0 + beta2 * (4.0 + 3.0 * beta2), delta2 = delta * delta;
-	double prob = NUMundefined;
+	double prob = undefined;
 
-	*tnb = *lnmu = *lnvar = NUMundefined;
+	*tnb = *lnmu = *lnvar = undefined;
 
 	if (n < 2 || p < 1) {
 		return prob;
@@ -1955,42 +1973,42 @@ double NUMnormalityTest_HenzeZirkler (double **data, long n, long p, double *bet
 
 double NUMmelToHertz3 (double mel) {
 	if (mel < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return mel < 1000.0 ? mel : 1000.0 * (exp (mel * log10 (2.0) / 1000.0) - 1.0);
 }
 
 double NUMhertzToMel3 (double hz) {
 	if (hz < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return hz < 1000.0 ? hz : 1000.0 * log10 (1.0 + hz / 1000.0) / log10 (2.0);
 }
 
 double NUMmelToHertz2 (double mel) {
 	if (mel < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 700.0 * (pow (10.0, mel / 2595.0) - 1.0);
 }
 
 double NUMhertzToMel2 (double hz) {
 	if (hz < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 2595.0 * log10 (1.0 + hz / 700.0);
 }
 
 double NUMhertzToBark_traunmueller (double hz) {
 	if (hz < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 26.81 * hz / (1960.0 + hz) - 0.53;
 }
 
 double NUMbarkToHertz_traunmueller (double bark) {
 	if (bark < 0.0 || bark > 26.28) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 1960.0 * (bark + 0.53) / (26.28 - bark);
 }
@@ -2001,14 +2019,14 @@ double NUMbarkToHertz_schroeder (double bark) {
 
 double NUMbarkToHertz_zwickerterhardt (double hz) {
 	if (hz < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 13.0 * atan (0.00076 * hz) + 3.5 * atan (hz / 7500.0);
 }
 
 double NUMhertzToBark_schroeder (double hz) {
 	if (hz < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	double h650 = hz / 650.0;
 	return 7.0 * log (h650 + sqrt (1.0 + h650 * h650));
@@ -2016,14 +2034,14 @@ double NUMhertzToBark_schroeder (double hz) {
 
 double NUMbarkToHertz2 (double bark) {
 	if (bark < 0.0) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 650.0 * sinh (bark / 7.0);
 }
 
 double NUMhertzToBark2 (double hz) {
 	if (hz < 0) {
-		return NUMundefined;
+		return undefined;
 	}
 	double h650 = hz / 650.0;
 	return 7.0 * log (h650 + sqrt (1.0 + h650 * h650));
@@ -2235,13 +2253,13 @@ void NUMsplint (double xa[], double ya[], double y2a[], long n, double x, double
 double NUMsinc (const double x) {
 	struct gsl_sf_result_struct result;
 	int status = gsl_sf_sinc_e (x / NUMpi, &result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return status == GSL_SUCCESS ? result. val : undefined;
 }
 
 double NUMsincpi (const double x) {
 	struct gsl_sf_result_struct result;
 	int status = gsl_sf_sinc_e (x, &result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return status == GSL_SUCCESS ? result. val : undefined;
 }
 
 /* Does the line segment from (x1,y1) to (x2,y2) intersect with the line segment from (x3,y3) to (x4,y4)? */
@@ -2644,7 +2662,7 @@ void NUMlineFit_theil (double *x, double *y, long numberOfPoints, double *p_m, d
 		 */
 		double m, intercept;
 		if (numberOfPoints <= 0) {
-			m = intercept = NUMundefined;
+			m = intercept = undefined;
 		} else if (numberOfPoints == 1) {
 			intercept = y[1];
 			m = 0;
@@ -3120,14 +3138,14 @@ Finish:
 
 double NUMrandomBinomial_real (double p, long n) {
 	if (p < 0.0 || p > 1.0 || n < 0) {
-		return NUMundefined;
+		return undefined;
 	} else {
 		return (double) NUMrandomBinomial (p, n);
 	}
 }
 
 void NUMlngamma_complex (double zr, double zi, double *lnr, double *arg) {
-	double ln_re = NUMundefined, ln_arg = NUMundefined;
+	double ln_re = undefined, ln_arg = undefined;
 	gsl_sf_result gsl_lnr, gsl_arg;
 	if (gsl_sf_lngamma_complex_e (zr, zi, & gsl_lnr, & gsl_arg)) {
 		ln_re = gsl_lnr.val; ln_arg = gsl_arg.val;
diff --git a/dwsys/NUM2.h b/dwsys/NUM2.h
index 464584e..1d5f080 100644
--- a/dwsys/NUM2.h
+++ b/dwsys/NUM2.h
@@ -24,7 +24,7 @@
 */
 
 #include <limits.h>
-#include "../num/NUM.h"
+#include "melder.h"
 #include "regularExp.h"
 
 /* machine precision */
@@ -41,7 +41,7 @@ int NUMstring_containsPrintableCharacter (const char32 *s);
 
 void NUMstring_chopWhiteSpaceAtExtremes_inline (char32 *string);
 
-double *NUMstring_to_numbers (const char32 *s, long *numbers_found);
+real * NUMstring_to_numbers (const char32 *s, integer *numbers_found);
 /* return array with the number of numbers found */
 
 /*
@@ -730,7 +730,7 @@ void NUMnrbis (void (*f)(double x, double *fx, double *dfx, void *closure), doub
 	Find the root of a function between xmin and xmax.
 	Method: Newton-Raphson with bisection (i.e., derivative is known!).
 	Error condition:
-		return NUMundefined if root not bracketed.
+		return undefined if root not bracketed.
 */
 
 double NUMridders (double (*f) (double x, void *closure), double xmin, double xmax, void *closure);
diff --git a/dwsys/NUMcomplex.cpp b/dwsys/NUMcomplex.cpp
index d72c332..948e50f 100644
--- a/dwsys/NUMcomplex.cpp
+++ b/dwsys/NUMcomplex.cpp
@@ -25,7 +25,7 @@
 //		gamma function. Technical report, Dept. of Mathematics, Univ. of California, Berkeley, 1987.
 
 static double norm1 (std::complex<double> *x) {
-	return fabs (real(*x)) + fabs (imag(*x));
+	return fabs (x -> real()) + fabs (imag(*x));
 }
 
 static void term (std::complex<double> *alpha, std::complex<double> *x, long i, std::complex<double> *p, std::complex<double> *q) {
@@ -47,7 +47,7 @@ static void term (std::complex<double> *alpha, std::complex<double> *x, long i,
 	std::complex<double> cdlx = log (*x);
 	// If (1-x**alphai) = -x**alphai,
 	// then change the inductive scheme to avoid overflow.
-	if (real (alphai * cdlx) > xlim && i != 0) {
+	if ((alphai * cdlx).real() > xlim && i != 0) {
 			*p *= (alphai - 1.0) / alphai;
 			*q *= - *x / di;
 		return;
@@ -95,7 +95,7 @@ static void cdhs (std::complex<double> *alpha, std::complex<double> *x, std::com
 
 static void cdh (std::complex<double> *alpha, std::complex<double> *x, std::complex<double> *result) {
 	std::complex<double> one (1.0, 0.0);
-	long n = (long) real (*alpha - *x);
+	long n = (long) (*alpha - *x).real();
 	if (n > 0) {
 		std::complex<double> cn = n + 1;
 		std::complex<double> alpha1 = *alpha - cn;
@@ -120,10 +120,10 @@ void NUMincompleteGammaFunction (double alpha_re, double alpha_im, double x_re,
 	double xlim = 1.0;
 	long ibuf = 34;
 	std::complex<double> re = 0.36787944117144232, one = 1.0, p, q, r;
-	if (norm1 (& x) < xlim || real (x) < 0.0 && fabs (imag (x)) < xlim) {
+	if (norm1 (& x) < xlim || x.real() < 0.0 && fabs (imag (x)) < xlim) {
 		cdh (& alpha, & one, & r);
 		result = re / r;
-		long ilim = real (x / re);
+		long ilim = (long) (x / re).real();
 		for (long i = 0; i <= ibuf - ilim; i++) {
 			term (& alpha, & x, i, & p, & q);
 			result += p * q;
diff --git a/dwsys/NUMfft_d.cpp b/dwsys/NUMfft_d.cpp
index 9beae6c..469b00a 100644
--- a/dwsys/NUMfft_d.cpp
+++ b/dwsys/NUMfft_d.cpp
@@ -24,8 +24,6 @@
 #include "NUM2.h"
 #include "melder.h"
 
-#define my me ->
-
 #define FFT_DATA_TYPE double
 #include "NUMfft_core.h"
 
diff --git a/dwsys/NUMhuber.cpp b/dwsys/NUMhuber.cpp
index 80f45df..aef5385 100644
--- a/dwsys/NUMhuber.cpp
+++ b/dwsys/NUMhuber.cpp
@@ -26,7 +26,7 @@
 void NUMmad (double *x, long n, double *location, int wantlocation, double *mad, double *work) {
 	double *tmp = work;
 
-	*mad = NUMundefined;
+	*mad = undefined;
 	if (n < 1) {
 		Melder_throw (U"The dimension must be at least 1");
 	}
diff --git a/dwsys/NUMlapack.cpp b/dwsys/NUMlapack.cpp
index 9b57fb6..a96cab8 100644
--- a/dwsys/NUMlapack.cpp
+++ b/dwsys/NUMlapack.cpp
@@ -22,10 +22,9 @@
  djmw 20071022 NUMmatricesToUpperTriangularForms now inializes l=0
 */
 
-#include "NUM.h"
+#include "melder.h"
 #include "NUMlapack.h"
 #include "NUMmachar.h"
-#include "melder.h"
 
 #define MAX(m,n) ((m) > (n) ? (m) : (n))
 #define MIN(m,n) ((m) < (n) ? (m) : (n))
diff --git a/dwsys/NUMmathlib.cpp b/dwsys/NUMmathlib.cpp
index 5f6793b..24ee2c1 100644
--- a/dwsys/NUMmathlib.cpp
+++ b/dwsys/NUMmathlib.cpp
@@ -43,26 +43,26 @@
 
 #define R_Q_P01_boundaries(p, _LEFT_, _RIGHT_)		\
     if (log_p) {					\
-		if(p > 0)					\
-	    	return NUMundefined;				\
-		if(p == 0) /* upper bound*/			\
+		if (p > 0.0)					\
+	    	return undefined;				\
+		if (p == 0.0) /* upper bound*/			\
 	    	return lower_tail ? _RIGHT_ : _LEFT_;	\
-		if(p == NUMundefined)	/* cannot occur*/		\
+		if (isundef (p))	/* cannot occur*/		\
 	    	return lower_tail ? _LEFT_ : _RIGHT_;	\
     } else { /* !log_p */					\
-		if(p < 0 || p > 1)				\
-			return NUMundefined;				\
-		if(p == 0)					\
-		return lower_tail ? _LEFT_ : _RIGHT_;	\
-		if(p == 1)					\
+		if (p < 0.0 || p > 1.0)				\
+			return undefined;				\
+		if (p == 0.0)					\
+			return lower_tail ? _LEFT_ : _RIGHT_;	\
+		if (p == 1.0)					\
 	    	return lower_tail ? _RIGHT_ : _LEFT_;	\
     }
 
 #define R_D_Lval(p)	(lower_tail ? (p) : (0.5 - (p) + 0.5))
 #define R_DT_qIv(p)	(log_p ? (lower_tail ? exp(p) : - expm1(p)) : R_D_Lval(p))
 
-#define R_D__0	(log_p ? NUMundefined : 0.)		/* 0 */
-#define R_D__1	(log_p ? 0. : 1.)			/* 1 */
+#define R_D__0	(log_p ? undefined : 0.0)		/* 0 */
+#define R_D__1	(log_p ? 0.0 : 1.0)			/* 1 */
 #define R_DT_0	(lower_tail ? R_D__0 : R_D__1)		/* 0 */
 #define R_DT_1	(lower_tail ? R_D__1 : R_D__0)		/* 1 */
 #define R_D_val(x)	(log_p	? log(x) : (x))
@@ -114,34 +114,33 @@ static double wprob(double w, double rr, double cc)
     const static double wincr1 = 2.;
     const static double wincr2 = 3.;
     const static double xleg[ihalf] = {
-	0.981560634246719250690549090149,
-	0.904117256370474856678465866119,
-	0.769902674194304687036893833213,
-	0.587317954286617447296702418941,
-	0.367831498998180193752691536644,
-	0.125233408511468915472441369464
+		0.981560634246719250690549090149,
+		0.904117256370474856678465866119,
+		0.769902674194304687036893833213,
+		0.587317954286617447296702418941,
+		0.367831498998180193752691536644,
+		0.125233408511468915472441369464
     };
     const static double aleg[ihalf] = {
-	0.047175336386511827194615961485,
-	0.106939325995318430960254718194,
-	0.160078328543346226334652529543,
-	0.203167426723065921749064455810,
-	0.233492536538354808760849898925,
-	0.249147045813402785000562436043
+		0.047175336386511827194615961485,
+		0.106939325995318430960254718194,
+		0.160078328543346226334652529543,
+		0.203167426723065921749064455810,
+		0.233492536538354808760849898925,
+		0.249147045813402785000562436043
     };
     double a, ac, pr_w, b, binc, c, cc1,
 	pminus, pplus, qexpo, qsqz, rinsum, wi, wincr, xx;
     long double blb, bub, einsum, elsum;
     int j, jj;
 
-
     qsqz = w * 0.5;
 
     /* if w >= 16 then the integral lower bound (occurs for c=20) */
     /* is 0.99999999999995 so return a value of 1. */
 
     if (qsqz >= bb)
-	return 1.0;
+		return 1.0;
 
     /* find (f(w/2) - 1) ^ cc */
     /* (first term in integral of hartley's form). */
@@ -150,17 +149,17 @@ static double wprob(double w, double rr, double cc)
     pr_w = 2 * NUMgaussP (qsqz) - 1.0;
     /* if pr_w ^ cc < 2e-22 then set pr_w = 0 */
     if (pr_w >= exp(C2 / cc))
-	pr_w = pow(pr_w, cc);
+		pr_w = pow(pr_w, cc);
     else
-	pr_w = 0.0;
+		pr_w = 0.0;
 
     /* if w is large then the second component of the */
     /* integral is small, so fewer intervals are needed. */
 
     if (w > wlar)
-	wincr = wincr1;
+		wincr = wincr1;
     else
-	wincr = wincr2;
+		wincr = wincr2;
 
     /* find the integral of second term of hartley's form */
     /* for the integral of the range for equal-length */
@@ -179,57 +178,57 @@ static double wprob(double w, double rr, double cc)
 
     cc1 = cc - 1.0;
     for (wi = 1; wi <= wincr; wi++) {
-	elsum = 0.0;
-	a = (double)(0.5 * (bub + blb));
-
-	/* legendre quadrature with order = nleg */
-
-	b = (double)(0.5 * (bub - blb));
-
-	for (jj = 1; jj <= nleg; jj++) {
-	    if (ihalf < jj) {
-		j = (nleg - jj) + 1;
-		xx = xleg[j-1];
-	    } else {
-		j = jj;
-		xx = -xleg[j-1];
-	    }
-	    c = b * xx;
-	    ac = a + c;
-
-	    /* if exp(-qexpo/2) < 9e-14, */
-	    /* then doesn't contribute to integral */
-
-	    qexpo = ac * ac;
-	    if (qexpo > C3)
-		break;
-
-	    pplus = 2 * NUMgaussP (ac); // djmw: 2 * pnorm(ac, 0., 1., 1,0);
-	    pminus= 2 * NUMgaussP (ac - w); // djmw: 2 * pnorm(ac, w,  1., 1,0);
-
-	    /* if rinsum ^ (cc-1) < 9e-14, */
-	    /* then doesn't contribute to integral */
-
-	    rinsum = (pplus * 0.5) - (pminus * 0.5);
-	    if (rinsum >= exp(C1 / cc1)) {
-		rinsum = (aleg[j-1] * exp(-(0.5 * qexpo))) * pow(rinsum, cc1);
-		elsum += rinsum;
-	    }
-	}
-	elsum *= (((2.0 * b) * cc) * NUM1_sqrt2pi);
-	einsum += elsum;
-	blb = bub;
-	bub += binc;
+		elsum = 0.0;
+		a = double (0.5 * (bub + blb));
+
+		/* legendre quadrature with order = nleg */
+
+		b = double (0.5 * (bub - blb));
+
+		for (jj = 1; jj <= nleg; jj ++) {
+			if (ihalf < jj) {
+				j = (nleg - jj) + 1;
+				xx = xleg [j-1];
+			} else {
+				j = jj;
+				xx = -xleg [j-1];
+			}
+			c = b * xx;
+			ac = a + c;
+
+			/* if exp(-qexpo/2) < 9e-14, */
+			/* then doesn't contribute to integral */
+
+			qexpo = ac * ac;
+			if (qexpo > C3)
+			break;
+
+			pplus = 2 * NUMgaussP (ac); // djmw: 2 * pnorm(ac, 0., 1., 1,0);
+			pminus= 2 * NUMgaussP (ac - w); // djmw: 2 * pnorm(ac, w,  1., 1,0);
+
+			/* if rinsum ^ (cc-1) < 9e-14, */
+			/* then doesn't contribute to integral */
+
+			rinsum = pplus * 0.5 - pminus * 0.5;
+			if (rinsum >= exp (C1 / cc1)) {
+				rinsum = aleg[j-1] * exp(-(0.5 * qexpo)) * pow(rinsum, cc1);
+				elsum += rinsum;
+			}
+		}
+		elsum *= 2.0 * b * cc * NUM1_sqrt2pi;
+		einsum += elsum;
+		blb = bub;
+		bub += binc;
     }
 
     /* if pr_w ^ rr < 9e-14, then return 0 */
     pr_w += (double) einsum;
     if (pr_w <= exp(C1 / rr))
-	return 0.;
+		return 0.0;
 
     pr_w = pow(pr_w, rr);
-    if (pr_w >= 1.)/* 1 was iMax was eps */
-	return 1.;
+    if (pr_w >= 1.0)   // 1 was iMax was eps
+		return 1.0;
     return pr_w;
 } /* wprob() */
 
@@ -311,46 +310,46 @@ static double ptukey(double q, double rr, double cc, double df, int lower_tail,
     const static double ulen3 = 0.25;
     const static double ulen4 = 0.125;
     const static double xlegq[ihalfq] = {
-	0.989400934991649932596154173450,
-	0.944575023073232576077988415535,
-	0.865631202387831743880467897712,
-	0.755404408355003033895101194847,
-	0.617876244402643748446671764049,
-	0.458016777657227386342419442984,
-	0.281603550779258913230460501460,
-	0.950125098376374401853193354250e-1
+		0.989400934991649932596154173450,
+		0.944575023073232576077988415535,
+		0.865631202387831743880467897712,
+		0.755404408355003033895101194847,
+		0.617876244402643748446671764049,
+		0.458016777657227386342419442984,
+		0.281603550779258913230460501460,
+		0.950125098376374401853193354250e-1
     };
     const static double alegq[ihalfq] = {
-	0.271524594117540948517805724560e-1,
-	0.622535239386478928628438369944e-1,
-	0.951585116824927848099251076022e-1,
-	0.124628971255533872052476282192,
-	0.149595988816576732081501730547,
-	0.169156519395002538189312079030,
-	0.182603415044923588866763667969,
-	0.189450610455068496285396723208
+		0.271524594117540948517805724560e-1,
+		0.622535239386478928628438369944e-1,
+		0.951585116824927848099251076022e-1,
+		0.124628971255533872052476282192,
+		0.149595988816576732081501730547,
+		0.169156519395002538189312079030,
+		0.182603415044923588866763667969,
+		0.189450610455068496285396723208
     };
     double ans, f2, f21, f2lf, ff4, otsum, qsqz, rotsum, t1, twa1, ulen, wprb;
     int i, j, jj;
 
-	if (q == NUMundefined || rr == NUMundefined || cc == NUMundefined || df == NUMundefined) {
-		return NUMundefined;
+	if (isundef (q) || isundef (rr) || isundef (cc) || isundef (df)) {
+		return undefined;
 	}
 
-    if (q <= 0)
-	return R_DT_0;
+    if (q <= 0.0)
+		return R_DT_0;
 
     /* df must be > 1 */
     /* there must be at least two values */
 
     if (df < 2 || rr < 1 || cc < 2) {
-		return NUMundefined;
+		return undefined;
 	}
 
-   // if(q == NUMundefined) { return R_DT_1; }
+   // if (isundef (q) { return R_DT_1; }
 
     if (df > dlarg)
-	return R_DT_val(wprob(q, rr, cc));
+		return R_DT_val(wprob(q, rr, cc));
 
     /* calculate leading constant */
 
@@ -369,64 +368,61 @@ static double ptukey(double q, double rr, double cc, double df, int lower_tail,
     else if (df <= deigh)	ulen = ulen3;
     else			ulen = ulen4;
 
-    f2lf += log(ulen);
+    f2lf += log (ulen);
 
     /* integrate over each subinterval */
 
     ans = 0.0;
 
     for (i = 1; i <= 50; i++) {
-	otsum = 0.0;
-
-	/* legendre quadrature with order = nlegq */
-	/* nodes (stored in xlegq) are symmetric around zero. */
-
-	twa1 = (2 * i - 1) * ulen;
-
-	for (jj = 1; jj <= nlegq; jj++) {
-	    if (ihalfq < jj) {
-		j = jj - ihalfq - 1;
-		t1 = (f2lf + (f21 * log(twa1 + (xlegq[j] * ulen))))
-		    - (((xlegq[j] * ulen) + twa1) * ff4);
-	    } else {
-		j = jj - 1;
-		t1 = (f2lf + (f21 * log(twa1 - (xlegq[j] * ulen))))
-		    + (((xlegq[j] * ulen) - twa1) * ff4);
-
-	    }
-
-	    /* if exp(t1) < 9e-14, then doesn't contribute to integral */
-	    if (t1 >= eps1) {
-		if (ihalfq < jj) {
-		    qsqz = q * sqrt(((xlegq[j] * ulen) + twa1) * 0.5);
-		} else {
-		    qsqz = q * sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5);
+		otsum = 0.0;
+
+		/* legendre quadrature with order = nlegq */
+		/* nodes (stored in xlegq) are symmetric around zero. */
+
+		twa1 = (2 * i - 1) * ulen;
+
+		for (jj = 1; jj <= nlegq; jj ++) {
+			if (ihalfq < jj) {
+				j = jj - ihalfq - 1;
+				t1 = f2lf + f21 * log (twa1 + xlegq[j] * ulen) - (xlegq[j] * ulen + twa1) * ff4;
+			} else {
+				j = jj - 1;
+				t1 = f2lf + f21 * log (twa1 - xlegq[j] * ulen) + (xlegq[j] * ulen - twa1) * ff4;
+			}
+
+			/* if exp(t1) < 9e-14, then doesn't contribute to integral */
+			if (t1 >= eps1) {
+				if (ihalfq < jj) {
+					qsqz = q * sqrt ((xlegq[j] * ulen + twa1) * 0.5);
+				} else {
+					qsqz = q * sqrt ((-(xlegq[j] * ulen) + twa1) * 0.5);
+				}
+
+				/* call wprob to find integral of range portion */
+
+				wprb = wprob (qsqz, rr, cc);
+				rotsum = wprb * alegq [j] * exp (t1);
+				otsum += rotsum;
+			}
+			/* end legendre integral for interval i */
+			/* L200: */
 		}
 
-		/* call wprob to find integral of range portion */
-
-		wprb = wprob(qsqz, rr, cc);
-		rotsum = (wprb * alegq[j]) * exp(t1);
-		otsum += rotsum;
-	    }
-	    /* end legendre integral for interval i */
-	    /* L200: */
-	}
+		/* if integral for interval i < 1e-14, then stop.
+		 * However, in order to avoid small area under left tail,
+		 * at least  1 / ulen  intervals are calculated.
+		 */
+		if (i * ulen >= 1.0 && otsum <= eps2)
+			break;
 
-	/* if integral for interval i < 1e-14, then stop.
-	 * However, in order to avoid small area under left tail,
-	 * at least  1 / ulen  intervals are calculated.
-	 */
-	if (i * ulen >= 1.0 && otsum <= eps2)
-	    break;
+		/* end of interval i */
+		/* L330: */
 
-	/* end of interval i */
-	/* L330: */
-
-	ans += otsum;
+		ans += otsum;
     }
 
-    if(otsum > eps2) { /* not converged */
+    if (otsum > eps2) { /* not converged */
 		Melder_throw (U"Not converged");
     }
     if (ans > 1.)
@@ -554,17 +550,17 @@ static double qtukey(double p, double rr, double cc, double df, int lower_tail,
     double ans = 0.0, valx0, valx1, x0, x1, xabs;
     int iter;
 
-	if (p == NUMundefined || rr == NUMundefined || cc == NUMundefined || df == NUMundefined) {
-		return NUMundefined;
+	if (isundef (p) || isundef (rr) || isundef (cc) || isundef (df)) {
+		return undefined;
 	}
     /* df must be > 1 ; there must be at least two values */
-    if (df < 2 || rr < 1 || cc < 2) {
-		return NUMundefined;
+    if (df < 2.0 || rr < 1.0 || cc < 2.0) {
+		return undefined;
 	}
 
-    //R_Q_P01_boundaries(p, 0, ML_POSINF);
-	R_Q_P01_boundaries(p, 0, NUMundefined);
-    p = R_DT_qIv(p); /* lower_tail,non-log "p" */
+    //R_Q_P01_boundaries (p, 0.0, ML_POSINF);
+	R_Q_P01_boundaries (p, 0.0, undefined);
+    p = R_DT_qIv (p); /* lower_tail,non-log "p" */
 
     /* Initial value */
 
@@ -580,35 +576,35 @@ static double qtukey(double p, double rr, double cc, double df, int lower_tail,
     /* first iterate; otherwise it is 1 greater. */
 
     if (valx0 > 0.0)
-	x1 = x0 > 1 ? x0 - 1 : 0; // djmw: fmax2 (0.0, x0 - 1.0);
+		x1 = ( x0 > 1.0 ? x0 - 1.0 : 0.0 ); // djmw: fmax2 (0.0, x0 - 1.0);
     else
-	x1 = x0 + 1.0;
-    valx1 = ptukey(x1, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
+		x1 = x0 + 1.0;
+    valx1 = ptukey (x1, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
 
     /* Find new iterate */
 
-    for(iter=1 ; iter < maxiter ; iter++) {
-	ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
-	valx0 = valx1;
+    for (iter = 1 ; iter < maxiter; iter ++) {
+		ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
+		valx0 = valx1;
 
-	/* New iterate must be >= 0 */
+		/* New iterate must be >= 0 */
 
-	x0 = x1;
-	if (ans < 0.0) {
-	    ans = 0.0;
-	    valx1 = -p;
-	}
-	/* Find prob(value < new iterate) */
+		x0 = x1;
+		if (ans < 0.0) {
+			ans = 0.0;
+			valx1 = -p;
+		}
+		/* Find prob(value < new iterate) */
 
-	valx1 = ptukey(ans, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
-	x1 = ans;
+		valx1 = ptukey (ans, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
+		x1 = ans;
 
-	/* If the difference between two successive */
-	/* iterates is less than eps, stop */
+		/* If the difference between two successive */
+		/* iterates is less than eps, stop */
 
-	xabs = fabs(x1 - x0);
-	if (xabs < eps)
-	    return ans;
+		xabs = fabs (x1 - x0);
+		if (xabs < eps)
+			return ans;
     }
 
     /* The process did not converge in 'maxiter' iterations */
diff --git a/dwsys/NUMstring.cpp b/dwsys/NUMstring.cpp
index 7e62a78..a2353ee 100644
--- a/dwsys/NUMstring.cpp
+++ b/dwsys/NUMstring.cpp
@@ -53,14 +53,14 @@ void NUMstring_chopWhiteSpaceAtExtremes_inline (char32 *string) {
 	string[n] = 0;
 }
 
-double *NUMstring_to_numbers (const char32 *s, long *p_numbers_found) {
-	long numbers_found = Melder_countTokens (s);
+real *NUMstring_to_numbers (const char32 *s, integer *p_numbers_found) {
+	integer numbers_found = Melder_countTokens (s);
 	if (numbers_found < 1) {
 		Melder_throw (U"Empty string.");
 	}
-	autoNUMvector<double> numbers (1, numbers_found);
-	long inum = 1;
-	for (char32 *token = Melder_firstToken (s); token; token = Melder_nextToken (), inum++) {
+	autoNUMvector <real> numbers (1, numbers_found);
+	integer inum = 1;
+	for (char32 *token = Melder_firstToken (s); token; token = Melder_nextToken (), inum ++) {
 		Interpreter_numericExpression (0, token, & numbers [inum]);
 	}
 	if (p_numbers_found) {
diff --git a/dwsys/Permutation.cpp b/dwsys/Permutation.cpp
index 69192e1..0387265 100644
--- a/dwsys/Permutation.cpp
+++ b/dwsys/Permutation.cpp
@@ -77,11 +77,11 @@ void structPermutation :: v_info () {
 }
 
 void structPermutation :: v_readText (MelderReadText text, int /*formatVersion*/) {
-	numberOfElements = texgeti4 (text);
+	numberOfElements = texgeti32 (text);
 	if (numberOfElements < 1) {
 		Melder_throw (U"Found a negative mumber of elements during reading.");
 	}
-	p = NUMvector_readText_i4 (1, numberOfElements, text, "p");
+	p = NUMvector_readText_i32 (1, numberOfElements, text, "p");
 	Permutation_checkInvariant (this);
 }
 
diff --git a/dwsys/SVD.cpp b/dwsys/SVD.cpp
index c0a8c52..ffafc48 100644
--- a/dwsys/SVD.cpp
+++ b/dwsys/SVD.cpp
@@ -223,7 +223,7 @@ void SVD_compute (SVD me) {
 		}
 
 		lwork = wt[0];
-		autoNUMvector<double> work (0L, lwork);
+		autoNUMvector<double> work ((integer) 0, lwork);
 		(void) NUMlapack_dgesvd (&jobu, &jobvt, &m, &n, &my u[1][1], &lda, &my d[1], &my v[1][1], &ldu, nullptr, &ldvt, work.peek(), &lwork, &info);
 		if (info != 0) {
 			Melder_throw (U"SVD not computed.");
diff --git a/dwtest/incompleteGamma.csv b/dwtest/incompleteGamma.csv
new file mode 100644
index 0000000..d145282
--- /dev/null
+++ b/dwtest/incompleteGamma.csv
@@ -0,0 +1,82 @@
+i,j,re,im
+1,1,0.1987661103,-0.3095598757
+1,2,0.3228445825,-0.1763707992
+1,3,0.3476302333,-0.1203682022
+1,4,0.3564429602,-0.0910148303
+1,5,0.3605463450,-0.0730863624
+1,6,0.3627818209,-0.0610297766
+1,7,0.3641319491,-0.0523756324
+1,8,0.3650091234,-0.0458652712
+1,9,0.3656109157,-0.0407914394
+2,1,0.0771619996,-0.4818187744
+2,2,0.3332466109,-0.2685201766
+2,3,0.3748663267,-0.1801562406
+2,4,0.3887452493,-0.1352656309
+2,5,0.3950369682,-0.1082453048
+2,6,0.3984183769,-0.0902142889
+2,7,0.4004446891,-0.0773301697
+2,8,0.4017547323,-0.0676654454
+2,9,0.4026505541,-0.0601477953
+3,1,-0.2256877572,-1.2391393906
+3,2,0.6478947321,-0.6902581039
+3,3,0.7655560731,-0.4551094325
+3,4,0.8024166047,-0.3392642144
+3,5,0.8186920055,-0.2705449113
+3,6,0.8273221736,-0.2250399151
+3,7,0.8324538062,-0.1926709448
+3,8,0.8357553293,-0.1684596766
+3,9,0.8380055822,-0.1496633971
+4,1,-2.264361410,-4.327440808
+4,2,1.839842165,-2.493713079
+4,3,2.306093198,-1.615251258
+4,4,2.443519764,-1.195343386
+4,5,2.502643441,-0.949851993
+4,6,2.533579464,-0.788538890
+4,7,2.551833194,-0.674310194
+4,8,2.563520136,-0.589114441
+4,9,2.571459844,-0.523100743
+5,1,-17.52755660,-18.39628590
+5,2,6.813849752,-11.604567948
+5,3,9.187920472,-7.382161401
+5,4,9.847181866,-5.422666278
+5,5,10.123636094,-4.293586701
+5,6,10.266392566,-3.557357046
+5,7,10.349982962,-3.038371617
+5,8,10.403243659,-2.652402892
+5,9,10.439310050,-2.353912713
+6,1,-142.2147946,-86.3667589
+6,2,30.77417029,-66.07794662
+6,3,45.53239729,-41.27240252
+6,4,49.39827607,-30.08931501
+6,5,50.97891899,-23.73809546
+6,6,51.78453447,-19.62845688
+6,7,52.25268314,-16.74454297
+6,8,52.54953922,-14.60592302
+6,9,52.74991236,-12.95520302
+7,1,-1260.0550811,-379.9000571
+7,2,161.5145876,-445.0258124
+7,3,269.8005899,-272.8616852
+7,4,296.5878130,-197.4080759
+7,5,307.2702388,-155.1696398
+7,6,312.6447046,-128.0480911
+7,7,315.7443221,-109.1015267
+7,8,317.7004274,-95.0915854
+7,9,319.0165276,-84.2986884
+8,1,-12204.087873,-584.381713
+8,2,944.049668,-3460.419535
+8,3,1859.619830,-2082.405984
+8,4,2073.731412,-1494.873175
+8,5,2157.035815,-1170.675295
+8,6,2198.412225,-964.099512
+8,7,2222.096670,-820.440378
+8,8,2236.972439,-714.516527
+8,9,2246.949085,-633.072836
+9,1,-127957.54410,24763.15853
+9,2,5847.29921,-30509.82261
+9,3,14609.44345,-18017.82575
+9,4,16548.40741,-12832.31223
+9,5,17284.62288,-10011.73271
+9,6,17645.66300,-8228.23470
+9,7,17850.79042,-6993.52505
+9,8,17979.01813,-6085.74594
+9,9,18064.74179,-5389.10996}
diff --git a/dwtest/test_detectSilences.praat b/dwtest/test_detectSilences.praat
new file mode 100644
index 0000000..7416cc3
--- /dev/null
+++ b/dwtest/test_detectSilences.praat
@@ -0,0 +1,50 @@
+# test_detectSilences.praat
+# djmw 20170808
+
+appendInfoLine: "test_detectSilences.praat"
+
+text$ [0] = "+-, +-+-, ..., +-+-+-+-+-"
+text$ [1] = "-+, -+-+, ..., -+-+-+-+-+"
+db0 = -30
+for k from 0 to 1
+	appendInfoLine: tab$, text$ [k]
+	sound [k] = Create Sound from formula: "s"+ string$(k), 1, 0, 1, 44100, "randomGauss (0,0.1)"
+	for i to 5
+		selectObject: sound [k]
+		Formula (part): (2*i-1 -k)*0.1, (2*i-k) *0.1, 1, 1, "self*10^(db0 / 20)"
+		tg = To TextGrid (silences): 100, 0, -25, 0.01, 0.01, "silent", "sounding"
+		numberOfIntervals = Get number of intervals: 1
+		numberOfIntervals2 = i * 2 + (if i < 5 then 1-k else 0 fi)
+		assert numberOfIntervals = numberOfIntervals2; 'numberOfIntervals' 'i' 'k'
+		removeObject: tg
+	endfor
+endfor
+
+appendInfoLine: tab$, "silence is  +3dB or -3dB w.r.t  threshold"
+db0 = -30
+for k from 0 to 1
+	for idb to 2
+		db = -27 - (idb -1) * 6; 3 db around db0
+		selectObject: sound [k]
+		tg = To TextGrid (silences): 100, 0, db, 0.01, 0.01, "silent", "sounding"
+		numberOfIntervals = Get number of intervals: 1
+		numberOfIntervals2 = if db < db0 then 1 else 10 fi
+		assert numberOfIntervals = numberOfIntervals2; 'db'
+		removeObject: tg
+	endfor
+endfor
+
+# sound [0] and sound [1] have 10 intervals
+appendInfoLine: tab$, "minimum sounding/silent interval exceeds largest interval"
+for k from 0 to 1
+	selectObject: sound [k]
+	tg = To TextGrid (silences): 100, 0, db, 0.15, 0.15, "silent", "sounding"
+	numberOfIntervals = Get number of intervals: 1
+	assert numberOfIntervals = 1
+	removeObject: sound [k], tg
+endfor
+
+# more tests...
+
+#removeObject: sound
+appendInfoLine: "test_detectSilences.praat OK"
diff --git a/dwtest/test_gammatonefilter.praat b/dwtest/test_gammatonefilter.praat
index fce9377..d324592 100644
--- a/dwtest/test_gammatonefilter.praat
+++ b/dwtest/test_gammatonefilter.praat
@@ -35,7 +35,7 @@ endfor
 appendInfoLine: tab$, "Compare incomplete gamma with Gamma[n,z]"
 # values in the csv file were calculated by the Mathematica function 
 # N[Gamma[i, i + I i/j], 10]
-Read Table from comma-separated file: "incompleteGamma.csv"
+igt = Read Table from comma-separated file: "incompleteGamma.csv"
 numberOfLines = Get number of rows
 eps = 1e-7
 for irow to numberOfLines
@@ -45,8 +45,10 @@ for irow to numberOfLines
 	im = Get value: irow, "im"
 	z$ = Get incomplete gamma: i, 0.0, i, i / j
 	pre = number (extractWord$ (z$, ""))
-	pim = number (extractWord$ (z$, " "))
+	pim = number (extractWord$ (z$, "+"))
 	;appendInfoLine: irow, " ", re, " ", im, " ", pre, " ", pim
-	assert abs((pre - re)/pre) < eps && abs ((pim - im)/pim) < eps; 'irow'
+	assert abs((pre - re)/pre) < eps && abs ((pim - im)/pim) < eps; 'irow' 'pre' 're' 'pim' 'im' <'z$'>
 endfor
+removeObject: igt
+
 appendInfoLine: "test_gammatonefilter.praat OK"
diff --git a/dwtools/CC.cpp b/dwtools/CC.cpp
index 6dbb1a8..9267b6a 100644
--- a/dwtools/CC.cpp
+++ b/dwtools/CC.cpp
@@ -129,9 +129,9 @@ void CC_drawC0 (CC me, Graphics g, double xmin, double xmax, double ymin, double
 		xmin = my xmin; xmax = my xmax;
 	}
 
-	long bframe, eframe;
-	(void) Sampled_getWindowSamples (me, xmin, xmax, &bframe, &eframe);
-	autoNUMvector<double> c (bframe, eframe);
+	integer bframe, eframe;
+	(void) Sampled_getWindowSamples (me, xmin, xmax, & bframe, & eframe);
+	autoNUMvector <double> c (bframe, eframe);
 	for (long i = bframe; i <= eframe; i++) {
 		CC_Frame cf = & my frame[i];
 		c[i] = cf -> c0;
@@ -213,24 +213,24 @@ long CC_getNumberOfCoefficients (CC me, long iframe) {
 
 double CC_getValueInFrame (CC me, long iframe, long index) {
 	if (iframe < 1 || iframe > my nx) {
-		return NUMundefined;
+		return undefined;
 	}
 	CC_Frame cf = & me -> frame[iframe];
-	return index > cf -> numberOfCoefficients ? NUMundefined : cf -> c[index];
+	return index > cf -> numberOfCoefficients ? undefined : cf -> c[index];
 }
 
 double CC_getValue (CC me, double t, long index) {
 	long iframe = Sampled_xToNearestIndex (me, t);
 	if (iframe < 1 || iframe > my nx) {
-		return NUMundefined;
+		return undefined;
 	}
 	CC_Frame cf = & me -> frame[iframe];
-	return index > cf -> numberOfCoefficients ? NUMundefined : cf -> c[index];
+	return index > cf -> numberOfCoefficients ? undefined : cf -> c[index];
 }
 
 double CC_getC0ValueInFrame (CC me, long iframe) {
 	if (iframe < 1 || iframe > my nx) {
-		return NUMundefined;
+		return undefined;
 	}
 	CC_Frame cf = & me -> frame[iframe];
 	return cf -> c0;
diff --git a/dwtools/CCA.cpp b/dwtools/CCA.cpp
index c4fbc6c..f930a4e 100644
--- a/dwtools/CCA.cpp
+++ b/dwtools/CCA.cpp
@@ -300,7 +300,7 @@ autoTableOfReal CCA_and_TableOfReal_factorLoadings (CCA me, TableOfReal thee) {
 
 double CCA_getCorrelationCoefficient (CCA me, long index) {
 	if (index < 1 || index > my numberOfCoefficients) {
-		return NUMundefined;
+		return undefined;
 	}
 	return sqrt (my y -> eigenvalues[index]);
 }
@@ -310,7 +310,7 @@ void CCA_getZeroCorrelationProbability (CCA me, long index, double *p_prob, doub
 	long nev = my y -> numberOfEigenvalues;
 	long ny = my y -> dimension, nx = my x -> dimension;
 
-	double chisq = NUMundefined, prob = NUMundefined, df = NUMundefined;
+	double chisq = undefined, prob = undefined, df = undefined;
 
 	if (index >= 1 && index <= nev) {
 		for (long i = index; i <= nev; i ++) {
diff --git a/dwtools/CCA_and_Correlation.cpp b/dwtools/CCA_and_Correlation.cpp
index 4ab6115..d557329 100644
--- a/dwtools/CCA_and_Correlation.cpp
+++ b/dwtools/CCA_and_Correlation.cpp
@@ -1,6 +1,6 @@
 /* CCA_and_Correlation.cpp
  *
- * Copyright (C) 1993-2011, 2015 David Weenink
+ * Copyright (C) 1993-2011, 2015 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -125,8 +125,8 @@ double CCA_and_Correlation_getRedundancy_sl (CCA me, Correlation thee, int x_or_
 	double redundancy = 0.0;
 	for (long icv = canonicalVariate_from; icv <= canonicalVariate_to; icv++) {
 		double varianceFraction = CCA_and_Correlation_getVarianceFraction (me, thee, x_or_y, icv, icv);
-		if (varianceFraction == NUMundefined) {
-			return NUMundefined;
+		if (isundef (varianceFraction)) {
+			return undefined;
 		}
 		redundancy += varianceFraction * my y -> eigenvalues[icv];
 	}
diff --git a/dwtools/CCs_to_DTW.cpp b/dwtools/CCs_to_DTW.cpp
index 33dabfd..aae3fdb 100644
--- a/dwtools/CCs_to_DTW.cpp
+++ b/dwtools/CCs_to_DTW.cpp
@@ -72,8 +72,8 @@ autoDTW CCs_to_DTW (CC me, CC thee, double wc, double wle, double wr, double wer
 		}
 
 		autoDTW him = DTW_create (my xmin, my xmax, my nx, my dx, my x1, thy xmin, thy xmax, thy nx, thy dx, thy x1);
-		autoNUMvector<double> ri (0L, my maximumNumberOfCoefficients);
-		autoNUMvector<double> rj (0L, my maximumNumberOfCoefficients);
+		autoNUMvector <double> ri ((integer) 0, my maximumNumberOfCoefficients);
+		autoNUMvector <double> rj ((integer) 0, my maximumNumberOfCoefficients);
 
 		/* Calculate distance matrix. */
 
@@ -85,7 +85,7 @@ autoDTW CCs_to_DTW (CC me, CC thee, double wc, double wle, double wr, double wer
 
 			for (long j = 1; j <= thy nx; j ++) {
 				CC_Frame fj = & thy frame [j];
-				double dist = 0.0, distr = 0.0;
+				real80 dist = 0.0, distr = 0.0;
 
 				/* Cepstral distance. */
 
@@ -126,7 +126,7 @@ autoDTW CCs_to_DTW (CC me, CC thee, double wc, double wle, double wr, double wer
 				}
 
 				dist /= wc + wle + wr + wer;
-				his z [i] [j] = sqrt (dist);   // prototype along y-direction
+				his z [i] [j] = sqrt ((real) dist);   // prototype along y-direction
 			}
 
 			if (i % 10 == 1) {
diff --git a/dwtools/Categories.cpp b/dwtools/Categories.cpp
index c2d98ec..d6c4d75 100644
--- a/dwtools/Categories.cpp
+++ b/dwtools/Categories.cpp
@@ -1,6 +1,6 @@
 /* Categories.cpp
  *
- * Copyright (C) 1993-2013, 2015 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 1993-2013, 2015 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
 #include "Categories.h"
 
 void structCategories :: v_readText (MelderReadText a_text, int /*formatVersion*/) {
-	long l_size = texgeti4 (a_text);
+	long l_size = texgeti32 (a_text);
 	if (l_size == 0) {
 		(void) 0;
 	} else if (l_size < 0) {
@@ -40,7 +40,7 @@ void structCategories :: v_readText (MelderReadText a_text, int /*formatVersion*
 }
 
 void structCategories :: v_writeText (MelderFile file) {
-	texputi4 (file, our size, U"size", nullptr, nullptr, nullptr, nullptr, nullptr);
+	texputi32 (file, our size, U"size", nullptr, nullptr, nullptr, nullptr, nullptr);
 	for (long i = 1; i <= our size; i ++) {
 		SimpleString data = our at [i];
 		texputintro (file, U"item [", Melder_integer (i), U"]:", nullptr, nullptr, nullptr);
diff --git a/dwtools/Confusion.cpp b/dwtools/Confusion.cpp
index b6fe037..98ed521 100644
--- a/dwtools/Confusion.cpp
+++ b/dwtools/Confusion.cpp
@@ -234,7 +234,7 @@ double Confusion_getValue (Confusion me, const char32 *stim, const char32 *resp)
 }
 
 void Confusion_getFractionCorrect (Confusion me, double *p_fraction, long *p_numberOfCorrect) {
-	double fraction = NUMundefined;
+	double fraction = undefined;
 	long numberOfCorrect = -1;
 
 	double c = 0.0, ct = 0.0;
diff --git a/dwtools/DTW.cpp b/dwtools/DTW.cpp
index ffaa052..984dde7 100644
--- a/dwtools/DTW.cpp
+++ b/dwtools/DTW.cpp
@@ -1,6 +1,6 @@
 /* DTW.cpp
  *
- * Copyright (C) 1993-2013, 2015-2016 David Weenink
+ * Copyright (C) 1993-2013, 2015-2016 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -492,7 +492,7 @@ double DTW_getPathY (DTW me, double tx) {
 		i ++;
 	}
 	if (i > my pathLength) {
-		return NUMundefined;
+		return undefined;
 	}
 	long iy = my path [i]. y; /* row */
 
@@ -605,7 +605,7 @@ long DTW_getMaximumConsecutiveSteps (DTW me, int direction) {
 
 static void DTW_paintDistances_raw (DTW me, Graphics g, double xmin, double xmax, double ymin,
                                     double ymax, double minimum, double maximum, bool garnish, bool inset) {
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	if (xmax <= xmin) {
 		xmin = my xmin;
 		xmax = my xmax;
@@ -652,7 +652,7 @@ void DTW_paintDistances (DTW me, Graphics g, double xmin, double xmax, double ym
 }
 
 static double RealTier_getXAtIndex (RealTier me, long point) {
-	double x = NUMundefined;
+	double x = undefined;
 	if (point > 0 && point <= my points.size) {
 		x = my points.at [point] -> number;
 	}
@@ -895,7 +895,7 @@ void DTW_drawDistancesAlongPath (DTW me, Graphics g, double xmin, double xmax, d
 	if (xmin >= xmax) {
 		xmin = my xmin; xmax = my xmax;
 	}
-	long ixmax, ixmin;
+	integer ixmax, ixmin;
 	if (! Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax)) {
 		return;
 	}
@@ -1016,9 +1016,6 @@ autoDTW Spectrograms_to_DTW (Spectrogram me, Spectrogram thee, int matchStart, i
 	}
 }
 
-#define FREQUENCY(frame)  ((frame) -> candidate [1]. frequency)
-#define NOT_VOICED(f)  ((f) <= 0.0 || (f) >= my ceiling)   /* This includes NUMundefined! */
-
 static int Pitch_findFirstAndLastVoicedFrame (Pitch me, long *first, long *last) {
 	*first = 1;
 	while (*first <= my nx && ! Pitch_isVoiced_i (me, *first)) {
@@ -1064,13 +1061,13 @@ autoDTW Pitches_to_DTW_sgc (Pitch me, Pitch thee, double vuv_costs, double time_
 			double t1 = my x1 + (i - 1) * my dx;
 			for (long j = 1; j <= thy nx; j++) {
 				double t2 = thy x1 + (j - 1) * thy dx;
-				double dist_f = 0.0; // based on pitch difference
+				double dist_f = 0.0;   // based on pitch difference
 				double dist_t = fabs (t1 - t2);
-				if (pitchy == NUMundefined) {
-					if (pitchx [j] != NUMundefined) {
+				if (isundef (pitchy)) {
+					if (isdefined (pitchx [j])) {
 						dist_f = vuv_costs;
 					}
-				} else if (pitchx [j] == NUMundefined) {
+				} else if (isundef (pitchx [j])) {
 					dist_f = vuv_costs;
 				} else {
 					dist_f = fabs (pitchy - pitchx[j]);
@@ -1108,11 +1105,11 @@ autoDTW Pitches_to_DTW (Pitch me, Pitch thee, double vuv_costs, double time_weig
 				double t2 = thy x1 + (j - 1) * thy dx;
 				double dist_f = 0; // based on pitch difference
 				double dist_t = fabs (t1 - t2);
-				if (pitchy == NUMundefined) {
-					if (pitchx [j] != NUMundefined) {
+				if (isundef (pitchy)) {
+					if (isdefined (pitchx [j])) {
 						dist_f = vuv_costs;
 					}
-				} else if (pitchx [j] == NUMundefined) {
+				} else if (isundef (pitchx [j])) {
 					dist_f = vuv_costs;
 				} else {
 					dist_f = fabs (pitchy - pitchx [j]);
diff --git a/dwtools/DTW_and_TextGrid.cpp b/dwtools/DTW_and_TextGrid.cpp
index be22f70..4c285bc 100644
--- a/dwtools/DTW_and_TextGrid.cpp
+++ b/dwtools/DTW_and_TextGrid.cpp
@@ -139,8 +139,8 @@ autoTable DTW_and_IntervalTier_to_Table (DTW me, IntervalTier thee, double preci
 				TextInterval textinterval = thy intervals.at [i];
 				double xmin = DTW_getXTimeFromYTime (me, textinterval -> xmin);
 				double xmax = DTW_getXTimeFromYTime (me, textinterval -> xmax);
-				long ixmin, ixmax;
-				long numberOfFrames = Matrix_getWindowSamplesX (me, xmin, xmax, &ixmin, &ixmax);
+				integer ixmin, ixmax;
+				integer numberOfFrames = Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 				double sumOfDistances = 0;
 				while (pathIndex < my pathLength && my path[pathIndex].x < ixmax) {
 					sumOfDistances += my z[my path[pathIndex].y][my path[pathIndex].x];
@@ -157,8 +157,8 @@ autoTable DTW_and_IntervalTier_to_Table (DTW me, IntervalTier thee, double preci
 				TextInterval textinterval = thy intervals.at [i];
 				double ymin = DTW_getYTimeFromXTime (me, textinterval -> xmin);
 				double ymax = DTW_getYTimeFromXTime (me, textinterval -> xmax);
-				long iymin, iymax;
-				long numberOfFrames = Matrix_getWindowSamplesY (me, ymin, ymax, &iymin, &iymax);
+				integer iymin, iymax;
+				integer numberOfFrames = Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 				double sumOfDistances = 0;
 				while (pathIndex < my pathLength && my path[pathIndex].y < iymax) {
 					sumOfDistances += my z[my path[pathIndex].y][my path[pathIndex].x];
@@ -176,8 +176,6 @@ autoTable DTW_and_IntervalTier_to_Table (DTW me, IntervalTier thee, double preci
 	} catch (MelderError) {
 		Melder_throw (me, U": no Table with distances created.");
 	}
-
-
 }
 
 /* Get times from TextGrid and substitute new time form the y-times of the DTW. */
diff --git a/dwtools/DataModeler.cpp b/dwtools/DataModeler.cpp
index 5b8b5c5..084e7a3 100644
--- a/dwtools/DataModeler.cpp
+++ b/dwtools/DataModeler.cpp
@@ -1,6 +1,6 @@
 /* DataModeler.cpp
  *
- * Copyright (C) 2014-2016 David Weenink
+ * Copyright (C) 2014-2016 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -132,7 +132,7 @@ static void chisqFromZScores (double *zscores, long numberOfZScores, double *p_c
 	long numberOfValidZScores = numberOfZScores;
 	double chisq = 0.0;
 	for (long i = 1; i <= numberOfZScores; i++) {
-		if (NUMdefined (zscores[i])) {
+		if (isdefined (zscores[i])) {
 			chisq += zscores[i] * zscores[i];
 		} else {
 			numberOfValidZScores--;
@@ -162,7 +162,7 @@ static double DataModeler_getDataPointInverseWeight (DataModeler me, long iPoint
 }
 
 double DataModeler_getModelValueAtX (DataModeler me, double x) {
-	double f = NUMundefined;
+	double f = undefined;
 	if (x >= my xmin && x <= my xmax) {
 		f = my f_evaluate (me, x, my parameter);
 	}
@@ -170,7 +170,7 @@ double DataModeler_getModelValueAtX (DataModeler me, double x) {
 }
 
 double DataModeler_getModelValueAtIndex (DataModeler me, long index) {
-	double f = NUMundefined;
+	double f = undefined;
 	if (index > 0 && index <= my numberOfDataPoints) {
 		f = my f_evaluate (me, my x[index], my parameter);
 	}
@@ -198,7 +198,7 @@ void DataModeler_getExtremaY (DataModeler me, double *p_ymin, double *p_ymax) {
 }
 
 double DataModeler_getDataPointYValue (DataModeler me, long index) {
-	double value = NUMundefined;
+	double value = undefined;
 	if (index > 0 && index <= my numberOfDataPoints && my dataPointStatus[index] != DataModeler_DATA_INVALID) {
 		value = my y[index];
 	}
@@ -206,7 +206,7 @@ double DataModeler_getDataPointYValue (DataModeler me, long index) {
 }
 
 double DataModeler_getDataPointXValue (DataModeler me, long index) {
-	double value = NUMundefined;
+	double value = undefined;
 	if (index > 0 && index <= my numberOfDataPoints && my dataPointStatus[index] != DataModeler_DATA_INVALID) {
 		value = my x[index];
 	}
@@ -234,14 +234,14 @@ void DataModeler_setDataPointValues (DataModeler me, long index, double xvalue,
 
 void DataModeler_setDataPointYSigma (DataModeler me, long index, double sigma) {
 	if (index > 0 && index <= my numberOfDataPoints) {
-		my sigmaY[index] = sigma;
+		my sigmaY [index] = sigma;
 	}
 }
 
 double DataModeler_getDataPointYSigma (DataModeler me, long index) {
-	double sigma = NUMundefined;
+	double sigma = undefined;
 	if (index > 0 && index <= my numberOfDataPoints) {
-		sigma = my sigmaY[index];
+		sigma = my sigmaY [index];
 	}
 	return sigma;
 }
@@ -256,7 +256,7 @@ int DataModeler_getDataPointStatus (DataModeler me, long index) {
 
 void DataModeler_setDataPointStatus (DataModeler me, long index, int status) {
 	if (index > 0 && index <= my numberOfDataPoints) {
-		if (status == DataModeler_DATA_VALID && ! NUMdefined (my y[index])) {
+		if (status == DataModeler_DATA_VALID && isundef (my y[index])) {
 			Melder_throw (U"Your data value is undefined. First set the value and then its status.");
 		}
 		my dataPointStatus[index] = status;
@@ -282,7 +282,7 @@ void DataModeler_setParameterValueFixed (DataModeler me, long index, double valu
 }
 
 double DataModeler_getParameterValue (DataModeler me, long index) {
-	double value = NUMundefined;
+	double value = undefined;
 	if (index > 0 && index <= my numberOfParameters) {
 		value = my parameter[index];
 	}
@@ -298,7 +298,7 @@ int DataModeler_getParameterStatus (DataModeler me, long index) {
 }
 
 double DataModeler_getParameterStandardDeviation (DataModeler me, long index) {
-	double stdev = NUMundefined;
+	double stdev = undefined;
 	if (index > 0 && index <= my numberOfParameters) {
 		stdev = sqrt (my parameterCovariances -> data[index][index]);
 	}
@@ -306,7 +306,7 @@ double DataModeler_getParameterStandardDeviation (DataModeler me, long index) {
 }
 
 double DataModeler_getVarianceOfParameters (DataModeler me, long fromIndex, long toIndex, long *p_numberOfFreeParameters) {
-	double variance = NUMundefined;
+	double variance = undefined;
 	if (toIndex < fromIndex || (toIndex == 0 && fromIndex == 0)) {
 		fromIndex = 1; toIndex = my numberOfParameters;
 	}
@@ -405,7 +405,7 @@ void DataModeler_getZScores (DataModeler me, int useSigmaY, double zscores[]) {
 			estimatedSigmaY = rss / (numberOfValidDataPoints - 1);
 		}
 		for (long i = 1; i <= my numberOfDataPoints; i++) {
-			double value = NUMundefined;
+			double value = undefined;
 			if (my dataPointStatus[i] != DataModeler_DATA_INVALID) {
 				double estimate = my f_evaluate (me, my x[i], my parameter);
 				double sigma = useSigmaY == DataModeler_DATA_WEIGH_EQUAL ? estimatedSigmaY : DataModeler_getDataPointInverseWeight (me, i, useSigmaY);
@@ -424,17 +424,17 @@ static void DataModeler_getChisqScoresFromZScores (DataModeler me, double *zscor
 	long numberOfDefined = my numberOfDataPoints;
 	double sumchisq = 0.0;
 	for (long i = 1; i <= my numberOfDataPoints; i++) {
-		if (NUMdefined (zscores[i])) {
-			chisq[i] = zscores[i] * zscores[i];
-			sumchisq += chisq[i];
+		if (isdefined (zscores [i])) {
+			chisq [i] = zscores [i] * zscores [i];
+			sumchisq += chisq [i];
 		} else {
-			numberOfDefined--;
-			chisq[i] = NUMundefined;
+			numberOfDefined --;
+			chisq [i] = undefined;
 		}
 	}
 	if (substituteAverage && numberOfDefined != my numberOfDataPoints && numberOfDefined > 0) {
-		for (long i = 1; i <= my numberOfDataPoints; i++) {
-			if (! NUMdefined (chisq[i])) {
+		for (long i = 1; i <= my numberOfDataPoints; i ++) {
+			if (isundef (chisq [i])) {
 				chisq[i] = sumchisq / numberOfDefined;
 			}
 		}
@@ -765,8 +765,8 @@ autoDataModeler DataModeler_create (double xmin, double xmax, long numberOfDataP
 
 autoDataModeler DataModeler_createSimple (double xmin, double xmax, long numberOfDataPoints, char32 *parameters, double gaussianNoiseStd, int type) {
 	try {
-		long numberOfParameters;
-		autoNUMvector<double> parameter (NUMstring_to_numbers (parameters, &numberOfParameters), 1);
+		integer numberOfParameters;
+		autoNUMvector <double> parameter (NUMstring_to_numbers (parameters, & numberOfParameters), 1);
 		if (numberOfParameters < 1) {
 			Melder_throw (U"At least one parameter must be defined.");
 		}
@@ -782,7 +782,7 @@ autoDataModeler DataModeler_createSimple (double xmin, double xmax, long numberO
 			my x[i] = xmin + (i - 0.5) * (xmax - xmin) / numberOfDataPoints;
 			double modelY = my f_evaluate (me.get(), my x[i], my parameter);
 			my y[i] = modelY + NUMrandomGauss (0.0, gaussianNoiseStd);
-			my sigmaY[i] = NUMundefined;
+			my sigmaY[i] = undefined;
 		}
 		my useSigmaY = DataModeler_DATA_WEIGH_EQUAL;
 		return me;
@@ -812,7 +812,7 @@ void DataModeler_fit (DataModeler me)
 
 		// estimate sigma if we weigh all datapoint equally. 
 		// This is necessary to get the parameter covariances right
-		double sigmaY = my useSigmaY == DataModeler_DATA_WEIGH_EQUAL ? DataModeler_estimateSigmaY (me) : NUMundefined;
+		double sigmaY = ( my useSigmaY == DataModeler_DATA_WEIGH_EQUAL ? DataModeler_estimateSigmaY (me) : undefined );
 		long idata = 0;
 		// Accumulate coefficients of the design matrix
 		for (long i = 1; i <= my numberOfDataPoints; i++) {
@@ -820,7 +820,7 @@ void DataModeler_fit (DataModeler me)
 				// function evaluation with only the FIXED parameters
 				double xi = my x[i], yi = my y[i];
 				double yFixed = my f_evaluate (me, xi, parameter.peek());
-				double si = my useSigmaY != DataModeler_DATA_WEIGH_EQUAL ? DataModeler_getDataPointInverseWeight (me, i, my useSigmaY) : sigmaY;
+				double si = ( my useSigmaY != DataModeler_DATA_WEIGH_EQUAL ? DataModeler_getDataPointInverseWeight (me, i, my useSigmaY) : sigmaY );
 
 				// individual terms of the function
 
@@ -916,7 +916,7 @@ autoDataModeler Table_to_DataModeler (Table me, double xmin, double xmax, long x
 		autoNUMvector<double> x (1, numberOfRows), y (1, numberOfRows), sy (1, numberOfRows);
 		for (long i = 1; i <= numberOfRows; i++) {
 			double val = Table_getNumericValue_Assert (me, i, xcolumn);
-			if (NUMdefined (val)) {
+			if (isdefined (val)) {
 				numberOfData++; x[numberOfData] = val;
 				if (numberOfData > 1) {
 					if (val < x[numberOfData - 1]) {
@@ -947,7 +947,7 @@ autoDataModeler Table_to_DataModeler (Table me, double xmin, double xmax, long x
 			if (x[i] >= xmin && x[i] <= xmax) {
 				thy x[++numberOfDataPoints] = x[i];
 				thy dataPointStatus[numberOfDataPoints] = DataModeler_DATA_INVALID;
-				if (NUMdefined (y[i])) {
+				if (isdefined (y[i])) {
 					thy y[numberOfDataPoints] = y[i];
 					thy sigmaY[numberOfDataPoints] = sy[i];
 					thy dataPointStatus[numberOfDataPoints] = DataModeler_DATA_VALID;
@@ -987,17 +987,17 @@ void structFormantModeler :: v_info () {
 double DataModeler_getResidualSumOfSquares (DataModeler me, long *numberOfDataPoints) {
 	long n = 0;
 	double rss = 0.0;
-	for (long i = 1; i <= my numberOfDataPoints; i++) {
+	for (long i = 1; i <= my numberOfDataPoints; i ++) {
 		if (my dataPointStatus[i] != DataModeler_DATA_INVALID) {
-				++n;
-				double dif = my y[i] - my f_evaluate (me, my x[i], my parameter);
+				++ n;
+				double dif = my y [i] - my f_evaluate (me, my x [i], my parameter);
 				rss += dif * dif;
 		}
 	}
 	if (numberOfDataPoints) {
 		*numberOfDataPoints = n;
 	}
-	return n > 0 ? rss : NUMundefined;
+	return ( n > 0 ? rss : undefined );
 }
 
 void DataModeler_reportChiSquared (DataModeler me, int weighDataType) {
@@ -1024,7 +1024,7 @@ double DataModeler_estimateSigmaY (DataModeler me) {
 		}
 		double variance;
 		NUMvector_avevar (y.peek(), numberOfDataPoints, nullptr, &variance);
-		double sigma = NUMdefined (variance) ? sqrt (variance / (numberOfDataPoints - 1)) : NUMundefined;
+		double sigma = ( isdefined (variance) ? sqrt (variance / (numberOfDataPoints - 1)) : undefined );
 		return sigma;
 	} catch (MelderError) {
 		Melder_throw (U"Cannot estimate sigma.");
@@ -1032,7 +1032,7 @@ double DataModeler_estimateSigmaY (DataModeler me) {
 }
 
 double FormantModeler_getStandardDeviation (FormantModeler me, long iformant) {
-	double sigma = NUMundefined;
+	double sigma = undefined;
 	if (iformant > 0 && iformant <= my trackmodelers.size) {
 		DataModeler ff = my trackmodelers.at [iformant];
 		sigma = DataModeler_estimateSigmaY (ff);
@@ -1041,7 +1041,7 @@ double FormantModeler_getStandardDeviation (FormantModeler me, long iformant) {
 }
 
 double FormantModeler_getDataPointValue (FormantModeler me, long iformant, long index) {
-	double value = NUMundefined;
+	double value = undefined;
 	if (iformant > 0 && iformant <= my trackmodelers.size) {
 		DataModeler ff = my trackmodelers.at [iformant];
 		value = DataModeler_getDataPointYValue (ff, index);
@@ -1057,7 +1057,7 @@ void FormantModeler_setDataPointValue (FormantModeler me, long iformant, long in
 }
 
 double FormantModeler_getDataPointSigma (FormantModeler me, long iformant, long index) {
-	double sigma = NUMundefined;
+	double sigma = undefined;
 	if (iformant > 0 && iformant <= my trackmodelers.size) {
 		DataModeler ff = (DataModeler) my trackmodelers.at [iformant];
 		sigma = DataModeler_getDataPointYSigma (ff, index);
@@ -1200,9 +1200,9 @@ static void FormantModeler_getVariancesBetweenTrackAndEstimatedTrack (FormantMod
 	DataModeler fi = my trackmodelers.at [iformant];
 	DataModeler fe = my trackmodelers.at [estimatedFormant];
 	for (long i = 1; i <= numberOfDataPoints; i ++) {
-		var[i] = NUMundefined;
+		var [i] = undefined;
 		if (fi -> dataPointStatus[i] != DataModeler_DATA_INVALID) {
-			double ye = fe -> f_evaluate (fe, fe -> x[i], fe -> parameter);
+			double ye = fe -> f_evaluate (fe, fe -> x [i], fe -> parameter);
 			double diff = ye - fi -> y[i];
 			var[i] = diff * diff;
 		}
@@ -1231,7 +1231,7 @@ static void FormantModeler_getSumOfVariancesBetweenShiftedAndEstimatedTracks (Fo
 		for (long iformant = *fromFormant; iformant <= *toFormant; iformant++) {
 			FormantModeler_getVariancesBetweenTrackAndEstimatedTrack (me, formantTrack, estimatedFormantTrack, vari.peek());
 			for (long i = 1; i <= numberOfDataPoints; i ++) {
-				if (NUMdefined (vari [i])) {
+				if (isdefined (vari [i])) {
 					var [i] += vari [i];
 				}
 			}
@@ -1257,7 +1257,7 @@ void FormantModeler_drawVariancesOfShiftedTracks (FormantModeler me, Graphics g,
 		FormantModeler_getSumOfVariancesBetweenShiftedAndEstimatedTracks (me, shiftDirection, &fromFormant, &toFormant, varShifted.peek());
 		FormantModeler_getSumOfVariancesBetweenShiftedAndEstimatedTracks (me, 0, &fromFormant, &toFormant, var.peek());
 		for (long i = ixmin + 1; i <= ixmax; i ++) {
-			if (NUMdefined (varShifted [i]) && NUMdefined (var [i])) {
+			if (isdefined (varShifted [i]) && isdefined (var [i])) {
 				var [i] -= varShifted [i];
 			}
 		}
@@ -1267,12 +1267,12 @@ void FormantModeler_drawVariancesOfShiftedTracks (FormantModeler me, Graphics g,
 		Graphics_setInner (g);
 		Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 		DataModeler thee = my trackmodelers.at [1];
-		while (! NUMdefined (var [ixmin]) && ixmin <= ixmax) {
+		while (isundef (var [ixmin]) && ixmin <= ixmax) {
 			ixmin++;
 		}
 		double xp = thy x [ixmin], yp = var [ixmin];
 		for (long i = ixmin + 1; i <= ixmax; i ++) {
-			if (NUMdefined (var [i])) {
+			if (isdefined (var [i])) {
 				Graphics_line (g, xp, yp, thy x [i], var [i]);
 				xp = thy x [i];
 				yp = var [i];
@@ -1440,7 +1440,7 @@ autoFormantModeler FormantModeler_create (double tmin, double tmax, long numberO
 }
 
 double FormantModeler_getModelValueAtTime (FormantModeler me, long iformant, double time) {
-	double f = NUMundefined;
+	double f = undefined;
 	if (iformant >= 1 && iformant <= my trackmodelers.size) {
 		DataModeler thee = my trackmodelers.at [iformant];
 		f = DataModeler_getModelValueAtX (thee, time);
@@ -1449,7 +1449,7 @@ double FormantModeler_getModelValueAtTime (FormantModeler me, long iformant, dou
 }
 
 double FormantModeler_getModelValueAtIndex (FormantModeler me, long iformant, long index) {
-	double f = NUMundefined;
+	double f = undefined;
 	if (iformant >= 1 && iformant <= my trackmodelers.size) {
 		DataModeler thee = my trackmodelers.at [iformant];
 		f = DataModeler_getModelValueAtIndex (thee, index);
@@ -1458,7 +1458,7 @@ double FormantModeler_getModelValueAtIndex (FormantModeler me, long iformant, lo
 }
 
 double FormantModeler_getWeightedMean (FormantModeler me, long iformant) {
-	double f = NUMundefined;
+	double f = undefined;
 	if (iformant >= 1 && iformant <= my trackmodelers.size) {
 		DataModeler thee = my trackmodelers.at [iformant];
 		f = DataModeler_getWeightedMean (thee);
@@ -1501,7 +1501,7 @@ long FormantModeler_getNumberOfInvalidDataPoints (FormantModeler me, long iforma
 }
 
 double FormantModeler_getParameterValue (FormantModeler me, long iformant, long iparameter) {
-	double value = NUMundefined;
+	double value = undefined;
 	if (iformant > 0 && iformant <= my trackmodelers.size) {
 		DataModeler ff = my trackmodelers.at [iformant];
 		value = DataModeler_getParameterValue (ff, iparameter);
@@ -1519,7 +1519,7 @@ int FormantModeler_getParameterStatus (FormantModeler me, long iformant, long in
 }
 
 double FormantModeler_getParameterStandardDeviation ( FormantModeler me, long iformant, long index) {
-	double stdev = NUMundefined;
+	double stdev = undefined;
 	if (iformant > 0 && iformant <= my trackmodelers.size) {
 		DataModeler ff = my trackmodelers.at [iformant];
 		stdev = DataModeler_getParameterStandardDeviation (ff, index);
@@ -1537,7 +1537,7 @@ double FormantModeler_getDegreesOfFreedom (FormantModeler me, long iformant) {
 }
 
 double FormantModeler_getVarianceOfParameters (FormantModeler me, long fromFormant, long toFormant, long fromIndex, long toIndex, long *numberOfFreeParameters) {
-	double variance = NUMundefined;
+	double variance = undefined;
 	long numberOfFormants = my trackmodelers.size, numberOfParameters = 0, nofp;
 	if (toFormant < fromFormant || (toFormant == 0 && fromFormant == 0)) {
 		fromFormant = 1; toFormant = numberOfFormants;
@@ -1627,16 +1627,16 @@ void FormantModeler_setTolerance (FormantModeler me, double tolerance) {
 double FormantModeler_indexToTime (FormantModeler me, long index) {
 	Melder_assert (my trackmodelers.size > 0);
 	DataModeler thee = my trackmodelers.at [1];
-	return index > 0 && index <= thy numberOfDataPoints ? thy x[index] : NUMundefined;
+	return ( index > 0 && index <= thy numberOfDataPoints ? thy x[index] : undefined );
 }
 
 autoFormantModeler Formant_to_FormantModeler (Formant me, double tmin, double tmax, long numberOfFormants, long numberOfParametersPerTrack, int bandwidthEstimatesSigma) {
 	try {
-		long ifmin, ifmax, posInCollection = 0;
+		integer ifmin, ifmax, posInCollection = 0;
 		if (tmax <= tmin) {
 			tmin = my xmin; tmax = my xmax;
 		}
-		long numberOfDataPoints = Sampled_getWindowSamples (me, tmin, tmax, &ifmin, &ifmax);
+		integer numberOfDataPoints = Sampled_getWindowSamples (me, tmin, tmax, & ifmin, & ifmax);
 		if (numberOfDataPoints < numberOfParametersPerTrack) {
 			Melder_throw (U"Not enought data points, extend the selection.");
 		}
@@ -1651,7 +1651,7 @@ autoFormantModeler Formant_to_FormantModeler (Formant me, double tmin, double tm
 				ffi -> dataPointStatus [idata] = DataModeler_DATA_INVALID;
 				if (iformant <= curFrame -> nFormants) {
 					double frequency = curFrame -> formant [iformant]. frequency;
-					if (NUMdefined (frequency)) {
+					if (isdefined (frequency)) {
 						double bw = curFrame -> formant [iformant]. bandwidth;
 						ffi -> y [idata] = curFrame -> formant [iformant]. frequency;
 						ffi -> sigmaY [idata] = bw;
@@ -1663,13 +1663,13 @@ autoFormantModeler Formant_to_FormantModeler (Formant me, double tmin, double tm
 			ffi -> useSigmaY = bandwidthEstimatesSigma;
 			ffi -> numberOfDataPoints = idata;
 			ffi -> tolerance = 1e-5;
-			if (validData < numberOfParametersPerTrack) { // remove don't throw exception
+			if (validData < numberOfParametersPerTrack) {   // remove don't throw exception
 				thy trackmodelers. removeItem (posInCollection);
 				posInCollection --;
 			}
 		}
 		if (posInCollection == 0) {
-			Melder_throw (U"Not enought data points in all the formants!");
+			Melder_throw (U"Not enough data points in all the formants.");
 		}
 		FormantModeler_fit (thee.get());
 		return thee;
@@ -1698,7 +1698,7 @@ autoFormant FormantModeler_to_Formant (FormantModeler me, int useEstimates, int
 			
 			for (long iformant = 1; iformant <= numberOfFormants; iformant ++) {
 				DataModeler ffi = my trackmodelers.at [iformant];
-				double f = NUMundefined, b = f;
+				double f = undefined, b = f;
 				if (ffi -> dataPointStatus[iframe] != DataModeler_DATA_INVALID) {
 					f = ( useEstimates ? DataModeler_getModelValueAtX (ffi, ffi -> x [iframe]) : ffi -> y [iframe]);
 					b = ff -> sigmaY[iframe]; // copy original value
@@ -1719,7 +1719,7 @@ autoFormant FormantModeler_to_Formant (FormantModeler me, int useEstimates, int
 }
 
 double FormantModeler_getChiSquaredQ (FormantModeler me, long fromFormant, long toFormant, int useSigmaY, double *probability, double *ndf) {
-	double chisq = NUMundefined, ndfTotal = 0.0;
+	double chisq = undefined, ndfTotal = 0.0;
 	if (toFormant < fromFormant || (fromFormant == 0 && toFormant == 0)) {
 		fromFormant = 1; toFormant = my trackmodelers.size;
 	}
@@ -1729,13 +1729,13 @@ double FormantModeler_getChiSquaredQ (FormantModeler me, long fromFormant, long
 		for (long iformant= fromFormant; iformant <= toFormant; iformant ++) {
 			DataModeler ffi = my trackmodelers.at [iformant];
 			double p, df, chisqi = DataModeler_getChiSquaredQ (ffi, useSigmaY, &p, &df);
-			if (NUMdefined (chisqi)) {
+			if (isdefined (chisqi)) {
 				chisq += df * chisqi;
 				ndfTotal += df;
 				numberOfDefined ++;
 			}
 		}
-		if (numberOfDefined == toFormant - fromFormant + 1) { // chisq of all tracks defined
+		if (numberOfDefined == toFormant - fromFormant + 1) {   // chisq of all tracks defined
 			chisq /= ndfTotal;
 			if (ndf) {
 				*ndf = ndfTotal;
@@ -1749,9 +1749,10 @@ double FormantModeler_getChiSquaredQ (FormantModeler me, long fromFormant, long
 }
 
 double FormantModeler_getCoefficientOfDetermination (FormantModeler me, long fromFormant, long toFormant) {
-	double rSquared = NUMundefined;
+	double rSquared = undefined;
 	if (fromFormant == 0 && toFormant == 0) {
-		fromFormant = 1; toFormant = my trackmodelers.size;
+		fromFormant = 1;
+		toFormant = my trackmodelers.size;
 	}
 	if (fromFormant >= 1 && toFormant <= my trackmodelers.size) {
 		double ssreg = 0.0, sstot = 0.0;
@@ -1768,7 +1769,8 @@ double FormantModeler_getCoefficientOfDetermination (FormantModeler me, long fro
 }
 
 double FormantModeler_getResidualSumOfSquares (FormantModeler me, long iformant, long *p_numberOfDataPoints) {
-	double rss = NUMundefined; long numberOfDataPoints = -1;
+	double rss = undefined;
+	long numberOfDataPoints = -1;
 	if (iformant > 0 && iformant <= my trackmodelers.size) {
 		DataModeler ff = my trackmodelers.at [iformant];
 		rss = DataModeler_getResidualSumOfSquares (ff, & numberOfDataPoints);
@@ -1781,7 +1783,8 @@ double FormantModeler_getResidualSumOfSquares (FormantModeler me, long iformant,
 
 void FormantModeler_setParameterValuesToZero (FormantModeler me, long fromFormant, long toFormant, double numberOfSigmas) {
 	if (fromFormant == 0 && toFormant == 0) {
-		fromFormant = 1; toFormant = my trackmodelers.size;
+		fromFormant = 1;
+		toFormant = my trackmodelers.size;
 	}
 	if (fromFormant >= 1 && toFormant <= my trackmodelers.size) {
 		for (long iformant= fromFormant; iformant <= toFormant; iformant ++) {
@@ -1813,7 +1816,7 @@ autoFormantModeler FormantModeler_processOutliers (FormantModeler me, double num
 		autoFormantModeler thee = Data_copy (me);
 		for (long i = 1; i <= numberOfDataPoints; i ++) {
 			// First the easy one: first formant missing: F1' = F2; F2' = F3
-			if (NUMdefined (z[1][i]) && NUMdefined (z[1][i]) && NUMdefined (z[3][i])) {
+			if (isdefined (z[1][i]) && isdefined (z[1][i]) && isdefined (z[3][i])) {
 				if (z[1][i] > numberOfSigmas && z[2][i] > numberOfSigmas && z[3][i] > numberOfSigmas) {
 					// all deviations have the same sign:
 					// probably F1 is missing
@@ -1834,15 +1837,16 @@ autoFormantModeler FormantModeler_processOutliers (FormantModeler me, double num
 }
 
 double FormantModeler_getSmoothnessValue (FormantModeler me, long fromFormant, long toFormant, long numberOfParametersPerTrack, double power) {
-	double smoothness = NUMundefined;
+	double smoothness = undefined;
 	if (toFormant < fromFormant || (toFormant == 0 && fromFormant == 0)) {
-		fromFormant = 1; toFormant = my trackmodelers. size;
+		fromFormant = 1;
+		toFormant = my trackmodelers.size;
 	}
-	if (fromFormant > 0 && fromFormant <= toFormant && toFormant <= my trackmodelers. size) {
+	if (fromFormant > 0 && fromFormant <= toFormant && toFormant <= my trackmodelers.size) {
 		long nofp;
 		double ndof, var = FormantModeler_getVarianceOfParameters (me, fromFormant, toFormant, 1, numberOfParametersPerTrack, &nofp);
 		double chisq = FormantModeler_getChiSquaredQ (me, fromFormant, toFormant, true, nullptr, &ndof);
-		if (NUMdefined (var) && NUMdefined (chisq) && nofp > 0) {
+		if (isdefined (var) && isdefined (chisq) && nofp > 0) {
 			smoothness = log10 (pow (var / nofp, power) * (chisq / ndof));
 		}
 	}
@@ -1850,11 +1854,11 @@ double FormantModeler_getSmoothnessValue (FormantModeler me, long fromFormant, l
 }
 
 double FormantModeler_getAverageDistanceBetweenTracks (FormantModeler me, long track1, long track2, int type) {
-	double diff = NUMundefined;
+	double diff = undefined;
 	if (track1 == track2) {
-		return 0;
+		return 0.0;
 	}
-	if (track1 <= my trackmodelers. size && track2 <= my trackmodelers.size) {
+	if (track1 <= my trackmodelers.size && track2 <= my trackmodelers.size) {
 		DataModeler fi = my trackmodelers.at [track1];
 		DataModeler fj = my trackmodelers.at [track2];
 		// fi and fj have equal number of data points
@@ -1862,13 +1866,13 @@ double FormantModeler_getAverageDistanceBetweenTracks (FormantModeler me, long t
 		diff = 0.0;
 		for (long i = 1; i <= fi -> numberOfDataPoints; i ++) {
 			if (type != 0) {
-				double fie = fi -> f_evaluate (fi, fi -> x[i], fi -> parameter);
-				double fje = fj -> f_evaluate (fj, fj -> x[i], fj -> parameter);
+				double fie = fi -> f_evaluate (fi, fi -> x [i], fi -> parameter);
+				double fje = fj -> f_evaluate (fj, fj -> x [i], fj -> parameter);
 				diff += fabs (fie - fje);
-				numberOfDataPoints++;
-			} else if (fi -> dataPointStatus[i] != DataModeler_DATA_INVALID && fj -> dataPointStatus[i] != DataModeler_DATA_INVALID) {
-				diff += fabs (fi -> y[i] - fj -> y[i]);
-				numberOfDataPoints++;
+				numberOfDataPoints ++;
+			} else if (fi -> dataPointStatus [i] != DataModeler_DATA_INVALID && fj -> dataPointStatus [i] != DataModeler_DATA_INVALID) {
+				diff += fabs (fi -> y [i] - fj -> y [i]);
+				numberOfDataPoints ++;
 			}
 		}
 		diff /= numberOfDataPoints;
@@ -1974,7 +1978,7 @@ long Formants_getSmoothestInInterval (CollectionOf<structFormant>* me, double tm
 				FormantModeler_setParameterValuesToZero (fs.get(), 1, numberOfFormantTracks, numberOfSigmas);
 				double cf = useConstraints ? FormantModeler_getFormantsConstraintsFactor (fs.get(), minF1, maxF1, minF2, maxF2, minF3) : 1;
 				double chiVar = FormantModeler_getSmoothnessValue (fs.get(), 1, numberOfFormantTracks, numberOfParametersPerTrack, power);
-				if (NUMdefined (chiVar) && cf * chiVar < minChiVar) {
+				if (isdefined (chiVar) && cf * chiVar < minChiVar) {
 					minChiVar = cf * chiVar;
 					index = iobject;
 				}
@@ -1994,11 +1998,11 @@ autoFormant Formant_extractPart (Formant me, double tmin, double tmax) {
 		if (tmin >= my xmax || tmax <= my xmin) {
 			Melder_throw (U"Your start and end time should be between ", my xmin, U" and ", my xmax, U".");
 		}
-		long thyindex = 1, ifmin, ifmax;
-		long numberOfFrames = Sampled_getWindowSamples (me, tmin, tmax, &ifmin, &ifmax);
+		integer thyindex = 1, ifmin, ifmax;
+		long numberOfFrames = Sampled_getWindowSamples (me, tmin, tmax, & ifmin, & ifmax);
 		double t1 = Sampled_indexToX (me, ifmin);
 		autoFormant thee = Formant_create (tmin, tmax, numberOfFrames, my dx, t1, my maxnFormants);
-		for (long iframe = ifmin; iframe <= ifmax; iframe++, thyindex++) {
+		for (integer iframe = ifmin; iframe <= ifmax; iframe++, thyindex++) {
 			Formant_Frame myFrame = & my d_frames [iframe];
 			Formant_Frame thyFrame = & thy d_frames [thyindex];
 			myFrame -> copy (thyFrame);
@@ -2040,18 +2044,18 @@ Thing_implement (PitchModeler, DataModeler, 0);
 
 autoPitchModeler Pitch_to_PitchModeler (Pitch me, double tmin, double tmax, long numberOfParameters) {
 	try {
-		long ifmin, ifmax;
+		integer ifmin, ifmax;
 		if (tmax <= tmin) {
 			tmin = my xmin; tmax = my xmax;
 		}
-		long numberOfDataPoints = Sampled_getWindowSamples (me, tmin, tmax, &ifmin, &ifmax);
+		integer numberOfDataPoints = Sampled_getWindowSamples (me, tmin, tmax, & ifmin, & ifmax);
 		if (numberOfDataPoints < numberOfParameters) {
 			Melder_throw (U"Not enough data points, extend the selection.");
 		}
 		autoPitchModeler thee = Thing_new (PitchModeler);
 		DataModeler_init (thee.get(), tmin, tmax, numberOfDataPoints, numberOfParameters, DataModeler_TYPE_LEGENDRE);
-		long idata = 0, validData = 0;
-		for (long iframe = ifmin; iframe <= ifmax; iframe ++) {
+		integer idata = 0, validData = 0;
+		for (integer iframe = ifmin; iframe <= ifmax; iframe ++) {
 			thy x [++ idata] = Sampled_indexToX (me, iframe);
 			thy dataPointStatus[idata] = DataModeler_DATA_INVALID;
 			if (Pitch_isVoiced_i (me, iframe)) {
@@ -2128,7 +2132,7 @@ autoFormant Sound_to_Formant_interval (Sound me, double startTime, double endTim
 			double cf = ( useConstraints ? FormantModeler_getFormantsConstraintsFactor (fm.get(), minF1, maxF1, minF2, maxF2, minF3) : 1 );
 			double chiVar = FormantModeler_getSmoothnessValue (fm.get(), 1, numberOfFormantTracks, numberOfParametersPerTrack, power);
 			double criterium = chiVar * cf;
-			if (NUMdefined (chiVar) && criterium < mincriterium) {
+			if (isdefined (chiVar) && criterium < mincriterium) {
 				mincriterium = criterium;
 				optimalCeiling = currentCeiling;
 				i_best = i;
@@ -2182,7 +2186,7 @@ autoFormant Sound_to_Formant_interval_robust (Sound me, double startTime, double
 			double cf = ( useConstraints ? FormantModeler_getFormantsConstraintsFactor (fm.get(), minF1, maxF1, minF2, maxF2, minF3) : 1 );
 			double chiVar = FormantModeler_getSmoothnessValue (fm.get(), 1, numberOfFormantTracks, numberOfParametersPerTrack, power);
 			double criterium = chiVar * cf;
-			if (NUMdefined (chiVar) && criterium < mincriterium) {
+			if (isdefined (chiVar) && criterium < mincriterium) {
 				mincriterium = criterium;
 				optimalCeiling = currentCeiling;
 				i_best = i;
diff --git a/dwtools/Discriminant.cpp b/dwtools/Discriminant.cpp
index e3fa3e9..c964638 100644
--- a/dwtools/Discriminant.cpp
+++ b/dwtools/Discriminant.cpp
@@ -94,7 +94,7 @@ autoDiscriminant Discriminant_create (long numberOfGroups, long numberOfEigenval
 }
 
 long Discriminant_groupLabelToIndex (Discriminant me, const char32 *label) {
-	char32 *name;
+	const char32 *name;
 
 	for (long i = 1; i <= my numberOfGroups; i ++) {
 		if (!! (name = Thing_getName (my groups -> at [i])) && str32equ (name, label)) {
@@ -156,7 +156,7 @@ autoStrings Discriminant_extractGroupLabels (Discriminant me) {
 		thy strings = NUMvector<char32 *> (1, my numberOfGroups);
 		thy numberOfStrings = my numberOfGroups;
 		for (long i = 1; i <= my numberOfGroups; i ++) {
-			char32 *name = Thing_getName (my groups->at [i]);
+			const char32 *name = Thing_getName (my groups->at [i]);
 			thy strings [i] = Melder_dup (name);
 		}
 		return thee;
@@ -192,7 +192,7 @@ autoTableOfReal Discriminant_extractGroupStandardDeviations (Discriminant me) {
 			TableOfReal_setRowLabel (thee.get(), i, Thing_getName (sscp));
 			long numberOfObservationsm1 = (long) floor (sscp -> numberOfObservations) - 1;
 			for (long j = 1; j <= n; j ++) {
-				thy data [i] [j] = numberOfObservationsm1 > 0 ? sqrt (sscp -> data [j] [j] / numberOfObservationsm1) : NUMundefined;
+				thy data [i] [j] = ( numberOfObservationsm1 > 0 ? sqrt (sscp -> data [j] [j] / numberOfObservationsm1) : undefined );
 			}
 		}
 		NUMstrings_copyElements (my groups->at [m] -> columnLabels, thy columnLabels, 1, n);
@@ -269,7 +269,7 @@ void Discriminant_getPartialDiscriminationProbability (Discriminant me, long num
 	long numberOfFunctions = Discriminant_getNumberOfFunctions (me);
 	double degreesOfFreedom = Discriminant_getDegreesOfFreedom (me);
 
-	double prob = NUMundefined,  chisq = NUMundefined, df = NUMundefined;
+	double prob = undefined, chisq = undefined, df = undefined;
 
 	if (k < numberOfFunctions) {
 		double lambda = NUMwilksLambda (my eigen -> eigenvalues, k + 1, numberOfFunctions);
@@ -295,7 +295,7 @@ void Discriminant_getPartialDiscriminationProbability (Discriminant me, long num
 double Discriminant_getConcentrationEllipseArea (Discriminant me, long group,
         double scale, bool confidence, int discriminantDirections, long d1, long d2)
 {
-	double area = NUMundefined;
+	double area = undefined;
 
 	if (group < 1 || group > my numberOfGroups) {
 		return area;
@@ -312,7 +312,7 @@ double Discriminant_getConcentrationEllipseArea (Discriminant me, long group,
 
 double Discriminant_getLnDeterminant_group (Discriminant me, long group) {
 	if (group < 1 || group > my numberOfGroups) {
-		return NUMundefined;
+		return undefined;
 	}
 	autoCovariance c = SSCP_to_Covariance (my groups->at [group], 1);
 	double ln_d = SSCP_getLnDeterminant (c.get());
diff --git a/dwtools/EditDistanceTable.cpp b/dwtools/EditDistanceTable.cpp
index 92c8660..e63d639 100644
--- a/dwtools/EditDistanceTable.cpp
+++ b/dwtools/EditDistanceTable.cpp
@@ -415,7 +415,7 @@ static void print4 (char *buffer, double value, int iformat, int width, int prec
 		if (numerator == 0)
 			snprintf (buffer, 40, "0");
 		else if (denominator > 1)
-			snprintf (buffer, 40, "%ld/%ld", numerator, denominator);
+			snprintf (buffer, 40, "%s/%s", Melder8_integer (numerator), Melder8_integer (denominator));
 		else
 			snprintf (buffer, 40, "%.7g", value);
 	} else {
diff --git a/dwtools/FilterBank.cpp b/dwtools/FilterBank.cpp
index eded5fb..ee6c63b 100644
--- a/dwtools/FilterBank.cpp
+++ b/dwtools/FilterBank.cpp
@@ -1,6 +1,6 @@
 /* FilterBank.cpp
  *
- * Copyright (C) 1993-2012, 2014-2015 David Weenink
+ * Copyright (C) 1993-2012, 2014-2015 David Weenink, Paul Boersma 2017
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@
 #define MIN(m,n) ((m) < (n) ? (m) : (n))
 
 static double scaleFrequency (double f, int scale_from, int scale_to) {
-	double fhz = NUMundefined;
+	double fhz = undefined;
 
 	if (scale_from == scale_to) {
 		return f;
@@ -52,7 +52,7 @@ static double scaleFrequency (double f, int scale_from, int scale_to) {
 		fhz = MELTOHZ (f);
 	}
 
-	if (scale_to == FilterBank_HERTZ || fhz == NUMundefined) {
+	if (scale_to == FilterBank_HERTZ || isundef (fhz)) {
 		return fhz;
 	}
 
@@ -61,7 +61,7 @@ static double scaleFrequency (double f, int scale_from, int scale_to) {
 	} else if (scale_to == FilterBank_MEL) {
 		f = HZTOMEL (fhz);
 	} else {
-		return NUMundefined;
+		return undefined;
 	}
 	return f;
 }
@@ -139,7 +139,7 @@ static void setDrawingLimits (double *a, long n, double amin, double amax, long
 
 	long lower = 1;
 	for (long i = 1; i <= n; i++) {
-		if (a[i] == NUMundefined) {
+		if (isundef (a[i])) {
 			if (lower == 0) {
 				// high frequency part
 				*iend = i;
@@ -252,9 +252,9 @@ void FilterBank_paint (FilterBank me, Graphics g, double xmin, double xmax, doub
 	if (ymax <= ymin) {
 		ymin = my ymin; ymax = my ymax;
 	}
-	long ixmin, ixmax, iymin, iymax;
-	(void) Matrix_getWindowSamplesX (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx, &ixmin, &ixmax);
-	(void) Matrix_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy, &iymin, &iymax);
+	integer ixmin, ixmax, iymin, iymax;
+	(void) Matrix_getWindowSamplesX (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx, & ixmin, & ixmax);
+	(void) Matrix_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy, & iymin, & iymax);
 	if (maximum <= minimum) {
 		(void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, &minimum, &maximum);
 	}
@@ -292,27 +292,26 @@ void BarkFilter_drawSekeyHansonFilterFunctions (BarkFilter me, Graphics g, int t
 	Graphics_setInner (g);
 	Graphics_setWindow (g, zmin, zmax, ymin, ymax);
 
-	for (long j = fromFilter; j <= toFilter; j++) {
+	for (long j = fromFilter; j <= toFilter; j ++) {
 		double df = (zmax - zmin) / (n - 1);
 		double zMid = Matrix_rowToY (me, j);
-		long ibegin, iend;
 
-		for (long i = 1; i <= n; i++) {
+		for (long i = 1; i <= n; i ++) {
 			double f = zmin + (i - 1) * df;
 			double z = scaleFrequency (f, toFreqScale, FilterBank_BARK);
-			if (z == NUMundefined) {
-				a[i] = NUMundefined;
+			if (isundef (z)) {
+				a [i] = undefined;
 			} else {
 				z -= zMid + 0.215;
-				a[i] = 7.0 - 7.5 * z - 17.5 * sqrt (0.196 + z * z);
+				a [i] = 7.0 - 7.5 * z - 17.5 * sqrt (0.196 + z * z);
 				if (! dbScale) {
 					a[i] = pow (10.0, a[i]);
 				}
 			}
 		}
 
-		setDrawingLimits (a.peek(), n, ymin, ymax, &ibegin, &iend);
-
+		long ibegin, iend;
+		setDrawingLimits (a.peek(), n, ymin, ymax, & ibegin, & iend);
 		if (ibegin <= iend) {
 			double fmin = zmin + (ibegin - 1) * df;
 			double fmax = zmax - (n - iend) * df;
@@ -391,12 +390,12 @@ void MelFilter_drawFilterFunctions (MelFilter me, Graphics g, int toFreqScale, i
 			// Filterfunction: triangular on a linear frequency scale AND a linear amplitude scale.
 			double f = zmin + (i - 1) * df;
 			double z = scaleFrequency (f, toFreqScale, FilterBank_HERTZ);
-			if (z == NUMundefined) {
-				a[i] = NUMundefined;
+			if (isundef (z)) {
+				a [i] = undefined;
 			} else {
-				a[i] = NUMtriangularfilter_amplitude (fl_hz, fc_hz, fh_hz, z);
+				a [i] = NUMtriangularfilter_amplitude (fl_hz, fc_hz, fh_hz, z);
 				if (dbScale) {
-					a[i] = to_dB (a[i], 10, ymin);
+					a [i] = to_dB (a [i], 10.0, ymin);
 				}
 			}
 		}
@@ -523,12 +522,12 @@ void FormantFilter_drawFilterFunctions (FormantFilter me, Graphics g, double ban
 		for (long i = 1; i <= n; i++) {
 			double f = zmin + (i - 1) * df;
 			double z = scaleFrequency (f, toFreqScale, FilterBank_HERTZ);
-			if (z == NUMundefined) {
-				a[i] = NUMundefined;
+			if (isundef (z)) {
+				a [i] = undefined;
 			} else {
-				a[i] = NUMformantfilter_amplitude (fc, bandwidth, z);
+				a [i] = NUMformantfilter_amplitude (fc, bandwidth, z);
 				if (dbScale) {
-					a[i] = to_dB (a[i], 10, ymin);
+					a [i] = to_dB (a [i], 10, ymin);
 				}
 			}
 		}
@@ -1164,7 +1163,7 @@ autoFormantFilter Sound_and_Pitch_to_FormantFilter (Sound me, Pitch thee, double
 
 		double f0_median = Pitch_getQuantile (thee, thy xmin, thy xmax, 0.5, kPitch_unit_HERTZ);
 
-		if (f0_median == NUMundefined || f0_median == 0) {
+		if (isundef (f0_median) || f0_median == 0.0) {
 			f0_median = 100;
 			Melder_warning (U"Pitch values undefined. Bandwith fixed to 100 Hz. ");
 		}
@@ -1198,8 +1197,9 @@ autoFormantFilter Sound_and_Pitch_to_FormantFilter (Sound me, Pitch thee, double
 			double t = Sampled_indexToX (him.get(), i);
 			double b, f0 = Pitch_getValueAtTime (thee, t, kPitch_unit_HERTZ, 0);
 
-			if (f0 == NUMundefined || f0 == 0) {
-				f0_undefined++; f0 = f0_median;
+			if (isundef (f0) || f0 == 0.0) {
+				f0_undefined ++;
+				f0 = f0_median;
 			}
 			b = relative_bw * f0;
 			Sound_into_Sound (me, sframe.get(), t - windowDuration / 2);
@@ -1207,9 +1207,8 @@ autoFormantFilter Sound_and_Pitch_to_FormantFilter (Sound me, Pitch thee, double
 
 			Sound_into_FormantFilter_frame (sframe.get(), him.get(), i, b);
 
-			if ( (i % 10) == 1) {
-				Melder_progress ( (double) i / nt, U"Frame ", i, U" out of ",
-				                   nt, U".");
+			if (i % 10 == 1) {
+				Melder_progress ((double) i / nt, U"Frame ", i, U" out of ", nt, U".");
 			}
 		}
 
diff --git a/dwtools/GaussianMixture.cpp b/dwtools/GaussianMixture.cpp
index 2d2bb2c..3ac3513 100644
--- a/dwtools/GaussianMixture.cpp
+++ b/dwtools/GaussianMixture.cpp
@@ -61,13 +61,15 @@ void GaussianMixture_updateProbabilityMarginals (GaussianMixture me, double **p,
 long GaussianMixture_getNumberOfParametersInComponent (GaussianMixture me);
 
 static void NUMdvector_scaleAsProbabilities (double *v, long n) {
-	double sum = 0;
-	for (long i = 1; i <= n; i++) {
-		sum += v[i];
+	real80 sum = 0.0;
+	for (long i = 1; i <= n; i ++) {
+		sum += v [i];
 	}
-	if (sum > 0) for (long i = 1; i <= n; i++) {
-			v[i] /= sum;
+	if (sum > 0.0) {
+		for (long i = 1; i <= n; i ++) {
+			v [i] /= sum;
 		}
+	}
 }
 
 static void GaussianMixture_updateCovariance (GaussianMixture me, long component, double **data, long numberOfRows, double **p) {
@@ -81,7 +83,7 @@ static void GaussianMixture_updateCovariance (GaussianMixture me, long component
 	// update the means
 
 	for (long j = 1; j <= thy numberOfColumns; j ++) {
-		thy centroid [j] = 0;
+		thy centroid [j] = 0.0;
 		for (long i = 1; i <= numberOfRows; i ++) {
 			double gamma = mixprob * p [i] [component] / p [i] [my numberOfComponents + 1];
 			thy centroid [j] += gamma * data [i] [j] ; // eq. Bishop 9.17
@@ -302,7 +304,7 @@ autoCovariance GaussianMixture_to_Covariance_between (GaussianMixture me) {
 
 		for (long i = 1; i <= my numberOfComponents; i ++) {
 			Covariance him = my covariances->at [i];
-			double nobs = his numberOfObservations - 1; // we loose 1 degree of freedom
+			double nobs = his numberOfObservations - 1; // we lose 1 degree of freedom
 			for (long ir = 1; ir <= my dimension; ir ++) {
 				double dir = his centroid [ir] - thy centroid [ir];
 				for (long ic = ir; ic <= my dimension; ic ++) {
@@ -345,7 +347,7 @@ autoCovariance GaussianMixture_to_Covariance_within (GaussianMixture me) {
 					}
 				}
 			}
-			thy numberOfObservations += his numberOfObservations - 1; // we loose a degree of freedom?
+			thy numberOfObservations += his numberOfObservations - 1; // we lose a degree of freedom?
 		}
 
 		// Leave centroid at 0 so we can add the within and between covariance nicely
@@ -435,7 +437,7 @@ autoPCA GaussianMixture_to_PCA (GaussianMixture me) {
 }
 
 void GaussianMixture_getIntervalsAlongDirections (GaussianMixture me, long d1, long d2, double nsigmas, double *xmin, double *xmax, double *ymin, double *ymax) {
-	*xmin = *xmax = *ymin = *ymax = NUMundefined;
+	*xmin = *xmax = *ymin = *ymax = undefined;
 	if (d1 < 1 || d1 > my dimension || d2 < 1 || d2 > my dimension) {
 		Melder_throw (U"Incorrect directions.");
 	}
@@ -1015,7 +1017,7 @@ void GaussianMixture_removeComponent_bookkeeping (GaussianMixture me, long compo
 }
 
 double GaussianMixture_and_TableOfReal_getLikelihoodValue (GaussianMixture me, TableOfReal thee, int criterion) {
-	double value = NUMundefined;
+	double value = undefined;
 	autoNUMmatrix<double> pp (1, thy numberOfRows + 1, 1, my numberOfComponents + 1);
 	if (GaussianMixture_and_TableOfReal_getProbabilities (me, thee, 0, pp.peek())) {
 		value = GaussianMixture_getLikelihoodValue (me, pp.peek(), thy numberOfRows, criterion);
@@ -1387,7 +1389,7 @@ autoTableOfReal GaussianMixture_and_TableOfReal_to_TableOfReal_BHEPNormalityTest
 			             - 4.0 * pow (delta, -d2) * (1.0 + 3.0 * d * beta4 / (2.0 * delta) + d * (d + 2.0) * beta8 / (2.0 * delta2));
 			double mu2 = mu * mu;
 
-			double prob = NUMundefined, tnb = NUMundefined, lnmu = NUMundefined, lnvar = NUMundefined;
+			double prob = undefined, tnb = undefined, lnmu = undefined, lnvar = undefined;
 
 			try {
 				SSCP_expandLowerCholesky (cov);
diff --git a/dwtools/HMM.cpp b/dwtools/HMM.cpp
index e369e39..2818ffa 100644
--- a/dwtools/HMM.cpp
+++ b/dwtools/HMM.cpp
@@ -1,6 +1,6 @@
 /* HMM.cpp
  *
- * Copyright (C) 2010-2012,2015 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 2010-2012,2015 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -91,7 +91,7 @@ autoHMMViterbi HMM_to_HMMViterbi (HMM me, long *obs, long ntimes);
 
 // evaluate the numbers given to probabilities
 static double *NUMwstring_to_probs (char32 *s, long nwanted) {
-	long numbers_found;
+	integer numbers_found;
 	autoNUMvector<double> numbers (NUMstring_to_numbers (s, & numbers_found), 1);
 	if (numbers_found != nwanted) {
 		Melder_throw (U"You supplied ", numbers_found, U", while ", nwanted, U" numbers needed.");
@@ -136,11 +136,11 @@ int NUMget_line_intersection_with_circle (double xc, double yc, double r, double
 static double HMM_and_HMM_getCrossEntropy_asym (HMM me, HMM thee, long observationLength) {
 	autoHMMObservationSequence os = HMM_to_HMMObservationSequence (thee, 0, observationLength);
 	double ce = HMM_and_HMMObservationSequence_getCrossEntropy (me, os.get());
-	if (ce == NUMundefined || ce == INFINITY) {
+	if (isundef (ce)) {
 		return ce;
 	}
 	double ce2 = HMM_and_HMMObservationSequence_getCrossEntropy (thee, os.get());
-	if (ce2 == NUMundefined || ce2 == INFINITY) {
+	if (isundef (ce2)) {
 		return ce2;
 	}
 	return ce - ce2;
@@ -667,25 +667,25 @@ autoTableOfReal HMM_extractEmissionProbabilities (HMM me) {
 
 double HMM_getExpectedValueOfDurationInState (HMM me, long istate) {
 	if (istate < 0 || istate > my numberOfStates) {
-		return NUMundefined;
+		return undefined;
 	}
 	return 1.0 / (1.0 - my transitionProbs [istate] [istate]);
 }
 
 double HMM_getProbabilityOfStayingInState (HMM me, long istate, long numberOfTimeUnits) {
 	if (istate < 0 || istate > my numberOfStates) {
-		return NUMundefined;
+		return undefined;
 	}
 	return pow (my transitionProbs [istate] [istate], numberOfTimeUnits - 1.0) * (1.0 - my transitionProbs[istate][istate]);
 }
 
 double HMM_and_HMM_getCrossEntropy (HMM me, HMM thee, long observationLength, int symmetric) {
 	double ce1 = HMM_and_HMM_getCrossEntropy_asym (me, thee, observationLength);
-	if (! symmetric || ce1 == NUMundefined || ce1 == INFINITY) {
+	if (! symmetric || isundef (ce1)) {
 		return ce1;
 	}
 	double ce2 = HMM_and_HMM_getCrossEntropy_asym (thee, me, observationLength);
-	if (ce2 == NUMundefined || ce2 == INFINITY) {
+	if (isundef (ce2)) {
 		return ce2;
 	}
 	return (ce1 + ce2) / 2.0;
@@ -693,11 +693,11 @@ double HMM_and_HMM_getCrossEntropy (HMM me, HMM thee, long observationLength, in
 
 double HMM_and_HMM_and_HMMObservationSequence_getCrossEntropy (HMM me, HMM thee, HMMObservationSequence him) {
 	double ce1 = HMM_and_HMMObservationSequence_getCrossEntropy (me, him);
-	if (ce1 == NUMundefined || ce1 == INFINITY) {
+	if (isundef (ce1)) {
 		return ce1;
 	}
 	double ce2 = HMM_and_HMMObservationSequence_getCrossEntropy (thee, him);
-	if (ce2 == NUMundefined || ce2 == INFINITY) {
+	if (isundef (ce2)) {
 		return ce2;
 	}
 	return (ce1 + ce2) / 2.0;
@@ -1369,11 +1369,11 @@ double HMM_and_HMMStateSequence_getProbability (HMM me, HMMStateSequence thee) {
 	long *index = si -> classIndex;
 
 	if (index == 0) {
-		return NUMundefined;
+		return undefined;
 	}
 	if (numberOfUnknowns > 0) {
 		Melder_warning (U"Unknown states (# = ", numberOfUnknowns, U").");
-		return NUMundefined;
+		return undefined;
 	}
 	double p0 = my transitionProbs [0] [index [1]];
 	if (p0 == 0) {
@@ -1388,7 +1388,7 @@ double HMM_and_HMMStateSequence_getProbability (HMM me, HMMStateSequence thee) {
 
 double HMM_getProbabilityAtTimeBeingInState (HMM me, long itime, long istate) {
 	if (istate < 1 || istate > my numberOfStates) {
-		return NUMundefined;
+		return undefined;
 	}
 
 	autoNUMvector<double> scale (1, itime);
@@ -1434,10 +1434,10 @@ double HMM_getProbabilityAtTimeBeingInState (HMM me, long itime, long istate) {
 double HMM_getProbabilityAtTimeBeingInStateEmittingSymbol (HMM me, long itime, long istate, long isymbol) {
 	// for a notHidden model emissionProbs may be zero!
 	if (isymbol < 1 || isymbol > my numberOfObservationSymbols || my emissionProbs[istate][isymbol] == 0) {
-		return NUMundefined;
+		return undefined;
 	}
 	double lnp = HMM_getProbabilityAtTimeBeingInState (me, itime, istate);
-	return lnp != NUMundefined && lnp != -INFINITY ? lnp + log (my emissionProbs[istate][isymbol]) : lnp;
+	return ( isundef (lnp) ? undefined : lnp + log (my emissionProbs [istate] [isymbol]) );
 }
 
 double HMM_getProbabilityOfObservations (HMM me, long *obs, long numberOfTimes) {
@@ -1499,13 +1499,13 @@ double HMM_and_HMMObservationSequence_getProbability (HMM me, HMMObservationSequ
 
 double HMM_and_HMMObservationSequence_getCrossEntropy (HMM me, HMMObservationSequence thee) {
 	double lnp = HMM_and_HMMObservationSequence_getProbability (me, thee);
-	return lnp == NUMundefined ? NUMundefined : (lnp == -INFINITY ? INFINITY :
-	        -lnp / (NUMln10 * HMMObservationSequence_getNumberOfObservations (thee)));
+	return isundef (lnp) ? undefined :
+	        -lnp / (NUMln10 * HMMObservationSequence_getNumberOfObservations (thee));
 }
 
 double HMM_and_HMMObservationSequence_getPerplexity (HMM me, HMMObservationSequence thee) {
 	double ce = HMM_and_HMMObservationSequence_getCrossEntropy (me, thee);
-	return ce == NUMundefined ? NUMundefined : (ce == INFINITY ? INFINITY : pow (2, ce));
+	return isundef (ce) ? undefined : pow (2.0, ce);
 }
 
 autoHMM HMM_createFromHMMObservationSequence (HMMObservationSequence me, long numberOfStates, int leftToRight) {
diff --git a/dwtools/HMM_def.h b/dwtools/HMM_def.h
index 82bd689..8b187f0 100644
--- a/dwtools/HMM_def.h
+++ b/dwtools/HMM_def.h
@@ -20,19 +20,19 @@
 #define ooSTRUCT HMMState
 oo_DEFINE_CLASS (HMMState, Daata)
 
-	oo_STRING(label)
+	oo_STRING (label)
 
-oo_END_CLASS(HMMState)
+oo_END_CLASS (HMMState)
 #undef ooSTRUCT
 
 
 #define ooSTRUCT HMMObservation
 oo_DEFINE_CLASS (HMMObservation, Daata)
 
-	oo_STRING(label)
+	oo_STRING (label)
 	oo_AUTO_OBJECT (GaussianMixture, 1, gm)
 
-oo_END_CLASS(HMMObservation)
+oo_END_CLASS (HMMObservation)
 #undef ooSTRUCT
 
 
@@ -56,7 +56,7 @@ oo_DEFINE_CLASS (HMM, Daata)
 			override;
 	#endif
 
-oo_END_CLASS(HMM)
+oo_END_CLASS (HMM)
 #undef ooSTRUCT
 
 
@@ -70,7 +70,7 @@ oo_DEFINE_CLASS (HMMViterbi, Daata)
 	oo_LONG_MATRIX (bp, numberOfStates, numberOfTimes)
 	oo_LONG_VECTOR (path, numberOfTimes)
 
-oo_END_CLASS(HMMViterbi)
+oo_END_CLASS (HMMViterbi)
 #undef ooSTRUCT
 
 
diff --git a/dwtools/Intensity_extensions.cpp b/dwtools/Intensity_extensions.cpp
index f5f3676..fd9be84 100644
--- a/dwtools/Intensity_extensions.cpp
+++ b/dwtools/Intensity_extensions.cpp
@@ -1,6 +1,6 @@
 /* Intensity_extensions.cpp
  *
- * Copyright (C) 2007-2011 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 2007-2011 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,12 +31,16 @@ static void IntervalTier_addBoundaryUnsorted (IntervalTier me, long iinterval, d
 		Melder_throw (U"Time is outside interval.");
 	}
 
-	// Find interval to split
+	/*
+		Find interval to split.
+	*/
 	if (iinterval <= 0) {
 		iinterval = IntervalTier_timeToLowIndex (me, time);
 	}
 
-	// Modify end time of left label
+	/*
+		Modify end time of left label.
+	*/
 	TextInterval ti = my intervals.at [iinterval];
 	ti -> xmax = time;
 	TextInterval_setText (ti, leftLabel);
@@ -49,7 +53,7 @@ autoTextGrid Intensity_to_TextGrid_detectSilences (Intensity me, double silenceT
 	try {
 		double duration = my xmax - my xmin, time;
 
-		if (silenceThreshold_dB >= 0) {
+		if (silenceThreshold_dB >= 0.0) {
 			Melder_throw (U"The silence threshold w.r.t. the maximum intensity should be a negative number.");
 		}
 
@@ -61,12 +65,12 @@ autoTextGrid Intensity_to_TextGrid_detectSilences (Intensity me, double silenceT
 		}
 
 		double intensity_max_db, intensity_min_db, xOfMaximum, xOfMinimum;
-		Vector_getMaximumAndX (me, 0, 0, 1, NUM_PEAK_INTERPOLATE_PARABOLIC, &intensity_max_db, &xOfMaximum);
-		Vector_getMinimumAndX (me, 0, 0, 1, NUM_PEAK_INTERPOLATE_PARABOLIC, &intensity_min_db, &xOfMinimum);
+		Vector_getMaximumAndX (me, 0.0, 0.0, 1, NUM_PEAK_INTERPOLATE_PARABOLIC, & intensity_max_db, & xOfMaximum);
+		Vector_getMinimumAndX (me, 0.0, 0.0, 1, NUM_PEAK_INTERPOLATE_PARABOLIC, & intensity_min_db, & xOfMinimum);
 		double intensity_dbRange = intensity_max_db - intensity_min_db;
 
-		if (intensity_dbRange < 10) {
-			Melder_warning (U"The loudest and softest part in your sound only differ by ", intensity_dbRange, U" dB.");
+		if (intensity_dbRange < 10.0) {
+			Melder_warning (U"The loudest and softest part in your sound differ by only ", intensity_dbRange, U" dB.");
 		}
 		double intensityThreshold = intensity_max_db - fabs (silenceThreshold_dB);
 
@@ -74,21 +78,21 @@ autoTextGrid Intensity_to_TextGrid_detectSilences (Intensity me, double silenceT
 			return thee;
 		}
 
-		int inSilenceInterval = my z[1][1] < intensityThreshold;
+		bool inSilenceInterval = my z [1] [1] < intensityThreshold;
 		long iinterval = 1;
 		const char32 *label;
-		for (long i = 2; i <= my nx; i++) {
-			int addBoundary = 0;
-			if (my z[1][i] < intensityThreshold) {
-				if (!inSilenceInterval) { // Start of silence
-					addBoundary = 1;
-					inSilenceInterval = 1;
+		for (long i = 2; i <= my nx; i ++) {
+			bool addBoundary = false;
+			if (my z [1] [i] < intensityThreshold) {
+				if (! inSilenceInterval) {   // start of silence
+					addBoundary = true;
+					inSilenceInterval = true;
 					label = soundingLabel;
 				}
 			} else {
-				if (inSilenceInterval) { // End of silence
-					addBoundary = 1;
-					inSilenceInterval = 0;
+				if (inSilenceInterval) {   // end of silence
+					addBoundary = true;
+					inSilenceInterval = false;
 					label = silenceLabel;
 				}
 			}
@@ -100,17 +104,20 @@ autoTextGrid Intensity_to_TextGrid_detectSilences (Intensity me, double silenceT
 			}
 		}
 
-		// (re)label last interval */
+		/*
+			(re)label last interval.
+		*/
 
 		label = inSilenceInterval ? silenceLabel : soundingLabel;
 		TextInterval_setText (it -> intervals.at [iinterval], label);
 		it -> intervals. sort ();
 
-		// First remove short non-silence intervals in-between silence intervals and
-		// then remove the remaining short silence intervals.
-		// This works much better than first removing short silence intervals and
-		// then short non-silence intervals.
-
+		/*
+			First remove short non-silence intervals in-between silence intervals and
+			then remove the remaining short silence intervals.
+			This works much better than first removing short silence intervals and
+			then short non-silence intervals.
+		*/
 		IntervalTier_cutIntervals_minimumDuration (it, soundingLabel, minSoundingDuration);
 		IntervalTier_cutIntervalsOnLabelMatch (it, silenceLabel);
 		IntervalTier_cutIntervals_minimumDuration (it, silenceLabel, minSilenceDuration);
@@ -127,24 +134,25 @@ autoIntensity IntensityTier_to_Intensity (IntensityTier me, double dt) {
 		long nt = (long) floor ((my xmax - my xmin) / dt);
 		double t1 = 0.5 * dt;
 		autoIntensity thee = Intensity_create (my xmin, my xmax, nt, dt, t1);
-		for (long i = 1; i <= nt; i++) {
+		for (long i = 1; i <= nt; i ++) {
 			double time = t1 + (i - 1) * dt;
-			thy z[1][i] = RealTier_getValueAtTime (me, time);
+			thy z [1] [i] = RealTier_getValueAtTime (me, time);
 		}
 		return thee;
 	} catch (MelderError) {
-		Melder_throw (me, U" no Intensity created.");
+		Melder_throw (me, U": Intensity not created.");
 	}
 }
 
 autoTextGrid IntensityTier_to_TextGrid_detectSilences (IntensityTier me, double dt, double silenceThreshold_dB, double minSilenceDuration,
-	double minSoundingDuration, const char32 *silenceLabel, const char32 *soundingLabel) {
+	double minSoundingDuration, const char32 *silenceLabel, const char32 *soundingLabel)
+{
 	try {
 		autoIntensity intensity = IntensityTier_to_Intensity (me, dt);
 		autoTextGrid thee = Intensity_to_TextGrid_detectSilences (intensity.get(), silenceThreshold_dB, minSilenceDuration, minSoundingDuration, silenceLabel, soundingLabel);
 		return thee;
 	} catch (MelderError) {
-		Melder_throw (me, U" no TextGrid created.");
+		Melder_throw (me, U": TextGrid not created.");
 	}
 }
 
diff --git a/dwtools/KlattGrid.cpp b/dwtools/KlattGrid.cpp
index 61d564f..9ffa5a3 100644
--- a/dwtools/KlattGrid.cpp
+++ b/dwtools/KlattGrid.cpp
@@ -1,6 +1,6 @@
 /* KlattGrid.cpp
  *
- * Copyright (C) 2008-2014 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 2008-2014 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -96,7 +96,7 @@
 /*static double NUMinterpolateLinear (double x1, double y1, double x2, double y2, double x)
 {
 	if (y1 == y2) return y1;
-	if (x1 == x2) return NUMundefined;
+	if (x1 == x2) return undefined;
 	return (y2 - y1) * (x - x1) / (x2 - x1) + y1;
 }*/
 
@@ -119,10 +119,10 @@ static void rel_to_abs (double *w, double *ws, long n, double d) {
 static bool RealTier_valuesInRange (RealTier me, double min, double max) {
 	for (long i = 1; i <= my points.size; i ++) {
 		RealPoint p = my points.at [i];
-		if (NUMdefined (min) && p -> value < min) {
+		if (isdefined (min) && p -> value < min) {
 			return false;
 		}
-		if (NUMdefined (max) && p -> value < max) {
+		if (isdefined (max) && p -> value < max) {
 			return false;
 		}
 	}
@@ -130,22 +130,22 @@ static bool RealTier_valuesInRange (RealTier me, double min, double max) {
 }
 
 static double PointProcess_getPeriodAtIndex (PointProcess me, long it, double maximumPeriod) {
-	double period = NUMundefined;
+	double period = undefined;
 	if (it >= 2) {
 		period = my t [it] - my t [it - 1];
 		if (period > maximumPeriod) {
-			period = NUMundefined;
+			period = undefined;
 		}
 	}
-	if (period == NUMundefined) {
+	if (isundef (period)) {
 		if (it < my nt) {
 			period = my t [it + 1] - my t [it];
 			if (period > maximumPeriod) {
-				period = NUMundefined;
+				period = undefined;
 			}
 		}
 	}
-	// NUMundefined can only occur for a single isolated pulse.
+	// undefined can only occur for a single isolated pulse.
 	return period;
 }
 
@@ -198,7 +198,7 @@ static autoRealTier RealTier_updateWithDelta (RealTier me, RealTier delta, Phona
 				// Add my points between t1 and t2
 				while (mytime > lasttime && mytime < t2) {
 					double dvalue = RealTier_getValueAtTime (delta, mytime);
-					if (NUMdefined (dvalue)) {
+					if (isdefined (dvalue)) {
 						double fraction = (mytime - t1) / (openglottis_fadeFraction * openDuration);
 						myvalue += dvalue * fraction;
 					}
@@ -208,7 +208,7 @@ static autoRealTier RealTier_updateWithDelta (RealTier me, RealTier delta, Phona
 
 			double myvalue2 = RealTier_getValueAtTime (me, t2);
 			double dvalue = RealTier_getValueAtTime (delta, t2);
-			if (NUMdefined (dvalue)) {
+			if (isdefined (dvalue)) {
 				myvalue2 += dvalue;
 			}
 			RealTier_addPoint (thee.get(), t2, myvalue2);
@@ -217,7 +217,7 @@ static autoRealTier RealTier_updateWithDelta (RealTier me, RealTier delta, Phona
 
 			while (mytime > lasttime && mytime < t3) {
 				dvalue = RealTier_getValueAtTime (delta, mytime);
-				if (NUMdefined (dvalue)) {
+				if (isdefined (dvalue)) {
 					myvalue += dvalue;
 				}
 				UPDATE_TIER
@@ -227,7 +227,7 @@ static autoRealTier RealTier_updateWithDelta (RealTier me, RealTier delta, Phona
 
 			double myvalue3 = RealTier_getValueAtTime (me, t3);
 			dvalue = RealTier_getValueAtTime (delta, t3);
-			if (NUMdefined (dvalue)) {
+			if (isdefined (dvalue)) {
 				myvalue3 += dvalue;
 			}
 			RealTier_addPoint (thee.get(), t3, myvalue3);
@@ -236,7 +236,7 @@ static autoRealTier RealTier_updateWithDelta (RealTier me, RealTier delta, Phona
 				// Add my points between t3 and t4
 				while (mytime > lasttime && mytime < t4) {
 					dvalue = RealTier_getValueAtTime (delta, mytime);
-					if (NUMdefined (dvalue)) {
+					if (isdefined (dvalue)) {
 						double fraction = 1 - (mytime - t3) / (openglottis_fadeFraction * openDuration);
 						myvalue += dvalue * fraction;
 					}
@@ -386,7 +386,7 @@ static void NUMcircle_radial_intersection_sq (double x, double y, double r, doub
 		*xi = x + dx * r / d;
 		*yi = y + dy * r / d;
 	} else {
-		*xi = *yi = NUMundefined;
+		*xi = *yi = undefined;
 	}
 }
 
@@ -418,7 +418,7 @@ static void _summer_drawConnections (Graphics g, double x, double y, double r, c
 			}
 		}
 		NUMcircle_radial_intersection_sq (x, y, r, xp, yp, &xto, &yto);
-		if (xto == NUMundefined || yto == NUMundefined) {
+		if (isundef (xto) || isundef (yto)) {
 			continue;
 		}
 		if (arrow) {
@@ -505,7 +505,7 @@ static void _Sound_FormantGrid_filterWithOneFormant_inline (Sound me, FormantGri
 		double t = my x1 + (is - 1) * my dx;
 		double f = RealTier_getValueAtTime (ftier, t);
 		double b = RealTier_getValueAtTime (btier, t);
-		if (f <= nyquist && NUMdefined (b)) {
+		if (f <= nyquist && isdefined (b)) {
 			Filter_setFB (r.get(), f, b);
 		}
 		my z [1] [is] = Filter_getOutput (r.get(), my z[1][is]);
@@ -542,10 +542,10 @@ void Sound_FormantGrid_Intensities_filterWithOneFormant_inline (Sound me, Forman
 			double f = RealTier_getValueAtTime (ftier, t);
 			double b = RealTier_getValueAtTime (btier, t);
 			double a;
-			if (f <= nyquist && NUMdefined (b)) {
+			if (f <= nyquist && isdefined (b)) {
 				Filter_setFB (r.get(), f, b);
 				a = RealTier_getValueAtTime (atier, t);
-				if (NUMdefined (a)) {
+				if (isdefined (a)) {
 					r -> a *= DB_to_A (a);
 				}
 			}
@@ -728,20 +728,20 @@ static void PhonationGrid_checkFlowFunction (PhonationGrid me) {
 	do {
 		double time = ( hasPower1Points ? my power1 -> points.at [ipoint] -> number : 0.5 * (my xmin + my xmax) );
 		double power1 = RealTier_getValueAtIndex (my power1.get(), ipoint);
-		if (power1 == NUMundefined) {
+		if (isundef (power1)) {
 			power1 = KlattGrid_POWER1_DEFAULT;
 		}
-		if (power1 <= 0) {
+		if (power1 <= 0.0) {
 			Melder_throw (U"All power1 values must greater than zero.");
 		}
 		double power2 = RealTier_getValueAtTime (my power2.get(), time);
-		if (power2 == NUMundefined) {
+		if (isundef (power2)) {
 			power2 = KlattGrid_POWER2_DEFAULT;
 		}
 		if (power2 <= power1) {
 			Melder_throw (U"At all times a power1 value must be smaller than the corresponding power2 value.");
 		}
-	} while (++ipoint < my power1 -> points.size);
+	} while (++ ipoint < my power1 -> points.size);
 
 	// Now check power2 values. This is necessary to catch situations where power2 has a valley:
 	// power1(0) = 3; power2(1)= 4; power2(1)= 4; power2(0.5) = 3;
@@ -750,17 +750,17 @@ static void PhonationGrid_checkFlowFunction (PhonationGrid me) {
 	do {
 		double time = ( hasPower2Points ? my power2 -> points.at [ipoint] -> number : 0.5 * (my xmin + my xmax) );
 		double power2 = RealTier_getValueAtIndex (my power2.get(), ipoint);
-		if (power2 == NUMundefined) {
+		if (isundef (power2)) {
 			power2 = KlattGrid_POWER2_DEFAULT;
 		}
 		double power1 = RealTier_getValueAtTime (my power1.get(), time);
-		if (power1 == NUMundefined) {
+		if (isundef (power1)) {
 			power1 = KlattGrid_POWER1_DEFAULT;
 		}
 		if (power2 <= power1) {
 			Melder_throw (U"At all times the power2 value must be greater than the corresponding power1 value.");
 		}
-	} while (++ipoint < my power2 -> points.size);
+	} while (++ ipoint < my power2 -> points.size);
 }
 
 static void PhonationGrid_draw_inside (PhonationGrid me, Graphics g, double xmin, double xmax, double ymin, double ymax, double dy, double *yout) {
@@ -819,7 +819,7 @@ void PhonationGrid_draw (PhonationGrid me, Graphics g) {
 
 double PhonationGrid_getMaximumPeriod (PhonationGrid me) {
 	double minimumPitch = RealTier_getMinimumValue (my pitch.get());
-	return 2.0 / ( NUMdefined (minimumPitch) && minimumPitch != 0.0 ? minimumPitch : my xmax - my xmin );
+	return 2.0 / ( isdefined (minimumPitch) && minimumPitch != 0.0 ? minimumPitch : my xmax - my xmin );
 }
 
 static autoPointProcess PitchTier_to_PointProcess_flutter (PitchTier pitch, RealTier flutter, double maximumPeriod) {
@@ -834,7 +834,7 @@ static autoPointProcess PitchTier_to_PointProcess_flutter (PitchTier pitch, Real
 			double period = thy t [it] - thy t [it - 1];
 			if (period < maximumPeriod && flutter -> points.size > 0) {
 				double fltr = RealTier_getValueAtTime (flutter, t);
-				if (NUMdefined (fltr)) {
+				if (isdefined (fltr)) {
 					// newF0 = f0 * (1 + (val / 50) * (sin ... + ...));
 					double newPeriod = period / (1.0 + (fltr / 50.0) * (sin (2.0 * NUMpi * 12.7 * t) + sin (2.0 * NUMpi * 7.1 * t) + sin (2.0 * NUMpi * 4.7 * t)));
 					tsum += newPeriod - period;
@@ -860,7 +860,7 @@ autoSound PhonationGrid_to_Sound_aspiration (PhonationGrid me, double samplingFr
 				double t = thy x1 + (i - 1) * thy dx;
 				double val = NUMrandomUniform (-1.0, 1.0);
 				double a = DBSPL_to_A (RealTier_getValueAtTime (my aspirationAmplitude.get(), t));
-				if (NUMdefined (a)) {
+				if (isdefined (a)) {
 					thy z [1] [i] = lastval = val + 0.75 * lastval;
 					lastval = (val += 0.75 * lastval); // soft low-pass
 					thy z [1] [i] = val * a;
@@ -917,7 +917,7 @@ static void nrfunction (double x, double *fx, double *dfx, void *closure) {
 }
 
 static double get_collisionPoint_x (double n, double m, double collisionPhase) {
-	double y = NUMundefined;
+	double y = undefined;
 	/*
 	Domain [0,1]:
 	The glottal flow is given by:
@@ -986,7 +986,7 @@ autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
 			double pulseScale = 1.0;        // For alternate pulses in case of diplophonia
 
 			double period = PointProcess_getPeriodAtIndex (point.get(), it, pp -> maximumPeriod);
-			if (period == NUMundefined) {
+			if (isundef (period)) {
 				period = 0.5 * pp -> maximumPeriod; // Some default value
 			}
 
@@ -996,15 +996,15 @@ autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
 			double periodStart = t - period; // point where period starts:
 
 			double collisionPhase = pp -> collisionPhase ? RealTier_getValueAtTime (my collisionPhase.get(), periodStart) : 0.0;
-			if (collisionPhase == NUMundefined) {
+			if (isundef (collisionPhase)) {
 				collisionPhase = 0.0;
 			}
 			double power1 = pp -> flowFunction == 1 ? RealTier_getValueAtTime (my power1.get(), periodStart) : pp -> flowFunction;
-			if (power1 == NUMundefined) {
+			if (isundef (power1)) {
 				power1 = KlattGrid_POWER1_DEFAULT;
 			}
 			double power2 = pp -> flowFunction == 1 ? RealTier_getValueAtTime (my power2.get(), periodStart) : pp -> flowFunction + 1;
-			if (power2 == NUMundefined) {
+			if (isundef (power2)) {
 				power2 = KlattGrid_POWER2_DEFAULT;
 			}
 			try {
@@ -1014,7 +1014,7 @@ autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
 			}
 
 			double openPhase = RealTier_getValueAtTime (my openPhase.get(), periodStart);
-			if (openPhase == NUMundefined) {
+			if (isundef (openPhase)) {
 				openPhase = KlattGrid_OPENPHASE_DEFAULT;
 			}
 
@@ -1026,7 +1026,7 @@ autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
 			// The doublePulsing scales the amplitudes as well as the delay linearly.
 
 			double doublePulsing = pp -> doublePulsing ? RealTier_getValueAtTime (my doublePulsing.get(), periodStart) : 0.0;
-			if (doublePulsing == NUMundefined) {
+			if (isundef (doublePulsing)) {
 				doublePulsing = 0.0;
 			}
 
@@ -1034,7 +1034,7 @@ autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
 				diplophonicPulseIndex ++;
 				if (diplophonicPulseIndex % 2 == 1) {   // the odd-numbered one
 					double nextPeriod = PointProcess_getPeriodAtIndex (point.get(), it + 1, pp -> maximumPeriod);
-					if (nextPeriod == NUMundefined) {
+					if (isundef (nextPeriod)) {
 						nextPeriod = period;
 					}
 					double openPhase2 = KlattGrid_OPENPHASE_DEFAULT;
@@ -1062,7 +1062,7 @@ autoPhonationTier PhonationGrid_to_PhonationTier (PhonationGrid me) {
 static autoSound PhonationGrid_PhonationTier_to_Sound_voiced (PhonationGrid me, PhonationTier thee, double samplingFrequency) {
 	try {
 		PhonationGridPlayOptions p = my options.get();
-		double lastVal = NUMundefined;
+		double lastVal = undefined;
 
 		if (my voicingAmplitude -> points.size == 0) {
 			Melder_throw (U"Voicing amplitude tier is empty.");
@@ -1161,7 +1161,7 @@ static autoSound PhonationGrid_PhonationTier_to_Sound_voiced (PhonationGrid me,
 		// Scale voiced part and add breathiness during open phase
 		if (p -> flowDerivative) {
 			double extremum = Vector_getAbsoluteExtremum (him.get(), 0.0, 0.0, Vector_VALUE_INTERPOLATION_CUBIC);
-			if (! NUMdefined (lastVal)) {
+			if (isundef (lastVal)) {
 				lastVal = 0.0;
 			}
 			for (long i = 1; i <= his nx; i ++) {
@@ -1841,7 +1841,7 @@ void FormantGrid_CouplingGrid_updateOpenPhases (FormantGrid me, CouplingGrid the
 			if (itier <= my formants.size) {
 				if (delta -> points.size > 0) {
 					autoRealTier rt = RealTier_updateWithDelta (my formants.at [itier], delta, thy glottis.get(), pc -> fadeFraction);
-					if (! RealTier_valuesInRange (rt.get(), 0, NUMundefined)) {
+					if (! RealTier_valuesInRange (rt.get(), 0, undefined)) {
 						Melder_throw (U"Formant ", itier, U" coupling gives negative values.");
 					}
 					my formants. replaceItem_move (rt.move(), itier);
@@ -1851,7 +1851,7 @@ void FormantGrid_CouplingGrid_updateOpenPhases (FormantGrid me, CouplingGrid the
 			if (itier <= my bandwidths.size) {
 				if (delta -> points.size > 0) {
 					autoRealTier rt = RealTier_updateWithDelta (my bandwidths.at [itier], delta, thy glottis.get(), pc -> fadeFraction);
-					if (! RealTier_valuesInRange (rt.get(), 0, NUMundefined)) {
+					if (! RealTier_valuesInRange (rt.get(), 0, undefined)) {
 						Melder_throw (U"Bandwidth ", itier, U" coupling gives negative values.");
 					}
 					my bandwidths. replaceItem_move (rt.move(), itier);
@@ -2017,7 +2017,7 @@ autoSound FricationGrid_to_Sound (FricationGrid me, double samplingFrequency) {
 			double a = 0.0;
 			if (my fricationAmplitude -> points.size > 0) {
 				double dba = RealTier_getValueAtTime (my fricationAmplitude.get(), t);
-				a = ( NUMdefined (dba) ? DBSPL_to_A (dba) : 0.0 );
+				a = ( isdefined (dba) ? DBSPL_to_A (dba) : 0.0 );
 			}
 			lastval = (val += 0.75 * lastval); // TODO: soft low-pass coefficient must be Fs dependent!
 			thy z[1][i] = val * a;
@@ -2053,10 +2053,10 @@ autoSound Sound_FricationGrid_filter (Sound me, FricationGrid thee) {
 		if (pf -> bypass) {
 			for (long is = 1; is <= his nx; is ++) {	// Bypass
 				double t = his x1 + (is - 1) * his dx;
-				double ab = 0;
+				double ab = 0.0;
 				if (thy bypass -> points.size > 0) {
 					double val = RealTier_getValueAtTime (thy bypass.get(), t);
-					ab = val == NUMundefined ? 0 : DB_to_A (val);
+					ab = ( isundef (val) ? 0.0 : DB_to_A (val) );
 				}
 				his z [1] [is] += my z [1] [is] * ab;
 			}
@@ -2459,9 +2459,9 @@ void KlattGrid_formula_amplitudes (KlattGrid me, int formantType, const char32 *
 			IntensityTier amplitudes = ordered->at [irow];
 			Formula_compile (interpreter, amplitudes, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 			for (long icol = 1; icol <= amplitudes -> points.size; icol ++) {
-				struct Formula_Result result;
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
-				if (result. result.numericResult == NUMundefined) {
+				if (isundef (result. result.numericResult)) {
 					Melder_throw (U"Cannot put an undefined value into the tier.\nFormula not finished.");
 				}
 				amplitudes -> points.at [icol] -> value = result. result.numericResult;
@@ -2475,7 +2475,7 @@ void KlattGrid_formula_amplitudes (KlattGrid me, int formantType, const char32 *
 double KlattGrid_getAmplitudeAtTime (KlattGrid me, int formantType, long iformant, double t) {
 	OrderedOf<structIntensityTier>* ordered = KlattGrid_getAddressOfAmplitudes (me, formantType);
 	if (iformant < 0 || iformant > ordered->size) {
-		return NUMundefined;
+		return undefined;
 	}
 	return RealTier_getValueAtTime (ordered->at [iformant], t);
 }
diff --git a/dwtools/KlattTable.cpp b/dwtools/KlattTable.cpp
index 70492db..2bee17b 100644
--- a/dwtools/KlattTable.cpp
+++ b/dwtools/KlattTable.cpp
@@ -1141,7 +1141,7 @@ autoSound KlattTable_to_Sound (KlattTable me, double samplingFrequency, int synt
 		}
 		thee = KlattGlobal_create (samplingFrequency);
 		frame = KlattFrame_create ();
-		autoNUMvector<short> iwave (0L, MAX_SAM);
+		autoNUMvector <short> iwave ((integer) 0, MAX_SAM);
 		thy samrate = (long) floor (samplingFrequency);
 
 		KlattGlobal_init (thee, synthesisModel, numberOfFormants, glottalSource, frameDuration, (long) floor (flutter), outputType);
diff --git a/dwtools/Ltas_extensions.cpp b/dwtools/Ltas_extensions.cpp
index 1ceb77f..700b884 100644
--- a/dwtools/Ltas_extensions.cpp
+++ b/dwtools/Ltas_extensions.cpp
@@ -24,20 +24,20 @@ void Ltas_fitTiltLine (Ltas me, double fmin, double fmax, bool lnf, int method,
 		if (fmax <= fmin) {
 			fmin = my xmin; fmax = my xmax;
 		}
-		long ifmin, ifmax, numberOfSamples = Sampled_getWindowSamples (me, fmin, fmax, &ifmin, &ifmax);
+		integer ifmin, ifmax, numberOfSamples = Sampled_getWindowSamples (me, fmin, fmax, & ifmin, & ifmax);
 		if (numberOfSamples < 2) {
 			Melder_throw (U"There must be at least two data points to fit a line.");
 		}
 		autoNUMvector<double> x (1, numberOfSamples);
 		autoNUMvector<double> y (1, numberOfSamples);
-		for (long i = ifmin; i <= ifmax; i++) {
-			long ixy = i - ifmin + 1;
-			x[ixy] = my x1 + (i - 1) * my dx;
+		for (integer i = ifmin; i <= ifmax; i ++) {
+			integer ixy = i - ifmin + 1;
+			x [ixy] = my x1 + (i - 1) * my dx;
 			if (lnf) {
 				// For Ltas always x1 > 0
-				x[ixy] = log10 (x[ixy]);
+				x [ixy] = log10 (x [ixy]);
 			}
-			y[ixy] = my z[1][i];
+			y [ixy] = my z [1] [i];
 		}
 		NUMlineFit (x.peek(), y.peek(), numberOfSamples, a, b, method);
 	} catch (MelderError) {
diff --git a/dwtools/MDS.cpp b/dwtools/MDS.cpp
index b9894b8..1f0691e 100644
--- a/dwtools/MDS.cpp
+++ b/dwtools/MDS.cpp
@@ -1,6 +1,6 @@
 /* MDS.cpp
  *
- * Copyright (C) 1993-2016 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 1993-2016 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -201,7 +201,7 @@ autoSimilarity DistanceList_to_Similarity_cc (DistanceList me, Weight w) {
 
 		for (long i = 1; i <= my size; i ++) {
 			Distance di = my at [i];
-			char32 *name = Thing_getName (di);
+			const char32 *name = Thing_getName (di);
 			TableOfReal_setRowLabel (thee.get(), i, name);
 			TableOfReal_setColumnLabel (thee.get(), i, name);
 			thy data[i][i] = 1;
@@ -868,11 +868,11 @@ static double Dissimilarity_getAverage (Dissimilarity me) {
 			}
 		}
 	}
-	return numberOfPositives > 0 ? sum /= numberOfPositives : NUMundefined;
+	return ( numberOfPositives > 0 ? sum /= numberOfPositives : undefined );
 }
 
 double Dissimilarity_getAdditiveConstant (Dissimilarity me) {
-	double additiveConstant = NUMundefined;
+	double additiveConstant = undefined;
 	try {
 		long nPoints = my numberOfRows, nPoints2 = 2 * nPoints;
 
@@ -883,7 +883,7 @@ double Dissimilarity_getAdditiveConstant (Dissimilarity me) {
 		}
 
 		additiveConstant = Dissimilarity_getAverage (me);
-		if (additiveConstant == NUMundefined) {
+		if (isundef (additiveConstant)) {
 			Melder_throw (U"There are no positive dissimilarities.");
 		}
 
@@ -1024,12 +1024,12 @@ autoDissimilarity Similarity_to_Dissimilarity (Similarity me, double maximumDiss
 
 autoDistance Dissimilarity_to_Distance (Dissimilarity me, int scale) {
 	try {
-		double additiveConstant = 0;
+		double additiveConstant = 0.0;
 
 		autoDistance thee = Distance_create (my numberOfRows);
 		TableOfReal_copyLabels (me, thee.get(), 1, 1);
 		if (scale == MDS_ORDINAL) {
-			if ((additiveConstant = Dissimilarity_getAdditiveConstant (me)) == NUMundefined) {
+			if (isundef (additiveConstant = Dissimilarity_getAdditiveConstant (me))) {
 				Melder_warning (U"Dissimilarity_to_Distance: could not determine \"additive constant\", the average dissimilarity was used as its value.");
 			}
 		}
@@ -1558,7 +1558,7 @@ autoDissimilarityList DistanceList_to_DissimilarityList (DistanceList me) {
 	try {
 		autoDissimilarityList thee = DissimilarityList_create ();
 		for (long i = 1; i <= my size; i ++) {
-			char32 *name = Thing_getName (my at [i]);
+			const char32 *name = Thing_getName (my at [i]);
 			autoDissimilarity him = Distance_to_Dissimilarity (my at [i]);
 			Thing_setName (him.get(), name ? name : U"untitled");
 			thy addItem_move (him.move());
@@ -1575,7 +1575,7 @@ autoDistanceList DissimilarityList_to_DistanceList (DissimilarityList me, int me
 
 		for (long i = 1; i <= my size; i ++) {
 			autoDistance him = Dissimilarity_to_Distance (my at [i], measurementLevel == MDS_ORDINAL);
-			char32 *name = Thing_getName (my at [i]);
+			const char32 *name = Thing_getName (my at [i]);
 			Thing_setName (him.get(), name ? name : U"untitled");
 			thy addItem_move (him.move());
 		}
@@ -1625,7 +1625,7 @@ static void smacof_guttmanTransform (Configuration cx, Configuration cz, Distanc
 }
 
 double Distance_Weight_stress (Distance fit, Distance conf, Weight weight, int stressMeasure) {
-	double eta_fit, eta_conf, rho, stress = NUMundefined, denum, tmp;
+	double eta_fit, eta_conf, rho, stress = undefined, denum, tmp;
 
 	Distance_Weight_rawStressComponents (fit, conf, weight, &eta_fit, &eta_conf, &rho);
 
@@ -1709,7 +1709,7 @@ void Distance_Weight_rawStressComponents (Distance fit, Distance conf, Weight we
 
 double Dissimilarity_Configuration_Transformator_Weight_stress (Dissimilarity d, Configuration c, Transformator t, Weight w, int stressMeasure) {
 	long nPoints = d -> numberOfRows;
-	double stress = NUMundefined;
+	double stress = undefined;
 
 	if (nPoints < 1 || nPoints != c -> numberOfRows  || nPoints != t -> numberOfPoints || (w && nPoints != w -> numberOfRows)) {
 		Melder_throw (U"Incorrect number of points.");
@@ -2939,7 +2939,7 @@ void drawSplines (Graphics g, double low, double high, double ymin, double ymax,
 	}
 	Graphics_unsetInner (g);
 	if (garnish) {
-		static MelderString ts { 0 };
+		static MelderString ts { };
 		long lastKnot = splineType == MDS_ISPLINE ? numberOfKnots - 2 : numberOfKnots;
 		Graphics_drawInnerBox (g);
 		Graphics_textLeft (g, false, splineType == MDS_MSPLINE ? U"\\s{M}\\--spline" : U"\\s{I}\\--spline");
diff --git a/dwtools/Makefile b/dwtools/Makefile
index 0f52e3f..3513bd3 100644
--- a/dwtools/Makefile
+++ b/dwtools/Makefile
@@ -1,10 +1,10 @@
 # Makefile of the library "dwtools"
 # David Weenink and Paul Boersma
-# 8 June 2017
+# 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../LPC -I ../fon -I ../sys -I ../stat -I ../dwsys -I ../external/portaudio -I ../external/espeak -I ../EEG -I ../kar
+CPPFLAGS = -I ../kar -I ../LPC -I ../fon -I ../sys -I ../stat -I ../dwsys -I ../external/portaudio -I ../external/espeak -I ../EEG -I ../kar
 
 OBJECTS = ActivationList.o AffineTransform.o \
 	Categories.o CategoriesEditor.o \
@@ -48,7 +48,7 @@ OBJECTS = ActivationList.o AffineTransform.o \
 	Table_extensions.o TableOfReal_and_SVD.o\
 	TableOfReal_extensions.o \
 	TableOfReal_and_Permutation.o \
-	TextGrid_and_DurationTier.o TextGrid_extensions.o \
+	TextGrid_and_DurationTier.o TextGrid_and_PitchTier.o TextGrid_extensions.o \
 	VowelEditor.o \
 	praat_MDS_init.o praat_BSS_init.o praat_HMM_init.o \
 	praat_KlattGrid_init.o praat_DataModeler_init.o praat_David_init.o
@@ -67,5 +67,5 @@ libdwtools.a: $(OBJECTS)
 	$(AR) cq libdwtools.a $(OBJECTS)
 	$(RANLIB) libdwtools.a
 
-$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h ../LPC/*.h ../external/espeak/*.h
+$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h ../LPC/*.h ../external/espeak/*.h
 
diff --git a/dwtools/Matrix_extensions.cpp b/dwtools/Matrix_extensions.cpp
index 5f6c14d..c202a90 100644
--- a/dwtools/Matrix_extensions.cpp
+++ b/dwtools/Matrix_extensions.cpp
@@ -80,33 +80,33 @@ void Matrix_scatterPlot (Matrix me, Graphics g, long icx, long icy, double xmin,
 
 void Matrix_drawAsSquares (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax, int garnish) {
 	Graphics_Colour colour = Graphics_inqColour (g);
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 
 	if (xmax <= xmin) {
 		xmin = my xmin;
 		xmax = my xmax;
 	}
-	long nx = Matrix_getWindowSamplesX (me, xmin, xmax, &ixmin, &ixmax);
+	integer nx = Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 	if (ymax <= ymin) {
 		ymin = my ymin;
 		ymax = my ymax;
 	}
-	long ny = Matrix_getWindowSamplesY (me, ymin, ymax, &iymin, &iymax);
+	integer ny = Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	double min, max = nx > ny ? nx : ny;
 	double dx = (xmax - xmin) / max, dy = (ymax - ymin) / max;
 	Graphics_setInner (g);
 	Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 	Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & min, & max);
 	double wAbsMax = fabs (max) > fabs (min) ? fabs (max) : fabs (min);
-	for (long i = iymin; i <= iymax; i++) {
+	for (integer i = iymin; i <= iymax; i++) {
 		double y = Matrix_rowToY (me, i);
-		for (long j = ixmin; j <= ixmax; j++) {
+		for (integer j = ixmin; j <= ixmax; j++) {
 			double x = Matrix_columnToX (me, j);
 			double d = 0.95 * sqrt (fabs (my z[i][j]) / wAbsMax);
 			if (d > 0) {
-				double x1WC = x - d * dx / 2, x2WC = x + d * dx / 2;
-				double y1WC = y - d * dy / 2, y2WC = y + d * dy / 2;
-				if (my z[i][j] > 0) {
+				double x1WC = x - d * dx / 2.0, x2WC = x + d * dx / 2.0;
+				double y1WC = y - d * dy / 2.0, y2WC = y + d * dy / 2.0;
+				if (my z [i] [j] > 0.0) {
 					Graphics_setColour (g, Graphics_WHITE);
 				}
 				Graphics_fillRectangle (g, x1WC, x2WC, y1WC, y2WC);
@@ -132,37 +132,41 @@ void Matrix_drawAsSquares (Matrix me, Graphics g, double xmin, double xmax, doub
 
 void Matrix_scale (Matrix me, int choice) {
 	double min, max, extremum;
-	long nZero = 0;
+	integer nZero = 0;
 
 	if (choice == 2) { /* by row */
-		for (long i = 1; i <= my ny; i++) {
+		for (integer i = 1; i <= my ny; i++) {
 			Matrix_getWindowExtrema (me, 1, my nx, i, i, &min, &max);
 			extremum = fabs (max) > fabs (min) ? fabs (max) : fabs (min);
 			if (extremum == 0.0) {
-				nZero++;
-			} else for (long j = 1; j <= my nx; j++) {
-					my z[i][j] /= extremum;
+				nZero ++;
+			} else {
+				for (integer j = 1; j <= my nx; j ++) {
+					my z [i] [j] /= extremum;
 				}
+			}
 		}
 	} else if (choice == 3) { /* by col */
-		for (long j = 1; j <= my nx; j++) {
+		for (integer j = 1; j <= my nx; j++) {
 			Matrix_getWindowExtrema (me, j, j, 1, my ny, &min, &max);
-			extremum =  fabs (max) > fabs (min) ? fabs (max) : fabs (min);
+			extremum = fabs (max) > fabs (min) ? fabs (max) : fabs (min);
 			if (extremum == 0.0) {
-				nZero++;
-			} else for (long i = 1; i <= my ny; i++) {
-					my z[i][j] /= extremum;
+				nZero ++;
+			} else {
+				for (integer i = 1; i <= my ny; i ++) {
+					my z [i] [j] /= extremum;
 				}
+			}
 		}
 	} else if (choice == 1) { /* overall */
 		Matrix_getWindowExtrema (me, 1, my nx, 1, my ny, &min, &max);
 		extremum =  fabs (max) > fabs (min) ? fabs (max) : fabs (min);
 		if (extremum == 0.0) {
-			nZero++;
+			nZero ++;
 		} else {
-			for (long i = 1; i <= my ny; i++) {
-				for (long j = 1; j <= my nx; j++) {
-					my z[i][j] /= extremum;
+			for (integer i = 1; i <= my ny; i ++) {
+				for (integer j = 1; j <= my nx; j ++) {
+					my z [i] [j] /= extremum;
 				}
 			}
 		}
@@ -178,9 +182,9 @@ void Matrix_scale (Matrix me, int choice) {
 autoMatrix Matrix_transpose (Matrix me) {
 	try {
 		autoMatrix thee = Matrix_create (my ymin, my ymax, my ny, my dy, my y1, my xmin, my xmax, my nx, my dx, my x1);
-		for (long i = 1; i <= my ny; i++) {
-			for (long j = 1; j <= my nx; j++) {
-				thy z[j][i] = my z[i][j];
+		for (integer i = 1; i <= my ny; i ++) {
+			for (integer j = 1; j <= my nx; j ++) {
+				thy z [j ][i] = my z [i] [j];
 			}
 		}
 		return thee;
@@ -201,7 +205,7 @@ void Matrix_drawDistribution (Matrix me, Graphics g, double xmin, double xmax, d
 	if (ymax <= ymin) {
 		ymin = my ymin; ymax = my ymax;
 	}
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	if ((Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax) == 0) || 
 		(Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax) == 0)) {
 		return;
@@ -272,21 +276,21 @@ void Matrix_drawSliceY (Matrix me, Graphics g, double x, double ymin, double yma
 	if (x < my xmin || x > my xmax) {
 		return;
 	}
-	long ix = Matrix_xToNearestColumn (me, x);
+	integer ix = Matrix_xToNearestColumn (me, x);
 
 	if (ymax <= ymin) {
 		ymin = my ymin;
 		ymax = my ymax;
 	}
 
-	long iymin, iymax;
-	long ny = Matrix_getWindowSamplesY (me, ymin, ymax, &iymin, &iymax);
+	integer iymin, iymax;
+	integer ny = Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	if (ny < 1) {
 		return;
 	}
 
 	if (max <= min) {
-		Matrix_getWindowExtrema (me, ix, ix, iymin, iymax, &min, &max);
+		Matrix_getWindowExtrema (me, ix, ix, iymin, iymax, & min, & max);
 	}
 	if (max <= min) {
 		min -= 0.5; max += 0.5;
@@ -296,8 +300,8 @@ void Matrix_drawSliceY (Matrix me, Graphics g, double x, double ymin, double yma
 	Graphics_setWindow (g, ymin, ymax, min, max);
 	Graphics_setInner (g);
 
-	for (long i = iymin; i <= iymax; i++) {
-		y[i] = my z[i][ix];
+	for (integer i = iymin; i <= iymax; i ++) {
+		y [i] = my z [i] [ix];
 	}
 	Graphics_function (g, y.peek(), iymin, iymax, Matrix_rowToY (me, iymin), Matrix_rowToY (me, iymax));
 	Graphics_unsetInner (g);
@@ -343,10 +347,10 @@ double Matrix_getMean (Matrix me, double xmin, double xmax, double ymin, double
 	if (ymax <= ymin) {
 		ymin = my ymin; ymax = my ymax;
 	}
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	if ((Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax) == 0) ||
 		(Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax) == 0)) {
-		return NUMundefined;
+		return undefined;
 	}
 	double sum = 0.0;
 	for (long row = iymin; row <= iymax; row++) {
@@ -364,14 +368,14 @@ double Matrix_getStandardDeviation (Matrix me, double xmin, double xmax, double
 	if (ymax <= ymin) {
 		ymin = my ymin; ymax = my ymax;
 	}
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	if ((Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax) == 0) ||
 		(Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax) == 0)) {
-		return NUMundefined;
+		return undefined;
 	}
 	long nx = ixmax - ixmin + 1, ny = iymax - iymin + 1;
 	if (nx == 1 && ny == 1) {
-		return NUMundefined;
+		return undefined;
 	}
 	double mean = Matrix_getMean (me, xmin, xmax, ymin, ymax), sum = 0;
 	for (long row = iymin; row <= iymax; row++) {
@@ -429,7 +433,7 @@ autoMatrix Matrix_readFromIDXFormatFile (MelderFile file) {
 	/*
 		From: http://yann.lecun.com/exdb/mnist/
 		
-		The IDX file format is a simple format for vectors and multidimensional matrices of various numerical types.
+		The IDX file format is a simple format for multidimensional arrays of various numerical types.
 
 		The basic format is
 
@@ -441,9 +445,9 @@ autoMatrix Matrix_readFromIDXFormatFile (MelderFile file) {
 			size in dimension N
 		data
 
-		The magic number is an integer (MSB first). The first 2 bytes are always 0.
+		The magic number is a four-byte integer (most significant byte first). The first 2 bytes are always 0.
 
-		The third byte codes the type of the data:
+		The third byte encodes the type of the data:
 		0x08: unsigned byte
 		0x09: signed byte
 		0x0B: short (2 bytes)
@@ -451,67 +455,68 @@ autoMatrix Matrix_readFromIDXFormatFile (MelderFile file) {
 		0x0D: float (4 bytes)
 		0x0E: double (8 bytes)
 
-		The 4-th byte codes the number of dimensions of the vector/matrix: 1 for vectors, 2 for matrices....
+		The 4-th byte encodes the number of dimensions (indices) of the array: 1 for vectors, 2 for matrices....
 
-		The sizes in each dimension are 4-byte integers (MSB first, big endian, like in most non-Intel processors).
+		The numbers of elements in each dimension (for a matrix: number of rows and number of columns)
+		are 4-byte integers (MSB first, big endian, as in most non-Intel processors).
 
-		The data is stored like in a C array, i.e. the index in the last dimension changes the fastest. 
+		The data is stored like in a C array, i.e. the index in the last dimension changes the fastest.
 
 	*/
 	try {
 		autofile f = Melder_fopen (file, "r");
-		unsigned int b1 = bingetu1 (f); // 0
-		unsigned int b2 = bingetu1 (f); // 0
+		unsigned int b1 = bingetu8 (f);   // 0
+		unsigned int b2 = bingetu8 (f);   // 0
 		if (b1 != 0 || b2 != 0) {
 			Melder_throw (U"Starting two bytes should be zero.");
 		}
-		unsigned int b3 = bingetu1 (f); // data type
-		unsigned int b4 = bingetu1 (f); // number of dimensions
-		long ncols = bingeti32 (f), nrows = 1; // ok if vector 
+		unsigned int b3 = bingetu8 (f);   // data type
+		unsigned int b4 = bingetu8 (f);   // number of dimensions
+		long ncols = bingeti32 (f), nrows = 1;   // ok if vector
 		if (b4 > 1) {
 			nrows = ncols;
 			ncols = bingeti32 (f);
 		}
-		while (b4 > 2) { // accumulate all other dimensions in the columns
+		while (b4 > 2) {   // accumulate all other dimensions in the columns
 			long n2 = bingeti32 (f);
-			ncols *= n2; // put the matrix in one row
+			ncols *= n2;   // put the matrix in one row
 			-- b4;
 		}
 		autoMatrix me = Matrix_create (0.0, ncols, ncols, 1, 0.5, 0, nrows, nrows, 1.0, 0.5);
-		if (b3 == 0x08) { // unsigned byte
+		if (b3 == 0x08) {   // 8 bits unsigned
 			for (long irow = 1; irow <= nrows; irow ++) {
 				for (long icol = 1; icol <= ncols; icol ++) {
-					my z [irow] [icol] = bingetu1 (f);
+					my z [irow] [icol] = bingetu8 (f);
 				}
 			}
-		} else if (b3 == 0x09) { // signed byte
+		} else if (b3 == 0x09) {   // 8 bits signed
 			for (long irow = 1; irow <= nrows; irow ++) {
 				for (long icol = 1; icol <= ncols; icol ++) {
-					my z [irow] [icol] = bingeti1 (f);
+					my z [irow] [icol] = bingeti8 (f);
 				}
 			}
-		} else if (b3 == 0x0B) { // short (2 bytes)
+		} else if (b3 == 0x0B) {   // 16 bits signed
 			for (long irow = 1; irow <= nrows; irow ++) {
 				for (long icol = 1; icol <= ncols; icol ++) {
-					my z [irow] [icol] = bingeti2 (f);
+					my z [irow] [icol] = bingeti16 (f);
 				}
 			}
-		} else if (b3 == 0x0C) { // int (4 bytes)
+		} else if (b3 == 0x0C) {   // 32 bits signed
 			for (long irow = 1; irow <= nrows; irow ++) {
 				for (long icol = 1; icol <= ncols; icol ++) {
 					my z [irow] [icol] = bingeti32 (f);
 				}
 			}
-		} else if (b3 == 0x0D) { // float (4 bytes)
+		} else if (b3 == 0x0D) {   // 32-bits IEEE floating point
 			for (long irow = 1; irow <= nrows; irow ++) {
 				for (long icol = 1; icol <= ncols; icol ++) {
-					my z [irow] [icol] = bingetr4 (f);
+					my z [irow] [icol] = bingetr32 (f);
 				}
 			}
-		} else if (b3 == 0x0E) { // double (8 bytes)
+		} else if (b3 == 0x0E) {   // 64-bits IEEE floating point
 			for (long irow = 1; irow <= nrows; irow ++) {
 				for (long icol = 1; icol <= ncols; icol ++) {
-					my z [irow] [icol] = bingetr8 (f);
+					my z [irow] [icol] = bingetr64 (f);
 				}
 			}
 		} else {
diff --git a/dwtools/Minimizers.cpp b/dwtools/Minimizers.cpp
index 96c519d..8e02e3b 100644
--- a/dwtools/Minimizers.cpp
+++ b/dwtools/Minimizers.cpp
@@ -77,13 +77,13 @@ void Minimizer_init (Minimizer me, long nParameters, Daata object) {
 	my object = object;
 	my minimum = 1.0e30;
 	my afterHook = classMinimizer_afterHook;
-	Minimizer_reset (me, nullptr); /* added 27/11/97 */
+	Minimizer_reset (me, nullptr);   // added 27/11/97
 }
 
 static void monitor_off (Minimizer me) {
 	Melder_monitor (1.1);
 	if (my gmonitor) {
-		Graphics_clearWs (my gmonitor); // DON'T forget (my gmonitor)
+		Graphics_clearWs (my gmonitor);   // DON'T forget (my gmonitor)
 		my gmonitor = nullptr;
 	}
 }
@@ -98,8 +98,8 @@ void Minimizer_minimize (Minimizer me, long maxNumOfIterations, double tolerance
 
 		if (my iteration + maxNumOfIterations > my maxNumOfIterations) {
 			my maxNumOfIterations += maxNumOfIterations;
-			if (my history) { // clumsy because vector must have been allocated  before one can append
-				NUMvector_append<double> (& my history, 1, & my maxNumOfIterations);
+			if (my history) {   // clumsy because vector must have been allocated  before one can append
+				NUMvector_append <double> (& my history, 1, & my maxNumOfIterations);
 			} else {
 				my history = NUMvector<double> (1, my maxNumOfIterations);
 			}
@@ -107,7 +107,7 @@ void Minimizer_minimize (Minimizer me, long maxNumOfIterations, double tolerance
 		if (monitor) {
 			my gmonitor = (Graphics) Melder_monitor (0.0, U"Starting...");
 		}
-		my start = 1; /* for my after() */
+		my start = 1;   // for my after()
 		my v_minimize ();
 		if (monitor) {
 			monitor_off (me);
@@ -116,9 +116,9 @@ void Minimizer_minimize (Minimizer me, long maxNumOfIterations, double tolerance
 			U" iterations and ", my funcCalls, U" function calls.");
 	} catch (MelderError) {
 		if (monitor) {
-			monitor_off (me);    // temporarily until better monitor facilities
+			monitor_off (me);   // temporarily until better monitor facilities
 		}
-		Melder_clearError(); // memory error in history mechanism is not fatal
+		Melder_clearError();   // memory error in history mechanism is not fatal
 	}
 }
 
diff --git a/dwtools/Minimizers.h b/dwtools/Minimizers.h
index f3e7558..0c8e9be 100644
--- a/dwtools/Minimizers.h
+++ b/dwtools/Minimizers.h
@@ -2,7 +2,7 @@
 #define _Minimizers_h_
 /* Minimizers.h
  *
- * Copyright (C) 1993-2011,2015-2016 David Weenink, 2015 Paul Boersma
+ * Copyright (C) 1993-2011,2015-2016 David Weenink, 2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ Thing_define (Minimizer, Thing) {
 	long funcCalls;		/* the number of times 'func' has been called */
 	long success;		/* indicates whether I'm done */
 	long start;			/* start iteration series */
-	long maxNumOfIterations; /* the current maximum number of iterations */
+	integer maxNumOfIterations; /* the current maximum number of iterations */
 	long iteration;     /* the total number of iterations */
 	void (*afterHook) (Minimizer me, Thing boss); /* to be called after each iteration */
 	Thing afterBoss;
diff --git a/dwtools/PCA.cpp b/dwtools/PCA.cpp
index 0a40d26..3b31e4b 100644
--- a/dwtools/PCA.cpp
+++ b/dwtools/PCA.cpp
@@ -90,23 +90,24 @@ long PCA_getNumberOfObservations (PCA me) {
 }
 
 void PCA_getEqualityOfEigenvalues (PCA me, long from, long to, int conservative, double *p_prob, double *p_chisq, double *p_df) {
-	double sum = 0, sumln = 0;
+	double sum = 0.0, sumln = 0.0;
 
-	double prob = NUMundefined, df = NUMundefined, chisq = NUMundefined;
+	double prob = undefined, df = undefined, chisq = undefined;
 	
 	if (from == 0 && to == 0) {
-		to = 1; from = my numberOfEigenvalues;
+		to = 1;
+		from = my numberOfEigenvalues;
 	}
 	if (from < to && from > 0 && to <= my numberOfEigenvalues) {
 		long i;
-		for (i = from; i <= to; i++) {
-			if (my eigenvalues[i] <= 0) {
+		for (i = from; i <= to; i ++) {
+			if (my eigenvalues [i] <= 0) {
 				break;
 			}
-			sum += my eigenvalues[i];
-			sumln += log (my eigenvalues[i]);
+			sum += my eigenvalues [i];
+			sumln += log (my eigenvalues [i]);
 		}
-		if (sum == 0) {
+		if (sum == 0.0) {
 			return;
 		}
 		long r = i - from;
@@ -317,10 +318,10 @@ autoTableOfReal PCA_and_Configuration_to_TableOfReal_reconstruct (PCA me, Config
 
 double PCA_and_TableOfReal_getFractionVariance (PCA me, TableOfReal thee, long from, long to) {
 	try {
-		double fraction = NUMundefined;
+		double fraction = undefined;
 
 		if (from < 1 || from > to || to > thy numberOfColumns) {
-			return NUMundefined;
+			return undefined;
 		}
 
 		autoSSCP s = TableOfReal_to_SSCP (thee, 0, 0, 0, 0);
@@ -328,18 +329,18 @@ double PCA_and_TableOfReal_getFractionVariance (PCA me, TableOfReal thee, long f
 		fraction = SSCP_getFractionVariation (sp.get(), from, to);
 		return fraction;
 	} catch (MelderError) {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
 autoTableOfReal PCA_to_TableOfReal_reconstruct1 (PCA me, char32 *numstring) {
 	try {
-		long npc;
+		integer npc;
 		autoNUMvector<double> pc (NUMstring_to_numbers (numstring, & npc), 1);
 
 		autoConfiguration c = Configuration_create (1, npc);
-		for (long j = 1; j <= npc; j++) {
-			c -> data [1][j] = pc[j];
+		for (integer j = 1; j <= npc; j ++) {
+			c -> data [1] [j] = pc [j];
 		}
 		autoTableOfReal him = PCA_and_Configuration_to_TableOfReal_reconstruct (me, c.get());
 		return him;
diff --git a/dwtools/Pitch_extensions.cpp b/dwtools/Pitch_extensions.cpp
index d803a45..037dd9b 100644
--- a/dwtools/Pitch_extensions.cpp
+++ b/dwtools/Pitch_extensions.cpp
@@ -1,6 +1,6 @@
 /* Pitch_extensions.cpp
  *
- * Copyright (C) 1993-2011, 2015-2016 David Weenink
+ * Copyright (C) 1993-2011, 2015-2016 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -122,14 +122,14 @@ autoPitch Pitch_scaleTime (Pitch me, double scaleFactor) {
 
 static double HertzToSpecial (double value, int pitchUnit) {
 	return	pitchUnit == kPitch_unit_HERTZ ? value :
-		pitchUnit == kPitch_unit_HERTZ_LOGARITHMIC ? value <= 0.0 ? NUMundefined : log10 (value) :
+		pitchUnit == kPitch_unit_HERTZ_LOGARITHMIC ? value <= 0.0 ? undefined : log10 (value) :
 		pitchUnit == kPitch_unit_MEL ? NUMhertzToMel (value) :
-		pitchUnit == kPitch_unit_LOG_HERTZ ? value <= 0.0 ? NUMundefined : log10 (value) :
-		pitchUnit == kPitch_unit_SEMITONES_1 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 1.0) / NUMln2 :
-		pitchUnit == kPitch_unit_SEMITONES_100 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 100.0) / NUMln2 :
-		pitchUnit == kPitch_unit_SEMITONES_200 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 200.0) / NUMln2 :
-		pitchUnit == kPitch_unit_SEMITONES_440 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 440.0) / NUMln2 :
-		pitchUnit == kPitch_unit_ERB ? NUMhertzToErb (value) : NUMundefined;
+		pitchUnit == kPitch_unit_LOG_HERTZ ? value <= 0.0 ? undefined : log10 (value) :
+		pitchUnit == kPitch_unit_SEMITONES_1 ? value <= 0.0 ? undefined : 12.0 * log (value / 1.0) / NUMln2 :
+		pitchUnit == kPitch_unit_SEMITONES_100 ? value <= 0.0 ? undefined : 12.0 * log (value / 100.0) / NUMln2 :
+		pitchUnit == kPitch_unit_SEMITONES_200 ? value <= 0.0 ? undefined : 12.0 * log (value / 200.0) / NUMln2 :
+		pitchUnit == kPitch_unit_SEMITONES_440 ? value <= 0.0 ? undefined : 12.0 * log (value / 440.0) / NUMln2 :
+		pitchUnit == kPitch_unit_ERB ? NUMhertzToErb (value) : undefined;
 }
 
 static double SpecialToHertz (double value, int pitchUnit) {
@@ -141,7 +141,7 @@ static double SpecialToHertz (double value, int pitchUnit) {
 		pitchUnit == kPitch_unit_SEMITONES_100 ? 100.0 * exp (value * (NUMln2 / 12.0)) :
 		pitchUnit == kPitch_unit_SEMITONES_200 ? 200.0 * exp (value * (NUMln2 / 12.0)) :
 		pitchUnit == kPitch_unit_SEMITONES_440 ? 440.0 * exp (value * (NUMln2 / 12.0)) :
-		pitchUnit == kPitch_unit_ERB ? NUMerbToHertz (value) : NUMundefined;
+		pitchUnit == kPitch_unit_ERB ? NUMerbToHertz (value) : undefined;
 }
 
 autoPitchTier PitchTier_normalizePitchRange (PitchTier me, double pitchMin_ref_Hz, double pitchMax_ref_Hz, double pitchMin_Hz, double pitchMax_Hz, int pitchUnit);
@@ -152,14 +152,14 @@ autoPitchTier PitchTier_normalizePitchRange (PitchTier me, double pitchMin_ref_H
 		double fmin = HertzToSpecial (pitchMin_Hz, pitchUnit);
 		double fmax = HertzToSpecial (pitchMax_Hz, pitchUnit);
 
-		if (fminr == NUMundefined || fmaxr == NUMundefined || fmin == NUMundefined || fmax == NUMundefined) {
+		if (isundef (fminr) || isundef (fmaxr) || isundef (fmin) || isundef (fmax)) {
 			Melder_throw (U"The conversion of a pitch value is not defined. ");
 		}
 		double ranger = fmaxr - fminr, range = fmax - fmin;
 		if (ranger < 0.01 || range < 0.01) {
 			Melder_throw (U"Pitch range too small.");
 		}
-		double fmidr = fminr + ranger / 2;
+		double fmidr = fminr + ranger / 2.0;
 		double factor = ranger / range;
 		autoPitchTier thee = Data_copy (me);
 		for (long i = 1; i <= my points.size; i ++) {
@@ -186,16 +186,16 @@ autoPitch PitchTier_to_Pitch (PitchTier me, double dt, double pitchFloor, double
 		if (pitchFloor >= pitchCeiling) {
 			Melder_throw (U"The pitch ceiling must be larger than the pitch floor.");
 		}
-		double tmin = my xmin, tmax = my xmax, t1 = my xmin + dt / 2;
+		double tmin = my xmin, tmax = my xmax, t1 = my xmin + dt / 2.0;
 		long nt = (long) floor ((tmax - tmin - t1) / dt);
 		if (t1 + nt * dt < tmax) {
-			nt++;
+			nt ++;
 		}
 		if (nt < 1) {
 			Melder_throw (U"Duration is too short.");
 		}
 		autoPitch thee = Pitch_create (tmin, tmax, nt, dt, t1, pitchCeiling, 1);
-		for (long i = 1; i <= nt; i++) {
+		for (long i = 1; i <= nt; i ++) {
 			Pitch_Frame frame = (Pitch_Frame) & thy frame [i];
 			Pitch_Candidate candidate = (Pitch_Candidate) & frame -> candidate [1];
 			double t = t1 + (i - 1) * dt;
diff --git a/dwtools/Polygon_extensions.cpp b/dwtools/Polygon_extensions.cpp
index 51158ed..c7a3fcc 100644
--- a/dwtools/Polygon_extensions.cpp
+++ b/dwtools/Polygon_extensions.cpp
@@ -72,8 +72,8 @@ void Polygon_getExtrema (Polygon me, double *p_xmin, double *p_xmax, double *p_y
 
 autoPolygon Polygon_createSimple (char32 *xystring) {
 	try {
-		long numberOfPoints;
-		autoNUMvector<double> xys (NUMstring_to_numbers (xystring, &numberOfPoints), 1);
+		integer numberOfPoints;
+		autoNUMvector <double> xys (NUMstring_to_numbers (xystring, & numberOfPoints), 1);
 		if (numberOfPoints < 6) {
 			Melder_throw (U"There must be at least 3 points (= x,y pairs) in the Polygon");
 		}
@@ -1256,7 +1256,7 @@ double Polygon_getAreaOfConvexHull (Polygon me) {
 		return Polygon_area (thee.get());
 	} catch (MelderError) {
 		Melder_clearError ();
-		return NUMundefined;
+		return undefined;
 	}
 }
 
diff --git a/dwtools/Polynomial.cpp b/dwtools/Polynomial.cpp
index 703ae5c..38cdfee 100644
--- a/dwtools/Polynomial.cpp
+++ b/dwtools/Polynomial.cpp
@@ -62,19 +62,20 @@
 void Polynomial_evaluateWithDerivative (Polynomial me, double x, double *f, double *df) {
 	long double p = my coefficients [my numberOfCoefficients], dp = 0.0, xc = x;
 
-	for (long i = my numberOfCoefficients - 1; i > 0; i--) {
+	for (long i = my numberOfCoefficients - 1; i > 0; i --) {
 		dp = dp * xc + p;
 		p =  p * xc + my coefficients [i];
 	}
-	*f = (double) p; *df = (double) dp;
+	*f = (double) p;
+	*df = (double) dp;
 }
 
 /* Get value and derivative */
 static void Polynomial_evaluateWithDerivative_z (Polynomial me, dcomplex *z, dcomplex *p, dcomplex *dp) {
-	long double pr = my coefficients[my numberOfCoefficients], pi = 0;
-	long double dpr = 0, dpi = 0, x = z -> re, y = z -> im;
+	long double pr = my coefficients[my numberOfCoefficients], pi = 0.0;
+	long double dpr = 0.0, dpi = 0.0, x = z -> re, y = z -> im;
 
-	for (long i = my numberOfCoefficients - 1; i > 0; i--) {
+	for (long i = my numberOfCoefficients - 1; i > 0; i --) {
 		long double tr   = dpr;
 		dpr  =  dpr * x -  dpi * y + pr;
 		dpi  =   tr * y +  dpi * x + pi;
@@ -82,8 +83,8 @@ static void Polynomial_evaluateWithDerivative_z (Polynomial me, dcomplex *z, dco
 		pr   =   pr * x -   pi * y + my coefficients[i];
 		pi   =   tr * y +   pi * x;
 	}
-	p -> re =   (double) pr;  p -> im =  (double) pi;
-	dp -> re =  (double) dpr; dp -> im = (double) dpi;
+	*p = { (double) pr, (double) pi };
+	*dp = { (double) dpr, (double) dpi };
 }
 
 
@@ -97,11 +98,12 @@ void Polynomial_evaluateDerivatives (Polynomial me, double x, double *derivative
 		derivatives [j] = 0.0;
 	}
 	for (long i = degree - 1; i >= 0; i--) {
-		long n = (numberOfDerivatives < (degree - i) ? numberOfDerivatives : degree - i);
-		for (long j = n; j >= 1; j--) {
-			derivatives [j] = derivatives [j] * x +  derivatives [j - 1];
+		long n =
+			numberOfDerivatives < degree - i ? numberOfDerivatives : degree - i;
+		for (long j = n; j >= 1; j --) {
+			derivatives [j] = derivatives [j] * x + derivatives [j - 1];
 		}
-		derivatives [0] = derivatives [0] * x + my coefficients [i + 1];  // Evaluate polynomial (Horner)
+		derivatives [0] = derivatives [0] * x + my coefficients [i + 1];   // evaluate polynomial (Horner)
 	}
 	double fact = 1.0;
 	for (long j = 2; j <= numberOfDerivatives; j ++) {
@@ -131,14 +133,14 @@ static void polynomial_divide (double *u, long m, double *v, long n, double *q,
 	// Copy u[1..m] into r[1..n] to prevent overwriting of u.
 	// Put the q coefficients to zero for cases n > m.
 
-	for (long k = 1; k <= m; k++) {
+	for (long k = 1; k <= m; k ++) {
 		r[k] = u[k];
-		q[k] = 0;
+		q[k] = 0.0;
 	}
 
-	for (long k = m - n + 1; k > 0; k--) { /* D1 */
+	for (long k = m - n + 1; k > 0; k --) { /* D1 */
 		q[k] = r[n + k - 1] / v[n]; /* D2 with u -> r*/
-		for (long j = n + k - 1; j >= k; j--) {
+		for (long j = n + k - 1; j >= k; j --) {
 			r[j] -= q[k] * v[j - k + 1];
 		}
 	}
@@ -156,16 +158,19 @@ static void Polynomial_polish_realroot (Polynomial me, double *x, long maxit) {
 		Polynomial_evaluateWithDerivative (me, *x, &p, &dp);
 		double fabsp = fabs (p);
 		if (fabsp > pmin || fabs (fabsp - pmin) < NUMfpp -> eps) {
-			// We stop because the approximation gets worse or we cannot get closer anymore
-			// Return previous (best) value for x.
-
-			*x = xbest; return;
+			/*
+				We stop, because the approximation is getting worse or we cannot get any closer.
+				Return the previous (hitherto best) value for x.
+			*/
+			*x = xbest;
+			return;
 		}
-		pmin = fabsp; xbest = *x;
-		if (fabs (dp) == 0) {
+		pmin = fabsp;
+		xbest = *x;
+		if (fabs (dp) == 0.0) {
 			return;
 		}
-		double dx = p / dp; /* Newton -Raphson */
+		double dx = p / dp;   // Newton-Raphson
 		*x -= dx;
 	}
 	// Melder_throw (U"Maximum number of iterations exceeded.");
@@ -183,16 +188,19 @@ static void Polynomial_polish_complexroot_nr (Polynomial me, dcomplex *z, long m
 		Polynomial_evaluateWithDerivative_z (me, z, &p, &dp);
 		double fabsp = dcomplex_abs (p);
 		if (fabsp > pmin || fabs (fabsp - pmin) < NUMfpp -> eps) {
-			// We stop because the approximation gets worse.
-			// Return previous (best) value for z.
-
-			*z = zbest; return;
+			/*
+				We stop, because the approximation is getting worse.
+				Return the previous (hitherto best) value for z.
+			*/
+			*z = zbest;
+			return;
 		}
-		pmin = fabsp; zbest = *z;
-		if (dcomplex_abs (dp) == 0) {
+		pmin = fabsp;
+		zbest = *z;
+		if (dcomplex_abs (dp) == 0.0) {
 			return;
 		}
-		dcomplex dz = dcomplex_div (p , dp); /* Newton -Raphson */
+		dcomplex dz = dcomplex_div (p, dp);   // Newton-Raphson
 		*z = dcomplex_sub (*z, dz);
 	}
 	// Melder_throw (U"Maximum number of iterations exceeded.");
@@ -224,36 +232,42 @@ static void NUMpolynomial_recurrence (double *pn, long degree, double a, double
 static void svdcvm (double **v, long mfit, long ma, int *frozen, double *w, double **cvm) {
 	autoNUMvector<double> wti (1, mfit);
 
-	for (long i = 1; i <= mfit; i++) {
+	for (long i = 1; i <= mfit; i ++) {
 		if (w[i] != 0.0) {
 			wti[i] = 1.0 / (w[i] * w[i]);
+		} else {
+			;   // TODO: write up an explanation for why it is not necessary to do anything if w[i] is zero
 		}
 	}
-	for (long i = 1; i <= mfit; i++) {
-		for (long j = 1; j <= i; j++) {
-			double sum = 0;
-			for (long k = 1; k <= mfit; k++) {
+	for (long i = 1; i <= mfit; i ++) {
+		for (long j = 1; j <= i; j ++) {
+			long double sum = 0.0;
+			for (long k = 1; k <= mfit; k ++) {
 				sum += v[i][k] * v[j][k] * wti[k];
 			}
-			cvm[j][i] = cvm[i][j] = sum;
+			cvm[j][i] = cvm[i][j] = (double) sum;
 		}
 	}
 
-	for (long i = mfit + 1; i <= ma; i++) {
-		for (long j = 1; j <= i; j++) {
-			cvm[j][i] = cvm[i][j] = 0;
+	for (long i = mfit + 1; i <= ma; i ++) {
+		for (long j = 1; j <= i; j ++) {
+			cvm[j][i] = cvm[i][j] = 0.0;
 		}
 	}
 
 	long k = mfit;
-	for (long j = ma; j > 0; j--) {
+	for (long j = ma; j > 0; j --) {
 		//			if (! frozen || ! frozen[i]) why i?? TODO
 		if (! frozen || ! frozen[j]) {
-			for (long i = 1; i <= ma; i++) {
-				double t = cvm[i][k]; cvm[i][k] = cvm[i][j]; cvm[i][j] = t;
+			for (long i = 1; i <= ma; i ++) {
+				double t = cvm[i][k];
+				cvm[i][k] = cvm[i][j];
+				cvm[i][j] = t;
 			}
-			for (long i = 1; i <= ma; i++) {
-				double t = cvm[k][i]; cvm[k][i] = cvm[j][i]; cvm[j][i] = t;
+			for (long i = 1; i <= ma; i ++) {
+				double t = cvm[k][i];
+				cvm[k][i] = cvm[j][i];
+				cvm[j][i] = t;
 			}
 			k--;
 		}
@@ -266,18 +280,18 @@ Thing_implement (FunctionTerms, Function, 0);
 
 double structFunctionTerms :: v_evaluate (double x) {
 	(void) x;
-	return NUMundefined;
+	return undefined;
 }
 
 void structFunctionTerms :: v_evaluate_z (dcomplex *z, dcomplex *p) {
 	(void) z;
-	p -> re = p -> im = NUMundefined;
+	p -> re = p -> im = undefined;
 }
 
 void structFunctionTerms :: v_evaluateTerms (double x, double terms[]) {
 	(void) x;
 	for (long i = 1; i <= numberOfCoefficients; i++) {
-		terms[i] = NUMundefined;
+		terms [i] = undefined;
 	}
 }
 
@@ -315,9 +329,9 @@ void structFunctionTerms :: v_getExtrema (double x1, double x2, double *p_xmin,
 	}
 }
 
-static inline void FunctionTerms_extendCapacityIf (FunctionTerms me, long minimum) {
+static inline void FunctionTerms_extendCapacityIf (FunctionTerms me, integer minimum) {
 	if (my _capacity < minimum) {
-		NUMvector_append<double> (& my coefficients, 1, & minimum);
+		NUMvector_append <double> (& my coefficients, 1, & minimum);
 		my _capacity = minimum;
 	}
 }
@@ -340,12 +354,12 @@ autoFunctionTerms FunctionTerms_create (double xmin, double xmax, long numberOfC
 	}
 }
 
-void FunctionTerms_initFromString (FunctionTerms me, double xmin, double xmax, const char32 *s, int allowTrailingZeros) {
-	long numberOfCoefficients;
-	autoNUMvector<double> numbers (NUMstring_to_numbers (s, &numberOfCoefficients), 1);
+void FunctionTerms_initFromString (FunctionTerms me, double xmin, double xmax, const char32 *s, bool allowTrailingZeros) {
+	integer numberOfCoefficients;
+	autoNUMvector <real> numbers (NUMstring_to_numbers (s, & numberOfCoefficients), 1);
 	if (! allowTrailingZeros) {
-		while (numbers[numberOfCoefficients] == 0 && numberOfCoefficients > 1) {
-			numberOfCoefficients--;
+		while (numbers [numberOfCoefficients] == 0 && numberOfCoefficients > 1) {
+			numberOfCoefficients --;
 		}
 	}
 
@@ -785,7 +799,7 @@ void Polynomial_initFromRealRoots (Polynomial me, double *roots, long numberOfRo
 autoPolynomial Polynomial_createFromRealRootsString (double xmin, double xmax, const char32 *s) {
 	try {
 		autoPolynomial me = Thing_new (Polynomial);
-		long numberOfRoots;
+		integer numberOfRoots;
 		autoNUMvector<double> roots (NUMstring_to_numbers (s, & numberOfRoots), 1);
 		FunctionTerms_init (me.get(), xmin, xmax, numberOfRoots + 1);
 		Polynomial_initFromRealRoots (me.get(), roots.peek(), numberOfRoots);
@@ -822,8 +836,8 @@ void Polynomial_initFromProductOfSecondOrderTerms (Polynomial me, double *a, lon
 autoPolynomial Polynomial_createFromProductOfSecondOrderTermsString (double xmin, double xmax, const char32 *s) {
 	try {
 		autoPolynomial me = Thing_new (Polynomial);
-		long numberOfTerms;
-		autoNUMvector<double> a (NUMstring_to_numbers (s, & numberOfTerms), 1);
+		integer numberOfTerms;
+		autoNUMvector <real> a (NUMstring_to_numbers (s, & numberOfTerms), 1);
 		FunctionTerms_init (me.get(), xmin, xmax, 2 * numberOfTerms + 1);
 		Polynomial_initFromProductOfSecondOrderTerms (me.get(), a.peek(), numberOfTerms);
 		return me;
@@ -940,7 +954,7 @@ double structLegendreSeries :: v_evaluate (double x) {
 	// Transform x from domain [xmin, xmax] to domain [-1, 1]
 
 	if (x < xmin || x > xmax) {
-		return NUMundefined;
+		return undefined;
 	}
 
 	double pim1 = x = (2 * x - xmin - xmax) / (xmax - xmin);
@@ -962,7 +976,7 @@ double structLegendreSeries :: v_evaluate (double x) {
 void structLegendreSeries :: v_evaluateTerms (double x, double terms[]) {
 	if (x < xmin || x > xmax) {
 		for (long i = 1; i <= numberOfCoefficients; i++) {
-			terms[i] = NUMundefined;
+			terms[i] = undefined;
 		}
 		return;
 	}
@@ -1293,7 +1307,7 @@ double Polynomial_findOneSimpleRealRoot_ridders (Polynomial me, double xmin, dou
 }
 
 void Polynomial_divide_firstOrderFactor (Polynomial me, double factor, double *p_remainder) { // P(x)/(x-a)
-	double remainder = NUMundefined;
+	double remainder = undefined;
 	if (my numberOfCoefficients > 1) {
 		remainder = my coefficients [my numberOfCoefficients];
 		for (long j = my numberOfCoefficients - 1; j > 0; j --) {
@@ -1414,7 +1428,7 @@ Thing_implement (ChebyshevSeries, FunctionTerms, 0);
 */
 double structChebyshevSeries :: v_evaluate (double x) {
 	if (x < xmin || x > xmax) {
-		return NUMundefined;
+		return undefined;
 	}
 
 	double d1 = 0, d2 = 0;
@@ -1438,7 +1452,7 @@ double structChebyshevSeries :: v_evaluate (double x) {
 void structChebyshevSeries :: v_evaluateTerms (double x, double *terms) {
 	if (x < xmin || x > xmax) {
 		for (long i = 1; i <= numberOfCoefficients; i++) {
-			terms[i] = NUMundefined;
+			terms[i] = undefined;
 		}
 		return;
 	}
@@ -1565,7 +1579,7 @@ void FunctionTerms_and_RealTier_fit (FunctionTerms me, RealTier thee, int freeze
 		autoSVD svd = SVD_create (numberOfData, numberOfFreeParameters);
 
 		double sigma = RealTier_getStandardDeviation_points (thee, my xmin, my xmax);
-		if (sigma == NUMundefined) {
+		if (isundef (sigma)) {
 			Melder_throw (U"Not enough data points in fit interval.");
 		}
 
@@ -1670,7 +1684,7 @@ static double NUMmspline2 (double points[], long numberOfPoints, long order, lon
 	Melder_assert (numberOfPoints > 2 && order > 0 && index > 0);
 
 	if (index > numberOfSplines) {
-		return NUMundefined;
+		return undefined;
 	}
 
 	/*
@@ -1782,8 +1796,8 @@ static void Spline_initKnotsFromString (Spline me, long degree, const char32 *in
 	if (degree > Spline_MAXIMUM_DEGREE) {
 		Melder_throw (U"Degree must be <= 20.");
 	}
-	long numberOfInteriorKnots;
-	autoNUMvector<double> numbers (NUMstring_to_numbers (interiorKnots, &numberOfInteriorKnots), 1);
+	integer numberOfInteriorKnots;
+	autoNUMvector <real> numbers (NUMstring_to_numbers (interiorKnots, & numberOfInteriorKnots), 1);
 	if (numberOfInteriorKnots > 0) {
 		NUMsort_d (numberOfInteriorKnots, numbers.peek());
 		if (numbers[1] <= my xmin || numbers[numberOfInteriorKnots] > my xmax) {
diff --git a/dwtools/Polynomial.h b/dwtools/Polynomial.h
index 908b621..22d879d 100644
--- a/dwtools/Polynomial.h
+++ b/dwtools/Polynomial.h
@@ -41,7 +41,7 @@
 
 void FunctionTerms_init (FunctionTerms me, double xmin, double xmax, long numberOfCoefficients);
 
-void FunctionTerms_initFromString (FunctionTerms me, double xmin, double xmax, const char32 *s, int allowTrailingZeros);
+void FunctionTerms_initFromString (FunctionTerms me, double xmin, double xmax, const char32 *s, bool allowTrailingZeros);
 
 autoFunctionTerms FunctionTerms_create (double xmin, double xmax, long numberOfCoefficients);
 
@@ -152,7 +152,7 @@ void Polynomial_divide_firstOrderFactor (Polynomial me, double factor, double *p
 /* Functions: calculate coefficients of new polynomial P(x)/(x-a)
  * if p_remainder != nullptr it will contain 
  *		remainder after dividing by monomial factor x-a.
- * 		NUMundefined if my numberOfCoefficients == 1 (error condition)
+ * 		`undefined` if my numberOfCoefficients == 1 (error condition)
  * Postcondition: my numberOfCoefficients reduced by 1 
 */
 
diff --git a/dwtools/SPINET.cpp b/dwtools/SPINET.cpp
index 9a938b2..481a4dc 100644
--- a/dwtools/SPINET.cpp
+++ b/dwtools/SPINET.cpp
@@ -141,7 +141,7 @@ void SPINET_spectralRepresentation (SPINET me, Graphics g, double fromTime, doub
 }
 
 void SPINET_drawSpectrum (SPINET me, Graphics g, double time, double fromErb, double toErb, double minimum, double maximum, int enhanced, int garnish) {
-	long ifmin, ifmax, icol = Sampled_xToLowIndex (me, time);   // ppgb: don't use Sampled2_xToColumn for integer rounding
+	integer ifmin, ifmax, icol = Sampled_xToLowIndex (me, time);   // ppgb: don't use Sampled2_xToColumn for integer rounding
 	double **z = enhanced ? my s : my y;
 	if (icol < 1 || icol > my nx) {
 		return;
diff --git a/dwtools/SSCP.cpp b/dwtools/SSCP.cpp
index 493a3ef..7e6385b 100644
--- a/dwtools/SSCP.cpp
+++ b/dwtools/SSCP.cpp
@@ -209,11 +209,11 @@ autoSSCPList SSCPList_extractTwoDimensions (SSCPList me, long d1, long d2) {
 	}
 }
 
-void SSCP_drawTwoDimensionalEllipse_inside (SSCP me, Graphics g, double scale, char32 * label, int fontSize) {
+void SSCP_drawTwoDimensionalEllipse_inside (SSCP me, Graphics g, double scale, const char32 *label, int fontSize) {
 	try {
-		long nsteps = 100;
-		autoNUMvector<double> x (0L, nsteps);
-		autoNUMvector<double> y (0L, nsteps);
+		integer nsteps = 100;
+		autoNUMvector <double> x ((integer) 0, nsteps);
+		autoNUMvector <double> y ((integer) 0, nsteps);
 		// Get principal axes and orientation for the ellipse by performing the
 		// eigen decomposition of a symmetric 2-by-2 matrix.
 		// Principal axes are a and b with eigenvector/orientation (cs, sn).
@@ -250,10 +250,10 @@ void SSCP_drawTwoDimensionalEllipse_inside (SSCP me, Graphics g, double scale, c
 
 static void _SSCP_drawTwoDimensionalEllipse (SSCP me, Graphics g, double scale, int fontSize) {
 	long nsteps = 100;
-	char32 *name;
+	const char32 *name;
 
-	autoNUMvector<double> x (0L, nsteps);
-	autoNUMvector<double> y (0L, nsteps);
+	autoNUMvector <double> x ((integer) 0, nsteps);
+	autoNUMvector <double> y ((integer) 0, nsteps);
 
 	// Get principal axes and orientation for the ellipse by performing the
 	// eigen decomposition of a symmetric 2-by-2 matrix.
@@ -381,7 +381,7 @@ double SSCP_getFractionVariation (SSCP me, long from, long to) {
 	long n = my numberOfRows;
 
 	if (from < 1 || from > to || to > n) {
-		return NUMundefined;
+		return undefined;
 	}
 
 	double sum = 0.0, trace = 0.0;
@@ -391,7 +391,7 @@ double SSCP_getFractionVariation (SSCP me, long from, long to) {
 			sum += my numberOfRows == 1 ? my data[1][i] : my data[i][i];
 		}
 	}
-	return trace > 0.0 ? sum / trace : NUMundefined;
+	return trace > 0.0 ? sum / trace : undefined;
 }
 
 void SSCP_drawConcentrationEllipse (SSCP me, Graphics g, double scale, int confidence, long d1, long d2, double xmin, double xmax, double ymin, double ymax, int garnish) {
@@ -452,7 +452,7 @@ double SSCP_getTotalVariance (SSCP me) {
 }
 
 double SSCP_getCumulativeContributionOfComponents (SSCP me, long from, long to) {
-	double sum = NUMundefined;
+	double sum = undefined;
 	if (to == 0) {
 		to = my numberOfRows;
 	}
@@ -1048,7 +1048,7 @@ autoCovariance CovarianceList_to_Covariance_pool (CovarianceList me) { // Morris
 }
 
 void SSCPList_getHomegeneityOfCovariances_box (SSCPList me, double *p_prob, double *p_chisq, double *p_df) {
-	double chisq = 0.0, df = NUMundefined;
+	double chisq = 0.0, df = undefined;
 
 	autoSSCP pooled = SSCPList_to_SSCP_pool (me);
 	long p = pooled -> numberOfColumns;
@@ -1202,9 +1202,9 @@ autoCovariance Covariance_create_reduceStorage (long dimension, long storage) {
 
 autoCovariance Covariance_createSimple (char32 *s_covariances, char32 *s_centroid, long numberOfObservations) {
 	try {
-		long dimension, numberOfCovariances;
-		autoNUMvector<double> centroid (NUMstring_to_numbers (s_centroid, & dimension), 1);
-		autoNUMvector<double> covariances (NUMstring_to_numbers (s_covariances, & numberOfCovariances), 1);
+		integer dimension, numberOfCovariances;
+		autoNUMvector <real> centroid (NUMstring_to_numbers (s_centroid, & dimension), 1);
+		autoNUMvector <real> covariances (NUMstring_to_numbers (s_covariances, & numberOfCovariances), 1);
 		long numberOfCovariances_wanted = dimension * (dimension + 1) / 2;
 		if (numberOfCovariances != numberOfCovariances_wanted) {
 			Melder_throw (U"The number of covariance matrix elements and the number of centroid elements are not in "
@@ -1255,7 +1255,7 @@ autoCovariance Covariance_createSimple (char32 *s_covariances, char32 *s_centroi
 
 autoCorrelation Correlation_createSimple (char32 *s_correlations, char32 *s_centroid, long numberOfObservations) {
 	try {
-		long dimension, numberOfCorrelations;
+		integer dimension, numberOfCorrelations;
 		autoNUMvector<double> centroids (NUMstring_to_numbers (s_centroid, & dimension), 1);
 		autoNUMvector<double> correlations (NUMstring_to_numbers (s_correlations, & numberOfCorrelations), 1);
 		long numberOfCorrelations_wanted = dimension * (dimension + 1) / 2;
@@ -1368,7 +1368,7 @@ double SSCP_getLnDeterminant (SSCP me) {
 		NUMdeterminant_cholesky (my data, my numberOfRows, & ln_d);
 		return ln_d;
 	} catch (MelderError) {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
@@ -1473,7 +1473,7 @@ double Covariances_getMultivariateCentroidDifference (Covariance me, Covariance
 	long N1 = (long) floor (my numberOfObservations), n1 = N1 - 1;
 	long N2 = (long) floor (thy numberOfObservations), n2 = N2 - 1;
 
-	double dif = NUMundefined, fisher = NUMundefined;
+	double dif = undefined, fisher = undefined;
 	double df1 = p, df2 = N - p - 1;
 	
 	if (df2 < 1) {
@@ -1557,7 +1557,7 @@ void Covariances_equality (CovarianceList me, int method, double *p_prob, double
 	try {
 
 		long numberOfMatrices = my size;
-		double chisq = NUMundefined, df = NUMundefined;
+		double chisq = undefined, df = undefined;
 
 		if (numberOfMatrices < 2) {
 			Melder_throw (U"We need at least two matrices");
@@ -1654,7 +1654,7 @@ void Covariance_difference (Covariance me, Covariance thee, double *p_prob, doub
 	long p = my numberOfRows;
 	long numberOfObservations = (long) floor (my numberOfObservations);
 	double  ln_me, ln_thee;
-	double chisq = NUMundefined, df = NUMundefined;
+	double chisq = undefined, df = undefined;
 	
 	if (my numberOfRows != thy numberOfRows) {
 		Melder_throw (U"Matrices must have equal dimensions.");
@@ -1723,7 +1723,7 @@ static void checkTwoIndices (TableOfReal me, long index1, long index2) {
 
 void Covariance_getSignificanceOfOneMean (Covariance me, long index, double mu, double *p_prob, double *p_t, double *p_df) {
 	double var = my data[index][index];
-	double prob = NUMundefined, t = NUMundefined, df = my numberOfObservations - 1.0;
+	double prob = undefined, t = undefined, df = my numberOfObservations - 1.0;
 
 	checkOneIndex (me, index);
 
@@ -1747,7 +1747,7 @@ void Covariance_getSignificanceOfOneMean (Covariance me, long index, double mu,
 void Covariance_getSignificanceOfMeansDifference (Covariance me, long index1, long index2, double mu, int paired, int equalVariances, double *p_prob, double *p_t, double *p_df) {
 	long n = (long) floor (my numberOfObservations);
 
-	double prob = NUMundefined, t = NUMundefined;
+	double prob = undefined, t = undefined;
 	double df = 2.0 * (n - 1);
 
 	checkTwoIndices (me, index1, index2);
@@ -1797,7 +1797,7 @@ end:
 
 void Covariance_getSignificanceOfOneVariance (Covariance me, long index, double sigmasq, double *p_prob, double *p_chisq, long *p_df) {
 	double var = my data [index] [index];
-	double prob = NUMundefined, chisq = NUMundefined;
+	double prob = undefined, chisq = undefined;
 	double df = my numberOfObservations - 1.0;
 
 	checkOneIndex (me, index);
@@ -1824,7 +1824,7 @@ void Covariance_getSignificanceOfOneVariance (Covariance me, long index, double
 }
 
 void Covariance_getSignificanceOfVariancesRatio (Covariance me, long index1, long index2, double ratio, double *p_prob, double *p_f, double *p_df) {
-	double df = my numberOfObservations - 1.0, prob = NUMundefined, f = NUMundefined;
+	double df = my numberOfObservations - 1.0, prob = undefined, f = undefined;
 	checkTwoIndices (me, index1, index2);
 
 	double var1 = my data [index1] [index1];
@@ -1945,7 +1945,7 @@ void SSCP_testDiagonality_bartlett (SSCP me, long numberOfContraints, double *ch
 /* Morrison, page 118 */
 void Correlation_testDiagonality_bartlett (Correlation me, long numberOfContraints, double *p_chisq, double *p_prob, double *p_df) {
 	long p = my numberOfRows;
-	double chisq = NUMundefined, prob = NUMundefined, df = p * (p -1) / 2.0;
+	double chisq = undefined, prob = undefined, df = p * (p -1) / 2.0;
 
 	if (numberOfContraints <= 0) {
 		numberOfContraints = 1;
diff --git a/dwtools/SSCP.h b/dwtools/SSCP.h
index 70a9562..f48d23d 100644
--- a/dwtools/SSCP.h
+++ b/dwtools/SSCP.h
@@ -47,7 +47,7 @@ void SSCP_init (SSCP me, long dimension, long storage);
 
 autoSSCP SSCP_create (long dimension);
 
-void SSCP_drawTwoDimensionalEllipse_inside  (SSCP me, Graphics g, double scale, char32 * label, int fontSize);
+void SSCP_drawTwoDimensionalEllipse_inside (SSCP me, Graphics g, double scale, const char32 *label, int fontSize);
 
 double SSCP_getEllipseScalefactor (SSCP me, double scale, bool confidence);
 
diff --git a/dwtools/Sound_and_Spectrogram_extensions.cpp b/dwtools/Sound_and_Spectrogram_extensions.cpp
index 93213be..2aa23a2 100644
--- a/dwtools/Sound_and_Spectrogram_extensions.cpp
+++ b/dwtools/Sound_and_Spectrogram_extensions.cpp
@@ -170,22 +170,22 @@ autoBarkSpectrogram Sound_to_BarkSpectrogram (Sound me, double analysisWidth, do
 static void Sound_into_MelSpectrogram_frame (Sound me, MelSpectrogram thee, long frame) {
 	autoSpectrum him = Sound_to_Spectrum_power (me);
 
-	for (long ifilter = 1; ifilter <= thy ny; ifilter ++) {
+	for (integer ifilter = 1; ifilter <= thy ny; ifilter ++) {
 		double power = 0;
 		double fc_mel = thy y1 + (ifilter - 1) * thy dy;
 		double fc_hz = thy v_frequencyToHertz (fc_mel);
 		double fl_hz = thy v_frequencyToHertz (fc_mel - thy dy);
 		double fh_hz =  thy v_frequencyToHertz (fc_mel + thy dy);
-		long ifrom, ito;
-		Sampled_getWindowSamples (him.get(), fl_hz, fh_hz, &ifrom, &ito);
-		for (long i = ifrom; i <= ito; i++) {
+		integer ifrom, ito;
+		Sampled_getWindowSamples (him.get(), fl_hz, fh_hz, & ifrom, & ito);
+		for (integer i = ifrom; i <= ito; i ++) {
 			// Bin with a triangular filter the power (= amplitude-squared)
 
 			double f = his x1 + (i - 1) * his dx;
 			double a = NUMtriangularfilter_amplitude (fl_hz, fc_hz, fh_hz, f);
-			power += a * his z[1][i];
+			power += a * his z [1] [i];
 		}
-		thy z[ifilter][frame] = power;
+		thy z [ifilter] [frame] = power;
 	}
 }
 
@@ -303,7 +303,7 @@ autoSpectrogram Sound_and_Pitch_to_Spectrogram (Sound me, Pitch thee, double ana
 
 		double f0_median = Pitch_getQuantile (thee, thy xmin, thy xmax, 0.5, kPitch_unit_HERTZ);
 
-		if (f0_median == NUMundefined || f0_median == 0.0) {
+		if (isundef (f0_median) || f0_median == 0.0) {
 			f0_median = 100.0;
 			Melder_warning (U"Pitch values undefined. Bandwith fixed to 100 Hz. ");
 		}
@@ -336,7 +336,7 @@ autoSpectrogram Sound_and_Pitch_to_Spectrogram (Sound me, Pitch thee, double ana
 			double t = Sampled_indexToX (him.get(), iframe);
 			double b, f0 = Pitch_getValueAtTime (thee, t, kPitch_unit_HERTZ, 0);
 
-			if (f0 == NUMundefined || f0 == 0.0) {
+			if (isundef (f0) || f0 == 0.0) {
 				f0_undefined ++;
 				f0 = f0_median;
 			}
@@ -347,7 +347,7 @@ autoSpectrogram Sound_and_Pitch_to_Spectrogram (Sound me, Pitch thee, double ana
 			Sound_into_Spectrogram_frame (sframe.get(), him.get(), iframe, b);
 
 			if (iframe % 10 == 1) {
-				Melder_progress ( (double) iframe / numberOfFrames, U"Frame ", iframe, U" out of ",
+				Melder_progress ((double) iframe / numberOfFrames, U"Frame ", iframe, U" out of ",
 					numberOfFrames, U".");
 			}
 		}
diff --git a/dwtools/Sound_extensions.cpp b/dwtools/Sound_extensions.cpp
index 6eeea6d..7d9ca20 100644
--- a/dwtools/Sound_extensions.cpp
+++ b/dwtools/Sound_extensions.cpp
@@ -1,6 +1,6 @@
 /* Sound_extensions.cpp
  *
- * Copyright (C) 1993-2011, 2015-2017 David Weenink
+ * Copyright (C) 1993-2011, 2015-2017 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -122,14 +122,14 @@ static void i1write (Sound me, FILE *f, long *nClip) {
 			sample = min;
 			(*nClip) ++;
 		}
-		binputi1 ((int) sample, f);
+		binputi8 ((int) sample, f);
 	}
 }
 
 static void i1read (Sound me, FILE *f) {
 	double *s = my z[1];
 	for (long i = 1; i <= my nx; i++) {
-		s[i] = bingeti1 (f) / 128.0;
+		s[i] = bingeti8 (f) / 128.0;
 	}
 }
 
@@ -145,20 +145,20 @@ static void u1write (Sound me, FILE *f, long *nClip) {
 			sample = min;
 			(*nClip) ++;
 		}
-		binputu1 ((unsigned int) sample, f);
+		binputu8 ((unsigned int) sample, f);
 	}
 }
 
 static void u1read (Sound me, FILE *f) {
 	double *s = my z[1];
 	for (long i = 1; i <= my nx; i++) {
-		s[i] = bingetu1 (f) / 128.0 - 1.0;
+		s[i] = bingetu8 (f) / 128.0 - 1.0;
 	}
 }
 
 static void i2write (Sound me, FILE *f, int littleEndian, long *nClip) {
 	double *s = my z[1], min = -32768, max = 32767;
-	void (*put) (int16_t, FILE *) = littleEndian ? binputi2LE : binputi2;
+	void (*put) (int16_t, FILE *) = littleEndian ? binputi16LE : binputi16;
 	*nClip = 0;
 	for (long i = 1; i <= my nx; i++) {
 		double sample = round (s[i] * 32768);
@@ -175,7 +175,7 @@ static void i2write (Sound me, FILE *f, int littleEndian, long *nClip) {
 
 static void i2read (Sound me, FILE *f, int littleEndian) {
 	double *s = my z[1];
-	int16_t (*get) (FILE *) = littleEndian ? bingeti2LE : bingeti2;
+	int16_t (*get) (FILE *) = littleEndian ? bingeti16LE : bingeti16;
 	for (long i = 1; i <= my nx; i++) {
 		s[i] = get (f) / 32768.;
 	}
@@ -183,7 +183,7 @@ static void i2read (Sound me, FILE *f, int littleEndian) {
 
 static void u2write (Sound me, FILE *f, int littleEndian, long *nClip) {
 	double *s = my z[1], min = 0, max = 65535;
-	void (*put) (uint16_t, FILE *) = littleEndian ? binputu2LE : binputu2;
+	void (*put) (uint16_t, FILE *) = littleEndian ? binputu16LE : binputu16;
 	*nClip = 0;
 	for (long i = 1; i <= my nx; i++) {
 		double sample = round ( (s[i] + 1) * 65535 / 2);
@@ -200,7 +200,7 @@ static void u2write (Sound me, FILE *f, int littleEndian, long *nClip) {
 
 static void u2read (Sound me, FILE *f, int littleEndian) {
 	double *s = my z[1];
-	uint16_t (*get) (FILE *) = littleEndian ? bingetu2LE : bingetu2;
+	uint16_t (*get) (FILE *) = littleEndian ? bingetu16LE : bingetu16;
 	for (long i = 1; i <= my nx; i++) {
 		s[i] = get (f) / 32768.0 - 1.0;
 	}
@@ -208,7 +208,7 @@ static void u2read (Sound me, FILE *f, int littleEndian) {
 
 static void i4write (Sound me, FILE *f, int littleEndian, long *nClip) {
 	double *s = my z[1]; double min = -2147483648.0, max = 2147483647.0;
-	void (*put) (int32_t, FILE *) = littleEndian ? binputi4LE : binputi4;
+	void (*put) (int32_t, FILE *) = littleEndian ? binputi32LE : binputi32;
 	*nClip = 0;
 	for (long i = 1; i <= my nx; i++) {
 		double sample = round (s[i] * 2147483648.0);
@@ -225,7 +225,7 @@ static void i4write (Sound me, FILE *f, int littleEndian, long *nClip) {
 
 static void i4read (Sound me, FILE *f, int littleEndian) {
 	double *s = my z[1];
-	int32_t (*get) (FILE *) = littleEndian ? bingeti4LE : bingeti4;
+	int32_t (*get) (FILE *) = littleEndian ? bingeti32LE : bingeti32;
 	for (long i = 1; i <= my nx; i++) {
 		s[i] = get (f) / 2147483648.;
 	}
@@ -234,7 +234,7 @@ static void i4read (Sound me, FILE *f, int littleEndian) {
 
 static void u4write (Sound me, FILE *f, int littleEndian, long *nClip) {
 	double *s = my z[1]; double min = 0.0, max = 4294967295.0;
-	void (*put) (uint32_t, FILE *) = littleEndian ? binputu4LE : binputu4;
+	void (*put) (uint32_t, FILE *) = littleEndian ? binputu32LE : binputu32;
 	*nClip = 0;
 	for (long i = 1; i <= my nx; i++) {
 		double sample = floor (s[i] * 4294967295.0 + 0.5);
@@ -251,7 +251,7 @@ static void u4write (Sound me, FILE *f, int littleEndian, long *nClip) {
 
 static void u4read (Sound me, FILE *f, int littleEndian) {
 	double *s = my z[1];
-	int32_t (*get) (FILE *) = littleEndian ? bingeti4LE : bingeti4;
+	int32_t (*get) (FILE *) = littleEndian ? bingeti32LE : bingeti32;
 	for (long i = 1; i <= my nx; i++) {
 		s[i] = get (f) / 2147483648.0 - 1.0;
 	}
@@ -261,14 +261,14 @@ static void u4read (Sound me, FILE *f, int littleEndian) {
 static void r4write (Sound me, FILE *f) {
 	double *s = my z[1];
 	for (long i = 1; i <= my nx; i++) {
-		binputr4 (s[i], f);
+		binputr32 (s[i], f);
 	}
 }
 
 static void r4read (Sound me, FILE *f) {
 	double *s = my z[1];
 	for (long i = 1; i <= my nx; i++) {
-		s[i] = bingetr4 (f);
+		s[i] = bingetr32 (f);
 	}
 }
 
@@ -277,21 +277,21 @@ autoSound Sound_readFromCmuAudioFile (MelderFile file) {
 	try {
 		int littleEndian = 1;
 		autofile f = Melder_fopen (file, "rb");
-		if (bingeti2LE (f) != 6) {
+		if (bingeti16LE (f) != 6) {
 			Melder_throw (U"Incorrect header size.");
 		}
-		bingeti2LE (f);
-		short nChannels = bingeti2LE (f);
+		bingeti16LE (f);
+		short nChannels = bingeti16LE (f);
 		if (nChannels < 1) {
 			Melder_throw (U"Incorrect number of channels.");
 		}
 		if (nChannels > 1) {
 			Melder_throw (U"File has multiple channels: cannot read.");
 		}
-		if (bingeti2LE (f) < 1) {
+		if (bingeti16LE (f) < 1) {
 			Melder_throw (U"Incorrect sampling frequency.");
 		}
-		long nSamples = bingeti4LE (f);
+		long nSamples = bingeti32LE (f);
 		if (nSamples < 1) {
 			Melder_throw (U"Incorrect number of samples.");
 		}
@@ -1274,7 +1274,7 @@ autoPointProcess Sound_to_PointProcess_getJumps (Sound me, double minimumJump, d
 /* Internal pitch representation in semitones */
 autoSound Sound_and_Pitch_changeSpeaker (Sound me, Pitch him, double formantMultiplier, double pitchMultiplier, double pitchRangeMultiplier, double durationMultiplier) {
 	try {
-		double samplingFrequency_old = 1 / my dx;
+		double samplingFrequency_old = 1.0 / my dx;
 
 		if (my xmin != his xmin || my xmax != his xmax) {
 			Melder_throw (U"The Pitch and the Sound object must have the same start and end times.");
@@ -1282,7 +1282,7 @@ autoSound Sound_and_Pitch_changeSpeaker (Sound me, Pitch him, double formantMult
 		autoSound sound = Data_copy (me);
 		Vector_subtractMean (sound.get());
 
-		if (formantMultiplier != 1) {
+		if (formantMultiplier != 1.0) {
 			// Shift all frequencies (inclusive pitch!) */
 			Sound_overrideSamplingFrequency (sound.get(), samplingFrequency_old * formantMultiplier);
 		}
@@ -1294,8 +1294,8 @@ autoSound Sound_and_Pitch_changeSpeaker (Sound me, Pitch him, double formantMult
 		autoPointProcess pulses = Sound_Pitch_to_PointProcess_cc (sound.get(), pitch.get());
 		autoPitchTier pitchTier = Pitch_to_PitchTier (pitch.get());
 
-		double median = Pitch_getQuantile (pitch.get(), 0, 0, 0.5, kPitch_unit_HERTZ);
-		if (median != 0 && median != NUMundefined) {
+		double median = Pitch_getQuantile (pitch.get(), 0.0, 0.0, 0.5, kPitch_unit_HERTZ);
+		if (isdefined (median) && median != 0.0) {
 			/* Incorporate pitch shift from overriding the sampling frequency */
 			PitchTier_multiplyFrequencies (pitchTier.get(), sound -> xmin, sound -> xmax, pitchMultiplier / formantMultiplier);
 			PitchTier_modifyExcursionRange (pitchTier.get(), sound -> xmin, sound -> xmax, pitchRangeMultiplier, median);
@@ -1309,7 +1309,7 @@ autoSound Sound_and_Pitch_changeSpeaker (Sound me, Pitch him, double formantMult
 
 		// Resample to the original sampling frequency
 
-		if (formantMultiplier != 1) {
+		if (formantMultiplier != 1.0) {
 			thee = Sound_resample (thee.get(), samplingFrequency_old, 10);
 		}
 		return thee;
@@ -1332,7 +1332,7 @@ autoTextGrid Sound_to_TextGrid_detectSilences (Sound me, double minPitch, double
 	double silenceThreshold, double minSilenceDuration, double minSoundingDuration,
 	const char32 *silentLabel, const char32 *soundingLabel) {
 	try {
-		int subtractMeanPressure = 1;
+		bool subtractMeanPressure = true;
 		autoSound filtered = Sound_filter_passHannBand (me, 80.0, 8000.0, 80.0);
 		autoIntensity thee = Sound_to_Intensity (filtered.get(), minPitch, timeStep, subtractMeanPressure);
 		autoTextGrid him = Intensity_to_TextGrid_detectSilences (thee.get(), silenceThreshold, minSilenceDuration, minSoundingDuration, silentLabel, soundingLabel);
@@ -1371,12 +1371,12 @@ void Sound_getStartAndEndTimesOfSounding (Sound me, double minPitch, double time
 autoSound Sound_and_IntervalTier_cutPartsMatchingLabel (Sound me, IntervalTier thee, const char32 *match) {
     try {
         // count samples of the trimmed sound
-        long ixmin, ixmax, numberOfSamples = 0, previous_ixmax = 0;
+        integer ixmin, ixmax, numberOfSamples = 0, previous_ixmax = 0;
 		double xmin = my xmin; // start time of output sound is start time of input sound
-        for (long iint = 1; iint <= thy intervals.size; iint ++) {
+        for (integer iint = 1; iint <= thy intervals.size; iint ++) {
             TextInterval interval = thy intervals.at [iint];
             if (! Melder_equ (interval -> text, match)) {
-                numberOfSamples += Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, &ixmin, &ixmax);
+                numberOfSamples += Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, & ixmin, & ixmax);
                 // if two contiguous intervals have to be copied then the last sample of previous interval
                 // and first sample of current interval might sometimes be equal
 				if (ixmin == previous_ixmax) {
@@ -1393,18 +1393,18 @@ autoSound Sound_and_IntervalTier_cutPartsMatchingLabel (Sound me, IntervalTier t
         autoSound him = Sound_create (my ny, xmin, xmin + numberOfSamples * my dx, numberOfSamples, my dx, xmin + 0.5 * my dx);
         numberOfSamples = 0;
 		previous_ixmax = 0;
-        for (long iint = 1; iint <= thy intervals.size; iint ++) {
+        for (integer iint = 1; iint <= thy intervals.size; iint ++) {
             TextInterval interval = thy intervals.at [iint];
             if (! Melder_equ (interval -> text, match)) {
-				long ipos;
+				integer ipos;
                 Sampled_getWindowSamples (me, interval -> xmin, interval -> xmax, &ixmin, &ixmax);
 				if (ixmin == previous_ixmax) {
-					ixmin++;
+					ixmin ++;
 				}
 				previous_ixmax = ixmax;
-                for (long ichan = 1; ichan <= my ny; ichan ++) {
+                for (integer ichan = 1; ichan <= my ny; ichan ++) {
                     ipos = numberOfSamples + 1;
-                    for (long i = ixmin; i <= ixmax; i ++, ipos ++) {
+                    for (integer i = ixmin; i <= ixmax; i ++, ipos ++) {
                         his z [ichan] [ipos] = my z [ichan] [i];
                     }
                 }
@@ -1557,9 +1557,9 @@ autoSound Sound_and_Pitch_changeGender_old (Sound me, Pitch him, double formantR
 		autoPitchTier pitchTier = Pitch_to_PitchTier (pitch.get());
 
 		double median = Pitch_getQuantile (pitch.get(), 0, 0, 0.5, kPitch_unit_HERTZ);
-		if (median != 0 && median != NUMundefined) {
+		if (isdefined (median) && median != 0.0) {
 			// Incorporate pitch shift from overriding the sampling frequency
-			if (new_pitch == 0) {
+			if (new_pitch == 0.0) {
 				new_pitch = median / formantRatio;
 			}
 			double factor = new_pitch / median;
@@ -1605,7 +1605,7 @@ void Sound_draw_btlr (Sound me, Graphics g, double tmin, double tmax, double ami
 	if (tmin == tmax) {
 		tmin = my xmin; tmax = my xmax;
 	}
-	long itmin, itmax;
+	integer itmin, itmax;
 	Matrix_getWindowSamplesX (me, tmin, tmax, &itmin, &itmax);
 	if (amin == amax) {
 		Matrix_getWindowExtrema (me, itmin, itmax, 1, my ny, &amin, &amax);
@@ -1836,7 +1836,7 @@ static void _Sound_garnish (Sound me, Graphics g, double tmin, double tmax, doub
 	}
 }
 
-static void _Sound_getWindowExtrema (Sound me, double *tmin, double *tmax, double *minimum, double *maximum, long *ixmin, long *ixmax) {
+static void _Sound_getWindowExtrema (Sound me, double *tmin, double *tmax, double *minimum, double *maximum, integer *ixmin, integer *ixmax) {
 	if (*tmin == *tmax) {
 		*tmin = my xmin;
 		*tmax = my xmax;
@@ -1895,7 +1895,7 @@ static void Sound_findIntermediatePoint_bs (Sound me, long ichannel, long isampl
 		for (long channel = 1; channel <= my ny; channel++) {
 			thy z[channel][2] = Vector_getValueAtX (me, xmid, channel, interpolation);
 		}
-		struct Formula_Result result;
+		Formula_Result result;
 		Formula_compile (interpreter, thee.get(), formula, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		Formula_run (ichannel, 2, & result);
 		bool current = (result.result.numericResult != 0.0);
@@ -1933,13 +1933,13 @@ void Sound_drawWhere (Sound me, Graphics g, double tmin, double tmax, double min
 	bool garnish, const char32 *method, long numberOfBisections, const char32 *formula, Interpreter interpreter) {
 	Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 
-	long ixmin, ixmax;
-	_Sound_getWindowExtrema (me, &tmin, &tmax, &minimum, &maximum, &ixmin, &ixmax);
+	integer ixmin, ixmax;
+	_Sound_getWindowExtrema (me, & tmin, & tmax, & minimum, & maximum, & ixmin, & ixmax);
 
 	// Set coordinates for drawing.
 
 	Graphics_setInner (g);
-	struct Formula_Result result;
+	Formula_Result result;
 	for (long channel = 1; channel <= my ny; channel ++) {
 		Graphics_setWindow (g, tmin, tmax, minimum - (my ny - channel) * (maximum - minimum), maximum + (channel - 1) * (maximum - minimum));
 		if (str32str (method, U"bars") || str32str (method, U"Bars")) {
@@ -2042,12 +2042,11 @@ void Sound_drawWhere (Sound me, Graphics g, double tmin, double tmax, double min
 
 void Sound_paintWhere (Sound me, Graphics g, Graphics_Colour colour, double tmin, double tmax, double minimum, double maximum, double level, bool garnish, long numberOfBisections, const char32 *formula, Interpreter interpreter) {
 	try {
-		long ixmin, ixmax;
-		struct Formula_Result result;
-
+		Formula_Result result;
 		Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 
-		_Sound_getWindowExtrema (me, &tmin, &tmax, &minimum, &maximum, &ixmin, &ixmax);
+		integer ixmin, ixmax;
+		_Sound_getWindowExtrema (me, & tmin, & tmax, & minimum, & maximum, & ixmin, & ixmax);
 
 		Graphics_setColour (g, colour);
 		Graphics_setInner (g);
@@ -2099,7 +2098,7 @@ void Sound_paintWhere (Sound me, Graphics g, Graphics_Colour colour, double tmin
 
 void Sounds_paintEnclosed (Sound me, Sound thee, Graphics g, Graphics_Colour colour, double tmin, double tmax, double minimum, double maximum, bool garnish) {
 	try {
-		long ixmin, ixmax, numberOfChannels = my ny > thy ny ? my ny : thy ny;
+		integer ixmin, ixmax, numberOfChannels = my ny > thy ny ? my ny : thy ny;
 		double min1 = minimum, max1 = maximum, tmin1 = tmin, tmax1 = tmax;
 		double min2 = min1, max2 = max1, tmin2 = tmin1, tmax2 = tmax1;
 		double xmin = my xmin > thy xmin ? my xmin : thy xmin;
@@ -2111,14 +2110,14 @@ void Sounds_paintEnclosed (Sound me, Sound thee, Graphics g, Graphics_Colour col
 			tmin = xmin;
 			tmax = xmax;
 		}
-		_Sound_getWindowExtrema (thee, &tmin1, &tmax1, &min1, &max1, &ixmin, &ixmax);
-		_Sound_getWindowExtrema (me,   &tmin2, &tmax2, &min2, &max2, &ixmin, &ixmax);
+		_Sound_getWindowExtrema (thee, & tmin1, & tmax1, & min1, & max1, & ixmin, & ixmax);
+		_Sound_getWindowExtrema (me,   & tmin2, & tmax2, & min2, & max2, & ixmin, & ixmax);
 		minimum = min1 < min2 ? min1 : min2;
 		maximum = max1 > max2 ? max1 : max2;
 
 		Graphics_setColour (g, colour);
 		Graphics_setInner (g);
-		for (long channel = 1; channel <= numberOfChannels; channel++) {
+		for (integer channel = 1; channel <= numberOfChannels; channel++) {
 			autoPolygon him = Sounds_to_Polygon_enclosed (me, thee, channel, tmin, tmax, minimum, maximum);
 			Graphics_setWindow (g, tmin, tmax, minimum - (numberOfChannels - channel) * (maximum - minimum), maximum + (channel - 1) * (maximum - minimum));
 			Graphics_fillArea (g, his numberOfPoints, &his x[1], &his y[1]);
@@ -2212,8 +2211,9 @@ static autoSound Sound_removeNoiseBySpectralSubtraction_mono (Sound me, Sound no
 
 static void Sound_findNoise (Sound me, double minimumNoiseDuration, double *noiseStart, double *noiseEnd) {
 	try {
-		*noiseStart = NUMundefined; *noiseEnd = NUMundefined;
-		autoIntensity intensity = Sound_to_Intensity (me, 20, 0.005, 1);
+		*noiseStart = undefined;
+		*noiseEnd = undefined;
+		autoIntensity intensity = Sound_to_Intensity (me, 20.0, 0.005, true);
 		double tmin = Vector_getXOfMinimum (intensity.get(), intensity -> xmin, intensity ->  xmax, 1) - minimumNoiseDuration / 2;
 		double tmax = tmin + minimumNoiseDuration;
 		if (tmin < my xmin) {
@@ -2225,7 +2225,8 @@ static void Sound_findNoise (Sound me, double minimumNoiseDuration, double *nois
 		if (tmin < my xmin) {
 			Melder_throw (U"Sound too short, or window length too long.");
 		}
-		*noiseStart = tmin; *noiseEnd = tmax;
+		*noiseStart = tmin;
+		*noiseEnd = tmax;
 	} catch (MelderError) {
 		Melder_throw (me, U": noise not found.");
 	}
diff --git a/dwtools/Spectrogram_extensions.cpp b/dwtools/Spectrogram_extensions.cpp
index 21a0c6c..577ae67 100644
--- a/dwtools/Spectrogram_extensions.cpp
+++ b/dwtools/Spectrogram_extensions.cpp
@@ -65,13 +65,13 @@ void structMelSpectrogram :: v_info () {
 
 // Preconditions: 1 <= iframe <= nx; 1 <= irow <= ny
 double structBandFilterSpectrogram :: v_getValueAtSample (long iframe, long ifreq, int units) {
-	double val = NUMundefined;
+	double val = undefined;
 	if (units == 0) {
-		val = z[ifreq][iframe];
+		val = z [ifreq] [iframe];
 	} else {
 		val = -300.0; // minimum dB value
-		if (z[ifreq][iframe] > 0) {
-			val = 10 * log10 (z[ifreq][iframe] / 4e-10); // power values
+		if (z [ifreq] [iframe] > 0.0) {
+			val = 10.0 * log10 (z [ifreq] [iframe] / 4e-10); // power values
 		}
 	}
 	return val;
@@ -262,9 +262,9 @@ void BandFilterSpectrogram_drawFrequencyScale (BandFilterSpectrogram me, Graphic
 
 	double dx = (xmax - xmin) / (n - 1);
 	double x1 = xmin, y1 = my v_hertzToFrequency (x1);
-	for (long i = 2; i <= n;  i++) {
+	for (integer i = 2; i <= n;  i++) {
 		double x2 = x1 + dx, y2 = my v_hertzToFrequency (x2);
-		if (NUMdefined (y1) && NUMdefined (y2)) {
+		if (isdefined (y1) && isdefined (y2)) {
 			double xo1, yo1, xo2, yo2;
 			if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, &xo1, &yo1, &xo2, &yo2)) {
 				Graphics_line (g, xo1, yo1, xo2, yo2);
@@ -290,7 +290,7 @@ void BandFilterSpectrogram_paintImage (BandFilterSpectrogram me, Graphics g, dou
 	if (ymax <= ymin) {
 		ymin = my ymin; ymax = my ymax;
 	}
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx, &ixmin, &ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy, &iymin, &iymax);
 	autoMatrix thee = Spectrogram_to_Matrix_dB ((Spectrogram) me, 4e-10, 10, -100);
@@ -324,7 +324,7 @@ void BandFilterSpectrogram_drawSpectrumAtNearestTimeSlice (BandFilterSpectrogram
 	if (time < my xmin || time > my xmax) {
 		return;
 	}
-	if (fmin == 0 && fmax == 0) { // autoscaling
+	if (fmin == 0 && fmax == 0) {   // autoscaling
 		fmin = my ymin; fmax = my ymax;
 	}
 	if (fmax <= fmin) {
@@ -333,20 +333,21 @@ void BandFilterSpectrogram_drawSpectrumAtNearestTimeSlice (BandFilterSpectrogram
 	long icol = Matrix_xToNearestColumn (me, time);
 	icol = icol < 1 ? 1 : (icol > my nx ? my nx : icol);
 	autoNUMvector<double> spectrum (1, my ny);
-	for (long i = 1; i <= my ny; i++) {
-		spectrum[i] = my v_getValueAtSample (icol, i, 1); // dB's
+	for (integer i = 1; i <= my ny; i++) {
+		spectrum[i] = my v_getValueAtSample (icol, i, 1);   // dB's
 	}
-	long iymin, iymax;
-	if (Matrix_getWindowSamplesY (me, fmin, fmax, &iymin, &iymax) < 2) { // too few values
+	integer iymin, iymax;
+	if (Matrix_getWindowSamplesY (me, fmin, fmax, & iymin, & iymax) < 2) {   // too few values
 		return;
 	}
 	if (dBmin == dBmax) { // autoscaling
-		dBmin = spectrum[iymin]; dBmax = dBmin;
-		for (long i = iymin + 1; i <= iymax; i++) {
-			if (spectrum[i] < dBmin) {
-				dBmin = spectrum[i];
-			} else if (spectrum[i] > dBmax) {
-				dBmax = spectrum[i];
+		dBmin = spectrum [iymin];
+		dBmax = dBmin;
+		for (long i = iymin + 1; i <= iymax; i ++) {
+			if (spectrum [i] < dBmin) {
+				dBmin = spectrum [i];
+			} else if (spectrum [i] > dBmax) {
+				dBmax = spectrum [i];
 			}
 		}
 		if (dBmin == dBmax) { 
@@ -356,14 +357,15 @@ void BandFilterSpectrogram_drawSpectrumAtNearestTimeSlice (BandFilterSpectrogram
 	Graphics_setWindow (g, fmin, fmax, dBmin, dBmax);
 	Graphics_setInner (g);
 
-	double x1 = my y1 + (iymin -1) * my dy, y1 = spectrum[iymin];
-	for (long i = iymin + 1; i <= iymax - 1; i++) {
-		double x2 = my y1 + (i -1) * my dy, y2 = spectrum[i];
+	double x1 = my y1 + (iymin -1) * my dy, y1 = spectrum [iymin];
+	for (integer i = iymin + 1; i <= iymax - 1; i ++) {
+		double x2 = my y1 + (i -1) * my dy, y2 = spectrum [i];
 		double xo1, yo1, xo2, yo2;
-		if (NUMclipLineWithinRectangle (x1, y1, x2, y2, fmin, dBmin, fmax, dBmax, &xo1, &yo1, &xo2, &yo2)) {
+		if (NUMclipLineWithinRectangle (x1, y1, x2, y2, fmin, dBmin, fmax, dBmax, & xo1, & yo1, & xo2, & yo2)) {
 			Graphics_line (g, xo1, yo1, xo2, yo2);
 		}
-		x1 = x2; y1 = y2;
+		x1 = x2;
+		y1 = y2;
 	}
 	Graphics_unsetInner (g);
 
@@ -381,15 +383,16 @@ void BarkSpectrogram_drawSekeyHansonFilterFunctions (BarkSpectrogram me, Graphic
 	if (zmin >= zmax) {
 		zmin = my ymin;
 		zmax = my ymax;
-		xmin = xIsHertz ? my v_frequencyToHertz (zmin) : zmin;
-		xmax = xIsHertz ? my v_frequencyToHertz (zmax) : zmax;
+		xmin = ( xIsHertz ? my v_frequencyToHertz (zmin) : zmin );
+		xmax = ( xIsHertz ? my v_frequencyToHertz (zmax) : zmax );
 	}
 	if (xIsHertz) {
-		zmin = my v_hertzToFrequency (xmin); zmax = my v_hertzToFrequency (xmax);
+		zmin = my v_hertzToFrequency (xmin);
+		zmax = my v_hertzToFrequency (xmax);
 	}
 	if (ymin >= ymax) {
-		ymin = yscale_dB ? -60.0 : 0.0;
-		ymax = yscale_dB ? 0.0 : 1.0;
+		ymin = ( yscale_dB ? -60.0 : 0.0 );
+		ymax = ( yscale_dB ? 0.0 : 1.0 );
 	}
 	fromFilter = fromFilter <= 0 ? 1 : fromFilter;
 	toFilter = ( toFilter <= 0 || toFilter > my ny ? my ny : toFilter );
@@ -398,35 +401,36 @@ void BarkSpectrogram_drawSekeyHansonFilterFunctions (BarkSpectrogram me, Graphic
 		toFilter = my ny;
 	}
 	long n = xIsHertz ? 1000 : 500;
-	autoNUMvector<double> xz (1, n), xhz (1,n), y (1, n);
+	autoNUMvector<double> xz (1, n), xhz (1, n), y (1, n);
 
 	Graphics_setInner (g);
 	Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 
 	double dz = (zmax - zmin) / (n - 1);
-	for (long iz = 1; iz <= n; iz++) {
+	for (long iz = 1; iz <= n; iz ++) {
 		double f = zmin + (iz - 1) * dz;
-		xz[iz] = f;
-		xhz[iz] = my v_frequencyToHertz (f); // just in case we need the linear scale
+		xz [iz] = f;
+		xhz [iz] = my v_frequencyToHertz (f); // just in case we need the linear scale
 	}
-	for (long ifilter = fromFilter; ifilter <= toFilter; ifilter++) {
+	for (long ifilter = fromFilter; ifilter <= toFilter; ifilter ++) {
 		double zMid = Matrix_rowToY (me, ifilter);
-		for (long iz = 1; iz <= n; iz++) {
+		for (long iz = 1; iz <= n; iz ++) {
 			double z = xz[iz] - (zMid - 0.215);
 			double amp = 7.0 - 7.5 * z - 17.5 * sqrt (0.196 + z * z);
-			y[iz] = yscale_dB ? amp : pow (10.0, amp / 10.0);
+			y [iz] = ( yscale_dB ? amp : pow (10.0, amp / 10.0) );
 		}
 		// the drawing
-		double x1 = xIsHertz ? xhz[1] : xz[1], y1 = y[1];
-		for (long iz = 2; iz <= n; iz++) {
-			double x2 = xIsHertz ? xhz[iz] : xz[iz], y2 = y[iz];
-			if (NUMdefined (x1) && NUMdefined (x2)) {
+		double x1 = ( xIsHertz ? xhz [1] : xz [1] ), y1 = y [1];
+		for (long iz = 2; iz <= n; iz ++) {
+			double x2 = ( xIsHertz ? xhz [iz] : xz [iz] ), y2 = y [iz];
+			if (isdefined (x1) && isdefined (x2)) {
 				double xo1, yo1, xo2, yo2;
-				if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, &xo1, &yo1, &xo2, &yo2)) {
+				if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, & xo1, & yo1, & xo2, & yo2)) {
 					Graphics_line (g, xo1, yo1, xo2, yo2);
 				}
 			}
-			x1 = x2; y1 = y2;
+			x1 = x2;
+			y1 = y2;
 		}
 	}	
 	Graphics_unsetInner (g);
@@ -509,10 +513,10 @@ void MelSpectrogram_drawTriangularFilterFunctions (MelSpectrogram me, Graphics g
 				y[iz] = yscale_dB ? (amp > 0.0 ? 20.0 * log10 (amp) : ymin - 10.0) : amp;
 			}
 			double x1 = xIsHertz ? xhz[1] : xz[1], y1 = y[1];
-			if (NUMdefined (y1)) {
+			if (isdefined (y1)) {
 				for (long iz = 1; iz <= n; iz++) {
 					double x2 = xIsHertz ? xhz[iz] : xz[iz], y2 = y[iz];
-					if (NUMdefined (y2)) {
+					if (isdefined (y2)) {
 						if (NUMclipLineWithinRectangle (x1, y1, x2, y2, xmin, ymin, xmax, ymax, &xo1, &yo1, &xo2, &yo2)) {
 							Graphics_line (g, xo1, yo1, xo2, yo2);
 						}
diff --git a/dwtools/Spectrum_extensions.cpp b/dwtools/Spectrum_extensions.cpp
index 60b74f7..f74d662 100644
--- a/dwtools/Spectrum_extensions.cpp
+++ b/dwtools/Spectrum_extensions.cpp
@@ -398,8 +398,8 @@ autoSpectrum Spectrum_compressFrequencyDomain (Spectrum me, double fmax, long in
 				x = NUM_interpolate_sinc (my z[1], my nx, index, interpolationDepth);
 				y = NUM_interpolate_sinc (my z[2], my nx, index, interpolationDepth);
 			} else {
-				x = NUMundefined;   // ppgb: better than data from random memory
-				y = NUMundefined;
+				x = undefined;   // ppgb: better than data from random memory
+				y = undefined;
 			}
 			thy z[1][i] = x; thy z[2][i] = y;
 		}
diff --git a/dwtools/SpeechSynthesizer.cpp b/dwtools/SpeechSynthesizer.cpp
index 394efbe..a5446d5 100644
--- a/dwtools/SpeechSynthesizer.cpp
+++ b/dwtools/SpeechSynthesizer.cpp
@@ -141,7 +141,7 @@ static void NUMvector_extendNumberOfElements (long elementSize, void **v, long l
 		char *result;
 		if (! *v) {
 			long newhi = lo + extraDemand - 1;
-			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, newhi));
+			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, newhi, true));
 			*hi = newhi;
 		} else {
 			long offset = lo * elementSize;
diff --git a/dwtools/SpeechSynthesizer_and_TextGrid.cpp b/dwtools/SpeechSynthesizer_and_TextGrid.cpp
index fa31fb9..1d529af 100644
--- a/dwtools/SpeechSynthesizer_and_TextGrid.cpp
+++ b/dwtools/SpeechSynthesizer_and_TextGrid.cpp
@@ -71,7 +71,7 @@ static double TextGrid_getStartTimeOfFirstOccurence (TextGrid thee, long tierNum
 	if (intervalTier -> classInfo != classIntervalTier) {
 		Melder_throw (U"Tier ", tierNumber, U" is not an interval tier.");
 	}
-	double start = NUMundefined;
+	double start = undefined;
 	for (long iint = 1; iint <= intervalTier -> intervals.size; iint ++) {
 		TextInterval ti = intervalTier -> intervals.at [iint];
 		if (Melder_cmp (ti -> text, label) == 0) {
@@ -88,7 +88,7 @@ static double TextGrid_getEndTimeOfLastOccurence (TextGrid thee, long tierNumber
 	if (intervalTier -> classInfo != classIntervalTier) {
 		Melder_throw (U"Tier ", tierNumber, U" is not an interval tier.");
 	}
-	double end = NUMundefined;
+	double end = undefined;
 	for (long iint = intervalTier -> intervals.size; iint > 0; iint --) {
 		TextInterval ti = intervalTier -> intervals.at [iint];
 		if (Melder_equ (ti -> text, label)) {
@@ -279,7 +279,7 @@ autoTextGrid TextGrid_and_IntervalTier_cutPartsMatchingLabel (TextGrid me, Inter
 // The resulting IntervalTier has thy xmin as starting time and thy xmax as end time
 autoIntervalTier IntervalTiers_patch_noBoundaries (IntervalTier me, IntervalTier thee, const char32 *patchLabel, double precision) {
     try {
-		autoNUMvector<double> durations (0L, my intervals.size + 1);
+		autoNUMvector <double> durations ((integer) 0, my intervals.size + 1);
 		for (long i = 1; i <= my intervals.size; i ++) {
 			TextInterval myti = my intervals.at [i];
 			durations [i] = myti -> xmax - myti -> xmin;
@@ -533,7 +533,7 @@ autoTextGrid SpeechSynthesizer_and_Sound_and_TextInterval_align (SpeechSynthesiz
 				for (long itier = 1; itier <= 4; itier	++) {
 					IntervalTier tier = result -> intervalTier_cast (itier);
 					tier -> xmax = thy xmax;
-					TextInterval textInterval = tier -> intervals.at [tier -> intervals . size];
+					TextInterval textInterval = tier -> intervals.at [tier -> intervals.size];
 					textInterval -> xmax = thy xmax;
 				}
 			} else {	
@@ -724,8 +724,8 @@ autoTable IntervalTiers_to_Table_textAlignmentment (IntervalTier target, Interva
 		for (long i = 2; i <= pathLength; i++) {
 			structPairOfInteger p = edit -> warpingPath -> path[i];
 			structPairOfInteger p1 = edit -> warpingPath -> path[i - 1];
-			double targetStart = NUMundefined, targetEnd = NUMundefined;
-			double sourceStart = NUMundefined, sourceEnd = NUMundefined;
+			double targetStart = undefined, targetEnd = undefined;
+			double sourceStart = undefined, sourceEnd = undefined;
 			const char32 * targetText = U"", *sourceText = U"";
 			long targetInterval = p.y > 1 ? targetOrigin[p.y - 1] : 0;
 			long sourceInterval = p.x > 1 ? sourceOrigin[p.x - 1] : 0;
@@ -745,8 +745,8 @@ autoTable IntervalTiers_to_Table_textAlignmentment (IntervalTier target, Interva
 			if (p.y == p1.y) { // deletion
 				Table_setNumericValue (thee.get(), irow, 1, 0);
 				Table_setStringValue  (thee.get(), irow, 2, U"");
-				Table_setNumericValue (thee.get(), irow, 3, NUMundefined);
-				Table_setNumericValue (thee.get(), irow, 4, NUMundefined);
+				Table_setNumericValue (thee.get(), irow, 3, undefined);
+				Table_setNumericValue (thee.get(), irow, 4, undefined);
 				Table_setNumericValue (thee.get(), irow, 5, sourceInterval);
 				Table_setStringValue  (thee.get(), irow, 6, sourceText);
 				Table_setNumericValue (thee.get(), irow, 7, sourceStart);
@@ -759,8 +759,8 @@ autoTable IntervalTiers_to_Table_textAlignmentment (IntervalTier target, Interva
 				Table_setNumericValue (thee.get(), irow, 4, targetEnd);
 				Table_setNumericValue (thee.get(), irow, 5, 0);
 				Table_setStringValue  (thee.get(), irow, 6, U"");
-				Table_setNumericValue (thee.get(), irow, 7, NUMundefined);
-				Table_setNumericValue (thee.get(), irow, 8, NUMundefined);
+				Table_setNumericValue (thee.get(), irow, 7, undefined);
+				Table_setNumericValue (thee.get(), irow, 8, undefined);
 				Table_setStringValue  (thee.get(), irow, 9, U"i");
 			} else { // substitution ?
 				Table_setNumericValue (thee.get(), irow, 1, targetInterval);
diff --git a/dwtools/TableOfReal_extensions.cpp b/dwtools/TableOfReal_extensions.cpp
index 7ef8c9d..5ef12a9 100644
--- a/dwtools/TableOfReal_extensions.cpp
+++ b/dwtools/TableOfReal_extensions.cpp
@@ -1,6 +1,6 @@
 /* TableOfReal_extensions.cpp
  *
- * Copyright (C) 1993-2012, 2014, 2015, 2017 David Weenink
+ * Copyright (C) 1993-2012, 2014, 2015, 2017 David Weenink, 2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -294,7 +294,7 @@ void TableOfReal_to_PatternList_and_Categories (TableOfReal me, long fromrow, lo
 }
 
 void TableOfReal_getColumnExtrema (TableOfReal me, long col, double *p_min, double *p_max) {
-	double min = NUMundefined, max = NUMundefined;
+	double min = undefined, max = undefined;
 	if (col < 1 || col > my numberOfColumns) {
 		Melder_throw (U"Invalid column number.");
 	}
@@ -324,16 +324,16 @@ void TableOfReal_drawRowsAsHistogram (TableOfReal me, Graphics g, const char32 *
 		Melder_throw (U"Invalid columns");
 	}
 
-	long nrows;
-	autoNUMvector<double> irows (NUMstring_to_numbers (rows, &nrows), 1);
-	for (long i = 1; i <= nrows; i++) {
-		long irow = (long) floor (irows[i]);
+	integer nrows;
+	autoNUMvector <real> irows (NUMstring_to_numbers (rows, & nrows), 1);
+	for (integer i = 1; i <= nrows; i ++) {
+		integer irow = (long) floor (irows [i]);
 		if (irow < 0 || irow > my numberOfRows) {
 			Melder_throw (U"Invalid row (", irow, U").");
 		}
 		if (ymin >= ymax) {
 			double min, max;
-			NUMvector_extrema (my data[irow], colb, cole, &min, &max);
+			NUMvector_extrema (my data [irow], colb, cole, & min, & max);
 			if (i > 1) {
 				if (min < ymin) {
 					ymin = min;
@@ -342,12 +342,13 @@ void TableOfReal_drawRowsAsHistogram (TableOfReal me, Graphics g, const char32 *
 					ymax = max;
 				}
 			} else {
-				ymin = min; ymax = max;
+				ymin = min;
+				ymax = max;
 			}
 		}
 	}
-	long ngreys;
-	autoNUMvector<double> igreys (NUMstring_to_numbers (greys, &ngreys), 1);
+	integer ngreys;
+	autoNUMvector <real> igreys (NUMstring_to_numbers (greys, & ngreys), 1);
 
 	Graphics_setWindow (g, 0.0, 1.0, ymin, ymax);
 	Graphics_setInner (g);
@@ -503,13 +504,13 @@ void TableOfReal_drawBoxPlots (TableOfReal me, Graphics g, long rowmin, long row
 	Graphics_setWindow (g, colmin - 0.5, colmax + 0.5, ymin, ymax);
 	Graphics_setInner (g);
 
-	for (long j = colmin; j <= colmax; j++) {
+	for (long j = colmin; j <= colmax; j ++) {
 		double x = j, r = 0.05, w = 0.2, t;
 		long ndata = 0;
 
 		for (long i = 1; i <= numberOfRows; i++) {
-			if ( (t = my data[rowmin + i - 1][j]) != NUMundefined) {
-				data[++ndata] = t;
+			if (isdefined (t = my data [rowmin + i - 1] [j])) {
+				data [++ ndata] = t;
 			}
 		}
 		Graphics_boxAndWhiskerPlot (g, data.peek(), ndata, x, r, w, ymin, ymax);
@@ -652,14 +653,13 @@ void TableOfReal_centreColumns_byRowLabel (TableOfReal me) {
 
 double TableOfReal_getRowSum (TableOfReal me, long index) {
 	if (index < 1 || index > my numberOfRows) {
-		return NUMundefined;
+		return undefined;
 	}
-
-	double sum = 0.0;
+	real80 sum = 0.0;
 	for (long j = 1; j <= my numberOfColumns; j ++) {
 		sum += my data [index] [j];
 	}
-	return sum;
+	return (real) sum;
 }
 
 double TableOfReal_getColumnSumByLabel (TableOfReal me, const char32 *label) {
@@ -680,14 +680,13 @@ double TableOfReal_getRowSumByLabel (TableOfReal me, const char32 *label) {
 
 double TableOfReal_getColumnSum (TableOfReal me, long index) {
 	if (index < 1 || index > my numberOfColumns) {
-		return NUMundefined;
+		return undefined;
 	}
-
-	double sum = 0.0;
+	real80 sum = 0.0;
 	for (long i = 1; i <= my numberOfRows; i ++) {
 		sum += my data [i] [index];
 	}
-	return sum;
+	return (real) sum;
 }
 
 double TableOfReal_getGrandSum (TableOfReal me) {
@@ -729,13 +728,13 @@ void TableOfReal_normalizeTable (TableOfReal me, double norm) {
 }
 
 double TableOfReal_getTableNorm (TableOfReal me) {
-	double sumsq = 0.0;
+	real80 sumsq = 0.0;
 	for (long i = 1; i <= my numberOfRows; i++) {
 		for (long j = 1; j <= my numberOfColumns; j++) {
 			sumsq += my data[i][j] * my data[i][j];
 		}
 	}
-	return sqrt (sumsq);
+	return sqrt ((real) sumsq);
 }
 
 int TableOfReal_checkPositive (TableOfReal me) {
@@ -744,14 +743,15 @@ int TableOfReal_checkPositive (TableOfReal me) {
 	for (long i = 1; i <= my numberOfRows; i++) {
 		for (long j = 1; j <= my numberOfColumns; j++) {
 			if (my data[i][j] < 0.0) {
-				negative ++; break;
+				negative ++;
+				break;
 			}
 		}
 	}
 	return negative == 0;
 }
 
-/* NUMundefined ??? */
+/* undefined ??? */
 void NUMdmatrix_getColumnExtrema (double **a, long rowb, long rowe, long icol, double *min, double *max);
 void NUMdmatrix_getColumnExtrema (double **a, long rowb, long rowe, long icol, double *min, double *max) {
 	*min = *max = a[rowb][icol];
@@ -982,7 +982,7 @@ bool TableOfRealList_haveIdenticalDimensions (TableOfRealList me) {
 double TableOfReal_getColumnQuantile (TableOfReal me, long col, double quantile) {
 	try {
 		if (col < 1 || col > my numberOfColumns) {
-			return NUMundefined;
+			return undefined;
 		}
 		autoNUMvector<double> values (1, my numberOfRows);
 
@@ -994,7 +994,7 @@ double TableOfReal_getColumnQuantile (TableOfReal me, long col, double quantile)
 		double r = NUMquantile (my numberOfRows, values.peek(), quantile);
 		return r;
 	} catch (MelderError) {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
@@ -1565,16 +1565,16 @@ double TableOfReal_normalityTest_BHEP (TableOfReal me, double *h, double *p_tnb,
 		double beta2 = beta * beta, beta4 = beta2 * beta2, beta8 = beta4 * beta4;
 		double gamma = 1 + 2 * beta2, gamma2 = gamma * gamma, gamma4 = gamma2 * gamma2;
 		double delta = 1.0 + beta2 * (4 + 3 * beta2), delta2 = delta * delta;
-		double prob = NUMundefined;
+		double prob = undefined;
 
 		if (*h <= 0) {
 			*h = NUMsqrt1_2 / beta;
 		}
 
-		double tnb = NUMundefined, lnmu = NUMundefined, lnvar = NUMundefined;
+		double tnb = undefined, lnmu = undefined, lnvar = undefined;
 
 		if (n < 2 || p < 1) {
-			return NUMundefined;
+			return undefined;
 		}
 
 		autoCovariance thee = TableOfReal_to_Covariance (me);
diff --git a/dwtools/Table_extensions.cpp b/dwtools/Table_extensions.cpp
index 596c292..685296a 100644
--- a/dwtools/Table_extensions.cpp
+++ b/dwtools/Table_extensions.cpp
@@ -1,6 +1,6 @@
 /* Table_extensions.cpp
 	 *
- * Copyright (C) 1997-2017 David Weenink
+ * Copyright (C) 1997-2017 David Weenink, Paul Boersma 2017
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -42,19 +42,19 @@
 #include "SSCP.h"
 #include "Table_extensions.h"
 
-static bool Table_selectedColumnPartIsNumeric (Table me, long column, long *selectedRows, long numberOfSelectedRows) {
+static bool Table_selectedColumnPartIsNumeric (Table me, integer column, integer *selectedRows, integer numberOfSelectedRows) {
 	if (column < 1 || column > my numberOfColumns) return false;
-	for (long irow = 1; irow <= numberOfSelectedRows; irow++) {
+	for (integer irow = 1; irow <= numberOfSelectedRows; irow ++) {
 		if (! Table_isCellNumeric_ErrorFalse (me, selectedRows[irow], column)) return false;
 	}
 	return true;
 }
 
-// column and selectedRows are valid; *min & *max must be intialized
-static void Table_columnExtremesFromSelectedRows (Table me, long column, long *selectedRows, long numberOfSelectedRows, double *min, double *max) {
+// column and selectedRows are valid; *min & *max must have been initialized
+static void Table_columnExtremesFromSelectedRows (Table me, integer column, integer *selectedRows, integer numberOfSelectedRows, double *min, double *max) {
 	double cmin = 1e308, cmax = - cmin;
-	for (long irow = 1; irow <= numberOfSelectedRows; irow++) {
-		double val = Table_getNumericValue_Assert (me, selectedRows[irow], column);
+	for (integer irow = 1; irow <= numberOfSelectedRows; irow ++) {
+		double val = Table_getNumericValue_Assert (me, selectedRows [irow], column);
 		if (val < cmin) { cmin = val; }
 		if (val > cmax) { cmax = val; }
 	}
@@ -3223,15 +3223,15 @@ void Table_horizontalErrorBarsPlotWhere (Table me, Graphics g, long xcolumn, lon
 	double ymin, double ymax, long xci_min, long xci_max, double bar_mm, bool garnish, const char32 *formula, Interpreter interpreter)
 {
 	try {
-		long nrows = my rows.size;
+		integer nrows = my rows.size;
 		if (xcolumn < 1 || xcolumn > nrows || ycolumn < 1 || ycolumn > nrows ||
 			(xci_min != 0 && xci_min > nrows) || (xci_max != 0 && xci_max > nrows)) {
 			return;
 		}
-		long numberOfSelectedRows = 0;
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);	
+		integer numberOfSelectedRows = 0;
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
 		if (ymin >= ymax) {
-			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, &ymin, &ymax);
+			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, & ymin, & ymax);
 			if (ymin >= ymax) {
 				ymin -= 1.0;
 				ymax += 1.0;
@@ -3239,13 +3239,13 @@ void Table_horizontalErrorBarsPlotWhere (Table me, Graphics g, long xcolumn, lon
 		}
 		double x1min, x1max;
 		if (xmin >= xmax) {
-			Table_columnExtremesFromSelectedRows (me, xcolumn, selectedRows.peek(), numberOfSelectedRows, &xmin, &xmax);
+			Table_columnExtremesFromSelectedRows (me, xcolumn, selectedRows.peek(), numberOfSelectedRows, & xmin, & xmax);
 			if (xci_min > 0) {
-				Table_columnExtremesFromSelectedRows (me, xci_min, selectedRows.peek(), numberOfSelectedRows, &x1min, &x1max);
+				Table_columnExtremesFromSelectedRows (me, xci_min, selectedRows.peek(), numberOfSelectedRows, & x1min, & x1max);
 				xmin -= x1max;
 			}
 			if (xci_max > 0) {
-				Table_columnExtremesFromSelectedRows (me, xci_max, selectedRows.peek(), numberOfSelectedRows, &x1min, &x1max);
+				Table_columnExtremesFromSelectedRows (me, xci_max, selectedRows.peek(), numberOfSelectedRows, & x1min, & x1max);
 				xmax += x1max;
 			}
 			if (xmin >= xmax) {
@@ -3256,22 +3256,24 @@ void Table_horizontalErrorBarsPlotWhere (Table me, Graphics g, long xcolumn, lon
 		Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 		Graphics_setInner (g);
 		double dy = Graphics_dyMMtoWC (g, bar_mm);
-		for (long row = 1; row <= numberOfSelectedRows; row++) {
-			double x = Table_getNumericValue_Assert (me, selectedRows [row], xcolumn);
-			double y = Table_getNumericValue_Assert (me, selectedRows [row], ycolumn);
-			double dx1 = ( xci_min > 0 ? Table_getNumericValue_Assert (me, selectedRows [row], xci_min) : 0 );
-			double dx2 = ( xci_max > 0 ? Table_getNumericValue_Assert (me, selectedRows [row], xci_max) : 0 );
+		for (long irow = 1; irow <= numberOfSelectedRows; irow ++) {
+			double x = Table_getNumericValue_Assert (me, selectedRows [irow], xcolumn);
+			double y = Table_getNumericValue_Assert (me, selectedRows [irow], ycolumn);
+			double dx1 =
+				xci_min > 0 ? Table_getNumericValue_Assert (me, selectedRows [irow], xci_min) : 0.0;
+			double dx2 =
+				xci_max > 0 ? Table_getNumericValue_Assert (me, selectedRows [irow], xci_max) : 0.0;
 			double x1 = x - dx1, x2 = x + dx2, xc1, yc1, xc2, yc2;
 
 			if (x <= xmax && x >= xmin && y <= ymax && y >= ymin) {
 				// horizontal confidence interval
-				if (intervalsIntersect (x1, x2, xmin, xmax, &xc1, &xc2)) {
+				if (intervalsIntersect (x1, x2, xmin, xmax, & xc1, & xc2)) {
 					Graphics_line (g, xc1, y, xc2, y);
-					if (dy > 0 && intervalsIntersect (y - dy / 2, y + dy / 2, ymin, ymax, &yc1, &yc2)) {
-						if (xc1 >= xmin && dx1 > 0) {
+					if (dy > 0 && intervalsIntersect (y - dy / 2.0, y + dy / 2.0, ymin, ymax, & yc1, & yc2)) {
+						if (xc1 >= xmin && dx1 > 0.0) {
 							Graphics_line (g, xc1, yc1, xc1, yc2);
 						}
-						if (xc2 <= xmax && dx2 > 0) {
+						if (xc2 <= xmax && dx2 > 0.0) {
 							Graphics_line (g, xc2, yc1, xc2, yc2);
 						}
 					}
@@ -3296,15 +3298,15 @@ void Table_verticalErrorBarsPlotWhere (Table me, Graphics g,
 	double bar_mm, bool garnish, const char32 *formula, Interpreter interpreter)
 {
 	try {
-		long nrows = my rows.size;
+		integer nrows = my rows.size;
 		if (xcolumn < 1 || xcolumn > nrows || ycolumn < 1 || ycolumn > nrows ||
 			(yci_min != 0 && yci_min > nrows) || (yci_max != 0 && yci_max > nrows)) {
 			return;
 		}
-		long numberOfSelectedRows = 0;
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);
+		integer numberOfSelectedRows = 0;
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
 		if (xmin >= xmax) {
-			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, &ymin, &ymax);
+			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, & ymin, & ymax);
 			if (xmin >= xmax) {
 				xmin -= 1.0;
 				xmax += 1.0;
@@ -3312,13 +3314,13 @@ void Table_verticalErrorBarsPlotWhere (Table me, Graphics g,
 		}
 		double y1min, y1max;
 		if (ymin >= ymax) {
-			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, &ymin, &ymax);
+			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, & ymin, & ymax);
 			if (yci_min > 0) {
-				Table_columnExtremesFromSelectedRows (me, yci_min, selectedRows.peek(), numberOfSelectedRows, &y1min, &y1max);
+				Table_columnExtremesFromSelectedRows (me, yci_min, selectedRows.peek(), numberOfSelectedRows, & y1min, & y1max);
 				ymin -= y1max;
 			}
 			if (yci_max > 0) {
-				Table_columnExtremesFromSelectedRows (me, yci_max, selectedRows.peek(), numberOfSelectedRows, &y1min, &y1max);
+				Table_columnExtremesFromSelectedRows (me, yci_max, selectedRows.peek(), numberOfSelectedRows, & y1min, & y1max);
 				ymax += y1max;
 			}
 			if (ymin >= ymax) {
@@ -3329,18 +3331,20 @@ void Table_verticalErrorBarsPlotWhere (Table me, Graphics g,
 		Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 		Graphics_setInner (g);
 		double dx = Graphics_dxMMtoWC (g, bar_mm);
-		for (long row = 1; row <= numberOfSelectedRows; row++) {
-			double x  = Table_getNumericValue_Assert (me, selectedRows[row], xcolumn);
-			double y  = Table_getNumericValue_Assert (me, selectedRows[row], ycolumn);
-			double dy1 = yci_min > 0 ? Table_getNumericValue_Assert (me, selectedRows[row], yci_min) : 0.0;
-			double dy2 = yci_max > 0 ? Table_getNumericValue_Assert (me, selectedRows[row], yci_max) : 0.0;
+		for (long irow = 1; irow <= numberOfSelectedRows; irow ++) {
+			double x  = Table_getNumericValue_Assert (me, selectedRows [irow], xcolumn);
+			double y  = Table_getNumericValue_Assert (me, selectedRows [irow], ycolumn);
+			double dy1 =
+				yci_min > 0 ? Table_getNumericValue_Assert (me, selectedRows [irow], yci_min) : 0.0;
+			double dy2 =
+				yci_max > 0 ? Table_getNumericValue_Assert (me, selectedRows [irow], yci_max) : 0.0;
 			double y1 = y - dy1, y2 = y + dy2, xc1, yc1, xc2, yc2;
 
 			if (x <= xmax && x >= xmin && y <= ymax && y >= ymin) {
 				// vertical confidence interval
-				if (intervalsIntersect (y1, y2, ymin, ymax, &yc1, &yc2)) {
+				if (intervalsIntersect (y1, y2, ymin, ymax, & yc1, & yc2)) {
 					Graphics_line (g, x, yc1, x, yc2);
-					if (dx > 0 && intervalsIntersect (x - dx / 2.0, x + dx / 2.0, xmin, xmax, &xc1, &xc2)) {
+					if (dx > 0 && intervalsIntersect (x - dx / 2.0, x + dx / 2.0, xmin, xmax, & xc1, & xc2)) {
 						if (yc1 >= ymin && dy1 > 0.0) {
 							Graphics_line (g, xc1, yc1, xc2, yc1);
 						}
@@ -3368,13 +3372,13 @@ double Table_getMedianAbsoluteDeviation (Table me, long columnNumber)
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_Assert (me, columnNumber);
 		if (my rows.size < 1) {
-			return NUMundefined;
+			return undefined;
 		}
 		autoNUMvector<double> data (1, my rows.size);
 		for (long irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			data[irow] = row -> cells[columnNumber].number;
-			if (data[irow] == NUMundefined) {
+			if (isundef (data [irow])) {
 				Melder_throw (me, U": the cell in row ", irow, U" of column \"",
 					my columnHeaders[columnNumber].label ? my columnHeaders[columnNumber].label : Melder_integer (columnNumber), U"\" is undefined.");
 			}
@@ -3538,7 +3542,7 @@ void Table_printAsAnovaTable (Table me) {
 		MelderString_copy (&s, Melder_padOrTruncate (width [1], row -> cells [1]. string), U"\t");
 		for (long j = 2; j <= 6; j ++) {
 			double value = row -> cells [j]. number;
-			if (NUMdefined (value)) {
+			if (isdefined (value)) {
 				MelderString_append (&s, Melder_pad (width [j], Melder_single (value)), j == 6 ? U"" : U"\t");
 			} else {
 				MelderString_append (&s, Melder_pad (width [j], U""), j == 6 ? U"" : U"\t");
@@ -3564,7 +3568,7 @@ void Table_printAsMeansTable (Table me) {
 		MelderString_copy (&s, Melder_padOrTruncate (10, row -> cells [1]. string), U"\t");
 		for (long j = 2; j <= my numberOfColumns; j++) {
 			double value = row -> cells[j].number;
-			if (value != NUMundefined) {
+			if (isdefined (value)) {
 				MelderString_append (&s,
 					Melder_pad (10, Melder_half (value)),
 					j == my numberOfColumns ? U"" : U"\t");
@@ -3660,7 +3664,7 @@ autoTable Table_getOneWayAnalysisOfVarianceF (Table me, long column, long factor
 			Table_setNumericValue (ameans.get(), irow, 2, factorLevelMeans [irow]);
 			Table_setNumericValue (ameans.get(), irow, 3, factorLevelSizes [irow]);
 		}
-		long columns [1+1] { 0, 2 };   // sort by column 2
+		integer columns [1+1] { 0, 2 };   // sort by column 2
 		Table_sortRows_Assert (ameans.get(), columns, 1);
 		_Table_postHocTukeyHSD (ameans.get(), ms_w, dof_w, meansDiff, meansDiffProbabilities);
 		if (means) {
@@ -4108,12 +4112,12 @@ void Table_boxPlots (Table me, Graphics g, long dataColumn, long factorColumn, d
 }
 
 void Table_boxPlotsWhere (Table me, Graphics g,
-	char32 *dataColumns_string, long factorColumn, double ymin, double ymax,
+	const char32 *dataColumns_string, long factorColumn, double ymin, double ymax,
 	bool garnish, const char32 *formula, Interpreter interpreter)
 {
 	try {
-		long numberOfSelectedColumns;
-		autoNUMvector<long> dataColumns (Table_getColumnIndicesFromColumnLabelString (me, dataColumns_string, & numberOfSelectedColumns), 1);
+		integer numberOfSelectedColumns;
+		autoNUMvector <integer> dataColumns (Table_getColumnIndicesFromColumnLabelString (me, dataColumns_string, & numberOfSelectedColumns), 1);
 		if (factorColumn < 1 || factorColumn > my numberOfColumns) {
 			return;
 		}
@@ -4145,7 +4149,7 @@ void Table_boxPlotsWhere (Table me, Graphics g,
 				long numberOfDataInLevelColumn = 0;
 				for (long irow = 1; irow <= numberOfData; irow ++) {
 					if (si -> classIndex[irow] == ilevel) {
-						struct Formula_Result result;
+						Formula_Result result;
 						Formula_run (irow, dataColumns [icol], & result);
 						if (result.result.numericResult != 0.0) {
 							data [++ numberOfDataInLevelColumn] = Table_getNumericValue_Assert (me, irow, dataColumns [icol]);
@@ -4184,7 +4188,7 @@ void Table_distributionPlotWhere (Table me, Graphics g,
 		long n = my rows.size, mrow = 0;
 		autoMatrix thee = Matrix_create (1.0, 1.0, 1, 1.0, 1.0, 0.0, n + 1.0, n, 1.0, 1.0);
 		for (long irow = 1; irow <= n; irow ++) {
-			struct Formula_Result result;
+			Formula_Result result;
 			Formula_run (irow, dataColumn, & result);
 			if (result.result.numericResult != 0.0) {
 				thy z[1][++mrow] = Table_getNumericValue_Assert (me, irow, dataColumn);
@@ -4256,7 +4260,7 @@ long Table_getNumberOfRowsWhere (Table me, const char32 *formula, Interpreter in
 	long numberOfRows = 0;
 	Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_UNKNOWN, true);
 	for (long irow = 1; irow <= my rows.size; irow ++) {
-		struct Formula_Result result;
+		Formula_Result result;
 		Formula_run (irow, 1, & result);
 		if (result.result.numericResult != 0.0) {
 			numberOfRows++;
@@ -4265,20 +4269,20 @@ long Table_getNumberOfRowsWhere (Table me, const char32 *formula, Interpreter in
 	return numberOfRows;
 }
 
-long *Table_findRowsMatchingCriterion (Table me, const char32 *formula, Interpreter interpreter, long *p_numberOfMatches) {
+integer *Table_findRowsMatchingCriterion (Table me, const char32 *formula, Interpreter interpreter, integer *p_numberOfMatches) {
 	try {
-		long numberOfMatches = Table_getNumberOfRowsWhere (me, formula, interpreter);
+		integer numberOfMatches = Table_getNumberOfRowsWhere (me, formula, interpreter);
 		if (numberOfMatches < 1) {
 			Melder_throw (U"No rows selected.");
 		}
 		Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_UNKNOWN, true);   // again?
-		autoNUMvector<long> selectedRows (1, numberOfMatches);
+		autoNUMvector <integer> selectedRows (1, numberOfMatches);
 		long n = 0;
 		for (long irow =1; irow <= my rows.size; irow ++) {
-			struct Formula_Result result;
+			Formula_Result result;
 			Formula_run (irow, 1, & result);
 			if (result.result.numericResult != 0.0) {
-				selectedRows[++n] = irow;
+				selectedRows [++ n] = irow;
 			}
 		}
 		Melder_assert (n == numberOfMatches);
@@ -4298,12 +4302,12 @@ void Table_barPlotWhere (Table me, Graphics g,
 	double angle, bool garnish, const char32 *formula, Interpreter interpreter)
 {
 	try {
-		long numberOfColumns, numberOfRowMatches = 0;
-		autoNUMvector<long> columnIndex (Table_getColumnIndicesFromColumnLabelString (me, columnLabels, &numberOfColumns), 1);
-		long labelIndex = Table_findColumnIndexFromColumnLabel (me, factorColumn);
-		autoStrings colour = itemizeColourString (colours);// removes all spaces within { } so each {} can be parsed as 1 item
+		integer numberOfColumns, numberOfRowMatches = 0;
+		autoNUMvector <integer> columnIndex (Table_getColumnIndicesFromColumnLabelString (me, columnLabels, & numberOfColumns), 1);
+		integer labelIndex = Table_findColumnIndexFromColumnLabel (me, factorColumn);
+		autoStrings colour = itemizeColourString (colours);   // removes all spaces within { } so each {} can be parsed as 1 item
 		
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfRowMatches), 1);
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfRowMatches), 1);
 		if (ymax <= ymin) { // autoscaling
 			ymin = 1e308; ymax= - ymin;
 			for (long icol = 1; icol <= numberOfColumns; icol++) {
@@ -4413,8 +4417,8 @@ void Table_lineGraphWhere (Table me, Graphics g,
 {
 	try {
 		if (ycolumn < 1 || ycolumn > my numberOfColumns) return;
-		long numberOfSelectedRows = 0;
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);	
+		integer numberOfSelectedRows = 0;
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
 		if (ymax <= ymin) { // autoscaling
 			Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, &ymin, &ymax);
 		}
@@ -4508,12 +4512,12 @@ void Table_lagPlotWhere (Table me, Graphics g,
 		if (column < 1 || column > my rows.size) {
 			return;
 		}
-		long numberOfSelectedRows = 0;
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);
+		integer numberOfSelectedRows = 0;
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
 		if (xmax <= xmin) { // autoscaling
-			Table_columnExtremesFromSelectedRows (me, column, selectedRows.peek(), numberOfSelectedRows, &xmin, &xmax);
+			Table_columnExtremesFromSelectedRows (me, column, selectedRows.peek(), numberOfSelectedRows, & xmin, & xmax);
 		}
-		autoNUMvector<double> x (1, numberOfSelectedRows);
+		autoNUMvector <double> x (1, numberOfSelectedRows);
 		for (long i = 1; i <= numberOfSelectedRows; i++) {
 			x[i] = Table_getNumericValue_Assert (me, selectedRows[i], column);
 		}
@@ -4544,7 +4548,7 @@ autoTable Table_extractRowsWhere (Table me, const char32 *formula, Interpreter i
 			thy columnHeaders [icol]. label = newLabel.transfer();
 		}
 		for (long irow = 1; irow <= my rows.size; irow ++) {
-			struct Formula_Result result;
+			Formula_Result result;
 			Formula_run (irow, 1, & result);
 			if (result.result.numericResult != 0.0) {
 				TableRow row = my rows.at [irow];
@@ -4563,23 +4567,23 @@ autoTable Table_extractRowsWhere (Table me, const char32 *formula, Interpreter i
 
 static autoTableOfReal Table_to_TableOfReal_where (Table me, const char32 *columnLabels, const char32 *factorColumn, const char32 *formula, Interpreter interpreter) {
 	try {
-		long numberOfColumns, numberOfSelectedRows = 0;
-		long factorColIndex = Table_findColumnIndexFromColumnLabel (me, factorColumn);
-		autoNUMvector<long> columnIndex (Table_getColumnIndicesFromColumnLabelString (me, columnLabels, &numberOfColumns), 1);
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);
+		integer numberOfColumns, numberOfSelectedRows = 0;
+		integer factorColIndex = Table_findColumnIndexFromColumnLabel (me, factorColumn);
+		autoNUMvector <integer> columnIndex (Table_getColumnIndicesFromColumnLabelString (me, columnLabels, & numberOfColumns), 1);
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
 		autoTableOfReal thee = TableOfReal_create (numberOfSelectedRows, numberOfColumns);
-		for (long i = 1; i <= numberOfSelectedRows; i++) {
-			for (long icol = 1; icol <= numberOfColumns; icol++) {
-				double value = Table_getNumericValue_Assert (me, selectedRows[i], columnIndex[icol]);
-				thy data[i][icol] = value;
+		for (integer i = 1; i <= numberOfSelectedRows; i++) {
+			for (integer icol = 1; icol <= numberOfColumns; icol++) {
+				double value = Table_getNumericValue_Assert (me, selectedRows [i], columnIndex [icol]);
+				thy data [i] [icol] = value;
 			}
 			if (factorColIndex > 0) { // if no factorColumn given labels may be empty
-				const char32 *label = Table_getStringValue_Assert (me, selectedRows[i], factorColIndex);
+				const char32 *label = Table_getStringValue_Assert (me, selectedRows [i], factorColIndex);
 				TableOfReal_setRowLabel (thee.get(), i, label);
 			}
 		}
-		for (long icol = 1; icol <= numberOfColumns; icol++) {
-			TableOfReal_setColumnLabel (thee.get(), icol, my columnHeaders [columnIndex[icol]].label);
+		for (integer icol = 1; icol <= numberOfColumns; icol++) {
+			TableOfReal_setColumnLabel (thee.get(), icol, my columnHeaders [columnIndex [icol]]. label);
 		}
 		return thee;
 	} catch (MelderError) {
@@ -4608,20 +4612,20 @@ static long SSCPList_findIndexOfGroupLabel (SSCPList me, const char32 *label) {
 
 static autoTable Table_and_SSCPList_extractMahalanobisWhere (Table me, SSCPList thee, double numberOfSigmas, int which_Melder_NUMBER, const char32 *factorColumn, const char32 *formula, Interpreter interpreter) {
 	try {
-		long numberOfGroups = thy size;
+		integer numberOfGroups = thy size;
 		Melder_assert (numberOfGroups > 0);
 
 		SSCP sscp = thy at [1];
-		long numberOfColumns = sscp -> numberOfColumns, numberOfSelectedRows = 0;
-		long factorColIndex = Table_findColumnIndexFromColumnLabel (me, factorColumn); // can be absent
-		autoNUMvector<long> columnIndex (1, numberOfColumns);
-		autoNUMvector<double> vector (1, numberOfColumns);
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
-		for (long icol = 1; icol <= numberOfColumns; icol++) {
-			columnIndex[icol] = Table_getColumnIndexFromColumnLabel (me, sscp -> columnLabels[icol]); // throw if not present
+		integer numberOfColumns = sscp -> numberOfColumns, numberOfSelectedRows = 0;
+		integer factorColIndex = Table_findColumnIndexFromColumnLabel (me, factorColumn);   // can be absent
+		autoNUMvector <integer> columnIndex (1, numberOfColumns);
+		autoNUMvector <double> vector (1, numberOfColumns);
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
+		for (integer icol = 1; icol <= numberOfColumns; icol ++) {
+			columnIndex [icol] = Table_getColumnIndexFromColumnLabel (me, sscp -> columnLabels [icol]);   // throw if not present
 		}
 		autoTable him = Table_create (0, my numberOfColumns);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			autostring32 newLabel = Melder_dup (my columnHeaders[icol].label);
 			his columnHeaders[icol].label = newLabel.transfer();
 		}
@@ -4670,14 +4674,15 @@ autoTable Table_extractMahalanobisWhere(Table me, const char32 *columnLabels, co
 
 void Table_drawEllipsesWhere (Table me, Graphics g, long xcolumn, long ycolumn, long factorColumn, double xmin, double xmax, double ymin, double ymax, double numberOfSigmas, long labelSize, bool garnish, const char32 *formula, Interpreter interpreter) {
 	try {
-		long numberOfSelectedRows = 0;
-		autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);	
+		integer numberOfSelectedRows = 0;
+		autoNUMvector <integer> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, & numberOfSelectedRows), 1);
 		autoTableOfReal thee = TableOfReal_create (numberOfSelectedRows, 2);
-		for (long i = 1; i <= numberOfSelectedRows; i++) {
-			double x = Table_getNumericValue_Assert (me, selectedRows[i], xcolumn);
-			double y = Table_getNumericValue_Assert (me, selectedRows[i], ycolumn);
-			const char32 *label = Table_getStringValue_Assert (me, selectedRows[i], factorColumn);
-			thy data[i][1] = x; thy data[i][2] = y;
+		for (integer i = 1; i <= numberOfSelectedRows; i++) {
+			double x = Table_getNumericValue_Assert (me, selectedRows [i], xcolumn);
+			double y = Table_getNumericValue_Assert (me, selectedRows [i], ycolumn);
+			const char32 *label = Table_getStringValue_Assert (me, selectedRows [i], factorColumn);
+			thy data [i] [1] = x;
+			thy data [i] [2] = y;
 			TableOfReal_setRowLabel (thee.get(), i, label);
 		}
 		autoSSCPList him = TableOfReal_to_SSCPList_byLabel (thee.get());
@@ -4712,7 +4717,7 @@ void Table_drawEllipsesWhere (Table me, Graphics g, long xcolumn, long ycolumn,
 	}
 }
 
-autoTable Table_extractColumnRanges (Table me, char32 *ranges) {
+autoTable Table_extractColumnRanges (Table me, const char32 *ranges) {
 	try {
 		long numberOfSelectedColumns, numberOfRows = my rows.size;
 		autoNUMvector<long> columnRanges (NUMstring_getElementsOfRanges (ranges, my numberOfColumns, & numberOfSelectedColumns, nullptr, U"columnn number", true), 1);
diff --git a/dwtools/Table_extensions.h b/dwtools/Table_extensions.h
index 3a866b8..2428e26 100644
--- a/dwtools/Table_extensions.h
+++ b/dwtools/Table_extensions.h
@@ -32,7 +32,7 @@
 
 long Table_getNumberOfRowsWhere (Table me, const char32 *formula, Interpreter interpreter);
 
-long *Table_findRowsMatchingCriterion (Table me, const char32 *formula, Interpreter interpreter, long *numberOfMatches);
+integer *Table_findRowsMatchingCriterion (Table me, const char32 *formula, Interpreter interpreter, integer *numberOfMatches);
 
 autoTable Table_create_petersonBarney1952 ();
 
@@ -67,11 +67,11 @@ void Table_quantileQuantilePlot_betweenLevels (Table me, Graphics g, long dataCo
 
 void Table_boxPlots (Table me, Graphics g, long dataColumn, long factorColumn, double ymin, double ymax, bool garnish);
 
-void Table_boxPlotsWhere (Table me, Graphics g, char32 *dataColumns_string, long factorColumn, double ymin, double ymax, bool garnish, const char32 *formula, Interpreter interpreter);
+void Table_boxPlotsWhere (Table me, Graphics g, const char32 *dataColumns_string, long factorColumn, double ymin, double ymax, bool garnish, const char32 *formula, Interpreter interpreter);
 
 autoTable Table_extractRowsWhere (Table me, const char32 *formula, Interpreter interpreter);
 
-autoTable Table_extractColumnRanges (Table me, char32 *ranges);
+autoTable Table_extractColumnRanges (Table me, const char32 *ranges);
 
 autoTable Table_extractMahalanobisWhere (Table me, const char32 *columnLabels, const char32 *factorColumn, double numberOfSigmas, int which_Melder_NUMBER, const char32 *formula, Interpreter interpreter);
 
diff --git a/dwtools/TextGrid_and_PitchTier.cpp b/dwtools/TextGrid_and_PitchTier.cpp
new file mode 100644
index 0000000..87fff63
--- /dev/null
+++ b/dwtools/TextGrid_and_PitchTier.cpp
@@ -0,0 +1,337 @@
+/* TextGrid_and_PitchTier.cpp
+ *
+ * Copyright (C) 2017 David Weenink
+ *
+ * This code 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.
+ *
+ * This code is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this work. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Interpreter.h"
+#include "NUM2.h"
+#include "Strings_extensions.h"
+#include "TextGrid_and_PitchTier.h"
+#include "Thing.h"
+
+
+#define TIME_OFFSET_AS_FRACTION_FROM_START 1
+#define TIME_OFFSET_AS_PERCENTAGE_FROM_START 2
+#define TIME_OFFSET_AS_SECONDS_FROM_START 3
+
+#define PITCH_VALUE_AS_FREQUENCY 1
+#define PITCH_VALUE_AS_FRACTION 2
+#define PITCH_VALUE_AS_PERCENTAGE 3
+#define PITCH_VALUE_AS_START_AND_SLOPES 4
+#define PITCH_VALUE_AS_SLOPES_AND_END 5
+#define PITCH_VALUE_AS_MUSIC_NOTE 6
+#define PITCH_VALUE_AS_SEMITONES 7
+
+#define PITCH_UNIT_HERTZ 1
+
+#define PITCH_ANCHOR_IS_NOT_USED 1
+#define PITCH_ANCHOR_IS_CURRENT 2
+#define PITCH_ANCHOR_IS_START 3
+#define PITCH_ANCHOR_IS_END 4
+#define PITCH_ANCHOR_IS_MEAN_OF_CURVE 5
+#define PITCH_ANCHOR_IS_MEAN_OF_POINTS 6
+#define PITCH_ANCHOR_IS_MAXIMUM 7
+#define PITCH_ANCHOR_IS_MINIMUM 8
+
+static real RealTier_getMinimumValue_interval (RealTier me, real tmin, real tmax) {
+	integer imin, imax;
+	(void) AnyTier_getWindowPoints ((AnyTier) me, tmin, tmax, & imin, & imax);
+	real result = undefined;
+	for (integer i = imin; i <= imax; i ++) {
+		RealPoint point = my points.at [i];
+		if (isundef (result) || point -> value < result) {
+			result = point -> value;
+		}
+	}
+	return result;
+}
+
+static real RealTier_getMaximumValue_interval (RealTier me, real tmin, real tmax) {
+	integer imin, imax;
+	(void) AnyTier_getWindowPoints ((AnyTier) me, tmin, tmax, & imin, & imax);
+	real result = undefined;
+	for (integer i = imin; i <= imax; i ++) {
+		RealPoint point = my points.at [i];
+		if (isundef (result) || point -> value > result) {
+			result = point -> value;
+		}
+	}
+	return result;
+}
+
+static autoPitchTier PitchTier_createFromPoints (double xmin, double xmax, double *times, double *pitches, integer numberOfTimes) {
+	try {
+		autoPitchTier me = PitchTier_create (xmin, xmax);
+		for (integer i = 1; i <= numberOfTimes; i ++) {
+			RealTier_addPoint (me.get(), times[i], pitches [i]);
+		}
+		return me;
+	} catch (MelderError) {
+		Melder_throw (U"No PitchTier created from points.");
+	} 
+}
+
+static double * getTimesFromString (double tmin, double tmax, const char32 *times_string, int time_offset, integer *numberOfTimes) {
+	autoNUMvector<double> times (NUMstring_to_numbers (times_string, numberOfTimes), 1);
+	/*
+		translate the "times" to real time
+	*/
+	for (integer i = 1; i <= *numberOfTimes; i ++) {
+		if (time_offset == TIME_OFFSET_AS_FRACTION_FROM_START) {
+			times [i] = tmin + times [i] * (tmax - tmin);
+		} else if (time_offset == TIME_OFFSET_AS_PERCENTAGE_FROM_START) {
+			times [i] = tmin + times [i] * (tmax - tmin) * 0.01;
+		} else if (time_offset == TIME_OFFSET_AS_SECONDS_FROM_START) {
+			times [i] = tmin + times [i];
+		} else {
+			// we should not be here
+		}
+	}
+	return times.transfer();
+}
+
+/*
+	a1, a#1, b1,b#1, ... g#1, a2, b2, a#1,b#2, a a# b c c# d d# e f f# g g#
+*/
+static double note_to_frequency (const char32 *token, double a4) {
+	double base = a4 / 8.0;
+	integer octave, index;
+	const char32 note = *token++, char2 = *token++;
+	if (note == U'a' || note == U'A') {
+		index = 1;
+	} else if (note == U'b' || note == U'B') {
+		index = 3;
+	} else if (note == U'c' || note == U'C') {
+		index = 4;
+	} else if (note == U'd' || note == U'D') {
+		index = 6;
+	} else if (note == U'e' || note == U'E') {
+		index = 8;
+	} else if (note == U'f' || note == U'F') {
+		index = 9;
+	} else if (note == U'g' || note == U'G') {
+		index = 10;
+	} else {
+		return undefined;
+	}
+	char32 char3;
+	if (char2 == U'#') {
+		index ++;
+		char3 = *token++;
+	} else {
+		char3 = char2;
+	}
+
+	if (char3 >= U'0' && char3 <= U'9') {
+		octave = char3 - U'0';
+	} else {
+		return undefined;
+	}
+	double frequency = base * pow (2, octave - 1.0 + (index - 1.0) / 12.0);
+	return frequency;
+}
+
+static autoPitchTier PitchTier_extractModifiedInterval (PitchTier me, double tmin, double tmax, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitchAnchor_status) {
+	(void) pitch_unit;
+	try {
+		if (tmin >= tmax) {
+			tmin = my xmin; tmax = my xmax;
+		}
+		
+		if (((pitch_as == PITCH_VALUE_AS_FRACTION) || (pitch_as == PITCH_VALUE_AS_PERCENTAGE)) && 
+			pitchAnchor_status == PITCH_ANCHOR_IS_NOT_USED) {
+			Melder_throw (U"You need to specify an anchor value to calculate ", (pitch_as == PITCH_VALUE_AS_FRACTION ? U"fractions" : U"percentages"), U".");
+		}
+		
+		integer numberOfTimes;
+		autoNUMvector<double> times (getTimesFromString (tmin, tmax, times_string, time_offset, & numberOfTimes), 1);
+		
+		autoStrings items = Strings_createAsTokens (pitches_string, U" ");
+		integer numberOfPitches = items -> numberOfStrings;
+		if (numberOfTimes != numberOfPitches) {
+			Melder_throw (U"The number of items in the times and the pitches string have to be equal.");
+		}
+		autoNUMvector<double> pitchesraw (1, numberOfPitches);
+		for (integer i = 1; i <= numberOfPitches; i ++) {
+			const char32 *token = items -> strings [i];
+			if (pitch_as == PITCH_VALUE_AS_MUSIC_NOTE) {
+				pitchesraw [i] = note_to_frequency (token, 440.0);
+			} else {
+				Interpreter_numericExpression (0, token, & pitchesraw [i]);
+			}
+		}
+		
+		// now we have the real times and we can sort them tohether with the pitches
+		
+		autoNUMvector<double> pitches (1, numberOfTimes);
+		NUMvector_copyElements<double> (pitchesraw.peek(), pitches.peek(), 1, numberOfPitches);
+		NUMsort2<double, double> (numberOfTimes, times.peek(), pitches.peek());
+		double pitchAnchor, pitch;
+		for (integer i = 1; i <= numberOfTimes; i ++) {
+			integer index = pitch_as != PITCH_VALUE_AS_SLOPES_AND_END ? i : numberOfTimes - i + 1;
+			double time = times [index];
+			if (pitchAnchor_status == PITCH_ANCHOR_IS_NOT_USED) {
+				pitchAnchor = undefined;
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_CURRENT) {
+				pitchAnchor = RealTier_getValueAtTime (me, time);
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_START) {
+				pitchAnchor = i == 1 ? RealTier_getValueAtTime (me, tmin) : pitchAnchor;
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_END) {
+				pitchAnchor = i == 1 ? RealTier_getValueAtTime (me, tmax) : pitchAnchor;
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_MEAN_OF_CURVE) {
+				pitchAnchor = i == 1 ? RealTier_getMean_curve (me, tmin, tmax) : pitchAnchor;
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_MEAN_OF_POINTS) {
+				pitchAnchor = i == 1 ? RealTier_getMean_points (me, tmin, tmax) : pitchAnchor;
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_MAXIMUM) {
+				pitchAnchor = i == 1 ? RealTier_getMaximumValue_interval (me, tmin, tmax) : pitchAnchor;
+			} else if (pitchAnchor_status == PITCH_ANCHOR_IS_MINIMUM) {
+				pitchAnchor = i == 1 ? RealTier_getMinimumValue_interval (me, tmin, tmax) : pitchAnchor;
+			} else {
+				// we should not be here
+			}
+			
+			if (isundef (pitchAnchor) && (pitchAnchor_status != PITCH_ANCHOR_IS_NOT_USED)) {
+				Melder_throw (U"The pitch anchor value is undefined because the PitchTier is empty.");
+			}
+			
+			/*
+				How to interpret the "pitch" value
+			*/
+			
+			if (pitch_as == PITCH_VALUE_AS_FREQUENCY) {
+				pitch = pitches [i];
+			} else if (pitch_as == PITCH_VALUE_AS_FRACTION) {
+				pitch = pitchAnchor * (1.0 + pitches [i]);
+			} else if (pitch_as == PITCH_VALUE_AS_PERCENTAGE) {
+				pitch = pitchAnchor * (1.0 + pitches [i] * 0.01);
+			} else if (pitch_as == PITCH_VALUE_AS_START_AND_SLOPES) {
+				if (i == 1) {
+					pitch = pitchAnchor;
+				} else {
+					pitch += (times [i] - times [i - 1]) * pitches [i];
+				}
+			} else if (pitch_as == PITCH_VALUE_AS_SLOPES_AND_END) {
+				if (i == 1) {
+					pitch = pitchAnchor;
+				} else {
+					pitch -= (times [index + 1] - times [index]) * pitches [index];
+				}
+			} else if (pitch_as == PITCH_VALUE_AS_MUSIC_NOTE) {
+				pitch = pitches [i];
+			} else if (pitch_as == PITCH_VALUE_AS_SEMITONES) {
+				pitch = NUMsemitonesToHertz (pitches [i]);
+			} else {
+				// we should not be here
+			}
+			pitches [index] = pitch;
+		}
+		
+		/*
+			Remove old points
+		*/
+		
+		autoPitchTier thee = PitchTier_createFromPoints (times [1], times [numberOfTimes], times.peek(), pitches.peek(), numberOfTimes);
+		
+		return thee;
+	} catch (MelderError) {
+		Melder_throw (me, U": no modified PitchTier created.");
+	}
+}
+
+static void PitchTiers_replacePoints (PitchTier me, PitchTier thee) {
+	AnyTier_removePointsBetween ((AnyTier) me, thy xmin, thy xmax);
+	for (integer i = 1; i <= thy points.size; i ++) {
+		RealPoint pp = thy points.at [i];
+		RealTier_addPoint (me, pp -> number, pp -> value);
+	}
+}
+
+void PitchTier_modifyInterval (PitchTier me, double tmin, double tmax, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitchAnchor_status) {
+	try {
+		autoPitchTier thee = PitchTier_extractModifiedInterval (me, tmin, tmax, times_string, time_offset, pitches_string, pitch_unit, pitch_as, pitchAnchor_status);
+		PitchTiers_replacePoints (me, thee.get());
+	} catch (MelderError) {
+		Melder_throw (me, U": interval modification not completed.");
+	}
+}
+
+
+autoPitchTier IntervalTier_and_PitchTier_to_PitchTier (IntervalTier me, PitchTier thee, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitchAnchor_status, int which_Melder_STRING, const char32 *criterion) {
+	try {
+		autoPitchTier him = Data_copy (thee);
+		for (integer i = 1; i <= my intervals.size; i ++) {
+			TextInterval segment = my intervals.at [i];
+			if (Melder_stringMatchesCriterion (segment -> text, which_Melder_STRING, criterion)) {
+				double xmin = segment -> xmin, xmax = segment -> xmax;
+				autoPitchTier modified = PitchTier_extractModifiedInterval (thee, xmin, xmax, times_string, time_offset, pitches_string, pitch_unit, pitch_as, pitchAnchor_status);
+				PitchTiers_replacePoints (him.get(), modified.get());
+			}
+		}
+		return him;
+	} catch (MelderError) {
+		Melder_throw (me, U": cannot create PitchTier.");
+	}
+}
+
+autoPitchTier TextGrid_and_PitchTier_to_PitchTier (TextGrid me, PitchTier thee, integer tierNumber, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitchAnchor_status, int which_Melder_STRING, const char32 *criterion) {
+	try {
+		IntervalTier tier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
+		return IntervalTier_and_PitchTier_to_PitchTier (tier, thee, times_string, time_offset, pitches_string, pitch_unit, pitch_as, pitchAnchor_status, which_Melder_STRING, criterion);
+	} catch (MelderError) {
+		Melder_throw (me, U": cannot create PitchTier.");
+	}
+}
+
+/* 
+	We specify pitches as tone levels (1 - numberOfToneLevels). These levels are relative to the pitch range of a speaker.
+	(normally in Mandarin Chinese they count 5 levels).
+*/
+static autoPitchTier PitchTier_extractModifiedInterval_toneLevels (PitchTier me, double tmin, double tmax, double fmin, double fmax, integer numberOfToneLevels, const char32 *times_string, int time_offset, const char32 *pitches_string) {
+	try {
+		if (tmin >= tmax) {
+			tmin = my xmin; tmax = my xmax;
+		}
+		if (fmin >= fmax) {
+			Melder_throw (U"The lowest frequency must be lower than the highest frequency.");
+		}
+		integer numberOfTimes, numberOfPitches;
+		autoNUMvector<double> times (getTimesFromString (tmin, tmax, times_string, time_offset, & numberOfTimes), 1);
+		autoNUMvector<double> pitches (NUMstring_to_numbers (pitches_string, & numberOfPitches), 1);
+		if (numberOfTimes != numberOfPitches) {
+			Melder_throw (U"The number of items in the times and the pitches string have to be equal.");
+		}
+		double scale = log10 (fmax / fmin) / numberOfToneLevels;
+		for (integer i = 1; i <= numberOfPitches; i ++) {
+			pitches [i] = fmin * pow (10.0, scale * pitches [i]);
+		}
+		NUMsort2<double, double> (numberOfTimes, times.peek(), pitches.peek());
+		autoPitchTier thee = PitchTier_createFromPoints (times [1], times [numberOfTimes], times.peek(), pitches.peek(), numberOfTimes);
+		return thee;
+	} catch (MelderError) {
+		Melder_throw (me, U": interval modification not succeeded.");
+	}
+}
+
+void PitchTier_modifyInterval_toneLevels (PitchTier me, double tmin, double tmax, double fmin, double fmax, integer numberOfToneLevels, const char32 *times_string, int time_offset, const char32 *pitches_string) {
+	try {
+		autoPitchTier thee = PitchTier_extractModifiedInterval_toneLevels (me, tmin, tmax, fmin, fmax, numberOfToneLevels, times_string, time_offset, pitches_string);
+		PitchTiers_replacePoints (me, thee.get());
+	} catch (MelderError) {
+		Melder_throw (me, U": interval modification as tone levels not succeeded.");
+	}	
+}
+
+/* End of file TextGrid_and_PitchTier.cpp */
diff --git a/dwtools/TextGrid_and_PitchTier.h b/dwtools/TextGrid_and_PitchTier.h
new file mode 100644
index 0000000..81310bf
--- /dev/null
+++ b/dwtools/TextGrid_and_PitchTier.h
@@ -0,0 +1,32 @@
+#ifndef _TextGrid_and_PitchTier_h_
+#define _TextGrid_and_PitchTier_h_
+/* TextGrid_and_PitchTier.h
+ *
+ * Copyright (C) 2017 David Weenink
+ *
+ * This code 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.
+ *
+ * This code is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this work. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TextGrid.h"
+#include "PitchTier.h"
+
+void PitchTier_modifyInterval (PitchTier me, double tmin, double tmax, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitch_is);
+
+void PitchTier_modifyInterval_toneLevels (PitchTier me, double tmin, double tmax, double fmin, double fmax, integer numberOfToneLevels, const char32 *times_string, int time_offset, const char32 *pitches_string);
+
+autoPitchTier IntervalTier_and_PitchTier_to_PitchTier (IntervalTier me, PitchTier thee, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitchAnchor_status, int which_Melder_STRING, const char32 *criterion);
+
+autoPitchTier TextGrid_and_PitchTier_to_PitchTier (TextGrid me, integer tierNumber, const char32 *times_string, int time_offset, const char32 *pitches_string, int pitch_unit, int pitch_as, int pitchAnchor_status, int which_Melder_STRING, const char32 *criterion);
+
+#endif
diff --git a/dwtools/TextGrid_extensions.cpp b/dwtools/TextGrid_extensions.cpp
index 815b4ca..66c6e71 100644
--- a/dwtools/TextGrid_extensions.cpp
+++ b/dwtools/TextGrid_extensions.cpp
@@ -505,7 +505,9 @@ void TextGrid_setTierName (TextGrid me, long itier, const char32 *newName) {
 static void IntervalTier_cutInterval (IntervalTier me, long index, int extend_option) {
 	long size_pre = my intervals.size;
 
-	// There always must be at least one interval
+	/*
+	 * There always must be at least one interval
+	 */
 	if (size_pre == 1 || index > size_pre || index < 1) {
 		return;
 	}
@@ -515,20 +517,28 @@ static void IntervalTier_cutInterval (IntervalTier me, long index, int extend_op
 	double xmax = ti -> xmax;
 	my intervals. removeItem (index);
 	if (index == 1) { 
-		// Change xmin of the new first interval.
+		/*
+		 * Change xmin of the new first interval.
+		 */
 		ti = my intervals.at [index];
 		ti -> xmin = xmin;
 	} else if (index == size_pre) { 
-		// Change xmax of the new last interval.
+		/*
+		 * Change xmax of the new last interval.
+		 */
 		ti = my intervals.at [my intervals.size];
 		ti -> xmax = xmax;
 	} else {
 		if (extend_option == 0) { 
-			// extend earlier interval to the right
+			/*
+			 * Extend earlier interval to the right
+			 */
 			ti = my intervals.at [index - 1];
 			ti -> xmax = xmax;
 		} else {
-			// extend next interval to the left
+			/*
+			 * Extend next interval to the left
+			 */
 			ti = my intervals.at [index];
 			ti -> xmin = xmin;
 		}
@@ -726,7 +736,7 @@ void TextTiers_append_inline (TextTier me, TextTier thee, bool preserveTimes) {
 	try {
 		for (long iint = 1; iint <= thy points.size; iint ++) {
 			autoTextPoint tp = Data_copy (thy points.at [iint]);
-			if (not preserveTimes) {
+			if (! preserveTimes) {
 				tp -> number += my xmax - thy xmin;
 			}
 			my points. addItem_move (tp.move());
@@ -808,12 +818,16 @@ autoTextGrid TextGrids_to_TextGrid_appendContinuous (OrderedOf<structTextGrid>*
 	}
 }
 
-void NUMshift (double *x, double dx) {
+static void NUMshift (double *x, double dx) {   // TODO: make global
 	*x += dx;
 }
 
-autoIntervalTier IntervalTier_shiftBoundaries (IntervalTier me, double startTime, double shiftTime) {
-	
+static autoIntervalTier IntervalTier_shiftBoundaries (IntervalTier me, double startTime, double shiftTime) {   // TODO: make global
+	autoIntervalTier result;   // TODO: implement
+	(void) me;   // TODO: use
+	(void) startTime;   // TODO: use
+	(void) shiftTime;   // TODO: use
+	return result;
 }
 
 /* End of file TextGrid_extensions.cpp */
diff --git a/dwtools/VowelEditor.cpp b/dwtools/VowelEditor.cpp
index 93f724e..dc81f36 100644
--- a/dwtools/VowelEditor.cpp
+++ b/dwtools/VowelEditor.cpp
@@ -255,18 +255,19 @@ static void VowelEditor_getF1F2FromXY (VowelEditor me, double x, double y, doubl
 	*f1 = my f1min * pow (my f1max / my f1min, 1.0 - y);
 }
 
-#define REPRESENTNUMBER(x,i) (((x) == NUMundefined) ? U" undef" : Melder_pad (6, Melder_fixed (x, 1)))
+#define REPRESENTNUMBER(x,i) (isundef (x) ? U" undef" : Melder_pad (6, Melder_fixed (x, 1)))
 static void appendF1F2F0 (MelderString *statusInfo, const char32 *intro, double f1, double f2, double f0, const char32 *ending) {
 	MelderString_append (statusInfo, intro, REPRESENTNUMBER (f1, 1), U", ", REPRESENTNUMBER (f2, 2), U", ", REPRESENTNUMBER (f0, 3), ending);
 }
 
 static double getRealFromTextWidget (GuiText me) {
-	double value = NUMundefined;
+	double value = undefined;
 	char32 *dirty = GuiText_getString (me);
 	try {
 		Interpreter_numericExpression (nullptr, dirty, & value);
 	} catch (MelderError) {
-		Melder_clearError (); value = NUMundefined;
+		Melder_clearError ();
+		value = undefined;
 	}
 	Melder_free (dirty);
 	return value;
@@ -288,7 +289,7 @@ static void checkF1F2 (VowelEditor me, double *f1, double *f2) {
 }
 
 static void checkF0 (structVowelEditor_F0 *f0p, double *f0) {
-	if (! NUMdefined (*f0)) {
+	if (isundef (*f0)) {
 		*f0 = f0p -> start;
 	}
 	if (*f0 > f0p -> maximum) {
@@ -325,11 +326,11 @@ static void VowelEditor_getF3F4 (VowelEditor me, double f1, double f2, double *f
 
 static void VowelEditor_updateF0Info (VowelEditor me) {
 	double f0 = getRealFromTextWidget (my f0TextField);
-	checkF0 (&my f0, &f0);
+	checkF0 (& my f0, & f0);
 	GuiText_setString (my f0TextField, Melder_double (f0));
 	my f0.start = f0;
 	double slopeOctPerSec = getRealFromTextWidget (my f0SlopeTextField);
-	if (! NUMdefined (slopeOctPerSec)) {
+	if (isundef (slopeOctPerSec)) {
 		slopeOctPerSec = f0default.slopeOctPerSec;
 	}
 	my f0.slopeOctPerSec = slopeOctPerSec;
@@ -338,7 +339,7 @@ static void VowelEditor_updateF0Info (VowelEditor me) {
 
 static void VowelEditor_updateExtendDuration (VowelEditor me) {
 	double extend = getRealFromTextWidget (my extendTextField);
-	if (! NUMdefined (extend) || extend <= MINIMUM_SOUND_DURATION || extend > my maximumDuration) {
+	if (isundef (extend) || extend <= MINIMUM_SOUND_DURATION || extend > my maximumDuration) {
 		extend = MINIMUM_SOUND_DURATION;
 	}
 	GuiText_setString (my extendTextField, Melder_double (extend));
@@ -347,20 +348,20 @@ static void VowelEditor_updateExtendDuration (VowelEditor me) {
 
 static double VowelEditor_updateDurationInfo (VowelEditor me) {
 	double duration = getRealFromTextWidget (my durationTextField);
-	if (! NUMdefined (duration) || duration < MINIMUM_SOUND_DURATION) {
+	if (isundef (duration) || duration < MINIMUM_SOUND_DURATION) {
 		duration = MINIMUM_SOUND_DURATION;
 	}
 	GuiText_setString (my durationTextField, Melder_double (MICROSECPRECISION (duration)));
 	return duration;
 }
 
-static void Sound_fadeIn (Sound me, double duration, int fromFirstNonZeroSample) {
+static void Sound_fadeIn (Sound me, double duration, bool fromFirstNonZeroSample) {
 	long istart = 1, numberOfSamples = (long) floor (duration / my dx);   // ppgb: waarom afronden naar beneden?
 
 	if (numberOfSamples < 2) {
 		return;
 	}
-	if (fromFirstNonZeroSample != 0) {
+	if (fromFirstNonZeroSample) {
 		// If the first part of the sound is very low level we put sample values to zero and
 		// start windowing from the position where the amplitude is above the minimum level.
 		// WARNING: this part is special for the artificial vowels because
@@ -438,7 +439,7 @@ static void VowelEditor_shiftF1F2 (VowelEditor me, double f1_st, double f2_st) {
 		FormantPoint fp = ft -> points.at [i];
 		double f1 = fp -> formant [0], f2 = fp -> formant [1];
 
-		f1 *= pow (2, f1_st / 12);
+		f1 *= pow (2, f1_st / 12.0);
 		if (f1 < my f1min) {
 			f1 = my f1min;
 		}
@@ -446,9 +447,9 @@ static void VowelEditor_shiftF1F2 (VowelEditor me, double f1_st, double f2_st) {
 			f1 = my f1max;
 		}
 		fp -> formant[0] = f1;
-		fp -> bandwidth[0] = f1 / 10;
+		fp -> bandwidth[0] = f1 / 10.0;
 
-		f2 *= pow (2, f2_st / 12);
+		f2 *= pow (2, f2_st / 12.0);
 		if (f2 < my f2min) {
 			f2 = my f2min;
 		}
@@ -456,7 +457,7 @@ static void VowelEditor_shiftF1F2 (VowelEditor me, double f1_st, double f2_st) {
 			f2 = my f2max;
 		}
 		fp -> formant[1] = f2;
-		fp -> bandwidth[1] = f2 / 10;
+		fp -> bandwidth[1] = f2 / 10.0;
 		double f3, b3, f4, b4;
 		VowelEditor_getF3F4 (me, f1, f2, &f3, &b3, &f4, &b4);
 		fp -> formant[2] = f3;
@@ -513,7 +514,7 @@ static autoSound VowelEditor_createTarget (VowelEditor me) {
 		VowelEditor_updateVowel (me);   // update pitch and duration
 		autoSound thee = Vowel_to_Sound_pulses (my vowel.get(), 44100.0, 0.7, 0.05, 30);
 		Vector_scale (thee.get(), 0.99);
-		Sound_fadeIn (thee.get(), 0.005, 1);
+		Sound_fadeIn (thee.get(), 0.005, true);
 		Sound_fadeOut (thee.get(), 0.005);
 		return thee;
 	} catch (MelderError) {
@@ -624,7 +625,7 @@ static void copyVowelMarksInPreferences_volatile (Table me) {
 		long col_f2 = Table_getColumnIndexFromColumnLabel (me, U"F2");
 		long col_size = Table_getColumnIndexFromColumnLabel (me, U"Size");
 		autoMelderString mark;
-		for (long i = 1; i <= VowelEditor_MAXIMUM_MARKERS; i++) {
+		for (long i = 1; i <= VowelEditor_MAXIMUM_MARKERS; i ++) {
 			if (i <= numberOfRows) {
 				MelderString_copy (&mark, Table_getStringValue_Assert (me, i, col_vowel), U"\t",
 					Table_getStringValue_Assert (me, i, col_f1), U"\t",
@@ -634,9 +635,9 @@ static void copyVowelMarksInPreferences_volatile (Table me) {
 				if (length >= Preferences_STRING_BUFFER_SIZE) {
 					Melder_throw (U"Preference mark ", i, U" contains too many characters");
 				}
-				str32cpy (prefs.mark[i-1], mark.string);
+				str32cpy (prefs.mark [i - 1], mark.string);
 			} else {
-				str32cpy (prefs.mark[i-1], U"x");
+				str32cpy (prefs.mark [i - 1], U"x");
 			}
 		}
 	}
@@ -687,15 +688,15 @@ static void VowelEditor_createTableFromVowelMarksInPreferences (VowelEditor me)
 	try {
 		autoTable newMarks = Table_createWithColumnNames (0, U"Vowel F1 F2 Size");
 		long nmarksFound = 0;
-		for (long i = 1; i <= numberOfRows; i++) {
-			autoMelderTokens rowi (prefs.mark[i-1]);
+		for (long i = 1; i <= numberOfRows; i ++) {
+			autoMelderTokens rowi (prefs.mark [i - 1]);
 			long numberOfTokens = rowi.count();
 			if (numberOfTokens < 4) { // we are done
 				break;
 			}
 			Table_appendRow (newMarks.get());
-			for (long j = 1; j <= 4; j++) {
-				Table_setStringValue (newMarks.get(), i, j, rowi[j]);
+			for (long j = 1; j <= 4; j ++) {
+				Table_setStringValue (newMarks.get(), i, j, rowi [j]);
 			}
 			nmarksFound++;
 		}
@@ -800,9 +801,9 @@ static void VowelEditor_drawBackground (VowelEditor me, Graphics g) {
 		VowelEditor_getXYFromF1F2 (me, my f1max, my f1max, &x2, &y2);
 		if (x2 >= 0.0 && x2 <= 1.0) {
 			autoPolygon p = Polygon_create (3);
-			p -> x[1] = x1; p -> y[1] = y1;
-			p -> x[2] = x2; p -> y[2] = y2;
-			p -> x[3] =  1; p -> y[3] =  0;
+			p -> x [1] = x1;    p -> y [1] = y1;
+			p -> x [2] = x2;    p -> y [2] = y2;
+			p -> x [3] = 1.0;   p -> y [3] = 0.0;
 			Graphics_fillArea (g, p -> numberOfPoints, & p -> x[1], & p -> y[1]);
 			// Polygon_paint does not work because of use of Graphics_setInner.
 			Graphics_line (g, x1, y1, x2, y2);
@@ -1176,7 +1177,7 @@ static void gui_button_cb_publish (VowelEditor me, GuiButtonEvent /* event */) {
 
 static void gui_button_cb_reverse (VowelEditor me, GuiButtonEvent /* event */) {
 	VowelEditor_Vowel_reverseFormantTier (me);
-	struct structGuiButtonEvent play_event { 0 };
+	structGuiButtonEvent play_event { };
 	gui_button_cb_play (me, & play_event);
 }
 
@@ -1186,7 +1187,7 @@ static void gui_drawingarea_cb_expose (VowelEditor me, GuiDrawingArea_ExposeEven
 	double ts = my vowel -> xmin, te = my vowel -> xmax;
 	FormantTier ft = my vowel -> ft.get();
 	Melder_assert (ft);
-	static MelderString statusInfo { 0 };
+	static MelderString statusInfo { };
 	if (! my graphics) {
 		return;   // could be the case in the very beginning
 	}
@@ -1307,7 +1308,7 @@ static void gui_drawingarea_cb_click (VowelEditor me, GuiDrawingArea_ClickEvent
 		checkXY (&x, &y);
 		// If the new point equals the previous one: no tier update
 		if (xb == x && yb == y) {
-			iskipped++;
+			iskipped ++;
 			continue;
 		}
 		// Add previous point only if at least one previous event was skipped...
diff --git a/dwtools/manual_dwtools.cpp b/dwtools/manual_dwtools.cpp
index 03aa0ad..10eceec 100644
--- a/dwtools/manual_dwtools.cpp
+++ b/dwtools/manual_dwtools.cpp
@@ -2629,6 +2629,10 @@ NORMAL (U"An object of type MSpline represents a linear combination of basis "
 FORMULA (U"MSpline (%x) = \\Si__%k=1..%numberOfCoefficients_ %c__%k_ %mspline__%k_(%x)")
 MAN_END
 
+MAN_BEGIN (U"pairwise algorithm for computing sample variances", U"djmw", 20170806)
+INTRO (U"An algorithm to compute the mean and the variance of an array of numbers. By pairwise combining array elements, the total number of arithmetic operations is reduced and therefore also the noise due to finite precision arithmetic. The algorithm is described in @@Chan, Golub & LeVeque (1979)@ and a comparison with other algorithms is presented in @@Chan, Golub & LeVeque (1983)@.")
+MAN_END
+
 MAN_BEGIN (U"PatternList", U"djmw", 20160524)
 INTRO (U"One of the @@types of objects@ in P\\s{RAAT}.")
 INTRO (U"An object of type PatternList is a list of patterns that can serve as "
@@ -2812,6 +2816,126 @@ MAN_BEGIN (U"PitchTier: To Pitch...", U"djmw", 20061128)
 INTRO (U"Synthesizes a new @Pitch from the selected @PitchTier.")
 MAN_END
 
+MAN_BEGIN (U"PitchTier: Modify interval...", U"djmw", 20170801)
+INTRO (U"Modifies a selected interval from the chosen @PitchTier by replacing the contents of the interval by newly defined pitch points.")
+ENTRY (U"Settings")
+SCRIPT (5.4, Manual_SETTINGS_WINDOW_HEIGHT (12), U""
+	Manual_DRAW_SETTINGS_WINDOW (U"PitchTier: Modify interval", 12)
+	Manual_DRAW_SETTINGS_WINDOW_RANGE (U"Time range (s)", U"0.0", U"0.0")
+	Manual_DRAW_SETTINGS_WINDOW_FIELD (U"Relative times", U"0.0 0.5 1.0")
+	Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU (U"...are...", U"fractions")
+	"Text... 50 left y half ...of the interval duration which will be added...\n" \
+	"y += 40\n" \
+	"Text... 50 left y half ...to the start time of the interval.\n" \
+	"y += 40\n" \
+	Manual_DRAW_SETTINGS_WINDOW_FIELD (U"The \"pitch\" values", U"100.0 200.0 100.0")
+	Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU (U"...are...", U"frequencies")
+	"Text... 50 left y half ...to be added to the anchor value (if used)...\n" \
+	"y += 40\n" \
+	Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU (U"...which is the...",U"not used")
+	"Text... 50 left y half ...frequency value in the interval...\n" \
+	"y += 40\n" \
+	Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU (U"Pitch frequency unit",U"Hertz")
+)
+TAG (U"##Time range (s)")
+DEFINITION (U"the start and end time of the interval where the changes will be applied.")
+TAG (U"##Relative times")
+DEFINITION (U"determine, together with the following option, the times of the new pitch points with respect to the start time of the interval.")
+TAG (U"##...are...")
+DEFINITION (U"determines how the times %t__%i_ of the new pitch points are calculated. The time of each new pitch point is determined by adding to the start time of the interval a time calculated from the relative time value. If %%t%__min_ and %%t%__max_ are the start and end time of the interval and %%r%__i_ is the %%i%^^th^ relative time, the times %t__%i_ are calculated according to the options as:")
+TAG1 (U"%%fractions%")
+DEFINITION (U"%%t%__%i_ = %t__min_ + %r__%i_ (%t__max_ \\-- %t__min_). The relative time values are fractions of the interval duration. Normally fractions are numbers in the range 0.0 to 1.0, although smaller and larger numbers are allowed.")
+TAG1 (U"%%percentages%")
+DEFINITION (U"%%t%__%i_ = %t__min_+ 0.01 %r__%i_ (%t__max_ \\-- %t__min_). The relative time values are percentages of the interval duration. Normally percentages are numbers in the range 0.0 to 100.0, although smaller and larger numbers are allowed.")
+TAG1 (U"%%independent%")
+DEFINITION (U"%%t%__%i_ = %t__min_ + %r__%i_. The relative time values specify an offset in seconds here. ")
+TAG (U"##The \"pitch\" values")
+DEFINITION (U"determine, together with the next two options, the frequency value of the new pitch points. Each value here must link to the corresponding time value.")
+TAG (U"##...are...")
+DEFINITION (U"determines the interpretation of the \"pitch\" value. Possible choices are")
+TAG1 (U"%%frequencies%")
+DEFINITION (U"the values are frequencies in hertz.")
+TAG1 (U"%%fractions%")
+DEFINITION (U"the values are fractions of a pitch value that is specified by the next option. Normally fractions are numbers in the range 0.0 to 1.0, although smaller and larger numbers are allowed.")
+TAG1 (U"%%percentages%")
+DEFINITION (U"the values are percentages of a pitch value that is specified by the next option. Normally percentages are numbers in the range 0.0 to 100.0, although smaller and larger numbers are allowed.")
+TAG1 (U"%%start and slopes%")
+DEFINITION (U"the values are a start frequency followed by slopes in Herz per second.")
+TAG1 (U"%%slopes and end%")
+DEFINITION (U"the values are slopes in herz per second followed by an end frequency in herz.")
+TAG1 (U"%%music notes%")
+DEFINITION (U"the values are music notes specified on the twelve tone scale as a0, a\\# 0, b0, c0, c\\# 0, d0, d\\# 0, e0, f0, f\\# 0, g0, g\\# 0, a1, a\\# 1, ... a4, ..., or g\\# 9. Here the octave is indicated by the number, 0 being the lowest octave and 9 the highest. The a4 is choosen to be at 440 Hz. Therefore, a0 is the note with the lowest frequency, four octaves below the a4 and corresponds to a frequency of 27.5 Hz. As a scale of reference we give a0 = 27.5 Hz, a1 = 55 Hz, a2 =  [...]
+TAG (U"##...which is the...")
+DEFINITION (U"the anchor point value, if used. The following options may be given for the anchor point frequency value:")
+TAG1 (U"%%not used%")
+DEFINITION (U"no anchor point frequency value is necessary. The previous two options are sufficient to determine the new pitch frequencies. This means that the \"pitch\" values given cannot be %%fractions% or %%percentages%.")
+TAG1 (U"%%current%")
+DEFINITION (U"the current pitch frequency at the corresponding time.")
+TAG1 (U"%%start%")
+DEFINITION (U"the pitch frequency at the start of the interval.")
+TAG1 (U"%%end%")
+DEFINITION (U"the pitch frequency at the end of the interval.")
+TAG1 (U"%%mean of the curve%")
+DEFINITION (U"the @@PitchTier: Get mean (curve)...|mean of the curve@ within the interval.")
+TAG1 (U" %%mean of the points%")
+DEFINITION (U"the @@PitchTier: Get mean (points)...|mean of the points@ within the interval.")
+TAG1 (U"%%maximum%")
+DEFINITION (U"the maximum pitch frequency in the interval.")
+TAG1 (U"%%minimum%")
+DEFINITION (U"the minimum pitch frequency in the interval.")
+TAG (U"##Pitch frequency unit")
+DEFINITION (U"Hertz")
+MAN_END
+
+MAN_BEGIN (U"PitchTier: Modify interval (tone levels)...", U"djmw", 20170801)
+INTRO (U"Modifies a selected interval from the chosen @PitchTier by replacing the contents of the interval by newly defined pitch points.")
+NORMAL (U"For tone languages the pitch contours of the tones are often expressed as a sequence of tone levels instead of a sequence of real frequency values in hertz because tone levels abstract away from the possibly different pitch ranges of individual speakers.")
+NORMAL (U"The tone levels %T are calculated from a given pitch %%frequency% in hertz as:")
+FORMULA (U"%T = %%numberOfToneLevels% \\.c log (%%frequency% / %F__min_) / log (%F__max_ / %F__min_),")
+NORMAL (U"where %F__min_ and %F__max_ are the minimum and the maximum frequency of a speaker's pitch range and %%numberOfToneLevels% is the number of levels into which the pitch range is divided. "
+	"This formula maps any frequency between %F__min_ and %F__max_ to a number between 0 and %%numberOfToneLevels%.")
+NORMAL (U"To get the frequency in hertz from a specified tone level %T we have to use the inverse formula:")
+FORMULA (U"%%frequency% = %F__min_ \\.c 10^^(%T \\.c log (%F__max_ / %F__min_)) / %%numberOfToneLevels%)^.")
+ENTRY (U"Settings")
+SCRIPT (5.4, Manual_SETTINGS_WINDOW_HEIGHT (9), U""
+	Manual_DRAW_SETTINGS_WINDOW (U"PitchTier: Modify interval (tone levels)", 9)
+	Manual_DRAW_SETTINGS_WINDOW_RANGE (U"Time range (s)", U"0.0", U"0.0")
+	Manual_DRAW_SETTINGS_WINDOW_RANGE (U"Pitch range (Hz)", U"80.0", U"200.0")
+	Manual_DRAW_SETTINGS_WINDOW_FIELD (U"Number of tone levels", U"5")
+	Manual_DRAW_SETTINGS_WINDOW_FIELD (U"Relative times", U"0.0 0.5 1.0")
+	Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU (U"...are...",U"fractions")
+	"Text... 50 left y half ...of the interval duration which will be added...\n" \
+	"y += 40\n" \
+	"Text... 50 left y half ...to the start time of the interval.\n" \
+	"y += 40\n" \
+	Manual_DRAW_SETTINGS_WINDOW_FIELD (U"Tone levels", U"2.1 2.1 5.0")
+)
+TAG (U"##Time range (s)")
+DEFINITION (U"the start and end time of the interval where the changes will be applied.")
+TAG (U"##Pitch range (Hz)")
+DEFINITION (U"The minimum and maximum frequency to which the tone levels refer.")
+TAG (U"##Number of tone levels")
+DEFINITION (U"The number of levels into which the pitch range is divided.")
+TAG (U"##Relative times")
+DEFINITION (U"determine, together with the following option, the times of the new pitch points with respect to the start time of the interval.")
+DEFINITION (U"determines how the times %t__%i_ of the new pitch points are calculated. The time of each new pitch point is determined by adding to the start time of the interval a time calculated from the relative time value. If %%t%__min_ and %%t%__max_ are the start and end time of the interval and %%r%__i_ is the %%i%^^th^ relative time, the times %t__%i_ are calculated according to the options as:")
+TAG1 (U"%%fractions%")
+DEFINITION (U"%%t%__%i_ = %t__min_ + %r__%i_ (%t__max_ \\-- %t__min_). The relative time values are fractions of the interval duration. Normally fractions are numbers in the range 0.0 to 1.0, although smaller and larger numbers are allowed.")
+TAG1 (U"%%percentages%")
+DEFINITION (U"%%t%__%i_ = %t__min_+ 0.01 %r__%i_ (%t__max_ \\-- %t__min_). The relative time values are percentages of the interval duration. Normally percentages are numbers in the range 0.0 to 100.0, although smaller and larger numbers are allowed.")
+TAG1 (U"%%independent%")
+DEFINITION (U"%%t%__%i_ = %t__min_ + %r__%i_. The relative time values specify an offset in seconds here. ")
+
+TAG (U"##Tone levels")
+DEFINITION (U"specify the frequencies at the corresponding time points as tone levels.")
+ENTRY (U"Algorithm")
+NORMAL (U"1. The real times are calculated from the relative times.")
+NORMAL (U"2. The frequencies are calculated from the tone levels.")
+NORMAL (U"3. The real times and the frequencies are sorted together by time.")
+NORMAL (U"4. All pitch points in the PitchTier between the first and the last time of the sorted time array are removed.")
+NORMAL (U"5. The newly calculated pitch points are added to the PitchTier.")
+MAN_END
+
 MAN_BEGIN (U"Polygon: Rotate...", U"djmw", 20100418)
 INTRO (U"Rotates the selected @@Polygon@ counterclockwise with respect to the given coordinates.")
 MAN_END
@@ -4734,6 +4858,8 @@ FORMULA (U"(%x__%ij_ \\-- %\\mu__%j_) / %\\si__%j_, ")
 NORMAL (U"where %\\mu__%j_ and %\\si__%j_ are the mean and the standard deviation as calculated "
 	"from the %j^^th^ column, respectively. After standardization all column means will equal zero "
 	"and all column standard deviations will equal one.")
+ENTRY (U"Algorithm")
+NORMAL (U"Standard deviations are calculated with the corrected two-pass algorithm as described in @@Chan, Golub & LeVeque (1983)@.")
 MAN_END
 
 MAN_BEGIN (U"TableOfReal: To Configuration (lda)...", U"djmw", 19981103)
@@ -5171,6 +5297,14 @@ NORMAL (U"A. Boomsma (1977): \"Comparing approximations of confidence intervals
 	"#31: 179-186.")
 MAN_END
 
+MAN_BEGIN (U"Chan, Golub & LeVeque (1983)", U"djmw", 20170802)
+NORMAL (U"T.F. Chan, G.H. Golub & R.J. LeVeque (1983): \"Algorithms for computing the sample variance: Analysis and recommendations.\" %%The American Statistician% #37: 242\\--247.")
+MAN_END
+
+MAN_BEGIN (U"Chan, Golub & LeVeque (1979)", U"djmw", 20170802)
+NORMAL (U"T.F. Chan, G.H. Golub & R.J. LeVeque (1979): \"Updating formulae and an pairwise algorithm for computing sample variances.\" %%Stanford working paper STAN-CS-79-773%, 1\\--22.")
+MAN_END
+
 MAN_BEGIN (U"Cooley & Lohnes (1971)", U"djmw", 20060322)
 NORMAL (U"W.W. Colley & P.R. Lohnes (1971): %%Multivariate data analysis%. "
 	"John Wiley & Sons.")
@@ -5178,8 +5312,7 @@ MAN_END
 
 MAN_BEGIN (U"Davis & Mermelstein (1980)", U"djmw", 20010419)
 NORMAL (U"S.B. Davis & P. Mermelstein (1980), \"Comparison of parametric "
-	"representations for monosyllabic word recognition in continuously "
-	"spoken sentences.\" "
+	"representations for monosyllabic word recognition in continuously spoken sentences.\" "
 	"%%IEEE Transactions on ASSP% #28: 357\\--366.")
 MAN_END
 
diff --git a/dwtools/praat_David_init.cpp b/dwtools/praat_David_init.cpp
index 1a28d64..b8033bc 100644
--- a/dwtools/praat_David_init.cpp
+++ b/dwtools/praat_David_init.cpp
@@ -130,6 +130,7 @@
 #include "Sound_to_SPINET.h"
 #include "TableOfReal_and_SVD.h"
 #include "TextGrid_and_DurationTier.h"
+#include "TextGrid_and_PitchTier.h"
 #include "VowelEditor.h"
 
 #include "praat_TimeFrameSampled.h"
@@ -1798,7 +1799,7 @@ FORM (REAL_DTW_getDistanceValue, U"DTW: Get distance value", nullptr) {
 	OK
 DO
 	NUMBER_ONE (DTW)
-		double result = NUMundefined;
+		double result = undefined;
 		if ((xTime >= my xmin && xTime <= my xmax) && (yTime >= my ymin && yTime <= my ymax)) {
 			long irow = Matrix_yToNearestRow (me, yTime);
 			long icol = Matrix_xToNearestColumn (me, xTime);
@@ -2220,7 +2221,7 @@ FORM (REAL_Eigen_getEigenvalue, U"Eigen: Get eigenvalue", U"Eigen: Get eigenvalu
 	OK
 DO
 	NUMBER_ONE (Eigen)
-		double result = NUMundefined;
+		double result = undefined;
 		if (eigenvalueNumber > 0 && eigenvalueNumber <= my numberOfEigenvalues) {
 			result = my eigenvalues [eigenvalueNumber];
 		}
@@ -2956,7 +2957,7 @@ FORM (REAL_FunctionTerms_getCoefficient, U"FunctionTerms: Get coefficient", null
 	OK
 DO
 	NUMBER_ONE (FunctionTerms)
-		double result = (index > 0 && index <= my numberOfCoefficients) ? my coefficients [index] : NUMundefined;
+		double result = ( index > 0 && index <= my numberOfCoefficients ? my coefficients [index] : undefined );
 	NUMBER_ONE_END (U"")
 }
 
@@ -3593,7 +3594,7 @@ FORM (REAL_FilterBank_getValueInCell, U"Get value in cell", nullptr) {
 	OK
 DO
 	NUMBER_ONE (FilterBank)
-		double result = NUMundefined;
+		double result = undefined;
 		if ((frequency >= my ymin && frequency <= my ymax) && (time >+ my xmin && time <= my ymin)) {
 			long col = Matrix_xToNearestColumn (me, time);
 			if (col < 1) {
@@ -3664,7 +3665,7 @@ FORM (REAL_BandFilterSpectrogram_getValueInCell, U"Get value in cell", nullptr)
 	OK
 DO
 	NUMBER_ONE (BandFilterSpectrogram)
-		double result = NUMundefined;
+		double result = undefined;
 		if ((frequency >= my ymin && frequency <= my ymax) && (time >+ my xmin && time <= my ymin)) {
 			long col = Matrix_xToNearestColumn (me, time);
 			if (col < 1) {
@@ -3976,7 +3977,7 @@ FORM (REAL_PatternList_getValue, U"", nullptr) {
 	OK
 DO
 	NUMBER_ONE (PatternList)
-		double result = patternNumber <= my ny && nodeNumber <= my nx ? my z [patternNumber] [nodeNumber] : NUMundefined;
+		double result = ( patternNumber <= my ny && nodeNumber <= my nx ? my z [patternNumber] [nodeNumber] : undefined );
 	NUMBER_ONE_END (U"")
 }
 
@@ -4399,6 +4400,71 @@ DO
 	CONVERT_EACH_END (my name)
 }
 
+FORM (MODIFY_PitchTier_modifyInterval, U"PitchTier: Modify interval", U"PitchTier: Modify interval...") {
+	REAL4 (fromTime, U"left Time range (s)", U"0.0")
+	REAL4 (toTime, U"right Time range", U"0.0 (= all)")
+	LABEL (U"", U"")
+	SENTENCEVAR (timesString, U"Relative times", U"0.0 0.5 1.0")
+	OPTIONMENUVAR (timeOffset, U"...are...", 1)
+		OPTION (U"fractions")
+		OPTION (U"percentages")
+		OPTION (U"independent")
+	LABEL (U"", U"...of the interval duration which will be added...")
+	LABEL (U"", U"...to the start time of the interval.")
+	SENTENCEVAR (pitches_string, U"The \"pitch\" values", U"100 200 100")
+	OPTIONMENUVAR (pitch_as, U"...are...", 1)
+		OPTION (U"frequencies")
+		OPTION (U"fractions")
+		OPTION (U"percentages")
+		OPTION (U"start and slopes")
+		OPTION (U"slopes and end")
+		OPTION (U"music notes")
+//		OPTION (U"semitones")
+	LABEL (U"", U"...to be added to the anchor value (if used)...")
+	OPTIONMENUVAR (pitch_is, U"...which is the...", 1)
+		OPTION (U"not used")
+		OPTION (U"current")
+		OPTION (U"start")
+		OPTION (U"end")
+		OPTION (U"mean of the curve")
+		OPTION (U"mean of the points")
+		OPTION (U"maximum")
+		OPTION (U"minimum")
+	LABEL (U"", U"...frequency value in the interval.")
+	LABEL (U"", U"")
+	OPTIONMENUVAR (pitch_unit, U"Pitch frequency unit", 1)
+		OPTION (U"Hertz")
+
+	OK
+DO
+	MODIFY_EACH (PitchTier)
+		PitchTier_modifyInterval (me, fromTime, toTime, timesString, timeOffset, pitches_string, pitch_unit, pitch_as, pitch_is);
+	MODIFY_EACH_END
+}
+
+
+FORM (MODIFY_PitchTier_modifyInterval_toneLevels, U"PitchTier: Modify interval (tone levels)", U"PitchTier: Modify interval (tone levels)...") {
+	REAL4 (fromTime, U"left Time range (s)", U"0.0")
+	REAL4 (toTime, U"right Time range", U"0.0 (= all)")
+	REAL4 (fmin, U"left Pitch range (Hz)", U"80.0")
+	REAL4 (fmax, U"right Pitch range", U"200.0")
+	NATURAL4 (numberOfToneLevels, U"Number of tone levels", U"5")
+	LABEL (U"", U"")
+	SENTENCEVAR (times_string, U"Relative times", U"0.0 0.5 1.0")
+	OPTIONMENUVAR (time_offset, U"...are...", 1)
+		OPTION (U"fractions")
+		OPTION (U"percentages")
+		OPTION (U"independent")
+	LABEL (U"", U"...of the interval duration which will be added...")
+	LABEL (U"", U"...to the start time of the interval.")
+	SENTENCEVAR (pitches_string, U"Tone levels", U"2.1 2.1 5.0")
+	OK
+DO
+	MODIFY_EACH (PitchTier)
+		PitchTier_modifyInterval_toneLevels (me, fromTime, toTime, fmin, fmax, numberOfToneLevels, times_string, time_offset, pitches_string);
+	MODIFY_EACH_END
+}
+
 /******************* Polygon & Categories *************************************/
 
 FORM (NEW1_Polygon_createSimple, U"Create simple Polygon", U"Create simple Polygon...") {
@@ -4436,7 +4502,7 @@ FORM (REAL_Polygon_getPointX, U"Polygon: Get point (x)", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Polygon)
-		double result = pointNumber <= my numberOfPoints ? my x[pointNumber] : NUMundefined;
+		double result = ( pointNumber <= my numberOfPoints ? my x [pointNumber] : undefined );
 	NUMBER_ONE_END (U" (x [", pointNumber, U"])")
 }
 
@@ -4445,7 +4511,7 @@ FORM (REAL_Polygon_getPointY, U"Polygon: Get point (y)", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Polygon)
-		double result = pointNumber <= my numberOfPoints ? my y[pointNumber] : NUMundefined;
+		double result = ( pointNumber <= my numberOfPoints ? my y [pointNumber] : undefined );
 	NUMBER_ONE_END (U" (y [", pointNumber, U"])")
 }
 
@@ -4459,8 +4525,8 @@ DO
 	REQUIRE (eps >= 0, U"The precision cannot be negative.")
 	STRING_ONE (Polygon)
 		int loc = Polygon_getLocationOfPoint (me, x, y, eps);
-		const char32 * result = loc == Polygon_INSIDE ? U"I" : loc == Polygon_OUTSIDE ? U"O" :
-		loc == Polygon_EDGE ? U"E" : U"V";
+		const char32 * result = ( loc == Polygon_INSIDE ? U"I" : loc == Polygon_OUTSIDE ? U"O" :
+			loc == Polygon_EDGE ? U"E" : U"V" );
 	STRING_ONE_END
 }
 
@@ -4639,12 +4705,12 @@ FORM (INFO_Polynomial_getDerivativesAtX, U"Polynomial: Get derivatives at X", nu
 	INTEGERVAR (numberOfDerivatives, U"Number of derivatives", U"2")
 	OK
 DO
-	autoNUMvector<double> derivatives (0L, numberOfDerivatives);
+	autoNUMvector <double> derivatives ((integer) 0, numberOfDerivatives);
 	INFO_ONE (Polynomial)
 		Polynomial_evaluateDerivatives (me, x, derivatives.peek(), numberOfDerivatives);
 		MelderInfo_open ();
-			for (long i = 0; i <= numberOfDerivatives; i++) {
-				MelderInfo_writeLine (i, U": ", i < my numberOfCoefficients ? derivatives [i] : NUMundefined);
+			for (integer i = 0; i <= numberOfDerivatives; i ++) {
+				MelderInfo_writeLine (i, U": ", i < my numberOfCoefficients ? derivatives [i] : undefined);
 			}
 		MelderInfo_close ();
 	INFO_ONE_END
@@ -4858,6 +4924,7 @@ DIRECT (INFO_Praat_ReportFloatingPointProperties) {
 	MelderInfo_writeLine (U"Underflow threshold (= radix ^ (expmin - 1)): ", NUMfpp -> rmin);
 	MelderInfo_writeLine (U"Safe minimum (such that its inverse does not overflow): ", NUMfpp -> sfmin);
 	MelderInfo_writeLine (U"Overflow threshold (= (1 - eps) * radix ^ expmax): ", NUMfpp -> rmax);
+	MelderInfo_writeLine (U"\nA long double is ", sizeof (long double), U" bytes");
 	MelderInfo_close ();
 END }
 
@@ -5870,7 +5937,7 @@ FORM (REAL_SSCP_getCentroidElement, U"SSCP: Get centroid element", U"SSCP: Get c
 	OK
 DO
 	NUMBER_ONE (SSCP)
-		double result = NUMundefined;
+		double result = undefined;
 		if (number > 0 && number <= my numberOfColumns) {
 			result = my centroid [number];
 		}
@@ -7875,6 +7942,8 @@ void praat_uvafon_David_init () {
 	praat_addAction1 (classPitch, 2, U"To DTW...", U"To PointProcess", praat_HIDDEN, NEW1_Pitches_to_DTW);
 
 	praat_addAction1 (classPitchTier, 0, U"To Pitch...", U"To Sound (sine)...", 1, NEW_PitchTier_to_Pitch);
+	praat_addAction1 (classPitchTier, 0, U"Modify interval...", U"Add point...", 1, MODIFY_PitchTier_modifyInterval); 
+	praat_addAction1 (classPitchTier, 0, U"Modify interval (tone levels)...", U"Modify interval...", 1, MODIFY_PitchTier_modifyInterval_toneLevels); 
 	praat_addAction1 (classPolygon, 0, QUERY_BUTTON, U"Paint circles...", 0, 0);
 	praat_addAction1 (classPolygon, 0, U"Get number of points", QUERY_BUTTON, 1, INTEGER_Polygon_getNumberOfPoints);
 	praat_addAction1 (classPolygon, 0, U"Get point (x)...", U"Get number of points", 1, REAL_Polygon_getPointX);
diff --git a/dwtools/praat_KlattGrid_init.cpp b/dwtools/praat_KlattGrid_init.cpp
index fb9f373..2f5b24a 100644
--- a/dwtools/praat_KlattGrid_init.cpp
+++ b/dwtools/praat_KlattGrid_init.cpp
@@ -421,7 +421,7 @@ KlattGrid_FORMULA_FORMANT_FBA_VALUE (Name, namef, Frequencies, frequencies, U"if
 KlattGrid_FORMULA_FORMANT_FBA_VALUE (Name, namef, Bandwidths, bandwidths, U"self / 10 ; 10% of frequency", formantType, U"Warning: self is formant frequency.") \
 KlattGrid_ADD_FBA_VALUE (Name, namef, Formant, Frequency, frequency, formantType, U"500.0", (Hz), (value>0), U"Frequency must be greater than zero.") \
 KlattGrid_ADD_FBA_VALUE (Name, namef, Bandwidth, Bandwidth, bandwidth, formantType, U"50.0", (Hz), (value>0), U"Bandwidth must be greater than zero.") \
-KlattGrid_ADD_FBA_VALUE (Name, namef, Amplitude, Amplitude, amplitude, formantType, U"0.0", (dB), (NUMdefined(value)), U"Amplitude must be defined.") \
+KlattGrid_ADD_FBA_VALUE (Name, namef, Amplitude, Amplitude, amplitude, formantType, U"0.0", (dB), (isdefined(value)), U"Amplitude must be defined.") \
 KlattGrid_REMOVE_FBA_VALUE (Name, namef, Formant, Frequency, frequency, formantType) \
 KlattGrid_REMOVE_FBA_VALUE (Name, namef, Bandwidth, Bandwidth, bandwidth, formantType) \
 KlattGrid_REMOVE_FBA_VALUE (Name, namef, Amplitude, Amplitude, amplitude, formantType) \
@@ -448,8 +448,8 @@ KlattGrid_REMOVE_FORMANT (Name, namef, formantType)
 #define KlattGrid_FORMULA_ADD_REMOVE_FB_DELTA(Name,namef,formantType)  \
 KlattGrid_FORMULA_FORMANT_FBA_VALUE (Name, namef, Frequencies, frequencies, U"if row = 2 then self + 200 else self fi",formantType, U" ") \
 KlattGrid_FORMULA_FORMANT_FBA_VALUE (Name, namef, Bandwidths, bandwidths, U"self / 10 ; 10% of frequency",formantType, U"Warning: self is formant frequency.") \
-KlattGrid_ADD_FBA_VALUE (Name, namef, Formant,Frequency, frequency, formantType, U"-100.0", (Hz), (value!=NUMundefined), U"Frequency must be defined.") \
-KlattGrid_ADD_FBA_VALUE (Name, namef, Bandwidth, Bandwidth, bandwidth, formantType,  U"-50.0", (Hz), (value!=NUMundefined), U"Bandwidth must be defined.") \
+KlattGrid_ADD_FBA_VALUE (Name, namef, Formant,Frequency, frequency, formantType, U"-100.0", (Hz), (isdefined(value)), U"Frequency must be defined.") \
+KlattGrid_ADD_FBA_VALUE (Name, namef, Bandwidth, Bandwidth, bandwidth, formantType,  U"-50.0", (Hz), (isdefined(value)), U"Bandwidth must be defined.") \
 KlattGrid_REMOVE_FBA_VALUE (Name, namef, Formant, Frequency, frequency, formantType) \
 KlattGrid_REMOVE_FBA_VALUE (Name, namef, Bandwidth, Bandwidth, bandwidth, formantType) \
 KlattGrid_ADD_FORMANT_FREQUENCYANDBANDWIDTHTIERS (Name, namef, formantType) \
diff --git a/external/espeak/Makefile b/external/espeak/Makefile
index 54878b1..7a457e1 100644
--- a/external/espeak/Makefile
+++ b/external/espeak/Makefile
@@ -2,7 +2,7 @@
 
 include ../../makefile.defs
 
-CPPFLAGS = -I ../../num -I ../../kar -I ../../stat -I ../../sys -I ../../dwsys
+CPPFLAGS = -I ../../kar -I ../../sys -I ../../dwsys -I ../../stat
 
 OBJECTS =  compiledict.o dictionary.o intonation.o klatt.o  \
 	numbers.o phonemelist.o readclause.o setlengths.o  \
@@ -25,5 +25,5 @@ libespeak.a: $(OBJECTS)
 	$(AR) cq libespeak.a $(OBJECTS)
 	$(RANLIB) libespeak.a
 
-$(OBJECTS):  *.h ../../num/NUM.h ../../kar/*.h ../../sys/*.h ../../stat/*.h
+$(OBJECTS):  *.h ../../kar/*.h ../../sys/*.h ../../dwsys/*.h ../../stat/*.h
 
diff --git a/external/gsl/Makefile b/external/gsl/Makefile
index 1e10701..e11e06e 100644
--- a/external/gsl/Makefile
+++ b/external/gsl/Makefile
@@ -1,5 +1,6 @@
 # Makefile for library gsl. This file was generated by the program flatten_gsl.py
 # David Weenink, 22 February 2010
+# Paul Boersma 2017-08-08: brought dependencies in line with include directories
 
 include ../../makefile.defs
 
@@ -218,4 +219,4 @@ libgsl.a: $(OBJECTS)
 	$(AR) cq libgsl.a $(OBJECTS)
 	$(RANLIB) libgsl.a
 
-$(OBJECTS): *.h
+$(OBJECTS): *.h ../../sys/*.h ../../dwsys/*.h
diff --git a/fon/AmplitudeTier.cpp b/fon/AmplitudeTier.cpp
index 9ddc8e2..c8bd2b6 100644
--- a/fon/AmplitudeTier.cpp
+++ b/fon/AmplitudeTier.cpp
@@ -1,6 +1,6 @@
 /* AmplitudeTier.cpp
  *
- * Copyright (C) 2003-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 2003-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@ autoAmplitudeTier AmplitudeTier_create (double tmin, double tmax) {
 }
 
 void AmplitudeTier_draw (AmplitudeTier me, Graphics g, double tmin, double tmax,
-	double ymin, double ymax, const char32 *method, int garnish)
+	double ymin, double ymax, const char32 *method, bool garnish)
 {
 	RealTier_draw (me, g, tmin, tmax, ymin, ymax, garnish, method, U"Sound pressure (Pa)");
 }
@@ -49,7 +49,7 @@ autoAmplitudeTier IntensityTier_to_AmplitudeTier (IntensityTier me) {
 	try {
 		autoAmplitudeTier thee = Thing_new (AmplitudeTier);
 		my structRealTier :: v_copy (thee.get());
-		for (long i = 1; i <= thy points.size; i ++) {
+		for (integer i = 1; i <= thy points.size; i ++) {
 			RealPoint point = thy points.at [i];
 			point -> value = pow (10.0, point -> value / 20.0) * 2.0e-5;
 		}
@@ -64,7 +64,7 @@ autoIntensityTier AmplitudeTier_to_IntensityTier (AmplitudeTier me, double thres
 		double threshold_Pa = pow (10.0, threshold_dB / 20.0) * 2.0e-5;   // often zero!
 		autoIntensityTier thee = Thing_new (IntensityTier);
 		my structRealTier :: v_copy (thee.get());
-		for (long i = 1; i <= thy points.size; i ++) {
+		for (integer i = 1; i <= thy points.size; i ++) {
 			RealPoint point = thy points.at [i];
 			double absoluteValue = fabs (point -> value);
 			point -> value = absoluteValue <= threshold_Pa ? threshold_dB : 20.0 * log10 (absoluteValue / 2.0e-5);
@@ -81,10 +81,10 @@ autoTableOfReal AmplitudeTier_downto_TableOfReal (AmplitudeTier me) {
 
 void Sound_AmplitudeTier_multiply_inline (Sound me, AmplitudeTier amplitude) {
 	if (amplitude -> points.size == 0) return;
-	for (long isamp = 1; isamp <= my nx; isamp ++) {
+	for (integer isamp = 1; isamp <= my nx; isamp ++) {
 		double t = my x1 + (isamp - 1) * my dx;
 		double factor = RealTier_getValueAtTime (amplitude, t);
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			my z [channel] [isamp] *= factor;
 		}
 	}
@@ -103,12 +103,12 @@ autoSound Sound_AmplitudeTier_multiply (Sound me, AmplitudeTier amplitude) {
 
 autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_point (PointProcess me, Sound you) {
 	try {
-		long imin, imax, numberOfPeaks = PointProcess_getWindowPoints (me, my xmin, my xmax, & imin, & imax);
+		integer imin, imax, numberOfPeaks = PointProcess_getWindowPoints (me, my xmin, my xmax, & imin, & imax);
 		if (numberOfPeaks < 3) return autoAmplitudeTier();
 		autoAmplitudeTier him = AmplitudeTier_create (my xmin, my xmax);
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double value = Vector_getValueAtX (you, my t [i], Vector_CHANNEL_AVERAGE, Vector_VALUE_INTERPOLATION_SINC700);
-			if (NUMdefined (value)) RealTier_addPoint (him.get(), my t [i], value);
+			if (isdefined (value)) RealTier_addPoint (him.get(), my t [i], value);
 		}
 		return him;
 	} catch (MelderError) {
@@ -116,67 +116,68 @@ autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_point (PointProcess me, So
 	}
 }
 /*
-static double Sound_getPeak (Sound me, double tmin, double tmax, long channel) {
-	double minimum, timeOfMinimum, maximum, timeOfMaximum;
-	double *y = my z [channel];
-	long i, imin, imax, sampleOfMinimum, sampleOfMaximum;
-	if (Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax) < 3) return NUMundefined;
-	maximum = minimum = y [imin];
-	sampleOfMaximum = sampleOfMinimum = imin;
-	for (i = imin + 1; i <= imax; i ++) {
+static real Sound_getPeak (Sound me, real tmin, real tmax, integer channel) {
+	real *y = my z [channel];
+	integer imin, imax;
+	if (Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax) < 3) return undefined;
+	real minimum = y [imin];
+	real maximum = y [imin];
+	integer sampleOfMinimum = imin;
+	integer sampleOfMaximum = imin;
+	for (integer i = imin + 1; i <= imax; i ++) {
 		if (y [i] < minimum) { minimum = y [i]; sampleOfMinimum = i; }
 		if (y [i] > maximum) { maximum = y [i]; sampleOfMaximum = i; }
 	}
-	timeOfMinimum = my x1 + (sampleOfMinimum - 1) * my dx;
-	timeOfMaximum = my x1 + (sampleOfMaximum - 1) * my dx;
+	real timeOfMinimum = my x1 + (sampleOfMinimum - 1) * my dx;
+	real timeOfMaximum = my x1 + (sampleOfMaximum - 1) * my dx;
 	Vector_getMinimumAndX (me, timeOfMinimum - my dx, timeOfMinimum + my dx, NUM_PEAK_INTERPOLATE_SINC70, & minimum, & timeOfMinimum);
 	Vector_getMaximumAndX (me, timeOfMaximum - my dx, timeOfMaximum + my dx, NUM_PEAK_INTERPOLATE_SINC70, & maximum, & timeOfMaximum);
 	return maximum - minimum;
 }
 */
-static double Sound_getHannWindowedRms (Sound me, double tmid, double widthLeft, double widthRight) {
-	double sumOfSquares = 0.0, windowSumOfSquares = 0.0;
-	long imin, imax;
-	if (Sampled_getWindowSamples (me, tmid - widthLeft, tmid + widthRight, & imin, & imax) < 3) return NUMundefined;
-	for (long i = imin; i <= imax; i ++) {
-		double t = my x1 + (i - 1) * my dx;
-		double width = t < tmid ? widthLeft : widthRight;
-		double windowPhase = (t - tmid) / width;   /* in [-1 .. 1] */
-		double window = 0.5 + 0.5 * cos (NUMpi * windowPhase);   /* Hann */
-		double windowedValue = ( my ny == 1 ? my z [1] [i] : 0.5 * (my z [1] [i] + my z [2] [i]) ) * window;
+static real Sound_getHannWindowedRms (Sound me, real tmid, real widthLeft, real widthRight) {
+	integer imin, imax;
+	if (Sampled_getWindowSamples (me, tmid - widthLeft, tmid + widthRight, & imin, & imax) < 3) return undefined;
+	real80 sumOfSquares = 0.0, windowSumOfSquares = 0.0;
+	for (integer i = imin; i <= imax; i ++) {
+		real t = my x1 + (i - 1) * my dx;
+		real width = t < tmid ? widthLeft : widthRight;
+		real windowPhase = (t - tmid) / width;   /* in [-1 .. 1] */
+		real window = 0.5 + 0.5 * cos (NUMpi * windowPhase);   /* Hann */
+		real windowedValue = ( my ny == 1 ? my z [1] [i] : 0.5 * (my z [1] [i] + my z [2] [i]) ) * window;
 		sumOfSquares += windowedValue * windowedValue;
 		windowSumOfSquares += window * window;
 	}
-	return sqrt (sumOfSquares / windowSumOfSquares);
+	return sqrt (real (sumOfSquares / windowSumOfSquares));
 }
-autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_period (PointProcess me, Sound thee, double tmin, double tmax,
+autoAmplitudeTier PointProcess_Sound_to_AmplitudeTier_period (PointProcess me, Sound you, double tmin, double tmax,
 	double pmin, double pmax, double maximumPeriodFactor)
 {
 	try {
 		if (tmax <= tmin) tmin = my xmin, tmax = my xmax;
-		long imin, imax;
-		long numberOfPeaks = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax);
+		integer imin, imax;
+		integer numberOfPeaks = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax);
 		if (numberOfPeaks < 3) Melder_throw (U"Too few pulses between ", tmin, U" and ", tmax, U" seconds.");
 		autoAmplitudeTier him = AmplitudeTier_create (tmin, tmax);
-		for (long i = imin + 1; i < imax; i ++) {
+		for (integer i = imin + 1; i < imax; i ++) {
 			double p1 = my t [i] - my t [i - 1], p2 = my t [i + 1] - my t [i];
 			double intervalFactor = p1 > p2 ? p1 / p2 : p2 / p1;
 			if (pmin == pmax || (p1 >= pmin && p1 <= pmax && p2 >= pmin && p2 <= pmax && intervalFactor <= maximumPeriodFactor)) {
-				double peak = Sound_getHannWindowedRms (thee, my t [i], 0.2 * p1, 0.2 * p2);
-				if (NUMdefined (peak) && peak > 0.0)
+				double peak = Sound_getHannWindowedRms (you, my t [i], 0.2 * p1, 0.2 * p2);
+				if (isdefined (peak) && peak > 0.0)
 					RealTier_addPoint (him.get(), my t [i], peak);
 			}
 		}
 		return him;
 	} catch (MelderError) {
-		Melder_throw (me, U" & ", thee, U": not converted to AmplitudeTier.");
+		Melder_throw (me, U" & ", you, U": not converted to AmplitudeTier.");
 	}
 }
 double AmplitudeTier_getShimmer_local (AmplitudeTier me, double pmin, double pmax, double maximumAmplitudeFactor) {
-	long numberOfPeaks = 0;
-	double numerator = 0.0, denominator = 0.0;
+	integer numberOfPeaks = 0;
+	real80 numerator = 0.0, denominator = 0.0;
 	RealPoint *points = & my points.at [0];
-	for (long i = 2; i <= my points.size; i ++) {
+	for (integer i = 2; i <= my points.size; i ++) {
 		double p = points [i] -> number - points [i - 1] -> number;
 		if (pmin == pmax || (p >= pmin && p <= pmax)) {
 			double a1 = points [i - 1] -> value, a2 = points [i] -> value;
@@ -187,22 +188,22 @@ double AmplitudeTier_getShimmer_local (AmplitudeTier me, double pmin, double pma
 			}
 		}
 	}
-	if (numberOfPeaks < 1) return NUMundefined;
+	if (numberOfPeaks < 1) return undefined;
 	numerator /= numberOfPeaks;
 	numberOfPeaks = 0;
-	for (long i = 1; i < my points.size; i ++) {
+	for (integer i = 1; i < my points.size; i ++) {
 		denominator += points [i] -> value;
 		numberOfPeaks ++;
 	}
 	denominator /= numberOfPeaks;
-	if (denominator == 0.0) return NUMundefined;
-	return numerator / denominator;
+	if (denominator == 0.0) return undefined;
+	return real (numerator / denominator);
 }
 double AmplitudeTier_getShimmer_local_dB (AmplitudeTier me, double pmin, double pmax, double maximumAmplitudeFactor) {
-	long numberOfPeaks = 0;
-	double result = 0.0;
+	integer numberOfPeaks = 0;
+	real80 result = 0.0;
 	RealPoint *points = & my points.at [0];
-	for (long i = 2; i <= my points.size; i ++) {
+	for (integer i = 2; i <= my points.size; i ++) {
 		double p = points [i] -> number - points [i - 1] -> number;
 		if (pmin == pmax || (p >= pmin && p <= pmax)) {
 			double a1 = points [i - 1] -> value, a2 = points [i] -> value;
@@ -213,15 +214,15 @@ double AmplitudeTier_getShimmer_local_dB (AmplitudeTier me, double pmin, double
 			}
 		}
 	}
-	if (numberOfPeaks < 1) return NUMundefined;
+	if (numberOfPeaks < 1) return undefined;
 	result /= numberOfPeaks;
-	return 20.0 * result;
+	return real (20.0 * result);
 }
 double AmplitudeTier_getShimmer_apq3 (AmplitudeTier me, double pmin, double pmax, double maximumAmplitudeFactor) {
-	long numberOfPeaks = 0;
-	double numerator = 0.0, denominator = 0.0;
+	integer numberOfPeaks = 0;
+	real80 numerator = 0.0, denominator = 0.0;
 	RealPoint *points = & my points.at [0];
-	for (long i = 2; i <= my points.size - 1; i ++) {
+	for (integer i = 2; i <= my points.size - 1; i ++) {
 		double
 			p1 = points [i] -> number - points [i - 1] -> number,
 			p2 = points [i + 1] -> number - points [i] -> number;
@@ -235,22 +236,22 @@ double AmplitudeTier_getShimmer_apq3 (AmplitudeTier me, double pmin, double pmax
 			}
 		}
 	}
-	if (numberOfPeaks < 1) return NUMundefined;
+	if (numberOfPeaks < 1) return undefined;
 	numerator /= numberOfPeaks;
 	numberOfPeaks = 0;
-	for (long i = 1; i < my points.size; i ++) {
+	for (integer i = 1; i < my points.size; i ++) {
 		denominator += points [i] -> value;
 		numberOfPeaks ++;
 	}
 	denominator /= numberOfPeaks;
-	if (denominator == 0.0) return NUMundefined;
-	return numerator / denominator;
+	if (denominator == 0.0) return undefined;
+	return real (numerator / denominator);
 }
 double AmplitudeTier_getShimmer_apq5 (AmplitudeTier me, double pmin, double pmax, double maximumAmplitudeFactor) {
-	long numberOfPeaks = 0;
-	double numerator = 0.0, denominator = 0.0;
+	integer numberOfPeaks = 0;
+	real80 numerator = 0.0, denominator = 0.0;
 	RealPoint *points = & my points.at [0];
-	for (long i = 3; i <= my points.size - 2; i ++) {
+	for (integer i = 3; i <= my points.size - 2; i ++) {
 		double
 			p1 = points [i - 1] -> number - points [i - 2] -> number,
 			p2 = points [i] -> number - points [i - 1] -> number,
@@ -266,28 +267,28 @@ double AmplitudeTier_getShimmer_apq5 (AmplitudeTier me, double pmin, double pmax
 			if (f1 <= maximumAmplitudeFactor && f2 <= maximumAmplitudeFactor &&
 			    f3 <= maximumAmplitudeFactor && f4 <= maximumAmplitudeFactor)
 			{
-				double fivePointAverage = (a1 + a2 + a3 + a4 + a5) / 5.0;
+				double fivePointAverage = ((a1 + a2 + a3) + (a4 + a5)) / 5.0;
 				numerator += fabs (a3 - fivePointAverage);
 				numberOfPeaks ++;
 			}
 		}
 	}
-	if (numberOfPeaks < 1) return NUMundefined;
+	if (numberOfPeaks < 1) return undefined;
 	numerator /= numberOfPeaks;
 	numberOfPeaks = 0;
-	for (long i = 1; i < my points.size; i ++) {
+	for (integer i = 1; i < my points.size; i ++) {
 		denominator += points [i] -> value;
 		numberOfPeaks ++;
 	}
 	denominator /= numberOfPeaks;
-	if (denominator == 0.0) return NUMundefined;
-	return numerator / denominator;
+	if (denominator == 0.0) return undefined;
+	return real (numerator / denominator);
 }
 double AmplitudeTier_getShimmer_apq11 (AmplitudeTier me, double pmin, double pmax, double maximumAmplitudeFactor) {
-	long numberOfPeaks = 0;
-	double numerator = 0.0, denominator = 0.0;
+	integer numberOfPeaks = 0;
+	real80 numerator = 0.0, denominator = 0.0;
 	RealPoint *points = & my points.at [0];
-	for (long i = 6; i <= my points.size - 5; i ++) {
+	for (integer i = 6; i <= my points.size - 5; i ++) {
 		double
 			p1 = points [i - 4] -> number - points [i - 5] -> number,
 			p2 = points [i - 3] -> number - points [i - 4] -> number,
@@ -319,45 +320,45 @@ double AmplitudeTier_getShimmer_apq11 (AmplitudeTier me, double pmin, double pma
 			    f7 <= maximumAmplitudeFactor && f8 <= maximumAmplitudeFactor &&
 			    f9 <= maximumAmplitudeFactor && f10 <= maximumAmplitudeFactor)
 			{
-				double elevenPointAverage = (a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11) / 11.0;
+				double elevenPointAverage = (((a1 + a2 + a3) + (a4 + a5 + a6)) + ((a7 + a8 + a9) + (a10 + a11))) / 11.0;
 				numerator += fabs (a6 - elevenPointAverage);
 				numberOfPeaks ++;
 			}
 		}
 	}
-	if (numberOfPeaks < 1) return NUMundefined;
+	if (numberOfPeaks < 1) return undefined;
 	numerator /= numberOfPeaks;
 	numberOfPeaks = 0;
-	for (long i = 1; i < my points.size; i ++) {
+	for (integer i = 1; i < my points.size; i ++) {
 		denominator += points [i] -> value;
 		numberOfPeaks ++;
 	}
 	denominator /= numberOfPeaks;
-	if (denominator == 0.0) return NUMundefined;
-	return numerator / denominator;
+	if (denominator == 0.0) return undefined;
+	return real (numerator / denominator);
 }
 double AmplitudeTier_getShimmer_dda (AmplitudeTier me, double pmin, double pmax, double maximumAmplitudeFactor) {
 	double apq3 = AmplitudeTier_getShimmer_apq3 (me, pmin, pmax, maximumAmplitudeFactor);
-	return NUMdefined (apq3) ? 3.0 * apq3 : NUMundefined;
+	return ( isdefined (apq3) ? 3.0 * apq3 : undefined );
 }
 
-autoSound AmplitudeTier_to_Sound (AmplitudeTier me, double samplingFrequency, long interpolationDepth) {
+autoSound AmplitudeTier_to_Sound (AmplitudeTier me, double samplingFrequency, integer interpolationDepth) {
 	try {
-		long sound_nt = 1 + (long) floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
+		integer sound_nt = 1 + (integer) floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
 		double dt = 1.0 / samplingFrequency;
 		double tmid = (my xmin + my xmax) / 2;
 		double t1 = tmid - 0.5 * (sound_nt - 1) * dt;
 		double *sound;
-		autoSound thee = Sound_create (1, my xmin, my xmax, sound_nt, dt, t1);
-		sound = thy z [1];
-		for (long it = 1; it <= my points.size; it ++) {
+		autoSound you = Sound_create (1, my xmin, my xmax, sound_nt, dt, t1);
+		sound = your z [1];
+		for (integer it = 1; it <= my points.size; it ++) {
 			RealPoint point = my points.at [it];
 			double t = point -> number, amplitude = point -> value, angle, halfampsinangle;
-			long mid = Sampled_xToNearestIndex (thee.get(), t), j;
-			long begin = mid - interpolationDepth, end = mid + interpolationDepth;
+			integer mid = Sampled_xToNearestIndex (you.get(), t), j;
+			integer begin = mid - interpolationDepth, end = mid + interpolationDepth;
 			if (begin < 1) begin = 1;
-			if (end > thy nx) end = thy nx;
-			angle = NUMpi * (Sampled_indexToX (thee.get(), begin) - t) / thy dx;
+			if (end > your nx) end = your nx;
+			angle = NUMpi * (Sampled_indexToX (you.get(), begin) - t) / your dx;
 			halfampsinangle = 0.5 * amplitude * sin (angle);
 			for (j = begin; j <= end; j ++) {
 				if (fabs (angle) < 1e-6)
@@ -372,7 +373,7 @@ autoSound AmplitudeTier_to_Sound (AmplitudeTier me, double samplingFrequency, lo
 				halfampsinangle = - halfampsinangle;
 			}
 		}
-		return thee;
+		return you;
 	} catch (MelderError) {
 		Melder_throw (me, U": not converted to Sound.");
 	}
diff --git a/fon/AmplitudeTier.h b/fon/AmplitudeTier.h
index ff362da..a2001ab 100644
--- a/fon/AmplitudeTier.h
+++ b/fon/AmplitudeTier.h
@@ -2,7 +2,7 @@
 #define _AmplitudeTier_h_
 /* AmplitudeTier.h
  *
- * Copyright (C) 2003-2011,2015 Paul Boersma
+ * Copyright (C) 2003-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ Thing_define (AmplitudeTier, RealTier) {
 autoAmplitudeTier AmplitudeTier_create (double tmin, double tmax);
 
 void AmplitudeTier_draw (AmplitudeTier me, Graphics g, double tmin, double tmax,
-	double ymin, double ymax, const char32 *method, int garnish);
+	double ymin, double ymax, const char32 *method, bool garnish);
 
 autoAmplitudeTier PointProcess_upto_AmplitudeTier (PointProcess me, double soundPressure);
 autoAmplitudeTier IntensityTier_to_AmplitudeTier (IntensityTier me);
@@ -51,7 +51,7 @@ double AmplitudeTier_getShimmer_apq5 (AmplitudeTier me, double shortestPeriod, d
 double AmplitudeTier_getShimmer_apq11 (AmplitudeTier me, double shortestPeriod, double longestPeriod, double maximumAmplitudeFactor);
 double AmplitudeTier_getShimmer_dda (AmplitudeTier me, double shortestPeriod, double longestPeriod, double maximumAmplitudeFactor);
 
-autoSound AmplitudeTier_to_Sound (AmplitudeTier me, double samplingFrequency, long interpolationDepth);
+autoSound AmplitudeTier_to_Sound (AmplitudeTier me, double samplingFrequency, integer interpolationDepth);
 
 /* End of file AmplitudeTier.h */
 #endif
diff --git a/fon/AnyTier.cpp b/fon/AnyTier.cpp
index 92b81e9..c199a75 100644
--- a/fon/AnyTier.cpp
+++ b/fon/AnyTier.cpp
@@ -115,7 +115,7 @@ long AnyTier_timeToHighIndex (AnyTier me, double time) {
 	return iright;
 }
 
-long AnyTier_getWindowPoints (AnyTier me, double tmin, double tmax, long *imin, long *imax) {
+integer AnyTier_getWindowPoints (AnyTier me, double tmin, double tmax, integer *imin, integer *imax) {
 	if (my points.size == 0) return 0;
 	*imin = AnyTier_timeToHighIndex (me, tmin);
 	*imax = AnyTier_timeToLowIndex (me, tmax);
diff --git a/fon/AnyTier.h b/fon/AnyTier.h
index 70504f9..2f8da91 100644
--- a/fon/AnyTier.h
+++ b/fon/AnyTier.h
@@ -2,7 +2,7 @@
 #define _AnyTier_h_
 /* AnyTier.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@ long AnyTier_timeToLowIndex (AnyTier me, double time);
 
 long AnyTier_timeToHighIndex (AnyTier me, double time);
 
-long AnyTier_getWindowPoints (AnyTier me, double tmin, double tmax, long *imin, long *imax);
+integer AnyTier_getWindowPoints (AnyTier me, double tmin, double tmax, integer *imin, integer *imax);
 
 long AnyTier_timeToNearestIndex (AnyTier me, double time);
 
diff --git a/fon/Cochleagram.cpp b/fon/Cochleagram.cpp
index ef97ade..c16cb49 100644
--- a/fon/Cochleagram.cpp
+++ b/fon/Cochleagram.cpp
@@ -1,6 +1,6 @@
 /* Cochleagram.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
 
 Thing_implement (Cochleagram, Matrix, 2);
 
-autoCochleagram Cochleagram_create (double tmin, double tmax, long nt, double dt, double t1, double df, long nf) {
+autoCochleagram Cochleagram_create (double tmin, double tmax, integer nt, double dt, double t1, double df, integer nf) {
 	try {
 		autoCochleagram me = Thing_new (Cochleagram);
 		Matrix_init (me.get(), tmin, tmax, nt, dt, t1, 0.0, nf * df, nf, df, 0.5 * df);
@@ -31,16 +31,16 @@ autoCochleagram Cochleagram_create (double tmin, double tmax, long nt, double dt
 	}
 }
 
-void Cochleagram_paint (Cochleagram me, Graphics g, double tmin, double tmax, int garnish) {
+void Cochleagram_paint (Cochleagram me, Graphics g, double tmin, double tmax, bool garnish) {
 	static double border [1 + 12]
 		{ 0.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0 };
 	try {
 		autoCochleagram copy = Data_copy (me);
 		if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-		long itmin, itmax;
+		integer itmin, itmax;
 		Matrix_getWindowSamplesX (me, tmin, tmax, & itmin, & itmax);
-		for (long iy = 2; iy < my ny; iy ++)
-			for (long ix = itmin; ix <= itmax; ix ++)
+		for (integer iy = 2; iy < my ny; iy ++)
+			for (integer ix = itmin; ix <= itmax; ix ++)
 				if (my z [iy] [ix] > my z [iy - 1] [ix] &&
 					my z [iy] [ix] > my z [iy + 1] [ix])
 				{
@@ -74,19 +74,19 @@ double Cochleagram_difference (Cochleagram me, Cochleagram thee, double tmin, do
 		if (my ny != thy ny)
 			Melder_throw (U"Unequal numbers of frequencies.");
 		if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-		long itmin, itmax;
-		long nt = Matrix_getWindowSamplesX (me, tmin, tmax, & itmin, & itmax);
+		integer itmin, itmax;
+		integer nt = Matrix_getWindowSamplesX (me, tmin, tmax, & itmin, & itmax);
 		if (nt == 0)
 			Melder_throw (U"Window too short.");
-		double diff = 0.0;
-		for (long itime = itmin; itime <= itmax; itime ++) {
-			for (long ifreq = 1; ifreq <= my ny; ifreq ++) {
+		real80 diff = 0.0;
+		for (integer itime = itmin; itime <= itmax; itime ++) {
+			for (integer ifreq = 1; ifreq <= my ny; ifreq ++) {
 				double d = my z [ifreq] [itime] - thy z [ifreq] [itime];
 				diff += d * d;
 			}
 		}
 		diff /= nt * my ny;
-		return sqrt (diff);
+		return sqrt ((real) diff);
 	} catch (MelderError) {
 		Melder_throw (me, U" & ", thee, U": difference not computed.");
 	}
diff --git a/fon/Cochleagram.h b/fon/Cochleagram.h
index 8624560..2302941 100644
--- a/fon/Cochleagram.h
+++ b/fon/Cochleagram.h
@@ -2,7 +2,7 @@
 #define _Cochleagram_h_
 /* Cochleagram.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,8 +39,8 @@ Thing_define (Cochleagram, Matrix) {
 	z;				// Basilar filter output (milliVolt), or firing rate (Hz), or intensity (phon).
 */
 
-autoCochleagram Cochleagram_create (double tmin, double tmax, long nt, double dt, double t1,
-	double df, long nf);
+autoCochleagram Cochleagram_create (double tmin, double tmax, integer nt, double dt, double t1,
+	double df, integer nf);
 /*
 	Function:
 		return a new instance of Cochleagram.
@@ -56,7 +56,7 @@ autoCochleagram Cochleagram_create (double tmin, double tmax, long nt, double dt
 		result -> z [1..nf] [1..nt] == 0.0;
 */
 
-void Cochleagram_paint (Cochleagram me, Graphics g, double tmin, double tmax, int garnish);
+void Cochleagram_paint (Cochleagram me, Graphics g, double tmin, double tmax, bool garnish);
 
 double Cochleagram_difference (Cochleagram me, Cochleagram thee, double tmin, double tmax);
 
diff --git a/fon/Distributions_and_Transition.cpp b/fon/Distributions_and_Transition.cpp
index c191095..aea7267 100644
--- a/fon/Distributions_and_Transition.cpp
+++ b/fon/Distributions_and_Transition.cpp
@@ -1,6 +1,6 @@
 /* Distributions_and_Transition.cpp
  *
- * Copyright (C) 1997-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1997-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -138,10 +138,13 @@ autoDistributions Distributions_Transition_map (Distributions me, Transition map
 		/*
 		 * Compute the elements of the surface distributions.
 		 */
-		for (long row = 1; row <= my numberOfRows; row ++) for (long col = 1; col <= my numberOfColumns; col ++) {
-			thy data [row] [col] = 0.0;
-			for (long m = 1; m <= map -> numberOfStates; m ++)
-				thy data [row] [col] += my data [m] [col] * map -> data [m] [row];
+		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+				thy data [irow] [icol] = 0.0;
+				for (long istate = 1; istate <= map -> numberOfStates; istate ++) {
+					thy data [irow] [icol] += my data [istate] [icol] * map -> data [istate] [irow];
+				}
+			}
 		}
 
 		return thee;
diff --git a/fon/Excitation.cpp b/fon/Excitation.cpp
index 63a5b8e..1be3dea 100644
--- a/fon/Excitation.cpp
+++ b/fon/Excitation.cpp
@@ -1,6 +1,6 @@
 /* Excitation.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -110,7 +110,7 @@ void Excitation_draw (Excitation me, Graphics g,
 	double fmin, double fmax, double minimum, double maximum, int garnish)
 {
 	if (fmax <= fmin) { fmin = my xmin; fmax = my xmax; }
-	long ifmin, ifmax;
+	integer ifmin, ifmax;
 	Matrix_getWindowSamplesX (me, fmin, fmax, & ifmin, & ifmax);
 	if (maximum <= minimum)
 		Matrix_getWindowExtrema (me, ifmin, ifmax, 1, 1, & minimum, & maximum);
diff --git a/fon/ExperimentMFC.cpp b/fon/ExperimentMFC.cpp
index f6ec5eb..3df6d25 100644
--- a/fon/ExperimentMFC.cpp
+++ b/fon/ExperimentMFC.cpp
@@ -1,6 +1,6 @@
 /* ExperimentMFC.cpp
  *
- * Copyright (C) 2001-2011,2013,2016 Paul Boersma
+ * Copyright (C) 2001-2011,2013,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -78,7 +78,7 @@ static void readSound (ExperimentMFC me, const char32 *fileNameHead, const char3
 {
 	char32 fileNameBuffer [256], *fileNames = & fileNameBuffer [0];
 	Melder_sprint (fileNameBuffer,256, *name);
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	/*
 	 * The following conversion is needed when fileNameHead is an absolute path,
 	 * and the stimulus names contain slashes for relative paths.
@@ -133,8 +133,10 @@ static void readSound (ExperimentMFC me, const char32 *fileNameHead, const char3
 		/*
 		 * Check whether all sounds have the same number of channels.
 		 */
-		if (my numberOfChannels == 0) {
-			my numberOfChannels = substimulus -> ny;
+		if (substimulus -> ny > INT16_MAX) {
+			Melder_throw (U"An ExperimentMFC cannot handle sounds with more than ", INT16_MAX, U" channels.");
+		} else if (my numberOfChannels == 0) {
+			my numberOfChannels = int16 (substimulus -> ny);   // guarded cast
 		} else if (substimulus -> ny != my numberOfChannels) {
 			Melder_throw (U"The sound in file ", & file, U" has a different number of channels than some other sound.");
 		}
diff --git a/fon/ExperimentMFC_def.h b/fon/ExperimentMFC_def.h
index f7aa767..3cd8403 100644
--- a/fon/ExperimentMFC_def.h
+++ b/fon/ExperimentMFC_def.h
@@ -1,6 +1,6 @@
 /* ExperimentMFC_def.h
  *
- * Copyright (C) 2001-2011,2013,2015,2016 Paul Boersma
+ * Copyright (C) 2001-2011,2013,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -77,7 +77,7 @@ oo_DEFINE_STRUCT (ResponseMFC)
 	oo_FLOAT (top)
 	oo_STRING (label)
 	oo_FROM (5)
-		oo_INT (fontSize)
+		oo_INT16 (fontSize)
 	oo_ENDFROM
 	oo_FROM (3)
 		oo_STRING (key)
@@ -104,7 +104,7 @@ oo_DEFINE_STRUCT (GoodnessMFC)
 	oo_FLOAT (top)
 	oo_STRING (label)
 	oo_FROM (7)
-		oo_INT (fontSize)
+		oo_INT16 (fontSize)
 		oo_STRING (key)
 	oo_ENDFROM
 
@@ -182,7 +182,7 @@ oo_DEFINE_CLASS (ExperimentMFC, Daata)
 	oo_ENDFROM
 	#if !oo_READING && !oo_WRITING
 		oo_DOUBLE (samplePeriod)
-		oo_INT (numberOfChannels)
+		oo_INT16 (numberOfChannels)
 		oo_BOOLEAN (pausing)
 		oo_LONG (trial)
 		oo_LONG (numberOfTrials)
diff --git a/fon/Formant.cpp b/fon/Formant.cpp
index 6468e4b..bbff8d8 100644
--- a/fon/Formant.cpp
+++ b/fon/Formant.cpp
@@ -1,6 +1,6 @@
 /* Formant.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ void structFormant :: v_info () {
 double structFormant :: v_getValueAtSample (long iframe, long which, int units) {
 	Formant_Frame frame = & d_frames [iframe];
 	long iformant = which >> 1;
-	if (iformant < 1 || iformant > frame -> nFormants) return NUMundefined;
+	if (iformant < 1 || iformant > frame -> nFormants) return undefined;
 	double frequency = frame -> formant [iformant]. frequency;
 	if ((which & 1) == 0) {
 		return units ? NUMhertzToBark (frequency) : frequency;
@@ -75,13 +75,13 @@ double structFormant :: v_getValueAtSample (long iframe, long which, int units)
 		double bandwidth = frame -> formant [iformant]. bandwidth;
 		if (units) {
 			double fleft = frequency - 0.5 * bandwidth, fright = frequency + 0.5 * bandwidth;
-			fleft = fleft <= 0.0 ? 0.0 : NUMhertzToBark (fleft);   // prevent NUMundefined
+			fleft = ( fleft <= 0.0 ? 0.0 : NUMhertzToBark (fleft) );   // prevent undefined
 			fright = NUMhertzToBark (fright);
 			return fright - fleft;
 		}
 		return bandwidth;
 	}
-	return NUMundefined;
+	return undefined;
 }
 
 autoFormant Formant_create (double tmin, double tmax, long nt, double dt, double t1,
@@ -115,18 +115,18 @@ long Formant_getMaxNumFormants (Formant me) {
 }
 
 void Formant_drawTracks (Formant me, Graphics g, double tmin, double tmax, double fmax, int garnish) {
-	long itmin, itmax, ntrack = Formant_getMinNumFormants (me);
+	integer itmin, itmax, ntrack = Formant_getMinNumFormants (me);
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) return;
 	Graphics_setInner (g);
 	Graphics_setWindow (g, tmin, tmax, 0.0, fmax);
-	for (long itrack = 1; itrack <= ntrack; itrack ++) {
-		for (long iframe = itmin; iframe < itmax; iframe ++) {
+	for (integer itrack = 1; itrack <= ntrack; itrack ++) {
+		for (integer iframe = itmin; iframe < itmax; iframe ++) {
 			Formant_Frame curFrame = & my d_frames [iframe], nextFrame = & my d_frames [iframe + 1];
 			double x1 = Sampled_indexToX (me, iframe), x2 = Sampled_indexToX (me, iframe + 1);
 			double f1 = curFrame -> formant [itrack]. frequency;
 			double f2 = nextFrame -> formant [itrack]. frequency;
-			if (NUMdefined (x1) && NUMdefined (f1) && NUMdefined (x2) && NUMdefined (f2))
+			if (isdefined (x1) && isdefined (f1) && isdefined (x2) && isdefined (f2))
 				Graphics_line (g, x1, f1, x2, f2);
 		}
 	}
@@ -143,7 +143,7 @@ void Formant_drawTracks (Formant me, Graphics g, double tmin, double tmax, doubl
 void Formant_drawSpeckles_inside (Formant me, Graphics g, double tmin, double tmax, double fmin, double fmax,
 	double suppress_dB)
 {
-	long itmin, itmax;
+	integer itmin, itmax;
 	double maximumIntensity = 0.0, minimumIntensity;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) return;
@@ -235,9 +235,9 @@ void Formant_getExtrema (Formant me, int iformant, double tmin, double tmax, dou
 	if (fmax) *fmax = 0.0;
 	if (iformant < 1) return;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-	long itmin, itmax;
+	integer itmin, itmax;
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) return;
-	for (long iframe = itmin; iframe <= itmax; iframe ++) {
+	for (integer iframe = itmin; iframe <= itmax; iframe ++) {
 		Formant_Frame frame = & my d_frames [iframe];
 		if (iformant > frame -> nFormants) continue;
 		double f = frame -> formant [iformant]. frequency;
@@ -251,7 +251,7 @@ void Formant_getMinimumAndTime (Formant me, int iformant, double tmin, double tm
 	double *return_minimum, double *return_timeOfMinimum)
 {
 	Sampled_getMinimumAndX (me, tmin, tmax, iformant << 1, bark, interpolate, return_minimum, return_timeOfMinimum);
-	if (return_minimum && *return_minimum <= 0.0) *return_minimum = NUMundefined;
+	if (return_minimum && *return_minimum <= 0.0) *return_minimum = undefined;
 }
 
 double Formant_getMinimum (Formant me, int iformant, double tmin, double tmax, int bark, int interpolate) {
@@ -270,7 +270,7 @@ void Formant_getMaximumAndTime (Formant me, int iformant, double tmin, double tm
 	double *return_maximum, double *return_timeOfMaximum)
 {
 	Sampled_getMaximumAndX (me, tmin, tmax, iformant << 1, bark, interpolate, return_maximum, return_timeOfMaximum);
-	if (return_maximum && *return_maximum <= 0.0) *return_maximum = NUMundefined;   // unlikely
+	if (return_maximum && *return_maximum <= 0.0) *return_maximum = undefined;   // unlikely
 }
 
 double Formant_getMaximum (Formant me, int iformant, double tmin, double tmax, int bark, int interpolate) {
@@ -294,14 +294,14 @@ double Formant_getMean (Formant me, int iformant, double tmin, double tmax, int
 }
 
 double Formant_getStandardDeviation (Formant me, int iformant, double tmin, double tmax, int bark) {
-	if (iformant < 1 || tmin == NUMundefined || tmax == NUMundefined) return NUMundefined;
+	if (iformant < 1 || isundef (tmin) || isundef (tmax)) return undefined;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-	long itmin, itmax;
-	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) return NUMundefined;
+	integer itmin, itmax;
+	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) return undefined;
 	double mean = Formant_getMean (me, iformant, tmin, tmax, bark);
 	double sum = 0.0;
-	long n = 0;
-	for (long iframe = itmin; iframe <= itmax; iframe ++) {
+	integer n = 0;
+	for (integer iframe = itmin; iframe <= itmax; iframe ++) {
 		Formant_Frame frame = & my d_frames [iframe];
 		if (iformant > frame -> nFormants) continue;
 		double f = frame -> formant [iformant]. frequency;
@@ -311,7 +311,7 @@ double Formant_getStandardDeviation (Formant me, int iformant, double tmin, doub
 		sum += (f - mean) * (f - mean);
 	}
 	if (n > 1) return sqrt (sum / (n - 1));
-	return NUMundefined;
+	return undefined;
 }
 
 double Formant_getValueAtTime (Formant me, int iformant, double time, int bark) {
@@ -332,7 +332,7 @@ void Formant_scatterPlot (Formant me, Graphics g, double tmin, double tmax,
 {
 	if (iformant1 < 1 || iformant2 < 1) return;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-	long itmin, itmax;
+	integer itmin, itmax;
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax)) return;
 	if (fmax1 == fmin1)
 		Formant_getExtrema (me, iformant1, tmin, tmax, & fmin1, & fmax1);
@@ -496,9 +496,9 @@ autoTable Formant_downto_Table (Formant me, bool includeFrameNumbers,
 					Table_setStringValue (thee.get(), iframe, ++ icol, Melder_fixed (formant -> bandwidth, frequencyDecimals));
 			}
 			for (long iformant = frame -> nFormants + 1; iformant <= my maxnFormants; iformant ++) {
-				Table_setNumericValue (thee.get(), iframe, ++ icol, NUMundefined);
+				Table_setNumericValue (thee.get(), iframe, ++ icol, undefined);
 				if (includeBandwidths)
-					Table_setNumericValue (thee.get(), iframe, ++ icol, NUMundefined);
+					Table_setNumericValue (thee.get(), iframe, ++ icol, undefined);
 			}
 		}
 		return thee;
diff --git a/fon/FormantGrid.cpp b/fon/FormantGrid.cpp
index b6f7334..ee9e188 100644
--- a/fon/FormantGrid.cpp
+++ b/fon/FormantGrid.cpp
@@ -1,6 +1,6 @@
 /* FormantGrid.cpp
  *
- * Copyright (C) 2008-2011,2014,2015,2016 Paul Boersma & David Weenink
+ * Copyright (C) 2008-2011,2014,2015,2016,2017 Paul Boersma & David Weenink
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -137,12 +137,12 @@ void FormantGrid_addBandwidthPoint (FormantGrid me, long iformant, double t, dou
 }
 
 double FormantGrid_getFormantAtTime (FormantGrid me, long iformant, double t) {
-	if (iformant < 1 || iformant > my formants.size) return NUMundefined;
+	if (iformant < 1 || iformant > my formants.size) return undefined;
 	return RealTier_getValueAtTime (my formants.at [iformant], t);
 }
 
 double FormantGrid_getBandwidthAtTime (FormantGrid me, long iformant, double t) {
-	if (iformant < 1 || iformant > my bandwidths.size) return NUMundefined;
+	if (iformant < 1 || iformant > my bandwidths.size) return undefined;
 	return RealTier_getValueAtTime (my bandwidths.at [iformant], t);
 }
 
@@ -170,7 +170,7 @@ void Sound_FormantGrid_filter_inline (Sound me, FormantGrid formantGrid) {
 				double formant, bandwidth;
 				formant = RealTier_getValueAtTime (formantTier, t);
 				bandwidth = RealTier_getValueAtTime (bandwidthTier, t);
-				if (NUMdefined (formant) && NUMdefined (bandwidth)) {
+				if (isdefined (formant) && isdefined (bandwidth)) {
 					double cosomdt = cos (2 * NUMpi * formant * dt);
 					double r = exp (- NUMpi * bandwidth * dt);
 					/* Formants at 0 Hz or the Nyquist are single poles, others are double poles. */
@@ -256,9 +256,9 @@ void FormantGrid_formula_bandwidths (FormantGrid me, const char32 *expression, I
 		for (long irow = 1; irow <= my formants.size; irow ++) {
 			RealTier bandwidth = thy bandwidths.at [irow];
 			for (long icol = 1; icol <= bandwidth -> points.size; icol ++) {
-				struct Formula_Result result;
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
-				if (result. result.numericResult == NUMundefined)
+				if (isundef (result. result.numericResult))
 					Melder_throw (U"Cannot put an undefined value into the tier.\nFormula not finished.");
 				bandwidth -> points.at [icol] -> value = result. result.numericResult;
 			}
@@ -275,9 +275,9 @@ void FormantGrid_formula_frequencies (FormantGrid me, const char32 *expression,
 		for (long irow = 1; irow <= my formants.size; irow ++) {
 			RealTier formant = thy formants.at [irow];
 			for (long icol = 1; icol <= formant -> points.size; icol ++) {
-				struct Formula_Result result;
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
-				if (result. result.numericResult == NUMundefined)
+				if (isundef (result. result.numericResult))
 					Melder_throw (U"Cannot put an undefined value into the tier.\nFormula not finished.");
 				formant -> points.at [icol] -> value = result. result.numericResult;
 			}
diff --git a/fon/FormantTier.cpp b/fon/FormantTier.cpp
index 017de43..226a9f1 100644
--- a/fon/FormantTier.cpp
+++ b/fon/FormantTier.cpp
@@ -1,6 +1,6 @@
 /* FormantTier.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -75,15 +75,15 @@ autoFormantTier FormantTier_create (double tmin, double tmax) {
 
 double FormantTier_getValueAtTime (FormantTier me, int iformant, double t) {
 	long n = my points.size;
-	if (n == 0 || iformant < 1) return NUMundefined;
+	if (n == 0 || iformant < 1) return undefined;
 	FormantPoint pointRight = my points.at [1];
 	if (t <= pointRight -> number) {
-		if (iformant > pointRight -> numberOfFormants) return NUMundefined;
+		if (iformant > pointRight -> numberOfFormants) return undefined;
 		return pointRight -> formant [iformant-1];   // constant extrapolation
 	}
 	FormantPoint pointLeft = my points.at [n];
 	if (t >= pointLeft -> number) {
-		if (iformant > pointLeft -> numberOfFormants) return NUMundefined;
+		if (iformant > pointLeft -> numberOfFormants) return undefined;
 		return pointLeft -> formant [iformant-1];   // constant extrapolation
 	}
 	Melder_assert (n >= 2);
@@ -92,11 +92,11 @@ double FormantTier_getValueAtTime (FormantTier me, int iformant, double t) {
 	pointLeft = my points.at [ileft];
 	pointRight = my points.at [iright];
 	double tleft = pointLeft -> number;
-	double fleft = iformant > pointLeft -> numberOfFormants ? NUMundefined : pointLeft -> formant [iformant-1];
+	double fleft = ( iformant > pointLeft -> numberOfFormants ? undefined : pointLeft -> formant [iformant-1] );
 	double tright = pointRight -> number;
-	double fright = iformant > pointRight -> numberOfFormants ? NUMundefined : pointRight -> formant [iformant-1];
-	return fleft == NUMundefined ? fright == NUMundefined ? NUMundefined : fright
-		: fright == NUMundefined ? fleft
+	double fright = ( iformant > pointRight -> numberOfFormants ? undefined : pointRight -> formant [iformant-1] );
+	return isundef (fleft) ? ( isundef (fright) ? undefined : fright )
+		: isundef (fright) ? fleft
 		: t == tright ? fright   // be very accurate
 		: tleft == tright ? 0.5 * (fleft + fright)   // unusual, but possible; no preference
 		: fleft + (t - tleft) * (fright - fleft) / (tright - tleft);   // linear interpolation
@@ -107,12 +107,12 @@ double FormantTier_getBandwidthAtTime (FormantTier me, int iformant, double t) {
 	if (n == 0) return 0.0;
 	FormantPoint pointRight = my points.at [1];
 	if (t <= pointRight -> number) {
-		if (iformant > pointRight -> numberOfFormants) return NUMundefined;
+		if (iformant > pointRight -> numberOfFormants) return undefined;
 		return pointRight -> bandwidth [iformant-1];   // constant extrapolation
 	}
 	FormantPoint pointLeft = my points.at [n];
 	if (t >= pointLeft -> number) {
-		if (iformant > pointLeft -> numberOfFormants) return NUMundefined;
+		if (iformant > pointLeft -> numberOfFormants) return undefined;
 		return pointLeft -> bandwidth [iformant-1];   // constant extrapolation
 	}
 	Melder_assert (n >= 2);
@@ -121,11 +121,11 @@ double FormantTier_getBandwidthAtTime (FormantTier me, int iformant, double t) {
 	pointLeft = my points.at [ileft];
 	pointRight = my points.at [iright];
 	double tleft = pointLeft -> number;
-	double fleft = iformant > pointLeft -> numberOfFormants ? NUMundefined : pointLeft -> bandwidth [iformant-1];
+	double fleft = iformant > pointLeft -> numberOfFormants ? undefined : pointLeft -> bandwidth [iformant-1];
 	double tright = pointRight -> number;
-	double fright = iformant > pointRight -> numberOfFormants ? NUMundefined : pointRight -> bandwidth [iformant-1];
-	return fleft == NUMundefined ? fright == NUMundefined ? NUMundefined : fright
-		: fright == NUMundefined ? fleft
+	double fright = iformant > pointRight -> numberOfFormants ? undefined : pointRight -> bandwidth [iformant-1];
+	return isundef (fleft) ? ( isundef (fright) ? undefined : fright )
+		: isundef (fright) ? fleft
 		: t == tright ? fright   // be very accurate
 		: tleft == tright ? 0.5 * (fleft + fright)   // unusual, but possible; no preference
 		: fleft + (t - tleft) * (fright - fleft) / (tright - tleft);   // linear interpolation
@@ -185,10 +185,10 @@ autoFormantTier Formant_PointProcess_to_FormantTier (Formant me, PointProcess pp
 			long iformant = 1;
 			for (; iformant <= 10; iformant ++) {
 				double value = FormantTier_getValueAtTime (temp.get(), iformant, time);
-				if (value == NUMundefined) break;
+				if (isundef (value)) break;
 				point -> formant [iformant-1] = value;
 				value = FormantTier_getBandwidthAtTime (temp.get(), iformant, time);
-				Melder_assert (value != NUMundefined);
+				Melder_assert (isdefined (value));
 				point -> bandwidth [iformant-1] = value;
 			}
 			point -> numberOfFormants = iformant - 1;
@@ -263,7 +263,7 @@ void Sound_FormantTier_filter_inline (Sound me, FormantTier formantTier) {
 			double formant, bandwidth;
 			formant = FormantTier_getValueAtTime (formantTier, iformant, t);
 			bandwidth = FormantTier_getBandwidthAtTime (formantTier, iformant, t);
-			if (NUMdefined (formant) && NUMdefined (bandwidth)) {
+			if (isdefined (formant) && isdefined (bandwidth)) {
 				double cosomdt = cos (2 * NUMpi * formant * dt);
 				double r = exp (- NUMpi * bandwidth * dt);
 				/* Formants at 0 Hz or the Nyquist are single poles, others are double poles. */
diff --git a/fon/FormantTier_def.h b/fon/FormantTier_def.h
index 5ccc252..23593c6 100644
--- a/fon/FormantTier_def.h
+++ b/fon/FormantTier_def.h
@@ -1,6 +1,6 @@
 /* FormantTier_def.h
  *
- * Copyright (C) 1992-2002,2015 Paul Boersma
+ * Copyright (C) 1992-2002,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
 #define ooSTRUCT FormantPoint
 oo_DEFINE_CLASS (FormantPoint, AnyPoint)
 
-	oo_INT (numberOfFormants)
+	oo_INT16 (numberOfFormants)
 	oo_DOUBLE_ARRAY (formant, 10, numberOfFormants)
 	oo_DOUBLE_ARRAY (bandwidth, 10, numberOfFormants)
 
diff --git a/fon/Formant_def.h b/fon/Formant_def.h
index 756cbbe..c1a9304 100644
--- a/fon/Formant_def.h
+++ b/fon/Formant_def.h
@@ -45,7 +45,7 @@ oo_DEFINE_STRUCT (Formant_Frame)
 		oo_DOUBLE (intensity)
 	oo_ENDFROM
 
-	oo_INT (nFormants)
+	oo_INT16 (nFormants)
 	oo_STRUCT_VECTOR (Formant_Formant, formant, nFormants)
 
 oo_END_STRUCT (Formant_Frame)
@@ -56,7 +56,7 @@ oo_END_STRUCT (Formant_Frame)
 #define ooSTRUCT Formant
 oo_DEFINE_CLASS (Formant, Sampled)
 
-	oo_INT (maxnFormants)
+	oo_INT16 (maxnFormants)
 	oo_STRUCT_VECTOR (Formant_Frame, d_frames, nx)
 
 	#if oo_DECLARING
diff --git a/fon/Function.cpp b/fon/Function.cpp
index 818e6a0..e6775ea 100644
--- a/fon/Function.cpp
+++ b/fon/Function.cpp
@@ -1,6 +1,6 @@
 /* Function.cpp
  *
- * Copyright (C) 1992-2012,2015 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -84,15 +84,15 @@ bool Function_isUnitLogarithmic (Function me, long ilevel, int unit) {
 }
 
 double Function_convertStandardToSpecialUnit (Function me, double value, long ilevel, int unit) {
-	return NUMdefined (value) ? my v_convertStandardToSpecialUnit (value, ilevel, unit) : NUMundefined;
+	return isdefined (value) ? my v_convertStandardToSpecialUnit (value, ilevel, unit) : undefined;
 }
 
 double Function_convertSpecialToStandardUnit (Function me, double value, long ilevel, int unit) {
-	return NUMdefined (value) ? my v_convertSpecialToStandardUnit (value, ilevel, unit) : NUMundefined;
+	return isdefined (value) ? my v_convertSpecialToStandardUnit (value, ilevel, unit) : undefined;
 }
 
 double Function_convertToNonlogarithmic (Function me, double value, long ilevel, int unit) {
-	return NUMdefined (value) && my v_isUnitLogarithmic (ilevel, unit) ? pow (10.0, value) : value;
+	return isdefined (value) && my v_isUnitLogarithmic (ilevel, unit) ? pow (10.0, value) : value;
 }
 
 void Function_shiftXBy (Function me, double shift) {
diff --git a/fon/FunctionEditor.cpp b/fon/FunctionEditor.cpp
index e57f6e9..994d374 100644
--- a/fon/FunctionEditor.cpp
+++ b/fon/FunctionEditor.cpp
@@ -68,7 +68,7 @@ static void updateScrollBar (FunctionEditor me) {
 	if (value < 1.0) value = 1.0;
 	double increment = slider_size / SCROLL_INCREMENT_FRACTION + 1.0;
 	double page_increment = RELATIVE_PAGE_INCREMENT * slider_size + 1.0;
-	GuiScrollBar_set (my scrollBar, NUMundefined, maximumScrollBarValue, value, slider_size, increment, page_increment);
+	GuiScrollBar_set (my scrollBar, undefined, maximumScrollBarValue, value, slider_size, increment, page_increment);
 }
 
 static void updateGroup (FunctionEditor me) {
@@ -218,7 +218,7 @@ static void drawNow (FunctionEditor me) {
 		double bottom = my rect [i]. bottom, top = my rect [i]. top;
 		if (left < right) {
 			const char *format = my v_format_long ();
-			double value = NUMundefined, inverseValue = 0.0;
+			double value = undefined, inverseValue = 0.0;
 			switch (i) {
 				case 0: format = my v_format_totalDuration (), value = my tmax - my tmin; break;
 				case 1: format = my v_format_window (), value = my endWindow - my startWindow;
@@ -1552,7 +1552,7 @@ void FunctionEditor_ungroup (FunctionEditor me) {
 }
 
 void FunctionEditor_drawRangeMark (FunctionEditor me, double yWC, const char32 *yWC_string, const char32 *units, int verticalAlignment) {
-	static MelderString text { 0 };
+	static MelderString text { };
 	MelderString_copy (& text, yWC_string, units);
 	double textWidth = Graphics_textWidth (my graphics.get(), text.string) + Graphics_dxMMtoWC (my graphics.get(), 0.5);
 	Graphics_setColour (my graphics.get(), Graphics_BLUE);
@@ -1585,7 +1585,7 @@ void FunctionEditor_insertCursorFunctionValue (FunctionEditor me, double yWC, co
 	} else if (tooLow) {
 		textY = minimum + Graphics_dyMMtoWC (my graphics.get(), 5.0);
 	}
-	static MelderString text { 0 };
+	static MelderString text { };
 	MelderString_copy (& text, yWC_string, units);
 	double textWidth = Graphics_textWidth (my graphics.get(), text.string);
 	Graphics_fillCircle_mm (my graphics.get(), my endWindow + textWidth + Graphics_dxMMtoWC (my graphics.get(), 1.5), textY, 1.5);
diff --git a/fon/Harmonicity.cpp b/fon/Harmonicity.cpp
index a306577..43cf89a 100644
--- a/fon/Harmonicity.cpp
+++ b/fon/Harmonicity.cpp
@@ -1,6 +1,6 @@
 /* Harmonicity.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,44 +23,44 @@ Thing_implement (Harmonicity, Vector, 2);
 
 double Harmonicity_getMean (Harmonicity me, double tmin, double tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-	long imin, imax;
-	long n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
-	if (n < 1) return NUMundefined;
-	double sum = 0.0;
+	integer imin, imax;
+	integer n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
+	if (n < 1) return undefined;
+	real80 sum = 0.0;
 	long nSounding = 0;
 	for (long i = imin; i <= imax; i ++) {
 		if (my z [1] [i] != -200.0) {
 			nSounding ++;
-			sum += my z [1] [i];
+			sum += (real80) my z [1] [i];
 		}
 	}
-	if (nSounding < 1) return NUMundefined;
-	return sum / nSounding;
+	if (nSounding < 1) return undefined;
+	return (real) sum / nSounding;
 }
 
 double Harmonicity_getStandardDeviation (Harmonicity me, double tmin, double tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
-	long imin, imax;
-	long n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
-	if (n < 1) return NUMundefined;
-	double sum = 0.0;
+	integer imin, imax;
+	integer n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
+	if (n < 1) return undefined;
+	real80 sum = 0.0;
 	long nSounding = 0;
-	for (long i = imin; i <= imax; i ++) {
+	for (integer i = imin; i <= imax; i ++) {
 		if (my z [1] [i] != -200.0) {
 			nSounding ++;
-			sum += my z [1] [i];
+			sum += (real80) my z [1] [i];
 		}
 	}
-	if (nSounding < 2) return NUMundefined;
-	double mean = sum / nSounding;
-	double sumOfSquares = 0.0;
-	for (long i = imin; i <= imax; i ++) {
+	if (nSounding < 2) return undefined;
+	real80 mean = sum / nSounding;
+	real80 sumOfSquares = 0.0;
+	for (integer i = imin; i <= imax; i ++) {
 		if (my z [1] [i] != -200.0) {
-			double d = my z [1] [i] - mean;
+			real80 d = (real80) my z [1] [i] - mean;
 			sumOfSquares += d * d;
 		}
 	}
-	return sqrt (sumOfSquares / (nSounding - 1));
+	return sqrt ((real) sumOfSquares / (nSounding - 1));
 }
 
 double Harmonicity_getQuantile (Harmonicity me, double quantile) {
diff --git a/fon/Intensity.cpp b/fon/Intensity.cpp
index 6ba7db8..8344267 100644
--- a/fon/Intensity.cpp
+++ b/fon/Intensity.cpp
@@ -91,7 +91,7 @@ void Intensity_drawInside (Intensity me, Graphics g, double tmin, double tmax, d
 		tmin = my xmin;   // autowindow
 		tmax = my xmax;
 	}
-	long itmin, itmax;
+	integer itmin, itmax;
 	Matrix_getWindowSamplesX (me, tmin, tmax, & itmin, & itmax);
 	if (maximum <= minimum)
 		Matrix_getWindowExtrema (me, itmin, itmax, 1, 1, & minimum, & maximum);   // autoscale
diff --git a/fon/LongSound.cpp b/fon/LongSound.cpp
index 6848ee4..ae5a0e6 100644
--- a/fon/LongSound.cpp
+++ b/fon/LongSound.cpp
@@ -325,13 +325,13 @@ void LongSound_readAudioToShort (LongSound me, int16 *buffer, long firstSample,
 	}
 }
 
-autoSound LongSound_extractPart (LongSound me, double tmin, double tmax, int preserveTimes) {
+autoSound LongSound_extractPart (LongSound me, double tmin, double tmax, bool preserveTimes) {
 	try {
 		if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 		if (tmin < my xmin) tmin = my xmin;
 		if (tmax > my xmax) tmax = my xmax;
-		long imin, imax;
-		long n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
+		integer imin, imax;
+		integer n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
 		if (n < 1) Melder_throw (U"Less than 1 sample in window.");
 		autoSound thee = Sound_create (my numberOfChannels, tmin, tmax, n, my dx, my x1 + (imin - 1) * my dx);
 		if (! preserveTimes) thy xmin = 0.0, thy xmax -= tmin, thy x1 -= tmin;
@@ -369,8 +369,8 @@ void LongSound_savePartAsAudioFile (LongSound me, int audioFileType, double tmin
 		if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 		if (tmin < my xmin) tmin = my xmin;
 		if (tmax > my xmax) tmax = my xmax;
-		long imin, imax;
-		long n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
+		integer imin, imax;
+		integer n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
 		if (n < 1) Melder_throw (U"Less than 1 sample selected.");
 		autoMelderFile mfile = MelderFile_create (file);
 		MelderFile_writeAudioFileHeader (file, audioFileType, my sampleRate, n, my numberOfChannels, numberOfBitsPerSamplePoint);
@@ -479,15 +479,15 @@ static void _LongSound_haveSamples (LongSound me, long imin, long imax) {
 }
 
 bool LongSound_haveWindow (LongSound me, double tmin, double tmax) {
-	long imin, imax;
-	long n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
+	integer imin, imax;
+	integer n = Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
 	if ((1.0 + 2 * MARGIN) * n + 1 > my nmax) return false;
 	_LongSound_haveSamples (me, imin, imax);
 	return true;
 }
 
 void LongSound_getWindowExtrema (LongSound me, double tmin, double tmax, int channel, double *minimum, double *maximum) {
-	long imin, imax;
+	integer imin, imax;
 	(void) Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
 	*minimum = 1.0;
 	*maximum = -1.0;
@@ -538,7 +538,7 @@ void LongSound_playPart (LongSound me, double tmin, double tmax,
 	Melder_free (thy resampledBuffer);   // just in case, and after playing has stopped
 	try {
 		int fits = LongSound_haveWindow (me, tmin, tmax);
-		long bestSampleRate = MelderAudio_getOutputBestSampleRate (my sampleRate), n, i1, i2;
+		integer bestSampleRate = MelderAudio_getOutputBestSampleRate (my sampleRate), n, i1, i2;
 		if (! fits)
 			Melder_throw (U"Sound too long (", tmax - tmin, U" seconds).");
 		/*
diff --git a/fon/LongSound.h b/fon/LongSound.h
index 849757a..e5facda 100644
--- a/fon/LongSound.h
+++ b/fon/LongSound.h
@@ -58,7 +58,7 @@ Thing_define (LongSound, Sampled) {
 
 autoLongSound LongSound_open (MelderFile file);
 
-autoSound LongSound_extractPart (LongSound me, double tmin, double tmax, int preserveTimes);
+autoSound LongSound_extractPart (LongSound me, double tmin, double tmax, bool preserveTimes);
 
 bool LongSound_haveWindow (LongSound me, double tmin, double tmax);
 /*
diff --git a/fon/Ltas.cpp b/fon/Ltas.cpp
index 69b40be..1ae80fc 100644
--- a/fon/Ltas.cpp
+++ b/fon/Ltas.cpp
@@ -1,6 +1,6 @@
 /* Ltas.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -86,7 +86,7 @@ void Ltas_draw (Ltas me, Graphics g, double fmin, double fmax, double minimum, d
 double Ltas_getSlope (Ltas me, double f1min, double f1max, double f2min, double f2max, int averagingUnits) {
 	double low = Sampled_getMean (me, f1min, f1max, 0, averagingUnits, false);
 	double high = Sampled_getMean (me, f2min, f2max, 0, averagingUnits, false);
-	if (low == NUMundefined || high == NUMundefined) return NUMundefined;
+	if (isundef (low) || isundef (high)) return undefined;
 	return averagingUnits == 3 ? high - low : Function_convertSpecialToStandardUnit (me, high / low, 0, averagingUnits);
 }
 
@@ -94,7 +94,7 @@ double Ltas_getLocalPeakHeight (Ltas me, double environmentMin, double environme
 	double environmentLow = Sampled_getMean (me, environmentMin, peakMin, 0, averagingUnits, false);
 	double environmentHigh = Sampled_getMean (me, peakMax, environmentMax, 0, averagingUnits, false);
 	double peak = Sampled_getMean (me, peakMin, peakMax, 0, averagingUnits, false);
-	if (environmentLow == NUMundefined || environmentHigh == NUMundefined || peak == NUMundefined) return NUMundefined;
+	if (isundef (environmentLow) || isundef (environmentHigh) || isundef (peak)) return undefined;
 	return averagingUnits == 3 ? peak - 0.5 * (environmentLow + environmentHigh) :
 		Function_convertSpecialToStandardUnit (me, peak / (0.5 * (environmentLow + environmentHigh)), 0, averagingUnits);
 }
@@ -178,32 +178,32 @@ autoLtas Ltas_computeTrendLine (Ltas me, double fmin, double fmax) {
 		/*
 		 * Find the first and last bin.
 		 */
-		long imin, imax, n;
+		integer imin, imax, n;
 		if ((n = Sampled_getWindowSamples (me, fmin, fmax, & imin, & imax)) < 2)
 			Melder_throw (U"Number of bins too low (", n, U"). Should be at least 2.");
 		autoLtas thee = Data_copy (me);
 		/*
 		 * Compute average amplitude and frequency.
 		 */
-		double sum = 0.0, amean, fmean, numerator = 0.0, denominator = 0.0, slope;
-		for (long i = imin; i <= imax; i ++) {
+		real80 sum = 0.0, numerator = 0.0, denominator = 0.0;
+		for (integer i = imin; i <= imax; i ++) {
 			sum += thy z [1] [i];
 		}
-		amean = sum / n;
-		fmean = thy x1 + (0.5 * (imin + imax) - 1) * thy dx;
+		real amean = real (sum / n);
+		real fmean = thy x1 + (0.5 * (imin + imax) - 1) * thy dx;
 		/*
 		 * Compute slope.
 		 */
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double da = thy z [1] [i] - amean, df = thy x1 + (i - 1) * thy dx - fmean;
 			numerator += da * df;
 			denominator += df * df;
 		}
-		slope = numerator / denominator;
+		real slope = real (numerator / denominator);
 		/*
 		 * Modify bins.
 		 */
-		for (long i = 1; i <= thy nx; i ++) {
+		for (integer i = 1; i <= thy nx; i ++) {
 			double df = thy x1 + (i - 1) * thy dx - fmean;
 			thy z [1] [i] = amean + slope * df;
 		}
@@ -218,7 +218,7 @@ autoLtas Ltas_subtractTrendLine (Ltas me, double fmin, double fmax) {
 		/*
 		 * Find the first and last bin.
 		 */
-		long imin, imax, n;
+		integer imin, imax, n;
 		if ((n = Sampled_getWindowSamples (me, fmin, fmax, & imin, & imax)) < 2)
 			Melder_throw (U"Number of bins too low (", n, U"). Should be at least 2.");
 		autoLtas thee = Data_copy (me);
@@ -261,7 +261,7 @@ autoLtas Ltas_subtractTrendLine (Ltas me, double fmin, double fmax) {
 
 autoLtas Spectrum_to_Ltas (Spectrum me, double bandWidth) {
 	try {
-		long numberOfBands = ceil ((my xmax - my xmin) / bandWidth);
+		integer numberOfBands = (integer) ceil ((my xmax - my xmin) / bandWidth);
 		if (bandWidth <= my dx)
 			Melder_throw (U"Bandwidth must be greater than ", my dx, U".");
 		autoLtas thee = Thing_new (Ltas);
@@ -311,7 +311,7 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 {
 	try {
 		long numberOfPeriods = pulses -> nt - 2, totalNumberOfEnergies = 0;
-		autoLtas ltas = Ltas_create (maximumFrequency / bandWidth, bandWidth);
+		autoLtas ltas = Ltas_create ((integer) floor (maximumFrequency / bandWidth), bandWidth);
 		ltas -> xmax = maximumFrequency;
 		autoLtas numbers = Data_copy (ltas.get());
 		if (numberOfPeriods < 1)
@@ -338,7 +338,7 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 					double realPart = spectrum -> z [1] [ifreq];
 					double imaginaryPart = spectrum -> z [2] [ifreq];
 					double energy = (realPart * realPart + imaginaryPart * imaginaryPart) * 2.0 * spectrum -> dx /* OLD: * sound -> nx */;
-					long iband = ceil (frequency / bandWidth);
+					integer iband = (integer) ceil (frequency / bandWidth);
 					if (iband >= 1 && iband <= ltas -> nx) {
 						ltas -> z [1] [iband] += energy;
 						numbers -> z [1] [iband] += 1;
@@ -351,16 +351,16 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 		}
 		if (numberOfPeriods < 1)
 			Melder_throw (U"There are no periods in the point process.");
-		for (long iband = 1; iband <= ltas -> nx; iband ++) {
+		for (integer iband = 1; iband <= ltas -> nx; iband ++) {
 			if (numbers -> z [1] [iband] == 0.0) {
-				ltas -> z [1] [iband] = NUMundefined;
+				ltas -> z [1] [iband] = undefined;
 			} else {
 				/*
 				 * Each bin now contains a total energy in Pa2 sec.
 				 * To convert this to power density, we
 				 */
 				double totalEnergyInThisBand = ltas -> z [1] [iband];
-				if (0 /* i.e. if you just want to have a spectrum of the voiced parts... */) {
+				if (false /* i.e. if you just want to have a spectrum of the voiced parts... */) {
 					double energyDensityInThisBand = totalEnergyInThisBand / ltas -> dx;
 					double powerDensityInThisBand = energyDensityInThisBand / (sound -> xmax - sound -> xmin);
 					ltas -> z [1] [iband] = 10.0 * log10 (powerDensityInThisBand / 4.0e-10);
@@ -379,10 +379,10 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 			}
 		}
 		for (long iband = 1; iband <= ltas -> nx; iband ++) {
-			if (ltas -> z [1] [iband] == NUMundefined) {
+			if (isundef (ltas -> z [1] [iband])) {
 				long ibandleft = iband - 1, ibandright = iband + 1;
-				while (ibandleft >= 1 && ltas -> z [1] [ibandleft] == NUMundefined) ibandleft --;
-				while (ibandright <= ltas -> nx && ltas -> z [1] [ibandright] == NUMundefined) ibandright ++;
+				while (ibandleft >= 1 && isundef (ltas -> z [1] [ibandleft])) ibandleft --;
+				while (ibandright <= ltas -> nx && isundef (ltas -> z [1] [ibandright])) ibandright ++;
 				if (ibandleft < 1 && ibandright > ltas -> nx)
 					Melder_throw (U"Cannot create an Ltas without energy in any bins.");
 				if (ibandleft < 1) {
diff --git a/fon/Makefile b/fon/Makefile
index 5650181..68b1c0c 100644
--- a/fon/Makefile
+++ b/fon/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "fon"
-# Paul Boersma, 27 October 2016
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../sys -I ../dwsys -I ../stat -I ../dwtools -I ../LPC -I ../fon -I ../external/portaudio -I ../external/flac -I ../external/mp3
+CPPFLAGS = -I ../kar -I ../sys -I ../dwsys -I ../stat -I ../dwtools -I ../LPC -I ../fon -I ../external/portaudio -I ../external/flac -I ../external/mp3
 
 OBJECTS = Transition.o Distributions_and_Transition.o \
    Function.o Sampled.o SampledXY.o Matrix.o Vector.o Polygon.o PointProcess.o \
@@ -54,4 +54,4 @@ libfon.a: $(OBJECTS)
 	$(AR) cq libfon.a $(OBJECTS)
 	$(RANLIB) libfon.a
 
-$(OBJECTS): *.h ../num/NUM.h ../external/portaudio/*.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../LPC/*.h ../external/flac/*.h ../external/mp3/mp3.h
+$(OBJECTS): *.h ../external/portaudio/*.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../LPC/*.h ../external/flac/*.h ../external/mp3/mp3.h
diff --git a/fon/ManipulationEditor.cpp b/fon/ManipulationEditor.cpp
index 2b6495a..d5b8607 100644
--- a/fon/ManipulationEditor.cpp
+++ b/fon/ManipulationEditor.cpp
@@ -1,6 +1,6 @@
 /* ManipulationEditor.cpp
  *
- * Copyright (C) 1992-2011,2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -427,15 +427,15 @@ static void menu_cb_setDurationRange (ManipulationEditor me, EDITOR_ARGS_FORM) {
 	EDITOR_DO
 		Manipulation ana = (Manipulation) my data;
 		double minimum = GET_REAL (U"Minimum"), maximum = GET_REAL (U"Maximum");
-		double minimumValue = ana -> duration ? RealTier_getMinimumValue (ana -> duration.get()) : NUMundefined;
-		double maximumValue = ana -> duration ? RealTier_getMaximumValue (ana -> duration.get()) : NUMundefined;
+		double minimumValue = ana -> duration ? RealTier_getMinimumValue (ana -> duration.get()) : undefined;
+		double maximumValue = ana -> duration ? RealTier_getMaximumValue (ana -> duration.get()) : undefined;
 		if (minimum > 1) Melder_throw (U"Minimum relative duration must not be greater than 1.");
 		if (maximum < 1) Melder_throw (U"Maximum relative duration must not be less than 1.");
 		if (minimum >= maximum) Melder_throw (U"Maximum relative duration must be greater than minimum.");
-		if (NUMdefined (minimumValue) && minimum > minimumValue)
+		if (isdefined (minimumValue) && minimum > minimumValue)
 			Melder_throw (U"Minimum relative duration must not be greater than the minimum value present, "
 				U"which is ", Melder_half (minimumValue), U".");
-		if (NUMdefined (maximumValue) && maximum < maximumValue)
+		if (isdefined (maximumValue) && maximum < maximumValue)
 			Melder_throw (U"Maximum relative duration must not be less than the maximum value present, "
 				U"which is ", Melder_half (maximumValue), U".");
 		my pref_duration_minimum () = my p_duration_minimum = minimum;
@@ -598,7 +598,6 @@ static void drawSoundArea (ManipulationEditor me, double ymin, double ymax) {
 	Manipulation ana = (Manipulation) my data;
 	Sound sound = ana -> sound.get();
 	PointProcess pulses = ana -> pulses.get();
-	long first, last, i;
 	Graphics_Viewport viewport = Graphics_insetViewport (my graphics.get(), 0.0, 1.0, ymin, ymax);
 	Graphics_setWindow (my graphics.get(), 0.0, 1.0, 0.0, 1.0);
 	Graphics_setColour (my graphics.get(), Graphics_WHITE);
@@ -618,7 +617,7 @@ static void drawSoundArea (ManipulationEditor me, double ymin, double ymax) {
 	if (pulses) {
 		Graphics_setWindow (my graphics.get(), my startWindow, my endWindow, 0.0, 1.0);
 		Graphics_setColour (my graphics.get(), Graphics_BLUE);
-		for (i = 1; i <= pulses -> nt; i ++) {
+		for (integer i = 1; i <= pulses -> nt; i ++) {
 			double t = pulses -> t [i];
 			if (t >= my startWindow && t <= my endWindow)
 				Graphics_line (my graphics.get(), t, 0.05, t, 0.95);
@@ -628,6 +627,7 @@ static void drawSoundArea (ManipulationEditor me, double ymin, double ymax) {
 	/*
 	 * Draw sound.
 	 */
+	integer first, last;
 	if (sound && Sampled_getWindowSamples (sound, my startWindow, my endWindow, & first, & last) > 1) {
 		double minimum, maximum, scaleMin, scaleMax;
 		Matrix_getWindowExtrema (sound, first, last, 1, 1, & minimum, & maximum);
@@ -1223,21 +1223,21 @@ autoManipulationEditor ManipulationEditor_create (const char32 *title, Manipulat
 		} else {
 			my p_pitch_minimum = -24.0;
 			my pitchTier.minPeriodic = -12.0;
-			my p_pitch_maximum = NUMdefined (maximumPitchValue) ? NUMhertzToSemitones (maximumPitchValue) : NUMundefined;
+			my p_pitch_maximum = ( isdefined (maximumPitchValue) ? NUMhertzToSemitones (maximumPitchValue) : undefined );
 			my pitchTier.cursor = my p_pitch_maximum - 4.0;
 			my p_pitch_maximum += 3.0;
 		}
-		if (my p_pitch_maximum == NUMundefined || my p_pitch_maximum < my pref_pitch_maximum ())
+		if (isundef (my p_pitch_maximum) || my p_pitch_maximum < my pref_pitch_maximum ())
 			my p_pitch_maximum = my pref_pitch_maximum ();
 
-		double minimumDurationValue = ana -> duration ? RealTier_getMinimumValue (ana -> duration.get()) : NUMundefined;
-		my p_duration_minimum = NUMdefined (minimumDurationValue) ? minimumDurationValue : 1.0;
+		double minimumDurationValue = ( ana -> duration ? RealTier_getMinimumValue (ana -> duration.get()) : undefined );
+		my p_duration_minimum = ( isdefined (minimumDurationValue) ? minimumDurationValue : 1.0 );
 		if (my pref_duration_minimum () > 1)
 			my pref_duration_minimum () = Melder_atof (my default_duration_minimum ());
 		if (my p_duration_minimum > my pref_duration_minimum ())
 			my p_duration_minimum = my pref_duration_minimum ();
-		double maximumDurationValue = ana -> duration ? RealTier_getMaximumValue (ana -> duration.get()) : NUMundefined;
-		my p_duration_maximum = NUMdefined (maximumDurationValue) ? maximumDurationValue : 1.0;
+		double maximumDurationValue = ( ana -> duration ? RealTier_getMaximumValue (ana -> duration.get()) : undefined );
+		my p_duration_maximum = ( isdefined (maximumDurationValue) ? maximumDurationValue : 1.0 );
 		if (my pref_duration_maximum () < 1)
 			my pref_duration_maximum () = Melder_atof (my default_duration_maximum ());
 		if (my pref_duration_maximum () <= my pref_duration_minimum ()) {
diff --git a/fon/Manipulation_def.h b/fon/Manipulation_def.h
index a01f716..9a1dd62 100644
--- a/fon/Manipulation_def.h
+++ b/fon/Manipulation_def.h
@@ -1,6 +1,6 @@
 /* Manipulation_def.h
  *
- * Copyright (C) 1992-2008,2015 Paul Boersma
+ * Copyright (C) 1992-2008,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ oo_DEFINE_CLASS (Manipulation, Function)
 		oo_DOUBLE (dummy12)
 		oo_AUTO_OBJECT (Intensity, 0, dummyIntensityAnalysis)
 		oo_AUTO_OBJECT (Formant, 1, dummyFormantAnalysis)
-		oo_INT (dummy4)
+		oo_INT16 (dummy4)
 		oo_DOUBLE (dummy5)
 		oo_DOUBLE (dummy6)
 		oo_DOUBLE (dummy7)
diff --git a/fon/Matrix.cpp b/fon/Matrix.cpp
index 5476c6a..864dbd6 100644
--- a/fon/Matrix.cpp
+++ b/fon/Matrix.cpp
@@ -1,6 +1,6 @@
 /* Matrix.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -60,16 +60,16 @@ void structMatrix :: v_info () {
 
 void structMatrix :: v_readText (MelderReadText text, int formatVersion) {
 	if (formatVersion < 0) {
-		our xmin = texgetr8 (text);
-		our xmax = texgetr8 (text);
-		our ymin = texgetr8 (text);
-		our ymax = texgetr8 (text);
-		our nx = texgeti4 (text);
-		our ny = texgeti4 (text);
-		our dx = texgetr8 (text);
-		our dy = texgetr8 (text);
-		our x1 = texgetr8 (text);
-		our y1 = texgetr8 (text);
+		our xmin = texgetr64 (text);
+		our xmax = texgetr64 (text);
+		our ymin = texgetr64 (text);
+		our ymax = texgetr64 (text);
+		our nx = texgeti32 (text);
+		our ny = texgeti32 (text);
+		our dx = texgetr64 (text);
+		our dy = texgetr64 (text);
+		our x1 = texgetr64 (text);
+		our y1 = texgetr64 (text);
 	} else {
 		Matrix_Parent :: v_readText (text, formatVersion);
 	}
@@ -85,12 +85,12 @@ void structMatrix :: v_readText (MelderReadText text, int formatVersion) {
 		Melder_throw (U"dx should be greater than 0.0.");
 	if (our dy <= 0.0)
 		Melder_throw (U"dy should be greater than 0.0.");
-	our z = NUMmatrix_readText_r8 (1, our ny, 1, our nx, text, "z");
+	our z = NUMmatrix_readText_r64 (1, our ny, 1, our nx, text, "z");
 }
 
 double structMatrix :: v_getValueAtSample (long isamp, long ilevel, int unit) {
 	double value = our z [ilevel] [isamp];
-	return NUMdefined (value) ? our v_convertStandardToSpecialUnit (value, ilevel, unit) : NUMundefined;
+	return ( isdefined (value) ? our v_convertStandardToSpecialUnit (value, ilevel, unit) : undefined );
 }
 
 double structMatrix :: v_getMatrix (long irow, long icol) {
@@ -102,7 +102,7 @@ double structMatrix :: v_getMatrix (long irow, long icol) {
 double structMatrix :: v_getFunction2 (double x, double y) {
 	double rrow = (y - our y1) / our dy + 1.0;
 	double rcol = (x - our x1) / our dx + 1.0;
-	long irow = (long) floor (rrow), icol = (long) floor (rcol);
+	integer irow = (integer) floor (rrow), icol = (integer) floor (rcol);
 	double drow = rrow - irow, dcol = rcol - icol;
 	double z1 = irow < 1 || irow >  our ny || icol < 1 || icol >  our nx ? 0.0 : z [irow]     [icol];
 	double z2 = irow < 0 || irow >= our ny || icol < 1 || icol >  our nx ? 0.0 : z [irow + 1] [icol];
@@ -112,8 +112,8 @@ double structMatrix :: v_getFunction2 (double x, double y) {
 }
 
 void Matrix_init
-	(Matrix me, double xmin, double xmax, long nx, double dx, double x1,
-	            double ymin, double ymax, long ny, double dy, double y1)
+	(Matrix me, double xmin, double xmax, integer nx, double dx, double x1,
+	            double ymin, double ymax, integer ny, double dy, double y1)
 {
 	Sampled_init (me, xmin, xmax, nx, dx, x1);
 	my ymin = ymin;
@@ -125,8 +125,8 @@ void Matrix_init
 }
 
 autoMatrix Matrix_create
-	(double xmin, double xmax, long nx, double dx, double x1,
-	 double ymin, double ymax, long ny, double dy, double y1)
+	(double xmin, double xmax, integer nx, double dx, double x1,
+	 double ymin, double ymax, integer ny, double dy, double y1)
 {
 	try {
 		autoMatrix me = Thing_new (Matrix);
@@ -137,7 +137,7 @@ autoMatrix Matrix_create
 	}
 }
 
-autoMatrix Matrix_createSimple (long numberOfRows, long numberOfColumns) {
+autoMatrix Matrix_createSimple (integer numberOfRows, integer numberOfColumns) {
 	try {
 		autoMatrix me = Thing_new (Matrix);
 		Matrix_init (me.get(), 0.5, numberOfColumns + 0.5, numberOfColumns, 1, 1,
@@ -154,39 +154,39 @@ double Matrix_rowToY (Matrix me, double row) { return my y1 + (row - 1.0) * my d
 
 double Matrix_xToColumn (Matrix me, double x) { return (x - my x1) / my dx + 1.0; }
 
-long Matrix_xToLowColumn (Matrix me, double x) { return (long) floor (Matrix_xToColumn (me, x)); }
+integer Matrix_xToLowColumn (Matrix me, double x) { return (integer) floor (Matrix_xToColumn (me, x)); }
 
-long Matrix_xToHighColumn (Matrix me, double x) { return (long) ceil (Matrix_xToColumn (me, x)); }
+integer Matrix_xToHighColumn (Matrix me, double x) { return (integer) ceil (Matrix_xToColumn (me, x)); }
 
-long Matrix_xToNearestColumn (Matrix me, double x) { return (long) floor (Matrix_xToColumn (me, x) + 0.5); }
+integer Matrix_xToNearestColumn (Matrix me, double x) { return (integer) floor (Matrix_xToColumn (me, x) + 0.5); }
 
 double Matrix_yToRow (Matrix me, double y) { return (y - my y1) / my dy + 1.0; }
 
-long Matrix_yToLowRow (Matrix me, double y) { return (long) floor (Matrix_yToRow (me, y)); }
+integer Matrix_yToLowRow (Matrix me, double y) { return (integer) floor (Matrix_yToRow (me, y)); }
 
-long Matrix_yToHighRow (Matrix me, double y) { return (long) ceil (Matrix_yToRow (me, y)); }
+integer Matrix_yToHighRow (Matrix me, double y) { return (integer) ceil (Matrix_yToRow (me, y)); }
 
-long Matrix_yToNearestRow (Matrix me, double y) { return (long) floor (Matrix_yToRow (me, y) + 0.5); }
+integer Matrix_yToNearestRow (Matrix me, double y) { return (integer) floor (Matrix_yToRow (me, y) + 0.5); }
 
-long Matrix_getWindowSamplesX (Matrix me, double xmin, double xmax, long *ixmin, long *ixmax) {
-	*ixmin = 1 + (long) ceil  ((xmin - my x1) / my dx);
-	*ixmax = 1 + (long) floor ((xmax - my x1) / my dx);
+integer Matrix_getWindowSamplesX (Matrix me, double xmin, double xmax, integer *ixmin, integer *ixmax) {
+	*ixmin = 1 + (integer) ceil  ((xmin - my x1) / my dx);
+	*ixmax = 1 + (integer) floor ((xmax - my x1) / my dx);
 	if (*ixmin < 1) *ixmin = 1;
 	if (*ixmax > my nx) *ixmax = my nx;
 	if (*ixmin > *ixmax) return 0;
 	return *ixmax - *ixmin + 1;
 }
 
-long Matrix_getWindowSamplesY (Matrix me, double ymin, double ymax, long *iymin, long *iymax) {
-	*iymin = 1 + (long) ceil  ((ymin - my y1) / my dy);
-	*iymax = 1 + (long) floor ((ymax - my y1) / my dy);
+integer Matrix_getWindowSamplesY (Matrix me, double ymin, double ymax, integer *iymin, integer *iymax) {
+	*iymin = 1 + (integer) ceil  ((ymin - my y1) / my dy);
+	*iymax = 1 + (integer) floor ((ymax - my y1) / my dy);
 	if (*iymin < 1) *iymin = 1;
 	if (*iymax > my ny) *iymax = my ny;
 	if (*iymin > *iymax) return 0;
 	return *iymax - *iymin + 1;
 }
 
-long Matrix_getWindowExtrema (Matrix me, long ixmin, long ixmax, long iymin, long iymax,
+integer Matrix_getWindowExtrema (Matrix me, integer ixmin, integer ixmax, integer iymin, integer iymax,
 	double *minimum, double *maximum)
 {
 	if (ixmin == 0) ixmin = 1;
@@ -195,8 +195,8 @@ long Matrix_getWindowExtrema (Matrix me, long ixmin, long ixmax, long iymin, lon
 	if (iymax == 0) iymax = my ny;
 	if (ixmin > ixmax || iymin > iymax) return 0;
 	*minimum = *maximum = my z [iymin] [ixmin];
-	for (long iy = iymin; iy <= iymax; iy ++) {
-		for (long ix = ixmin; ix <= ixmax; ix ++) {
+	for (integer iy = iymin; iy <= iymax; iy ++) {
+		for (integer ix = ixmin; ix <= ixmax; ix ++) {
 			if (my z [iy] [ix] < *minimum) *minimum = my z [iy] [ix];
 			if (my z [iy] [ix] > *maximum) *maximum = my z [iy] [ix];
 		}
@@ -205,25 +205,23 @@ long Matrix_getWindowExtrema (Matrix me, long ixmin, long ixmax, long iymin, lon
 }
 
 double Matrix_getValueAtXY (Matrix me, double x, double y) {
-	long bottomRow, leftCol, topRow, rightCol;
-	double drow, dcol;
-	double row_real = (y - my y1) / my dy + 1.0;
-	double col_real = (x - my x1) / my dx + 1.0;
+	real row_real = (y - my y1) / my dy + 1.0;
+	real col_real = (x - my x1) / my dx + 1.0;
 	/*
 	 * We imagine a unit square around every (xi, yi) point in the matrix.
 	 * For (x, y) values outside the union of these squares, the z value is undefined.
 	 */
-	if (row_real < 0.5 || row_real > my ny + 0.5) return NUMundefined;
-	if (col_real < 0.5 || col_real > my nx + 0.5) return NUMundefined;
+	if (row_real < 0.5 || row_real > my ny + 0.5) return undefined;
+	if (col_real < 0.5 || col_real > my nx + 0.5) return undefined;
 	/*
 	 * Determine the four nearest (xi, yi) points.
 	 */
-	bottomRow = (long) floor (row_real);   // 0 <= bottomRow <= my ny
-	topRow = bottomRow + 1;         // 1 <= topRow <= my ny + 1
-	leftCol = (long) floor (col_real);     // 0 <= leftCol <= my nx
-	rightCol = leftCol + 1;         // 1 <= rightCol <= my nx + 1
-	drow = row_real - bottomRow;    // 0.0 <= drow < 1.0
-	dcol = col_real - leftCol;      // 0.0 <= dcol < 1.0
+	integer bottomRow = (integer) floor (row_real);   // 0 <= bottomRow <= my ny
+	integer topRow = bottomRow + 1;         // 1 <= topRow <= my ny + 1
+	integer leftCol = (integer) floor (col_real);     // 0 <= leftCol <= my nx
+	integer rightCol = leftCol + 1;         // 1 <= rightCol <= my nx + 1
+	real drow = row_real - bottomRow;    // 0.0 <= drow < 1.0
+	real dcol = col_real - leftCol;      // 0.0 <= dcol < 1.0
 	/*
 	 * If adjacent points exist
 	 * (i.e., both row numbers are between 1 and my ny,
@@ -243,19 +241,19 @@ double Matrix_getValueAtXY (Matrix me, double x, double y) {
 }
 
 double Matrix_getSum (Matrix me) {
-	double sum = 0.0;
-	for (long row = 1; row <= my ny; row ++)
-		for (long col = 1; col <= my nx; col ++)
-			sum += my z [row] [col];
-	return sum;
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= my ny; irow ++)
+		for (integer icol = 1; icol <= my nx; icol ++)
+			sum += my z [irow] [icol];
+	return (real) sum;
 }
 
 double Matrix_getNorm (Matrix me) {
-	double sum = 0.0;
-	for (long row = 1; row <= my ny; row ++)
-		for (long col = 1; col <= my nx; col ++)
-			sum += my z [row] [col] * my z [row] [col];
-	return sqrt (sum);
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= my ny; irow ++)
+		for (integer icol = 1; icol <= my nx; icol ++)
+			sum += my z [irow] [icol] * my z [irow] [icol];
+	return sqrt ((real) sum);
 }
 
 void Matrix_drawRows (Matrix me, Graphics g, double xmin, double xmax, double ymin, double ymax,
@@ -263,7 +261,7 @@ void Matrix_drawRows (Matrix me, Graphics g, double xmin, double xmax, double ym
 {
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
 	if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	if (maximum <= minimum)
@@ -271,7 +269,7 @@ void Matrix_drawRows (Matrix me, Graphics g, double xmin, double xmax, double ym
 	if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
 	if (xmin >= xmax) return;
 	Graphics_setInner (g);
-	for (long iy = iymin; iy <= iymax; iy ++) {
+	for (integer iy = iymin; iy <= iymax; iy ++) {
 		Graphics_setWindow (g, xmin, xmax,
 			minimum - (iy - iymin) * (maximum - minimum),
 			maximum + (iymax - iy) * (maximum - minimum));
@@ -291,7 +289,7 @@ void Matrix_drawOneContour (Matrix me, Graphics g, double xmin, double xmax, dou
 	if (ymax == ymin) { ymin = my ymin; ymax = my ymax; }
 	if (xreversed) { double temp = xmin; xmin = xmax; xmax = temp; }
 	if (yreversed) { double temp = ymin; ymin = ymax; ymax = temp; }
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	if (xmin == xmax || ymin == ymax) return;
@@ -311,13 +309,13 @@ void Matrix_drawContours (Matrix me, Graphics g, double xmin, double xmax, doubl
 	double border [1 + 8];
 	if (xmax == xmin) { xmin = my xmin; xmax = my xmax; }
 	if (ymax == ymin) { ymin = my ymin; ymax = my ymax; }
-	long ixmin, ixmax, iymin, iymax, iborder;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	if (maximum <= minimum)
 		(void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
 	if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
-	for (iborder = 1; iborder <= 8; iborder ++)
+	for (integer iborder = 1; iborder <= 8; iborder ++)
 		border [iborder] = minimum + iborder * (maximum - minimum) / (8 + 1);
 	if (xmin == xmax || ymin == ymax) return;
 	Graphics_setInner (g);
@@ -336,13 +334,13 @@ void Matrix_paintContours (Matrix me, Graphics g, double xmin, double xmax, doub
 	double border [1 + 30];
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
 	if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
-	long ixmin, ixmax, iymin, iymax, iborder;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	if (maximum <= minimum)
 		(void) Matrix_getWindowExtrema (me, ixmin, ixmax, iymin, iymax, & minimum, & maximum);
 	if (maximum <= minimum) { minimum -= 1.0; maximum += 1.0; }
-	for (iborder = 1; iborder <= 30; iborder ++)
+	for (integer iborder = 1; iborder <= 30; iborder ++)
 		border [iborder] = minimum + iborder * (maximum - minimum) / (30 + 1);
 	if (xmin >= xmax || ymin >= ymax) return;
 	Graphics_setInner (g);
@@ -360,7 +358,7 @@ static void cellArrayOrImage (Matrix me, Graphics g, double xmin, double xmax, d
 {
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
 	if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx,
 		& ixmin, & ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy,
@@ -402,7 +400,7 @@ void Matrix_paintSurface (Matrix me, Graphics g, double xmin, double xmax, doubl
 {
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
 	if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	(void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 	(void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
 	if (maximum <= minimum)
@@ -421,8 +419,8 @@ void Matrix_movie (Matrix me, Graphics g) {
 	autoNUMvector <double> column (1, my ny);
 	double minimum = 0.0, maximum = 1.0;
 	Matrix_getWindowExtrema (me, 1, my nx, 1, my ny, & minimum, & maximum);
-	for (long icol = 1; icol <= my nx; icol ++) {
-		for (long irow = 1; irow <= my ny; irow ++) {
+	for (integer icol = 1; icol <= my nx; icol ++) {
+		for (integer irow = 1; irow <= my ny; irow ++) {
 			column [irow] = my z [irow] [icol];
 		}
 		Graphics_beginMovieFrame (g, & Graphics_WHITE);
@@ -436,8 +434,8 @@ autoMatrix Matrix_readAP (MelderFile file) {
 	try {
 		autofile f = Melder_fopen (file, "rb");
 		int16_t header [256];
-		for (long i = 0; i < 256; i ++)
-			header [i] = bingeti2LE (f);
+		for (integer i = 0; i < 256; i ++)
+			header [i] = bingeti16LE (f);
 		double samplingFrequency = header [100];   // converting up (from 16 to 54 bytes)
 		Melder_casual (U"Sampling frequency ", samplingFrequency);
 		autoMatrix me = Matrix_create (0.0, (double) header [34], header [34] /* Number of frames. */, 1.0, 0.5,
@@ -449,14 +447,14 @@ autoMatrix Matrix_readAP (MelderFile file) {
 							   Buffer.I2 [101]); (* Sampling frequency. *)*/
 		Melder_casual (U"... Loading ", header [34], U" frames",
 			U" of ", header [35], U" words ...");
-		for (long i = 1; i <= my nx; i ++)
-			for (long j = 1; j <= my ny; j ++)
-				my z [j] [i] = bingeti2LE (f);   // converting up (from 16 to 54 bytes)
+		for (integer i = 1; i <= my nx; i ++)
+			for (integer j = 1; j <= my ny; j ++)
+				my z [j] [i] = bingeti16LE (f);   // converting up (from 16 to 54 bytes)
 
 		/*
 		 * Get pitch frequencies.
 		 */
-		for (long i = 1; i <= my nx; i ++)
+		for (integer i = 1; i <= my nx; i ++)
 			if (my z [1] [i] != 0.0)
 				my z [1] [i] = - samplingFrequency / my z [1] [i];
 
@@ -474,11 +472,11 @@ autoMatrix Matrix_appendRows (Matrix me, Matrix thee, ClassInfo klas) {
 			my xmax > thy xmax ? my xmax : thy xmax,
 			my nx > thy nx ? my nx : thy nx, my dx, my x1 < thy x1 ? my x1 : thy x1,
 			my ymin, my ymax + (thy ymax - thy ymin), my ny + thy ny, my dy, my y1);
-		for (long irow = 1; irow <= my ny; irow ++)
-			for (long icol = 1; icol <= my nx; icol ++)
+		for (integer irow = 1; irow <= my ny; irow ++)
+			for (integer icol = 1; icol <= my nx; icol ++)
 				his z [irow] [icol] = my z [irow] [icol];
-		for (long irow = 1; irow <= thy ny; irow ++)
-			for (long icol = 1; icol <= thy nx; icol ++)
+		for (integer irow = 1; irow <= thy ny; irow ++)
+			for (integer icol = 1; icol <= thy nx; icol ++)
 				his z [irow + my ny] [icol] = thy z [irow] [icol];
 		return him;
 	} catch (MelderError) {
@@ -493,7 +491,7 @@ autoMatrix Matrix_readFromRawTextFile (MelderFile file) {   // BUG: not Unicode-
 		/*
 		 * Count number of columns.
 		 */
-		long ncol = 0;
+		integer ncol = 0;
 		for (;;) {
 			int kar = fgetc (f);
 			if (kar == '\n' || kar == '\r' || kar == EOF) break;
@@ -511,7 +509,7 @@ autoMatrix Matrix_readFromRawTextFile (MelderFile file) {   // BUG: not Unicode-
 		 * Count number of elements.
 		 */
 		rewind (f);
-		long nelements = 0;
+		integer nelements = 0;
 		for (;;) {
 			double element;
 			if (fscanf (f, "%lf", & element) < 1) break;   // zero or end-of-file
@@ -527,15 +525,15 @@ autoMatrix Matrix_readFromRawTextFile (MelderFile file) {   // BUG: not Unicode-
 		/*
 		 * Create simple matrix.
 		 */
-		long nrow = nelements / ncol;
+		integer nrow = nelements / ncol;
 		autoMatrix me = Matrix_createSimple (nrow, ncol);
 
 		/*
 		 * Read elements.
 		 */
 		rewind (f);
-		for (long irow = 1; irow <= nrow; irow ++)
-			for (long icol = 1; icol <= ncol; icol ++)
+		for (integer irow = 1; irow <= nrow; irow ++)
+			for (integer icol = 1; icol <= ncol; icol ++)
 				fscanf (f, "%lf", & my z [irow] [icol]);
 
 		f.close (file);
@@ -554,9 +552,9 @@ void Matrix_eigen (Matrix me, autoMatrix *out_eigenvectors, autoMatrix *out_eige
 		Eigen_initFromSymmetricMatrix (eigen.get(), my z, my nx);
 		autoMatrix eigenvectors = Data_copy (me);
 		autoMatrix eigenvalues = Matrix_create (1.0, 1.0, 1, 1.0, 1.0, my ymin, my ymax, my ny, my dy, my y1);
-		for (long i = 1; i <= my nx; i ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			eigenvalues -> z [i] [1] = eigen -> eigenvalues [i];
-			for (long j = 1; j <= my nx; j ++)
+			for (integer j = 1; j <= my nx; j ++)
 				eigenvectors -> z [i] [j] = eigen -> eigenvectors [j] [i];
 		}
 		*out_eigenvectors = eigenvectors.move();
@@ -566,18 +564,18 @@ void Matrix_eigen (Matrix me, autoMatrix *out_eigenvectors, autoMatrix *out_eige
 	}
 }
 
-autoMatrix Matrix_power (Matrix me, long power) {
+autoMatrix Matrix_power (Matrix me, integer power) {
 	try {
 		if (my nx != my ny)
 			Melder_throw (U"Matrix not square.");
 		autoMatrix thee = Data_copy (me);
 		autoMatrix him = Data_copy (me);
-		for (long ipow = 2; ipow <= power; ipow ++) {
+		for (integer ipow = 2; ipow <= power; ipow ++) {
 			double **tmp = his z; his z = thy z; thy z = tmp;
-			for (long irow = 1; irow <= my ny; irow ++) {
-				for (long icol = 1; icol <= my nx; icol ++) {
+			for (integer irow = 1; irow <= my ny; irow ++) {
+				for (integer icol = 1; icol <= my nx; icol ++) {
 					thy z [irow] [icol] = 0.0;
-					for (long i = 1; i <= my nx; i ++) {
+					for (integer i = 1; i <= my nx; i ++) {
 						thy z [irow] [icol] += his z [irow] [i] * my z [i] [icol];
 					}
 				}
@@ -592,12 +590,15 @@ autoMatrix Matrix_power (Matrix me, long power) {
 void Matrix_writeToMatrixTextFile (Matrix me, MelderFile file) {
 	try {
 		autofile f = Melder_fopen (file, "w");
-		fprintf (f, "\"ooTextFile\"\n\"Matrix\"\n%.17g %.17g %ld %.17g %.17g\n%.17g %.17g %ld %.17g %.17g\n",
-			my xmin, my xmax, (long) my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1);
-		for (long i = 1; i <= my ny; i ++) {
-			for (long j = 1; j <= my nx; j ++) {
+		fprintf (f, "\"ooTextFile\"\n\"Matrix\"\n%s %s %s %s %s\n%s %s %s %s %s\n",
+			Melder8_double (my xmin), Melder8_double (my xmax), Melder8_integer (my nx),
+				Melder8_double (my dx), Melder8_double (my x1),
+			Melder8_double (my ymin), Melder8_double (my ymax), Melder8_integer (my ny),
+				Melder8_double (my dy), Melder8_double (my y1));
+		for (integer i = 1; i <= my ny; i ++) {
+			for (integer j = 1; j <= my nx; j ++) {
 				if (j > 1) fprintf (f, " ");
-				fprintf (f, "%.17g", my z [i] [j]);
+				fprintf (f, "%s", Melder8_double (my z [i] [j]));
 			}
 			fprintf (f, "\n");
 		}
@@ -610,8 +611,8 @@ void Matrix_writeToMatrixTextFile (Matrix me, MelderFile file) {
 void Matrix_writeToHeaderlessSpreadsheetFile (Matrix me, MelderFile file) {
 	try {
 		autofile f = Melder_fopen (file, "w");
-		for (long i = 1; i <= my ny; i ++) {
-			for (long j = 1; j <= my nx; j ++) {
+		for (integer i = 1; i <= my ny; i ++) {
+			for (integer j = 1; j <= my nx; j ++) {
 				if (j > 1) fprintf (f, "\t");
 				fprintf (f, "%s", Melder8_single (my z [i] [j]));
 			}
@@ -625,11 +626,11 @@ void Matrix_writeToHeaderlessSpreadsheetFile (Matrix me, MelderFile file) {
 
 void Matrix_formula (Matrix me, const char32 *expression, Interpreter interpreter, Matrix target) {
 	try {
-		struct Formula_Result result;
+		Formula_Result result;
 		Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		if (! target) target = me;
-		for (long irow = 1; irow <= my ny; irow ++) {
-			for (long icol = 1; icol <= my nx; icol ++) {
+		for (integer irow = 1; irow <= my ny; irow ++) {
+			for (integer icol = 1; icol <= my nx; icol ++) {
 				Formula_run (irow, icol, & result);
 				target -> z [irow] [icol] = result. result.numericResult;
 			}
@@ -645,14 +646,14 @@ void Matrix_formula_part (Matrix me, double xmin, double xmax, double ymin, doub
 	try {
 		if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
 		if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
-		long ixmin, ixmax, iymin, iymax;
+		integer ixmin, ixmax, iymin, iymax;
 		(void) Matrix_getWindowSamplesX (me, xmin, xmax, & ixmin, & ixmax);
 		(void) Matrix_getWindowSamplesY (me, ymin, ymax, & iymin, & iymax);
-		struct Formula_Result result;
+		Formula_Result result;
 		Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		if (! target) target = me;
-		for (long irow = iymin; irow <= iymax; irow ++) {
-			for (long icol = ixmin; icol <= ixmax; icol ++) {
+		for (integer irow = iymin; irow <= iymax; irow ++) {
+			for (integer icol = ixmin; icol <= ixmax; icol ++) {
 				Formula_run (irow, icol, & result);
 				target -> z [irow] [icol] = result. result.numericResult;
 			}
@@ -664,8 +665,8 @@ void Matrix_formula_part (Matrix me, double xmin, double xmax, double ymin, doub
 
 void Matrix_scaleAbsoluteExtremum (Matrix me, double scale) {
 	double extremum = 0.0;
-	for (long i = 1; i <= my ny; i ++) {
-		for (long j = 1; j <= my nx; j ++) {
+	for (integer i = 1; i <= my ny; i ++) {
+		for (integer j = 1; j <= my nx; j ++) {
 			if (fabs (my z [i] [j]) > extremum) {
 				extremum = fabs (my z [i] [j]);
 			}
@@ -673,8 +674,8 @@ void Matrix_scaleAbsoluteExtremum (Matrix me, double scale) {
 	}
 	if (extremum != 0.0) {
 		double factor = scale / extremum;
-		for (long i = 1; i <= my ny; i ++) {
-			for (long j = 1; j <= my nx; j ++) {
+		for (integer i = 1; i <= my ny; i ++) {
+			for (integer j = 1; j <= my nx; j ++) {
 				my z [i] [j] *= factor;
 			}
 		}
@@ -684,8 +685,8 @@ void Matrix_scaleAbsoluteExtremum (Matrix me, double scale) {
 autoMatrix TableOfReal_to_Matrix (TableOfReal me) {
 	try {
 		autoMatrix thee = Matrix_createSimple (my numberOfRows, my numberOfColumns);
-		for (long i = 1; i <= my numberOfRows; i ++)
-			for (long j = 1; j <= my numberOfColumns; j ++)
+		for (integer i = 1; i <= my numberOfRows; i ++)
+			for (integer j = 1; j <= my numberOfColumns; j ++)
 				thy z [i] [j] = my data [i] [j];
 		return thee;
 	} catch (MelderError) {
@@ -696,8 +697,8 @@ autoMatrix TableOfReal_to_Matrix (TableOfReal me) {
 autoTableOfReal Matrix_to_TableOfReal (Matrix me) {
 	try {
 		autoTableOfReal thee = TableOfReal_create (my ny, my nx);
-		for (long i = 1; i <= my ny; i ++)
-			for (long j = 1; j <= my nx; j ++)
+		for (integer i = 1; i <= my ny; i ++)
+			for (integer j = 1; j <= my nx; j ++)
 				thy data [i] [j] = my z [i] [j];
 		return thee;
 	} catch (MelderError) {
@@ -708,12 +709,12 @@ autoTableOfReal Matrix_to_TableOfReal (Matrix me) {
 autoMatrix Table_to_Matrix (Table me) {
 	try {
 		autoMatrix thee = Matrix_createSimple (my rows.size, my numberOfColumns);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			Table_numericize_Assert (me, icol);
 		}
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 				thy z [irow] [icol] = row -> cells [icol]. number;
 			}
 		}
diff --git a/fon/Matrix.h b/fon/Matrix.h
index c0cb55f..21e779f 100644
--- a/fon/Matrix.h
+++ b/fon/Matrix.h
@@ -36,12 +36,12 @@ template <typename T, typename... Args>
 #endif
 
 void Matrix_init
-	(Matrix me, double xmin, double xmax, long nx, double dx, double x1,
-	            double ymin, double ymax, long ny, double dy, double y1);
+	(Matrix me, double xmin, double xmax, integer nx, double dx, double x1,
+	            double ymin, double ymax, integer ny, double dy, double y1);
 
 autoMatrix Matrix_create
-	(double xmin, double xmax, long nx, double dx, double x1,
-	 double ymin, double ymax, long ny, double dy, double y1);
+	(double xmin, double xmax, integer nx, double dx, double x1,
+	 double ymin, double ymax, integer ny, double dy, double y1);
 /*
 	Function:
 		return a new empty Matrix.
@@ -66,7 +66,7 @@ autoMatrix Matrix_create
 		result -> z [1..ny] [1..nx] == 0.0;
 */
 
-autoMatrix Matrix_createSimple (long numberOfRows, long numberOfColumns);
+autoMatrix Matrix_createSimple (integer numberOfRows, integer numberOfColumns);
 /*
 	Function:
 		return a new empty Matrix.
@@ -108,7 +108,7 @@ autoMatrix Matrix_createSimple (long numberOfRows, long numberOfColumns);
 			you cannot use them to change the meaning or order of the data.
 */
 
-long Matrix_getWindowSamplesX (Matrix me, double xmin, double xmax, long *ixmin, long *ixmax);
+integer Matrix_getWindowSamplesX (Matrix me, double xmin, double xmax, integer *ixmin, integer *ixmax);
 /*
 	Function:
 		return the number of samples with x values in [xmin, xmax].
@@ -125,7 +125,7 @@ double Matrix_getValueAtXY (Matrix me, double x, double y);
 /*
 	Linear interpolation between matrix points,
 	constant extrapolation in cells on the edge,
-	NUMundefined outside the union of the unit squares around the points.
+	undefined outside the union of the unit squares around the points.
 */
 
 double Matrix_getSum (Matrix me);
@@ -137,23 +137,23 @@ double Matrix_rowToY (Matrix me, double row);   // return my y1 + (row - 1) * my
 
 double Matrix_xToColumn (Matrix me, double x);   // return (x - xmin) / my dx + 1
 
-long Matrix_xToLowColumn (Matrix me, double x);   // return floor (Matrix_xToColumn (me, x))
+integer Matrix_xToLowColumn (Matrix me, double x);   // return floor (Matrix_xToColumn (me, x))
 
-long Matrix_xToHighColumn (Matrix me, double x);   // return ceil (Matrix_xToColumn (me, x))
+integer Matrix_xToHighColumn (Matrix me, double x);   // return ceil (Matrix_xToColumn (me, x))
 
-long Matrix_xToNearestColumn (Matrix me, double x);   // return floor (Matrix_xToColumn (me, x) + 0.5)
+integer Matrix_xToNearestColumn (Matrix me, double x);   // return floor (Matrix_xToColumn (me, x) + 0.5)
 
 double Matrix_yToRow (Matrix me, double y);   // return (y - ymin) / my dy + 1
 
-long Matrix_yToLowRow (Matrix me, double y);   // return floor (Matrix_yToRow (me, y))
+integer Matrix_yToLowRow (Matrix me, double y);   // return floor (Matrix_yToRow (me, y))
 
-long Matrix_yToHighRow (Matrix me, double x);   // return ceil (Matrix_yToRow (me, y))
+integer Matrix_yToHighRow (Matrix me, double x);   // return ceil (Matrix_yToRow (me, y))
 
-long Matrix_yToNearestRow (Matrix me, double y);   // return floor (Matrix_yToRow (me, y) + 0.5)
+integer Matrix_yToNearestRow (Matrix me, double y);   // return floor (Matrix_yToRow (me, y) + 0.5)
 
-long Matrix_getWindowSamplesY (Matrix me, double ymin, double ymax, long *iymin, long *iymax);
+integer Matrix_getWindowSamplesY (Matrix me, double ymin, double ymax, integer *iymin, integer *iymax);
 
-long Matrix_getWindowExtrema (Matrix me, long ixmin, long ixmax, long iymin, long iymax,
+integer Matrix_getWindowExtrema (Matrix me, integer ixmin, integer ixmax, integer iymin, integer iymax,
 	double *minimum, double *maximum);
 /*
 	Function:
@@ -243,7 +243,7 @@ autoMatrix Matrix_readAP (MelderFile file);
 autoMatrix Matrix_appendRows (Matrix me, Matrix thee, ClassInfo klas);
 
 void Matrix_eigen (Matrix me, autoMatrix *eigenvectors, autoMatrix *eigenvalues);
-autoMatrix Matrix_power (Matrix me, long power);
+autoMatrix Matrix_power (Matrix me, integer power);
 
 void Matrix_scaleAbsoluteExtremum (Matrix me, double scale);
 
diff --git a/fon/Matrix_and_Pitch.cpp b/fon/Matrix_and_Pitch.cpp
index 4736253..ecd84cc 100644
--- a/fon/Matrix_and_Pitch.cpp
+++ b/fon/Matrix_and_Pitch.cpp
@@ -1,6 +1,6 @@
 /* Matrix_and_Pitch.cpp
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,24 +16,17 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-/*
- * pb 2002/07/16 GPL
- * pb 2007/08/12 wchar
- * pb 2009/01/18 Interpreter argument to formula
- * pb 2009/04/04 corrected voiceless frames in Pitch_to_Matrix
- * pb 2011/06/04 C++
- */
-
 #include "Matrix_and_Pitch.h"
 
 autoMatrix Pitch_to_Matrix (Pitch me) {
 	try {
-		autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1, 1, 1, 1, 1);
-		for (long i = 1; i <= my nx; i ++) {
+		autoMatrix you = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1.0, 1.0, 1, 1.0, 1.0);
+		for (integer i = 1; i <= my nx; i ++) {
 			double value = my frame [i]. candidate [1]. frequency;
-			thy z [1] [i] = value > 0.0 && value < my ceiling ? my frame [i]. candidate [1]. frequency : 0.0;
+			your z [1] [i] =
+				value > 0.0 && value < my ceiling ? my frame [i]. candidate [1]. frequency : 0.0;
 		}
-		return thee;
+		return you;
 	} catch (MelderError) {
 		Melder_throw (me, U": not converted to Matrix.");
 	}
@@ -41,23 +34,23 @@ autoMatrix Pitch_to_Matrix (Pitch me) {
 
 autoPitch Matrix_to_Pitch (Matrix me) {
 	try {
-		autoPitch thee = Pitch_create (my xmin, my xmax, my nx, my dx, my x1, 5000, 2);
-		for (long i = 1; i <= my nx; i ++) {
-			Pitch_Frame frame = & thy frame [i];
+		autoPitch you = Pitch_create (my xmin, my xmax, my nx, my dx, my x1, 5000.0, 2);
+		for (integer i = 1; i <= my nx; i ++) {
+			Pitch_Frame frame = & your frame [i];
 			if (my z [1] [i] == 0.0) {
 				Pitch_Frame_init (frame, 1);
-				frame->candidate[1].frequency = 0.0;   // voiceless candidate always present
-				frame->candidate[1].strength = 0.4;
+				frame -> candidate [1]. frequency = 0.0;   // voiceless candidate always present
+				frame -> candidate [1]. strength = 0.4;
 			} else {
 				Pitch_Frame_init (frame, 2);
-				frame->intensity = 1;
-				frame->candidate[1].frequency = my z [1] [i];
-				frame->candidate[1].strength = 0.9;
-				frame->candidate[2].frequency = 0.0;   // voiceless candidate always present
-				frame->candidate[2].strength = 0.4;
+				frame -> intensity = 1;
+				frame -> candidate [1]. frequency = my z [1] [i];
+				frame -> candidate [1]. strength = 0.9;
+				frame -> candidate [2]. frequency = 0.0;   // voiceless candidate always present
+				frame -> candidate [2]. strength = 0.4;
 			}
 		}
-		return thee;
+		return you;
 	} catch (MelderError) {
 		Melder_throw (me, U": not converted to Pitch.");
 	}
@@ -65,16 +58,16 @@ autoPitch Matrix_to_Pitch (Matrix me) {
 
 void Pitch_formula (Pitch me, const char32 *formula, Interpreter interpreter) {
 	try {
-		autoMatrix m = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1, my maxnCandidates, my maxnCandidates, 1, 1);
-		for (long iframe = 1; iframe <= my nx; iframe ++) {
+		autoMatrix m = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1.0, my maxnCandidates, my maxnCandidates, 1.0, 1.0);
+		for (integer iframe = 1; iframe <= my nx; iframe ++) {
 			Pitch_Frame frame = & my frame [iframe];
-			for (long icand = 1; icand <= frame -> nCandidates; icand ++)
+			for (integer icand = 1; icand <= frame -> nCandidates; icand ++)
 				m -> z [icand] [iframe] = frame -> candidate [icand]. frequency;
 		}
 		Matrix_formula (m.get(), formula, interpreter, nullptr);
-		for (long iframe = 1; iframe <= my nx; iframe ++) {
+		for (integer iframe = 1; iframe <= my nx; iframe ++) {
 			Pitch_Frame frame = & my frame [iframe];
-			for (long icand = 1; icand <= frame -> nCandidates; icand ++)
+			for (integer icand = 1; icand <= frame -> nCandidates; icand ++)
 				frame -> candidate [icand]. frequency = m -> z [icand] [iframe];
 		}
 	} catch (MelderError) {
diff --git a/fon/Matrix_and_PointProcess.cpp b/fon/Matrix_and_PointProcess.cpp
index 993df9d..bf660b5 100644
--- a/fon/Matrix_and_PointProcess.cpp
+++ b/fon/Matrix_and_PointProcess.cpp
@@ -1,6 +1,6 @@
 /* Matrix_and_PointProcess.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,10 +22,10 @@ autoMatrix PointProcess_to_Matrix (PointProcess me) {
 	try {
 		if (my nt == 0)
 			Melder_throw (U"No times in PointProcess.");
-		autoMatrix thee = Matrix_create (1.0, my nt, my nt, 1.0, 1.0, 1.0, 1.0, 1, 1.0, 1.0);
-		for (long i = 1; i <= my nt; i ++)
-			thy z [1] [i] = my t [i];
-		return thee;
+		autoMatrix you = Matrix_create (1.0, my nt, my nt, 1.0, 1.0, 1.0, 1.0, 1, 1.0, 1.0);
+		for (integer i = 1; i <= my nt; i ++)
+			your z [1] [i] = my t [i];
+		return you;
 	} catch (MelderError) {
 		Melder_throw (me, U": not converted to Matrix.");
 	}
@@ -33,11 +33,11 @@ autoMatrix PointProcess_to_Matrix (PointProcess me) {
 
 autoPointProcess Matrix_to_PointProcess (Matrix me) {
 	try {
-		autoPointProcess thee = PointProcess_create (my z [1] [1], my z [1] [my nx], my nx);
-		for (long i = 1; i <= my nx; i ++) {
-			PointProcess_addPoint (thee.get(), my z [1] [i]);
+		autoPointProcess you = PointProcess_create (my z [1] [1], my z [1] [my nx], my nx);
+		for (integer i = 1; i <= my nx; i ++) {
+			PointProcess_addPoint (you.get(), my z [1] [i]);
 		}
-		return thee;
+		return you;
 	} catch (MelderError) {
 		Melder_throw (me, U": not converted to PointProcess.");
 	}
diff --git a/fon/Matrix_and_PointProcess.h b/fon/Matrix_and_PointProcess.h
index adf3af0..57ef4a3 100644
--- a/fon/Matrix_and_PointProcess.h
+++ b/fon/Matrix_and_PointProcess.h
@@ -1,6 +1,6 @@
 /* Matrix_and_PointProcess.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,13 +24,13 @@ autoMatrix PointProcess_to_Matrix (PointProcess me);
 	Function:
 		create a Matrix from a PointProcess.
 	Postconditions:
-		thy xmin == 1;
-		thy xmax == my numberOfEvents;
-		thy nx == my numberOfEvents;
-		thy dx == 1;
-		thy x1 == 1;
-		thy ymin ymax ny dy y1 == 1;
-		for (ievent in 1..my numberOfEvents) thy z [1] [ievent] == my event [ievent];
+		your xmin == 1;
+		your xmax == my numberOfEvents;
+		your nx == my numberOfEvents;
+		your dx == 1;
+		your x1 == 1;
+		your ymin ymax ny dy y1 == 1;
+		for (ievent in 1..my numberOfEvents) your z [1] [ievent] == my event [ievent];
 */
 
 autoPointProcess Matrix_to_PointProcess (Matrix me);
@@ -38,9 +38,9 @@ autoPointProcess Matrix_to_PointProcess (Matrix me);
 	Function:
 		create a PointProcess from a Matrix.
 	Postconditions:
-		thy maximumNumberOfEvents == my nx;
-		thy numberOfEvents == my nx;
-		for (ix in 1..my nx) thy event [ix] == my z [1] [ix];
+		your maximumNumberOfEvents == my nx;
+		your numberOfEvents == my nx;
+		for (ix in 1..my nx) your event [ix] == my z [1] [ix];
 */
 
 /* End of file Matrix_and_PointProcess.h */
diff --git a/fon/Movie.cpp b/fon/Movie.cpp
index 0abdd2e..dae4aa9 100644
--- a/fon/Movie.cpp
+++ b/fon/Movie.cpp
@@ -1,6 +1,6 @@
 /* Movie.cpp
  *
- * Copyright (C) 2011-2012,2015,2016 Paul Boersma
+ * Copyright (C) 2011-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -73,7 +73,7 @@ autoMovie Movie_openFromSoundFile (MelderFile file)
 		*extensionLocation = U'\0';
 		fileNameHead.length = extensionLocation - fileNameHead.string;
 		autoStrings strings = Strings_createAsFileList (Melder_cat (fileNameHead.string, U"*.png"));
-		struct structMelderDir folder;
+		structMelderDir folder { };
 		MelderFile_getParentDir (file, & folder);
 		Movie_init (me.get(), sound.move(), Melder_dirToPath (& folder), strings.move());
 		return me;
@@ -89,9 +89,9 @@ void Movie_paintOneImageInside (Movie me, Graphics graphics, long frameNumber, d
 		if (frameNumber > my nx) Melder_throw (U"Specified frame number is ", frameNumber, U" but there are only ", my nx, U"frames.");
 		Melder_assert (my d_fileNames);
 		Melder_assert (my d_fileNames -> numberOfStrings == my nx);
-		struct structMelderDir folder;
+		structMelderDir folder { };
 		Melder_pathToDir (my d_folderName, & folder);
-		struct structMelderFile file;
+		structMelderFile file { };
 		MelderDir_getFile (& folder, my d_fileNames -> strings [frameNumber], & file);
 		Graphics_imageFromFile (graphics, Melder_fileToPath (& file), xmin, xmax, ymin, ymax);
 	} catch (MelderError) {
diff --git a/fon/Photo.cpp b/fon/Photo.cpp
index 6b6115c..f05103f 100644
--- a/fon/Photo.cpp
+++ b/fon/Photo.cpp
@@ -439,7 +439,7 @@ void Photo_replaceTransparency (Photo me, Matrix transparency) {
 static void _Photo_cellArrayOrImage (Photo me, Graphics g, double xmin, double xmax, double ymin, double ymax, bool interpolate) {
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
 	if (ymax <= ymin) { ymin = my ymin; ymax = my ymax; }
-	long ixmin, ixmax, iymin, iymax;
+	integer ixmin, ixmax, iymin, iymax;
 	Sampled_getWindowSamples    (me, xmin - 0.49999 * my dx, xmax + 0.49999 * my dx, & ixmin, & ixmax);
 	SampledXY_getWindowSamplesY (me, ymin - 0.49999 * my dy, ymax + 0.49999 * my dy, & iymin, & iymax);
 	if (ixmin > ixmax || iymin > iymax) {
@@ -449,8 +449,8 @@ static void _Photo_cellArrayOrImage (Photo me, Graphics g, double xmin, double x
 	Graphics_setInner (g);
 	Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 	autoNUMmatrix <double_rgbt> z (iymin, iymax, ixmin, ixmax);
-	for (long iy = iymin; iy <= iymax; iy ++) {
-		for (long ix = ixmin; ix <= ixmax; ix ++) {
+	for (integer iy = iymin; iy <= iymax; iy ++) {
+		for (integer ix = ixmin; ix <= ixmax; ix ++) {
 			z [iy] [ix]. red          = my d_red          -> z [iy] [ix];
 			z [iy] [ix]. green        = my d_green        -> z [iy] [ix];
 			z [iy] [ix]. blue         = my d_blue         -> z [iy] [ix];
diff --git a/fon/Photo.h b/fon/Photo.h
index b011975..351dd8b 100644
--- a/fon/Photo.h
+++ b/fon/Photo.h
@@ -2,7 +2,7 @@
 #define _Photo_h_
 /* Photo.h
  *
- * Copyright (C) 2013,2014,2015 Paul Boersma
+ * Copyright (C) 2013,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@ double_rgbt Photo_getValueAtXY (Photo me, double x, double y);
 /*
 	Linear interpolation between matrix points,
 	constant extrapolation in cells on the edge,
-	NUMundefined outside the union of the unit squares around the points.
+	undefined outside the union of the unit squares around the points.
 */
 
 void Photo_replaceRed (Photo me, Matrix red);
diff --git a/fon/Pitch.cpp b/fon/Pitch.cpp
index 072f82d..2684382 100644
--- a/fon/Pitch.cpp
+++ b/fon/Pitch.cpp
@@ -1,6 +1,6 @@
 /* Pitch.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -49,7 +49,7 @@ Thing_implement (Pitch, Sampled, 1);
 
 #define FREQUENCY(frame)  ((frame) -> candidate [1]. frequency)
 #define STRENGTH(frame)  ((frame) -> candidate [1]. strength)
-#define NOT_VOICED(f)  ((f) <= 0.0 || (f) >= my ceiling)   /* This includes NUMundefined! */
+#define NOT_VOICED(f)  (! ((f) > 0.0 && (f) < my ceiling))
 
 int structPitch :: v_getMinimumUnit (long ilevel) {
 	return ilevel == Pitch_LEVEL_FREQUENCY ? kPitch_unit_MIN : Pitch_STRENGTH_UNIT_min;
@@ -98,15 +98,15 @@ double structPitch :: v_convertStandardToSpecialUnit (double value, long ilevel,
 	if (ilevel == Pitch_LEVEL_FREQUENCY) {
 		return
 			unit == kPitch_unit_HERTZ ? value :
-			unit == kPitch_unit_HERTZ_LOGARITHMIC ? value <= 0.0 ? NUMundefined : log10 (value) :
+			unit == kPitch_unit_HERTZ_LOGARITHMIC ? value <= 0.0 ? undefined : log10 (value) :
 			unit == kPitch_unit_MEL ? NUMhertzToMel (value) :
-			unit == kPitch_unit_LOG_HERTZ ? value <= 0.0 ? NUMundefined : log10 (value) :
-			unit == kPitch_unit_SEMITONES_1 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 1.0) / NUMln2 :
-			unit == kPitch_unit_SEMITONES_100 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 100.0) / NUMln2 :
-			unit == kPitch_unit_SEMITONES_200 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 200.0) / NUMln2 :
-			unit == kPitch_unit_SEMITONES_440 ? value <= 0.0 ? NUMundefined : 12.0 * log (value / 440.0) / NUMln2 :
+			unit == kPitch_unit_LOG_HERTZ ? value <= 0.0 ? undefined : log10 (value) :
+			unit == kPitch_unit_SEMITONES_1 ? value <= 0.0 ? undefined : 12.0 * log (value / 1.0) / NUMln2 :
+			unit == kPitch_unit_SEMITONES_100 ? value <= 0.0 ? undefined : 12.0 * log (value / 100.0) / NUMln2 :
+			unit == kPitch_unit_SEMITONES_200 ? value <= 0.0 ? undefined : 12.0 * log (value / 200.0) / NUMln2 :
+			unit == kPitch_unit_SEMITONES_440 ? value <= 0.0 ? undefined : 12.0 * log (value / 440.0) / NUMln2 :
 			unit == kPitch_unit_ERB ? NUMhertzToErb (value) :
-			NUMundefined;
+			undefined;
 	} else {
 		return
 			unit == Pitch_STRENGTH_UNIT_AUTOCORRELATION ? value :
@@ -114,7 +114,7 @@ double structPitch :: v_convertStandardToSpecialUnit (double value, long ilevel,
 				value <= 1e-15 ? 1e15 : value > 1.0 - 1e-15 ? 1e-15 : (1.0 - value) / value :   /* Before losing precision. */
 			unit == Pitch_STRENGTH_UNIT_HARMONICS_NOISE_DB ?
 				value <= 1e-15 ? -150.0 : value > 1.0 - 1e-15 ? 150.0 : 10 * log10 (value / (1.0 - value)) :   /* Before losing precision. */
-			NUMundefined;
+			undefined;
 	}
 }
 
@@ -130,9 +130,9 @@ double structPitch :: v_convertSpecialToStandardUnit (double value, long ilevel,
 			unit == kPitch_unit_SEMITONES_200 ? 200.0 * exp (value * (NUMln2 / 12.0)):
 			unit == kPitch_unit_SEMITONES_440 ? 440.0 * exp (value * (NUMln2 / 12.0)):
 			unit == kPitch_unit_ERB ? NUMerbToHertz (value) :
-			NUMundefined;
+			undefined;
 	} else {
-		return NUMundefined;
+		return undefined;
 	}
 }
 
@@ -143,16 +143,16 @@ double structPitch :: v_convertSpecialToStandardUnit (double value, long ilevel,
 
 double structPitch :: v_getValueAtSample (long iframe, long ilevel, int unit) {
 	double f = frame [iframe]. candidate [1]. frequency;
-	if (f <= 0.0 || f >= ceiling) return NUMundefined;   // frequency out of range (or NUMundefined)? Voiceless
+	if (! (f > 0.0 && f < ceiling)) return undefined;   // frequency out of range (or undefined)? Voiceless
 	return v_convertStandardToSpecialUnit (ilevel == Pitch_LEVEL_FREQUENCY ? f : frame [iframe]. candidate [1]. strength, ilevel, unit);
 }
 
 bool Pitch_isVoiced_i (Pitch me, long iframe) {
-	return NUMdefined (Sampled_getValueAtSample (me, iframe, Pitch_LEVEL_FREQUENCY, kPitch_unit_HERTZ));
+	return isdefined (Sampled_getValueAtSample (me, iframe, Pitch_LEVEL_FREQUENCY, kPitch_unit_HERTZ));
 }
 
 bool Pitch_isVoiced_t (Pitch me, double time) {
-	return NUMdefined (Sampled_getValueAtX (me, time, Pitch_LEVEL_FREQUENCY, kPitch_unit_HERTZ, false));
+	return isdefined (Sampled_getValueAtX (me, time, Pitch_LEVEL_FREQUENCY, kPitch_unit_HERTZ, false));
 }
 
 double Pitch_getValueAtTime (Pitch me, double time, int unit, bool interpolate) {
@@ -178,7 +178,7 @@ double Pitch_getMeanStrength (Pitch me, double tmin, double tmax, int unit) {
 double Pitch_getQuantile (Pitch me, double tmin, double tmax, double quantile, int unit) {
 	double value = Sampled_getQuantile (me, tmin, tmax, quantile, Pitch_LEVEL_FREQUENCY, unit);
 	if (value <= 0.0 && ! doesUnitAllowNegativeValues (unit)) {
-		value = NUMundefined;
+		value = undefined;
 	}
 	return value;
 }
@@ -197,7 +197,7 @@ void Pitch_getMaximumAndTime (Pitch me, double tmin, double tmax, int unit, bool
 	Sampled_getMaximumAndX (me, tmin, tmax, Pitch_LEVEL_FREQUENCY, unit, interpolate, return_maximum, return_timeOfMaximum);
 	if (! doesUnitAllowNegativeValues (unit) && return_maximum && *return_maximum <= 0.0)
 	{
-		*return_maximum = NUMundefined;   // unlikely
+		*return_maximum = undefined;   // unlikely
 	}
 }
 
@@ -219,7 +219,7 @@ void Pitch_getMinimumAndTime (Pitch me, double tmin, double tmax, int unit, bool
 	Sampled_getMinimumAndX (me, tmin, tmax, Pitch_LEVEL_FREQUENCY, unit, interpolate, return_minimum, return_timeOfMinimum);
 	if (! doesUnitAllowNegativeValues (unit) && return_minimum && *return_minimum <= 0.0)
 	{
-		*return_minimum = NUMundefined;   // not so unlikely
+		*return_minimum = undefined;   // not so unlikely
 	}
 }
 
@@ -242,7 +242,7 @@ static long Pitch_getMeanAbsoluteSlope (Pitch me,
 	autoNUMvector <double> frequencies (1, my nx);
 	for (long i = 1; i <= my nx; i ++) {
 		double frequency = my frame [i]. candidate [1]. frequency;
-		frequencies [i] = frequency > 0.0 && frequency < my ceiling ? frequency : 0.0;
+		frequencies [i] = ( frequency > 0.0 && frequency < my ceiling ? frequency : 0.0 );
 		if (frequencies [i] != 0.0) nVoiced ++;
 	}
 	for (long i = 1; i <= my nx; i ++)   // look for first voiced frame
@@ -271,11 +271,11 @@ static long Pitch_getMeanAbsoluteSlope (Pitch me,
 		if (out_erb) *out_erb = slopeErb / span;
 		if (out_withoutOctaveJumps) *out_withoutOctaveJumps = slopeRobust / span;
 	} else {
-		if (out_hertz) *out_hertz = NUMundefined;
-		if (out_mel) *out_mel = NUMundefined;
-		if (out_semitones) *out_semitones = NUMundefined;
-		if (out_erb) *out_erb = NUMundefined;
-		if (out_withoutOctaveJumps) *out_withoutOctaveJumps = NUMundefined;
+		if (out_hertz) *out_hertz = undefined;
+		if (out_mel) *out_mel = undefined;
+		if (out_semitones) *out_semitones = undefined;
+		if (out_erb) *out_erb = undefined;
+		if (out_withoutOctaveJumps) *out_withoutOctaveJumps = undefined;
 	}
 	return nVoiced;
 }
@@ -458,7 +458,7 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 			unvoicedStrength = voicingThreshold + (unvoicedStrength > 0 ? unvoicedStrength : 0);
 			for (long icand = 1; icand <= frame->nCandidates; icand ++) {
 				Pitch_Candidate candidate = & frame->candidate [icand];
-				int voiceless = candidate->frequency == 0 || candidate->frequency > ceiling2;
+				bool voiceless = ! (candidate->frequency > 0.0 && candidate->frequency < ceiling2);
 				delta [iframe] [icand] = voiceless ? unvoicedStrength :
 					candidate->strength - octaveCost * NUMlog2 (ceiling / candidate->frequency);
 			}
@@ -479,8 +479,8 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 				for (long icand1 = 1; icand1 <= prevFrame -> nCandidates; icand1 ++) {
 					double f1 = prevFrame -> candidate [icand1]. frequency;
 					double transitionCost;
-					bool previousVoiceless = f1 <= 0 || f1 >= ceiling2;
-					bool currentVoiceless = f2 <= 0 || f2 >= ceiling2;
+					bool previousVoiceless = ! (f1 > 0.0 && f1 < ceiling2);
+					bool currentVoiceless = ! (f2 > 0.0 && f2 < ceiling2);
 					if (currentVoiceless) {
 						if (previousVoiceless) {
 							transitionCost = 0;   // both voiceless
@@ -498,7 +498,7 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 								for (long jframe = iframe - 2; jframe >= 1; jframe --) {
 									place1 = psi [jframe + 1] [place1];
 									f1 = my frame [jframe]. candidate [place1]. frequency;
-									if (f1 > 0 && f1 < ceiling) {
+									if (f1 > 0.0 && f1 < ceiling) {
 										transitionCost += octaveJumpCost * fabs (NUMlog2 (f1 / f2)) / (iframe - jframe);
 										break;
 									}
@@ -563,7 +563,7 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 				Pitch_Frame frame = & my frame [iframe];
 				Pitch_Candidate winner = & frame -> candidate [1];
 				double f = winner -> frequency;
-				if (f > ceiling && f <= ceiling2) {
+				if (f > ceiling && f < ceiling2) {
 					for (long icand = 2; icand <= frame -> nCandidates; icand ++) {
 						Pitch_Candidate loser = & frame -> candidate [icand];
 						if (loser -> frequency == 0.0) {
@@ -610,8 +610,8 @@ void Pitch_difference (Pitch me, Pitch thee) {
 	}
 	for (long i = 1; i <= my nx; i ++) {
 		double myf = my frame [i]. candidate [1]. frequency, thyf = thy frame [i]. candidate [1]. frequency;
-		int myUnvoiced = myf == 0 || myf > my ceiling;
-		int thyUnvoiced = thyf == 0 || thyf > thy ceiling;
+		int myUnvoiced = ! (myf > 0.0 && myf < my ceiling);
+		int thyUnvoiced = ! (thyf > 0.0 && thyf < thy ceiling);
 		double t = Sampled_indexToX (me, i);
 		if (myUnvoiced && ! thyUnvoiced) {
 			Melder_casual (
@@ -802,8 +802,8 @@ autoPitch Pitch_smooth (Pitch me, double bandWidth) {
 		autoMatrix matrix2 = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1.0, 1.0, 1, 1.0, 1.0);
 		for (long i = 1; i <= my nx; i ++) {
 			double originalF0 = my frame [i]. candidate [1]. frequency;
-			matrix2 -> z [1] [i] = originalF0 > 0.0 && originalF0 < my ceiling ?
-				sound2 -> z [1] [i + matrix2 -> nx] : 0.0;
+			matrix2 -> z [1] [i] = ( originalF0 > 0.0 && originalF0 < my ceiling ?
+				sound2 -> z [1] [i + matrix2 -> nx] : 0.0 );
 		}
 		autoPitch thee = Matrix_to_Pitch (matrix2.get());
 		thy ceiling = my ceiling;
@@ -815,19 +815,19 @@ autoPitch Pitch_smooth (Pitch me, double bandWidth) {
 
 void Pitch_step (Pitch me, double step, double precision, double tmin, double tmax) {
 	Melder_assert (precision >= 0.0 && precision < 1.0);
-	long imin, imax;
+	integer imin, imax;
 	if (! Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax)) return;
-	for (long i = imin; i <= imax; i ++) {
+	for (integer i = imin; i <= imax; i ++) {
 		Pitch_Frame frame = & my frame [i];
 		double currentFrequency = frame -> candidate [1]. frequency;
 		if (currentFrequency > 0.0 && currentFrequency < my ceiling) {
 			double targetFrequency = currentFrequency * step;
 			double fmin = (1 - precision) * targetFrequency;
 			double fmax = (1 + precision) * targetFrequency;
-			int icand, nearestCandidate = 0;
+			int nearestCandidate = 0;
 			double nearestDistance = my ceiling;
 			if (fmax > my ceiling) fmax = my ceiling;
-			for (icand = 2; icand <= frame -> nCandidates; icand ++) {
+			for (int icand = 2; icand <= frame -> nCandidates; icand ++) {
 				double f = frame -> candidate [icand]. frequency;
 				if (f > fmin && f < fmax) {
 					double localDistance = fabs (f - targetFrequency);
@@ -837,7 +837,7 @@ void Pitch_step (Pitch me, double step, double precision, double tmin, double tm
 					}
 				}
 			}
-			if (nearestCandidate) {   /* Swap candidates. */
+			if (nearestCandidate) {   // swap candidates
 				struct structPitch_Candidate candidate = frame -> candidate [nearestCandidate];
 				frame -> candidate [nearestCandidate] = frame -> candidate [1];
 				frame -> candidate [1] = candidate;
diff --git a/fon/PitchEditor.cpp b/fon/PitchEditor.cpp
index 6326b38..3c8b3be 100644
--- a/fon/PitchEditor.cpp
+++ b/fon/PitchEditor.cpp
@@ -159,8 +159,6 @@ void structPitchEditor :: v_createHelpMenuItems (EditorMenu menu) {
 
 void structPitchEditor :: v_draw () {
 	Pitch pitch = (Pitch) our data;
-	long it, it1, it2;
-	double dyUnv, dyIntens;
 
 	Graphics_setWindow (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
 	Graphics_setColour (our graphics.get(), Graphics_WHITE);
@@ -168,22 +166,23 @@ void structPitchEditor :: v_draw () {
 	Graphics_setColour (our graphics.get(), Graphics_BLACK);
 	Graphics_rectangle (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
 
-	dyUnv = Graphics_dyMMtoWC (our graphics.get(), HEIGHT_UNV);
-	dyIntens = Graphics_dyMMtoWC (our graphics.get(), HEIGHT_INTENS);
+	real dyUnv = Graphics_dyMMtoWC (our graphics.get(), HEIGHT_UNV);
+	real dyIntens = Graphics_dyMMtoWC (our graphics.get(), HEIGHT_INTENS);
 
+	integer it1, it2;
 	Sampled_getWindowSamples (pitch, our startWindow, our endWindow, & it1, & it2);
 
 	/*
 	 * Show pitch.
 	 */
 	{
-		long df =
-			pitch -> ceiling > 10000 ? 2000 :
-			pitch -> ceiling > 5000 ? 1000 :
-			pitch -> ceiling > 2000 ? 500 :
-			pitch -> ceiling > 800 ? 200 :
-			pitch -> ceiling > 400 ? 100 :
-			50;
+		real df =
+			pitch -> ceiling > 10000.0 ? 2000.0 :
+			pitch -> ceiling > 5000.0 ? 1000.0 :
+			pitch -> ceiling > 2000.0 ? 500.0 :
+			pitch -> ceiling > 800.0 ? 200.0 :
+			pitch -> ceiling > 400.0 ? 100.0 :
+			50.0;
 		double radius;
 		Graphics_Viewport previous;
 		previous = Graphics_insetViewport (our graphics.get(), 0.0, 1.0, dyUnv, 1.0 - dyIntens);
@@ -194,7 +193,7 @@ void structPitchEditor :: v_draw () {
 
 		if (our startSelection == our endSelection && our startSelection >= our startWindow && our startSelection <= our endWindow) {
 			double f = Pitch_getValueAtTime (pitch, our startSelection, kPitch_unit_HERTZ, Pitch_LINEAR);
-			if (NUMdefined (f)) {
+			if (isdefined (f)) {
 				Graphics_setColour (our graphics.get(), Graphics_RED);
 				Graphics_line (our graphics.get(), our startWindow - radius, f, our endWindow, f);
 				Graphics_setTextAlignment (our graphics.get(), Graphics_RIGHT, Graphics_HALF);
@@ -207,7 +206,7 @@ void structPitchEditor :: v_draw () {
 		Graphics_setColour (our graphics.get(), Graphics_BLUE);
 		Graphics_setLineType (our graphics.get(), Graphics_DOTTED);
 		Graphics_setTextAlignment (our graphics.get(), Graphics_LEFT, Graphics_HALF);
-		for (long f = df; f <= pitch -> ceiling; f += df) {
+		for (real f = df; f <= pitch -> ceiling; f += df) {
 			Graphics_line (our graphics.get(), our startWindow, f, our endWindow, f);
 			Graphics_text (our graphics.get(), our endWindow + 0.5 * radius, f,   f, U" Hz");
 		}
@@ -215,7 +214,7 @@ void structPitchEditor :: v_draw () {
 
 		/* Show candidates. */
 
-		for (it = it1; it <= it2; it ++) {
+		for (integer it = it1; it <= it2; it ++) {
 			Pitch_Frame frame = & pitch -> frame [it];
 			double t = Sampled_indexToX (pitch, it);
 			double f = frame -> candidate [1]. frequency;
@@ -247,10 +246,10 @@ void structPitchEditor :: v_draw () {
 		Graphics_setTextAlignment (our graphics.get(), Graphics_LEFT, Graphics_HALF);
 		Graphics_text (our graphics.get(), our endWindow, 0.5, U"intens");
 		Graphics_setTextAlignment (our graphics.get(), Graphics_CENTRE, Graphics_HALF);
-		for (it = it1; it <= it2; it ++) {
+		for (integer it = it1; it <= it2; it ++) {
 			Pitch_Frame frame = & pitch -> frame [it];
 			double t = Sampled_indexToX (pitch, it);
-			long strength = lround (10 * frame -> intensity + 0.5);   // map 0.0-1.0 to 0-9
+			integer strength = lround (10.0 * frame -> intensity + 0.5);   // map 0.0-1.0 to 0-9
 			if (strength > 9) strength = 9;
 			Graphics_text (our graphics.get(), t, 0.5,   strength);
 		}
@@ -271,7 +270,7 @@ void structPitchEditor :: v_draw () {
 		Graphics_text (our graphics.get(), our startWindow, 0.5, U"Unv");
 		Graphics_setTextAlignment (our graphics.get(), Graphics_LEFT, Graphics_HALF);
 		Graphics_text (our graphics.get(), our endWindow, 0.5, U"Unv");
-		for (it = it1; it <= it2; it ++) {
+		for (integer it = it1; it <= it2; it ++) {
 			Pitch_Frame frame = & pitch -> frame [it];
 			double t = Sampled_indexToX (pitch, it), tleft = t - 0.5 * pitch -> dx, tright = t + 0.5 * pitch -> dx;
 			double f = frame -> candidate [1]. frequency;
diff --git a/fon/PitchTier.cpp b/fon/PitchTier.cpp
index 24b22fc..0d8070d 100644
--- a/fon/PitchTier.cpp
+++ b/fon/PitchTier.cpp
@@ -1,6 +1,6 @@
 /* PitchTier.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -84,7 +84,7 @@ void PitchTier_stylize (PitchTier me, double frequencyResolution, int useSemiton
 static void PitchTier_writeToSpreadsheetFile (PitchTier me, MelderFile file, bool hasHeader) {
 	autofile f = Melder_fopen (file, "w");
 	if (hasHeader)
-		fprintf (f, "\"ooTextFile\"\n\"PitchTier\"\n%.17g %.17g %ld\n", my xmin, my xmax, my points.size);
+		fprintf (f, "\"ooTextFile\"\n\"PitchTier\"\n%.17g %.17g %ld\n", my xmin, my xmax, (long) my points.size);
 	for (long i = 1; i <= my points.size; i ++) {
 		RealPoint point = my points.at [i];
 		fprintf (f, "%.17g\t%.17g\n", point -> number, point -> value);
diff --git a/fon/PitchTier_to_PointProcess.cpp b/fon/PitchTier_to_PointProcess.cpp
index 025f327..46745b6 100644
--- a/fon/PitchTier_to_PointProcess.cpp
+++ b/fon/PitchTier_to_PointProcess.cpp
@@ -1,6 +1,6 @@
 /* PitchTier_to_PointProcess.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,13 +27,13 @@ autoPointProcess PitchTier_to_PointProcess (PitchTier me) {
 		if (size == 0) return thee;
 		for (long interval = 0; interval <= size; interval ++) {
 			double t1 = ( interval == 0 ? my xmin : my points.at [interval] -> number );
-			Melder_assert (NUMdefined (t1));
+			Melder_assert (isdefined (t1));
 			double t2 = ( interval == size ? my xmax : my points.at [interval + 1] -> number );
-			Melder_assert (NUMdefined (t2));
+			Melder_assert (isdefined (t2));
 			double f1 = my points.at [interval == 0 ? 1 : interval] -> value;
-			Melder_assert (NUMdefined (f1));
+			Melder_assert (isdefined (f1));
 			double f2 = my points.at [interval == size ? size : interval + 1] -> value;
-			Melder_assert (NUMdefined (f2));
+			Melder_assert (isdefined (f2));
 			area += (t2 - t1) * 0.5 * (f1 + f2);
 			while (area >= 1.0) {
 				double slope = (f2 - f1) / (t2 - t1), discriminant;
diff --git a/fon/PitchTier_to_Sound.cpp b/fon/PitchTier_to_Sound.cpp
index 5324d80..e7f4d43 100644
--- a/fon/PitchTier_to_Sound.cpp
+++ b/fon/PitchTier_to_Sound.cpp
@@ -26,7 +26,7 @@ autoSound PitchTier_to_Sound_pulseTrain (PitchTier me, double samplingFrequency,
 	static double formant [1 + 6] = { 0.0, 600.0, 1400.0, 2400.0, 3400.0, 4500.0, 5500.0 };
 	static double bandwidth [1 + 6] = { 0.0, 50.0, 100.0, 200.0, 300.0, 400.0, 500.0 };
 	try {
-		autoPointProcess point = PitchTier_to_PointProcess (me);
+		const autoPointProcess point = PitchTier_to_PointProcess (me);
 		autoSound sound = PointProcess_to_Sound_pulseTrain (point.get(), samplingFrequency, adaptFactor, adaptTime, interpolationDepth);
 		if (hum) {
 			Sound_filterWithFormants (sound.get(), 0.0, 0.0, 6, formant, bandwidth);
@@ -43,7 +43,7 @@ autoSound PitchTier_to_Sound_phonation (PitchTier me, double samplingFrequency,
 	static double formant [1 + 6] = { 0.0, 600.0, 1400.0, 2400.0, 3400.0, 4500.0, 5500.0 };
 	static double bandwidth [1 + 6] = { 0.0, 50.0, 100.0, 200.0, 300.0, 400.0, 500.0 };
 	try {
-		autoPointProcess point = PitchTier_to_PointProcess (me);
+		const autoPointProcess point = PitchTier_to_PointProcess (me);
 		autoSound sound = PointProcess_to_Sound_phonation (point.get(), samplingFrequency, adaptFactor,
 			maximumPeriod, openPhase, collisionPhase, power1, power2);
 		if (hum) {
@@ -57,7 +57,7 @@ autoSound PitchTier_to_Sound_phonation (PitchTier me, double samplingFrequency,
 
 void PitchTier_playPart (PitchTier me, double tmin, double tmax, bool hum) {
 	try {
-		autoSound sound = PitchTier_to_Sound_pulseTrain (me, 44100.0, 0.7, 0.05, 30, hum);
+		const autoSound sound = PitchTier_to_Sound_pulseTrain (me, 44100.0, 0.7, 0.05, 30, hum);
 		Sound_playPart (sound.get(), tmin, tmax, nullptr, nullptr);
 	} catch (MelderError) {
 		Melder_throw (me, U": not played.");
diff --git a/fon/Pitch_AnyTier_to_PitchTier.cpp b/fon/Pitch_AnyTier_to_PitchTier.cpp
index 6280520..d623f70 100644
--- a/fon/Pitch_AnyTier_to_PitchTier.cpp
+++ b/fon/Pitch_AnyTier_to_PitchTier.cpp
@@ -1,6 +1,6 @@
 /* Pitch_AnyTier_to_PitchTier.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ autoPitchTier Pitch_AnyTier_to_PitchTier (Pitch pitch, AnyTier tier, int checkMe
 			AnyPoint point = tier -> points.at [ipoint];
 			double time = point -> number;
 			double frequency = Pitch_getValueAtTime (pitch, time, kPitch_unit_HERTZ, Pitch_LINEAR);
-			if (frequency == NUMundefined && checkMethod)
+			if (isundef (frequency) && checkMethod != 0)
 				Melder_throw (U"No periodicity at time ", time, U" seconds.");
 			RealTier_addPoint (thee.get(), time, frequency);
 		}
diff --git a/fon/Pitch_Intensity.cpp b/fon/Pitch_Intensity.cpp
index 971d8dc..5a92750 100644
--- a/fon/Pitch_Intensity.cpp
+++ b/fon/Pitch_Intensity.cpp
@@ -1,6 +1,6 @@
 /* Pitch_Intensity.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,8 +40,8 @@ void Pitch_Intensity_draw (Pitch pitch, Intensity intensity, Graphics g,
 	if (s1 == s2) { s1 -= 1.0; s2 += 1.0; }
 	Graphics_setWindow (g, f1, f2, s1, s2);
 	Graphics_setInner (g);
-	double previousX = NUMundefined;
-	double previousY = NUMundefined;
+	double previousX = undefined;
+	double previousY = undefined;
 	long previousI = 0;
 	for (long i = 1; i <= pitch -> nx; i ++) {
 		double t = Sampled_indexToX (pitch, i);
@@ -51,7 +51,7 @@ void Pitch_Intensity_draw (Pitch pitch, Intensity intensity, Graphics g,
 			continue;   // voiceless
 		}
 		if (connect & 1) Graphics_speckle (g, x, y);
-		if ((connect & 2) && NUMdefined (previousX)) {
+		if ((connect & 2) && isdefined (previousX)) {
 			if (previousI >= 1 && previousI < i - 1) {
 				Graphics_setLineType (g, Graphics_DOTTED);
 			}
@@ -84,7 +84,7 @@ double Pitch_Intensity_getMean (Pitch thee, Intensity me) {
 			numberOfValidLocalMeasurements += 1;
 		}
 	}
-	return numberOfValidLocalMeasurements > 0 ? sumOfLocalValues / numberOfValidLocalMeasurements : NUMundefined;
+	return numberOfValidLocalMeasurements > 0 ? sumOfLocalValues / numberOfValidLocalMeasurements : undefined;
 }
 
 double Pitch_Intensity_getMeanAbsoluteSlope (Pitch thee, Intensity me) {
@@ -101,7 +101,7 @@ double Pitch_Intensity_getMeanAbsoluteSlope (Pitch thee, Intensity me) {
 		}
 	}
 	sumOfLocalAbsoluteSlopes /= my dx;   // convert to dB per second
-	return numberOfValidLocalMeasurements > 0 ? sumOfLocalAbsoluteSlopes / numberOfValidLocalMeasurements : NUMundefined;
+	return numberOfValidLocalMeasurements > 0 ? sumOfLocalAbsoluteSlopes / numberOfValidLocalMeasurements : undefined;
 }
 
 /* End of file Pitch_Intensity.cpp */
diff --git a/fon/Pitch_def.h b/fon/Pitch_def.h
index 6b98623..0961203 100644
--- a/fon/Pitch_def.h
+++ b/fon/Pitch_def.h
@@ -1,6 +1,6 @@
 /* Pitch_def.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,7 +55,7 @@ oo_DEFINE_STRUCT (Pitch_Frame)
 
 	#if oo_READING_BINARY
 		if (formatVersion < 0) {
-			oo_INT (nCandidates)
+			oo_INT16 (nCandidates)
 			oo_FLOAT (intensity)
 		} else if (formatVersion == 0) {
 			oo_FLOAT (intensity)
@@ -79,7 +79,7 @@ oo_END_STRUCT (Pitch_Frame)
 oo_DEFINE_CLASS (Pitch, Sampled)
 
 	oo_DOUBLE (ceiling)
-	oo_INT (maxnCandidates)
+	oo_INT16 (maxnCandidates)
 	oo_STRUCT_VECTOR (Pitch_Frame, frame, nx)
 
 	#if oo_DECLARING
diff --git a/fon/Pitch_to_PointProcess.cpp b/fon/Pitch_to_PointProcess.cpp
index 3ee733a..310ddb2 100644
--- a/fon/Pitch_to_PointProcess.cpp
+++ b/fon/Pitch_to_PointProcess.cpp
@@ -1,6 +1,6 @@
 /* Pitch_to_PointProcess.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
  * pb 2003/05/17 introduced silence threshold
  * pb 2003/05/20 removed bug in global peak
  * pb 2003/05/22 changed 1.2 to 1.25
- * pb 2004/05/11 undefined pitch is NUMundefined rather than 0.0
+ * pb 2004/05/11 undefined pitch is `undefined` rather than 0.0
  * pb 2004/11/01 Pitch_getVoicedIntervalAfter clips to my xmax
  * pb 2004/11/28 repaired memory leak in Pitch_to_PointProcess
  * pb 2004/11/28 truncated tleft in Pitch_getVoicedIntervalAfter to my xmin (otherwise, getValue can crash)
@@ -111,8 +111,8 @@ static double findExtremum_3 (double *channel1_base, double *channel2_base, long
 
 static double Sound_findExtremum (Sound me, double tmin, double tmax, int includeMaxima, int includeMinima) {
 	long imin = Sampled_xToLowIndex (me, tmin), imax = Sampled_xToHighIndex (me, tmax);
-	Melder_assert (NUMdefined (tmin));
-	Melder_assert (NUMdefined (tmax));
+	Melder_assert (isdefined (tmin));
+	Melder_assert (isdefined (tmax));
 	if (imin < 1) imin = 1;
 	if (imax > my nx) imax = my nx;
 	double iextremum = findExtremum_3 (my z [1], my ny > 1 ? my z [2] : nullptr, imin - 1, imax - imin + 1, includeMaxima, includeMinima);
@@ -124,7 +124,7 @@ static double Sound_findExtremum (Sound me, double tmin, double tmax, int includ
 
 static double Sound_findMaximumCorrelation (Sound me, double t1, double windowLength, double tmin2, double tmax2, double *tout, double *peak) {
 	double maximumCorrelation = -1.0;   // smart 'impossible' starting value
-	double r1_best = NUMundefined, r3_best = NUMundefined, ir = NUMundefined;   // assignments not necessary, but extra safe
+	double r1_best = undefined, r3_best = undefined, ir = undefined;   // assignments not necessary, but extra safe
 	double r1 = 0.0, r2 = 0.0, r3 = 0.0;
 	double halfWindowLength = 0.5 * windowLength;
 	long ileft1 = Sampled_xToNearestIndex ((Sampled) me, t1 - halfWindowLength);
@@ -148,7 +148,7 @@ static double Sound_findMaximumCorrelation (Sound me, double t1, double windowLe
 		}
 		r1 = r2;   // >= 0
 		r2 = r3;   // >= 0
-		r3 = product != 0.0 ? product / (sqrt (norm1 * norm2)) : 0.0;   // >= 0
+		r3 = ( product != 0.0 ? product / (sqrt (norm1 * norm2)) : 0.0 );   // >= 0
 		if (r2 > maximumCorrelation /* true on first test */ && r2 >= r1 && r2 >= r3) {
 			r1_best = r1;
 			maximumCorrelation = r2;
@@ -162,7 +162,7 @@ static double Sound_findMaximumCorrelation (Sound me, double t1, double windowLe
 	 */
 	if (maximumCorrelation > -1.0) {   // was maximumCorrelation ever assigned to?...
 		// ...then r1_best and r3_best and ir must also have been assigned to:
-		Melder_assert (NUMdefined (r1_best) && NUMdefined (r3_best) && NUMdefined (ir));
+		Melder_assert (isdefined (r1_best) && isdefined (r3_best) && isdefined (ir));
 		double d2r = 2 * maximumCorrelation - r1_best - r3_best;
 		if (d2r != 0.0) {
 			double dr = 0.5 * (r3_best - r1_best);
@@ -200,7 +200,7 @@ autoPointProcess Sound_Pitch_to_PointProcess_cc (Sound sound, Pitch pitch) {
 			/*
 			 * Our first point is near this middle.
 			 */
-			if (f0middle == NUMundefined) {
+			if (isundef (f0middle)) {
 				Melder_fatal (U"Sound_Pitch_to_PointProcess_cc:"
 					U" tleft ", tleft,
 					U", tright ", tright,
@@ -208,13 +208,13 @@ autoPointProcess Sound_Pitch_to_PointProcess_cc (Sound sound, Pitch pitch) {
 				);
 			}
 			double tmax = Sound_findExtremum (sound, tmiddle - 0.5 / f0middle, tmiddle + 0.5 / f0middle, true, true);
-			Melder_assert (NUMdefined (tmax));
+			Melder_assert (isdefined (tmax));
 			PointProcess_addPoint (point.get(), tmax);
 
 			double tsave = tmax;
 			for (;;) {
 				double f0 = Pitch_getValueAtTime (pitch, tmax, kPitch_unit_HERTZ, Pitch_LINEAR), correlation;
-				if (f0 == NUMundefined) break;
+				if (isundef (f0)) break;
 				correlation = Sound_findMaximumCorrelation (sound, tmax, 1.0 / f0, tmax - 1.25 / f0, tmax - 0.8 / f0, & tmax, & peak);
 				if (correlation == -1) /*break*/ tmax -= 1.0 / f0;   // this one period will drop out
 				if (tmax < tleft) {
@@ -232,7 +232,7 @@ autoPointProcess Sound_Pitch_to_PointProcess_cc (Sound sound, Pitch pitch) {
 			tmax = tsave;
 			for (;;) {
 				double f0 = Pitch_getValueAtTime (pitch, tmax, kPitch_unit_HERTZ, Pitch_LINEAR), correlation;
-				if (f0 == NUMundefined) break;
+				if (isundef (f0)) break;
 				correlation = Sound_findMaximumCorrelation (sound, tmax, 1.0 / f0, tmax + 0.8 / f0, tmax + 1.25 / f0, & tmax, & peak);
 				if (correlation == -1) /*break*/ tmax += 1.0 / f0;
 				if (tmax > tright) {
@@ -279,15 +279,15 @@ autoPointProcess Sound_Pitch_to_PointProcess_peaks (Sound sound, Pitch pitch, in
 			/*
 			 * Our first point is near this middle.
 			 */
-			Melder_assert (NUMdefined (f0middle));
+			Melder_assert (isdefined (f0middle));
 			double tmax = Sound_findExtremum (sound, tmiddle - 0.5 / f0middle, tmiddle + 0.5 / f0middle, includeMaxima, includeMinima);
-			Melder_assert (NUMdefined (tmax));
+			Melder_assert (isdefined (tmax));
 			PointProcess_addPoint (point.get(), tmax);
 
 			double tsave = tmax;
 			for (;;) {
 				double f0 = Pitch_getValueAtTime (pitch, tmax, kPitch_unit_HERTZ, Pitch_LINEAR);
-				if (f0 == NUMundefined) break;
+				if (isundef (f0)) break;
 				tmax = Sound_findExtremum (sound, tmax - 1.25 / f0, tmax - 0.8 / f0, includeMaxima, includeMinima);
 				if (tmax < tleft) {
 					if (tmax - addedRight > 0.8 / f0) {
@@ -302,7 +302,7 @@ autoPointProcess Sound_Pitch_to_PointProcess_peaks (Sound sound, Pitch pitch, in
 			tmax = tsave;
 			for (;;) {
 				double f0 = Pitch_getValueAtTime (pitch, tmax, kPitch_unit_HERTZ, Pitch_LINEAR);
-				if (f0 == NUMundefined) break;
+				if (isundef (f0)) break;
 				tmax = Sound_findExtremum (sound, tmax + 0.8 / f0, tmax + 1.25 / f0, includeMaxima, includeMinima);
 				if (tmax > tright) {
 					PointProcess_addPoint (point.get(), tmax);
diff --git a/fon/PointEditor.cpp b/fon/PointEditor.cpp
index 0861025..6613448 100644
--- a/fon/PointEditor.cpp
+++ b/fon/PointEditor.cpp
@@ -159,7 +159,7 @@ void structPointEditor :: v_draw () {
 	Graphics_fillRectangle (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
 	double minimum = -1.0, maximum = +1.0;
 	if (sound && (p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_BY_WINDOW || p_sound_scalingStrategy == kTimeSoundEditor_scalingStrategy_BY_WINDOW_AND_CHANNEL)) {
-		long first, last;
+		integer first, last;
 		if (Sampled_getWindowSamples (sound, our startWindow, our endWindow, & first, & last) >= 1) {
 			Matrix_getWindowExtrema (sound, first, last, 1, 1, & minimum, & maximum);
 			if (minimum == maximum) minimum -= 1.0, maximum += 1.0;
@@ -168,7 +168,7 @@ void structPointEditor :: v_draw () {
 	Graphics_setWindow (our graphics.get(), our startWindow, our endWindow, minimum, maximum);
 	Graphics_setColour (our graphics.get(), Graphics_BLACK);
 	if (sound) {
-		long first, last;
+		integer first, last;
 		if (Sampled_getWindowSamples (sound, our startWindow, our endWindow, & first, & last) > 1) {
 			Graphics_setLineType (our graphics.get(), Graphics_DOTTED);
 			Graphics_line (our graphics.get(), our startWindow, 0.0, our endWindow, 0.0);
diff --git a/fon/PointProcess.cpp b/fon/PointProcess.cpp
index ad18d75..35997bc 100644
--- a/fon/PointProcess.cpp
+++ b/fon/PointProcess.cpp
@@ -1,6 +1,6 @@
 /* PointProcess.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@
 Thing_implement (PointProcess, Function, 0);
 
 static void infoPeriods (PointProcess me, double shortestPeriod, double longestPeriod, double maximumPeriodFactor, int precision) {
-	long numberOfPeriods = PointProcess_getNumberOfPeriods (me, 0.0, 0.0, shortestPeriod, longestPeriod, maximumPeriodFactor);
+	integer numberOfPeriods = PointProcess_getNumberOfPeriods (me, 0.0, 0.0, shortestPeriod, longestPeriod, maximumPeriodFactor);
 	double meanPeriod = PointProcess_getMeanPeriod (me, 0.0, 0.0, shortestPeriod, longestPeriod, maximumPeriodFactor);
 	double stdevPeriod = PointProcess_getStdevPeriod (me, 0.0, 0.0, shortestPeriod, longestPeriod, maximumPeriodFactor);
 	double jitter_local = PointProcess_getJitter_local (me, 0.0, 0.0, shortestPeriod, longestPeriod, maximumPeriodFactor);
@@ -79,19 +79,19 @@ void structPointProcess :: v_info () {
 
 void structPointProcess :: v_shiftX (double xfrom, double xto) {
 	PointProcess_Parent :: v_shiftX (xfrom, xto);
-	for (long i = 1; i <= nt; i ++) {
+	for (integer i = 1; i <= nt; i ++) {
 		NUMshift (& t [i], xfrom, xto);
 	}
 }
 
 void structPointProcess :: v_scaleX (double xminfrom, double xmaxfrom, double xminto, double xmaxto) {
 	PointProcess_Parent :: v_scaleX (xminfrom, xmaxfrom, xminto, xmaxto);
-	for (long i = 1; i <= nt; i ++) {
+	for (integer i = 1; i <= nt; i ++) {
 		NUMscale (& t [i], xminfrom, xmaxfrom, xminto, xmaxto);
 	}
 }
 
-void PointProcess_init (PointProcess me, double tmin, double tmax, long initialMaxnt) {
+void PointProcess_init (PointProcess me, double tmin, double tmax, integer initialMaxnt) {
 	Function_init (me, tmin, tmax);
 	if (initialMaxnt < 1) initialMaxnt = 1;
 	my maxnt = initialMaxnt;
@@ -99,7 +99,7 @@ void PointProcess_init (PointProcess me, double tmin, double tmax, long initialM
 	my t = NUMvector <double> (1, my maxnt);
 }
 
-autoPointProcess PointProcess_create (double tmin, double tmax, long initialMaxnt) {
+autoPointProcess PointProcess_create (double tmin, double tmax, integer initialMaxnt) {
 	try {
 		autoPointProcess me = Thing_new (PointProcess);
 		PointProcess_init (me.get(), tmin, tmax, initialMaxnt);
@@ -111,10 +111,10 @@ autoPointProcess PointProcess_create (double tmin, double tmax, long initialMaxn
 
 autoPointProcess PointProcess_createPoissonProcess (double startingTime, double finishingTime, double density) {
 	try {
-		long nt = NUMrandomPoisson ((finishingTime - startingTime) * density);
+		integer nt = (integer) NUMrandomPoisson ((finishingTime - startingTime) * density);
 		autoPointProcess me = PointProcess_create (startingTime, finishingTime, nt);
 		my nt = nt;
-		for (long i = 1; i <= nt; i ++)
+		for (integer i = 1; i <= nt; i ++)
 			my t [i] = NUMrandomUniform (startingTime, finishingTime);
 		NUMsort_d (my nt, my t);
 		return me;
@@ -123,23 +123,23 @@ autoPointProcess PointProcess_createPoissonProcess (double startingTime, double
 	}
 }
 
-long PointProcess_getLowIndex (PointProcess me, double t) {
+integer PointProcess_getLowIndex (PointProcess me, double t) {
 	if (my nt == 0 || t < my t [1])
 		return 0;
 	if (t >= my t [my nt])   // special case that often occurs in practice
 		return my nt;
 	Melder_assert (my nt != 1);   // may fail if t or my t [1] is NaN
 	/* Start binary search. */
-	long left = 1, right = my nt;
+	integer left = 1, right = my nt;
 	while (left < right - 1) {
-		long mid = (left + right) / 2;
+		integer mid = (left + right) / 2;
 		if (t >= my t [mid]) left = mid; else right = mid;
 	}
 	Melder_assert (right == left + 1);
 	return left;
 }
 
-long PointProcess_getHighIndex (PointProcess me, double t) {
+integer PointProcess_getHighIndex (PointProcess me, double t) {
 	if (my nt == 0)
 		return 0;
 	if (t <= my t [1])
@@ -147,16 +147,16 @@ long PointProcess_getHighIndex (PointProcess me, double t) {
 	if (t > my t [my nt])
 		return my nt + 1;
 	/* Start binary search. */
-	long left = 1, right = my nt;
+	integer left = 1, right = my nt;
 	while (left < right - 1) {
-		long mid = (left + right) / 2;
+		integer mid = (left + right) / 2;
 		if (t > my t [mid]) left = mid; else right = mid;
 	}
 	Melder_assert (right == left + 1);
 	return right;
 }
 
-long PointProcess_getNearestIndex (PointProcess me, double t) {
+integer PointProcess_getNearestIndex (PointProcess me, double t) {
 	if (my nt == 0)
 		return 0;
 	if (t <= my t [1])
@@ -164,9 +164,9 @@ long PointProcess_getNearestIndex (PointProcess me, double t) {
 	if (t >= my t [my nt])
 		return my nt;
 	/* Start binary search. */
-	long left = 1, right = my nt;
+	integer left = 1, right = my nt;
 	while (left < right - 1) {
-		long mid = (left + right) / 2;
+		integer mid = (left + right) / 2;
 		if (t >= my t [mid]) left = mid; else right = mid;
 	}
 	Melder_assert (right == left + 1);
@@ -175,7 +175,7 @@ long PointProcess_getNearestIndex (PointProcess me, double t) {
 
 void PointProcess_addPoint (PointProcess me, double t) {
 	try {
-		if (t == NUMundefined)
+		if (isundef (t))
 			Melder_throw (U"Cannot add a point at an undefined time.");
 		if (my nt >= my maxnt) {
 			/*
@@ -193,9 +193,9 @@ void PointProcess_addPoint (PointProcess me, double t) {
 		if (my nt == 0 || t >= my t [my nt]) {   // special case that often occurs in practice
 			my t [++ my nt] = t;
 		} else {
-			long left = PointProcess_getLowIndex (me, t);
+			integer left = PointProcess_getLowIndex (me, t);
 			if (left == 0 || my t [left] != t) {
-				for (long i = my nt; i > left; i --) my t [i + 1] = my t [i];
+				for (integer i = my nt; i > left; i --) my t [i + 1] = my t [i];
 				my nt ++;
 				my t [left + 1] = t;
 			}
@@ -205,9 +205,9 @@ void PointProcess_addPoint (PointProcess me, double t) {
 	}
 }
 
-void PointProcess_removePoint (PointProcess me, long pointNumber) {
+void PointProcess_removePoint (PointProcess me, integer pointNumber) {
 	if (pointNumber < 1 || pointNumber > my nt) return;
-	for (long i = pointNumber; i < my nt; i ++)
+	for (integer i = pointNumber; i < my nt; i ++)
 		my t [i] = my t [i + 1];
 	my nt --;
 }
@@ -216,12 +216,12 @@ void PointProcess_removePointNear (PointProcess me, double time) {
 	PointProcess_removePoint (me, PointProcess_getNearestIndex (me, time));
 }
 
-void PointProcess_removePoints (PointProcess me, long first, long last) {
+void PointProcess_removePoints (PointProcess me, integer first, integer last) {
 	if (first < 1) first = 1;
 	if (last > my nt) last = my nt;
-	long distance = last - first + 1;
+	integer distance = last - first + 1;
 	if (distance <= 0) return;
-	for (long i = first + distance; i <= my nt; i ++)
+	for (integer i = first + distance; i <= my nt; i ++)
 		my t [i - distance] = my t [i];
 	my nt -= distance;
 }
@@ -234,12 +234,12 @@ void PointProcess_draw (PointProcess me, Graphics g, double tmin, double tmax, b
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 	Graphics_setWindow (g, tmin, tmax, -1.0, 1.0);
 	if (my nt) {
-		long imin = PointProcess_getHighIndex (me, tmin);
-		long imax = PointProcess_getLowIndex  (me, tmax);
+		integer imin = PointProcess_getHighIndex (me, tmin);
+		integer imax = PointProcess_getLowIndex  (me, tmax);
 		int lineType = Graphics_inqLineType (g);
 		Graphics_setLineType (g, Graphics_DOTTED);
 		Graphics_setInner (g);
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			Graphics_line (g, my t [i], -1.0, my t [i], 1.0);
 		}
 		Graphics_setLineType (g, lineType);
@@ -253,8 +253,8 @@ void PointProcess_draw (PointProcess me, Graphics g, double tmin, double tmax, b
 }
 
 double PointProcess_getInterval (PointProcess me, double t) {
-	long ileft = PointProcess_getLowIndex (me, t);
-	if (ileft <= 0 || ileft >= my nt) return NUMundefined;
+	integer ileft = PointProcess_getLowIndex (me, t);
+	if (ileft <= 0 || ileft >= my nt) return undefined;
 	return my t [ileft + 1] - my t [ileft];
 }
 
@@ -263,7 +263,7 @@ autoPointProcess PointProcesses_union (PointProcess me, PointProcess thee) {
 		autoPointProcess him = Data_copy (me);
 		if (thy xmin < my xmin) his xmin = thy xmin;
 		if (thy xmax > my xmax) his xmax = thy xmax;
-		for (long i = 1; i <= thy nt; i ++) {
+		for (integer i = 1; i <= thy nt; i ++) {
 			PointProcess_addPoint (him.get(), thy t [i]);
 		}
 		return him;
@@ -272,12 +272,12 @@ autoPointProcess PointProcesses_union (PointProcess me, PointProcess thee) {
 	}
 }
 
-long PointProcess_findPoint (PointProcess me, double t) {
-	long left = 1, right = my nt;
+integer PointProcess_findPoint (PointProcess me, double t) {
+	integer left = 1, right = my nt;
 	if (my nt == 0) return 0;
 	if (t < my t [left] || t > my t [right]) return 0;
 	while (left < right - 1) {
-		long mid = (left + right) / 2;   // tleft <= t <= tright
+		integer mid = (left + right) / 2;   // tleft <= t <= tright
 		if (t == my t [mid]) return mid;
 		if (t > my t [mid])
 			left = mid;
@@ -294,7 +294,7 @@ autoPointProcess PointProcesses_intersection (PointProcess me, PointProcess thee
 		autoPointProcess him = Data_copy (me);
 		if (thy xmin > my xmin) his xmin = thy xmin;
 		if (thy xmax < my xmax) his xmax = thy xmax;
-		for (long i = my nt; i >= 1; i --)
+		for (integer i = my nt; i >= 1; i --)
 			if (! PointProcess_findPoint (thee, my t [i]))
 				PointProcess_removePoint (him.get(), i);
 		return him;
@@ -306,7 +306,7 @@ autoPointProcess PointProcesses_intersection (PointProcess me, PointProcess thee
 autoPointProcess PointProcesses_difference (PointProcess me, PointProcess thee) {
 	try {
 		autoPointProcess him = Data_copy (me);
-		for (long i = my nt; i >= 1; i --)
+		for (integer i = my nt; i >= 1; i --)
 			if (PointProcess_findPoint (thee, my t [i]))
 				PointProcess_removePoint (him.get(), i);
 		return him;
@@ -318,9 +318,9 @@ autoPointProcess PointProcesses_difference (PointProcess me, PointProcess thee)
 void PointProcess_fill (PointProcess me, double tmin, double tmax, double period) {
 	try {
 		if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   // autowindowing
-		long n = (long) floor ((tmax - tmin) / period);
+		integer n = (integer) floor ((tmax - tmin) / period);
 		double t = 0.5 * (tmin + tmax - n * period);
-		for (long i = 1; i <= n; i ++, t += period) {
+		for (integer i = 1; i <= n; i ++, t += period) {
 			PointProcess_addPoint (me, t);
 		}
 	} catch (MelderError) {
@@ -330,9 +330,9 @@ void PointProcess_fill (PointProcess me, double tmin, double tmax, double period
 
 void PointProcess_voice (PointProcess me, double period, double maxT) {
 	try {
-		long ipointright;
+		integer ipointright;
 		double beginVoiceless = my xmin, endVoiceless;
-		for (long ipointleft = 1; ipointleft <= my nt; ipointleft = ipointright + 1) {
+		for (integer ipointleft = 1; ipointleft <= my nt; ipointleft = ipointright + 1) {
 			endVoiceless = my t [ipointleft];
 			PointProcess_fill (me, beginVoiceless, endVoiceless, period);
 			for (ipointright = ipointleft + 1; ipointright <= my nt; ipointright ++)
@@ -348,19 +348,19 @@ void PointProcess_voice (PointProcess me, double period, double maxT) {
 	}
 }
 
-long PointProcess_getWindowPoints (PointProcess me, double tmin, double tmax, long *p_imin, long *p_imax) {
-	long imin = PointProcess_getHighIndex (me, tmin);
-	long imax = PointProcess_getLowIndex (me, tmax);
+integer PointProcess_getWindowPoints (PointProcess me, double tmin, double tmax, integer *p_imin, integer *p_imax) {
+	integer imin = PointProcess_getHighIndex (me, tmin);
+	integer imax = PointProcess_getLowIndex (me, tmax);
 	if (p_imin) *p_imin = imin;
 	if (p_imax) *p_imax = imax;
 	return imax - imin + 1;
 }
 
-static bool PointProcess_isPeriod (PointProcess me, long ileft, double minimumPeriod, double maximumPeriod, double maximumPeriodFactor) {
+static bool PointProcess_isPeriod (PointProcess me, integer ileft, double minimumPeriod, double maximumPeriod, double maximumPeriodFactor) {
 	/*
 	 * This function answers the question: is the interval from point 'ileft' to point 'ileft+1' a period?
 	 */
-	long iright = ileft + 1;
+	integer iright = ileft + 1;
 	/*
 	 * Period condition 1: both 'ileft' and 'iright' have to be within the point process.
 	 */
@@ -376,27 +376,29 @@ static bool PointProcess_isPeriod (PointProcess me, long ileft, double minimumPe
 			double interval = my t [iright] - my t [ileft];
 			if (interval <= 0.0 || interval < minimumPeriod || interval > maximumPeriod) {
 				return false;
-			} else if (! NUMdefined (maximumPeriodFactor) || maximumPeriodFactor < 1.0) {
+			} else if (isundef (maximumPeriodFactor) || maximumPeriodFactor < 1.0) {
 				return true;
 			} else {
 				/*
 				 * Period condition 3: the interval cannot be too different from both of its neigbours, if any.
 				 */
-				double previousInterval = ileft <= 1 ? NUMundefined : my t [ileft] - my t [ileft - 1];
-				double nextInterval = iright >= my nt ? NUMundefined : my t [iright + 1] - my t [iright];
-				double previousIntervalFactor = NUMdefined (previousInterval) && previousInterval > 0.0 ? interval / previousInterval : NUMundefined;
-				double nextIntervalFactor = NUMdefined (nextInterval) && nextInterval > 0.0 ? interval / nextInterval : NUMundefined;
-				if (! NUMdefined (previousIntervalFactor) && ! NUMdefined (nextIntervalFactor)) {
+				double previousInterval = ( ileft <= 1 ? undefined : my t [ileft] - my t [ileft - 1] );
+				double nextInterval = ( iright >= my nt ? undefined : my t [iright + 1] - my t [iright] );
+				double previousIntervalFactor =
+					( isdefined (previousInterval) && previousInterval > 0.0 ? interval / previousInterval : undefined );
+				double nextIntervalFactor =
+					( isdefined (nextInterval) && nextInterval > 0.0 ? interval / nextInterval : undefined );
+				if (isundef (previousIntervalFactor) && isundef (nextIntervalFactor)) {
 					return true;   // no neighbours: this is a period
 				}
-				if (NUMdefined (previousIntervalFactor) && previousIntervalFactor > 0.0 && previousIntervalFactor < 1.0) {
+				if (isdefined (previousIntervalFactor) && previousIntervalFactor > 0.0 && previousIntervalFactor < 1.0) {
 					previousIntervalFactor = 1.0 / previousIntervalFactor;
 				}
-				if (NUMdefined (nextIntervalFactor) && nextIntervalFactor > 0.0 && nextIntervalFactor < 1.0) {
+				if (isdefined (nextIntervalFactor) && nextIntervalFactor > 0.0 && nextIntervalFactor < 1.0) {
 					nextIntervalFactor = 1.0 / nextIntervalFactor;
 				}
-				if (NUMdefined (previousIntervalFactor) && previousIntervalFactor > maximumPeriodFactor &&
-					NUMdefined (nextIntervalFactor) && nextIntervalFactor > maximumPeriodFactor)
+				if (isdefined (previousIntervalFactor) && previousIntervalFactor > maximumPeriodFactor &&
+					isdefined (nextIntervalFactor) && nextIntervalFactor > maximumPeriodFactor)
 				{
 					return false;
 				}
@@ -406,14 +408,14 @@ static bool PointProcess_isPeriod (PointProcess me, long ileft, double minimumPe
 	return true;
 }
 
-long PointProcess_getNumberOfPeriods (PointProcess me, double tmin, double tmax,
+integer PointProcess_getNumberOfPeriods (PointProcess me, double tmin, double tmax,
 	double minimumPeriod, double maximumPeriod, double maximumPeriodFactor)
 {
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   // autowindowing
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
 	if (numberOfPeriods < 1) return 0;
-	for (long i = imin; i < imax; i ++) {
+	for (integer i = imin; i < imax; i ++) {
 		if (PointProcess_isPeriod (me, i, minimumPeriod, maximumPeriod, maximumPeriodFactor)) {
 			(void) 0;   // this interval counts as a period
 		} else {
@@ -427,45 +429,45 @@ double PointProcess_getMeanPeriod (PointProcess me, double tmin, double tmax,
 	double minimumPeriod, double maximumPeriod, double maximumPeriodFactor)
 {
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   // autowindowing
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
-	if (numberOfPeriods < 1) return NUMundefined;
-	double sum = 0.0;
-	for (long i = imin; i < imax; i ++) {
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	if (numberOfPeriods < 1) return undefined;
+	real80 sum = 0.0;
+	for (integer i = imin; i < imax; i ++) {
 		if (PointProcess_isPeriod (me, i, minimumPeriod, maximumPeriod, maximumPeriodFactor)) {
 			sum += my t [i + 1] - my t [i];   // this interval counts as a period
 		} else {
 			numberOfPeriods --;   // this interval does not count as a period
 		}
 	}
-	return numberOfPeriods > 0 ? sum / numberOfPeriods : NUMundefined;
+	return numberOfPeriods > 0 ? real (sum / numberOfPeriods) : undefined;
 }
 
 double PointProcess_getStdevPeriod (PointProcess me, double tmin, double tmax,
 	double minimumPeriod, double maximumPeriod, double maximumPeriodFactor)
 {
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   // autowindowing
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
-	if (numberOfPeriods < 2) return NUMundefined;
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	if (numberOfPeriods < 2) return undefined;
 	/*
 	 * Compute mean.
 	 */
-	double sum = 0.0;
-	for (long i = imin; i < imax; i ++) {
+	real80 sum = 0.0;
+	for (integer i = imin; i < imax; i ++) {
 		if (PointProcess_isPeriod (me, i, minimumPeriod, maximumPeriod, maximumPeriodFactor)) {
 			sum += my t [i + 1] - my t [i];   // this interval counts as a period
 		} else {
 			numberOfPeriods --;   // this interval does not count as a period
 		}
 	}
-	if (numberOfPeriods < 2) return NUMundefined;
-	double mean = sum / numberOfPeriods;
+	if (numberOfPeriods < 2) return undefined;
+	double mean = real (sum / numberOfPeriods);
 	/*
 	 * Compute variance.
 	 */
-	double sum2 = 0.0;
-	for (long i = imin; i < imax; i ++) {
+	real80 sum2 = 0.0;
+	for (integer i = imin; i < imax; i ++) {
 		if (PointProcess_isPeriod (me, i, minimumPeriod, maximumPeriod, maximumPeriodFactor)) {
 			double dperiod = my t [i + 1] - my t [i] - mean;
 			sum2 += dperiod * dperiod;
@@ -474,7 +476,7 @@ double PointProcess_getStdevPeriod (PointProcess me, double tmin, double tmax,
 	/*
 	 * Compute standard deviation.
 	 */
-	return sqrt (sum2 / (numberOfPeriods - 1));
+	return sqrt (real (sum2 / (numberOfPeriods - 1)));
 }
 
 /* End of file PointProcess.cpp */
diff --git a/fon/PointProcess.h b/fon/PointProcess.h
index 850cef5..282dfe1 100644
--- a/fon/PointProcess.h
+++ b/fon/PointProcess.h
@@ -2,7 +2,7 @@
 #define _PointProcess_h_
 /* PointProcess.h
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,18 +23,18 @@
 
 #include "PointProcess_def.h"
 
-autoPointProcess PointProcess_create (double startingTime, double finishingTime, long initialMaxnt);
+autoPointProcess PointProcess_create (double startingTime, double finishingTime, integer initialMaxnt);
 autoPointProcess PointProcess_createPoissonProcess (double startingTime, double finishingTime, double density);
-void PointProcess_init (PointProcess me, double startingTime, double finishingTime, long initialMaxnt);
-long PointProcess_getLowIndex (PointProcess me, double t);
-long PointProcess_getHighIndex (PointProcess me, double t);
-long PointProcess_getNearestIndex (PointProcess me, double t);
-long PointProcess_getWindowPoints (PointProcess me, double tmin, double tmax, long *p_imin, long *p_imax);
+void PointProcess_init (PointProcess me, double startingTime, double finishingTime, integer initialMaxnt);
+integer PointProcess_getLowIndex (PointProcess me, double t);
+integer PointProcess_getHighIndex (PointProcess me, double t);
+integer PointProcess_getNearestIndex (PointProcess me, double t);
+integer PointProcess_getWindowPoints (PointProcess me, double tmin, double tmax, integer *p_imin, integer *p_imax);
 void PointProcess_addPoint (PointProcess me, double t);
-long PointProcess_findPoint (PointProcess me, double t);
-void PointProcess_removePoint (PointProcess me, long index);
+integer PointProcess_findPoint (PointProcess me, double t);
+void PointProcess_removePoint (PointProcess me, integer index);
 void PointProcess_removePointNear (PointProcess me, double t);
-void PointProcess_removePoints (PointProcess me, long first, long last);
+void PointProcess_removePoints (PointProcess me, integer first, integer last);
 void PointProcess_removePointsBetween (PointProcess me, double fromTime, double toTime);
 void PointProcess_draw (PointProcess me, Graphics g, double fromTime, double toTime, bool garnish);
 double PointProcess_getInterval (PointProcess me, double t);
@@ -44,7 +44,7 @@ autoPointProcess PointProcesses_difference (PointProcess me, PointProcess thee);
 void PointProcess_fill (PointProcess me, double tmin, double tmax, double period);
 void PointProcess_voice (PointProcess me, double period, double maxT);
 
-long PointProcess_getNumberOfPeriods (PointProcess me, double tmin, double tmax,
+integer PointProcess_getNumberOfPeriods (PointProcess me, double tmin, double tmax,
 	double minimumPeriod, double maximumPeriod, double maximumPeriodFactor);
 double PointProcess_getMeanPeriod (PointProcess me, double tmin, double tmax,
 	double minimumPeriod, double maximumPeriod, double maximumPeriodFactor);
diff --git a/fon/PointProcess_and_Sound.cpp b/fon/PointProcess_and_Sound.cpp
index e986755..61b0ae5 100644
--- a/fon/PointProcess_and_Sound.cpp
+++ b/fon/PointProcess_and_Sound.cpp
@@ -1,6 +1,6 @@
 /* PointProcess_and_Sound.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -101,7 +101,7 @@ autoSound PointProcess_to_Sound_phonation
 		double *sound = thy z [1];
 		for (long it = 1; it <= my nt; it ++) {
 			double t = my t [it], amplitude = a;
-			double period = NUMundefined, te, phase, flow;
+			double period = undefined, te, phase, flow;
 			long midSample = Sampled_xToNearestIndex (thee.get(), t);
 			/*
 			 * Determine the period: first look left (because that's where the open phase is),
@@ -110,17 +110,17 @@ autoSound PointProcess_to_Sound_phonation
 			if (it >= 2) {
 				period = my t [it] - my t [it - 1];
 				if (period > maximumPeriod) {
-					period = NUMundefined;
+					period = undefined;
 				}
 			}
-			if (! NUMdefined (period)) {
+			if (isundef (period)) {
 				if (it < my nt) {
 					period = my t [it + 1] - my t [it];
 					if (period > maximumPeriod) {
-						period = NUMundefined;
+						period = undefined;
 					}
 				}
-				if (! NUMdefined (period)) {
+				if (isundef (period)) {
 					period = 0.5 * maximumPeriod;   // some default value
 				}
 			}
diff --git a/fon/Polygon.cpp b/fon/Polygon.cpp
index 00a9cbf..256bd5e 100644
--- a/fon/Polygon.cpp
+++ b/fon/Polygon.cpp
@@ -1,6 +1,6 @@
 /* Polygon.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -42,22 +42,22 @@ void structPolygon :: v_info () {
 }
   
 void structPolygon :: v_writeText (MelderFile file) {
-	texputi4 (file, our numberOfPoints, U"numberOfPoints", 0,0,0,0,0);
+	texputi32 (file, our numberOfPoints, U"numberOfPoints", 0,0,0,0,0);
 	for (long i = 1; i <= our numberOfPoints; i ++) {
-		texputr4 (file, our x [i], U"x [", Melder_integer (i), U"]", 0,0,0);
-		texputr4 (file, our y [i], U"y [", Melder_integer (i), U"]", 0,0,0);
+		texputr64 (file, our x [i], U"x [", Melder_integer (i), U"]", 0,0,0);
+		texputr64 (file, our y [i], U"y [", Melder_integer (i), U"]", 0,0,0);
 	}
 }
 
 void structPolygon :: v_readText (MelderReadText text, int /*formatVersion*/) {
-	our numberOfPoints = texgeti4 (text);
+	our numberOfPoints = texgeti32 (text);
 	if (our numberOfPoints < 1)
 		Melder_throw (U"Cannot read a Polygon with only ", our numberOfPoints, U" points.");
 	our x = NUMvector <double> (1, our numberOfPoints);
 	our y = NUMvector <double> (1, our numberOfPoints);
 	for (long i = 1; i <= our numberOfPoints; i ++) {
-		our x [i] = texgetr4 (text);
-		our y [i] = texgetr4 (text);
+		our x [i] = texgetr64 (text);
+		our y [i] = texgetr64 (text);
 	}
 }
 
@@ -221,7 +221,7 @@ void Polygon_salesperson (Polygon me, long numberOfIterations) {
 			Melder_throw (U"No points.");
 		autoNUMmatrix <int> distance (1, numberOfCities, 1, numberOfCities);
 		computeDistanceTable (me, distance.peek());
-		autoNUMvector <int> path (0L, numberOfCities);
+		autoNUMvector <int> path ((integer) 0, numberOfCities);
 		for (int i = 1; i <= numberOfCities; i ++)
 			path [i] = i;
 		path [0] = numberOfCities;   // close path
diff --git a/fon/Praat_tests.cpp b/fon/Praat_tests.cpp
index c955528..8feda17 100644
--- a/fon/Praat_tests.cpp
+++ b/fon/Praat_tests.cpp
@@ -1,6 +1,6 @@
 /* Praat_tests.cpp
  *
- * Copyright (C) 2001-2012,2015,2016 Paul Boersma
+ * Copyright (C) 2001-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,6 +26,8 @@
 
 #include "Graphics.h"
 #include "praat.h"
+#include "NUM2.h"
+#include "Sound.h"
 
 #include "enums_getText.h"
 #include "Praat_tests_enums.h"
@@ -46,6 +48,11 @@ static autoDaata newAutoData () {
 	autoDaata data (Thing_new (Daata));
 	return data;
 }
+static int length (const char32 *s) {
+	int result = str32len (s);
+	Melder_free (s);
+	return result;
+}
 
 int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *arg4) {
 	int64 n = Melder_atoi (arg1);
@@ -87,9 +94,9 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 		} break;
 		case kPraatTests_TIME_FLOAT: {
 			double sum = 0.0, fn = n;
-			for (double fi = 1.0; fi <= fn; fi = fi + 1.0)
+			for (double fi = 1.0; fi <= fn; fi ++)
 				sum += fi * (fi - 1.0) * (fi - 2.0);
-			t = Melder_stopwatch ();
+			t = Melder_stopwatch ();   // 2.02 ns
 			MelderInfo_writeLine (sum);
 		} break;
 		case kPraatTests_TIME_FLOAT_TO_UNSIGNED_BUILTIN: {
@@ -97,7 +104,7 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 			double fn = n;
 			for (double fi = 1.0; fi <= fn; fi = fi + 1.0)
 				sum += (uint32) fi;
-			t = Melder_stopwatch ();   // 2.59   // 1.60
+			t = Melder_stopwatch ();   // 1.45 ns
 			MelderInfo_writeLine (sum);
 		} break;
 		case kPraatTests_TIME_FLOAT_TO_UNSIGNED_EXTERN: {
@@ -105,7 +112,7 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 			double fn = n;
 			for (double fi = 1.0; fi <= fn; fi = fi + 1.0)
 				sum += (uint32) ((int32) (fi - 2147483648.0) + 2147483647L + 1);
-			t = Melder_stopwatch ();   // 1.60
+			t = Melder_stopwatch ();   // 1.47 ns
 			MelderInfo_writeLine (sum);
 		} break;
 		case kPraatTests_TIME_UNSIGNED_TO_FLOAT_BUILTIN: {
@@ -113,7 +120,7 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 			uint32 nu = (uint32) n;
 			for (uint32 iu = 1; iu <= nu; iu ++)
 				sum += (double) iu;
-			t = Melder_stopwatch ();   // 1.35
+			t = Melder_stopwatch ();   // 0.88 ns
 			MelderInfo_writeLine (sum);
 		} break;
 		case kPraatTests_TIME_UNSIGNED_TO_FLOAT_EXTERN: {
@@ -121,7 +128,7 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 			uint32 nu = (uint32) n;
 			for (uint32 iu = 1; iu <= nu; iu ++)
 				sum += (double) (int32) (iu - 2147483647L - 1) + 2147483648.0;
-			t = Melder_stopwatch ();   // 0.96
+			t = Melder_stopwatch ();   // 0.87 ns
 			MelderInfo_writeLine (sum);
 		} break;
 		case kPraatTests_TIME_STRING_MELDER_32: {
@@ -254,6 +261,128 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 			}
 			t = Melder_stopwatch ();
 		} break;
+		case kPraatTests_TIME_UNDEFINED_NUMUNDEFINED: {
+			bool isAllDefined = true;
+			double x = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				x += (double) i;
+				isAllDefined &= ( x != undefined );
+			}
+			t = Melder_stopwatch ();   // 0.86 ns
+			MelderInfo_writeLine (isAllDefined, U" ", x);
+		} break;
+		case kPraatTests_TIME_UNDEFINED_ISINF_OR_ISNAN: {
+			bool isAllDefined = true;
+			double x = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				x += (double) i;
+				isAllDefined &= ! isinf (x) && ! isnan (x);
+			}
+			t = Melder_stopwatch ();   // 1.29 ns
+			MelderInfo_writeLine (isAllDefined, U" ", x);
+		} break;
+		case kPraatTests_TIME_UNDEFINED_0x7FF: {
+			bool isAllDefined = true;
+			double x = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				x += (double) i;
+				isAllDefined &= ((* (uint64_t *) & x) & 0x7FF0000000000000) != 0x7FF0000000000000;
+			}
+			t = Melder_stopwatch ();   // 0.90 ns
+			MelderInfo_writeLine (isAllDefined, U" ", x);
+		} break;
+		case kPraatTests_TIME_INNER: {
+			int size = Melder_atoi (arg2);
+			autonumvec x { size, false }, y { size, false };
+			for (int64 i = 1; i <= size; i ++) {
+				x [i] = NUMrandomGauss (0.0, 1.0);
+				y [i] = NUMrandomGauss (0.0, 1.0);
+			}
+			real z = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				z += inner_scalar (x.get(), y.get());
+			}
+			t = Melder_stopwatch () / size;   // 0.43 ns per multiplication-addition pair
+			MelderInfo_writeLine (z);
+		} break;
+		case kPraatTests_TIME_OUTER_NUMMAT: {
+			int nrow = 100, ncol = 100;
+			numvec x { NUMvector<double> (1, nrow), nrow }, y { NUMvector<double> (1, ncol), ncol };
+			for (int64 i = 1; i <= nrow; i ++)
+				x.at [i] = NUMrandomGauss (0.0, 1.0);
+			for (int64 i = 1; i <= ncol; i ++)
+				y.at [i] = NUMrandomGauss (0.0, 1.0);
+			for (int64 i = 1; i <= n; i ++) {
+				const autonummat mat = outer_nummat (x, y);
+			}
+			t = Melder_stopwatch () / nrow / ncol;   // 0.29 ns, i.e. less than one clock cycle per cell
+			NUMvector_free (x.at, 1);
+			NUMvector_free (y.at, 1);
+		} break;
+		case kPraatTests_CHECK_INVFISHERQ: {
+			MelderInfo_writeLine (NUMinvFisherQ (0.003, 1, 100000));
+		} break;
+		case kPraatTests_TIME_AUTOSTRING: {
+			const char32 *strings [6] = { U"ghdg", U"jhd", U"hkfjjd", U"fhfj", U"jhksfd", U"hfjs" };
+			int64 sumOfLengths = 0;
+			for (int64 i = 1; i <= n; i ++) {
+				int istring = i % 6;
+				autostring32 s = Melder_dup (strings [istring]);
+				sumOfLengths += length (s.transfer());
+			}
+			t = Melder_stopwatch ();   // 72 ns (but 152 bytes more)
+			MelderInfo_writeLine (sumOfLengths);
+		} break;
+		case kPraatTests_TIME_CHAR32: {
+			const char32 *strings [6] = { U"ghdg", U"jhd", U"hkfjjd", U"fhfj", U"jhksfd", U"hfjs" };
+			int64 sumOfLengths = 0;
+			for (int64 i = 1; i <= n; i ++) {
+				int istring = i % 6;
+				char32 *s = Melder_dup (strings [istring]);
+				sumOfLengths += length (s);
+			}
+			t = Melder_stopwatch ();   // 72 ns
+			MelderInfo_writeLine (sumOfLengths);
+		} break;
+		case kPraatTests_TIME_SUM: {
+			integer size = Melder_atoi (arg2);
+			autonumvec x { size, false };
+			for (integer i = 1; i <= size; i ++)
+				x.at [i] = NUMrandomGauss (0.0, 1.0);
+			double z = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				real sum = sum_scalar (x.get());
+				z += sum;
+			}
+			t = Melder_stopwatch () / size;   // for size == 100: 0.31 ns
+			MelderInfo_writeLine (z);
+		} break;
+		case kPraatTests_TIME_MEAN: {
+			integer size = Melder_atoi (arg2);
+			autonumvec x { size, false };
+			for (integer i = 1; i <= size; i ++)
+				x.at [i] = NUMrandomGauss (0.0, 1.0);
+			double z = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				real sum = mean_scalar (x.get());
+				z += sum;
+			}
+			t = Melder_stopwatch () / size;   // for size == 100: 0.34 ns
+			MelderInfo_writeLine (z);
+		} break;
+		case kPraatTests_TIME_STDEV: {
+			integer size = 10000;
+			autonumvec x { size, false };
+			for (integer i = 1; i <= size; i ++)
+				x.at [i] = NUMrandomGauss (0.0, 1.0);
+			double z = 0.0;
+			for (int64 i = 1; i <= n; i ++) {
+				real stdev = stdev_scalar (x.get());
+				z += stdev;
+			}
+			t = Melder_stopwatch () / size;
+			MelderInfo_writeLine (z);
+		} break;
 		case kPraatTests_THING_AUTO: {
 			int numberOfThingsBefore = theTotalNumberOfThings;
 			{
@@ -313,7 +442,7 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 			}
 			int numberOfThingsAfter = theTotalNumberOfThings;
 			fprintf (stderr, "Number of things: before %d, after %d\n", numberOfThingsBefore, numberOfThingsAfter);
-			#if 1
+			#if 0
 				MelderCallback<void,structDaata>::FunctionType f;
 				typedef void (*DataFunc) (Daata);
 				typedef void (*OrderedFunc) (Ordered);
@@ -326,6 +455,26 @@ int Praat_tests (int itest, char32 *arg1, char32 *arg2, char32 *arg3, char32 *ar
 				autoDaata data = Thing_new (Daata);
 				dataFun3 (data.get());
 			#endif
+			{
+				#if 0
+				autoMelderAsynchronous x;
+				//autoMelderAsynchronous y = x;   // deleted copy constructor
+				autoMelderAsynchronous y = x.move();   // defined move constructor
+				//x = y;   // deleted copy assignment
+				x = y.move();   // defined move assignment
+				autonumvec a;
+				autonumvec b = a.move();
+				const autonumvec c;
+				const autonumvec d { };
+				double *e;
+				const autonumvec f { e, 10 };
+				const autonumvec g { 100, true };
+				//return f;   // call to deleted constructor
+				#endif
+				autoSound sound = Sound_create (1, 0.0, 1.0, 10000, 0.0001, 0.0);
+				sound = Sound_create (1, 0.0, 1.0, 10000, 0.0001, 0.00005);
+				Melder_casual (U"hello ", sound -> dx);
+			}
 		} break;
 	}
 	MelderInfo_writeLine (Melder_single (t / n * 1e9), U" nanoseconds");
diff --git a/fon/Praat_tests_enums.h b/fon/Praat_tests_enums.h
index 8ea9b1c..35947ef 100644
--- a/fon/Praat_tests_enums.h
+++ b/fon/Praat_tests_enums.h
@@ -1,6 +1,6 @@
 /* Praat_tests_enums.h
  *
- * Copyright (C) 2001-2012,2015,2016 Paul Boersma
+ * Copyright (C) 2001-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,7 +40,18 @@ enums_begin (kPraatTests, 0)
 	enums_add (kPraatTests, 20, TIME_WCSCPY, U"TimeWcscpy")
 	enums_add (kPraatTests, 21, TIME_STR32CPY, U"TimeStr32cpy")
 	enums_add (kPraatTests, 22, TIME_GRAPHICS_TEXT_TOP, U"TimeGraphicsTextTop")
-	enums_add (kPraatTests, 23, THING_AUTO, U"ThingAuto")
-enums_end (kPraatTests, 23, CHECK_RANDOM_1009_2009)
+	enums_add (kPraatTests, 23, TIME_UNDEFINED_NUMUNDEFINED, U"TimeUndefinedNUMundefined")
+	enums_add (kPraatTests, 24, TIME_UNDEFINED_ISINF_OR_ISNAN, U"TimeUndefinedIsinfOrIsnan")
+	enums_add (kPraatTests, 25, TIME_UNDEFINED_0x7FF, U"TimeUndefined0x7FF")
+	enums_add (kPraatTests, 26, TIME_INNER, U"TimeInner")
+	enums_add (kPraatTests, 27, TIME_OUTER_NUMMAT, U"TimeOuter##")
+	enums_add (kPraatTests, 28, CHECK_INVFISHERQ, U"invFisherQ(0.003,1,100000)")
+	enums_add (kPraatTests, 29, TIME_AUTOSTRING, U"TimeAutostring")
+	enums_add (kPraatTests, 30, TIME_CHAR32, U"TimeChar32")
+	enums_add (kPraatTests, 31, TIME_SUM, U"TimeSum")
+	enums_add (kPraatTests, 32, TIME_MEAN, U"TimeMean")
+	enums_add (kPraatTests, 33, TIME_STDEV, U"TimeStdev")
+	enums_add (kPraatTests, 34, THING_AUTO, U"ThingAuto")
+enums_end (kPraatTests, 34, CHECK_RANDOM_1009_2009)
 
 /* End of file Praat_tests_enums.h */
diff --git a/fon/RealTier.cpp b/fon/RealTier.cpp
index 4b61adf..3052cb8 100644
--- a/fon/RealTier.cpp
+++ b/fon/RealTier.cpp
@@ -105,13 +105,13 @@ void RealTier_addPoint (RealTier me, double t, double value) {
 }
 
 double RealTier_getValueAtIndex (RealTier me, long i) {
-	if (i < 1 || i > my points.size) return NUMundefined;
+	if (i < 1 || i > my points.size) return undefined;
 	return my points.at [i] -> value;
 }
 
 double RealTier_getValueAtTime (RealTier me, double t) {
 	long n = my points.size;
-	if (n == 0) return NUMundefined;
+	if (n == 0) return undefined;
 	RealPoint pointRight = my points.at [1];
 	if (t <= pointRight -> number) return pointRight -> value;   // constant extrapolation
 	RealPoint pointLeft = my points.at [n];
@@ -129,22 +129,22 @@ double RealTier_getValueAtTime (RealTier me, double t) {
 }
 
 double RealTier_getMaximumValue (RealTier me) {
-	double result = NUMundefined;
+	double result = undefined;
 	long n = my points.size;
 	for (long i = 1; i <= n; i ++) {
 		RealPoint point = my points.at [i];
-		if (result == NUMundefined || point -> value > result)
+		if (isundef (result) || point -> value > result)
 			result = point -> value;
 	}
 	return result;
 }
 
 double RealTier_getMinimumValue (RealTier me) {
-	double result = NUMundefined;
+	double result = undefined;
 	long n = my points.size;
 	for (long i = 1; i <= n; i ++) {
 		RealPoint point = my points.at [i];
-		if (result == NUMundefined || point -> value < result)
+		if (isundef (result) || point -> value < result)
 			result = point -> value;
 	}
 	return result;
@@ -152,7 +152,7 @@ double RealTier_getMinimumValue (RealTier me) {
 
 double RealTier_getArea (RealTier me, double tmin, double tmax) {
 	long n = my points.size, imin, imax;
-	if (n == 0) return NUMundefined;
+	if (n == 0) return undefined;
 	if (n == 1) return (tmax - tmin) * my points.at [1] -> value;
 	imin = AnyTier_timeToLowIndex (me->asAnyTier(), tmin);
 	if (imin == n) return (tmax - tmin) * my points.at [n] -> value;
@@ -189,15 +189,14 @@ double RealTier_getArea (RealTier me, double tmin, double tmax) {
 double RealTier_getMean_curve (RealTier me, double tmin, double tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindow
 	double area = RealTier_getArea (me, tmin, tmax);
-	if (area == NUMundefined) return NUMundefined;
+	if (isundef (area)) return undefined;
 	return area / (tmax - tmin);
 }
 
 double RealTier_getStandardDeviation_curve (RealTier me, double tmin, double tmax) {
 	long n = my points.size, imin, imax;
-	double mean, integral = 0.0;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindow
-	if (n == 0) return NUMundefined;
+	if (n == 0) return undefined;
 	if (n == 1) return 0.0;
 	imin = AnyTier_timeToLowIndex (me->asAnyTier(), tmin);
 	if (imin == n) return 0.0;
@@ -209,9 +208,10 @@ double RealTier_getStandardDeviation_curve (RealTier me, double tmin, double tma
 	 * Add the areas between the points.
 	 * This works even if imin is 0 (offleft) and/or imax is n + 1 (offright).
 	 */
-	mean = RealTier_getMean_curve (me, tmin, tmax);
+	real mean = RealTier_getMean_curve (me, tmin, tmax);
+	real80 integral = 0.0;
 	for (long i = imin; i < imax; i ++) {
-		double tleft, fleft, tright, fright, sum, diff;
+		double tleft, fleft, tright, fright;
 		if (i == imin) {
 			tleft = tmin;
 			fleft = RealTier_getValueAtTime (me, tmin);
@@ -236,42 +236,42 @@ double RealTier_getStandardDeviation_curve (RealTier me, double tmin, double tma
 		 *   = (t2-t1) [1/4 (f1+f2)^2 + 1/12 (f1-f2)^2]
 		 * In the last expression, we have a sum of squares, which is computationally best.
 		 */
-		sum = fleft + fright;
-		diff = fleft - fright;
+		double sum = fleft + fright;
+		double diff = fleft - fright;
 		integral += (sum * sum + (1.0/3.0) * diff * diff) * (tright - tleft);
 	}
-	return sqrt (0.25 * integral / (tmax - tmin));
+	return sqrt (0.25 * (real) integral / (tmax - tmin));
 }
 
-double RealTier_getMean_points (RealTier me, double tmin, double tmax) {
-	long n = my points.size, imin, imax;
-	double sum = 0.0;
+real RealTier_getMean_points (RealTier me, real tmin, real tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindow
-	n = AnyTier_getWindowPoints (me->asAnyTier(), tmin, tmax, & imin, & imax);
-	if (n == 0) return NUMundefined;
-	for (long i = imin; i <= imax; i ++)
+	integer imin, imax;
+	integer n = AnyTier_getWindowPoints (me->asAnyTier(), tmin, tmax, & imin, & imax);
+	if (n == 0) return undefined;
+	real80 sum = 0.0;
+	for (integer i = imin; i <= imax; i ++)
 		sum += my points.at [i] -> value;
-	return sum / n;
+	return (real) sum / n;
 }
 
-double RealTier_getStandardDeviation_points (RealTier me, double tmin, double tmax) {
-	long n = my points.size, imin, imax;
-	double mean, sum = 0.0;
+real RealTier_getStandardDeviation_points (RealTier me, real tmin, real tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindow
-	n = AnyTier_getWindowPoints (me->asAnyTier(), tmin, tmax, & imin, & imax);
-	if (n < 2) return NUMundefined;
-	mean = RealTier_getMean_points (me, tmin, tmax);
+	integer imin, imax;
+	integer n = AnyTier_getWindowPoints (me->asAnyTier(), tmin, tmax, & imin, & imax);
+	if (n < 2) return undefined;
+	real mean = RealTier_getMean_points (me, tmin, tmax);
+	real80 sum = 0.0;
 	for (long i = imin; i <= imax; i ++) {
-		double diff = my points.at [i] -> value - mean;
+		real diff = my points.at [i] -> value - mean;
 		sum += diff * diff;
 	}
-	return sqrt (sum / (n - 1));
+	return sqrt ((real) sum / (n - 1));
 }
 
 void RealTier_multiplyPart (RealTier me, double tmin, double tmax, double factor) {
-	for (long ipoint = 1; ipoint <= my points.size; ipoint ++) {
+	for (integer ipoint = 1; ipoint <= my points.size; ipoint ++) {
 		RealPoint point = my points.at [ipoint];
-		double t = point -> number;
+		real t = point -> number;
 		if (t >= tmin && t <= tmax) {
 			point -> value *= factor;
 		}
@@ -466,9 +466,9 @@ void RealTier_formula (RealTier me, const char32 *expression, Interpreter interp
 		Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		if (! thee) thee = me;
 		for (long icol = 1; icol <= my points.size; icol ++) {
-			struct Formula_Result result;
+			Formula_Result result;
 			Formula_run (0, icol, & result);
-			if (result. result.numericResult == NUMundefined)
+			if (isundef (result. result.numericResult))
 				Melder_throw (U"Cannot put an undefined value into the tier.");
 			thy points.at [icol] -> value = result. result.numericResult;
 		}
diff --git a/fon/RealTier.h b/fon/RealTier.h
index 1617a55..d46e507 100644
--- a/fon/RealTier.h
+++ b/fon/RealTier.h
@@ -48,12 +48,12 @@ autoRealTier RealTier_createWithClass (double tmin, double tmax, ClassInfo klas)
 */
 
 double RealTier_getValueAtIndex (RealTier me, long point);
-/* No points or 'point' out of range: NUMundefined. */
+/* No points or 'point' out of range: undefined. */
 
 double RealTier_getValueAtTime (RealTier me, double t);
 /* Inside points: linear intrapolation. */
 /* Outside points: constant extrapolation. */
-/* No points: NUMundefined. */
+/* No points: undefined. */
 
 double RealTier_getMinimumValue (RealTier me);
 double RealTier_getMaximumValue (RealTier me);
diff --git a/fon/RealTierEditor.cpp b/fon/RealTierEditor.cpp
index d464c5a..51da7f5 100644
--- a/fon/RealTierEditor.cpp
+++ b/fon/RealTierEditor.cpp
@@ -38,9 +38,9 @@ static void menu_cb_removePoints (RealTierEditor me, EDITOR_ARGS_DIRECT) {
 }
 
 static void menu_cb_addPointAtCursor (RealTierEditor me, EDITOR_ARGS_DIRECT) {
-	if (NUMdefined (my v_minimumLegalValue ()) && my ycursor < my v_minimumLegalValue ())
+	if (isdefined (my v_minimumLegalValue ()) && my ycursor < my v_minimumLegalValue ())
 		Melder_throw (U"Cannot add a point below ", my v_minimumLegalValue (), my v_rightTickUnits (), U".");
-	if (NUMdefined (my v_maximumLegalValue ()) && my ycursor > my v_maximumLegalValue ())
+	if (isdefined (my v_maximumLegalValue ()) && my ycursor > my v_maximumLegalValue ())
 		Melder_throw (U"Cannot add a point above ", my v_maximumLegalValue (), my v_rightTickUnits (), U".");
 	Editor_save (me, U"Add point");
 	RealTier_addPoint ((RealTier) my data, 0.5 * (my startSelection + my endSelection), my ycursor);
@@ -58,9 +58,9 @@ static void menu_cb_addPointAt (RealTierEditor me, EDITOR_ARGS_FORM) {
 		SET_REAL (my v_quantityKey (), my ycursor)
 	EDITOR_DO
 		double desiredValue = GET_REAL (my v_quantityKey ());
-		if (NUMdefined (my v_minimumLegalValue ()) && desiredValue < my v_minimumLegalValue ())
+		if (isdefined (my v_minimumLegalValue ()) && desiredValue < my v_minimumLegalValue ())
 			Melder_throw (U"Cannot add a point below ", my v_minimumLegalValue (), my v_rightTickUnits (), U".");
-		if (NUMdefined (my v_maximumLegalValue ()) && desiredValue > my v_maximumLegalValue ())
+		if (isdefined (my v_maximumLegalValue ()) && desiredValue > my v_maximumLegalValue ())
 			Melder_throw (U"Cannot add a point above ", my v_maximumLegalValue (), my v_rightTickUnits (), U".");
 		Editor_save (me, U"Add point");
 		RealTier_addPoint ((RealTier) my data, GET_REAL (U"Time"), desiredValue);
@@ -111,23 +111,23 @@ void RealTierEditor_updateScaling (RealTierEditor me) {
 		double range = ymax - ymin;
 		if (range == 0.0) ymin -= 1.0, ymax += 1.0;
 		else ymin -= 0.2 * range, ymax += 0.2 * range;
-		if (NUMdefined (my v_minimumLegalValue()) && ymin < my v_minimumLegalValue ())
+		if (isdefined (my v_minimumLegalValue()) && ymin < my v_minimumLegalValue ())
 			ymin = my v_minimumLegalValue ();
-		if (NUMdefined (my v_maximumLegalValue ()) && ymin > my v_maximumLegalValue ())
+		if (isdefined (my v_maximumLegalValue ()) && ymin > my v_maximumLegalValue ())
 			ymin = my v_maximumLegalValue ();
-		if (NUMdefined (my v_minimumLegalValue ()) && ymax < my v_minimumLegalValue ())
+		if (isdefined (my v_minimumLegalValue ()) && ymax < my v_minimumLegalValue ())
 			ymax = my v_minimumLegalValue ();
-		if (NUMdefined (my v_maximumLegalValue ()) && ymax > my v_maximumLegalValue ())
+		if (isdefined (my v_maximumLegalValue ()) && ymax > my v_maximumLegalValue ())
 			ymax = my v_maximumLegalValue ();
 		if (ymin >= ymax) {
-			if (NUMdefined (my v_minimumLegalValue ()) && NUMdefined (my v_maximumLegalValue ())) {
+			if (isdefined (my v_minimumLegalValue ()) && isdefined (my v_maximumLegalValue ())) {
 				ymin = my v_minimumLegalValue ();
 				ymax = my v_maximumLegalValue ();
-			} else if (NUMdefined (my v_minimumLegalValue ())) {
+			} else if (isdefined (my v_minimumLegalValue ())) {
 				ymin = my v_minimumLegalValue ();
 				ymax = ymin + 1.0;
 			} else {
-				Melder_assert (NUMdefined (my v_maximumLegalValue ()));
+				Melder_assert (isdefined (my v_maximumLegalValue ()));
 				ymax = my v_maximumLegalValue ();
 				ymin = ymax - 1.0;
 			}
@@ -333,9 +333,9 @@ bool structRealTierEditor :: v_click (double xWC, double yWC, bool shiftKeyPress
 		RealPoint point = pitch -> points.at [i];
 		point -> number += dt;
 		point -> value += df;
-		if (NUMdefined (v_minimumLegalValue ()) && point -> value < v_minimumLegalValue ())
+		if (isdefined (v_minimumLegalValue ()) && point -> value < v_minimumLegalValue ())
 			point -> value = v_minimumLegalValue ();
-		if (NUMdefined (v_maximumLegalValue ()) && point -> value > v_maximumLegalValue ())
+		if (isdefined (v_maximumLegalValue ()) && point -> value > v_maximumLegalValue ())
 			point -> value = v_maximumLegalValue ();
 	}
 
@@ -357,9 +357,9 @@ bool structRealTierEditor :: v_click (double xWC, double yWC, bool shiftKeyPress
 		 */
 		/*our cursor += dt;*/
 		our ycursor += df;
-		if (NUMdefined (v_minimumLegalValue ()) && our ycursor < v_minimumLegalValue ())
+		if (isdefined (v_minimumLegalValue ()) && our ycursor < v_minimumLegalValue ())
 			our ycursor = v_minimumLegalValue ();
-		if (NUMdefined (v_maximumLegalValue ()) && our ycursor > v_maximumLegalValue ())
+		if (isdefined (v_maximumLegalValue ()) && our ycursor > v_maximumLegalValue ())
 			our ycursor = v_maximumLegalValue ();
 	}
 
diff --git a/fon/RealTierEditor.h b/fon/RealTierEditor.h
index 970a626..6435b1e 100644
--- a/fon/RealTierEditor.h
+++ b/fon/RealTierEditor.h
@@ -2,7 +2,7 @@
 #define _RealTierEditor_h_
 /* RealTierEditor.h
  *
- * Copyright (C) 1992-2011,2012,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -37,8 +37,8 @@ Thing_define (RealTierEditor, TimeSoundEditor) {
 	void v_createMenuItems_view (EditorMenu menu)
 		override;
 
-	virtual double v_minimumLegalValue () { return NUMundefined; }
-	virtual double v_maximumLegalValue () { return NUMundefined; }
+	virtual double v_minimumLegalValue () { return undefined; }
+	virtual double v_maximumLegalValue () { return undefined; }
 	virtual const char32 * v_quantityText () { return U"Y"; }   // normally includes units
 	virtual const char32 * v_quantityKey () { return U"Y"; }   // without units
 	virtual const char32 * v_rightTickUnits () { return U""; }
diff --git a/fon/RunnerMFC.cpp b/fon/RunnerMFC.cpp
index ebf5cbd..6aedfb7 100644
--- a/fon/RunnerMFC.cpp
+++ b/fon/RunnerMFC.cpp
@@ -115,7 +115,7 @@ static void drawNow (RunnerMFC me) {
 				if (visibleText_q) visibleText_p = visibleText_q + 1; else visibleText_p += str32len (visibleText_p);
 			}
 			if (str32nequ (textToDraw, U"\\FI", 3)) {
-				structMelderFile file = { 0 };
+				structMelderFile file { };
 				MelderDir_relativePathToFile (& experiment -> rootDirectory, textToDraw + 3, & file);
 				Graphics_imageFromFile (my graphics.get(), Melder_fileToPath (& file), response -> left, response -> right, response -> bottom, response -> top);
 			} else {
@@ -469,7 +469,7 @@ autoRunnerMFC RunnerMFC_create (const char32 *title, autoExperimentMFCList exper
 		my experiments = experiments.move();
 		my graphics = Graphics_create_xmdrawingarea (my d_drawingArea);
 
-struct structGuiDrawingArea_ResizeEvent event { my d_drawingArea, 0 };
+structGuiDrawingArea_ResizeEvent event { my d_drawingArea, 0, 0 };
 event. width  = GuiControl_getWidth  (my d_drawingArea);
 event. height = GuiControl_getHeight (my d_drawingArea);
 gui_drawingarea_cb_resize (me.get(), & event);
diff --git a/fon/Sampled.cpp b/fon/Sampled.cpp
index 28cb1a2..77ac6b6 100644
--- a/fon/Sampled.cpp
+++ b/fon/Sampled.cpp
@@ -1,6 +1,6 @@
 /* Sampled.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -51,7 +51,7 @@ void structSampled :: v_scaleX (double xminfrom, double xmaxfrom, double xminto,
 	our dx *= (xmaxto - xminto) / (xmaxfrom - xminfrom);
 }
 
-long Sampled_getWindowSamples (Sampled me, double xmin, double xmax, long *ixmin, long *ixmax) {
+integer Sampled_getWindowSamples (Sampled me, double xmin, double xmax, integer *ixmin, integer *ixmax) {
 	double rixmin = 1.0 + ceil ((xmin - my x1) / my dx);
 	double rixmax = 1.0 + floor ((xmax - my x1) / my dx);   // could be above 32-bit LONG_MAX
 	*ixmin = rixmin < 1.0 ? 1 : (long) rixmin;
@@ -82,12 +82,12 @@ void Sampled_shortTermAnalysis (Sampled me, double windowDuration, double timeSt
 }
 
 double Sampled_getValueAtSample (Sampled me, long isamp, long ilevel, int unit) {
-	if (isamp < 1 || isamp > my nx) return NUMundefined;
+	if (isamp < 1 || isamp > my nx) return undefined;
 	return my v_getValueAtSample (isamp, ilevel, unit);
 }
 
 double Sampled_getValueAtX (Sampled me, double x, long ilevel, int unit, bool interpolate) {
-	if (x < my xmin || x > my xmax) return NUMundefined;
+	if (x < my xmin || x > my xmax) return undefined;
 	if (interpolate) {
 		double ireal = Sampled_xToIndex (me, x);
 		long ileft = (long) floor (ireal), inear, ifar;
@@ -98,12 +98,12 @@ double Sampled_getValueAtX (Sampled me, double x, long ilevel, int unit, bool in
 			ifar = ileft, inear = ileft + 1;
 			phase = 1.0 - phase;
 		}
-		if (inear < 1 || inear > my nx) return NUMundefined;   // x out of range?
+		if (inear < 1 || inear > my nx) return undefined;   // x out of range?
 		double fnear = my v_getValueAtSample (inear, ilevel, unit);
-		if (fnear == NUMundefined) return NUMundefined;   // function value not defined?
+		if (isundef (fnear)) return undefined;   // function value not defined?
 		if (ifar < 1 || ifar > my nx) return fnear;   // at edge? Extrapolate
 		double ffar = my v_getValueAtSample (ifar, ilevel, unit);
-		if (ffar == NUMundefined) return fnear;   // neighbour undefined? Extrapolate
+		if (isundef (ffar)) return fnear;   // neighbour undefined? Extrapolate
 		return fnear + phase * (ffar - fnear);   // interpolate
 	}
 	return Sampled_getValueAtSample (me, Sampled_xToNearestIndex (me, x), ilevel, unit);
@@ -113,7 +113,7 @@ long Sampled_countDefinedSamples (Sampled me, long ilevel, int unit) {
 	long numberOfDefinedSamples = 0;
 	for (long isamp = 1; isamp <= my nx; isamp ++) {
 		double value = my v_getValueAtSample (isamp, ilevel, unit);
-		if (value == NUMundefined) continue;
+		if (isundef (value)) continue;
 		numberOfDefinedSamples += 1;
 	}
 	return numberOfDefinedSamples;
@@ -124,7 +124,7 @@ double * Sampled_getSortedValues (Sampled me, long ilevel, int unit, long *retur
 	autoNUMvector <double> values (1, my nx);
 	for (isamp = 1; isamp <= my nx; isamp ++) {
 		double value = my v_getValueAtSample (isamp, ilevel, unit);
-		if (value == NUMundefined) continue;
+		if (isundef (value)) continue;
 		values [++ numberOfDefinedSamples] = value;
 	}
 	if (numberOfDefinedSamples) NUMsort_d (numberOfDefinedSamples, values.peek());
@@ -136,16 +136,16 @@ double Sampled_getQuantile (Sampled me, double xmin, double xmax, double quantil
 	try {
 		autoNUMvector <double> values (1, my nx);
 		Function_unidirectionalAutowindow (me, & xmin, & xmax);
-		if (! Function_intersectRangeWithDomain (me, & xmin, & xmax)) return NUMundefined;
-		long imin, imax, numberOfDefinedSamples = 0;
+		if (! Function_intersectRangeWithDomain (me, & xmin, & xmax)) return undefined;
+		integer imin, imax, numberOfDefinedSamples = 0;
 		Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax);
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double value = my v_getValueAtSample (i, ilevel, unit);
-			if (NUMdefined (value)) {
+			if (isdefined (value)) {
 				values [++ numberOfDefinedSamples] = value;
 			}
 		}
-		double result = NUMundefined;
+		double result = undefined;
 		if (numberOfDefinedSamples >= 1) {
 			NUMsort_d (numberOfDefinedSamples, values.peek());
 			result = NUMquantile (numberOfDefinedSamples, values.peek(), quantile);
@@ -164,16 +164,16 @@ static void Sampled_getSumAndDefinitionRange
 		Outside [x1-dx/2, xN+dx/2], the curve is undefined and neither times nor values are counted.
 		In [x1-dx/2,x1] and [xN,xN+dx/2], the curve is linearly extrapolated.
 	*/
-	long imin, imax, isamp;
-	double sum = 0.0, definitionRange = 0.0;
+	real80 sum = 0.0, definitionRange = 0.0;
 	Function_unidirectionalAutowindow (me, & xmin, & xmax);
 	if (Function_intersectRangeWithDomain (me, & xmin, & xmax)) {
 		if (interpolate) {
+			integer imin, imax;
 			if (Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) {
 				double leftEdge = my x1 - 0.5 * my dx, rightEdge = leftEdge + my nx * my dx;
-				for (isamp = imin; isamp <= imax; isamp ++) {
+				for (integer isamp = imin; isamp <= imax; isamp ++) {
 					double value = my v_getValueAtSample (isamp, ilevel, unit);   // a fast way to integrate a linearly interpolated curve; works everywhere except at the edges
-					if (NUMdefined (value)) {
+					if (isdefined (value)) {
 						definitionRange += 1.0;
 						sum += value;
 					}
@@ -185,10 +185,10 @@ static void Sampled_getSumAndDefinitionRange
 					double phase = (my x1 + (imin - 1) * my dx - xmin) / my dx;   // this fraction of sampling interval is still to be determined
 					double rightValue = Sampled_getValueAtSample (me, imin, ilevel, unit);
 					double leftValue = Sampled_getValueAtSample (me, imin - 1, ilevel, unit);
-					if (NUMdefined (rightValue)) {
+					if (isdefined (rightValue)) {
 						definitionRange -= 0.5;   // delete constant extrapolation over 0.5 sample
 						sum -= 0.5 * rightValue;
-						if (NUMdefined (leftValue)) {
+						if (isdefined (leftValue)) {
 							definitionRange += phase;   // add current fraction
 							sum += phase * (rightValue + 0.5 * phase * (leftValue - rightValue));   // interpolate to outside sample
 						} else {
@@ -196,7 +196,7 @@ static void Sampled_getSumAndDefinitionRange
 							definitionRange += phase;   // add current fraction, but never more than 0.5
 							sum += phase * rightValue;
 						}
-					} else if (NUMdefined (leftValue) && phase > 0.5) {
+					} else if (isdefined (leftValue) && phase > 0.5) {
 						definitionRange += phase - 0.5;
 						sum += (phase - 0.5) * leftValue;
 					}
@@ -205,10 +205,10 @@ static void Sampled_getSumAndDefinitionRange
 					double phase = (xmax - (my x1 + (imax - 1) * my dx)) / my dx;   // this fraction of sampling interval is still to be determined
 					double leftValue = Sampled_getValueAtSample (me, imax, ilevel, unit);
 					double rightValue = Sampled_getValueAtSample (me, imax + 1, ilevel, unit);
-					if (NUMdefined (leftValue)) {
+					if (isdefined (leftValue)) {
 						definitionRange -= 0.5;   // delete constant extrapolation over 0.5 sample
 						sum -= 0.5 * leftValue;
-						if (NUMdefined (rightValue)) {
+						if (isdefined (rightValue)) {
 							definitionRange += phase;   // add current fraction
 							sum += phase * (leftValue + 0.5 * phase * (rightValue - leftValue));   // interpolate to outside sample
 						} else {
@@ -216,7 +216,7 @@ static void Sampled_getSumAndDefinitionRange
 							definitionRange += phase;   // add current fraction, but never more than 0.5
 							sum += phase * leftValue;
 						}
-					} else if (NUMdefined (rightValue) && phase > 0.5) {
+					} else if (isdefined (rightValue) && phase > 0.5) {
 						definitionRange += phase - 0.5;
 						sum += (phase - 0.5) * rightValue;
 					}
@@ -231,8 +231,8 @@ static void Sampled_getSumAndDefinitionRange
 				double phase1 = (xmin - (my x1 + (imax - 1) * my dx)) / my dx;
 				double phase2 = (xmax - (my x1 + (imax - 1) * my dx)) / my dx;
 				if (imin == imax + 1) {   // not too far from sample definition region
-					if (NUMdefined (leftValue)) {
-						if (NUMdefined (rightValue)) {
+					if (isdefined (leftValue)) {
+						if (isdefined (rightValue)) {
 							definitionRange += phase2 - phase1;
 							sum += (phase2 - phase1) * (leftValue + 0.5 * (phase1 + phase2) * (rightValue - leftValue));
 						} else if (phase1 < 0.5) {
@@ -240,7 +240,7 @@ static void Sampled_getSumAndDefinitionRange
 							definitionRange += phase2 - phase1;
 							sum += (phase2 - phase1) * leftValue;
 						}
-					} else if (NUMdefined (rightValue) && phase2 > 0.5) {
+					} else if (isdefined (rightValue) && phase2 > 0.5) {
 						if (phase1 < 0.5) phase1 = 0.5;
 						definitionRange += phase2 - phase1;
 						sum += (phase2 - phase1) * rightValue;
@@ -250,18 +250,18 @@ static void Sampled_getSumAndDefinitionRange
 		} else {   // no interpolation
 			double rimin = Sampled_xToIndex (me, xmin), rimax = Sampled_xToIndex (me, xmax);
 			if (rimax >= 0.5 && rimin < my nx + 0.5) {
-				imin = rimin < 0.5 ? 0 : (long) floor (rimin + 0.5);
-				imax = rimax >= my nx + 0.5 ? my nx + 1 : (long) floor (rimax + 0.5);
-				for (isamp = imin + 1; isamp < imax; isamp ++) {
+				integer imin = rimin < 0.5 ? 0 : (integer) floor (rimin + 0.5);
+				integer imax = rimax >= my nx + 0.5 ? my nx + 1 : (integer) floor (rimax + 0.5);
+				for (integer isamp = imin + 1; isamp < imax; isamp ++) {
 					double value = my v_getValueAtSample (isamp, ilevel, unit);
-					if (NUMdefined (value)) {
+					if (isdefined (value)) {
 						definitionRange += 1.0;
 						sum += value;
 					}
 				}
 				if (imin == imax) {
 					double value = my v_getValueAtSample (imin, ilevel, unit);
-					if (NUMdefined (value)) {
+					if (isdefined (value)) {
 						double phase = rimax - rimin;
 						definitionRange += phase;
 						sum += phase * value;
@@ -269,7 +269,7 @@ static void Sampled_getSumAndDefinitionRange
 				} else {
 					if (imin >= 1) {
 						double value = my v_getValueAtSample (imin, ilevel, unit);
-						if (NUMdefined (value)) {
+						if (isdefined (value)) {
 							double phase = imin - rimin + 0.5;
 							definitionRange += phase;
 							sum += phase * value;
@@ -277,7 +277,7 @@ static void Sampled_getSumAndDefinitionRange
 					}
 					if (imax <= my nx) {
 						double value = my v_getValueAtSample (imax, ilevel, unit);
-						if (NUMdefined (value)) {
+						if (isdefined (value)) {
 							double phase = rimax - imax + 0.5;
 							definitionRange += phase;
 							sum += phase * value;
@@ -287,14 +287,14 @@ static void Sampled_getSumAndDefinitionRange
 			}
 		}
 	}
-	if (return_sum) *return_sum = sum;
-	if (return_definitionRange) *return_definitionRange = definitionRange;
+	if (return_sum) *return_sum = (real) sum;
+	if (return_definitionRange) *return_definitionRange = (real) definitionRange;
 }
 
 double Sampled_getMean (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
 	double sum, definitionRange;
 	Sampled_getSumAndDefinitionRange (me, xmin, xmax, ilevel, unit, interpolate, & sum, & definitionRange);
-	return definitionRange <= 0.0 ? NUMundefined : sum / definitionRange;
+	return definitionRange <= 0.0 ? undefined : sum / definitionRange;
 }
 
 double Sampled_getMean_standardUnit (Sampled me, double xmin, double xmax, long ilevel, int averagingUnit, bool interpolate) {
@@ -319,16 +319,16 @@ static void Sampled_getSum2AndDefinitionRange
 		Outside [x1-dx/2, xN+dx/2], the curve is undefined and neither times nor values are counted.
 		In [x1-dx/2,x1] and [xN,xN+dx/2], the curve is linearly extrapolated.
 	*/
-	long imin, imax;
-	double sum2 = 0.0, definitionRange = 0.0;
+	real80 sum2 = 0.0, definitionRange = 0.0;
 	Function_unidirectionalAutowindow (me, & xmin, & xmax);
 	if (Function_intersectRangeWithDomain (me, & xmin, & xmax)) {
 		if (interpolate) {
+			integer imin, imax;
 			if (Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) {
 				double leftEdge = my x1 - 0.5 * my dx, rightEdge = leftEdge + my nx * my dx;
 				for (long isamp = imin; isamp <= imax; isamp ++) {
 					double value = my v_getValueAtSample (isamp, ilevel, unit);   // a fast way to integrate a linearly interpolated curve; works everywhere except at the edges
-					if (NUMdefined (value)) {
+					if (isdefined (value)) {
 						value -= mean;
 						value *= value;
 						definitionRange += 1.0;
@@ -342,12 +342,12 @@ static void Sampled_getSum2AndDefinitionRange
 					double phase = (my x1 + (imin - 1) * my dx - xmin) / my dx;   // this fraction of sampling interval is still to be determined
 					double rightValue = Sampled_getValueAtSample (me, imin, ilevel, unit);
 					double leftValue = Sampled_getValueAtSample (me, imin - 1, ilevel, unit);
-					if (NUMdefined (rightValue)) {
+					if (isdefined (rightValue)) {
 						rightValue -= mean;
 						rightValue *= rightValue;
 						definitionRange -= 0.5;   // delete constant extrapolation over 0.5 sample
 						sum2 -= 0.5 * rightValue;
-						if (NUMdefined (leftValue)) {
+						if (isdefined (leftValue)) {
 							leftValue -= mean;
 							leftValue *= leftValue;
 							definitionRange += phase;   // add current fraction
@@ -357,7 +357,7 @@ static void Sampled_getSum2AndDefinitionRange
 							definitionRange += phase;   // add current fraction, but never more than 0.5
 							sum2 += phase * rightValue;
 						}
-					} else if (NUMdefined (leftValue) && phase > 0.5) {
+					} else if (isdefined (leftValue) && phase > 0.5) {
 						leftValue -= mean;
 						leftValue *= leftValue;
 						definitionRange += phase - 0.5;
@@ -368,12 +368,12 @@ static void Sampled_getSum2AndDefinitionRange
 					double phase = (xmax - (my x1 + (imax - 1) * my dx)) / my dx;   // this fraction of sampling interval is still to be determined
 					double leftValue = Sampled_getValueAtSample (me, imax, ilevel, unit);
 					double rightValue = Sampled_getValueAtSample (me, imax + 1, ilevel, unit);
-					if (NUMdefined (leftValue)) {
+					if (isdefined (leftValue)) {
 						leftValue -= mean;
 						leftValue *= leftValue;
 						definitionRange -= 0.5;   // delete constant extrapolation over 0.5 sample
 						sum2 -= 0.5 * leftValue;
-						if (NUMdefined (rightValue)) {
+						if (isdefined (rightValue)) {
 							rightValue -= mean;
 							rightValue *= rightValue;
 							definitionRange += phase;   // add current fraction
@@ -383,7 +383,7 @@ static void Sampled_getSum2AndDefinitionRange
 							definitionRange += phase;   // add current fraction, but never more than 0.5
 							sum2 += phase * leftValue;
 						}
-					} else if (NUMdefined (rightValue) && phase > 0.5) {
+					} else if (isdefined (rightValue) && phase > 0.5) {
 						rightValue -= mean;
 						rightValue *= rightValue;
 						definitionRange += phase - 0.5;
@@ -400,10 +400,10 @@ static void Sampled_getSum2AndDefinitionRange
 				double phase1 = (xmin - (my x1 + (imax - 1) * my dx)) / my dx;
 				double phase2 = (xmax - (my x1 + (imax - 1) * my dx)) / my dx;
 				if (imin == imax + 1) {   // not too far from sample definition region
-					if (NUMdefined (leftValue)) {
+					if (isdefined (leftValue)) {
 						leftValue -= mean;
 						leftValue *= leftValue;
-						if (NUMdefined (rightValue)) {
+						if (isdefined (rightValue)) {
 							rightValue -= mean;
 							rightValue *= rightValue;
 							definitionRange += phase2 - phase1;
@@ -413,7 +413,7 @@ static void Sampled_getSum2AndDefinitionRange
 							definitionRange += phase2 - phase1;
 							sum2 += (phase2 - phase1) * leftValue;
 						}
-					} else if (NUMdefined (rightValue) && phase2 > 0.5) {
+					} else if (isdefined (rightValue) && phase2 > 0.5) {
 						rightValue -= mean;
 						rightValue *= rightValue;
 						if (phase1 < 0.5) phase1 = 0.5;
@@ -425,11 +425,11 @@ static void Sampled_getSum2AndDefinitionRange
 		} else {   // no interpolation
 			double rimin = Sampled_xToIndex (me, xmin), rimax = Sampled_xToIndex (me, xmax);
 			if (rimax >= 0.5 && rimin < my nx + 0.5) {
-				imin = rimin < 0.5 ? 0 : lround (rimin);
-				imax = rimax >= my nx + 0.5 ? my nx + 1 : lround (rimax);
-				for (long isamp = imin + 1; isamp < imax; isamp ++) {
+				integer imin = rimin < 0.5 ? 0 : lround (rimin);
+				integer imax = rimax >= my nx + 0.5 ? my nx + 1 : lround (rimax);
+				for (integer isamp = imin + 1; isamp < imax; isamp ++) {
 					double value = my v_getValueAtSample (isamp, ilevel, unit);
-					if (NUMdefined (value)) {
+					if (isdefined (value)) {
 						value -= mean;
 						value *= value;
 						definitionRange += 1.0;
@@ -438,7 +438,7 @@ static void Sampled_getSum2AndDefinitionRange
 				}
 				if (imin == imax) {
 					double value = my v_getValueAtSample (imin, ilevel, unit);
-					if (NUMdefined (value)) {
+					if (isdefined (value)) {
 						double phase = rimax - rimin;
 						value -= mean;
 						value *= value;
@@ -448,7 +448,7 @@ static void Sampled_getSum2AndDefinitionRange
 				} else {
 					if (imin >= 1) {
 						double value = my v_getValueAtSample (imin, ilevel, unit);
-						if (NUMdefined (value)) {
+						if (isdefined (value)) {
 							double phase = imin - rimin + 0.5;
 							value -= mean;
 							value *= value;
@@ -458,7 +458,7 @@ static void Sampled_getSum2AndDefinitionRange
 					}
 					if (imax <= my nx) {
 						double value = my v_getValueAtSample (imax, ilevel, unit);
-						if (NUMdefined (value)) {
+						if (isdefined (value)) {
 							double phase = rimax - imax + 0.5;
 							value -= mean;
 							value *= value;
@@ -470,14 +470,14 @@ static void Sampled_getSum2AndDefinitionRange
 			}
 		}
 	}
-	if (return_sum2) *return_sum2 = sum2;
-	if (return_definitionRange) *return_definitionRange = definitionRange;
+	if (return_sum2) *return_sum2 = (real) sum2;
+	if (return_definitionRange) *return_definitionRange = (real) definitionRange;
 }
 
 double Sampled_getStandardDeviation (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
 	double sum, sum2, definitionRange;
 	Sampled_getSumAndDefinitionRange (me, xmin, xmax, ilevel, unit, interpolate, & sum, & definitionRange);
-	if (definitionRange < 2.0) return NUMundefined;
+	if (definitionRange < 2.0) return undefined;
 	Sampled_getSum2AndDefinitionRange (me, xmin, xmax, ilevel, unit, sum / definitionRange, interpolate, & sum2, & definitionRange);
 	return sqrt (sum2 / (definitionRange - 1.0));
 }
@@ -490,16 +490,16 @@ void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, long ilevel,
 	double *return_minimum, double *return_xOfMinimum)
 {
 	double minimum = 1e301, xOfMinimum = 0.0;
-	if (xmin == NUMundefined || xmax == NUMundefined) {
-		minimum = xOfMinimum = NUMundefined;
+	if (isundef (xmin) || isundef (xmax)) {
+		minimum = xOfMinimum = undefined;
 		goto end;
 	}
 	Function_unidirectionalAutowindow (me, & xmin, & xmax);
 	if (! Function_intersectRangeWithDomain (me, & xmin, & xmax)) {
-		minimum = xOfMinimum = NUMundefined;   // requested range and logical domain do not intersect
+		minimum = xOfMinimum = undefined;   // requested range and logical domain do not intersect
 		goto end;
 	}
-	long imin, imax;
+	integer imin, imax;
 	if (! Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) {
 		/*
 		 * No sample centres between xmin and xmax.
@@ -507,21 +507,21 @@ void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, long ilevel,
 		 */
 		double fleft = Sampled_getValueAtX (me, xmin, ilevel, unit, interpolate);
 		double fright = Sampled_getValueAtX (me, xmax, ilevel, unit, interpolate);
-		if (NUMdefined (fleft) && fleft < minimum) minimum = fleft, xOfMinimum = xmin;
-		if (NUMdefined (fright) && fright < minimum) minimum = fright, xOfMinimum = xmax;
+		if (isdefined (fleft) && fleft < minimum) minimum = fleft, xOfMinimum = xmin;
+		if (isdefined (fright) && fright < minimum) minimum = fright, xOfMinimum = xmax;
 	} else {
 		for (long i = imin; i <= imax; i ++) {
 			double fmid = my v_getValueAtSample (i, ilevel, unit);
-			if (fmid == NUMundefined) continue;
+			if (isundef (fmid)) continue;
 			if (! interpolate) {
 				if (fmid < minimum) minimum = fmid, xOfMinimum = i;
 			} else {
 				/*
 				 * Try an interpolation, possibly even taking into account a sample just outside the selection.
 				 */
-				double fleft = i <= 1 ? NUMundefined : my v_getValueAtSample (i - 1, ilevel, unit);
-				double fright = i >= my nx ? NUMundefined : my v_getValueAtSample (i + 1, ilevel, unit);
-				if (fleft == NUMundefined || fright == NUMundefined) {
+				double fleft = i <= 1 ? undefined : my v_getValueAtSample (i - 1, ilevel, unit);
+				double fright = i >= my nx ? undefined : my v_getValueAtSample (i + 1, ilevel, unit);
+				if (isundef (fleft) || isundef (fright)) {
 					if (fmid < minimum) minimum = fmid, xOfMinimum = i;
 				} else if (fmid < fleft && fmid <= fright) {
 					double y [4], i_real, localMinimum;
@@ -537,13 +537,13 @@ void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, long ilevel,
 		if (interpolate) {
 			double fleft = Sampled_getValueAtX (me, xmin, ilevel, unit, true);
 			double fright = Sampled_getValueAtX (me, xmax, ilevel, unit, true);
-			if (NUMdefined (fleft) && fleft < minimum) minimum = fleft, xOfMinimum = xmin;
-			if (NUMdefined (fright) && fright < minimum) minimum = fright, xOfMinimum = xmax;
+			if (isdefined (fleft) && fleft < minimum) minimum = fleft, xOfMinimum = xmin;
+			if (isdefined (fright) && fright < minimum) minimum = fright, xOfMinimum = xmax;
 		}
 		if (xOfMinimum < xmin) xOfMinimum = xmin;
 		if (xOfMinimum > xmax) xOfMinimum = xmax;
 	}
-	if (minimum == 1e301) minimum = xOfMinimum = NUMundefined;
+	if (minimum == 1e301) minimum = xOfMinimum = undefined;
 end:
 	if (return_minimum) *return_minimum = minimum;
 	if (return_xOfMinimum) *return_xOfMinimum = xOfMinimum;
@@ -565,16 +565,16 @@ void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, long ilevel,
 	double *return_maximum, double *return_xOfMaximum)
 {
 	double maximum = -1e301, xOfMaximum = 0.0;
-	if (xmin == NUMundefined || xmax == NUMundefined) {
-		maximum = xOfMaximum = NUMundefined;
+	if (isundef (xmin) || isundef (xmax)) {
+		maximum = xOfMaximum = undefined;
 		goto end;
 	}
 	Function_unidirectionalAutowindow (me, & xmin, & xmax);
 	if (! Function_intersectRangeWithDomain (me, & xmin, & xmax)) {
-		maximum = xOfMaximum = NUMundefined;   // requested range and logical domain do not intersect
+		maximum = xOfMaximum = undefined;   // requested range and logical domain do not intersect
 		goto end;
 	}
-	long imin, imax;
+	integer imin, imax;
 	if (! Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) {
 		/*
 		 * No sample centres between tmin and tmax.
@@ -582,21 +582,23 @@ void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, long ilevel,
 		 */
 		double fleft = Sampled_getValueAtX (me, xmin, ilevel, unit, interpolate);
 		double fright = Sampled_getValueAtX (me, xmax, ilevel, unit, interpolate);
-		if (NUMdefined (fleft) && fleft > maximum) maximum = fleft, xOfMaximum = xmin;
-		if (NUMdefined (fright) && fright > maximum) maximum = fright, xOfMaximum = xmax;
+		if (isdefined (fleft) && fleft > maximum) maximum = fleft, xOfMaximum = xmin;
+		if (isdefined (fright) && fright > maximum) maximum = fright, xOfMaximum = xmax;
 	} else {
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double fmid = my v_getValueAtSample (i, ilevel, unit);
-			if (fmid == NUMundefined) continue;
+			if (isundef (fmid)) continue;
 			if (! interpolate) {
 				if (fmid > maximum) maximum = fmid, xOfMaximum = i;
 			} else {
 				/*
 				 * Try an interpolation, possibly even taking into account a sample just outside the selection.
 				 */
-				double fleft = i <= 1 ? NUMundefined : my v_getValueAtSample (i - 1, ilevel, unit);
-				double fright = i >= my nx ? NUMundefined : my v_getValueAtSample (i + 1, ilevel, unit);
-				if (fleft == NUMundefined || fright == NUMundefined) {
+				double fleft =
+					i <= 1 ? undefined : my v_getValueAtSample (i - 1, ilevel, unit);
+				double fright =
+					i >= my nx ? undefined : my v_getValueAtSample (i + 1, ilevel, unit);
+				if (isundef (fleft) || isundef (fright)) {
 					if (fmid > maximum) maximum = fmid, xOfMaximum = i;
 				} else if (fmid > fleft && fmid >= fright) {
 					double y [4], i_real, localMaximum;
@@ -612,13 +614,13 @@ void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, long ilevel,
 		if (interpolate) {
 			double fleft = Sampled_getValueAtX (me, xmin, ilevel, unit, true);
 			double fright = Sampled_getValueAtX (me, xmax, ilevel, unit, true);
-			if (NUMdefined (fleft) && fleft > maximum) maximum = fleft, xOfMaximum = xmin;
-			if (NUMdefined (fright) && fright > maximum) maximum = fright, xOfMaximum = xmax;
+			if (isdefined (fleft) && fleft > maximum) maximum = fleft, xOfMaximum = xmin;
+			if (isdefined (fright) && fright > maximum) maximum = fright, xOfMaximum = xmax;
 		}
 		if (xOfMaximum < xmin) xOfMaximum = xmin;
 		if (xOfMaximum > xmax) xOfMaximum = xmax;
 	}
-	if (maximum == -1e301) maximum = xOfMaximum = NUMundefined;
+	if (maximum == -1e301) maximum = xOfMaximum = undefined;
 end:
 	if (return_maximum) *return_maximum = maximum;
 	if (return_xOfMaximum) *return_xOfMaximum = xOfMaximum;
@@ -640,7 +642,7 @@ static void Sampled_speckleInside (Sampled me, Graphics g, double xmin, double x
 	long ilevel, int unit)
 {
 	Function_unidirectionalAutowindow (me, & xmin, & xmax);
-	long ixmin, ixmax;
+	integer ixmin, ixmax;
 	Sampled_getWindowSamples (me, xmin, xmax, & ixmin, & ixmax);
 	if (Function_isUnitLogarithmic (me, ilevel, unit)) {
 		ymin = Function_convertStandardToSpecialUnit (me, ymin, ilevel, unit);
@@ -648,9 +650,9 @@ static void Sampled_speckleInside (Sampled me, Graphics g, double xmin, double x
 	}
 	if (ymax <= ymin) return;
 	Graphics_setWindow (g, xmin, xmax, ymin, ymax);
-	for (long ix = ixmin; ix <= ixmax; ix ++) {
+	for (integer ix = ixmin; ix <= ixmax; ix ++) {
 		double value = Sampled_getValueAtSample (me, ix, ilevel, unit);
-		if (NUMdefined (value)) {
+		if (isdefined (value)) {
 			double x = Sampled_indexToX (me, ix);
 			if (value >= ymin && value <= ymax) {
 				Graphics_speckle (g, x, value);
@@ -668,7 +670,7 @@ void Sampled_drawInside (Sampled me, Graphics g, double xmin, double xmax, doubl
 			return;
 		}
 		Function_unidirectionalAutowindow (me, & xmin, & xmax);
-		long ixmin, ixmax, startOfDefinedStretch = -1;
+		integer ixmin, ixmax, startOfDefinedStretch = -1;
 		Sampled_getWindowSamples (me, xmin, xmax, & ixmin, & ixmax);
 		if (Function_isUnitLogarithmic (me, ilevel, unit)) {
 			ymin = Function_convertStandardToSpecialUnit (me, ymin, ilevel, unit);
@@ -679,15 +681,15 @@ void Sampled_drawInside (Sampled me, Graphics g, double xmin, double xmax, doubl
 		autoNUMvector <double> xarray (ixmin - 1, ixmax + 1);
 		autoNUMvector <double> yarray (ixmin - 1, ixmax + 1);
 		double previousValue = Sampled_getValueAtSample (me, ixmin - 1, ilevel, unit);
-		if (NUMdefined (previousValue)) {
+		if (isdefined (previousValue)) {
 			startOfDefinedStretch = ixmin - 1;
 			xarray [ixmin - 1] = Sampled_indexToX (me, ixmin - 1);
 			yarray [ixmin - 1] = previousValue;
 		}
-		for (long ix = ixmin; ix <= ixmax; ix ++) {
+		for (integer ix = ixmin; ix <= ixmax; ix ++) {
 			double x = Sampled_indexToX (me, ix), value = Sampled_getValueAtSample (me, ix, ilevel, unit);
-			if (NUMdefined (value)) {
-				if (NUMdefined (previousValue)) {
+			if (isdefined (value)) {
+				if (isdefined (previousValue)) {
 					xarray [ix] = x;
 					yarray [ix] = value;
 				} else {
@@ -697,7 +699,7 @@ void Sampled_drawInside (Sampled me, Graphics g, double xmin, double xmax, doubl
 					xarray [ix] = x;
 					yarray [ix] = value;
 				}
-			} else if (NUMdefined (previousValue)) {
+			} else if (isdefined (previousValue)) {
 				Melder_assert (startOfDefinedStretch >= ixmin - 1);
 				if (ix > ixmin) {
 					xarray [ix] = x - 0.5 * my dx;
@@ -715,8 +717,8 @@ void Sampled_drawInside (Sampled me, Graphics g, double xmin, double xmax, doubl
 		}
 		if (startOfDefinedStretch > -1) {
 			double x = Sampled_indexToX (me, ixmax + 1), value = Sampled_getValueAtSample (me, ixmax + 1, ilevel, unit);
-			Melder_assert (NUMdefined (previousValue));
-			if (NUMdefined (value)) {
+			Melder_assert (isdefined (previousValue));
+			if (isdefined (value)) {
 				xarray [ixmax + 1] = x;
 				yarray [ixmax + 1] = value;
 			} else {
diff --git a/fon/Sampled.h b/fon/Sampled.h
index 361fd2b..69c7cbb 100644
--- a/fon/Sampled.h
+++ b/fon/Sampled.h
@@ -2,7 +2,7 @@
 #define _Sampled_h_
 /* Sampled.h
  *
- * Copyright (C) 1992-2011,2014 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,14 +29,13 @@
 /* The first sample point is at x1, the second at x1 + dx, */
 /* and the last at x1 + (nx - 1) * dx. */
 
-static inline double Sampled_indexToX (Sampled me, long   index) { return my x1 + (index - 1  ) * my dx; }
-static inline double Sampled_indexToX (Sampled me, double index) { return my x1 + (index - 1.0) * my dx; }
-static inline double Sampled_xToIndex (Sampled me, double x) { return (x - my x1) / my dx + 1.0; }
-static inline long Sampled_xToLowIndex     (Sampled me, double x) { return (long) floor ((x - my x1) / my dx + 1.0); }
-static inline long Sampled_xToHighIndex    (Sampled me, double x) { return (long) ceil  ((x - my x1) / my dx + 1.0); }
-static inline long Sampled_xToNearestIndex (Sampled me, double x) { return (long) round ((x - my x1) / my dx + 1.0); }
+template <typename T> static inline double Sampled_indexToX (Sampled me, T index) { return my x1 + (index - (T) 1) * my dx; }
+static inline double Sampled_xToIndex (Sampled me, double        x) { return (x - my x1) / my dx + 1.0; }
+static inline integer Sampled_xToLowIndex     (Sampled me, double x) { return (integer) floor ((x - my x1) / my dx + 1.0); }
+static inline integer Sampled_xToHighIndex    (Sampled me, double x) { return (integer) ceil  ((x - my x1) / my dx + 1.0); }
+static inline integer Sampled_xToNearestIndex (Sampled me, double x) { return (integer) round ((x - my x1) / my dx + 1.0); }
 
-long Sampled_getWindowSamples (Sampled me, double xmin, double xmax, long *ixmin, long *ixmax);
+integer Sampled_getWindowSamples (Sampled me, double xmin, double xmax, integer *ixmin, integer *ixmax);
 
 void Sampled_init (Sampled me, double xmin, double xmax, long nx, double dx, double x1);
 
diff --git a/fon/SampledXY.cpp b/fon/SampledXY.cpp
index ce9829d..cf839d4 100644
--- a/fon/SampledXY.cpp
+++ b/fon/SampledXY.cpp
@@ -1,6 +1,6 @@
 /* SampledXY.cpp
  *
- * Copyright (C) 1992-2012,2013,2014 Paul Boersma
+ * Copyright (C) 1992-2012,2013,2014,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,8 +54,8 @@ Thing_implement (SampledXY, Sampled, 0);
 */
 
 void SampledXY_init (SampledXY me,
-	double xmin, double xmax, long nx, double dx, double x1,
-	double ymin, double ymax, long ny, double dy, double y1)
+	double xmin, double xmax, integer nx, double dx, double x1,
+	double ymin, double ymax, integer ny, double dy, double y1)
 {
 	Sampled_init (me, xmin, xmax, nx, dx, x1);
 	my ymin = ymin;
@@ -65,7 +65,7 @@ void SampledXY_init (SampledXY me,
 	my y1 = y1;
 }
 
-long SampledXY_getWindowSamplesY (SampledXY me, double fromY, double toY, long *iymin, long *iymax) {
+integer SampledXY_getWindowSamplesY (SampledXY me, double fromY, double toY, integer *iymin, integer *iymax) {
 	double riymin = 1.0 + ceil ((fromY - my y1) / my dy);
 	double riymax = 1.0 + floor ((toY - my y1) / my dy);   // could be above 32-bit LONG_MAX
 	*iymin = riymin < 1.0 ? 1 : (long) riymin;
diff --git a/fon/SampledXY.h b/fon/SampledXY.h
index d8c0ab2..cc604ff 100644
--- a/fon/SampledXY.h
+++ b/fon/SampledXY.h
@@ -2,7 +2,7 @@
 #define _SampledXY_h_
 /* SampledXY.h
  *
- * Copyright (C) 1992-2011,2013,2014 Paul Boersma
+ * Copyright (C) 1992-2011,2013,2014,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,17 +22,16 @@
 
 #include "SampledXY_def.h"
 
-void SampledXY_init (SampledXY me, double xmin, double xmax, long nx, double dx, double x1,
-                                   double ymin, double ymax, long ny, double dy, double y1);
+void SampledXY_init (SampledXY me, double xmin, double xmax, integer nx, double dx, double x1,
+                                   double ymin, double ymax, integer ny, double dy, double y1);
 
-static inline double SampledXY_indexToY (SampledXY me, long   index) { return my y1 + (index - 1  ) * my dy; }
-static inline double SampledXY_indexToY (SampledXY me, double index) { return my y1 + (index - 1.0) * my dy; }
+template <typename T> static inline double SampledXY_indexToY (SampledXY me, T index) { return my y1 + (index - (T) 1) * my dy; }
 static inline double SampledXY_yToIndex (SampledXY me, double y) { return (y - my y1) / my dy + 1.0; }
-static inline long SampledXY_yToLowIndex     (SampledXY me, double y) { return (long) floor ((y - my y1) / my dy + 1.0); }
-static inline long SampledXY_yToHighIndex    (SampledXY me, double y) { return (long) ceil  ((y - my y1) / my dy + 1.0); }
-static inline long SampledXY_yToNearestIndex (SampledXY me, double y) { return (long) round ((y - my y1) / my dy + 1.0); }
+static inline integer SampledXY_yToLowIndex     (SampledXY me, double y) { return (integer) floor ((y - my y1) / my dy + 1.0); }
+static inline integer SampledXY_yToHighIndex    (SampledXY me, double y) { return (integer) ceil  ((y - my y1) / my dy + 1.0); }
+static inline integer SampledXY_yToNearestIndex (SampledXY me, double y) { return (integer) round ((y - my y1) / my dy + 1.0); }
 
-long SampledXY_getWindowSamplesY (SampledXY me, double ymin, double ymax, long *iymin, long *iymax);
+integer SampledXY_getWindowSamplesY (SampledXY me, double ymin, double ymax, integer *iymin, integer *iymax);
 
 /* End of file SampledXY.h */
 #endif
diff --git a/fon/Sampled_def.h b/fon/Sampled_def.h
index a726b6c..70f85f0 100644
--- a/fon/Sampled_def.h
+++ b/fon/Sampled_def.h
@@ -55,7 +55,7 @@ oo_DEFINE_CLASS (Sampled, Function)
 			override;
 
 		virtual double v_getValueAtSample (long /* isamp */, long /* ilevel */, int /* unit */)
-			{ return NUMundefined; }
+			{ return undefined; }
 	#endif
 
 oo_END_CLASS (Sampled)
diff --git a/fon/Sound.cpp b/fon/Sound.cpp
index 25d05e9..dd2513b 100644
--- a/fon/Sound.cpp
+++ b/fon/Sound.cpp
@@ -1,6 +1,6 @@
 /* Sound.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -196,16 +196,13 @@ autoSound Sounds_combineToStereo (OrderedOf<structSound>* me) {
 						U"You could resample one or more of the sounds before combining.");
 			}
 		}
-		double sharedMinimumTime = NUMundefined, sharedMaximumTime = NUMundefined;
-		for (long isound = 1; isound <= my size; isound ++) {
+		Melder_assert (my size > 0);
+		double sharedMinimumTime = my at [1] -> xmin;
+		double sharedMaximumTime = my at [1] -> xmax;
+		for (long isound = 2; isound <= my size; isound ++) {
 			Sound sound = my at [isound];
-			if (isound == 1) {
-				sharedMinimumTime = sound -> xmin;
-				sharedMaximumTime = sound -> xmax;
-			} else {
-				if (sound -> xmin < sharedMinimumTime) sharedMinimumTime = sound -> xmin;
-				if (sound -> xmax > sharedMaximumTime) sharedMaximumTime = sound -> xmax;
-			}
+			if (sound -> xmin < sharedMinimumTime) sharedMinimumTime = sound -> xmin;
+			if (sound -> xmax > sharedMaximumTime) sharedMaximumTime = sound -> xmax;
 		}
 		autoNUMvector <double> numberOfInitialZeroes (1, my size);
 		long sharedNumberOfSamples = 0;
@@ -252,56 +249,56 @@ autoSound Sound_extractChannel (Sound me, long ichan) {
 	}
 }
 
-static double getSumOfSquares (Sound me, double xmin, double xmax, long *n) {
+static double getSumOfSquares (Sound me, double xmin, double xmax, integer *n) {
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
-	long imin, imax;
+	integer imin, imax;
 	*n = Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax);
-	if (*n < 1) return NUMundefined;
-	double sum2 = 0.0;
-	for (long channel = 1; channel <= my ny; channel ++) {
+	if (*n < 1) return undefined;
+	real80 sum2 = 0.0;
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		double *amplitude = my z [channel];
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double value = amplitude [i];
 			sum2 += value * value;
 		}
 	}
-	return sum2;
+	return (real) sum2;
 }
 
 double Sound_getRootMeanSquare (Sound me, double xmin, double xmax) {
-	long n;
+	integer n;
 	double sum2 = getSumOfSquares (me, xmin, xmax, & n);
-	return NUMdefined (sum2) ? sqrt (sum2 / (n * my ny)) : NUMundefined;
+	return isdefined (sum2) ? sqrt (sum2 / (n * my ny)) : undefined;
 }
 
 double Sound_getEnergy (Sound me, double xmin, double xmax) {
-	long n;
+	integer n;
 	double sum2 = getSumOfSquares (me, xmin, xmax, & n);
-	return NUMdefined (sum2) ? sum2 * my dx / my ny : NUMundefined;
+	return isdefined (sum2) ? sum2 * my dx / my ny : undefined;
 }
 
 double Sound_getPower (Sound me, double xmin, double xmax) {
-	long n;
+	integer n;
 	double sum2 = getSumOfSquares (me, xmin, xmax, & n);
-	return NUMdefined (sum2) ? sum2 / (n * my ny) : NUMundefined;
+	return isdefined (sum2) ? sum2 / (n * my ny) : undefined;
 }
 
 double Sound_getEnergyInAir (Sound me) {
-	long n;
-	double sum2 = getSumOfSquares (me, 0, 0, & n);
-	return NUMdefined (sum2) ? sum2 * my dx / (400 * my ny) : NUMundefined;
+	integer n;
+	double sum2 = getSumOfSquares (me, 0.0, 0.0, & n);
+	return isdefined (sum2) ? sum2 * my dx / (400.0 * my ny) : undefined;
 }
 
 double Sound_getIntensity_dB (Sound me) {
-	long n;
-	double sum2 = getSumOfSquares (me, 0, 0, & n);
-	return NUMdefined (sum2) && sum2 != 0.0 ? 10 * log10 (sum2 / (n * my ny) / 4.0e-10) : NUMundefined;
+	integer n;
+	double sum2 = getSumOfSquares (me, 0.0, 0.0, & n);
+	return isdefined (sum2) && sum2 != 0.0 ? 10.0 * log10 (sum2 / (n * my ny) / 4.0e-10) : undefined;
 }
 
 double Sound_getPowerInAir (Sound me) {
-	long n;
+	integer n;
 	double sum2 = getSumOfSquares (me, 0, 0, & n);
-	return NUMdefined (sum2) ? sum2 / (n * my ny) / 400 : NUMundefined;
+	return ( isdefined (sum2) ? sum2 / (n * my ny) / 400 : undefined );
 }
 
 autoSound Matrix_to_Sound_mono (Matrix me, long row) {
@@ -745,23 +742,23 @@ autoSound Sound_autoCorrelate (Sound me, enum kSounds_convolve_scaling scaling,
 void Sound_draw (Sound me, Graphics g,
 	double tmin, double tmax, double minimum, double maximum, bool garnish, const char32 *method)
 {
-	long ixmin, ixmax;
 	bool treversed = tmin > tmax;
 	if (treversed) { double temp = tmin; tmin = tmax; tmax = temp; }
 	/*
-	 * Automatic domain.
-	 */
+		Automatic domain.
+	*/
 	if (tmin == tmax) {
 		tmin = my xmin;
 		tmax = my xmax;
 	}
 	/*
-	 * Domain expressed in sample numbers.
-	 */
+		Domain expressed in sample numbers.
+	*/
+	integer ixmin, ixmax;
 	Matrix_getWindowSamplesX (me, tmin, tmax, & ixmin, & ixmax);
 	/*
-	 * Automatic vertical range.
-	 */
+		Automatic vertical range.
+	*/
 	if (minimum == maximum) {
 		Matrix_getWindowExtrema (me, ixmin, ixmax, 1, my ny, & minimum, & maximum);
 		if (minimum == maximum) {
@@ -770,8 +767,8 @@ void Sound_draw (Sound me, Graphics g,
 		}
 	}
 	/*
-	 * Set coordinates for drawing.
-	 */
+		Set coordinates for drawing.
+	*/
 	Graphics_setInner (g);
 	for (long channel = 1; channel <= my ny; channel ++) {
 		Graphics_setWindow (g, treversed ? tmax : tmin, treversed ? tmin : tmax,
@@ -852,7 +849,7 @@ double Sound_getNearestZeroCrossing (Sound me, double position, long channel) {
 		return interpolate (me, leftSample, channel);
 	}
 	/* Search to the left. */
-	if (leftSample > my nx) return NUMundefined;
+	if (leftSample > my nx) return undefined;
 	for (ileft = leftSample - 1; ileft >= 1; ileft --)
 		if ((amplitude [ileft] >= 0.0) != (amplitude [ileft + 1] >= 0.0))
 		{
@@ -860,14 +857,14 @@ double Sound_getNearestZeroCrossing (Sound me, double position, long channel) {
 			break;
 		}
 	/* Search to the right. */
-	if (rightSample < 1) return NUMundefined;
+	if (rightSample < 1) return undefined;
 	for (iright = rightSample + 1; iright <= my nx; iright ++)
 		if ((amplitude [iright] >= 0.0) != (amplitude [iright - 1] >= 0.0))
 		{
 			rightZero = interpolate (me, iright - 1, channel);
 			break;
 		}
-	if (ileft < 1 && iright > my nx) return NUMundefined;
+	if (ileft < 1 && iright > my nx) return undefined;
 	return ileft < 1 ? rightZero : iright > my nx ? leftZero :
 		position - leftZero < rightZero - position ? leftZero : rightZero;
 }
@@ -881,11 +878,11 @@ void Sound_setZero (Sound me, double tmin_in, double tmax_in, bool roundTimesToN
 			if (tmin > my xmin) tmin = Sound_getNearestZeroCrossing (me, tmin_in, channel);
 			if (tmax < my xmax) tmax = Sound_getNearestZeroCrossing (me, tmax_in, channel);
 		}
-		if (tmin == NUMundefined) tmin = my xmin;
-		if (tmax == NUMundefined) tmax = my xmax;
-		long imin, imax;
+		if (isundef (tmin)) tmin = my xmin;
+		if (isundef (tmax)) tmax = my xmax;
+		integer imin, imax;
 		Sampled_getWindowSamples (me, tmin, tmax, & imin, & imax);
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			my z [channel] [i] = 0.0;
 		}
 	}
@@ -900,7 +897,7 @@ autoSound Sound_createAsPureTone (long numberOfChannels, double startingTime, do
 			Melder_throw (U"Cannot create sounds with more than ", Melder_bigInteger (INT32_MAX), U" samples, because they cannot be saved to disk.");
 		autoSound me = Sound_create (numberOfChannels, startingTime, endTime, (long) numberOfSamples_f,
 			1.0 / sampleRate, startingTime + 0.5 / sampleRate);
-		for (long isamp = 1; isamp <= my nx; isamp ++) {
+		for (integer isamp = 1; isamp <= my nx; isamp ++) {
 			double time = my x1 + (isamp - 1) * my dx;
 			double value = amplitude * sin (NUM2pi * frequency * time);
 			double timeFromStart = time - startingTime;
@@ -950,14 +947,14 @@ autoSound Sound_createAsToneComplex (double startTime, double endTime, double sa
 		autoSound me = Sound_create (1, startTime, endTime, lround ((endTime - startTime) * samplingFrequency),
 			1.0 / samplingFrequency, startTime + 0.5 / samplingFrequency);
 		double *amplitude = my z [1];
-		for (long isamp = 1; isamp <= my nx; isamp ++) {
+		for (integer isamp = 1; isamp <= my nx; isamp ++) {
 			double value = 0.0, t = Sampled_indexToX (me.get(), isamp);
 			double omegaStepT = omegaStep * t, firstOmegaT = firstOmega * t;
 			if (phase == Sound_TONE_COMPLEX_SINE) {
-				for (long icomp = 1; icomp <= numberOfComponents; icomp ++)
+				for (integer icomp = 1; icomp <= numberOfComponents; icomp ++)
 					value += sin (firstOmegaT + (icomp - 1) * omegaStepT);
 			} else {
-				for (long icomp = 1; icomp <= numberOfComponents; icomp ++)
+				for (integer icomp = 1; icomp <= numberOfComponents; icomp ++)
 					value += cos (firstOmegaT + (icomp - 1) * omegaStepT);
 			}
 			amplitude [isamp] = value * factor;
@@ -970,77 +967,64 @@ autoSound Sound_createAsToneComplex (double startTime, double endTime, double sa
 
 void Sound_multiplyByWindow (Sound me, enum kSound_windowShape windowShape) {
 	for (long channel = 1; channel <= my ny; channel ++) {
-		long i, n = my nx;
+		integer n = my nx;
 		double *amp = my z [channel];
-		double imid, edge, onebyedge1, factor;
 		switch (windowShape) {
-			case kSound_windowShape_RECTANGULAR:
+			case kSound_windowShape_RECTANGULAR: {
 				;
-			break;
-			case kSound_windowShape_TRIANGULAR:   /* "Bartlett" */
-				for (i = 1; i <= n; i ++) { double phase = (double) i / n;   /* 0..1 */
+			} break; case kSound_windowShape_TRIANGULAR: {   // "Bartlett"
+				for (integer i = 1; i <= n; i ++) { double phase = (double) i / n;   // 0..1
 					amp [i] *= 1.0 - fabs ((2.0 * phase - 1.0)); }
-			break;
-			case kSound_windowShape_PARABOLIC:   /* "Welch" */
-				for (i = 1; i <= n; i ++) { double phase = (double) i / n;
+			} break; case kSound_windowShape_PARABOLIC: {   // "Welch"
+				for (integer i = 1; i <= n; i ++) { double phase = (double) i / n;
 					amp [i] *= 1.0 - (2.0 * phase - 1.0) * (2.0 * phase - 1.0); }
-			break;
-			case kSound_windowShape_HANNING:
-				for (i = 1; i <= n; i ++) { double phase = (double) i / n;
+			} break; case kSound_windowShape_HANNING: {
+				for (integer i = 1; i <= n; i ++) { double phase = (double) i / n;
 					amp [i] *= 0.5 * (1.0 - cos (2.0 * NUMpi * phase)); }
-			break;
-			case kSound_windowShape_HAMMING:
-				for (i = 1; i <= n; i ++) { double phase = (double) i / n;
+			} break; case kSound_windowShape_HAMMING: {
+				for (integer i = 1; i <= n; i ++) { double phase = (double) i / n;
 					amp [i] *= 0.54 - 0.46 * cos (2.0 * NUMpi * phase); }
-			break;
-			case kSound_windowShape_GAUSSIAN_1:
-				imid = 0.5 * (n + 1), edge = exp (-3.0), onebyedge1 = 1 / (1.0 - edge);   /* -0.5..+0.5 */
-				for (i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
+			} break; case kSound_windowShape_GAUSSIAN_1: {
+				real imid = 0.5 * (n + 1), edge = exp (-3.0), onebyedge1 = 1.0 / (1.0 - edge);   // -0.5..+0.5
+				for (integer i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
 					amp [i] *= (exp (-12.0 * phase * phase) - edge) * onebyedge1; }
-			break;
-			case kSound_windowShape_GAUSSIAN_2:
-				imid = 0.5 * (double) (n + 1), edge = exp (-12.0), onebyedge1 = 1 / (1.0 - edge);
-				for (i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
+			} break; case kSound_windowShape_GAUSSIAN_2: {
+				real imid = 0.5 * (double) (n + 1), edge = exp (-12.0), onebyedge1 = 1.0 / (1.0 - edge);
+				for (integer i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
 					amp [i] *= (exp (-48.0 * phase * phase) - edge) * onebyedge1; }
-			break;
-			case kSound_windowShape_GAUSSIAN_3:
-				imid = 0.5 * (double) (n + 1), edge = exp (-27.0), onebyedge1 = 1 / (1.0 - edge);
-				for (i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
+			} break; case kSound_windowShape_GAUSSIAN_3: {
+				real imid = 0.5 * (double) (n + 1), edge = exp (-27.0), onebyedge1 = 1.0 / (1.0 - edge);
+				for (integer i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
 					amp [i] *= (exp (-108.0 * phase * phase) - edge) * onebyedge1; }
-			break;
-			case kSound_windowShape_GAUSSIAN_4:
-				imid = 0.5 * (double) (n + 1), edge = exp (-48.0), onebyedge1 = 1 / (1.0 - edge);
-				for (i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
+			} break; case kSound_windowShape_GAUSSIAN_4: {
+				real imid = 0.5 * (double) (n + 1), edge = exp (-48.0), onebyedge1 = 1.0 / (1.0 - edge);
+				for (integer i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
 					amp [i] *= (exp (-192.0 * phase * phase) - edge) * onebyedge1; }
-			break;
-			case kSound_windowShape_GAUSSIAN_5:
-				imid = 0.5 * (double) (n + 1), edge = exp (-75.0), onebyedge1 = 1 / (1.0 - edge);
-				for (i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
+			} break; case kSound_windowShape_GAUSSIAN_5: {
+				real imid = 0.5 * (double) (n + 1), edge = exp (-75.0), onebyedge1 = 1.0 / (1.0 - edge);
+				for (integer i = 1; i <= n; i ++) { double phase = ((double) i - imid) / n;
 					amp [i] *= (exp (-300.0 * phase * phase) - edge) * onebyedge1; }
-			break;
-			case kSound_windowShape_KAISER_1:
-				imid = 0.5 * (double) (n + 1);
-				factor = 1 / NUMbessel_i0_f (2 * NUMpi);
-				for (i = 1; i <= n; i ++) { double phase = 2 * ((double) i - imid) / n;   /* -1..+1 */
-					double root = 1 - phase * phase;
-					amp [i] *= root <= 0.0 ? 0.0 : factor * NUMbessel_i0_f (2 * NUMpi * sqrt (root)); }
-			break;
-			case kSound_windowShape_KAISER_2:
-				imid = 0.5 * (double) (n + 1);
-				factor = 1 / NUMbessel_i0_f (2 * NUMpi * NUMpi + 0.5);
-				for (i = 1; i <= n; i ++) { double phase = 2 * ((double) i - imid) / n;   /* -1..+1 */
-					double root = 1 - phase * phase;
-					amp [i] *= root <= 0.0 ? 0.0 : factor * NUMbessel_i0_f ((2 * NUMpi * NUMpi + 0.5) * sqrt (root)); }
-			break;
-			default:
-			break;
+			} break; case kSound_windowShape_KAISER_1: {
+				real imid = 0.5 * (double) (n + 1);
+				real factor = 1.0 / NUMbessel_i0_f (2 * NUMpi);
+				for (integer i = 1; i <= n; i ++) { double phase = 2.0 * ((double) i - imid) / n;   // -1..+1
+					double root = 1.0 - phase * phase;
+					amp [i] *= root <= 0.0 ? 0.0 : factor * NUMbessel_i0_f (2.0 * NUMpi * sqrt (root)); }
+			} break; case kSound_windowShape_KAISER_2: {
+				real imid = 0.5 * (double) (n + 1);
+				real factor = 1.0 / NUMbessel_i0_f (2 * NUMpi * NUMpi + 0.5);
+				for (integer i = 1; i <= n; i ++) { double phase = 2.0 * ((double) i - imid) / n;   // -1..+1
+					double root = 1.0 - phase * phase;
+					amp [i] *= root <= 0.0 ? 0.0 : factor * NUMbessel_i0_f ((2.0 * NUMpi * NUMpi + 0.5) * sqrt (root)); }
+			} break; default: {
+			}
 		}
 	}
 }
 
 void Sound_scaleIntensity (Sound me, double newAverageIntensity) {
 	double currentIntensity = Sound_getIntensity_dB (me), factor;
-	if (currentIntensity == NUMundefined) return;
+	if (isundef (currentIntensity)) return;
 	factor = pow (10, (newAverageIntensity - currentIntensity) / 20.0);
 	for (long channel = 1; channel <= my ny; channel ++) {
 		for (long i = 1; i <= my nx; i ++) {
@@ -1144,10 +1128,10 @@ void Sound_filterWithFormants (Sound me, double tmin, double tmax,
 	int numberOfFormants, double formant [], double bandwidth [])
 {
 	try {
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindowing
-			long itmin, itmax;
-			long n = Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax);
+			integer itmin, itmax;
+			integer n = Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax);
 			if (n <= 2)
 				Melder_throw (U"Sound too short.");
 			double *amplitude = my z [channel] + itmin - 1;   // base 1
@@ -1203,11 +1187,11 @@ autoSound Sound_filter_deemphasis (Sound me, double frequency) {
 
 void Sound_reverse (Sound me, double tmin, double tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindowing
-	long itmin, itmax;
-	long n = Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax) / 2;
+	integer itmin, itmax;
+	integer n = Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax) / 2;
 	for (long channel = 1; channel <= my ny; channel ++) {
 		double *amp = my z [channel];
-		for (long i = 0; i < n; i ++) {
+		for (integer i = 0; i < n; i ++) {
 			double dummy = amp [itmin + i];
 			amp [itmin + i] = amp [itmax - i];
 			amp [itmax - i] = dummy;
@@ -1215,7 +1199,7 @@ void Sound_reverse (Sound me, double tmin, double tmax) {
 	}
 }
 
-autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double tmax, int normalize) {
+autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double tmax, bool normalize) {
 	try {
 		if (my dx != thy dx)
 			Melder_throw (U"Sampling frequencies are not equal.");
@@ -1224,15 +1208,15 @@ autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double
 		double dt = my dx;
 		double dphase = (thy x1 - my x1) / dt;
 		dphase -= floor (dphase);   // a number between 0 and 1
-		long i1 = (long) ceil (tmin / dt - dphase);   // index of first sample if sample at dphase has index 0
-		long i2 = (long) floor (tmax / dt - dphase);   // index of last sample if sample at dphase has index 0
-		long nt = i2 - i1 + 1;
+		integer i1 = (integer) ceil (tmin / dt - dphase);   // index of first sample if sample at dphase has index 0
+		integer i2 = (integer) floor (tmax / dt - dphase);   // index of last sample if sample at dphase has index 0
+		integer nt = i2 - i1 + 1;
 		if (nt < 1)
 			Melder_throw (U"Window too small.");
 		double t1 = (dphase + i1) * dt;
 		autoSound him = Sound_create (1, tmin, tmax, nt, dt, t1);
-		for (long i = 1; i <= nt; i ++) {
-			long di = i - 1 + i1;
+		for (integer i = 1; i <= nt; i ++) {
+			integer di = i - 1 + i1;
 			for (long ime = 1; ime <= my nx; ime ++) {
 				if (ime + di < 1) continue;
 				if (ime + di > thy nx) break;
@@ -1243,25 +1227,25 @@ autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double
 		}
 		if (normalize) {
 			double mypower = 0.0, thypower = 0.0;
-			for (long channel = 1; channel <= my ny; channel ++) {
-				for (long i = 1; i <= my nx; i ++) {
+			for (integer channel = 1; channel <= my ny; channel ++) {
+				for (integer i = 1; i <= my nx; i ++) {
 					double value = my z [channel] [i];
 					mypower += value * value;
 				}
-				for (long i = 1; i <= thy nx; i ++) {
+				for (integer i = 1; i <= thy nx; i ++) {
 					double value = thy z [channel] [i];
 					thypower += value * value;
 				}
 			}
 			if (mypower != 0.0 && thypower != 0.0) {
 				double factor = 1.0 / (sqrt (mypower) * sqrt (thypower));
-				for (long i = 1; i <= nt; i ++) {
+				for (integer i = 1; i <= nt; i ++) {
 					his z [1] [i] *= factor;
 				}
 			}
 		} else {
 			double factor = dt / my ny;
-			for (long i = 1; i <= nt; i ++) {
+			for (integer i = 1; i <= nt; i ++) {
 				his z [1] [i] *= factor;
 			}
 		}
diff --git a/fon/Sound.h b/fon/Sound.h
index 36a002e..b604352 100644
--- a/fon/Sound.h
+++ b/fon/Sound.h
@@ -2,7 +2,7 @@
 #define _Sound_h_
 /* Sound.h
  *
- * Copyright (C) 1992-2011,2012,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -151,7 +151,7 @@ autoSound Sounds_convolve (Sound me, Sound thee, enum kSounds_convolve_scaling s
 				sum (j = 1..i, my z [1] [j] * thy z [1] [i - j + 1])
 */
 autoSound Sounds_crossCorrelate (Sound me, Sound thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain);
-autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double tmax, int normalize);
+autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double tmax, bool normalize);
 autoSound Sound_autoCorrelate (Sound me, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain);
 
 double Sound_getRootMeanSquare (Sound me, double xmin, double xmax);
diff --git a/fon/SoundEditor.cpp b/fon/SoundEditor.cpp
index ea13b11..4b8a14b 100644
--- a/fon/SoundEditor.cpp
+++ b/fon/SoundEditor.cpp
@@ -49,10 +49,10 @@ static void menu_cb_Copy (SoundEditor me, EDITOR_ARGS_DIRECT) {
 static void menu_cb_Cut (SoundEditor me, EDITOR_ARGS_DIRECT) {
 	try {
 		Sound sound = (Sound) my data;
-		long first, last, selectionNumberOfSamples = Sampled_getWindowSamples (sound,
+		integer first, last, selectionNumberOfSamples = Sampled_getWindowSamples (sound,
 			my startSelection, my endSelection, & first, & last);
-		long oldNumberOfSamples = sound -> nx;
-		long newNumberOfSamples = oldNumberOfSamples - selectionNumberOfSamples;
+		integer oldNumberOfSamples = sound -> nx;
+		integer newNumberOfSamples = oldNumberOfSamples - selectionNumberOfSamples;
 		if (newNumberOfSamples < 1)
 			Melder_throw (U"You cannot cut all of the signal away,\n"
 				U"because you cannot create a Sound with 0 samples.\n"
@@ -64,19 +64,19 @@ static void menu_cb_Cut (SoundEditor me, EDITOR_ARGS_DIRECT) {
 			 */
 			autoSound publish = Sound_create (sound -> ny, 0.0, selectionNumberOfSamples * sound -> dx,
 							selectionNumberOfSamples, sound -> dx, 0.5 * sound -> dx);
-			for (long channel = 1; channel <= sound -> ny; channel ++) {
-				long j = 0;
-				for (long i = first; i <= last; i ++) {
+			for (integer channel = 1; channel <= sound -> ny; channel ++) {
+				integer j = 0;
+				for (integer i = first; i <= last; i ++) {
 					publish -> z [channel] [++ j] = oldData [channel] [i];
 				}
 			}
 			autoNUMmatrix <double> newData (1, sound -> ny, 1, newNumberOfSamples);
-			for (long channel = 1; channel <= sound -> ny; channel ++) {
-				long j = 0;
-				for (long i = 1; i < first; i ++) {
+			for (integer channel = 1; channel <= sound -> ny; channel ++) {
+				integer j = 0;
+				for (integer i = 1; i < first; i ++) {
 					newData [channel] [++ j] = oldData [channel] [i];
 				}
-				for (long i = last + 1; i <= oldNumberOfSamples; i ++) {
+				for (integer i = last + 1; i <= oldNumberOfSamples; i ++) {
 					newData [channel] [++ j] = oldData [channel] [i];
 				}
 			}
@@ -211,11 +211,11 @@ static void menu_cb_Paste (SoundEditor me, EDITOR_ARGS_DIRECT) {
 
 static void menu_cb_SetSelectionToZero (SoundEditor me, EDITOR_ARGS_DIRECT) {
 	Sound sound = (Sound) my data;
-	long first, last;
+	integer first, last;
 	Sampled_getWindowSamples (sound, my startSelection, my endSelection, & first, & last);
 	Editor_save (me, U"Set to zero");
-	for (long channel = 1; channel <= sound -> ny; channel ++) {
-		for (long i = first; i <= last; i ++) {
+	for (integer channel = 1; channel <= sound -> ny; channel ++) {
+		for (integer i = first; i <= last; i ++) {
 			sound -> z [channel] [i] = 0.0;
 		}
 	}
@@ -236,7 +236,7 @@ static void menu_cb_ReverseSelection (SoundEditor me, EDITOR_ARGS_DIRECT) {
 
 static void menu_cb_MoveCursorToZero (SoundEditor me, EDITOR_ARGS_DIRECT) {
 	double zero = Sound_getNearestZeroCrossing ((Sound) my data, 0.5 * (my startSelection + my endSelection), 1);   // STEREO BUG
-	if (NUMdefined (zero)) {
+	if (isdefined (zero)) {
 		my startSelection = my endSelection = zero;
 		FunctionEditor_marksChanged (me, true);
 	}
@@ -244,7 +244,7 @@ static void menu_cb_MoveCursorToZero (SoundEditor me, EDITOR_ARGS_DIRECT) {
 
 static void menu_cb_MoveBtoZero (SoundEditor me, EDITOR_ARGS_DIRECT) {
 	double zero = Sound_getNearestZeroCrossing ((Sound) my data, my startSelection, 1);   // STEREO BUG
-	if (NUMdefined (zero)) {
+	if (isdefined (zero)) {
 		my startSelection = zero;
 		if (my startSelection > my endSelection) {
 			double dummy = my startSelection;
@@ -257,7 +257,7 @@ static void menu_cb_MoveBtoZero (SoundEditor me, EDITOR_ARGS_DIRECT) {
 
 static void menu_cb_MoveEtoZero (SoundEditor me, EDITOR_ARGS_DIRECT) {
 	double zero = Sound_getNearestZeroCrossing ((Sound) my data, my endSelection, 1);   // STEREO BUG
-	if (NUMdefined (zero)) {
+	if (isdefined (zero)) {
 		my endSelection = zero;
 		if (my startSelection > my endSelection) {
 			double dummy = my startSelection;
@@ -375,8 +375,8 @@ void structSoundEditor :: v_draw () {
 
 	/* Update buttons. */
 
-	long first, last;
-	long selectedSamples = Sampled_getWindowSamples (data, our startSelection, our endSelection, & first, & last);
+	integer first, last;
+	integer selectedSamples = Sampled_getWindowSamples (data, our startSelection, our endSelection, & first, & last);
 	v_updateMenuItems_file ();
 	if (d_sound.data) {
 		GuiThing_setSensitive (cutButton     , selectedSamples != 0 && selectedSamples < our d_sound.data -> nx);
diff --git a/fon/SoundRecorder.cpp b/fon/SoundRecorder.cpp
index 83a164a..605e012 100644
--- a/fon/SoundRecorder.cpp
+++ b/fon/SoundRecorder.cpp
@@ -535,13 +535,13 @@ static void gui_button_cb_record (SoundRecorder me, GuiButtonEvent /* event */)
 		my lastRightMaximum = 0;
 		if (! my synchronous) {
 			if (my inputUsesPortAudio) {
-				PaStreamParameters streamParameters = { 0 };
+				PaStreamParameters streamParameters = { };
 				streamParameters. device = my deviceIndices [theControlPanel. inputSource];
 				streamParameters. channelCount = my numberOfChannels;
 				streamParameters. sampleFormat = paInt16;
 				streamParameters. suggestedLatency = my deviceInfos [theControlPanel. inputSource] -> defaultLowInputLatency;
 				#if defined (macintosh)
-					PaMacCoreStreamInfo macCoreStreamInfo = { 0 };
+					PaMacCoreStreamInfo macCoreStreamInfo = { };
 					macCoreStreamInfo. size = sizeof (PaMacCoreStreamInfo);
 					macCoreStreamInfo. hostApiType = paCoreAudio;
 					macCoreStreamInfo. version = 0x01;
@@ -741,11 +741,11 @@ static void gui_radiobutton_cb_input (SoundRecorder me, GuiRadioButtonEvent even
 static void gui_radiobutton_cb_fsamp (SoundRecorder me, GuiRadioButtonEvent event) {
 	if (my recording) return;
 	try {
-		double fsamp = NUMundefined;
+		double fsamp = undefined;
 		for (long i = 1; i <= SoundRecorder_IFSAMP_MAX; i ++)
 			if (event -> toggle == my fsamps [i]. button)
 				fsamp = my fsamps [i]. fsamp;
-		Melder_assert (NUMdefined (fsamp));
+		Melder_assert (isdefined (fsamp));
 		/*
 		 * If we push the 48000 button while the sampling frequency is 22050,
 		 * we first get a message that the 22050 button has changed,
@@ -888,13 +888,13 @@ void structSoundRecorder :: v_createChildren ()
 static void writeFakeMonoFile (SoundRecorder me, MelderFile file, int audioFileType) {
 	long nsamp = my nsamp / 2;
 	autoMelderFile mfile = MelderFile_create (file);
-	MelderFile_writeAudioFileHeader (file, audioFileType, theControlPanel. sampleRate, nsamp, 1, 16);
+	MelderFile_writeAudioFileHeader (file, audioFileType, lround (theControlPanel. sampleRate), nsamp, 1, 16);
 	if (Melder_defaultAudioFileEncoding (audioFileType, 16) == Melder_LINEAR_16_BIG_ENDIAN) {
 		for (long i = 0; i < nsamp; i ++)
-			binputi2 ((my buffer [i + i - 2] + my buffer [i + i - 1]) / 2, file -> filePointer);
+			binputi16 ((my buffer [i + i - 2] + my buffer [i + i - 1]) / 2, file -> filePointer);
 	} else {
 		for (long i = 0; i < nsamp; i ++)
-			binputi2LE ((my buffer [i + i - 2] + my buffer [i + i - 1]) / 2, file -> filePointer);
+			binputi16LE ((my buffer [i + i - 2] + my buffer [i + i - 1]) / 2, file -> filePointer);
 	}
 	MelderFile_writeAudioFileTrailer (file, audioFileType, lround (theControlPanel. sampleRate), nsamp, 1, 16);
 	mfile.close ();
diff --git a/fon/Sound_and_Spectrum.cpp b/fon/Sound_and_Spectrum.cpp
index f7026d9..2f507fd 100644
--- a/fon/Sound_and_Spectrum.cpp
+++ b/fon/Sound_and_Spectrum.cpp
@@ -129,31 +129,31 @@ autoSound Spectrum_to_Sound (Spectrum me) {
 autoSpectrum Spectrum_lpcSmoothing (Spectrum me, int numberOfPeaks, double preemphasisFrequency) {
 	try {
 		double gain, a [100];
-		long numberOfCoefficients = 2 * numberOfPeaks;
+		integer numberOfCoefficients = 2 * numberOfPeaks;
 
 		autoSound sound = Spectrum_to_Sound (me);
 		NUMpreemphasize_f (sound -> z [1], sound -> nx, sound -> dx, preemphasisFrequency);	 	
 		
 		NUMburg (sound -> z [1], sound -> nx, a, numberOfCoefficients, & gain);
-		for (long i = 1; i <= numberOfCoefficients; i ++) a [i] = - a [i];
+		for (integer i = 1; i <= numberOfCoefficients; i ++) a [i] = - a [i];
 		autoSpectrum thee = Data_copy (me);
 
-		long nfft = 2 * (thy nx - 1);
-		long ndata = numberOfCoefficients < nfft ? numberOfCoefficients : nfft - 1;
+		integer nfft = 2 * (thy nx - 1);
+		integer ndata = numberOfCoefficients < nfft ? numberOfCoefficients : nfft - 1;
 		double scale = 10.0 * (gain > 0.0 ? sqrt (gain) : 1.0) / numberOfCoefficients;
 		autoNUMvector <double> data (1, nfft);
 		data [1] = 1.0;
-		for (long i = 1; i <= ndata; i ++)
+		for (integer i = 1; i <= ndata; i ++)
 			data [i + 1] = a [i];
 		NUMrealft (data.peek(), nfft, 1);
 		double *re = thy z [1];
 		double *im = thy z [2];
 		re [1] = scale / data [1];
 		im [1] = 0.0;
-		long halfnfft = nfft / 2;
-		for (long i = 2; i <= halfnfft; i ++) {
-			double real = data [i + i - 1], imag = data [i + i];
-			re [i] = scale / sqrt (real * real + imag * imag) / (1.0 + thy dx * (i - 1) / preemphasisFrequency);
+		integer halfnfft = nfft / 2;
+		for (integer i = 2; i <= halfnfft; i ++) {
+			double realPart = data [i + i - 1], imaginaryPart = data [i + i];
+			re [i] = scale / sqrt (realPart * realPart + imaginaryPart * imaginaryPart) / (1.0 + thy dx * (i - 1) / preemphasisFrequency);
 			im [i] = 0.0;
 		}
 		re [halfnfft + 1] = scale / data [2] / (1.0 + thy dx * halfnfft / preemphasisFrequency);
diff --git a/fon/Sound_audio.cpp b/fon/Sound_audio.cpp
index 769e01c..de09903 100644
--- a/fon/Sound_audio.cpp
+++ b/fon/Sound_audio.cpp
@@ -512,7 +512,7 @@ void Sound_playPart (Sound me, double tmin, double tmax, Sound_PlayCallback call
 			struct SoundPlay *thee = (struct SoundPlay *) & thePlayingSound;
 			double *fromLeft = my z [1], *fromRight = my ny > 1 ? my z [2] : nullptr;
 			MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
-			long i1, i2;
+			integer i1, i2;
 			if ((thy numberOfSamples = Matrix_getWindowSamplesX (me, tmin, tmax, & i1, & i2)) < 1) return;
 			thy tmin = tmin;
 			thy tmax = tmax;
diff --git a/fon/Sound_files.cpp b/fon/Sound_files.cpp
index 0f3ff46..607db5a 100644
--- a/fon/Sound_files.cpp
+++ b/fon/Sound_files.cpp
@@ -1,6 +1,6 @@
 /* Sound_files.cpp
  *
- * Copyright (C) 1992-2011,2012,2014,2015,2016 Paul Boersma & David Weenink
+ * Copyright (C) 1992-2011,2012,2014,2015,2016,2017 Paul Boersma & David Weenink
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -95,7 +95,7 @@ autoSound Sound_readFromSesamFile (MelderFile file) {
 		autofile f = Melder_fopen (file, "rb");
 		int32_t header [1 + 128];
 		for (long i = 1; i <= 128; i ++)
-			header [i] = bingeti4LE (f);
+			header [i] = bingeti32LE (f);
 		/*
 		 * Try SESAM header.
 		 */
@@ -112,7 +112,7 @@ autoSound Sound_readFromSesamFile (MelderFile file) {
 			Melder_throw (U"Not a correct SESAM or LVS file.");
 		autoSound me = Sound_createSimple (1, numberOfSamples / samplingFrequency, samplingFrequency);
 		for (int32_t i = 1; i <= numberOfSamples; i ++) {
-			my z [1] [i] = (double) bingeti2LE (f) * (1.0 / 2048);   // 12 bits
+			my z [1] [i] = (double) bingeti16LE (f) * (1.0 / 2048);   // 12 bits
 		}
 		f.close (file);
 		return me;
@@ -177,7 +177,7 @@ autoSound Sound_readFromBellLabsFile (MelderFile file) {
 		 */
 		fseek (f, tagLength + headerLength, SEEK_SET);
 		for (unsigned long i = 1; i <= numberOfSamples; i ++)
-			my z [1] [i] = (double) bingeti2 (f) * (1.0 / 32768);   // 16-bits big-endian
+			my z [1] [i] = (double) bingeti16 (f) * (1.0 / 32768);   // 16-bits big-endian
 
 		f.close (file);
 		return me;
@@ -206,17 +206,17 @@ autoSound Sound_readFromKayFile (MelderFile file) {
 		if (fread (data, 1, 4, f) < 4) readError ();
 		if (! strnequ (data, "HEDR", 4) && ! strnequ (data, "HDR8", 4))
 			Melder_throw (U"Missing HEDR or HDR8 chunk. Please report to paul.boersma at uva.nl.");
-		uint32_t chunkSize = bingetu4LE (f);
+		uint32_t chunkSize = bingetu32LE (f);
 		if (chunkSize & 1) ++ chunkSize;
 		if (chunkSize != 32 && chunkSize != 44)
-			Melder_throw (U"Unknown chunk size %ld. Please report to paul.boersma at uva.nl.", chunkSize);
+			Melder_throw (U"Unknown chunk size ", chunkSize, U". Please report to paul.boersma at uva.nl.");
 		if (fread (data, 1, 20, f) < 20) readError ();
-		double samplingFrequency = bingetu4LE (f);   // converting up (from 32 to 53 bits)
-		uint32_t numberOfSamples = bingetu4LE (f);
+		double samplingFrequency = bingetu32LE (f);   // converting up (from 32 to 53 bits)
+		uint32_t numberOfSamples = bingetu32LE (f);
 		if (samplingFrequency <= 0 || samplingFrequency > 1e7 || numberOfSamples >= 1000000000)
 			Melder_throw (U"Not a correct Kay file.");
-		int16_t tmp1 = bingeti2LE (f);
-		int16_t tmp2 = bingeti2LE (f);
+		int16_t tmp1 = bingeti16LE (f);
+		int16_t tmp2 = bingeti16LE (f);
 		long numberOfChannels = tmp1 == -1 || tmp2 == -1 ? 1 : 2;
 		if (chunkSize == 44)
 			if (fread (data, 1, 12, f) < 12) readError ();
@@ -227,19 +227,19 @@ autoSound Sound_readFromKayFile (MelderFile file) {
 		while (! strnequ (data, "SDA_", 4) && ! strnequ (data, "SD_B", 4)) {
 			if (feof ((FILE *) f))
 				Melder_throw (U"Missing or unreadable SD chunk. Please report to paul.boersma at uva.nl.");
-			chunkSize = bingetu4LE (f);
+			chunkSize = bingetu32LE (f);
 			if (chunkSize & 1) ++ chunkSize;
 			if (fread (data, 1, chunkSize, f) < chunkSize) readError ();
 			if (fread (data, 1, 4, f) < 4) readError ();
 		}
-		chunkSize = bingetu4LE (f);
+		chunkSize = bingetu32LE (f);
 		if (chunkSize != numberOfSamples * 2)
 			Melder_throw (U"Incomplete SD chunk. Please report to paul.boersma at uva.nl.");
 
 		autoSound me = Sound_createSimple (numberOfChannels, numberOfSamples / samplingFrequency, samplingFrequency);
 		for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
 			for (unsigned long i = 1; i <= numberOfSamples; i ++) {
-				my z [ichan] [i] = (double) bingeti2LE (f) / 32768.0;
+				my z [ichan] [i] = (double) bingeti16LE (f) / 32768.0;
 			}
 		}
 		f.close (file);
@@ -288,18 +288,18 @@ void Sound_saveAsSesamFile (Sound me, MelderFile file) {
 		/* LVS header. */
 			header [62] = lround (1 / my dx);   // sampling frequency, rounded to n Hz
 			header [63] = -32000;   // magic: "sampled signal"
-			header [66] = 2047;   // maximum absolute value: 12 bits
+			header [66] = INT12_MAX;   // maximum absolute value: 12 bits
 			header [67] = 2047;   // LVS magic
 			header [68] = my nx % 256;   // number of samples in last block
 			header [69] = 1;   // ?
 		/* Sesam header. */
 			header [126] = lround (1 / my dx);   // sampling frequency, rounded to n Hz
 			header [127] = my nx;   // number of samples
-		for (long i = 1; i <= 128; i ++) binputi4LE (header [i], f);
-		for (long i = 1; i <= my nx; i ++) binputi2LE (lround (my z [1] [i] * 2048), f);
+		for (long i = 1; i <= 128; i ++) binputi32LE (header [i], f);
+		for (long i = 1; i <= my nx; i ++) binputi16LE (lround (my z [1] [i] * 2048), f);
 		tail = 256 - my nx % 256;
 		if (tail == 256) tail = 0;
-		for (long i = 1; i <= tail; i ++) binputi2LE (0, f);   // pad last block with zeroes
+		for (long i = 1; i <= tail; i ++) binputi16LE (0, f);   // pad last block with zeroes
 		f.close (file);
 	} catch (MelderError) {
 		Melder_throw (me, U": not written to Sesam file ", file, U".");
@@ -312,26 +312,26 @@ void Sound_saveAsKayFile (Sound me, MelderFile file) {
 
 		/* Form Chunk: contains all other chunks. */
 		fwrite ("FORMDS16", 1, 8, file -> filePointer);
-		binputi4LE (48 + my nx * 2, file -> filePointer);   // size of Form Chunk
+		binputi32LE (48 + my nx * 2, file -> filePointer);   // size of Form Chunk
 		fwrite ("HEDR", 1, 4, file -> filePointer);
-		binputi4LE (32, file -> filePointer);
+		binputi32LE (32, file -> filePointer);
 
 		char date [100];
 		time_t today = time (nullptr);
 		strcpy (date, ctime (& today));	
 		fwrite (date+4, 1, 20, file -> filePointer);   // skip weekday
 
-		binputi4LE (lround (1 / my dx), file -> filePointer);   // sampling frequency
-		binputi4LE (my nx, file -> filePointer);   // number of samples
+		binputi32LE (lround (1 / my dx), file -> filePointer);   // sampling frequency
+		binputi32LE (my nx, file -> filePointer);   // number of samples
 		int maximumA = 0;
 		for (long i = 1; i <= my nx; i ++) {
 			long value = lround (my z [1] [i] * 32768);
 			if (value < - maximumA) maximumA = - value;
 			if (value > maximumA) maximumA = value;
 		}
-		binputi2LE (maximumA, file -> filePointer);   // absolute maximum window A
+		binputi16LE (maximumA, file -> filePointer);   // absolute maximum window A
 		if (my ny == 1) {
-			binputi2LE (-1, file -> filePointer);
+			binputi16LE (-1, file -> filePointer);
 		} else {
 			int maximumB = 0;
 			for (long i = 1; i <= my nx; i ++) {
@@ -339,10 +339,10 @@ void Sound_saveAsKayFile (Sound me, MelderFile file) {
 				if (value < - maximumB) maximumB = - value;
 				if (value > maximumB) maximumB = value;
 			}
-			binputi2LE (maximumB, file -> filePointer);   // absolute maximum window B
+			binputi16LE (maximumB, file -> filePointer);   // absolute maximum window B
 		}
 		fwrite ("SDA_", 1, 4, file -> filePointer);
-		binputi4LE (my nx * 2, file -> filePointer);   // chunk size
+		binputi32LE (my nx * 2, file -> filePointer);   // chunk size
 
 		MelderFile_writeFloatToAudio (file, 1, Melder_LINEAR_16_LITTLE_ENDIAN, my z, my nx, true);
 		if (my ny > 1)
diff --git a/fon/Sound_to_Cochleagram.cpp b/fon/Sound_to_Cochleagram.cpp
index 5f51572..e9e8a97 100644
--- a/fon/Sound_to_Cochleagram.cpp
+++ b/fon/Sound_to_Cochleagram.cpp
@@ -1,6 +1,6 @@
 /* Sound_to_Cochleagram.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -111,16 +111,16 @@ autoCochleagram Sound_to_Cochleagram_edb
 	try {
 		double duration_seconds = my xmax;
 		if (dtime < my dx) dtime = my dx;
-		long ntime = lround (duration_seconds / dtime);
+		integer ntime = lround (duration_seconds / dtime);
 		if (ntime < 2) return autoCochleagram ();
-		long nfreq = lround (25.6 / dfreq);   // 25.6 Bark = highest frequency
+		integer nfreq = lround (25.6 / dfreq);   // 25.6 Bark = highest frequency
 
 		autoCochleagram thee = Cochleagram_create (my xmin, my xmax, ntime, dtime, 0.5 * dtime, dfreq, nfreq);
 
 		/* Stages 1 and 2: outer- and middle-ear filtering. */
 		/* From acoustic sound to oval window. */
 
-		for (long ifreq = 1; ifreq <= nfreq; ifreq ++) {
+		for (integer ifreq = 1; ifreq <= nfreq; ifreq ++) {
 			double *response = thy z [ifreq];
 
 			/* Stage 3: basilar membrane filtering by gammatones. */
@@ -151,7 +151,7 @@ autoCochleagram Sound_to_Cochleagram_edb
 				double c = M * y * kt / (l * kt + y * (l + r));   // cleft contents
 				double q = c * (l + r) / kt;   // free transmitter
 				double w = c * r / x;   // reprocessing store
-				for (long itime = 1; itime <= basil -> nx; itime ++) {
+				for (integer itime = 1; itime <= basil -> nx; itime ++) {
 					double splusA = basil -> z [1] [itime] * 10.0 + A;
 					double replenish = ( M > q ? ydt * (M - q) : 0.0 );
 					kt = ( splusA > 0.0 ? gdt * splusA / (splusA + B) : 0.0 );
@@ -167,7 +167,7 @@ autoCochleagram Sound_to_Cochleagram_edb
 			}
 			
 			if (dtime == my dx) {
-				for (long itime = 1; itime <= ntime; itime ++)
+				for (integer itime = 1; itime <= ntime; itime ++)
 					response [itime] = basil -> z [1] [itime];
 			} else {
 				double d = dtime / basil -> dx / 2;
@@ -178,17 +178,17 @@ autoCochleagram Sound_to_Cochleagram_edb
 					double t1 = (itime - 1) * dtime;
 					double t2 = t1 + dtime;
 					double mean = 0.0;
-					long i1, i2;
-					long n = Matrix_getWindowSamplesX (basil.get(), t1, t2, & i1, & i2);
+					integer i1, i2;
+					integer n = Matrix_getWindowSamplesX (basil.get(), t1, t2, & i1, & i2);
 					Melder_assert (n >= 1);
 					if (n <= 2) {
-						for (long isamp = i1; isamp <= i2; isamp ++)
+						for (integer isamp = i1; isamp <= i2; isamp ++)
 							mean += basil -> z [1] [isamp];
 						mean /= n;
 					} else {
 						double mu = floor ((i1 + i2) / 2.0);
-						long muint = (long) mu, dint = (long) d;
-						for (long isamp = muint - dint; isamp <= muint + dint; isamp ++) {
+						integer muint = (long) mu, dint = (long) d;
+						for (integer isamp = muint - dint; isamp <= muint + dint; isamp ++) {
 							double y = 0;
 							if (isamp < 1 || isamp > basil -> nx)
 								Melder_casual (U"isamp ", isamp);
diff --git a/fon/Sound_to_Intensity.cpp b/fon/Sound_to_Intensity.cpp
index b243ce8..9d53731 100644
--- a/fon/Sound_to_Intensity.cpp
+++ b/fon/Sound_to_Intensity.cpp
@@ -38,8 +38,8 @@ static autoIntensity Sound_to_Intensity_ (Sound me, double minimumPitch, double
 		/*
 		 * Preconditions.
 		 */
-		if (! NUMdefined (minimumPitch)) Melder_throw (U"(Sound-to-Intensity:) Minimum pitch undefined.");
-		if (! NUMdefined (timeStep)) Melder_throw (U"(Sound-to-Intensity:) Time step undefined.");
+		if (isundef (minimumPitch)) Melder_throw (U"(Sound-to-Intensity:) Minimum pitch undefined.");
+		if (isundef (timeStep)) Melder_throw (U"(Sound-to-Intensity:) Time step undefined.");
 		if (timeStep < 0.0) Melder_throw (U"(Sound-to-Intensity:) Time step should be zero or positive instead of ", timeStep, U".");
 		if (my dx <= 0.0) Melder_throw (U"(Sound-to-Intensity:) The Sound's time step should be positive.");
 		if (minimumPitch <= 0.0) Melder_throw (U"(Sound-to-Intensity:) Minimum pitch should be positive.");
@@ -74,7 +74,7 @@ static autoIntensity Sound_to_Intensity_ (Sound me, double minimumPitch, double
 			const double midTime = Sampled_indexToX (thee.get(), iframe);
 			const long midSample = Sampled_xToNearestIndex (me, midTime);   // time accuracy is half a sampling period
 			long leftSample = midSample - halfWindowSamples, rightSample = midSample + halfWindowSamples;
-			double sumxw = 0.0, sumw = 0.0;
+			long double sumxw = 0.0, sumw = 0.0;
 			if (leftSample < 1) leftSample = 1;
 			if (rightSample > my nx) rightSample = my nx;
 
@@ -83,11 +83,11 @@ static autoIntensity Sound_to_Intensity_ (Sound me, double minimumPitch, double
 					amplitude [i - midSample] = my z [channel] [i];
 				}
 				if (subtractMeanPressure) {
-					double sum = 0.0;
+					long double sum = 0.0;
 					for (long i = leftSample; i <= rightSample; i ++) {
 						sum += amplitude [i - midSample];
 					}
-					double mean = sum / (rightSample - leftSample + 1);
+					double mean = (double) sum / (rightSample - leftSample + 1);
 					for (long i = leftSample; i <= rightSample; i ++) {
 						amplitude [i - midSample] -= mean;
 					}
@@ -97,7 +97,7 @@ static autoIntensity Sound_to_Intensity_ (Sound me, double minimumPitch, double
 					sumw += window [i - midSample];
 				}
 			}
-			double intensity = sumxw / sumw;
+			double intensity = double (sumxw / sumw);
 			intensity /= 4.0e-10;
 			thy z [1] [iframe] = intensity < 1.0e-30 ? -300.0 : 10.0 * log10 (intensity);
 		}
diff --git a/fon/Sound_to_Pitch.cpp b/fon/Sound_to_Pitch.cpp
index bda78fb..30a5472 100644
--- a/fon/Sound_to_Pitch.cpp
+++ b/fon/Sound_to_Pitch.cpp
@@ -1,6 +1,6 @@
 /* Sound_to_Pitch.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -49,11 +49,10 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 	double **frame, double *ac, double *window, double *windowR,
 	double *r, long *imax, double *localMean)
 {
-	double localPeak;
-	long leftSample = Sampled_xToLowIndex (me, t), rightSample = leftSample + 1;
-	long startSample, endSample;
+	integer leftSample = Sampled_xToLowIndex (me, t), rightSample = leftSample + 1;
+	integer startSample, endSample;
 
-	for (long channel = 1; channel <= my ny; channel ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		/*
 		 * Compute the local mean; look one longest period to both sides.
 		 */
@@ -62,7 +61,7 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 		Melder_assert (startSample >= 1);
 		Melder_assert (endSample <= my nx);
 		localMean [channel] = 0.0;
-		for (long i = startSample; i <= endSample; i ++) {
+		for (integer i = startSample; i <= endSample; i ++) {
 			localMean [channel] += my z [channel] [i];
 		}
 		localMean [channel] /= 2 * nsamp_period;
@@ -76,12 +75,12 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 		Melder_assert (startSample >= 1);
 		Melder_assert (endSample <= my nx);
 		if (method < FCC_NORMAL) {
-			for (long j = 1, i = startSample; j <= nsamp_window; j ++)
+			for (integer j = 1, i = startSample; j <= nsamp_window; j ++)
 				frame [channel] [j] = (my z [channel] [i ++] - localMean [channel]) * window [j];
-			for (long j = nsamp_window + 1; j <= nsampFFT; j ++)
+			for (integer j = nsamp_window + 1; j <= nsampFFT; j ++)
 				frame [channel] [j] = 0.0;
 		} else {
-			for (long j = 1, i = startSample; j <= nsamp_window; j ++)
+			for (integer j = 1, i = startSample; j <= nsamp_window; j ++)
 				frame [channel] [j] = my z [channel] [i ++] - localMean [channel];
 		}
 	}
@@ -89,64 +88,65 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 	/*
 	 * Compute the local peak; look half a longest period to both sides.
 	 */
-	localPeak = 0.0;
+	real localPeak = 0.0;
 	if ((startSample = halfnsamp_window + 1 - halfnsamp_period) < 1) startSample = 1;
 	if ((endSample = halfnsamp_window + halfnsamp_period) > nsamp_window) endSample = nsamp_window;
-	for (long channel = 1; channel <= my ny; channel ++) {
-		for (long j = startSample; j <= endSample; j ++) {
-			double value = fabs (frame [channel] [j]);
+	for (integer channel = 1; channel <= my ny; channel ++) {
+		for (integer j = startSample; j <= endSample; j ++) {
+			real value = fabs (frame [channel] [j]);
 			if (value > localPeak) localPeak = value;
 		}
 	}
-	pitchFrame->intensity = localPeak > globalPeak ? 1.0 : localPeak / globalPeak;
+	pitchFrame -> intensity =
+		localPeak > globalPeak ? 1.0 : localPeak / globalPeak;
 
 	/*
 	 * Compute the correlation into the array 'r'.
 	 */
 	if (method >= FCC_NORMAL) {
-		double startTime = t - 0.5 * (1.0 / minimumPitch + dt_window);
-		long localSpan = maximumLag + nsamp_window, localMaximumLag, offset;
+		real startTime = t - 0.5 * (1.0 / minimumPitch + dt_window);
+		integer localSpan = maximumLag + nsamp_window, localMaximumLag, offset;
 		if ((startSample = Sampled_xToLowIndex (me, startTime)) < 1) startSample = 1;
 		if (localSpan > my nx + 1 - startSample) localSpan = my nx + 1 - startSample;
 		localMaximumLag = localSpan - nsamp_window;
 		offset = startSample - 1;
-		double sumx2 = 0;   // sum of squares
-		for (long channel = 1; channel <= my ny; channel ++) {
-			double *amp = my z [channel] + offset;
-			for (long i = 1; i <= nsamp_window; i ++) {
-				double x = amp [i] - localMean [channel];
+		real80 sumx2 = 0.0;   // sum of squares
+		for (integer channel = 1; channel <= my ny; channel ++) {
+			real *amp = my z [channel] + offset;
+			for (integer i = 1; i <= nsamp_window; i ++) {
+				real x = amp [i] - localMean [channel];
 				sumx2 += x * x;
 			}
 		}
-		double sumy2 = sumx2;   // at zero lag, these are still equal
+		real80 sumy2 = sumx2;   // at zero lag, these are still equal
 		r [0] = 1.0;
-		for (long i = 1; i <= localMaximumLag; i ++) {
-			double product = 0.0;
-			for (long channel = 1; channel <= my ny; channel ++) {
-				double *amp = my z [channel] + offset;
-				double y0 = amp [i] - localMean [channel];
-				double yZ = amp [i + nsamp_window] - localMean [channel];
+		for (integer i = 1; i <= localMaximumLag; i ++) {
+			real80 product = 0.0;
+			for (integer channel = 1; channel <= my ny; channel ++) {
+				real *amp = my z [channel] + offset;
+				real y0 = amp [i] - localMean [channel];
+				real yZ = amp [i + nsamp_window] - localMean [channel];
 				sumy2 += yZ * yZ - y0 * y0;
-				for (long j = 1; j <= nsamp_window; j ++) {
-					double x = amp [j] - localMean [channel];
-					double y = amp [i + j] - localMean [channel];
+				for (integer j = 1; j <= nsamp_window; j ++) {
+					real x = amp [j] - localMean [channel];
+					real y = amp [i + j] - localMean [channel];
 					product += x * y;
 				}
 			}
-			r [- i] = r [i] = product / sqrt (sumx2 * sumy2);
+			r [- i] = r [i] = (real) product / sqrt ((real) sumx2 * (real) sumy2);
 		}
 	} else {
 
 		/*
 		 * The FFT of the autocorrelation is the power spectrum.
 		 */
-		for (long i = 1; i <= nsampFFT; i ++) {
+		for (integer i = 1; i <= nsampFFT; i ++) {
 			ac [i] = 0.0;
 		}
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			NUMfft_forward (fftTable, frame [channel]);   // complex spectrum
 			ac [1] += frame [channel] [1] * frame [channel] [1];   // DC component
-			for (long i = 2; i < nsampFFT; i += 2) {
+			for (integer i = 2; i < nsampFFT; i += 2) {
 				ac [i] += frame [channel] [i] * frame [channel] [i] + frame [channel] [i+1] * frame [channel] [i+1];   // power spectrum
 			}
 			ac [nsampFFT] += frame [channel] [nsampFFT] * frame [channel] [nsampFFT];   // Nyquist frequency
@@ -158,22 +158,22 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 		 * and divide it by the normalized autocorrelation of the window.
 		 */
 		r [0] = 1.0;
-		for (long i = 1; i <= brent_ixmax; i ++)
+		for (integer i = 1; i <= brent_ixmax; i ++)
 			r [- i] = r [i] = ac [i + 1] / (ac [1] * windowR [i + 1]);
 	}
 
 	/*
 	 * Register the first candidate, which is always present: voicelessness.
 	 */
-	pitchFrame->nCandidates = 1;
-	pitchFrame->candidate[1].frequency = 0.0;   // voiceless: always present
-	pitchFrame->candidate[1].strength = 0.0;
+	pitchFrame -> nCandidates = 1;
+	pitchFrame -> candidate [1]. frequency = 0.0;   // voiceless: always present
+	pitchFrame -> candidate [1]. strength = 0.0;
 
 	/*
 	 * Shortcut: absolute silence is always voiceless.
 	 * We are done for this frame.
 	 */
-	if (localPeak == 0) return;
+	if (localPeak == 0.0) return;
 
 	/*
 	 * Find the strongest maxima of the correlation of this frame, 
@@ -190,8 +190,8 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 		 * Use parabolic interpolation for first estimate of frequency,
 		 * and sin(x)/x interpolation to compute the strength of this frequency.
 		 */
-		double dr = 0.5 * (r [i+1] - r [i-1]), d2r = 2 * r [i] - r [i-1] - r [i+1];
-		double frequencyOfMaximum = 1 / my dx / (i + dr / d2r);
+		double dr = 0.5 * (r [i+1] - r [i-1]), d2r = 2.0 * r [i] - r [i-1] - r [i+1];
+		double frequencyOfMaximum = 1.0 / my dx / (i + dr / d2r);
 		long offset = - brent_ixmax - 1;
 		double strengthOfMaximum = /* method & 1 ? */
 			NUM_interpolate_sinc (& r [offset], brent_ixmax - offset, 1 / my dx / frequencyOfMaximum - offset, 30)
@@ -203,24 +203,27 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 		 * Find a place for this maximum.
 		 */
 		if (pitchFrame->nCandidates < maxnCandidates) {   // is there still a free place?
-			place = ++ pitchFrame->nCandidates;
+			place = ++ pitchFrame -> nCandidates;
 		} else {
 			/* Try the place of the weakest candidate so far. */
-			double weakest = 2;
+			double weakest = 2.0;
 			for (int iweak = 2; iweak <= maxnCandidates; iweak ++) {
 				/* High frequencies are to be favoured */
 				/* if we want to analyze a perfectly periodic signal correctly. */
-				double localStrength = pitchFrame->candidate[iweak].strength - octaveCost *
-					NUMlog2 (minimumPitch / pitchFrame->candidate[iweak].frequency);
-				if (localStrength < weakest) { weakest = localStrength; place = iweak; }
+				double localStrength = pitchFrame -> candidate [iweak]. strength - octaveCost *
+					NUMlog2 (minimumPitch / pitchFrame -> candidate [iweak]. frequency);
+				if (localStrength < weakest) {
+					weakest = localStrength;
+					place = iweak;
+				}
 			}
 			/* If this maximum is weaker than the weakest candidate so far, give it no place. */
 			if (strengthOfMaximum - octaveCost * NUMlog2 (minimumPitch / frequencyOfMaximum) <= weakest)
 				place = 0;
 		}
 		if (place) {   // have we found a place for this candidate?
-			pitchFrame->candidate[place].frequency = frequencyOfMaximum;
-			pitchFrame->candidate[place].strength = strengthOfMaximum;
+			pitchFrame -> candidate [place]. frequency = frequencyOfMaximum;
+			pitchFrame -> candidate [place]. strength = strengthOfMaximum;
 			imax [place] = i;
 		}
 	}
@@ -228,16 +231,16 @@ static void Sound_into_PitchFrame (Sound me, Pitch_Frame pitchFrame, double t,
 	/*
 	 * Second pass: for extra precision, maximize sin(x)/x interpolation ('sinc').
 	 */
-	for (long i = 2; i <= pitchFrame->nCandidates; i ++) {
-		if (method != AC_HANNING || pitchFrame->candidate[i].frequency > 0.0 / my dx) {
+	for (long i = 2; i <= pitchFrame -> nCandidates; i ++) {
+		if (method != AC_HANNING || pitchFrame -> candidate [i]. frequency > 0.0 / my dx) {
 			double xmid, ymid;
 			long offset = - brent_ixmax - 1;
 			ymid = NUMimproveMaximum (& r [offset], brent_ixmax - offset, imax [i] - offset,
-				pitchFrame->candidate[i].frequency > 0.3 / my dx ? NUM_PEAK_INTERPOLATE_SINC700 : brent_depth, & xmid);
+				pitchFrame -> candidate [i]. frequency > 0.3 / my dx ? NUM_PEAK_INTERPOLATE_SINC700 : brent_depth, & xmid);
 			xmid += offset;
-			pitchFrame->candidate[i].frequency = 1.0 / my dx / xmid;
+			pitchFrame -> candidate [i]. frequency = 1.0 / my dx / xmid;
 			if (ymid > 1.0) ymid = 1.0 / ymid;
-			pitchFrame->candidate[i].strength = ymid;
+			pitchFrame -> candidate [i]. strength = ymid;
 		}
 	}
 }
@@ -348,13 +351,10 @@ autoPitch Sound_to_Pitch_any (Sound me,
 {
 	try {
 		autoNUMfft_Table fftTable;
-		double duration, t1;
-		double dt_window;   // window length in seconds
-		long nsamp_window, halfnsamp_window;   // number of samples per window
+		double t1;
 		long nFrames, minimumLag, maximumLag;
 		long nsampFFT;
 		double interpolation_depth;
-		long nsamp_period, halfnsamp_period;   // number of samples in longest period
 		long brent_ixmax, brent_depth;
 		double globalPeak;
 
@@ -384,7 +384,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 				interpolation_depth = 1.0;
 				break;
 		}
-		duration = my dx * my nx;
+		real duration = my dx * my nx;
 		if (minimumPitch < periodsPerWindow / duration)
 			Melder_throw (U"To analyse this Sound, ", U_LEFT_DOUBLE_QUOTE, U"minimum pitch", U_RIGHT_DOUBLE_QUOTE, U" must not be less than ", periodsPerWindow / duration, U" Hz.");
 
@@ -393,17 +393,17 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		 * We need this to compute the local mean of the sound (looking one period in both directions),
 		 * and to compute the local peak of the sound (looking half a period in both directions).
 		 */
-		nsamp_period = (long) floor (1 / my dx / minimumPitch);
-		halfnsamp_period = nsamp_period / 2 + 1;
+		integer nsamp_period = (long) floor (1 / my dx / minimumPitch);
+		integer halfnsamp_period = nsamp_period / 2 + 1;
 
 		if (ceiling > 0.5 / my dx) ceiling = 0.5 / my dx;
 
 		/*
 		 * Determine window length in seconds and in samples.
 		 */
-		dt_window = periodsPerWindow / minimumPitch;
-		nsamp_window = (long) floor (dt_window / my dx);
-		halfnsamp_window = nsamp_window / 2 - 1;
+		real dt_window = periodsPerWindow / minimumPitch;
+		integer nsamp_window = (long) floor (dt_window / my dx);
+		integer halfnsamp_window = nsamp_window / 2 - 1;
 		if (halfnsamp_window < 2)
 			Melder_throw (U"Analysis window too short.");
 		nsamp_window = halfnsamp_window * 2;
@@ -411,7 +411,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		/*
 		 * Determine the minimum and maximum lags.
 		 */
-		minimumLag = (long) floor (1 / my dx / ceiling);
+		minimumLag = (long) floor (1.0 / my dx / ceiling);
 		if (minimumLag < 2) minimumLag = 2;
 		maximumLag = (long) floor (nsamp_window / periodsPerWindow) + 2;
 		if (maximumLag > nsamp_window) maximumLag = nsamp_window;
@@ -423,7 +423,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		 * because that allows us to compare the two methods.
 		 */
 		try {
-			Sampled_shortTermAnalysis (me, method >= FCC_NORMAL ? 1 / minimumPitch + dt_window : dt_window, dt, & nFrames, & t1);
+			Sampled_shortTermAnalysis (me, method >= FCC_NORMAL ? 1.0 / minimumPitch + dt_window : dt_window, dt, & nFrames, & t1);
 		} catch (MelderError) {
 			Melder_throw (U"The pitch analysis would give zero pitch frames.");
 		}
@@ -446,11 +446,11 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		 */
 		globalPeak = 0.0;
 		for (long channel = 1; channel <= my ny; channel ++) {
-			double mean = 0.0;
+			real80 sum = 0.0;
 			for (long i = 1; i <= my nx; i ++) {
-				mean += my z [channel] [i];
+				sum += my z [channel] [i];
 			}
-			mean /= my nx;
+			real mean = real (sum / my nx);
 			for (long i = 1; i <= my nx; i ++) {
 				double value = fabs (my z [channel] [i] - mean);
 				if (value > globalPeak) globalPeak = value;
@@ -475,7 +475,10 @@ autoPitch Sound_to_Pitch_any (Sound me,
 			* The maximum lag considered for maxima is maximumLag.
 			* The maximum lag used in interpolation is nsamp_window * interpolation_depth.
 			*/
-			nsampFFT = 1; while (nsampFFT < nsamp_window * (1 + interpolation_depth)) nsampFFT *= 2;
+			nsampFFT = 1;
+			while (nsampFFT < nsamp_window * (1 + interpolation_depth)) {
+				nsampFFT *= 2;
+			}
 
 			/*
 			* Create buffers for autocorrelation analysis.
@@ -491,27 +494,33 @@ autoPitch Sound_to_Pitch_any (Sound me,
 			*/
 			if (method == AC_GAUSS) {   /* Gaussian window. */
 				double imid = 0.5 * (nsamp_window + 1), edge = exp (-12.0);
-				for (long i = 1; i <= nsamp_window; i ++)
+				for (long i = 1; i <= nsamp_window; i ++) {
 					window [i] = (exp (-48.0 * (i - imid) * (i - imid) /
-						(nsamp_window + 1) / (nsamp_window + 1)) - edge) / (1 - edge);
+						(nsamp_window + 1) / (nsamp_window + 1)) - edge) / (1.0 - edge);
+				}
 			} else {   // Hanning window
-				for (long i = 1; i <= nsamp_window; i ++)
+				for (long i = 1; i <= nsamp_window; i ++) {
 					window [i] = 0.5 - 0.5 * cos (i * 2 * NUMpi / (nsamp_window + 1));
+				}
 			}
 
 			/*
 			* Compute the normalized autocorrelation of the window.
 			*/
-			for (long i = 1; i <= nsamp_window; i ++) windowR [i] = window [i];
+			for (long i = 1; i <= nsamp_window; i ++) {
+				windowR [i] = window [i];
+			}
 			NUMfft_forward (& fftTable, windowR.peek());
 			windowR [1] *= windowR [1];   // DC component
 			for (long i = 2; i < nsampFFT; i += 2) {
-				windowR [i] = windowR [i] * windowR [i] + windowR [i+1] * windowR [i+1];
+				windowR [i] = windowR [i] * windowR [i] + windowR [i + 1] * windowR [i + 1];
 				windowR [i + 1] = 0.0;   // power spectrum: square and zero
 			}
 			windowR [nsampFFT] *= windowR [nsampFFT];   // Nyquist frequency
 			NUMfft_backward (& fftTable, windowR.peek());   // autocorrelation
-			for (long i = 2; i <= nsamp_window; i ++) windowR [i] /= windowR [1];   // normalize
+			for (long i = 2; i <= nsamp_window; i ++) {
+				windowR [i] /= windowR [1];   // normalize
+			}
 			windowR [1] = 1.0;   // normalize
 
 			brent_ixmax = (long) floor (nsamp_window * interpolation_depth);
diff --git a/fon/Spectrogram.cpp b/fon/Spectrogram.cpp
index 33f2c34..de09098 100644
--- a/fon/Spectrogram.cpp
+++ b/fon/Spectrogram.cpp
@@ -57,7 +57,7 @@ void Spectrogram_paintInside (Spectrogram me, Graphics g, double tmin, double tm
 {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 	if (fmax <= fmin) { fmin = my ymin; fmax = my ymax; }
-	long itmin, itmax, ifmin, ifmax;
+	integer itmin, itmax, ifmin, ifmax;
 	if (! Matrix_getWindowSamplesX (me, tmin - 0.49999 * my dx, tmax + 0.49999 * my dx, & itmin, & itmax) ||
 		 ! Matrix_getWindowSamplesY (me, fmin - 0.49999 * my dy, fmax + 0.49999 * my dy, & ifmin, & ifmax))
 		return;
@@ -65,9 +65,9 @@ void Spectrogram_paintInside (Spectrogram me, Graphics g, double tmin, double tm
 	autoNUMvector <double> preemphasisFactor (ifmin, ifmax);
 	autoNUMvector <double> dynamicFactor (itmin, itmax);
 	/* Pre-emphasis in place; also compute maximum after pre-emphasis. */
-	for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++) {
+	for (integer ifreq = ifmin; ifreq <= ifmax; ifreq ++) {
 		preemphasisFactor [ifreq] = (preemphasis / NUMln2) * log (ifreq * my dy / 1000.0);
-		for (long itime = itmin; itime <= itmax; itime ++) {
+		for (integer itime = itmin; itime <= itmax; itime ++) {
 			double value = my z [ifreq] [itime];   // power
 			value = (10.0/NUMln10) * log ((value + 1e-30) / 4.0e-10) + preemphasisFactor [ifreq];   // dB
 			if (value > dynamicFactor [itime]) dynamicFactor [itime] = value;   // local maximum
@@ -77,13 +77,13 @@ void Spectrogram_paintInside (Spectrogram me, Graphics g, double tmin, double tm
 	/* Compute global maximum. */
 	if (autoscaling) {
 		maximum = 0.0;
-		for (long itime = itmin; itime <= itmax; itime ++)
+		for (integer itime = itmin; itime <= itmax; itime ++)
 			if (dynamicFactor [itime] > maximum) maximum = dynamicFactor [itime];
 	}
 	/* Dynamic compression in place. */
-	for (long itime = itmin; itime <= itmax; itime ++) {
+	for (integer itime = itmin; itime <= itmax; itime ++) {
 		dynamicFactor [itime] = dynamicCompression * (maximum - dynamicFactor [itime]);
-		for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++)
+		for (integer ifreq = ifmin; ifreq <= ifmax; ifreq ++)
 			my z [ifreq] [itime] += dynamicFactor [itime];
 	}
 	Graphics_image (g, my z,
@@ -94,8 +94,8 @@ void Spectrogram_paintInside (Spectrogram me, Graphics g, double tmin, double tm
 		Matrix_rowToY (me, ifmin - 0.5),
 		Matrix_rowToY (me, ifmax + 0.5),
 		maximum - dynamic, maximum);
-	for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++)
-		for (long itime = itmin; itime <= itmax; itime ++) {
+	for (integer ifreq = ifmin; ifreq <= ifmax; ifreq ++)
+		for (integer itime = itmin; itime <= itmax; itime ++) {
 			double value = 4.0e-10 * exp ((my z [ifreq] [itime] - dynamicFactor [itime]
 				- preemphasisFactor [ifreq]) * (NUMln10 / 10.0)) - 1e-30;
 			my z [ifreq] [itime] = value > 0.0 ? value : 0.0;
diff --git a/fon/SpectrogramEditor.cpp b/fon/SpectrogramEditor.cpp
index 9235638..5cdd393 100644
--- a/fon/SpectrogramEditor.cpp
+++ b/fon/SpectrogramEditor.cpp
@@ -29,7 +29,7 @@ void structSpectrogramEditor :: v_draw () {
 	Graphics_setColour (our graphics.get(), Graphics_BLACK);
 	Graphics_rectangle (our graphics.get(), 0.0, 1.0, 0.0, 1.0);
 
-	long itmin, itmax;
+	integer itmin, itmax;
 	Sampled_getWindowSamples (spectrogram, our startWindow, our endWindow, & itmin, & itmax);
 
 	/*
diff --git a/fon/Spectrum.cpp b/fon/Spectrum.cpp
index e22bf30..da6240f 100644
--- a/fon/Spectrum.cpp
+++ b/fon/Spectrum.cpp
@@ -1,6 +1,6 @@
 /* Spectrum.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -62,7 +62,7 @@ void structSpectrum :: v_info () {
 
 double structSpectrum :: v_getValueAtSample (long isamp, long which, int units) {
 	if (units == 0) {
-		return which == 1 ? z [1] [isamp] : which == 2 ? z [2] [isamp] : NUMundefined;
+		return which == 1 ? z [1] [isamp] : which == 2 ? z [2] [isamp] : undefined;
 	} else {
 		/*
 		 * The energy in a bin is 2 * (re^2 + im^2) times the bin width.
@@ -82,7 +82,7 @@ double structSpectrum :: v_getValueAtSample (long isamp, long which, int units)
 			}
 		}
 	}
-	return NUMundefined;
+	return undefined;
 }
 
 autoSpectrum Spectrum_create (double fmax, long nf) {
@@ -113,7 +113,7 @@ void Spectrum_drawInside (Spectrum me, Graphics g, double fmin, double fmax, dou
 	bool autoscaling = ( minimum >= maximum );
 
 	if (fmax <= fmin) { fmin = my xmin; fmax = my xmax; }
-	long ifmin, ifmax;
+	integer ifmin, ifmax;
 	if (! Matrix_getWindowSamplesX (me, fmin, fmax, & ifmin, & ifmax)) return;
 
 	autoNUMvector <double> yWC (ifmin, ifmax);
@@ -166,7 +166,7 @@ void Spectrum_draw (Spectrum me, Graphics g, double fmin, double fmax, double mi
 void Spectrum_drawLogFreq (Spectrum me, Graphics g, double fmin, double fmax, double minimum, double maximum, int garnish) {
 	bool autoscaling = ( minimum >= maximum );
 	if (fmax <= fmin) { fmin = my xmin; fmax = my xmax; }
-	long ifmin, ifmax;
+	integer ifmin, ifmax;
 	if (! Matrix_getWindowSamplesX (me, fmin, fmax, & ifmin, & ifmax)) return;
 if(ifmin==1)ifmin=2;  /* BUG */
 	autoNUMvector <double> xWC (ifmin, ifmax);
@@ -357,7 +357,7 @@ double Spectrum_getBandEnergy (Spectrum me, double fmin, double fmax) {
 	 * of the positive-frequency values, and that only the positive-frequency values are included
 	 * in the spectrum.
 	 */
-	if (my xmin < 0.0) return NUMundefined;
+	if (my xmin < 0.0) return undefined;
 	/*
 	 * Any energy outside [my xmin, my xmax] is ignored.
 	 * This is very important, since my xmin and my xmax determine the meaning of the first and last bins; see below.
@@ -378,28 +378,29 @@ double Spectrum_getBandEnergy (Spectrum me, double fmin, double fmax) {
 }
 
 double Spectrum_getBandDensity (Spectrum me, double fmin, double fmax) {
-	if (my xmin < 0.0) return NUMundefined;   // no negative frequencies allowed in one-sided spectral density
+	if (my xmin < 0.0) return undefined;   // no negative frequencies allowed in one-sided spectral density
 	return Sampled_getMean (me, fmin, fmax, 0, 1, false);
 }
 
 double Spectrum_getBandDensityDifference (Spectrum me, double lowBandMin, double lowBandMax, double highBandMin, double highBandMax) {
 	double lowBandDensity = Spectrum_getBandDensity (me, lowBandMin, lowBandMax);
 	double highBandDensity = Spectrum_getBandDensity (me, highBandMin, highBandMax);
-	if (lowBandDensity == NUMundefined || highBandDensity == NUMundefined) return NUMundefined;
-	if (lowBandDensity == 0.0 || highBandDensity == 0.0) return NUMundefined;
-	return 10 * log10 (highBandDensity / lowBandDensity);
+	if (isundef (lowBandDensity) || isundef (highBandDensity)) return undefined;
+	if (lowBandDensity == 0.0 || highBandDensity == 0.0) return undefined;
+	return 10.0 * log10 (highBandDensity / lowBandDensity);
 }
 
 double Spectrum_getBandEnergyDifference (Spectrum me, double lowBandMin, double lowBandMax, double highBandMin, double highBandMax) {
 	double lowBandEnergy = Spectrum_getBandEnergy (me, lowBandMin, lowBandMax);
 	double highBandEnergy = Spectrum_getBandEnergy (me, highBandMin, highBandMax);
-	if (lowBandEnergy == NUMundefined || highBandEnergy == NUMundefined) return NUMundefined;
-	if (lowBandEnergy == 0.0 || highBandEnergy == 0.0) return NUMundefined;
+	if (isundef (lowBandEnergy) || isundef (highBandEnergy)) return undefined;
+	if (lowBandEnergy == 0.0 || highBandEnergy == 0.0) return undefined;
 	return 10.0 * log10 (highBandEnergy / lowBandEnergy);
 }
 
 double Spectrum_getCentreOfGravity (Spectrum me, double power) {
-	double halfpower = 0.5 * power, sumenergy = 0.0, sumfenergy = 0.0;
+	double halfpower = 0.5 * power;
+	long double sumenergy = 0.0, sumfenergy = 0.0;
 	for (long i = 1; i <= my nx; i ++) {
 		double re = my z [1] [i], im = my z [2] [i], energy = re * re + im * im;
 		double f = my x1 + (i - 1) * my dx;
@@ -407,13 +408,14 @@ double Spectrum_getCentreOfGravity (Spectrum me, double power) {
 		sumenergy += energy;
 		sumfenergy += f * energy;
 	}
-	return sumenergy == 0.0 ? NUMundefined : sumfenergy / sumenergy;
+	return sumenergy == 0.0 ? undefined : double (sumfenergy / sumenergy);
 }
 
 double Spectrum_getCentralMoment (Spectrum me, double moment, double power) {
-	double halfpower = 0.5 * power, sumenergy = 0.0, sumfenergy = 0.0;
 	double fmean = Spectrum_getCentreOfGravity (me, power);
-	if (fmean == NUMundefined) return NUMundefined;
+	if (isundef (fmean)) return undefined;
+	double halfpower = 0.5 * power;
+	long double sumenergy = 0.0, sumfenergy = 0.0;
 	for (long i = 1; i <= my nx; i ++) {
 		double re = my z [1] [i], im = my z [2] [i], energy = re * re + im * im;
 		double f = my x1 + (i - 1) * my dx;
@@ -421,7 +423,7 @@ double Spectrum_getCentralMoment (Spectrum me, double moment, double power) {
 		sumenergy += energy;
 		sumfenergy += pow (f - fmean, moment) * energy;
 	}
-	return sumfenergy / sumenergy;
+	return double (sumfenergy / sumenergy);
 }
 
 double Spectrum_getStandardDeviation (Spectrum me, double power) {
@@ -431,21 +433,21 @@ double Spectrum_getStandardDeviation (Spectrum me, double power) {
 double Spectrum_getSkewness (Spectrum me, double power) {
 	double m2 = Spectrum_getCentralMoment (me, 2.0, power);
 	double m3 = Spectrum_getCentralMoment (me, 3.0, power);
-	if (m2 == NUMundefined || m3 == NUMundefined || m2 == 0.0) return NUMundefined;
+	if (isundef (m2) || isundef (m3) || m2 == 0.0) return undefined;
 	return m3 / (m2 * sqrt (m2));
 }
 
 double Spectrum_getKurtosis (Spectrum me, double power) {
 	double m2 = Spectrum_getCentralMoment (me, 2.0, power);
 	double m4 = Spectrum_getCentralMoment (me, 4.0, power);
-	if (m2 == NUMundefined || m4 == NUMundefined || m2 == 0.0) return NUMundefined;
+	if (isundef (m2) || isundef (m4) || m2 == 0.0) return undefined;
 	return m4 / (m2 * m2) - 3;
 }
 
 void Spectrum_getNearestMaximum (Spectrum me, double frequency, double *frequencyOfMaximum, double *heightOfMaximum) {
 	try {
 		autoSpectrumTier thee = Spectrum_to_SpectrumTier_peaks (me);
-		long index = AnyTier_timeToNearestIndex (thee.get()->asAnyTier(), frequency);
+		integer index = AnyTier_timeToNearestIndex (thee.get()->asAnyTier(), frequency);
 		if (index == 0)
 			Melder_throw (U"No peak.");
 		RealPoint point = thy points.at [index];
diff --git a/fon/SpectrumEditor.cpp b/fon/SpectrumEditor.cpp
index 08049f2..931698b 100644
--- a/fon/SpectrumEditor.cpp
+++ b/fon/SpectrumEditor.cpp
@@ -59,8 +59,8 @@ void structSpectrumEditor :: v_draw () {
 
 	/* Update buttons. */
 
-	long first, last;
-	long selectedSamples = Sampled_getWindowSamples (spectrum, our startSelection, our endSelection, & first, & last);
+	integer first, last;
+	integer selectedSamples = Sampled_getWindowSamples (spectrum, our startSelection, our endSelection, & first, & last);
 	GuiThing_setSensitive (our publishBandButton,  selectedSamples != 0);
 	GuiThing_setSensitive (our publishSoundButton, selectedSamples != 0);
 }
diff --git a/fon/TextGrid.cpp b/fon/TextGrid.cpp
index 5e810a1..0d1ec5b 100644
--- a/fon/TextGrid.cpp
+++ b/fon/TextGrid.cpp
@@ -1,6 +1,6 @@
 /* TextGrid.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1316,23 +1316,23 @@ autoTextGrid TextGrid_readFromChronologicalTextFile (MelderFile file) {
 	try {
 		int formatVersion = 0;
 		autoMelderReadText text = MelderReadText_createFromFile (file);
-		autostring32 tag = texgetw2 (text.peek());
+		autostring32 tag = texgetw16 (text.peek());
 		if (! str32equ (tag.peek(), U"Praat chronological TextGrid text file"))
 			Melder_throw (U"This is not a chronological TextGrid text file.");
 		autoTextGrid me = Thing_new (TextGrid);
 		my structFunction :: v_readText (text.peek(), formatVersion);
 		my tiers = FunctionList_create ();
-		long numberOfTiers = texgeti4 (text.peek());
+		long numberOfTiers = texgeti32 (text.peek());
 		for (long itier = 1; itier <= numberOfTiers; itier ++) {
-			autostring32 klas = texgetw2 (text.peek());
+			autostring32 klas = texgetw16 (text.peek());
 			if (str32equ (klas.peek(), U"IntervalTier")) {
 				autoIntervalTier tier = Thing_new (IntervalTier);
-				tier -> name = texgetw2 (text.peek());
+				tier -> name = texgetw16 (text.peek());
 				tier -> structFunction :: v_readText (text.peek(), formatVersion);
 				my tiers -> addItem_move (tier.move());
 			} else if (str32equ (klas.peek(), U"TextTier")) {
 				autoTextTier tier = Thing_new (TextTier);
-				tier -> name = texgetw2 (text.peek());
+				tier -> name = texgetw16 (text.peek());
 				tier -> structFunction :: v_readText (text.peek(), formatVersion);
 				my tiers -> addItem_move (tier.move());
 			} else {
@@ -1342,7 +1342,7 @@ autoTextGrid TextGrid_readFromChronologicalTextFile (MelderFile file) {
 		for (;;) {
 			long tierNumber;
 			try {
-				tierNumber = texgeti4 (text.peek());
+				tierNumber = texgeti32 (text.peek());
 			} catch (MelderError) {
 				if (str32str (Melder_getError (), U"Early end of text")) {
 					Melder_clearError ();
@@ -1447,13 +1447,13 @@ void TextGrid_writeToChronologicalTextFile (TextGrid me, MelderFile file) {
 					TextInterval interval = tier -> intervals.at [firstRemainingElement];
 					if (tier -> name) MelderFile_write (file, U"\n\n! ", tier -> name, U":");
 					MelderFile_write (file, U"\n", firstRemainingTier, U" ", interval -> xmin, U" ", interval -> xmax);
-					texputw4 (file, interval -> text, U"", 0,0,0,0,0);
+					texputw32 (file, interval -> text, U"", 0,0,0,0,0);
 				} else {
 					TextTier tier = static_cast <TextTier> (anyTier);
 					TextPoint point = tier -> points.at [firstRemainingElement];
 					if (tier -> name) MelderFile_write (file, U"\n\n! ", tier -> name, U":");
 					MelderFile_write (file, U"\n", firstRemainingTier, U" ", point -> number, U" ");
-					texputw4 (file, point -> mark, U"", 0,0,0,0,0);
+					texputw32 (file, point -> mark, U"", 0,0,0,0,0);
 				}
 				sortingTime = firstRemainingTime;
 				sortingTier = firstRemainingTier;
@@ -1655,8 +1655,8 @@ autoTextGrid TextGrid_readFromCgnSyntaxFile (MelderFile file) {
 }
 
 autoTable TextGrid_downto_Table (TextGrid me, bool includeLineNumbers, int timeDecimals, bool includeTierNames, bool includeEmptyIntervals) {
-	long numberOfRows = 0;
-	for (long itier = 1; itier <= my tiers->size; itier ++) {
+	integer numberOfRows = 0;
+	for (integer itier = 1; itier <= my tiers->size; itier ++) {
 		Function anyTier = my tiers->at [itier];
 		if (anyTier -> classInfo == classIntervalTier) {
 			IntervalTier tier = static_cast <IntervalTier> (anyTier);
@@ -1676,7 +1676,7 @@ autoTable TextGrid_downto_Table (TextGrid me, bool includeLineNumbers, int timeD
 		}
 	}
 	autoTable thee = Table_createWithoutColumnNames (numberOfRows, 3 + includeLineNumbers + includeTierNames);
-	long icol = 0;
+	integer icol = 0;
 	if (includeLineNumbers)
 		Table_setColumnLabel (thee.get(), ++ icol, U"line");
 	Table_setColumnLabel (thee.get(), ++ icol, U"tmin");
@@ -1684,12 +1684,12 @@ autoTable TextGrid_downto_Table (TextGrid me, bool includeLineNumbers, int timeD
 		Table_setColumnLabel (thee.get(), ++ icol, U"tier");
 	Table_setColumnLabel (thee.get(), ++ icol, U"text");
 	Table_setColumnLabel (thee.get(), ++ icol, U"tmax");
-	long irow = 0;
-	for (long itier = 1; itier <= my tiers->size; itier ++) {
+	integer irow = 0;
+	for (integer itier = 1; itier <= my tiers->size; itier ++) {
 		Function anyTier = my tiers->at [itier];
 		if (anyTier -> classInfo == classIntervalTier) {
 			IntervalTier tier = static_cast <IntervalTier> (anyTier);
-			for (long iinterval = 1; iinterval <= tier -> intervals.size; iinterval ++) {
+			for (integer iinterval = 1; iinterval <= tier -> intervals.size; iinterval ++) {
 				TextInterval interval = tier -> intervals.at [iinterval];
 				if (includeEmptyIntervals || (interval -> text && interval -> text [0] != U'\0')) {
 					++ irow;
@@ -1705,7 +1705,7 @@ autoTable TextGrid_downto_Table (TextGrid me, bool includeLineNumbers, int timeD
 			}
 		} else {
 			TextTier tier = static_cast <TextTier> (anyTier);
-			for (long ipoint = 1; ipoint <= tier -> points.size; ipoint ++) {
+			for (integer ipoint = 1; ipoint <= tier -> points.size; ipoint ++) {
 				TextPoint point = tier -> points.at [ipoint];
 				++ irow;
 				icol = 0;
@@ -1719,7 +1719,7 @@ autoTable TextGrid_downto_Table (TextGrid me, bool includeLineNumbers, int timeD
 			}
 		}
 	}
-	long columns [1+2] = { 0, 1 + includeLineNumbers, 3 + includeLineNumbers + includeTierNames };   // sort by tmin and tmax
+	integer columns [1+2] = { 0, 1 + includeLineNumbers, 3 + includeLineNumbers + includeTierNames };   // sort by tmin and tmax
 	Table_sortRows_Assert (thee.get(), columns, 2);
 	return thee;
 }
diff --git a/fon/TextGridEditor.cpp b/fon/TextGridEditor.cpp
index 6b2fdf0..f4af4ff 100644
--- a/fon/TextGridEditor.cpp
+++ b/fon/TextGridEditor.cpp
@@ -299,7 +299,7 @@ static void menu_cb_GetStartingPointOfInterval (TextGridEditor me, EDITOR_ARGS_D
 	if (anyTier -> classInfo == classIntervalTier) {
 		IntervalTier tier = (IntervalTier) anyTier;
 		long iinterval = IntervalTier_timeToIndex (tier, my startSelection);
-		double time = iinterval < 1 || iinterval > tier -> intervals.size ? NUMundefined :
+		double time = iinterval < 1 || iinterval > tier -> intervals.size ? undefined :
 			tier -> intervals.at [iinterval] -> xmin;
 		Melder_informationReal (time, U"seconds");
 	} else {
@@ -314,7 +314,7 @@ static void menu_cb_GetEndPointOfInterval (TextGridEditor me, EDITOR_ARGS_DIRECT
 	if (anyTier -> classInfo == classIntervalTier) {
 		IntervalTier tier = (IntervalTier) anyTier;
 		long iinterval = IntervalTier_timeToIndex (tier, my startSelection);
-		double time = iinterval < 1 || iinterval > tier -> intervals.size ? NUMundefined :
+		double time = iinterval < 1 || iinterval > tier -> intervals.size ? undefined :
 			tier -> intervals.at [iinterval] -> xmax;
 		Melder_informationReal (time, U"seconds");
 	} else {
@@ -442,7 +442,7 @@ static void menu_cb_ExtendSelectNextInterval (TextGridEditor me, EDITOR_ARGS_DIR
 
 static void menu_cb_MoveBtoZero (TextGridEditor me, EDITOR_ARGS_DIRECT) {
 	double zero = Sound_getNearestZeroCrossing (my d_sound.data, my startSelection, 1);   // STEREO BUG
-	if (NUMdefined (zero)) {
+	if (isdefined (zero)) {
 		my startSelection = zero;
 		if (my startSelection > my endSelection) {
 			double dummy = my startSelection;
@@ -455,7 +455,7 @@ static void menu_cb_MoveBtoZero (TextGridEditor me, EDITOR_ARGS_DIRECT) {
 
 static void menu_cb_MoveCursorToZero (TextGridEditor me, EDITOR_ARGS_DIRECT) {
 	double zero = Sound_getNearestZeroCrossing (my d_sound.data, 0.5 * (my startSelection + my endSelection), 1);   // STEREO BUG
-	if (NUMdefined (zero)) {
+	if (isdefined (zero)) {
 		my startSelection = my endSelection = zero;
 		FunctionEditor_marksChanged (me, true);
 	}
@@ -463,7 +463,7 @@ static void menu_cb_MoveCursorToZero (TextGridEditor me, EDITOR_ARGS_DIRECT) {
 
 static void menu_cb_MoveEtoZero (TextGridEditor me, EDITOR_ARGS_DIRECT) {
 	double zero = Sound_getNearestZeroCrossing (my d_sound.data, my endSelection, 1);   // STEREO BUG
-	if (NUMdefined (zero)) {
+	if (isdefined (zero)) {
 		my endSelection = zero;
 		if (my startSelection > my endSelection) {
 			double dummy = my startSelection;
@@ -745,7 +745,7 @@ static void do_movePointOrBoundary (TextGridEditor me, int where) {
 		right = tier -> intervals.at [selectedLeftBoundary];
 		position = where == 1 ? my startSelection : where == 2 ? my endSelection :
 			Sound_getNearestZeroCrossing (my d_sound.data, left -> xmax, 1);   // STEREO BUG
-		if (position == NUMundefined)
+		if (isundef (position))
 			Melder_throw (U"There is no zero crossing to move to.");
 		if (position <= left -> xmin || position >= right -> xmax)
 			Melder_throw (U"Cannot move a boundary past its neighbour.");
@@ -763,7 +763,7 @@ static void do_movePointOrBoundary (TextGridEditor me, int where) {
 		point = tier -> points.at [selectedPoint];
 		position = where == 1 ? my startSelection : where == 2 ? my endSelection :
 			Sound_getNearestZeroCrossing (my d_sound.data, point -> number, 1);   // STEREO BUG
-		if (position == NUMundefined)
+		if (isundef (position))
 			Melder_throw (U"There is no zero crossing to move to.");
 
 		Editor_save (me, pointSaveText [where]);
@@ -1900,7 +1900,7 @@ bool structTextGridEditor :: v_click (double xclick, double yWC, bool shiftKeyPr
 	/*
 	 * Get the time of the nearest boundary or point.
 	 */
-	tnear = NUMundefined;
+	tnear = undefined;
 	if (intervalTier) {
 		iClickedInterval = IntervalTier_timeToIndex (intervalTier, xclick);
 		if (iClickedInterval) {
@@ -1932,7 +1932,7 @@ bool structTextGridEditor :: v_click (double xclick, double yWC, bool shiftKeyPr
 	/*
 	 * Where did she click?
 	 */
-	nearBoundaryOrPoint = ( tnear != NUMundefined && fabs (Graphics_dxWCtoMM (our graphics.get(), xclick - tnear)) < 1.5 );
+	nearBoundaryOrPoint = ( isdefined (tnear) && fabs (Graphics_dxWCtoMM (our graphics.get(), xclick - tnear)) < 1.5 );
 	nearCursorCircle = ( our startSelection == our endSelection && Graphics_distanceWCtoMM (our graphics.get(), xclick, yWC,
 		our startSelection, (ntiers + 1 - iClickedTier) * soundY / ntiers - Graphics_dyMMtoWC (our graphics.get(), 1.5)) < 1.5 );
 
@@ -2070,7 +2070,7 @@ void structTextGridEditor :: v_clickSelectionViewer (double xWC, double yWC) {
 	if (our text) {
 		long first = 0, last = 0;
 		char32 *oldText = GuiText_getStringAndSelectionPosition (our text, & first, & last);
-		static MelderString newText { 0 };
+		static MelderString newText { };
 		MelderString_empty (& newText);
 		MelderString_ncopy (& newText, oldText, first);
 		MelderString_append (& newText, character);
@@ -2132,7 +2132,7 @@ void structTextGridEditor :: v_play (double tmin, double tmax) {
 	}
 	if (d_longSound.data) {
 		if (numberOfMuteChannels > 0) {
-			autoSound part = LongSound_extractPart (d_longSound.data, tmin, tmax, 1);
+			autoSound part = LongSound_extractPart (d_longSound.data, tmin, tmax, true);
 			autoMixingMatrix thee = MixingMatrix_create (numberOfChannelsToPlay, numberOfChannels);
 			MixingMatrix_muteAndActivateChannels (thee.get(), muteChannels);
 			Sound_and_MixingMatrix_playPart (part.get(), thee.get(), tmin, tmax, theFunctionEditor_playCallback, this);
diff --git a/fon/TextGrid_Sound.cpp b/fon/TextGrid_Sound.cpp
index 9b39c78..fcb8077 100644
--- a/fon/TextGrid_Sound.cpp
+++ b/fon/TextGrid_Sound.cpp
@@ -83,7 +83,7 @@ static void IntervalTier_insertIntervalDestructively (IntervalTier me, double tm
 	/*
 	 * Empty the interval in the word tier.
 	 */
-	trace (U"Empty interval %ld down to ", lastIntervalNumber, U".", firstIntervalNumber);
+	trace (U"Empty interval ", lastIntervalNumber, U" down to ", U".", firstIntervalNumber);
 	for (long iinterval = lastIntervalNumber; iinterval >= firstIntervalNumber; iinterval --) {
 		TextInterval interval = my intervals.at [iinterval];
 		if (interval -> xmin > tmin && interval -> xmin < tmax) {
@@ -360,7 +360,7 @@ void TextGrid_Sound_draw (TextGrid me, Sound sound, Graphics g, double tmin, dou
 	/*
 	 * Draw sound in upper part.
 	 */
-	long first, last;
+	integer first, last;
 	if (sound && Sampled_getWindowSamples (sound, tmin, tmax, & first, & last) > 1) {
 		Graphics_setLineType (g, Graphics_DOTTED);
 		Graphics_line (g, tmin, 0.0, tmax, 0.0);
diff --git a/fon/TimeSoundAnalysisEditor.cpp b/fon/TimeSoundAnalysisEditor.cpp
index f3650d4..ee0142b 100644
--- a/fon/TimeSoundAnalysisEditor.cpp
+++ b/fon/TimeSoundAnalysisEditor.cpp
@@ -216,13 +216,13 @@ static void menu_cb_logSettings (TimeSoundAnalysisEditor me, EDITOR_ARGS_FORM) {
 }
 
 static void menu_cb_deleteLogFile1 (TimeSoundAnalysisEditor me, EDITOR_ARGS_DIRECT) {
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	Melder_pathToFile (my p_log1_fileName, & file);
 	MelderFile_delete (& file);
 }
 
 static void menu_cb_deleteLogFile2 (TimeSoundAnalysisEditor me, EDITOR_ARGS_DIRECT) {
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	Melder_pathToFile (my p_log2_fileName, & file);
 	MelderFile_delete (& file);
 }
@@ -238,7 +238,7 @@ static void do_log (TimeSoundAnalysisEditor me, int which) {
 		 */
 		char32 *q = p + 1, varName [300], *r, *s, *colon;
 		int precision = -1;
-		double value = NUMundefined;
+		double value = undefined;
 		const char32 *stringValue = nullptr;
 		while (*q != U'\0' && *q != U'\'') q ++;
 		if (*q == U'\0') break;   /* No matching right quote: done with this line. */
@@ -316,7 +316,7 @@ static void do_log (TimeSoundAnalysisEditor me, int which) {
 			if (part != TimeSoundAnalysisEditor_PART_CURSOR) Melder_throw (U"Click inside the spectrogram first.");
 			value = Matrix_getValueAtXY (my d_spectrogram.get(), tmin, my d_spectrogram_cursor);
 		}
-		if (NUMdefined (value)) {
+		if (isdefined (value)) {
 			int varlen = (q - p) - 1, headlen = p - format;
 			char32 formattedNumber [400];
 			if (precision >= 0) {
@@ -325,14 +325,14 @@ static void do_log (TimeSoundAnalysisEditor me, int which) {
 				Melder_sprint (formattedNumber,400, value);
 			}
 			int arglen = str32len (formattedNumber);
-			static MelderString buffer { 0 };
+			static MelderString buffer { };
 			MelderString_ncopy (& buffer, format, headlen);
 			MelderString_append (& buffer, formattedNumber, p + varlen + 2);
 			str32cpy (format, buffer.string);
 			p += arglen - 1;
 		} else if (stringValue) {
 			int varlen = (q - p) - 1, headlen = p - format, arglen = str32len (stringValue);
-			static MelderString buffer { 0 };
+			static MelderString buffer { };
 			MelderString_ncopy (& buffer, format, headlen);
 			MelderString_append (& buffer, stringValue, p + varlen + 2);
 			str32cpy (format, buffer.string);
@@ -346,7 +346,7 @@ static void do_log (TimeSoundAnalysisEditor me, int which) {
 		MelderInfo_close ();
 	}
 	if ((which == 1 && my p_log1_toLogFile) || (which == 2 && my p_log2_toLogFile)) {
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		str32cpy (format + str32len (format), U"\n");
 		Melder_relativePathToFile (which == 1 ? my p_log1_fileName : my p_log2_fileName, & file);
 		MelderFile_appendText (& file, format);
@@ -725,7 +725,7 @@ static void menu_cb_pitchListing (TimeSoundAnalysisEditor me, EDITOR_ARGS_DIRECT
 		f0 = Function_convertToNonlogarithmic (my d_pitch.get(), f0, Pitch_LEVEL_FREQUENCY, my p_pitch_unit);
 		MelderInfo_writeLine (Melder_fixed (tmin, 6), U"   ", Melder_fixed (f0, 6));
 	} else {
-		long i, i1, i2;
+		integer i, i1, i2;
 		Sampled_getWindowSamples (my d_pitch.get(), tmin, tmax, & i1, & i2);
 		for (i = i1; i <= i2; i ++) {
 			double t = Sampled_indexToX (my d_pitch.get(), i);
@@ -802,7 +802,7 @@ static void menu_cb_moveCursorToMinimumPitch (TimeSoundAnalysisEditor me, EDITOR
 		double time;
 		Pitch_getMinimumAndTime (my d_pitch.get(), my startSelection, my endSelection,
 			my p_pitch_unit, 1, nullptr, & time);
-		if (! NUMdefined (time))
+		if (isundef (time))
 			Melder_throw (U"Selection is voiceless.");
 		my startSelection = my endSelection = time;
 		FunctionEditor_marksChanged (me, true);
@@ -822,7 +822,7 @@ static void menu_cb_moveCursorToMaximumPitch (TimeSoundAnalysisEditor me, EDITOR
 		double time;
 		Pitch_getMaximumAndTime (my d_pitch.get(), my startSelection, my endSelection,
 			my p_pitch_unit, 1, nullptr, & time);
-		if (! NUMdefined (time))
+		if (isundef (time))
 			Melder_throw (U"Selection is voiceless.");
 		my startSelection = my endSelection = time;
 		FunctionEditor_marksChanged (me, true);
@@ -972,7 +972,7 @@ static void menu_cb_intensityListing (TimeSoundAnalysisEditor me, EDITOR_ARGS_DI
 		double intensity = Vector_getValueAtX (my d_intensity.get(), tmin, Vector_CHANNEL_1, Vector_VALUE_INTERPOLATION_LINEAR);
 		MelderInfo_writeLine (Melder_fixed (tmin, 6), U"   ", Melder_fixed (intensity, 6));
 	} else {
-		long i, i1, i2;
+		integer i, i1, i2;
 		Sampled_getWindowSamples (my d_intensity.get(), tmin, tmax, & i1, & i2);
 		for (i = i1; i <= i2; i ++) {
 			double t = Sampled_indexToX (my d_intensity.get(), i);
@@ -1146,9 +1146,9 @@ static void menu_cb_formantListing (TimeSoundAnalysisEditor me, EDITOR_ARGS_DIRE
 		double f4 = Formant_getValueAtTime (my d_formant.get(), 4, tmin, 0);
 		MelderInfo_writeLine (Melder_fixed (tmin, 6), U"   ", Melder_fixed (f1, 6), U"   ", Melder_fixed (f2, 6), U"   ", Melder_fixed (f3, 6), U"   ", Melder_fixed (f4, 6));
 	} else {
-		long i, i1, i2;
+		integer i1, i2;
 		Sampled_getWindowSamples (my d_formant.get(), tmin, tmax, & i1, & i2);
-		for (i = i1; i <= i2; i ++) {
+		for (integer i = i1; i <= i2; i ++) {
 			double t = Sampled_indexToX (my d_formant.get(), i);
 			double f1 = Formant_getValueAtTime (my d_formant.get(), 1, t, 0);
 			double f2 = Formant_getValueAtTime (my d_formant.get(), 2, t, 0);
@@ -1770,7 +1770,7 @@ static void TimeSoundAnalysisEditor_v_draw_analysis (TimeSoundAnalysisEditor me)
 	 * Draw vertical scales.
 	 */
 	if (my p_pitch_show) {
-		double pitchCursor_overt = NUMundefined, pitchCursor_hidden = NUMundefined;
+		double pitchCursor_overt = undefined, pitchCursor_hidden = undefined;
 		Graphics_setWindow (my graphics.get(), my startWindow, my endWindow, pitchViewFrom_hidden, pitchViewTo_hidden);
 		Graphics_setColour (my graphics.get(), Graphics_BLUE);
 		if (my d_pitch) {
@@ -1779,19 +1779,19 @@ static void TimeSoundAnalysisEditor_v_draw_analysis (TimeSoundAnalysisEditor me)
 			else
 				pitchCursor_hidden = Pitch_getMean (my d_pitch.get(), my startSelection, my endSelection, my p_pitch_unit);
 			pitchCursor_overt = Function_convertToNonlogarithmic (my d_pitch.get(), pitchCursor_hidden, Pitch_LEVEL_FREQUENCY, my p_pitch_unit);
-			if (NUMdefined (pitchCursor_hidden)) {
+			if (isdefined (pitchCursor_hidden)) {
 				Graphics_setTextAlignment (my graphics.get(), Graphics_LEFT, Graphics_HALF);
 				Graphics_text (my graphics.get(), my endWindow, pitchCursor_hidden,
 					Melder_float (Melder_half (pitchCursor_overt)), U" ",
 					Function_getUnitText (my d_pitch.get(), Pitch_LEVEL_FREQUENCY, my p_pitch_unit, Function_UNIT_TEXT_SHORT | Function_UNIT_TEXT_GRAPHICAL));
 			}
-			if (! NUMdefined (pitchCursor_hidden) || Graphics_dyWCtoMM (my graphics.get(), pitchCursor_hidden - pitchViewFrom_hidden) > 5.0) {
+			if (isundef (pitchCursor_hidden) || Graphics_dyWCtoMM (my graphics.get(), pitchCursor_hidden - pitchViewFrom_hidden) > 5.0) {
 				Graphics_setTextAlignment (my graphics.get(), Graphics_LEFT, Graphics_BOTTOM);
 				Graphics_text (my graphics.get(), my endWindow, pitchViewFrom_hidden - Graphics_dyMMtoWC (my graphics.get(), 0.5),
 					Melder_float (Melder_half (pitchViewFrom_overt)), U" ",
 					Function_getUnitText (my d_pitch.get(), Pitch_LEVEL_FREQUENCY, my p_pitch_unit, Function_UNIT_TEXT_SHORT | Function_UNIT_TEXT_GRAPHICAL));
 			}
-			if (! NUMdefined (pitchCursor_hidden) || Graphics_dyWCtoMM (my graphics.get(), pitchViewTo_hidden - pitchCursor_hidden) > 5.0) {
+			if (isundef (pitchCursor_hidden) || Graphics_dyWCtoMM (my graphics.get(), pitchViewTo_hidden - pitchCursor_hidden) > 5.0) {
 				Graphics_setTextAlignment (my graphics.get(), Graphics_LEFT, Graphics_TOP);
 				Graphics_text (my graphics.get(), my endWindow, pitchViewTo_hidden,
 					Melder_float (Melder_half (pitchViewTo_overt)), U" ",
@@ -1807,7 +1807,7 @@ static void TimeSoundAnalysisEditor_v_draw_analysis (TimeSoundAnalysisEditor me)
 		Graphics_setColour (my graphics.get(), Graphics_BLACK);
 	}
 	if (my p_intensity_show) {
-		double intensityCursor = NUMundefined;
+		double intensityCursor = undefined;
 		Graphics_Colour textColour;
 		int alignment;
 		double y;
@@ -1824,7 +1824,7 @@ static void TimeSoundAnalysisEditor_v_draw_analysis (TimeSoundAnalysisEditor me)
 				}
 			}
 			Graphics_setColour (my graphics.get(), textColour);
-			bool intensityCursorVisible = NUMdefined (intensityCursor) &&
+			bool intensityCursorVisible = isdefined (intensityCursor) &&
 				intensityCursor > my p_intensity_viewFrom && intensityCursor < my p_intensity_viewTo;
 			if (intensityCursorVisible) {
 				static const char32 *methodString [] = { U" (.5)", U" (μE)", U" (μS)", U" (μ)" };
diff --git a/fon/TimeSoundEditor.cpp b/fon/TimeSoundEditor.cpp
index dd3f93d..af7fb34 100644
--- a/fon/TimeSoundEditor.cpp
+++ b/fon/TimeSoundEditor.cpp
@@ -194,18 +194,18 @@ static void do_write (TimeSoundEditor me, MelderFile file, int format, int numbe
 	} else if (my d_sound.data) {
 		Sound sound = my d_sound.data;
 		double margin = 0.0;
-		long nmargin = (long) floor (margin / sound -> dx);
-		long first, last, numberOfSamples = Sampled_getWindowSamples (sound,
+		integer nmargin = (integer) floor (margin / sound -> dx);
+		integer first, last, numberOfSamples = Sampled_getWindowSamples (sound,
 			my startSelection, my endSelection, & first, & last) + nmargin * 2;
 		first -= nmargin;
 		last += nmargin;
 		if (numberOfSamples) {
 			autoSound save = Sound_create (sound -> ny, 0.0, numberOfSamples * sound -> dx, numberOfSamples, sound -> dx, 0.5 * sound -> dx);
-			long offset = first - 1;
+			integer offset = first - 1;
 			if (first < 1) first = 1;
 			if (last > sound -> nx) last = sound -> nx;
-			for (long channel = 1; channel <= sound -> ny; channel ++) {
-				for (long i = first; i <= last; i ++) {
+			for (integer channel = 1; channel <= sound -> ny; channel ++) {
+				for (integer i = first; i <= last; i ++) {
 					save -> z [channel] [i - offset] = sound -> z [channel] [i];
 				}
 			}
@@ -434,7 +434,7 @@ void structTimeSoundEditor :: v_updateMenuItems_file () {
 		sound = d_longSound.data;
 	}
 	if (! sound) return;
-	long first, last, selectedSamples = Sampled_getWindowSamples (sound, our startSelection, our endSelection, & first, & last);
+	integer first, last, selectedSamples = Sampled_getWindowSamples (sound, our startSelection, our endSelection, & first, & last);
 	if (drawButton) {
 		GuiThing_setSensitive (drawButton, selectedSamples != 0);
 		GuiThing_setSensitive (publishButton, selectedSamples != 0);
@@ -478,7 +478,7 @@ void TimeSoundEditor_drawSound (TimeSoundEditor me, double globalMinimum, double
 		Graphics_text (my graphics.get(), 0.5, 0.5, U"(window too large; zoom in to see the data)");
 		return;
 	}
-	long first, last;
+	integer first, last;
 	if (Sampled_getWindowSamples (sound ? (Sampled) sound : (Sampled) longSound, my startWindow, my endWindow, & first, & last) <= 1) {
 		Graphics_setWindow (my graphics.get(), 0.0, 1.0, 0.0, 1.0);
 		Graphics_setTextAlignment (my graphics.get(), Graphics_CENTRE, Graphics_HALF);
@@ -562,18 +562,18 @@ void TimeSoundEditor_drawSound (TimeSoundEditor me, double globalMinimum, double
 			double mid = 0.5 * (minimum + maximum);
 			Graphics_text (my graphics.get(), my startWindow, mid, Melder_float (Melder_half (mid)));
 		} else {
-			if (! cursorVisible || ! NUMdefined (cursorFunctionValue) || Graphics_dyWCtoMM (my graphics.get(), cursorFunctionValue - minimum) > 5.0) {
+			if (! cursorVisible || isundef (cursorFunctionValue) || Graphics_dyWCtoMM (my graphics.get(), cursorFunctionValue - minimum) > 5.0) {
 				Graphics_setTextAlignment (my graphics.get(), Graphics_RIGHT, Graphics_BOTTOM);
 				Graphics_text (my graphics.get(), my startWindow, minimum, Melder_float (Melder_half (minimum)));
 			}
-			if (! cursorVisible || ! NUMdefined (cursorFunctionValue) || Graphics_dyWCtoMM (my graphics.get(), maximum - cursorFunctionValue) > 5.0) {
+			if (! cursorVisible || isundef (cursorFunctionValue) || Graphics_dyWCtoMM (my graphics.get(), maximum - cursorFunctionValue) > 5.0) {
 				Graphics_setTextAlignment (my graphics.get(), Graphics_RIGHT, Graphics_TOP);
 				Graphics_text (my graphics.get(), my startWindow, maximum, Melder_float (Melder_half (maximum)));
 			}
 		}
 		if (minimum < 0 && maximum > 0 && ! horizontal) {
 			Graphics_setWindow (my graphics.get(), 0.0, 1.0, minimum, maximum);
-			if (! cursorVisible || ! NUMdefined (cursorFunctionValue) || fabs (Graphics_dyWCtoMM (my graphics.get(), cursorFunctionValue - 0.0)) > 3.0) {
+			if (! cursorVisible || isundef (cursorFunctionValue) || fabs (Graphics_dyWCtoMM (my graphics.get(), cursorFunctionValue - 0.0)) > 3.0) {
 				Graphics_setTextAlignment (my graphics.get(), Graphics_RIGHT, Graphics_HALF);
 				Graphics_text (my graphics.get(), 0.0, 0.0, U"0");
 			}
@@ -593,7 +593,7 @@ void TimeSoundEditor_drawSound (TimeSoundEditor me, double globalMinimum, double
 			Graphics_setTextAlignment (my graphics.get(), Graphics_LEFT, Graphics_HALF);
 			Graphics_setTextAlignment (my graphics.get(), Graphics_LEFT, Graphics_HALF);
 			const char32 *channelName = my v_getChannelName (ichan);
-			static MelderString channelLabel;
+			static MelderString channelLabel { };
 			MelderString_copy (& channelLabel, ( channelName ? U"ch" : U"Ch " ), ichan);
 			if (channelName)
 				MelderString_append (& channelLabel, U": ", channelName);
@@ -620,7 +620,7 @@ void TimeSoundEditor_drawSound (TimeSoundEditor me, double globalMinimum, double
 		/*if (ichan == 1) FunctionEditor_SoundAnalysis_drawPulses (this);*/
 		if (sound) {
 			Graphics_setWindow (my graphics.get(), my startWindow, my endWindow, minimum, maximum);
-			if (cursorVisible && NUMdefined (cursorFunctionValue))
+			if (cursorVisible && isdefined (cursorFunctionValue))
 				FunctionEditor_drawCursorFunctionValue (me, cursorFunctionValue, Melder_float (Melder_half (cursorFunctionValue)), U"");
 			Graphics_setColour (my graphics.get(), Graphics_BLACK);
 			Graphics_function (my graphics.get(), sound -> z [ichan], first, last,
diff --git a/fon/Transition.cpp b/fon/Transition.cpp
index 685ac90..679fe6d 100644
--- a/fon/Transition.cpp
+++ b/fon/Transition.cpp
@@ -1,6 +1,6 @@
 /* Transition.cpp
  *
- * Copyright (C) 1997-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1997-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -45,7 +45,7 @@ void structTransition :: v_info () {
 }
 
 void structTransition :: v_writeText (MelderFile file) {
-	texputi4 (file, numberOfStates, U"numberOfStates", 0,0,0,0,0);
+	texputi32 (file, numberOfStates, U"numberOfStates", 0,0,0,0,0);
 	MelderFile_write (file, U"\nstateLabels []: ");
 	if (numberOfStates < 1) MelderFile_write (file, U"(empty)");
 	MelderFile_write (file, U"\n");
@@ -101,7 +101,7 @@ static void print4 (char *buffer, double value, int iformat, int width, int prec
 		if (numerator == 0)
 			snprintf (buffer, 40, "0");
 		else if (denominator > 1)
-			snprintf (buffer, 40, "%ld/%ld", numerator, denominator);
+			snprintf (buffer, 40, "%s/%s", Melder8_integer (numerator), Melder8_integer (denominator));
 		else
 			snprintf (buffer, 40, "%.7g", value);
 	} else {
diff --git a/fon/Vector.cpp b/fon/Vector.cpp
index 9d5c672..da30fbd 100644
--- a/fon/Vector.cpp
+++ b/fon/Vector.cpp
@@ -1,6 +1,6 @@
 /* Vector.cpp
  *
- * Copyright (C) 1992-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,11 +26,11 @@ double structVector :: v_getVector (long irow, long icol) {
 	if (ny == 1) return z [1] [icol];   // optimization
 	if (irow == 0) {
 		if (ny == 2) return 0.5 * (z [1] [icol] + z [2] [icol]);   // optimization
-		double sum = 0.0;
+		real80 sum = 0.0;
 		for (long channel = 1; channel <= ny; channel ++) {
 			sum += z [channel] [icol];
 		}
-		return sum / ny;
+		return real (sum / ny);
 	}
 	Melder_assert (irow > 0 && irow <= ny);
 	return z [irow] [icol];
@@ -41,7 +41,7 @@ double structVector :: v_getVector (long irow, long icol) {
 //
 double structVector :: v_getFunction1 (long irow, double x) {
 	double rcol = (x - x1) / dx + 1.0;
-	long icol = floor (rcol);
+	integer icol = (integer) floor (rcol);
 	double dcol = rcol - icol;
 	double z1;
 	if (icol < 1 || icol > nx) {
@@ -52,11 +52,11 @@ double structVector :: v_getFunction1 (long irow, double x) {
 		if (ny == 2) {
 			z1 = 0.5 * (z [1] [icol] + z [2] [icol]);   // optimization
 		} else {
-			double sum = 0.0;
-			for (long channel = 1; channel <= ny; channel ++) {
+			real80 sum = 0.0;
+			for (integer channel = 1; channel <= ny; channel ++) {
 				sum += z [channel] [icol];
 			}
-			z1 = sum / ny;
+			z1 = real (sum / ny);
 		}
 	} else {
 		Melder_assert (irow > 0 && irow <= ny);
@@ -71,11 +71,11 @@ double structVector :: v_getFunction1 (long irow, double x) {
 		if (ny == 2) {
 			z2 = 0.5 * (z [1] [icol + 1] + z [2] [icol + 1]);   // optimization
 		} else {
-			double sum = 0.0;
+			real80 sum = 0.0;
 			for (long channel = 1; channel <= ny; channel ++) {
 				sum += z [channel] [icol + 1];
 			}
-			z2 = sum / ny;
+			z2 = real (sum / ny);
 		}
 	} else {
 		Melder_assert (irow > 0 && irow <= ny);
@@ -96,13 +96,13 @@ double structVector :: v_getValueAtSample (long isamp, long ilevel, int unit) {
 	} else if (ny == 2) {
 		value = 0.5 * (z [1] [isamp] + z [2] [isamp]);   // optimization
 	} else {
-		double sum = 0.0;
+		real80 sum = 0.0;
 		for (long channel = 1; channel <= ny; channel ++) {
 			sum += z [channel] [isamp];
 		}
-		value = sum / ny;
+		value = real (sum / ny);
 	}
-	return NUMdefined (value) ? v_convertStandardToSpecialUnit (value, ilevel, unit) : NUMundefined;
+	return isdefined (value) ? v_convertStandardToSpecialUnit (value, ilevel, unit) : undefined;
 }
 
 Thing_implement (Vector, Matrix, 2);
@@ -114,7 +114,7 @@ Thing_implement (Vector, Matrix, 2);
 //
 double Vector_getValueAtX (Vector me, double x, long ilevel, int interpolation) {
 	double leftEdge = my x1 - 0.5 * my dx, rightEdge = leftEdge + my nx * my dx;
-	if (x <  leftEdge || x > rightEdge) return NUMundefined;
+	if (x <  leftEdge || x > rightEdge) return undefined;
 	if (ilevel > Vector_CHANNEL_AVERAGE) {
 		Melder_assert (ilevel <= my ny);
 		return NUM_interpolate_sinc (my z [ilevel], my nx, Sampled_xToIndex (me, x),
@@ -137,7 +137,7 @@ double Vector_getValueAtX (Vector me, double x, long ilevel, int interpolation)
 void Vector_getMinimumAndX (Vector me, double xmin, double xmax, long channel, int interpolation,
 	double *return_minimum, double *return_xOfMinimum)
 {
-	long imin, imax, n = my nx;
+	integer imin, imax, n = my nx;
 	Melder_assert (channel >= 1 && channel <= my ny);
 	double *y = my z [channel];
 	double minimum, x;
@@ -158,7 +158,7 @@ void Vector_getMinimumAndX (Vector me, double xmin, double xmax, long channel, i
 		if (y [imax] < minimum) minimum = y [imax], x = imax;
 		if (imin == 1) imin ++;
 		if (imax == my nx) imax --;
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			if (y [i] < y [i - 1] && y [i] <= y [i + 1]) {
 				double i_real, localMinimum = NUMimproveMinimum (y, n, i, interpolation, & i_real);
 				if (localMinimum < minimum) minimum = localMinimum, x = i_real;
@@ -212,7 +212,7 @@ long Vector_getChannelOfMinimum (Vector me, double xmin, double xmax, int interp
 void Vector_getMaximumAndX (Vector me, double xmin, double xmax, long channel, int interpolation,
 	double *return_maximum, double *return_xOfMaximum)
 {
-	long imin, imax, i, n = my nx;
+	integer imin, imax, i, n = my nx;
 	Melder_assert (channel >= 1 && channel <= my ny);
 	double *y = my z [channel];
 	double maximum, x;
@@ -298,18 +298,18 @@ double Vector_getMean (Vector me, double xmin, double xmax, long channel) {
 
 double Vector_getStandardDeviation (Vector me, double xmin, double xmax, long ilevel) {
 	if (xmax <= xmin) { xmin = my xmin; xmax = my xmax; }
-	long imin, imax, n = Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax);
-	if (n < 2) return NUMundefined;
+	integer imin, imax, n = Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax);
+	if (n < 2) return undefined;
 	if (ilevel == Vector_CHANNEL_AVERAGE) {
-		double sum2 = 0.0;
-		for (long channel = 1; channel <= my ny; channel ++) {
+		real80 sum2 = 0.0;
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			double mean = Vector_getMean (me, xmin, xmax, channel);
-			for (long i = imin; i <= imax; i ++) {
+			for (integer i = imin; i <= imax; i ++) {
 				double diff = my z [channel] [i] - mean;
 				sum2 += diff * diff;
 			}
 		}
-		return sqrt (sum2 / (n * my ny - my ny));   // The number of constraints equals the number of channels,
+		return sqrt (real (sum2 / (n * my ny - my ny)));   // The number of constraints equals the number of channels,
 				// because from every channel its own mean was subtracted.
 				// Corollary: a two-channel mono sound will have the same stdev as the corresponding one-channel sound.
 	}
@@ -373,21 +373,21 @@ void Vector_draw (Vector me, Graphics g, double *pxmin, double *pxmax, double *p
 	bool xreversed = *pxmin > *pxmax, yreversed = *pymin > *pymax;
 	if (xreversed) { double temp = *pxmin; *pxmin = *pxmax; *pxmax = temp; }
 	if (yreversed) { double temp = *pymin; *pymin = *pymax; *pymax = temp; }
-	long ixmin, ixmax, ix;
 	/*
-	 * Automatic domain.
-	 */
+		Automatic domain.
+	*/
 	if (*pxmin == *pxmax) {
 		*pxmin = my xmin;
 		*pxmax = my xmax;
 	}
 	/*
-	 * Domain expressed in sample numbers.
-	 */
+		Domain expressed in sample numbers.
+	*/
+	integer ixmin, ixmax;
 	Matrix_getWindowSamplesX (me, *pxmin, *pxmax, & ixmin, & ixmax);
 	/*
-	 * Automatic vertical range.
-	 */
+		Automatic vertical range.
+	*/
 	if (*pymin == *pymax) {
 		Matrix_getWindowExtrema (me, ixmin, ixmax, 1, 1, pymin, pymax);
 		if (*pymin == *pymax) {
@@ -396,12 +396,12 @@ void Vector_draw (Vector me, Graphics g, double *pxmin, double *pxmax, double *p
 		}
 	}
 	/*
-	 * Set coordinates for drawing.
-	 */
+		Set coordinates for drawing.
+	*/
 	Graphics_setInner (g);
 	Graphics_setWindow (g, xreversed ? *pxmax : *pxmin, xreversed ? *pxmin : *pxmax, yreversed ? *pymax : *pymin, yreversed ? *pymin : *pymax);
 	if (str32str (method, U"bars") || str32str (method, U"Bars")) {
-		for (ix = ixmin; ix <= ixmax; ix ++) {
+		for (integer ix = ixmin; ix <= ixmax; ix ++) {
 			double x = Sampled_indexToX (me, ix);
 			double y = my z [1] [ix];
 			double left = x - 0.5 * my dx, right = x + 0.5 * my dx;
@@ -415,12 +415,12 @@ void Vector_draw (Vector me, Graphics g, double *pxmin, double *pxmax, double *p
 			}
 		}
 	} else if (str32str (method, U"poles") || str32str (method, U"Poles")) {
-		for (ix = ixmin; ix <= ixmax; ix ++) {
+		for (integer ix = ixmin; ix <= ixmax; ix ++) {
 			double x = Sampled_indexToX (me, ix);
-			Graphics_line (g, x, 0, x, my z [1] [ix]);
+			Graphics_line (g, x, 0.0, x, my z [1] [ix]);
 		}
 	} else if (str32str (method, U"speckles") || str32str (method, U"Speckles")) {
-		for (ix = ixmin; ix <= ixmax; ix ++) {
+		for (integer ix = ixmin; ix <= ixmax; ix ++) {
 			double x = Sampled_indexToX (me, ix);
 			Graphics_speckle (g, x, my z [1] [ix]);
 		}
diff --git a/fon/VoiceAnalysis.cpp b/fon/VoiceAnalysis.cpp
index 1f90b25..abfbb48 100644
--- a/fon/VoiceAnalysis.cpp
+++ b/fon/VoiceAnalysis.cpp
@@ -1,6 +1,6 @@
 /* VoiceAnalysis.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,12 +22,12 @@
 double PointProcess_getJitter_local (PointProcess me, double tmin, double tmax,
 	double pmin, double pmax, double maximumPeriodFactor)
 {
-	double sum = 0.0;
+	real80 sum = 0.0;
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   /* Autowindowing. */
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
-	if (numberOfPeriods < 2) return NUMundefined;
-	for (long i = imin + 1; i < imax; i ++) {
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	if (numberOfPeriods < 2) return undefined;
+	for (integer i = imin + 1; i < imax; i ++) {
 		double p1 = my t [i] - my t [i - 1], p2 = my t [i + 1] - my t [i];
 		double intervalFactor = p1 > p2 ? p1 / p2 : p2 / p1;
 		if (pmin == pmax || (p1 >= pmin && p1 <= pmax && p2 >= pmin && p2 <= pmax && intervalFactor <= maximumPeriodFactor)) {
@@ -36,19 +36,19 @@ double PointProcess_getJitter_local (PointProcess me, double tmin, double tmax,
 			numberOfPeriods --;
 		}
 	}
-	if (numberOfPeriods < 2) return NUMundefined;
-	return sum / (numberOfPeriods - 1) / PointProcess_getMeanPeriod (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
+	if (numberOfPeriods < 2) return undefined;
+	return real (sum / (numberOfPeriods - 1)) / PointProcess_getMeanPeriod (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
 }
 
 double PointProcess_getJitter_local_absolute (PointProcess me, double tmin, double tmax,
 	double pmin, double pmax, double maximumPeriodFactor)
 {
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   /* Autowindowing. */
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
-	if (numberOfPeriods < 2) return NUMundefined;
-	double sum = 0.0;
-	for (long i = imin + 1; i < imax; i ++) {
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	if (numberOfPeriods < 2) return undefined;
+	real80 sum = 0.0;
+	for (integer i = imin + 1; i < imax; i ++) {
 		double p1 = my t [i] - my t [i - 1], p2 = my t [i + 1] - my t [i];
 		double intervalFactor = p1 > p2 ? p1 / p2 : p2 / p1;
 		if (pmin == pmax || (p1 >= pmin && p1 <= pmax && p2 >= pmin && p2 <= pmax && intervalFactor <= maximumPeriodFactor)) {
@@ -57,19 +57,19 @@ double PointProcess_getJitter_local_absolute (PointProcess me, double tmin, doub
 			numberOfPeriods --;
 		}
 	}
-	if (numberOfPeriods < 2) return NUMundefined;
-	return sum / (numberOfPeriods - 1);
+	if (numberOfPeriods < 2) return undefined;
+	return real (sum / (numberOfPeriods - 1));
 }
 
 double PointProcess_getJitter_rap (PointProcess me, double tmin, double tmax,
 	double pmin, double pmax, double maximumPeriodFactor)
 {
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   /* Autowindowing. */
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
-	if (numberOfPeriods < 3) return NUMundefined;
-	double sum = 0.0;
-	for (long i = imin + 2; i < imax; i ++) {
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	if (numberOfPeriods < 3) return undefined;
+	real80 sum = 0.0;
+	for (integer i = imin + 2; i < imax; i ++) {
 		double p1 = my t [i - 1] - my t [i - 2], p2 = my t [i] - my t [i - 1], p3 = my t [i + 1] - my t [i];
 		double intervalFactor1 = p1 > p2 ? p1 / p2 : p2 / p1, intervalFactor2 = p2 > p3 ? p2 / p3 : p3 / p2;
 		if (pmin == pmax || (p1 >= pmin && p1 <= pmax && p2 >= pmin && p2 <= pmax && p3 >= pmin && p3 <= pmax
@@ -80,19 +80,19 @@ double PointProcess_getJitter_rap (PointProcess me, double tmin, double tmax,
 			numberOfPeriods --;
 		}
 	}
-	if (numberOfPeriods < 3) return NUMundefined;
-	return sum / (numberOfPeriods - 2) / PointProcess_getMeanPeriod (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
+	if (numberOfPeriods < 3) return undefined;
+	return real (sum / (numberOfPeriods - 2)) / PointProcess_getMeanPeriod (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
 }
 
 double PointProcess_getJitter_ppq5 (PointProcess me, double tmin, double tmax,
 	double pmin, double pmax, double maximumPeriodFactor)
 {
 	if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   /* Autowindowing. */
-	long imin, imax;
-	long numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
-	if (numberOfPeriods < 5) return NUMundefined;
-	double sum = 0.0;
-	for (long i = imin + 5; i <= imax; i ++) {
+	integer imin, imax;
+	integer numberOfPeriods = PointProcess_getWindowPoints (me, tmin, tmax, & imin, & imax) - 1;
+	if (numberOfPeriods < 5) return undefined;
+	real80 sum = 0.0;
+	for (integer i = imin + 5; i <= imax; i ++) {
 		double
 			p1 = my t [i - 4] - my t [i - 5],
 			p2 = my t [i - 3] - my t [i - 4],
@@ -113,15 +113,15 @@ double PointProcess_getJitter_ppq5 (PointProcess me, double tmin, double tmax,
 			numberOfPeriods --;
 		}
 	}
-	if (numberOfPeriods < 5) return NUMundefined;
-	return sum / (numberOfPeriods - 4) / PointProcess_getMeanPeriod (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
+	if (numberOfPeriods < 5) return undefined;
+	return real (sum / (numberOfPeriods - 4)) / PointProcess_getMeanPeriod (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
 }
 
 double PointProcess_getJitter_ddp (PointProcess me, double tmin, double tmax,
 	double pmin, double pmax, double maximumPeriodFactor)
 {
 	double rap = PointProcess_getJitter_rap (me, tmin, tmax, pmin, pmax, maximumPeriodFactor);
-	return NUMdefined (rap) ? 3.0 * rap : NUMundefined;
+	return ( isdefined (rap) ? 3.0 * rap : undefined );
 }
 
 double PointProcess_Sound_getShimmer_local (PointProcess me, Sound thee, double tmin, double tmax,
@@ -134,7 +134,7 @@ double PointProcess_Sound_getShimmer_local (PointProcess me, Sound thee, double
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			return NUMundefined;
+			return undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer (local) not computed.");
 		}
@@ -151,7 +151,7 @@ double PointProcess_Sound_getShimmer_local_dB (PointProcess me, Sound thee, doub
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			return NUMundefined;
+			return undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer (local, dB) not computed.");
 		}
@@ -168,7 +168,7 @@ double PointProcess_Sound_getShimmer_apq3 (PointProcess me, Sound thee, double t
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			return NUMundefined;
+			return undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer (apq3) not computed.");
 		}
@@ -185,7 +185,7 @@ double PointProcess_Sound_getShimmer_apq5 (PointProcess me, Sound thee, double t
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			return NUMundefined;
+			return undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer (apq5) not computed.");
 		}
@@ -202,7 +202,7 @@ double PointProcess_Sound_getShimmer_apq11 (PointProcess me, Sound thee, double
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			return NUMundefined;
+			return undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer (apq11) not computed.");
 		}
@@ -216,11 +216,12 @@ double PointProcess_Sound_getShimmer_dda (PointProcess me, Sound thee, double tm
 		if (tmax <= tmin) tmin = my xmin, tmax = my xmax;   /* Autowindowing. */
 		autoAmplitudeTier peaks = PointProcess_Sound_to_AmplitudeTier_period (me, thee, tmin, tmax, pmin, pmax, maximumPeriodFactor);
 		double apq3 = AmplitudeTier_getShimmer_apq3 (peaks.get(), pmin, pmax, maximumAmplitudeFactor);
-		return NUMdefined (apq3) ? 3.0 * apq3 : NUMundefined;
+		return
+			isdefined (apq3) ? 3.0 * apq3 : undefined;
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			return NUMundefined;
+			return undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer (dda) not computed.");
 		}
@@ -246,12 +247,12 @@ void PointProcess_Sound_getShimmer_multi (PointProcess me, Sound thee, double tm
 	} catch (MelderError) {
 		if (Melder_hasError (U"Too few pulses between ")) {
 			Melder_clearError ();
-			if (local)    *local    = NUMundefined;
-			if (local_dB) *local_dB = NUMundefined;
-			if (apq3)     *apq3     = NUMundefined;
-			if (apq5)     *apq5     = NUMundefined;
-			if (apq11)    *apq11    = NUMundefined;
-			if (dda)      *dda      = NUMundefined;
+			if (local)    *local    = undefined;
+			if (local_dB) *local_dB = undefined;
+			if (apq3)     *apq3     = undefined;
+			if (apq5)     *apq5     = undefined;
+			if (apq11)    *apq11    = undefined;
+			if (dda)      *dda      = undefined;
 		} else {
 			Melder_throw (me, U" & ", thee, U": shimmer measures not computed.");
 		}
@@ -264,13 +265,13 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 	try {
 		if (tmin >= tmax) tmin = sound -> xmin, tmax = sound -> xmax;
 		/*
-		 * Time domain. Should be preceded by something like "Time range of SELECTION:" or so.
-		 */
+			Time domain. Should be preceded by something like "Time range of SELECTION:" or so.
+		*/
 		MelderInfo_write (U"   From ", Melder_fixed (tmin, 6), U" to ", Melder_fixed (tmax, 6), U" seconds");
 		MelderInfo_writeLine (U" (duration: ", Melder_fixed (tmax - tmin, 6), U" seconds)");
 		/*
-		 * Pitch statistics.
-		 */
+			Pitch statistics.
+		*/
 		MelderInfo_writeLine (U"Pitch:");
 		MelderInfo_writeLine (U"   Median pitch: ", Melder_fixed (Pitch_getQuantile (pitch, tmin, tmax, 0.50, kPitch_unit_HERTZ), 3), U" Hz");
 		MelderInfo_writeLine (U"   Mean pitch: ", Melder_fixed (Pitch_getMean (pitch, tmin, tmax, kPitch_unit_HERTZ), 3), U" Hz");
@@ -278,8 +279,8 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 		MelderInfo_writeLine (U"   Minimum pitch: ", Melder_fixed (Pitch_getMinimum (pitch, tmin, tmax, kPitch_unit_HERTZ, 1), 3), U" Hz");
 		MelderInfo_writeLine (U"   Maximum pitch: ", Melder_fixed (Pitch_getMaximum (pitch, tmin, tmax, kPitch_unit_HERTZ, 1), 3), U" Hz");
 		/*
-		 * Pulses statistics.
-		 */
+			Pulses statistics.
+		*/
 		double pmin = 0.8 / ceiling, pmax = 1.25 / floor;
 		MelderInfo_writeLine (U"Pulses:");
 		MelderInfo_writeLine (U"   Number of pulses: ", PointProcess_getWindowPoints (pulses, tmin, tmax, nullptr, nullptr));
@@ -287,13 +288,13 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 		MelderInfo_writeLine (U"   Mean period: ", Melder_fixedExponent (PointProcess_getMeanPeriod (pulses, tmin, tmax, pmin, pmax, maximumPeriodFactor), -3, 6), U" seconds");
 		MelderInfo_writeLine (U"   Standard deviation of period: ", Melder_fixedExponent (PointProcess_getStdevPeriod (pulses, tmin, tmax, pmin, pmax, maximumPeriodFactor), -3, 6), U" seconds");
 		/*
-		 * Voicing.
-		 */
-		long imin, imax, n = Sampled_getWindowSamples (pitch, tmin, tmax, & imin, & imax), nunvoiced = n;
-		for (long i = imin; i <= imax; i ++) {
+			Voicing.
+		*/
+		integer imin, imax, n = Sampled_getWindowSamples (pitch, tmin, tmax, & imin, & imax), nunvoiced = n;
+		for (integer i = imin; i <= imax; i ++) {
 			Pitch_Frame frame = & pitch -> frame [i];
 			if (frame -> intensity >= silenceThreshold) {
-				for (long icand = 1; icand <= frame -> nCandidates; icand ++) {
+				for (integer icand = 1; icand <= frame -> nCandidates; icand ++) {
 					Pitch_Candidate cand = & frame -> candidate [icand];
 					if (cand -> frequency > 0.0 && cand -> frequency < ceiling && cand -> strength >= voicingThreshold) {
 						nunvoiced --;
@@ -303,14 +304,14 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 			}
 		}
 		MelderInfo_writeLine (U"Voicing:");
-		MelderInfo_write (U"   Fraction of locally unvoiced frames: ", Melder_percent (n <= 0 ? NUMundefined : (double) nunvoiced / n, 3));
+		MelderInfo_write (U"   Fraction of locally unvoiced frames: ", Melder_percent (n <= 0 ? undefined : (double) nunvoiced / n, 3));
 		MelderInfo_writeLine (U"   (", nunvoiced, U" / ", n, U")");
 		n = PointProcess_getWindowPoints (pulses, tmin, tmax, & imin, & imax);
-		long numberOfVoiceBreaks = 0;
+		integer numberOfVoiceBreaks = 0;
 		double durationOfVoiceBreaks = 0.0;
 		if (n > 1) {
 			bool previousPeriodVoiced = true;
-			for (long i = imin + 1; i < imax; i ++) {
+			for (integer i = imin + 1; i < imax; i ++) {
 				double period = pulses -> t [i] - pulses -> t [i - 1];
 				if (period > pmax) {
 					durationOfVoiceBreaks += period;
@@ -327,8 +328,8 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 		MelderInfo_write (U"   Degree of voice breaks: ", Melder_percent (durationOfVoiceBreaks / (tmax - tmin), 3));
 		MelderInfo_writeLine (U"   (", Melder_fixed (durationOfVoiceBreaks, 6), U" seconds / ", Melder_fixed (tmax - tmin, 6), U" seconds)");
 		/*
-		 * Jitter.
-		 */
+			Jitter.
+		*/
 		double shimmerLocal, shimmerLocal_dB, apq3, apq5, apq11, dda;
 		MelderInfo_writeLine (U"Jitter:");
 		MelderInfo_writeLine (U"   Jitter (local): ", Melder_percent (PointProcess_getJitter_local (pulses, tmin, tmax, pmin, pmax, maximumPeriodFactor), 3));
@@ -337,8 +338,8 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 		MelderInfo_writeLine (U"   Jitter (ppq5): ", Melder_percent (PointProcess_getJitter_ppq5 (pulses, tmin, tmax, pmin, pmax, maximumPeriodFactor), 3));
 		MelderInfo_writeLine (U"   Jitter (ddp): ", Melder_percent (PointProcess_getJitter_ddp (pulses, tmin, tmax, pmin, pmax, maximumPeriodFactor), 3));
 		/*
-		 * Shimmer.
-		 */
+			Shimmer.
+		*/
 		PointProcess_Sound_getShimmer_multi (pulses, sound, tmin, tmax, pmin, pmax, maximumPeriodFactor, maximumAmplitudeFactor,
 			& shimmerLocal, & shimmerLocal_dB, & apq3, & apq5, & apq11, & dda);
 		MelderInfo_writeLine (U"Shimmer:");
@@ -349,8 +350,8 @@ void Sound_Pitch_PointProcess_voiceReport (Sound sound, Pitch pitch, PointProces
 		MelderInfo_writeLine (U"   Shimmer (apq11): ", Melder_percent (apq11, 3));
 		MelderInfo_writeLine (U"   Shimmer (dda): ", Melder_percent (dda, 3));
 		/*
-		 * Harmonicity.
-		 */
+			Harmonicity.
+		*/
 		MelderInfo_writeLine (U"Harmonicity of the voiced parts only:");
 		MelderInfo_writeLine (U"   Mean autocorrelation: ", Melder_fixed (Pitch_getMeanStrength (pitch, tmin, tmax, Pitch_STRENGTH_UNIT_AUTOCORRELATION), 6));
 		MelderInfo_writeLine (U"   Mean noise-to-harmonics ratio: ", Melder_fixed (Pitch_getMeanStrength (pitch, tmin, tmax, Pitch_STRENGTH_UNIT_NOISE_HARMONICS_RATIO), 6));
diff --git a/fon/WordList.cpp b/fon/WordList.cpp
index 26a9743..4e1f460 100644
--- a/fon/WordList.cpp
+++ b/fon/WordList.cpp
@@ -1,6 +1,6 @@
 /* WordList.cpp
  *
- * Copyright (C) 1999-2012,2015 Paul Boersma
+ * Copyright (C) 1999-2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -57,7 +57,7 @@ void structWordList :: v_info () {
 void structWordList :: v_readBinary (FILE *f, int /*formatVersion*/) {
 	char32 *current, *p;
 	int kar = 0;
-	our length = bingeti4 (f);
+	our length = bingeti32 (f);
 	if (our length < 0)
 		Melder_throw (U"Wrong length ", our length, U".");
 	string = Melder_calloc (char32, our length + 1);
@@ -104,7 +104,7 @@ void structWordList :: v_readBinary (FILE *f, int /*formatVersion*/) {
 void structWordList :: v_writeBinary (FILE *f) {
 	long currentLength, previousLength;
 	if (! length) length = str32len (string);
-	binputi4 (length, f);
+	binputi32 (length, f);
 	if (length > 0) {
 		char32 *current = string, *kar = current;
 		for (kar = current; *kar != U'\n'; kar ++) { }
diff --git a/fon/manual_Script.cpp b/fon/manual_Script.cpp
index 496de93..8143d1a 100644
--- a/fon/manual_Script.cpp
+++ b/fon/manual_Script.cpp
@@ -2678,7 +2678,7 @@ NORMAL (U"You can use any number of array and dictionary variables in a script,
 	"or to use Matrix or Sound objects.")
 MAN_END
 
-MAN_BEGIN (U"Scripting 5.7. Vectors and matrices", U"ppgb", 20170722)
+MAN_BEGIN (U"Scripting 5.7. Vectors and matrices", U"ppgb", 20170821)
 ENTRY (U"1. What is a vector?")
 NORMAL (U"A ##numeric vector# is an array of numbers, regarded as a single object. "
 	"For instance, the squares of the first five integers can be collected in the vector { 1, 4, 9, 16, 25 }. "
@@ -2742,13 +2742,13 @@ NORMAL (U"which gives 9.669539802906858 (the standard deviation is undefined for
 	"The ##center of gravity# of the distribution defined by regarding "
 	"the five values as relative frequencies as a function of the index from 1 to 5 is computed by")
 CODE (U"center (squares\\# )")
-NORMAL (U"which gives 4.090909090909091 (for vector with five elements, the result will always be "
+NORMAL (U"which gives 4.090909090909091 (for a vector with five elements, the result will always be "
 	"a number between 1.0 and 5.0). You compute the ##inner product# of two equally long vectors as follows:")
 CODE (U"other\\#  = { 2, 1.5, 1, 0.5, 0 }")
-CODE (U"result\\#  = inner (square\\# , other\\# )")
+CODE (U"result\\#  = inner (squares\\# , other\\# )")
 NORMAL (U"which gives 1*2 + 4*1.5 + 9*1 + 16*0.5 + 25*0 = 25. "
-	"The formula for this is \\su__%i=1_^5 square[i] * other[i], so that an alternative piece of 1code could be")
-CODE (U"result\\#  = sumOver (i to 5, square\\#  [i] * other\\#  [i])")
+	"The formula for this is \\su__%i=1_^5 squares[i] * other[i], so that an alternative piece of code could be")
+CODE (U"result\\#  = sumOver (i to 5, squares\\#  [i] * other\\#  [i])")
 ENTRY (U"4. Converting vectors to vectors")
 CODE (U"a\\#  = squares\\#  + 5   ; adding a number to each element of a vector")
 NORMAL (U"causes a\\#  to become the vector { 6, 9, 14, 21, 30 }.")
@@ -2764,7 +2764,7 @@ NORMAL (U"A vector can also be given to a ##menu command# that returns another v
 CODE (U"selectObject: myPitch")
 CODE (U"tmin = Get start time")
 CODE (U"tmax = Get end time")
-CODE (U"times\\#  = linear\\#  (tmin, tmax, 0.01, xx)")
+CODE (U"times\\#  = sequence_by_centre\\#  (tmin, tmax, 0.01)")
 CODE (U"pitches\\#  = Get values at times: times\\# , \"hertz\", \"linear\"")
 MAN_END
 
diff --git a/fon/manual_tutorials.cpp b/fon/manual_tutorials.cpp
index 6039b92..a4f98c7 100644
--- a/fon/manual_tutorials.cpp
+++ b/fon/manual_tutorials.cpp
@@ -26,6 +26,9 @@ MAN_BEGIN (U"What's new?", U"ppgb", 20170722)
 INTRO (U"Latest changes in Praat.")
 //LIST_ITEM (U"• Manual page about @@drawing a vowel triangle at .")
 
+NORMAL (U"##6.0.31# (21 August 2017)")
+LIST_ITEM (U"• Scripting: more vectors and matrices.")
+LIST_ITEM (U"• Numerics: faster and more precise sums, means, standard deviations.")
 NORMAL (U"##6.0.30# (22 July 2017)")
 LIST_ITEM (U"• Removed a bug that caused an incorrect title for a PitchTier or PointProcess window.")
 LIST_ITEM (U"• Removed a bug that caused Praat to crash when doing a linear regression on a Table with no rows.")
diff --git a/fon/praat_Fon.cpp b/fon/praat_Fon.cpp
index 467dbb4..15e8747 100644
--- a/fon/praat_Fon.cpp
+++ b/fon/praat_Fon.cpp
@@ -740,7 +740,7 @@ FORM (REAL_Harmonicity_getValueInFrame, U"Get value in frame", U"Harmonicity: Ge
 	OK
 DO
 	NUMBER_ONE (Harmonicity)
-		double result = frameNumber < 1 || frameNumber > my nx ? NUMundefined : my z [1] [frameNumber];
+		double result = ( frameNumber < 1 || frameNumber > my nx ? undefined : my z [1] [frameNumber] );
 	NUMBER_ONE_END (U" dB")
 }
 
@@ -803,7 +803,7 @@ FORM (REAL_Intensity_getValueInFrame, U"Get value in frame", U"Intensity: Get va
 	OK
 DO
 	NUMBER_ONE (Intensity)
-		double result = frameNumber < 1 || frameNumber > my nx ? NUMundefined : my z [1] [frameNumber];
+		double result = ( frameNumber < 1 || frameNumber > my nx ? undefined : my z [1] [frameNumber] );
 	NUMBER_ONE_END (U" dB")
 }
 
@@ -1232,7 +1232,7 @@ FORM (REAL_Ltas_getValueInBin, U"Get value in bin", U"Ltas: Get value in bin..."
 	OK
 DO
 	NUMBER_ONE (Ltas)
-		double result = binNumber < 1 || binNumber > my nx ? NUMundefined : my z [1] [binNumber];
+		double result = binNumber < 1 || binNumber > my nx ? undefined : my z [1] [binNumber];
 	NUMBER_ONE_END (U" dB")
 }
 
@@ -2573,7 +2573,7 @@ DIRECT (NEW_Spectrum_to_SpectrumTier_peaks) {
 FORM (NEW1_Strings_createAsFileList, U"Create Strings as file list", U"Create Strings as file list...") {
 	SENTENCEVAR (name, U"Name", U"fileList")
 	LABEL (U"", U"File path:")
-	static structMelderDir defaultDir { { 0 } };
+	static structMelderDir defaultDir { };
 	Melder_getHomeDir (& defaultDir);
 	static const char32 *homeDirectory = Melder_dirToPath (& defaultDir);
 	static char32 defaultPath [kMelder_MAXPATH+1];
@@ -2598,7 +2598,7 @@ DO
 FORM (NEW1_Strings_createAsDirectoryList, U"Create Strings as directory list", U"Create Strings as directory list...") {
 	SENTENCEVAR (name, U"Name", U"directoryList")
 	LABEL (U"", U"Path:")
-	static structMelderDir defaultDir = { { 0 } };
+	static structMelderDir defaultDir { };
 	Melder_getHomeDir (& defaultDir);
 	static const char32 *homeDirectory = Melder_dirToPath (& defaultDir);
 	static char32 defaultPath [kMelder_MAXPATH+1];
diff --git a/fon/praat_Matrix.cpp b/fon/praat_Matrix.cpp
index 6b2ca3c..e95f658 100644
--- a/fon/praat_Matrix.cpp
+++ b/fon/praat_Matrix.cpp
@@ -352,7 +352,7 @@ DO
 
 DIRECT (REAL_Matrix_getMinimum) {
 	NUMBER_ONE (Matrix)
-		double minimum = NUMundefined, maximum = NUMundefined;
+		double minimum = undefined, maximum = undefined;
 		Matrix_getWindowExtrema (me, 0, 0, 0, 0, & minimum, & maximum);
 		double result = minimum;
 	NUMBER_ONE_END (U" (minimum)");
@@ -360,7 +360,7 @@ DIRECT (REAL_Matrix_getMinimum) {
 
 DIRECT (REAL_Matrix_getMaximum) {
 	NUMBER_ONE (Matrix)
-		double minimum = NUMundefined, maximum = NUMundefined;
+		double minimum = undefined, maximum = undefined;
 		Matrix_getWindowExtrema (me, 0, 0, 0, 0, & minimum, & maximum);
 		double result = maximum;
 	NUMBER_ONE_END (U" (maximum)");
diff --git a/fon/praat_Sound.cpp b/fon/praat_Sound.cpp
index db765ae..17ccf9b 100644
--- a/fon/praat_Sound.cpp
+++ b/fon/praat_Sound.cpp
@@ -140,7 +140,7 @@ FORM (SAVE_LongSound_savePartAsAudioFile, U"LongSound: Save part as audio file",
 	OK
 DO
 	SAVE_ONE (LongSound)
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (audioFile, & file);
 		LongSound_savePartAsAudioFile (me, type, fromTime, toTime, & file, 16);
 	SAVE_ONE_END
@@ -1074,7 +1074,7 @@ FORM (REAL_old_Sound_getValueAtIndex, U"Sound: Get value at sample number", U"So
 	OK
 DO
 	NUMBER_ONE (Sound)
-		double result = sampleNumber < 1 || sampleNumber > my nx ? NUMundefined :
+		double result = sampleNumber < 1 || sampleNumber > my nx ? undefined :
 			my ny == 1 ? my z [1] [sampleNumber] : 0.5 * (my z [1] [sampleNumber] + my z [2] [sampleNumber]);
 	NUMBER_ONE_END (U" Pascal")
 }
@@ -1086,7 +1086,7 @@ FORM (REAL_Sound_getValueAtIndex, U"Sound: Get value at sample number", U"Sound:
 DO_ALTERNATIVE (REAL_old_Sound_getValueAtIndex)
 	NUMBER_ONE (Sound)
 		if (channel > my ny) channel = 1;
-		double result = sampleNumber < 1 || sampleNumber > my nx ? NUMundefined :
+		double result = sampleNumber < 1 || sampleNumber > my nx ? undefined :
 			Sampled_getValueAtSample (me, sampleNumber, channel, 0);
 	NUMBER_ONE_END (U" Pascal")
 }
diff --git a/fon/praat_Tiers.cpp b/fon/praat_Tiers.cpp
index b2933f0..0cc62aa 100644
--- a/fon/praat_Tiers.cpp
+++ b/fon/praat_Tiers.cpp
@@ -1232,7 +1232,8 @@ FORM (REAL_PointProcess_getTimeFromIndex, U"Get time", 0 /*"PointProcess: Get ti
 	OK
 DO
 	NUMBER_ONE (PointProcess)
-		double result = ( pointNumber > my nt ? NUMundefined : my t [pointNumber] );
+		double result =
+			pointNumber > my nt ? undefined : my t [pointNumber];
 	NUMBER_ONE_END (U" seconds")
 }
 
diff --git a/gram/Makefile b/gram/Makefile
index f2ea49e..58e45ec 100644
--- a/gram/Makefile
+++ b/gram/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "gram"
-# Paul Boersma, 15 May 2016
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../sys -I ../dwsys -I ../stat -I ../dwtools -I ../fon
+CPPFLAGS = -I ../kar -I ../sys -I ../dwsys -I ../stat -I ../dwtools -I ../fon
 
 OBJECTS = Network.o \
    OTGrammar.o OTGrammarEditor.o manual_gram.o praat_gram.o OTMulti.o OTMultiEditor.o \
@@ -24,4 +24,4 @@ libgram.a: $(OBJECTS)
 	$(AR) cq libgram.a $(OBJECTS)
 	$(RANLIB) libgram.a
 
-$(OBJECTS): *.h ../num/NUM.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
+$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
diff --git a/gram/Network.cpp b/gram/Network.cpp
index a7a0ba0..1dbfe5a 100644
--- a/gram/Network.cpp
+++ b/gram/Network.cpp
@@ -1,6 +1,6 @@
 /* Network.cpp
  *
- * Copyright (C) 2009-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 2009-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -432,7 +432,9 @@ void Network_draw (Network me, Graphics graphics, bool useColour) {
 
 void Network_addNode (Network me, double x, double y, double activity, bool clamped) {
 	try {
-		NUMvector_append (& my nodes, 1, & my numberOfNodes);
+		integer numberOfNodes = my numberOfNodes;
+		NUMvector_append (& my nodes, 1, & numberOfNodes);
+		my numberOfNodes = numberOfNodes;
 		my nodes [my numberOfNodes]. x = x;
 		my nodes [my numberOfNodes]. y = y;
 		my nodes [my numberOfNodes]. activity = my nodes [my numberOfNodes]. excitation = activity;
@@ -444,7 +446,9 @@ void Network_addNode (Network me, double x, double y, double activity, bool clam
 
 void Network_addConnection (Network me, long nodeFrom, long nodeTo, double weight, double plasticity) {
 	try {
-		NUMvector_append (& my connections, 1, & my numberOfConnections);
+		integer numberOfConnections = my numberOfConnections;
+		NUMvector_append (& my connections, 1, & numberOfConnections);
+		my numberOfConnections = numberOfConnections;
 		my connections [my numberOfConnections]. nodeFrom = nodeFrom;
 		my connections [my numberOfConnections]. nodeTo = nodeTo;
 		my connections [my numberOfConnections]. weight = weight;
diff --git a/gram/OTGrammar.cpp b/gram/OTGrammar.cpp
index 4f868c5..6cbf264 100644
--- a/gram/OTGrammar.cpp
+++ b/gram/OTGrammar.cpp
@@ -1,6 +1,6 @@
 /* OTGrammar.cpp
  *
- * Copyright (C) 1997-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1997-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -73,7 +73,6 @@
  */
 
 #include "OTGrammar.h"
-#include "NUM.h"
 
 #include "oo_DESTROY.h"
 #include "OTGrammar_def.h"
@@ -172,20 +171,20 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 	OTGrammar_Parent :: v_readText (text, formatVersion);
 	if (formatVersion >= 1) {
 		try {
-			decisionStrategy = texgete1 (text, kOTGrammar_decisionStrategy_getValue);
+			decisionStrategy = texgete8 (text, kOTGrammar_decisionStrategy_getValue);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read decision strategy.");
 		}
 	}
 	if (formatVersion >= 2) {
 		try {
-			leak = texgetr8 (text);
+			leak = texgetr64 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read leak.");
 		}
 	}
 	try {
-		numberOfConstraints = texgeti4 (text);
+		numberOfConstraints = texgeti32 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Trying to read number of constraints.");
 	}
@@ -194,17 +193,17 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 	for (long icons = 1; icons <= numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & constraints [icons];
 		try {
-			constraint -> name = texgetw2 (text);
+			constraint -> name = texgetw16 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read name of constraint ", icons, U".");
 		}
 		try {
-			constraint -> ranking = texgetr8 (text);
+			constraint -> ranking = texgetr64 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read ranking of constraint ", icons, U".");
 		}
 		try {
-			constraint -> disharmony = texgetr8 (text);
+			constraint -> disharmony = texgetr64 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read disharmony of constraint ", icons, U".");
 		}
@@ -212,14 +211,14 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 			constraint -> plasticity = 1.0;
 		} else {
 			try {
-				constraint -> plasticity = texgetr8 (text);
+				constraint -> plasticity = texgetr64 (text);
 			} catch (MelderError) {
 				Melder_throw (U"Trying to read plasticity of constraint ", icons, U".");
 			}
 		}
 	}
 	try {
-		numberOfFixedRankings = texgeti4 (text);
+		numberOfFixedRankings = texgeti32 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Trying to read number of fixed rankings.");
 	}
@@ -228,19 +227,19 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 		for (long irank = 1; irank <= numberOfFixedRankings; irank ++) {
 			OTGrammarFixedRanking fixedRanking = & fixedRankings [irank];
 			try {
-				fixedRanking -> higher = texgeti4 (text);
+				fixedRanking -> higher = texgeti32 (text);
 			} catch (MelderError) {
 				Melder_throw (U"Trying to read the higher of constraint pair ", irank, U".");
 			}
 			try {
-				fixedRanking -> lower = texgeti4 (text);
+				fixedRanking -> lower = texgeti32 (text);
 			} catch (MelderError) {
 				Melder_throw (U"Trying to read the lower of constraint pair ", irank, U".");
 			}
 		}
 	}
 	try {
-		numberOfTableaus = texgeti4 (text);
+		numberOfTableaus = texgeti32 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Trying to read number of tableaus.");
 	}
@@ -249,12 +248,12 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 	for (long itab = 1; itab <= numberOfTableaus; itab ++) {
 		OTGrammarTableau tableau = & tableaus [itab];
 		try {
-			tableau -> input = texgetw2 (text);
+			tableau -> input = texgetw16 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read input of tableau ", itab, U".");
 		}
 		try {
-			tableau -> numberOfCandidates = texgeti4 (text);
+			tableau -> numberOfCandidates = texgeti32 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read number of candidates of tableau ", itab, U".");
 		}
@@ -269,7 +268,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 			OTGrammarCandidate candidate = & tableau -> candidates [icand];
 			try {
-				candidate -> output = texgetw2 (text);
+				candidate -> output = texgetw16 (text);
 			} catch (MelderError) {
 				Melder_throw (U"Trying to read candidate ", icand, U" of tableau ", itab,
 					U" (input: ", tableau -> input, U") in line ", MelderReadText_getLineNumber (text), U".");
@@ -278,7 +277,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 			candidate -> marks = NUMvector <int> (1, candidate -> numberOfConstraints);
 			for (long icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
 				try {
-					candidate -> marks [icons] = texgeti2 (text);
+					candidate -> marks [icons] = texgeti16 (text);
 				} catch (MelderError) {
 					Melder_throw
 					(U"Trying to read number of violations of constraint ", icons,
@@ -1832,7 +1831,7 @@ bool OTGrammar_PairDistribution_findPositiveWeights_e (OTGrammar me, PairDistrib
 		 */
 		linprog = NUMlinprog_new (false);
 		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
-			NUMlinprog_addVariable (linprog, weightFloor, NUMundefined, 1.0);
+			NUMlinprog_addVariable (linprog, weightFloor, undefined, 1.0);
 		}
 		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tab = & my tableaus [itab];
@@ -1842,7 +1841,7 @@ bool OTGrammar_PairDistribution_findPositiveWeights_e (OTGrammar me, PairDistrib
 			OTGrammarCandidate optimalCandidate = & tab -> candidates [ioptimalCandidate];
 			for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) if (icand != ioptimalCandidate) {
 				OTGrammarCandidate cand = & tab -> candidates [icand];
-				NUMlinprog_addConstraint (linprog, marginOfSeparation, NUMundefined);
+				NUMlinprog_addConstraint (linprog, marginOfSeparation, undefined);
 				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
 					NUMlinprog_addConstraintCoefficient (linprog, cand -> marks [icons] - optimalCandidate -> marks [icons]);
 				}
@@ -2186,7 +2185,7 @@ static void OTGrammar_Distributions_opt_createOutputMatching (OTGrammar me, Dist
 			for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
 				OTGrammarCandidate cand = & tab -> candidates [icand];
 				cand -> numberOfPotentialPartialOutputsMatching = thy numberOfRows;
-				cand -> partialOutputMatches = NUMvector <signed char> (1, thy numberOfRows);
+				cand -> partialOutputMatches = NUMvector <bool> (1, thy numberOfRows);
 			}
 		}
 		for (long ipartialOutput = 1; ipartialOutput <= thy numberOfRows; ipartialOutput ++) {
diff --git a/gram/OTGrammar_def.h b/gram/OTGrammar_def.h
index 504d23c..6c25453 100644
--- a/gram/OTGrammar_def.h
+++ b/gram/OTGrammar_def.h
@@ -1,6 +1,6 @@
 /* OTGrammar_def.h
  *
- * Copyright (C) 1997-2011,2015 Paul Boersma
+ * Copyright (C) 1997-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,8 +34,8 @@ oo_DEFINE_STRUCT (OTGrammarConstraint)
 	#endif
 
 	#if !oo_READING && !oo_WRITING
-		oo_INT (tiedToTheLeft)
-		oo_INT (tiedToTheRight)
+		oo_INT16 (tiedToTheLeft)
+		oo_INT16 (tiedToTheRight)
 	#endif
 
 oo_END_STRUCT (OTGrammarConstraint)
diff --git a/gram/OTMulti.cpp b/gram/OTMulti.cpp
index a4e440d..a69d7fa 100644
--- a/gram/OTMulti.cpp
+++ b/gram/OTMulti.cpp
@@ -1,6 +1,6 @@
 /* OTMulti.cpp
  *
- * Copyright (C) 2005-2012,2013,2015,2016 Paul Boersma
+ * Copyright (C) 2005-2012,2013,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -105,44 +105,44 @@ void structOTMulti :: v_readText (MelderReadText text, int formatVersion) {
 	OTMulti_Parent :: v_readText (text, formatVersion);
 	if (formatVersion >= 1) {
 		try {
-			decisionStrategy = texgete1 (text, kOTGrammar_decisionStrategy_getValue);
+			decisionStrategy = texgete8 (text, kOTGrammar_decisionStrategy_getValue);
 		} catch (MelderError) {
 			Melder_throw (U"Decision strategy not read.");
 		}
 	}
 	if (formatVersion >= 2) {
 		try {
-			leak = texgetr8 (text);
+			leak = texgetr64 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Trying to read leak.");
 		}
 	}
-	if ((numberOfConstraints = texgeti4 (text)) < 1) Melder_throw (U"No constraints.");
+	if ((numberOfConstraints = texgeti32 (text)) < 1) Melder_throw (U"No constraints.");
 	constraints = NUMvector <structOTConstraint> (1, numberOfConstraints);
 	for (long icons = 1; icons <= numberOfConstraints; icons ++) {
 		OTConstraint constraint = & constraints [icons];
-		constraint -> name = texgetw2 (text);
-		constraint -> ranking = texgetr8 (text);
-		constraint -> disharmony = texgetr8 (text);
+		constraint -> name = texgetw16 (text);
+		constraint -> ranking = texgetr64 (text);
+		constraint -> disharmony = texgetr64 (text);
 		if (formatVersion < 2) {
 			constraint -> plasticity = 1.0;
 		} else {
 			try {
-				constraint -> plasticity = texgetr8 (text);
+				constraint -> plasticity = texgetr64 (text);
 			} catch (MelderError) {
 				Melder_throw (U"Plasticity of constraint ", icons, U" not read.");
 			}
 		}
 	}
-	if ((numberOfCandidates = texgeti4 (text)) < 1) Melder_throw (U"No candidates.");
+	if ((numberOfCandidates = texgeti32 (text)) < 1) Melder_throw (U"No candidates.");
 	candidates = NUMvector <structOTCandidate> (1, numberOfCandidates);
 	for (long icand = 1; icand <= numberOfCandidates; icand ++) {
 		OTCandidate candidate = & candidates [icand];
-		candidate -> string = texgetw2 (text);
+		candidate -> string = texgetw16 (text);
 		candidate -> numberOfConstraints = numberOfConstraints;   // redundancy, needed for writing binary
 		candidate -> marks = NUMvector <int> (1, candidate -> numberOfConstraints);
 		for (long icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
-			candidate -> marks [icons] = texgeti2 (text);
+			candidate -> marks [icons] = texgeti16 (text);
 		}
 	}
 	OTMulti_checkIndex (this);
diff --git a/gram/OTMultiEditor.cpp b/gram/OTMultiEditor.cpp
index b9448a3..25f6598 100644
--- a/gram/OTMultiEditor.cpp
+++ b/gram/OTMultiEditor.cpp
@@ -187,7 +187,7 @@ static void drawTableau (Graphics g) {
 
 void structOTMultiEditor :: v_draw () {
 	OTMulti grammar = (OTMulti) data;
-	static MelderString buffer { 0 };
+	static MelderString buffer { };
 	double rowHeight = 0.25, tableauHeight = 2 * rowHeight;
 	Graphics_clearWs (graphics.get());
 	HyperPage_listItem (this, U"\t\t      %%ranking value\t      %disharmony\t      %plasticity");
diff --git a/gram/OTMulti_def.h b/gram/OTMulti_def.h
index 7181853..6e7fefc 100644
--- a/gram/OTMulti_def.h
+++ b/gram/OTMulti_def.h
@@ -1,6 +1,6 @@
 /* OTMulti_def.h
  *
- * Copyright (C) 2005-2011,2015 Paul Boersma
+ * Copyright (C) 2005-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,8 +34,8 @@ oo_DEFINE_STRUCT (OTConstraint)
 	#endif
 
 	#if !oo_READING && !oo_WRITING
-		oo_INT (tiedToTheLeft)
-		oo_INT (tiedToTheRight)
+		oo_INT16 (tiedToTheLeft)
+		oo_INT16 (tiedToTheRight)
 	#endif
 
 oo_END_STRUCT (OTConstraint)
diff --git a/gram/RBM_def.h b/gram/RBM_def.h
index ffc55d3..dbba3ba 100644
--- a/gram/RBM_def.h
+++ b/gram/RBM_def.h
@@ -1,6 +1,6 @@
 /* RBM_def.h
  *
- * Copyright (C) 2016 Paul Boersma
+ * Copyright (C) 2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
 #define ooSTRUCT RBM
 oo_DEFINE_CLASS (RBM, Daata)
 
-	oo_BOOL (inputsAreBinary)
+	oo_QUESTION (inputsAreBinary)
 	oo_LONG (numberOfInputNodes)
 	oo_LONG (numberOfOutputNodes)
 	oo_DOUBLE_MATRIX (weights, numberOfInputNodes, numberOfOutputNodes)
diff --git a/main/Makefile b/main/Makefile
index 7da2cb8..a2d7143 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the 'main' routines.
-# Paul Boersma, 2 June 2017
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../sys -I ../fon
+CPPFLAGS = -I ../kar -I ../sys -I ../fon
 
 .PHONY: clean
 
diff --git a/makefiles/makefile.defs.linux.nogui b/makefiles/makefile.defs.linux.nogui
index fb0a8f8..1e10780 100644
--- a/makefiles/makefile.defs.linux.nogui
+++ b/makefiles/makefile.defs.linux.nogui
@@ -7,7 +7,7 @@ CC = gcc -std=gnu99
 
 CXX = g++ -std=c++11
 
-CFLAGS = -DNO_GUI -DNO_NETWORK -D_FILE_OFFSET_BITS=64 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/cairo -I/usr/include/pango-1.0 -DUNIX -Dlinux -Werror=missing-prototypes -Werror=implicit -Wreturn-type -Wunused -Wunused-parameter -Wuninitialized -O3 -g1 -pthread
+CFLAGS = -DNO_GUI -DNO_NETWORK -D_FILE_OFFSET_BITS=64 `pkg-config --cflags pangocairo` -DUNIX -Dlinux -Werror=missing-prototypes -Werror=implicit -Wreturn-type -Wunused -Wunused-parameter -Wuninitialized -O3 -g1 -pthread
 
 CXXFLAGS = $(CFLAGS) -Wshadow
 
@@ -15,7 +15,7 @@ LINK = g++
 
 EXECUTABLE = praat_nogui
 
-LIBS = -lpangocairo-1.0 -lcairo -lpango-1.0 -lgobject-2.0 -lm -lpthread
+LIBS = `pkg-config --libs pangocairo` -lm -lpthread
 
 AR = ar
 RANLIB = ls
diff --git a/num/Makefile b/num/Makefile
index e54819a..252940d 100644
--- a/num/Makefile
+++ b/num/Makefile
@@ -1,5 +1,5 @@
 # Makefile of the library "num"
-# Paul Boersma, 24 August 2013
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
@@ -21,4 +21,4 @@ libnum.a: $(OBJECTS)
 	$(AR) cq libnum.a $(OBJECTS)
 	$(RANLIB) libnum.a
 
-$(OBJECTS): *.h ../external/gsl/*.h ../external/glpk/*.h ../sys/*.h ../dwsys/*.h
+$(OBJECTS): ../external/gsl/*.h ../external/glpk/*.h ../sys/*.h ../dwsys/*.h
diff --git a/num/NUM.cpp b/num/NUM.cpp
index 2e63fa6..be656f1 100644
--- a/num/NUM.cpp
+++ b/num/NUM.cpp
@@ -1,6 +1,6 @@
 /* NUM.cpp
  *
- * Copyright (C) 1992-2008,2011,2012,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2008,2011,2012,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
  * pb 2002/03/07 GPL
  * pb 2003/06/19 ridders3 replaced with ridders
  * pb 2003/07/09 gsl
- * pb 2003/08/27 NUMfisherQ: underflow and iteration excess should not return NUMundefined
+ * pb 2003/08/27 NUMfisherQ: underflow and iteration excess should not return undefined
  * pb 2005/07/08 NUMpow
  * pb 2006/08/02 NUMinvSigmoid
  * pb 2007/01/27 use #defines for value interpolation
@@ -31,12 +31,9 @@
  * pb 2011/03/29 C++
  */
 
-#include "NUM.h"
-#include "NUM2.h"
-#include <stdlib.h>
 #include "melder.h"
+#include "NUM2.h"
 #define SIGN(x,s) ((s) < 0 ? -fabs (x) : fabs(x))
-#define my  me ->
 double NUMpow (double base, double exponent) { return base <= 0.0 ? 0.0 : pow (base, exponent); }
 /*
 	GSL is more accurate than the other routines, but makes
@@ -116,11 +113,11 @@ void NUMautoscale (double x [], long n, double scale) {
 double NUMlnGamma (double x) {
 	gsl_sf_result result;
 	int status = gsl_sf_lngamma_e (x, & result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return ( status == GSL_SUCCESS ? result. val : undefined );
 }
 
 double NUMbeta (double z, double w) {
-	if (z <= 0.0 || w <= 0.0) return NUMundefined;
+	if (z <= 0.0 || w <= 0.0) return undefined;
 	return exp (NUMlnGamma (z) + NUMlnGamma (w) - NUMlnGamma (z + w));
 }
 
@@ -129,22 +126,22 @@ double NUMincompleteBeta (double a, double b, double x) {
 	int status = gsl_sf_beta_inc_e (a, b, x, & result);
 	if (status != GSL_SUCCESS && status != GSL_EUNDRFLW && status != GSL_EMAXITER) {
 		Melder_fatal (U"NUMincompleteBeta status ", status);
-		return NUMundefined;
+		return undefined;
 	}
 	return result. val;
 }
 
 double NUMbinomialP (double p, double k, double n) {
 	double binomialQ;
-	if (p < 0.0 || p > 1.0 || n <= 0.0 || k < 0.0 || k > n) return NUMundefined;
+	if (p < 0.0 || p > 1.0 || n <= 0.0 || k < 0.0 || k > n) return undefined;
 	if (k == n) return 1.0;
 	binomialQ = NUMincompleteBeta (k + 1, n - k, p);
-	if (binomialQ == NUMundefined) return NUMundefined;
+	if (isundef (binomialQ)) return undefined;
 	return 1.0 - binomialQ;
 }
 
 double NUMbinomialQ (double p, double k, double n) {
-	if (p < 0.0 || p > 1.0 || n <= 0.0 || k < 0.0 || k > n) return NUMundefined;
+	if (p < 0.0 || p > 1.0 || n <= 0.0 || k < 0.0 || k > n) return undefined;
 	if (k == 0.0) return 1.0;
 	return NUMincompleteBeta (k, n - k + 1, p);
 }
@@ -163,7 +160,7 @@ static double binomialQ (double p, void *binomial_void) {
 
 double NUMinvBinomialP (double p, double k, double n) {
 	static struct binomial binomial;
-	if (p < 0 || p > 1 || n <= 0 || k < 0 || k > n) return NUMundefined;
+	if (p < 0 || p > 1 || n <= 0 || k < 0 || k > n) return undefined;
 	if (k == n) return 1.0;
 	binomial. p = p;
 	binomial. k = k;
@@ -173,7 +170,7 @@ double NUMinvBinomialP (double p, double k, double n) {
 
 double NUMinvBinomialQ (double p, double k, double n) {
 	static struct binomial binomial;
-	if (p < 0 || p > 1 || n <= 0 || k < 0 || k > n) return NUMundefined;
+	if (p < 0 || p > 1 || n <= 0 || k < 0 || k > n) return undefined;
 	if (k == 0) return 0.0;
 	binomial. p = p;
 	binomial. k = k;
@@ -226,12 +223,12 @@ double NUMbessel_i1_f (double x) {
 double NUMbesselI (long n, double x) {
 	gsl_sf_result result;
 	int status = gsl_sf_bessel_In_e (n, x, & result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return ( status == GSL_SUCCESS ? result. val : undefined );
 }
 
 /* Modified Bessel function K0. Abramowicz & Stegun, p. 379. */
 double NUMbessel_k0_f (double x) {
-	if (x <= 0.0) return NUMundefined;   /* Positive infinity. */
+	if (x <= 0.0) return undefined;
 	if (x <= 2.0) {
 		/* Formula 9.8.5. Accuracy 1e-8. */
 		double x2 = 0.5 * x, t = x2 * x2;
@@ -251,7 +248,7 @@ double NUMbessel_k0_f (double x) {
 
 /* Modified Bessel function K1. Abramowicz & Stegun, p. 379. */
 double NUMbessel_k1_f (double x) {
-	if (x <= 0.0) return NUMundefined;   /* Positive infinity. */
+	if (x <= 0.0) return undefined;
 	if (x <= 2.0) {
 		/* Formula 9.8.7. Accuracy  of the polynomial factor 8e-9. */
 		double x2 = 0.5 * x, t = x2 * x2;
@@ -270,43 +267,42 @@ double NUMbessel_k1_f (double x) {
 }
 
 double NUMbesselK_f (long n, double x) {
-	double twoByX, besselK_min2, besselK_min1, besselK = NUMundefined;
-	long i;
+	double besselK = undefined;
 	Melder_assert (n >= 0 && x > 0);
-	besselK_min2 = NUMbessel_k0_f (x);
+	double besselK_min2 = NUMbessel_k0_f (x);
 	if (n == 0) return besselK_min2;
-	besselK_min1 = NUMbessel_k1_f (x);
+	double besselK_min1 = NUMbessel_k1_f (x);
 	if (n == 1) return besselK_min1;
 	Melder_assert (n >= 2);
-	twoByX = 2.0 / x;
+	double twoByX = 2.0 / x;
 	/*
 		Recursion formula.
 	*/
-	for (i = 1; i < n; i ++) {
+	for (long i = 1; i < n; i ++) {
 		besselK = besselK_min2 + twoByX * i * besselK_min1;
 		besselK_min2 = besselK_min1;
 		besselK_min1 = besselK;
 	}
-	Melder_assert (NUMdefined (besselK));
+	Melder_assert (isdefined (besselK));
 	return besselK;
 }
 
 double NUMbesselK (long n, double x) {
 	gsl_sf_result result;
 	int status = gsl_sf_bessel_Kn_e (n, x, & result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return ( status == GSL_SUCCESS ? result. val : undefined );
 }
 
 double NUMsigmoid (double x)
-	{ return x > 0.0 ? 1 / (1 + exp (- x)) : 1 - 1 / (1 + exp (x)); }
+	{ return x > 0.0 ? 1.0 / (1.0 + exp (- x)) : 1.0 - 1.0 / (1.0 + exp (x)); }
 
 double NUMinvSigmoid (double x)
-	{ return x <= 0.0 || x >= 1.0 ? NUMundefined : log (x / (1.0 - x)); }
+	{ return x <= 0.0 || x >= 1.0 ? undefined : log (x / (1.0 - x)); }
 
 double NUMerfcc (double x) {
 	gsl_sf_result result;
 	int status = gsl_sf_erfc_e (x, & result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return status == GSL_SUCCESS ? result. val : undefined;
 }
 
 double NUMgaussP (double z) {
@@ -320,22 +316,22 @@ double NUMgaussQ (double z) {
 double NUMincompleteGammaP (double a, double x) {
 	gsl_sf_result result;
 	int status = gsl_sf_gamma_inc_P_e (a, x, & result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return status == GSL_SUCCESS ? result. val : undefined;
 }
 
 double NUMincompleteGammaQ (double a, double x) {
 	gsl_sf_result result;
 	int status = gsl_sf_gamma_inc_Q_e (a, x, & result);
-	return status == GSL_SUCCESS ? result. val : NUMundefined;
+	return status == GSL_SUCCESS ? result. val : undefined;
 }
 
 double NUMchiSquareP (double chiSquare, double degreesOfFreedom) {
-	if (chiSquare < 0 || degreesOfFreedom <= 0) return NUMundefined;
+	if (chiSquare < 0 || degreesOfFreedom <= 0) return undefined;
 	return NUMincompleteGammaP (0.5 * degreesOfFreedom, 0.5 * chiSquare);
 }
 
 double NUMchiSquareQ (double chiSquare, double degreesOfFreedom) {
-	if (chiSquare < 0 || degreesOfFreedom <= 0) return NUMundefined;
+	if (chiSquare < 0 || degreesOfFreedom <= 0) return undefined;
 	return NUMincompleteGammaQ (0.5 * degreesOfFreedom, 0.5 * chiSquare);
 }
 
@@ -349,7 +345,7 @@ double NUMcombinations (long n, long k) {
 }
 
 #define NUM_interpolate_simple_cases \
-	if (nx < 1) return NUMundefined; \
+	if (nx < 1) return undefined; \
 	if (x > nx) return y [nx]; \
 	if (x < 1) return y [1]; \
 	if (x == midleft) return y [midleft]; \
diff --git a/num/NUM.h b/num/NUM.h
deleted file mode 100644
index c73388d..0000000
--- a/num/NUM.h
+++ /dev/null
@@ -1,612 +0,0 @@
-#ifndef _NUM_h_
-#define _NUM_h_
-/* NUM.h
- *
- * Copyright (C) 1992-2011,2013,2015 Paul Boersma
- *
- * This code 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.
- *
- * This code is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this work. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* "NUM" = "NUMerics" */
-/* More mathematical and numerical things than there are in <math.h>. */
-
-/********** Inherit all the ANSI routines from math.h **********/
-
-/* On the sgi, math.h declares some bessel functions. */
-/* The following statements suppress these declarations */
-/* so that the compiler will give no warnings */
-/* when you redeclare y0 etc. in your code. */
-#ifdef sgi
-	#define y0 sgi_y0
-	#define y1 sgi_y1
-	#define yn sgi_yn
-	#define j0 sgi_j0
-	#define j1 sgi_j1
-	#define jn sgi_jn
-#endif
-#include <math.h>
-#ifdef sgi
-	#undef y0
-	#undef y1
-	#undef yn
-	#undef j0
-	#undef j1
-	#undef jn
-#endif
-#include <stdio.h>
-#include <wchar.h>
-#include "../sys/abcio.h"
-#define NUMlog2(x)  (log (x) * NUMlog2e)
-
-void NUMinit ();
-
-double NUMpow (double base, double exponent);   /* Zero for non-positive base. */
-void NUMshift (double *x, double xfrom, double xto);
-void NUMscale (double *x, double xminfrom, double xmaxfrom, double xminto, double xmaxto);
-
-/********** Constants **********
- * Forty-digit constants computed by e.g.:
- *    bc -l
- *       scale=42
- *       print e(1)
- * Then rounding away the last two digits.
- */
-//      print e(1)
-#define NUMe  2.7182818284590452353602874713526624977572
-//      print 1/l(2)
-#define NUMlog2e  1.4426950408889634073599246810018921374266
-//      print l(10)/l(2)
-#define NUMlog2_10  3.3219280948873623478703194294893901758648
-//      print 1/l(10)
-#define NUMlog10e  0.4342944819032518276511289189166050822944
-//      print l(2)/l(10)
-#define NUMlog10_2  0.3010299956639811952137388947244930267682
-//      print l(2)
-#define NUMln2  0.6931471805599453094172321214581765680755
-//      print l(10)
-#define NUMln10  2.3025850929940456840179914546843642076011
-//      print a(1)*8
-#define NUM2pi  6.2831853071795864769252867665590057683943
-//      print a(1)*4
-#define NUMpi  3.1415926535897932384626433832795028841972
-//      print a(1)*2
-#define NUMpi_2  1.5707963267948966192313216916397514420986
-//      print a(1)
-#define NUMpi_4  0.7853981633974483096156608458198757210493
-//      print 0.25/a(1)
-#define NUM1_pi  0.3183098861837906715377675267450287240689
-//      print 0.5/a(1)
-#define NUM2_pi  0.6366197723675813430755350534900574481378
-//      print sqrt(a(1)*4)
-#define NUMsqrtpi  1.7724538509055160272981674833411451827975
-//      print sqrt(a(1)*8)
-#define NUMsqrt2pi  2.5066282746310005024157652848110452530070
-//      print 1/sqrt(a(1)*8)
-#define NUM1_sqrt2pi  0.3989422804014326779399460599343818684759
-//      print 1/sqrt(a(1))
-#define NUM2_sqrtpi  1.1283791670955125738961589031215451716881
-//      print l(a(1)*4)
-#define NUMlnpi  1.1447298858494001741434273513530587116473
-//      print sqrt(2)
-#define NUMsqrt2  1.4142135623730950488016887242096980785697
-//      print sqrt(0.5)
-#define NUMsqrt1_2  0.7071067811865475244008443621048490392848
-//      print sqrt(3)
-#define NUMsqrt3  1.7320508075688772935274463415058723669428
-//      print sqrt(5)
-#define NUMsqrt5  2.2360679774997896964091736687312762354406
-//      print sqrt(6)
-#define NUMsqrt6  2.4494897427831780981972840747058913919659
-//      print sqrt(7)
-#define NUMsqrt7  2.6457513110645905905016157536392604257102
-//      print sqrt(8)
-#define NUMsqrt8  2.8284271247461900976033774484193961571393
-//      print sqrt(10)
-#define NUMsqrt10  3.1622776601683793319988935444327185337196
-//      print sqrt(5)/2-0.5
-#define NUM_goldenSection  0.6180339887498948482045868343656381177203
-// The Euler-Mascheroni constant cannot be computed by bc.
-// Instead we use the 40 digits computed by Johann von Soldner in 1809.
-#define NUM_euler  0.5772156649015328606065120900824024310422
-#define NUMundefined  HUGE_VAL
-#define NUMdefined(x)  ((x) != NUMundefined)
-
-/********** Arrays with one index (NUMarrays.cpp) **********/
-
-void * NUMvector (long elementSize, long lo, long hi);
-/*
-	Function:
-		create a vector [lo...hi] with all values initialized to 0.
-	Preconditions:
-		hi >= lo;
-*/
-
-void NUMvector_free (long elementSize, void *v, long lo);
-/*
-	Function:
-		destroy a vector v that was created with NUMvector.
-	Preconditions:
-		lo must have the same values as with the creation of the vector.
-*/
-
-void * NUMvector_copy (long elementSize, void *v, long lo, long hi);
-/*
-	Function:
-		copy (part of) a vector v, which need not have been created with NUMvector, to a new one.
-	Preconditions:
-		if v != nullptr, the values v [lo..hi] must exist.
-*/
-
-void NUMvector_copyElements (long elementSize, void *v, void *to, long lo, long hi);
-/*
-	copy the vector elements v [lo..hi] to those of a vector 'to'.
-	These vectors need not have been created by NUMvector.
-*/
-
-bool NUMvector_equal (long elementSize, void *v1, void *v2, long lo, long hi);
-/*
-	return true if the vector elements v1 [lo..hi] are equal
-	to the corresponding elements of the vector v2; otherwise, return false.
-	The vectors need not have been created by NUMvector.
-*/
-
-void NUMvector_append (long elementSize, void **v, long lo, long *hi);
-void NUMvector_insert (long elementSize, void **v, long lo, long *hi, long position);
-/*
-	add one element to the vector *v.
-	The new element is initialized to zero.
-	On success, *v points to the new vector, and *hi is incremented by 1.
-	On failure, *v and *hi are not changed.
-*/
-
-/********** Arrays with two indices (NUMarrays.cpp) **********/
-
-void * NUMmatrix (long elementSize, long row1, long row2, long col1, long col2);
-/*
-	Function:
-		create a matrix [row1...row2] [col1...col2] with all values initialized to 0.
-	Preconditions:
-		row2 >= row1;
-		col2 >= col1;
-*/
-
-void NUMmatrix_free (long elementSize, void *m, long row1, long col1);
-/*
-	Function:
-		destroy a matrix m created with NUM...matrix.
-	Preconditions:
-		if m != nullptr: row1 and col1
-		must have the same value as with the creation of the matrix.
-*/
-
-void * NUMmatrix_copy (long elementSize, void *m, long row1, long row2, long col1, long col2);
-/*
-	Function:
-		copy (part of) a matrix m, wich does not have to be created with NUMmatrix, to a new one.
-	Preconditions:
-		if m != nullptr: the values m [rowmin..rowmax] [colmin..colmax] must exist.
-*/
-
-void NUMmatrix_copyElements (long elementSize, void *m, void *to, long row1, long row2, long col1, long col2);
-/*
-	copy the matrix elements m [r1..r2] [c1..c2] to those of a matrix 'to'.
-	These matrices need not have been created by NUMmatrix.
-*/
-
-bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2, long col1, long col2);
-/*
-	return 1 if the matrix elements m1 [r1..r2] [c1..c2] are equal
-	to the corresponding elements of the matrix m2; otherwise, return 0.
-	The matrices need not have been created by NUM...matrix.
-*/
-
-long NUM_getTotalNumberOfArrays ();   // for debugging
-
-/********** Special functions (NUM.cpp) **********/
-
-double NUMlnGamma (double x);
-double NUMbeta (double z, double w);
-double NUMbesselI (long n, double x);   // precondition: n >= 0
-double NUMbessel_i0_f (double x);
-double NUMbessel_i1_f (double x);
-double NUMbesselK (long n, double x);   // preconditions: n >= 0 && x > 0.0
-double NUMbessel_k0_f (double x);
-double NUMbessel_k1_f (double x);
-double NUMbesselK_f (long n, double x);
-double NUMsigmoid (double x);   // correct also for large positive or negative x
-double NUMinvSigmoid (double x);
-double NUMerfcc (double x);
-double NUMgaussP (double z);
-double NUMgaussQ (double z);
-double NUMincompleteGammaP (double a, double x);
-double NUMincompleteGammaQ (double a, double x);
-double NUMchiSquareP (double chiSquare, double degreesOfFreedom);
-double NUMchiSquareQ (double chiSquare, double degreesOfFreedom);
-double NUMcombinations (long n, long k);
-double NUMincompleteBeta (double a, double b, double x);   // incomplete beta function Ix(a,b). Preconditions: a, b > 0; 0 <= x <= 1
-double NUMbinomialP (double p, double k, double n);
-double NUMbinomialQ (double p, double k, double n);
-double NUMinvBinomialP (double p, double k, double n);
-double NUMinvBinomialQ (double p, double k, double n);
-
-/********** Auditory modelling (NUMear.cpp) **********/
-
-double NUMhertzToBark (double hertz);
-double NUMbarkToHertz (double bark);
-double NUMphonToDifferenceLimens (double phon);
-double NUMdifferenceLimensToPhon (double ndli);
-double NUMsoundPressureToPhon (double soundPressure, double bark);
-double NUMhertzToMel (double hertz);
-double NUMmelToHertz (double mel);
-double NUMhertzToSemitones (double hertz);
-double NUMsemitonesToHertz (double semitones);
-double NUMerb (double f);
-double NUMhertzToErb (double hertz);
-double NUMerbToHertz (double erb);
-
-/********** Sorting (NUMsort.cpp) **********/
-
-void NUMsort_d (long n, double ra []);   // heap sort
-void NUMsort_i (long n, int ra []);
-void NUMsort_l (long n, long ra []);
-void NUMsort_str (long n, char32 *a []);
-void NUMsort_p (long n, void *a [], int (*compare) (const void *, const void *));
-
-double NUMquantile (long n, double a [], double factor);
-/*
-	An estimate of the quantile 'factor' (between 0 and 1) of the distribution
-	from which the set 'a [1..n]' is a sorted array of random samples.
-	For instance, if 'factor' is 0.5, this function returns an estimate of
-	the median of the distribution underlying the sorted set a [].
-	If your array has not been sorted, first sort it with NUMsort (n, a).
-*/
-
-/********** Interpolation and optimization (NUM.cpp) **********/
-
-// Special values for interpolationDepth:
-#define NUM_VALUE_INTERPOLATE_NEAREST  0
-#define NUM_VALUE_INTERPOLATE_LINEAR  1
-#define NUM_VALUE_INTERPOLATE_CUBIC  2
-// Higher values than 2 yield a true sinc interpolation. Here are some examples:
-#define NUM_VALUE_INTERPOLATE_SINC70  70
-#define NUM_VALUE_INTERPOLATE_SINC700  700
-double NUM_interpolate_sinc (double y [], long nx, double x, long interpolationDepth);
-
-#define NUM_PEAK_INTERPOLATE_NONE  0
-#define NUM_PEAK_INTERPOLATE_PARABOLIC  1
-#define NUM_PEAK_INTERPOLATE_CUBIC  2
-#define NUM_PEAK_INTERPOLATE_SINC70  3
-#define NUM_PEAK_INTERPOLATE_SINC700  4
-
-double NUMimproveExtremum (double *y, long nx, long ixmid, int interpolation, double *ixmid_real, int isMaximum);
-double NUMimproveMaximum (double *y, long nx, long ixmid, int interpolation, double *ixmid_real);
-double NUMimproveMinimum (double *y, long nx, long ixmid, int interpolation, double *ixmid_real);
-
-void NUM_viterbi (
-	long numberOfFrames, long maxnCandidates,
-	long (*getNumberOfCandidates) (long iframe, void *closure),
-	double (*getLocalCost) (long iframe, long icand, void *closure),
-	double (*getTransitionCost) (long iframe, long icand1, long icand2, void *closure),
-	void (*putResult) (long iframe, long place, void *closure),
-	void *closure);
-
-void NUM_viterbi_multi (
-	long nframe, long ncand, int ntrack,
-	double (*getLocalCost) (long iframe, long icand, int itrack, void *closure),
-	double (*getTransitionCost) (long iframe, long icand1, long icand2, int itrack, void *closure),
-	void (*putResult) (long iframe, long place, int itrack, void *closure),
-	void *closure);
-
-/********** Metrics (NUM.cpp) **********/
-
-int NUMrotationsPointInPolygon
-	(double x0, double y0, long n, double x [], double y []);
-/*
-	Returns the number of times that the closed polygon
-	(x [1], y [1]), (x [2], y [2]),..., (x [n], y [n]), (x [1], y [1]) encloses the point (x0, y0).
-	The result is positive if the polygon encloses the point in the
-	anti-clockwise direction, and negative if the direction is clockwise.
-	The result is 0 if the point is outside the polygon.
-	If the point is on the polygon, the result is unpredictable.
-*/
-
-/********** Random numbers (NUMrandom.cpp) **********/
-
-void NUMrandom_init ();   // automatically called by NUMinit ();
-
-double NUMrandomFraction ();
-double NUMrandomFraction_mt (int threadNumber);
-
-double NUMrandomUniform (double lowest, double highest);
-
-long NUMrandomInteger (long lowest, long highest);
-
-bool NUMrandomBernoulli (double probability);
-double NUMrandomBernoulli_real (double probability);
-
-double NUMrandomGauss (double mean, double standardDeviation);
-double NUMrandomGauss_mt (int threadNumber, double mean, double standardDeviation);
-
-double NUMrandomPoisson (double mean);
-
-uint32 NUMhashString (const char32 *string);
-
-void NUMfbtoa (double formant, double bandwidth, double dt, double *a1, double *a2);
-void NUMfilterSecondOrderSection_a (double x [], long n, double a1, double a2);
-void NUMfilterSecondOrderSection_fb (double x [], long n, double dt, double formant, double bandwidth);
-double NUMftopreemphasis (double f, double dt);
-void NUMpreemphasize_a (double x [], long n, double preemphasis);
-void NUMdeemphasize_a (double x [], long n, double preemphasis);
-void NUMpreemphasize_f (double x [], long n, double dt, double frequency);
-void NUMdeemphasize_f (double x [], long n, double dt, double frequency);
-void NUMautoscale (double x [], long n, double scale);
-
-/* The following ANSI-C power trick generates the declarations of 156 functions. */
-#define FUNCTION(type,storage)  \
-	void NUMvector_writeText_##storage (const type *v, long lo, long hi, MelderFile file, const char32 *name); \
-	void NUMvector_writeBinary_##storage (const type *v, long lo, long hi, FILE *f); \
-	type * NUMvector_readText_##storage (long lo, long hi, MelderReadText text, const char *name); \
-	type * NUMvector_readBinary_##storage (long lo, long hi, FILE *f); \
-	void NUMmatrix_writeText_##storage (type **v, long r1, long r2, long c1, long c2, MelderFile file, const char32 *name); \
-	void NUMmatrix_writeBinary_##storage (type **v, long r1, long r2, long c1, long c2, FILE *f); \
-	type ** NUMmatrix_readText_##storage (long r1, long r2, long c1, long c2, MelderReadText text, const char *name); \
-	type ** NUMmatrix_readBinary_##storage (long r1, long r2, long c1, long c2, FILE *f);
-FUNCTION (signed char, i1)
-FUNCTION (int, i2)
-FUNCTION (long, i4)
-FUNCTION (unsigned char, u1)
-FUNCTION (unsigned int, u2)
-FUNCTION (unsigned long, u4)
-FUNCTION (double, r4)
-FUNCTION (double, r8)
-FUNCTION (fcomplex, c8)
-FUNCTION (dcomplex, c16)
-#undef FUNCTION
-
-/*
-void NUMvector_writeBinary_r8 (const double *v, long lo, long hi, FILE *f);   // etc
-	write the vector elements v [lo..hi] as machine-independent
-	binary data to the stream f.
-	Throw an error message if anything went wrong.
-	The vectors need not have been created by NUM...vector.
-double * NUMvector_readText_r8 (long lo, long hi, MelderReadString *text, const char *name);   // etc
-	create and read a vector as text.
-	Throw an error message if anything went wrong.
-	Every element is supposed to be on the beginning of a line.
-double * NUMvector_readBinary_r8 (long lo, long hi, FILE *f);   // etc
-	create and read a vector as machine-independent binary data from the stream f.
-	Throw an error message if anything went wrong.
-void NUMvector_writeText_r8 (const double *v, long lo, long hi, MelderFile file, const char32 *name);   // etc
-	write the vector elements v [lo..hi] as text to the open file,
-	each element on its own line, preceded by "name [index]: ".
-	Throw an error message if anything went wrong.
-	The vectors need not have been created by NUMvector.
-void NUMmatrix_writeText_r8 (double **m, long r1, long r2, long c1, long c2, MelderFile file, const char32 *name);   // etc
-	write the matrix elements m [r1..r2] [c1..c2] as text to the open file.
-	Throw an error message if anything went wrong.
-	The matrices need not have been created by NUMmatrix.
-void NUMmatrix_writeBinary_r8 (double **m, long r1, long r2, long c1, long c2, FILE *f);   // etc
-	write the matrix elements m [r1..r2] [c1..c2] as machine-independent
-	binary data to the stream f.
-	Throw an error message if anything went wrong.
-	The matrices need not have been created by NUMmatrix.
-double ** NUMmatrix_readText_r8 (long r1, long r2, long c1, long c2, MelderReadString *text, const char *name);   // etc
-	create and read a matrix as text.
-	Throw an error message if anything went wrong.
-double ** NUMmatrix_readBinary_r8 (long r1, long r2, long c1, long c2, FILE *f);   // etc
-	create and read a matrix as machine-independent binary data from the stream f.
-	Throw an error message if anything went wrong.
-*/
-
-typedef struct structNUMlinprog *NUMlinprog;
-void NUMlinprog_delete (NUMlinprog me);
-NUMlinprog NUMlinprog_new (bool maximize);
-void NUMlinprog_addVariable (NUMlinprog me, double lowerBound, double upperBound, double coeff);
-void NUMlinprog_addConstraint (NUMlinprog me, double lowerBound, double upperBound);
-void NUMlinprog_addConstraintCoefficient (NUMlinprog me, double coefficient);
-void NUMlinprog_run (NUMlinprog me);
-double NUMlinprog_getPrimalValue (NUMlinprog me, long ivar);
-
-template <class T>
-T* NUMvector (long from, long to) {
-	T* result = static_cast <T*> (NUMvector (sizeof (T), from, to));
-	return result;
-}
-
-template <class T>
-void NUMvector_free (T* ptr, long from) {
-	NUMvector_free (sizeof (T), ptr, from);
-}
-
-template <class T>
-T* NUMvector_copy (T* ptr, long lo, long hi) {
-	T* result = static_cast <T*> (NUMvector_copy (sizeof (T), ptr, lo, hi));
-	return result;
-}
-
-template <class T>
-bool NUMvector_equal (T* v1, T* v2, long lo, long hi) {
-	return NUMvector_equal (sizeof (T), v1, v2, lo, hi);
-}
-
-template <class T>
-void NUMvector_copyElements (T* vfrom, T* vto, long lo, long hi) {
-	NUMvector_copyElements (sizeof (T), vfrom, vto, lo, hi);
-}
-
-template <class T>
-void NUMvector_append (T** v, long lo, long *hi) {
-	NUMvector_append (sizeof (T), (void**) v, lo, hi);
-}
-
-template <class T>
-void NUMvector_insert (T** v, long lo, long *hi, long position) {
-	NUMvector_insert (sizeof (T), (void**) v, lo, hi, position);
-}
-
-template <class T>
-class autoNUMvector {
-	T* d_ptr;
-	long d_from;
-public:
-	autoNUMvector<T> (long from, long to) : d_from (from) {
-		d_ptr = static_cast <T*> (NUMvector (sizeof (T), from, to));
-	}
-	autoNUMvector (T *ptr, long from) : d_ptr (ptr), d_from (from) {
-	}
-	autoNUMvector () : d_ptr (nullptr), d_from (1) {
-	}
-	~autoNUMvector<T> () {
-		if (d_ptr) NUMvector_free (sizeof (T), d_ptr, d_from);
-	}
-	T& operator[] (long i) {
-		return d_ptr [i];
-	}
-	T* peek () const {
-		return d_ptr;
-	}
-	T* transfer () {
-		T* temp = d_ptr;
-		d_ptr = nullptr;   // make the pointer non-automatic again
-		return temp;
-	}
-	void reset (long from, long to) {
-		if (d_ptr) {
-			NUMvector_free (sizeof (T), d_ptr, d_from);
-			d_ptr = nullptr;
-		}
-		d_from = from;
-		d_ptr = static_cast <T*> (NUMvector (sizeof (T), from, to));
-	}
-};
-
-template <class T>
-T** NUMmatrix (long row1, long row2, long col1, long col2) {
-	T** result = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2));
-	return result;
-}
-
-template <class T>
-void NUMmatrix_free (T** ptr, long row1, long col1) {
-	NUMmatrix_free (sizeof (T), ptr, row1, col1);
-}
-
-template <class T>
-T** NUMmatrix_copy (T** ptr, long row1, long row2, long col1, long col2) {
-	#if 1
-	T** result = static_cast <T**> (NUMmatrix_copy (sizeof (T), ptr, row1, row2, col1, col2));
-	#else
-	T** result = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2));
-	for (long irow = row1; irow <= row2; irow ++)
-		for (long icol = col1; icol <= col2; icol ++)
-			result [irow] [icol] = ptr [irow] [icol];
-	#endif
-	return result;
-}
-
-template <class T>
-bool NUMmatrix_equal (T** m1, T** m2, long row1, long row2, long col1, long col2) {
-	return NUMmatrix_equal (sizeof (T), m1, m2, row1, row2, col1, col2);
-}
-
-template <class T>
-void NUMmatrix_copyElements (T** mfrom, T** mto, long row1, long row2, long col1, long col2) {
-	NUMmatrix_copyElements (sizeof (T), mfrom, mto, row1, row2, col1, col2);
-}
-
-template <class T>
-class autoNUMmatrix {
-	T** d_ptr;
-	long d_row1, d_col1;
-public:
-	autoNUMmatrix (long row1, long row2, long col1, long col2) : d_row1 (row1), d_col1 (col1) {
-		d_ptr = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2));
-	}
-	autoNUMmatrix (T **ptr, long row1, long col1) : d_ptr (ptr), d_row1 (row1), d_col1 (col1) {
-	}
-	autoNUMmatrix () : d_ptr (nullptr), d_row1 (0), d_col1 (0) {
-	}
-	~autoNUMmatrix () {
-		if (d_ptr) NUMmatrix_free (sizeof (T), d_ptr, d_row1, d_col1);
-	}
-	T*& operator[] (long row) {
-		return d_ptr [row];
-	}
-	T** peek () const {
-		return d_ptr;
-	}
-	T** transfer () {
-		T** temp = d_ptr;
-		d_ptr = nullptr;
-		return temp;
-	}
-	void reset (long row1, long row2, long col1, long col2) {
-		if (d_ptr) {
-			NUMmatrix_free (sizeof (T), d_ptr, d_row1, d_col1);
-			d_ptr = nullptr;
-		}
-		d_row1 = row1;
-		d_col1 = col1;
-		d_ptr = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2));
-	}
-};
-
-template <class T>
-class autodatavector {
-	T* d_ptr;
-	long d_from, d_to;
-public:
-	autodatavector<T> (long from, long to) : d_from (from), d_to (to) {
-		d_ptr = static_cast <T*> (NUMvector (sizeof (T), from, to));
-	}
-	autodatavector (T *ptr, long from, long to) : d_ptr (ptr), d_from (from), d_to (to) {
-	}
-	autodatavector () : d_ptr (nullptr), d_from (1), d_to (0) {
-	}
-	~autodatavector<T> () {
-		if (d_ptr) {
-			for (long i = d_from; i <= d_to; i ++)
-				Melder_free (d_ptr [i]);
-			NUMvector_free (sizeof (T), d_ptr, d_from);
-		}
-	}
-	T& operator[] (long i) {
-		return d_ptr [i];
-	}
-	T* peek () const {
-		return d_ptr;
-	}
-	T* transfer () {
-		T* temp = d_ptr;
-		d_ptr = nullptr;   // make the pointer non-automatic again
-		return temp;
-	}
-	void reset (long from, long to) {
-		if (d_ptr) {
-			for (long i = d_from; i <= d_to; i ++)
-				Melder_free (d_ptr [i]);
-			NUMvector_free (sizeof (T), d_ptr, d_from);
-			d_ptr = nullptr;
-		}
-		d_from = from;   // this assignment is safe, because d_ptr is null
-		d_to = to;
-		d_ptr = static_cast <T*> (NUMvector (sizeof (T), from, to));
-	}
-};
-
-typedef autodatavector <char32 *> autostring32vector;
-typedef autodatavector <char *> autostring8vector;
-
-/* End of file NUM.h */
-#endif
diff --git a/num/NUMarrays.cpp b/num/NUMarrays.cpp
index 0a226c2..cdf6f07 100644
--- a/num/NUMarrays.cpp
+++ b/num/NUMarrays.cpp
@@ -1,6 +1,6 @@
 /* NUMarrays.cpp
  *
- * Copyright (C) 1992-2012 Paul Boersma
+ * Copyright (C) 1992-2012,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,22 +16,23 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "NUM.h"
 #include "melder.h"
 
-static long theTotalNumberOfArrays;
+static integer theTotalNumberOfArrays;
 
-long NUM_getTotalNumberOfArrays () { return theTotalNumberOfArrays; }
+integer NUM_getTotalNumberOfArrays () { return theTotalNumberOfArrays; }
 
 /*** Generic memory routines for vectors. ***/
 
-void * NUMvector (long elementSize, long lo, long hi) {
+void * NUMvector (integer elementSize, integer lo, integer hi, bool zero) {
 	try {
 		if (hi < lo) return nullptr;   // not an error
 		char *result;
 		Melder_assert (sizeof (char) == 1);   // some say that this is true by definition
 		for (;;) {   // not very infinite: 99.999 % of the time once, 0.001 % twice
-			result = reinterpret_cast<char*> (_Melder_calloc (hi - lo + 1, elementSize));
+			result = zero ?
+				reinterpret_cast<char*> (_Melder_calloc (hi - lo + 1, elementSize)) :
+				reinterpret_cast<char*> (_Melder_malloc ((hi - lo + 1) * elementSize));
 			if (result -= lo * elementSize) break;   // this will normally succeed at the first try
 			(void) Melder_realloc_f (result + lo * elementSize, 1);   // make "sure" that the second try will succeed (not *very* sure, because realloc might move memory even if it shrinks)
 		}
@@ -42,18 +43,18 @@ void * NUMvector (long elementSize, long lo, long hi) {
 	}
 }
 
-void NUMvector_free (long elementSize, void *v, long lo) {
+void NUMvector_free (integer elementSize, void *v, integer lo) noexcept {
 	if (! v) return;   // no error
 	char *dum = (char *) v + lo * elementSize;
 	Melder_free (dum);
 	theTotalNumberOfArrays -= 1;
 }
 
-void * NUMvector_copy (long elementSize, void *v, long lo, long hi) {
+void * NUMvector_copy (integer elementSize, void *v, integer lo, integer hi) {
 	try {
 		if (! v) return nullptr;
-		char *result = reinterpret_cast <char *> (NUMvector (elementSize, lo, hi));
-		long offset = lo * elementSize;
+		char *result = reinterpret_cast <char *> (NUMvector (elementSize, lo, hi, false));
+		integer offset = lo * elementSize;
 		memcpy (result + offset, (char *) v + offset, (hi - lo + 1) * elementSize);
 		return result;
 	} catch (MelderError) {
@@ -61,26 +62,26 @@ void * NUMvector_copy (long elementSize, void *v, long lo, long hi) {
 	}
 }
 
-void NUMvector_copyElements (long elementSize, void *v, void *to, long lo, long hi) {
-	long offset = lo * elementSize;
+void NUMvector_copyElements (integer elementSize, void *v, void *to, integer lo, integer hi) {
+	integer offset = lo * elementSize;
 	Melder_assert (!! v && !! to);
 	if (hi >= lo) memcpy ((char *) to + offset, (char *) v + offset, (hi - lo + 1) * elementSize);
 }
 
-bool NUMvector_equal (long elementSize, void *v1, void *v2, long lo, long hi) {
-	long offset = lo * elementSize;
+bool NUMvector_equal (integer elementSize, void *v1, void *v2, integer lo, integer hi) {
+	integer offset = lo * elementSize;
 	Melder_assert (v1 && v2);
 	return ! memcmp ((char *) v1 + offset, (char *) v2 + offset, (hi - lo + 1) * elementSize);
 }
 
-void NUMvector_append (long elementSize, void **v, long lo, long *hi) {
+void NUMvector_append (integer elementSize, void **v, integer lo, integer *hi) {
 	try {
 		char *result;
 		if (! *v) {
-			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, lo));
+			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, lo, true));
 			*hi = lo;
 		} else {
-			long offset = lo * elementSize;
+			integer offset = lo * elementSize;
 			for (;;) {   // not very infinite: 99.999 % of the time once, 0.001 % twice
 				result = reinterpret_cast <char *> (Melder_realloc ((char *) *v + offset, (*hi - lo + 2) * elementSize));
 				if ((result -= offset) != nullptr) break;   // this will normally succeed at the first try
@@ -95,17 +96,18 @@ void NUMvector_append (long elementSize, void **v, long lo, long *hi) {
 	}
 }
 
-void NUMvector_insert (long elementSize, void **v, long lo, long *hi, long position) {
+void NUMvector_insert (integer elementSize, void **v, integer lo, integer *hi, integer position) {
 	try {
 		char *result;
 		if (! *v) {
-			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, lo));
+			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, lo, true));
 			*hi = lo;
 			Melder_assert (position == lo);
 		} else {
-			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, *hi + 1));
+			result = reinterpret_cast <char *> (NUMvector (elementSize, lo, *hi + 1, false));
 			Melder_assert (position >= lo && position <= *hi + 1);
 			NUMvector_copyElements (elementSize, *v, result, lo, position - 1);
+			memset (result + position * elementSize, 0, elementSize);
 			NUMvector_copyElements (elementSize, *v, result + elementSize, position, *hi);
 			NUMvector_free (elementSize, *v, lo);
 			(*hi) ++;
@@ -118,7 +120,7 @@ void NUMvector_insert (long elementSize, void **v, long lo, long *hi, long posit
 
 /*** Generic memory routines for matrices. ***/
 
-void * NUMmatrix (long elementSize, long row1, long row2, long col1, long col2) {
+void * NUMmatrix (integer elementSize, integer row1, integer row2, integer col1, integer col2, bool zero) {
 	try {
 		int64 numberOfRows = row2 - row1 + 1;
 		int64 numberOfColumns = col2 - col1 + 1;
@@ -130,7 +132,7 @@ void * NUMmatrix (long elementSize, long row1, long row2, long col1, long col2)
 		char **result;
 		Melder_assert (sizeof (char) == 1);   // true by definition
 		for (;;) {
-			result = reinterpret_cast <char **> (_Melder_malloc_f (numberOfRows * sizeof (char *)));   // assume that all pointers have the same size
+			result = reinterpret_cast <char **> (_Melder_malloc_f (numberOfRows * (int64) sizeof (char *)));   // assume that all pointers have the same size
 			result -= row1;
 			if (result) break;   // this will normally succeed at the first try
 			(void) Melder_realloc_f (result + row1, 1);   // make "sure" that the second try will succeed
@@ -141,7 +143,9 @@ void * NUMmatrix (long elementSize, long row1, long row2, long col1, long col2)
 		 */
 		for (;;) {
 			try {
-				result [row1] = reinterpret_cast <char *> (_Melder_calloc (numberOfCells, elementSize));
+				result [row1] = zero ?
+					reinterpret_cast <char *> (_Melder_calloc (numberOfCells, elementSize)) :
+					reinterpret_cast <char *> (_Melder_malloc (numberOfCells * elementSize));
 			} catch (MelderError) {
 				result += row1;
 				Melder_free (result);   // free the row pointers
@@ -151,7 +155,7 @@ void * NUMmatrix (long elementSize, long row1, long row2, long col1, long col2)
 			(void) Melder_realloc_f (result [row1] + col1 * elementSize, 1);   // make "sure" that the second try will succeed
 		}
 		int64 columnSize = numberOfColumns * elementSize;
-		for (long irow = row1 + 1; irow <= row2; irow ++) result [irow] = result [irow - 1] + columnSize;
+		for (integer irow = row1 + 1; irow <= row2; irow ++) result [irow] = result [irow - 1] + columnSize;
 		theTotalNumberOfArrays += 1;
 		return result;
 	} catch (MelderError) {
@@ -159,7 +163,7 @@ void * NUMmatrix (long elementSize, long row1, long row2, long col1, long col2)
 	}
 }
 
-void NUMmatrix_free (long elementSize, void *m, long row1, long col1) {
+void NUMmatrix_free (integer elementSize, void *m, integer row1, integer col1) noexcept {
 	if (! m) return;
 	char *dummy1 = ((char **) m) [row1] + col1 * elementSize;
 	Melder_free (dummy1);
@@ -168,13 +172,13 @@ void NUMmatrix_free (long elementSize, void *m, long row1, long col1) {
 	theTotalNumberOfArrays -= 1;
 }
 
-void * NUMmatrix_copy (long elementSize, void * m, long row1, long row2, long col1, long col2) {
+void * NUMmatrix_copy (integer elementSize, void * m, integer row1, integer row2, integer col1, integer col2) {
 	try {
 		if (! m) return nullptr;
-		char **result = reinterpret_cast <char **> (NUMmatrix (elementSize, row1, row2, col1, col2));
+		char **result = reinterpret_cast <char **> (NUMmatrix (elementSize, row1, row2, col1, col2, false));
 		if (! result) return nullptr;
-		long columnOffset = col1 * elementSize;
-		long dataSize = (row2 - row1 + 1) * (col2 - col1 + 1) * elementSize;
+		integer columnOffset = col1 * elementSize;
+		integer dataSize = (row2 - row1 + 1) * (col2 - col1 + 1) * elementSize;
 		memcpy (result [row1] + columnOffset, ((char **) m) [row1] + columnOffset, dataSize);
 		return result;
 	} catch (MelderError) {
@@ -182,40 +186,40 @@ void * NUMmatrix_copy (long elementSize, void * m, long row1, long row2, long co
 	}
 }
 
-void NUMmatrix_copyElements (long elementSize, void *m, void *to, long row1, long row2, long col1, long col2) {
+void NUMmatrix_copyElements (integer elementSize, void *m, void *to, integer row1, integer row2, integer col1, integer col2) {
 	Melder_assert (m && to);
-	long columnOffset = col1 * elementSize;
-	long dataSize = (row2 - row1 + 1) * (col2 - col1 + 1) * elementSize;
+	integer columnOffset = col1 * elementSize;
+	integer dataSize = (row2 - row1 + 1) * (col2 - col1 + 1) * elementSize;
 	memcpy (((char **) to) [row1] + columnOffset, ((char **) m) [row1] + columnOffset, dataSize);
 }
 
-bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2, long col1, long col2) {
+bool NUMmatrix_equal (integer elementSize, void *m1, void *m2, integer row1, integer row2, integer col1, integer col2) {
 	Melder_assert (m1 && m2);
-	long columnOffset = col1 * elementSize;
-	long dataSize = (row2 - row1 + 1) * (col2 - col1 + 1) * elementSize;
+	integer columnOffset = col1 * elementSize;
+	integer dataSize = (row2 - row1 + 1) * (col2 - col1 + 1) * elementSize;
 	return ! memcmp (((char **) m1) [row1] + columnOffset, ((char **) m2) [row1] + columnOffset, dataSize);
 }
 
 /*** Typed I/O routines for vectors and matrices. ***/
 
 #define FUNCTION(type,storage)  \
-	void NUMvector_writeText_##storage (const type *v, long lo, long hi, MelderFile file, const char32 *name) { \
+	void NUMvector_writeText_##storage (const type *v, integer lo, integer hi, MelderFile file, const char32 *name) { \
 		texputintro (file, name, U" []: ", hi >= lo ? nullptr : U"(empty)", 0,0,0); \
-		for (long i = lo; i <= hi; i ++) \
+		for (integer i = lo; i <= hi; i ++) \
 			texput##storage (file, v [i], name, U" [", Melder_integer (i), U"]", 0,0); \
 		texexdent (file); \
 		if (feof (file -> filePointer) || ferror (file -> filePointer)) Melder_throw (U"Write error."); \
 	} \
-	void NUMvector_writeBinary_##storage (const type *v, long lo, long hi, FILE *f) { \
-		for (long i = lo; i <= hi; i ++) \
+	void NUMvector_writeBinary_##storage (const type *v, integer lo, integer hi, FILE *f) { \
+		for (integer i = lo; i <= hi; i ++) \
 			binput##storage (v [i], f); \
 		if (feof (f) || ferror (f)) Melder_throw (U"Write error."); \
 	} \
-	type * NUMvector_readText_##storage (long lo, long hi, MelderReadText text, const char *name) { \
+	type * NUMvector_readText_##storage (integer lo, integer hi, MelderReadText text, const char *name) { \
 		type *result = nullptr; \
 		try { \
 			result = NUMvector <type> (lo, hi); \
-			for (long i = lo; i <= hi; i ++) { \
+			for (integer i = lo; i <= hi; i ++) { \
 				try { \
 					result [i] = texget##storage (text); \
 				} catch (MelderError) { \
@@ -228,11 +232,11 @@ bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2
 			throw; \
 		} \
 	} \
-	type * NUMvector_readBinary_##storage (long lo, long hi, FILE *f) { \
+	type * NUMvector_readBinary_##storage (integer lo, integer hi, FILE *f) { \
 		type *result = nullptr; \
 		try { \
 			result = NUMvector <type> (lo, hi); \
-			for (long i = lo; i <= hi; i ++) { \
+			for (integer i = lo; i <= hi; i ++) { \
 				result [i] = binget##storage (f); \
 			} \
 			return result; \
@@ -241,12 +245,12 @@ bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2
 			throw; \
 		} \
 	} \
-	void NUMmatrix_writeText_##storage (type **m, long row1, long row2, long col1, long col2, MelderFile file, const char32 *name) { \
+	void NUMmatrix_writeText_##storage (type **m, integer row1, integer row2, integer col1, integer col2, MelderFile file, const char32 *name) { \
 		texputintro (file, name, U" [] []: ", row2 >= row1 ? nullptr : U"(empty)", 0,0,0); \
 		if (row2 >= row1) { \
-			for (long irow = row1; irow <= row2; irow ++) { \
+			for (integer irow = row1; irow <= row2; irow ++) { \
 				texputintro (file, name, U" [", Melder_integer (irow), U"]:", 0,0); \
-				for (long icol = col1; icol <= col2; icol ++) { \
+				for (integer icol = col1; icol <= col2; icol ++) { \
 					texput##storage (file, m [irow] [icol], name, U" [", Melder_integer (irow), U"] [", Melder_integer (icol), U"]"); \
 				} \
 				texexdent (file); \
@@ -255,20 +259,20 @@ bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2
 		texexdent (file); \
 		if (feof (file -> filePointer) || ferror (file -> filePointer)) Melder_throw (U"Write error."); \
 	} \
-	void NUMmatrix_writeBinary_##storage (type **m, long row1, long row2, long col1, long col2, FILE *f) { \
+	void NUMmatrix_writeBinary_##storage (type **m, integer row1, integer row2, integer col1, integer col2, FILE *f) { \
 		if (row2 >= row1) { \
-			for (long irow = row1; irow <= row2; irow ++) { \
-				for (long icol = col1; icol <= col2; icol ++) \
+			for (integer irow = row1; irow <= row2; irow ++) { \
+				for (integer icol = col1; icol <= col2; icol ++) \
 					binput##storage (m [irow] [icol], f); \
 			} \
 		} \
 		if (feof (f) || ferror (f)) Melder_throw (U"Write error."); \
 	} \
-	type ** NUMmatrix_readText_##storage (long row1, long row2, long col1, long col2, MelderReadText text, const char *name) { \
+	type ** NUMmatrix_readText_##storage (integer row1, integer row2, integer col1, integer col2, MelderReadText text, const char *name) { \
 		type **result = nullptr; \
 		try { \
 			result = NUMmatrix <type> (row1, row2, col1, col2); \
-			for (long irow = row1; irow <= row2; irow ++) for (long icol = col1; icol <= col2; icol ++) { \
+			for (integer irow = row1; irow <= row2; irow ++) for (integer icol = col1; icol <= col2; icol ++) { \
 				try { \
 					result [irow] [icol] = texget##storage (text); \
 				} catch (MelderError) { \
@@ -281,11 +285,11 @@ bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2
 			throw; \
 		} \
 	} \
-	type ** NUMmatrix_readBinary_##storage (long row1, long row2, long col1, long col2, FILE *f) { \
+	type ** NUMmatrix_readBinary_##storage (integer row1, integer row2, integer col1, integer col2, FILE *f) { \
 		type **result = nullptr; \
 		try { \
 			result = NUMmatrix <type> (row1, row2, col1, col2); \
-			for (long irow = row1; irow <= row2; irow ++) for (long icol = col1; icol <= col2; icol ++) \
+			for (integer irow = row1; irow <= row2; irow ++) for (integer icol = col1; icol <= col2; icol ++) \
 				result [irow] [icol] = binget##storage (f); \
 			return result; \
 		} catch (MelderError) { \
@@ -294,16 +298,16 @@ bool NUMmatrix_equal (long elementSize, void *m1, void *m2, long row1, long row2
 		} \
 	}
 
-FUNCTION (signed char, i1)
-FUNCTION (int, i2)
-FUNCTION (long, i4)
-FUNCTION (unsigned char, u1)
-FUNCTION (unsigned int, u2)
-FUNCTION (unsigned long, u4)
-FUNCTION (double, r4)
-FUNCTION (double, r8)
-FUNCTION (fcomplex, c8)
-FUNCTION (dcomplex, c16)
+FUNCTION (signed char, i8)
+FUNCTION (int, i16)
+FUNCTION (long, i32)
+FUNCTION (unsigned char, u8)
+FUNCTION (unsigned int, u16)
+FUNCTION (unsigned long, u32)
+FUNCTION (double, r32)
+FUNCTION (double, r64)
+FUNCTION (fcomplex, c64)
+FUNCTION (dcomplex, c128)
 #undef FUNCTION
 
 /* End of file NUMarrays.cpp */
diff --git a/num/NUMear.cpp b/num/NUMear.cpp
index 3f83605..28978e4 100644
--- a/num/NUMear.cpp
+++ b/num/NUMear.cpp
@@ -1,6 +1,6 @@
 /* NUMear.cpp
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,55 +16,55 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "NUM.h"
+#include "melder.h"
 
 double NUMhertzToBark (double hertz) {
-	double r = hertz / 650;
-	return hertz < 0 ? NUMundefined : 7.0 * log (r + sqrt (1 + r * r));
+	double r = hertz / 650.0;
+	return hertz < 0.0 ? undefined : 7.0 * log (r + sqrt (1.0 + r * r));
 }
 double NUMbarkToHertz (double bark) {
-	return bark < 0 ? NUMundefined : 650.0 * sinh (bark / 7.0);
+	return bark < 0.0 ? undefined : 650.0 * sinh (bark / 7.0);
 }
 
 double NUMphonToDifferenceLimens (double phon) {
-	return phon < 0 ? NUMundefined : 30 * (pow (61.0 / 60, phon) - 1);
+	return phon < 0.0 ? undefined : 30.0 * (pow (61.0 / 60.0, phon) - 1.0);
 }
 double NUMdifferenceLimensToPhon (double ndli) {
-	return ndli < 0 ? NUMundefined : log (1 + ndli / 30) / log (61.0 / 60);
+	return ndli < 0.0 ? undefined : log (1.0 + ndli / 30.0) / log (61.0 / 60.0);
 }
 
 double NUMsoundPressureToPhon (double soundPressure, double bark) {
-	double result = 0, dum;
-	if (soundPressure <= 0 || bark < 0) return NUMundefined;
+	double result = 0.0, dum;
+	if (soundPressure <= 0.0 || bark < 0.0) return undefined;
 
 	/*  dB = 20 * log10 (soundPressure / threshold)  */
-	if (soundPressure > 0)
-		result = 20 * log10 (soundPressure / 2.0e-5);   /* First approximation: phon = dB */
+	if (soundPressure > 0.0)
+		result = 20.0 * log10 (soundPressure / 2.0e-5);   /* First approximation: phon = dB */
 
 	/*  Phones from dB  */
-	if (result < 90 && bark < 8.0) {
-		dum = (90 - result) * (8.0 - bark);
-		result -= dum * dum / 2500;
+	if (result < 90.0 && bark < 8.0) {
+		dum = (90.0 - result) * (8.0 - bark);
+		result -= dum * dum / 2500.0;
 	}
-	dum = bark / 3.6 - 5;
-	result += 5 * exp (- dum * dum);
-	if (bark > 20.0) { dum = bark - 20; result -= 0.5 * dum * dum; }
-	if (result < 0) result = 0;
+	dum = bark / 3.6 - 5.0;
+	result += 5.0 * exp (- dum * dum);
+	if (bark > 20.0) { dum = bark - 20.0; result -= 0.5 * dum * dum; }
+	if (result < 0.0) result = 0.0;
 	return result;
 }
 
 double NUMhertzToMel (double hertz) {
-	return hertz < 0 ? NUMundefined : 550.0 * log (1.0 + hertz / 550.0);
+	return hertz < 0.0 ? undefined : 550.0 * log (1.0 + hertz / 550.0);
 }
 double NUMmelToHertz (double mel) {
-	return mel < 0 ? NUMundefined : 550.0 * (exp (mel / 550.0) - 1);
+	return mel < 0.0 ? undefined : 550.0 * (exp (mel / 550.0) - 1.0);
 }
 
 double NUMhertzToSemitones (double hertz) {
-	return hertz <= 0.0 ? NUMundefined : 12.0 * log (hertz / 100.0) / NUMln2;
+	return hertz <= 0.0 ? undefined : 12.0 * log (hertz / 100.0) / NUMln2;
 }
 double NUMsemitonesToHertz (double semitones) {
-	return semitones == NUMundefined ? NUMundefined : 100.0 * exp (semitones * (NUMln2 / 12.0));
+	return isundef (semitones) ? undefined : 100.0 * exp (semitones * (NUMln2 / 12.0));
 }
 
 /* Moore & Glasberg 1983 JASA 74: 750 */
@@ -73,11 +73,11 @@ double NUMerb (double f) {
 	return 6.23e-6 * f * f + 0.09339 * f + 28.52;
 }
 double NUMhertzToErb (double hertz) {
-	return hertz < 0 ? NUMundefined : 11.17 * log ((hertz + 312.0) / (hertz + 14680.0)) + 43.0;
+	return hertz < 0.0 ? undefined : 11.17 * log ((hertz + 312.0) / (hertz + 14680.0)) + 43.0;
 }
 double NUMerbToHertz (double erb) {
 	double dum = exp ((erb - 43.0) / 11.17);
-	return erb < 0 ? NUMundefined : (14680.0 * dum - 312.0) / (1.0 - dum);
+	return erb < 0.0 ? undefined : (14680.0 * dum - 312.0) / (1.0 - dum);
 }
 
 /* End of file NUMear.cpp */
diff --git a/num/NUMlinprog.cpp b/num/NUMlinprog.cpp
index 651e153..d65324e 100644
--- a/num/NUMlinprog.cpp
+++ b/num/NUMlinprog.cpp
@@ -1,6 +1,6 @@
 /* NUMlinprog.cpp
  *
- * Copyright (C) 2008-2011,2012,2015 Paul Boersma
+ * Copyright (C) 2008-2011,2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,11 +16,9 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "NUM.h"
+#include "melder.h"
 #include "../external/glpk/glpk.h"
 
-#define my  me ->
-
 struct structNUMlinprog {
 	glp_prob *linearProgram;
 	long numberOfConstraints, ivar, numberOfVariables;
@@ -53,8 +51,8 @@ NUMlinprog NUMlinprog_new (bool maximize) {
 void NUMlinprog_addVariable (NUMlinprog me, double lowerBound, double upperBound, double coeff) {
 	glp_add_cols (my linearProgram, 1);
 	glp_set_col_bnds (my linearProgram, ++ my numberOfVariables,
-		lowerBound == NUMundefined ? ( upperBound == NUMundefined ? GLP_FR : GLP_UP ) :
-		upperBound == NUMundefined ? GLP_LO :
+		isundef (lowerBound) ? ( isundef (upperBound) ? GLP_FR : GLP_UP ) :
+		isundef (upperBound) ? GLP_LO :
 		lowerBound == upperBound ? GLP_FX : GLP_DB, lowerBound, upperBound);
 	glp_set_obj_coef (my linearProgram, my ivar, coeff);
 }
@@ -75,8 +73,8 @@ void NUMlinprog_addConstraint (NUMlinprog me, double lowerBound, double upperBou
 		}
 		glp_add_rows (my linearProgram, 1);   // TODO: check
 		glp_set_row_bnds (my linearProgram, ++ my numberOfConstraints,
-			lowerBound == NUMundefined ? ( upperBound == NUMundefined ? GLP_FR : GLP_UP ) :
-			upperBound == NUMundefined ? GLP_LO :
+			isundef (lowerBound) ? ( isundef (upperBound) ? GLP_FR : GLP_UP ) :
+			isundef (upperBound) ? GLP_LO :
 			lowerBound == upperBound ? GLP_FX : GLP_DB, lowerBound, upperBound);
 		my ivar = 0;
 	} catch (MelderError) {
diff --git a/num/NUMrandom.cpp b/num/NUMrandom.cpp
index c831e86..036c924 100644
--- a/num/NUMrandom.cpp
+++ b/num/NUMrandom.cpp
@@ -1,6 +1,6 @@
 /* NUMrandom.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -76,8 +76,6 @@
 #endif
 #include <unistd.h>
 #include "melder.h"
-#include "NUM.h"
-#define my me ->
 
 #define NN  312
 #define MM  156
diff --git a/num/NUMsort.cpp b/num/NUMsort.cpp
index 6b77041..205c0da 100644
--- a/num/NUMsort.cpp
+++ b/num/NUMsort.cpp
@@ -1,6 +1,6 @@
 /* NUMsort.c
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,8 +23,7 @@
  * pb 2011/03/29 C++
  */
 
-#include "NUM.h"
-#include <string.h>
+#include "melder.h"
 
 /*
 	NUMsort uses heapsort.
diff --git a/stat/Distributions.cpp b/stat/Distributions.cpp
index cadec9d..29aa645 100644
--- a/stat/Distributions.cpp
+++ b/stat/Distributions.cpp
@@ -1,6 +1,6 @@
 /* Distributions.cpp
  *
- * Copyright (C) 1997-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1997-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,18 +47,19 @@ void Distributions_peek (Distributions me, long column, char32 **string, long *n
 	Distributions_checkSpecifiedColumnNumberWithinRange (me, column);
 	if (my numberOfRows < 1)
 		Melder_throw (me, U": I have no candidates.");
-	double total = 0.0;
+	real80 total = 0.0;
 	for (long irow = 1; irow <= my numberOfRows; irow ++) {
-		total += my data [irow] [column];
+		total += (real80) my data [irow] [column];
 	}
 	if (total <= 0.0)
 		Melder_throw (me, U": the total weight of column ", column, U" is not positive.");
 	long irow;
 	do {
-		double rand = NUMrandomUniform (0, total), sum = 0.0;
+		double rand = NUMrandomUniform (0, (real) total);
+		long double sum = 0.0;
 		for (irow = 1; irow <= my numberOfRows; irow ++) {
-			sum += my data [irow] [column];
-			if (rand <= sum) break;
+			sum += (real80) my data [irow] [column];
+			if ((real80) rand <= sum) break;
 		}
 	} while (irow > my numberOfRows);   // guard against rounding errors
 	if (! my rowLabels [irow])
@@ -71,26 +72,26 @@ void Distributions_peek (Distributions me, long column, char32 **string, long *n
 
 double Distributions_getProbability (Distributions me, const char32 *string, long column) {
 	long row, rowOfString = 0;
-	double total = 0.0;
-	if (column < 1 || column > my numberOfColumns) return NUMundefined;
+	real80 total = 0.0;
+	if (column < 1 || column > my numberOfColumns) return undefined;
 	for (row = 1; row <= my numberOfRows; row ++) {
-		total += my data [row] [column];
+		total += (real80) my data [row] [column];
 		if (my rowLabels [row] && str32equ (my rowLabels [row], string))
 			rowOfString = row;
 	}
-	if (total <= 0.0) return NUMundefined;
+	if (total <= 0.0) return undefined;
 	if (rowOfString == 0) return 0.0;
-	return my data [rowOfString] [column] / total;
+	return my data [rowOfString] [column] / (real) total;
 }
 
 double Distributionses_getMeanAbsoluteDifference (Distributions me, Distributions thee, long column) {
 	if (column < 1 || column > my numberOfColumns || column > thy numberOfColumns ||
-	    my numberOfRows != thy numberOfRows) return NUMundefined;
-	double total = 0.0;
+	    my numberOfRows != thy numberOfRows) return undefined;
+	real80 total = 0.0;
 	for (long irow = 1; irow <= my numberOfRows; irow ++) {
-		total += fabs (my data [irow] [column] - thy data [irow] [column]);
+		total += (real80) fabs (my data [irow] [column] - thy data [irow] [column]);
 	}
-	return total / my numberOfRows;
+	return (real) total / my numberOfRows;
 }
 
 static void unicize (Distributions me) {
diff --git a/stat/LogisticRegression.cpp b/stat/LogisticRegression.cpp
index 4793095..681ead4 100644
--- a/stat/LogisticRegression.cpp
+++ b/stat/LogisticRegression.cpp
@@ -1,6 +1,6 @@
 /* LogisticRegression.cpp
  *
- * Copyright (C) 2005-2012,2015,2016 Paul Boersma
+ * Copyright (C) 2005-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -46,18 +46,18 @@ void structLogisticRegression :: v_info () {
 	MelderInfo_writeLine (U"Dependent 2: ", our dependent2);
 	MelderInfo_writeLine (U"Interpretation:");
 	MelderInfo_write (U"   ln (P(", dependent2, U")/P(", dependent1, U")) " UNITEXT_ALMOST_EQUAL_TO U" ", Melder_fixed (intercept, 6));
-	for (long ivar = 1; ivar <= parameters.size; ivar ++) {
+	for (integer ivar = 1; ivar <= parameters.size; ivar ++) {
 		RegressionParameter parm = parameters.at [ivar];
 		MelderInfo_write (parm -> value < 0.0 ? U" - " : U" + ", Melder_fixed (fabs (parm -> value), 6), U" * ", parm -> label);
 	}
 	MelderInfo_writeLine (U"");
 	MelderInfo_writeLine (U"Log odds ratios:");
-	for (long ivar = 1; ivar <= parameters.size; ivar ++) {
+	for (integer ivar = 1; ivar <= parameters.size; ivar ++) {
 		RegressionParameter parm = parameters.at [ivar];
 		MelderInfo_writeLine (U"   Log odds ratio of factor ", parm -> label, U": ", Melder_fixed ((parm -> maximum - parm -> minimum) * parm -> value, 6));
 	}
 	MelderInfo_writeLine (U"Odds ratios:");
-	for (long ivar = 1; ivar <= parameters.size; ivar ++) {
+	for (integer ivar = 1; ivar <= parameters.size; ivar ++) {
 		RegressionParameter parm = parameters.at [ivar];
 		MelderInfo_writeLine (U"   Odds ratio of factor ", parm -> label, U": ", exp ((parm -> maximum - parm -> minimum) * parm -> value));
 	}
@@ -75,9 +75,9 @@ autoLogisticRegression LogisticRegression_create (const char32 *dependent1, cons
 	}
 }
 
-static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *factors, long numberOfFactors, long dependent1, long dependent2) {
-	long numberOfParameters = numberOfFactors + 1;
-	long numberOfCells = my rows.size, numberOfY0 = 0, numberOfY1 = 0, numberOfData = 0;
+static autoLogisticRegression _Table_to_LogisticRegression (Table me, integer *factors, integer numberOfFactors, integer dependent1, integer dependent2) {
+	integer numberOfParameters = numberOfFactors + 1;
+	integer numberOfCells = my rows.size, numberOfY0 = 0, numberOfY1 = 0, numberOfData = 0;
 	double logLikelihood = 1e307, previousLogLikelihood = 1e308;
 	if (numberOfParameters < 1)   // includes intercept
 		Melder_throw (U"Not enough columns (has to be more than 1).");
@@ -91,19 +91,19 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 	autoNUMvector <double> stdevX (1, numberOfFactors);
 	autoNUMmatrix <double> smallMatrix (0, numberOfFactors, 0, numberOfParameters);
 	autoLogisticRegression thee = LogisticRegression_create (my columnHeaders [dependent1]. label, my columnHeaders [dependent2]. label);
-	for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+	for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 		double minimum = Table_getMinimum (me, factors [ivar]);
 		double maximum = Table_getMaximum (me, factors [ivar]);
 		Regression_addParameter (thee.get(), my columnHeaders [factors [ivar]]. label, minimum, maximum, 0.0);
 	}
-	for (long icell = 1; icell <= numberOfCells; icell ++) {
+	for (integer icell = 1; icell <= numberOfCells; icell ++) {
 		y0 [icell] = Table_getNumericValue_Assert (me, icell, dependent1);
 		y1 [icell] = Table_getNumericValue_Assert (me, icell, dependent2);
 		numberOfY0 += y0 [icell];
 		numberOfY1 += y1 [icell];
 		numberOfData += y0 [icell] + y1 [icell];
 		x [icell] [0] = 1.0;   // intercept
-		for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+		for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 			x [icell] [ivar] = Table_getNumericValue_Assert (me, icell, factors [ivar]);
 			meanX [ivar] += x [icell] [ivar] * (y0 [icell] + y1 [icell]);
 		}
@@ -117,20 +117,20 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 	/*
 	 * Normalize the data.
 	 */
-	for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+	for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 		meanX [ivar] /= numberOfData;
-		for (long icell = 1; icell <= numberOfCells; icell ++) {
+		for (integer icell = 1; icell <= numberOfCells; icell ++) {
 			x [icell] [ivar] -= meanX [ivar];
 		}
 	}
-	for (long icell = 1; icell <= numberOfCells; icell ++) {
-		for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+	for (integer icell = 1; icell <= numberOfCells; icell ++) {
+		for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 			stdevX [ivar] += x [icell] [ivar] * x [icell] [ivar] * (y0 [icell] + y1 [icell]);
 		}
 	}
-	for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+	for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 		stdevX [ivar] = sqrt (stdevX [ivar] / numberOfData);
-		for (long icell = 1; icell <= numberOfCells; icell ++) {
+		for (integer icell = 1; icell <= numberOfCells; icell ++) {
 			x [icell] [ivar] /= stdevX [ivar];
 		}
 	}
@@ -138,15 +138,15 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 	 * Initial state of iteration: the null model.
 	 */
 	thy intercept = log ((double) numberOfY1 / (double) numberOfY0);   // initial state of intercept: best guess for average log odds
-	for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+	for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 		RegressionParameter parm = thy parameters.at [ivar];
 		parm -> value = 0.0;   // initial state of dependence: none
 	}
-	long iteration = 1;
+	integer iteration = 1;
 	for (; iteration <= 100; iteration ++) {
 		previousLogLikelihood = logLikelihood;
-		for (long ivar = 0; ivar <= numberOfFactors; ivar ++) {
-			for (long jvar = ivar; jvar <= numberOfParameters; jvar ++) {
+		for (integer ivar = 0; ivar <= numberOfFactors; ivar ++) {
+			for (integer jvar = ivar; jvar <= numberOfParameters; jvar ++) {
 				smallMatrix [ivar] [jvar] = 0.0;
 			}
 		}
@@ -154,9 +154,9 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 		 * Compute the current log likelihood.
 		 */
 		logLikelihood = 0.0;
-		for (long icell = 1; icell <= numberOfCells; icell ++) {
+		for (integer icell = 1; icell <= numberOfCells; icell ++) {
 			double fittedLogit = thy intercept, fittedP, fittedQ, fittedLogP, fittedLogQ, fittedPQ, fittedVariance;
-			for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+			for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 				RegressionParameter parm = thy parameters.at [ivar];
 				fittedLogit += parm -> value * x [icell] [ivar];
 			}
@@ -202,12 +202,12 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 			 * so that dLL/da = Sum(k) (y1k d ln pk / da + y0k ln qk / da) = Sum(k) (y1k qk - y0k pk)
 			 */
 			fittedVariance = fittedPQ * (y0 [icell] + y1 [icell]);
-			for (long ivar = 0; ivar <= numberOfFactors; ivar ++) {
+			for (integer ivar = 0; ivar <= numberOfFactors; ivar ++) {
 				/*
 				 * The last column gets the gradient of LL: dLL/da, dLL/db, dLL/dc.
 				 */
 				smallMatrix [ivar] [numberOfParameters] += x [icell] [ivar] * (y1 [icell] * fittedQ - y0 [icell] * fittedP);
-				for (long jvar = ivar; jvar <= numberOfFactors; jvar ++) {
+				for (integer jvar = ivar; jvar <= numberOfFactors; jvar ++) {
 					smallMatrix [ivar] [jvar] += x [icell] [ivar] * x [icell] [jvar] * fittedVariance;
 				}
 			}
@@ -218,25 +218,25 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 		/*
 		 * Make matrix symmetric.
 		 */
-		for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
-			for (long jvar = 0; jvar < ivar; jvar ++) {
+		for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
+			for (integer jvar = 0; jvar < ivar; jvar ++) {
 				smallMatrix [ivar] [jvar] = smallMatrix [jvar] [ivar];
 			}
 		}
 		/*
 		 * Invert matrix in the simplest way, and shift and wipe the last column with it.
 		 */
-		for (long ivar = 0; ivar <= numberOfFactors; ivar ++) {
+		for (integer ivar = 0; ivar <= numberOfFactors; ivar ++) {
 			double pivot = smallMatrix [ivar] [ivar];   /* Save diagonal. */
 			smallMatrix [ivar] [ivar] = 1.0;
-			for (long jvar = 0; jvar <= numberOfParameters; jvar ++) {
+			for (integer jvar = 0; jvar <= numberOfParameters; jvar ++) {
 				smallMatrix [ivar] [jvar] /= pivot;
 			}
-			for (long jvar = 0; jvar <= numberOfFactors; jvar ++) {
+			for (integer jvar = 0; jvar <= numberOfFactors; jvar ++) {
 				if (jvar != ivar) {
 					double temp = smallMatrix [jvar] [ivar];
 					smallMatrix [jvar] [ivar] = 0.0;
-					for (long kvar = 0; kvar <= numberOfParameters; kvar ++) {
+					for (integer kvar = 0; kvar <= numberOfParameters; kvar ++) {
 						smallMatrix [jvar] [kvar] -= temp * smallMatrix [ivar] [kvar];
 					}
 				}
@@ -246,7 +246,7 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 		 * Update the parameters from the last column of smallMatrix.
 		 */
 		thy intercept += smallMatrix [0] [numberOfParameters];
-		for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+		for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 			RegressionParameter parm = thy parameters.at [ivar];
 			parm -> value += smallMatrix [ivar] [numberOfParameters];
 		}
@@ -254,7 +254,7 @@ static autoLogisticRegression _Table_to_LogisticRegression (Table me, long *fact
 	if (iteration > 100) {
 		Melder_warning (U"Logistic regression has not converged in 100 iterations. The results are unreliable.");
 	}
-	for (long ivar = 1; ivar <= numberOfFactors; ivar ++) {
+	for (integer ivar = 1; ivar <= numberOfFactors; ivar ++) {
 		RegressionParameter parm = thy parameters.at [ivar];
 		parm -> value /= stdevX [ivar];
 		thy intercept -= parm -> value * meanX [ivar];
@@ -266,10 +266,10 @@ autoLogisticRegression Table_to_LogisticRegression (Table me, const char32 *fact
 	const char32 *dependent1_columnLabel, const char32 *dependent2_columnLabel)
 {
 	try {
-		long numberOfFactors;
-		autoNUMvector <long> factors_columnIndices (Table_getColumnIndicesFromColumnLabelString (me, factors_columnLabelString, & numberOfFactors), 1);
-		long dependent1_columnIndex = Table_getColumnIndexFromColumnLabel (me, dependent1_columnLabel);
-		long dependent2_columnIndex = Table_getColumnIndexFromColumnLabel (me, dependent2_columnLabel);
+		integer numberOfFactors;
+		autoNUMvector <integer> factors_columnIndices (Table_getColumnIndicesFromColumnLabelString (me, factors_columnLabelString, & numberOfFactors), 1);
+		integer dependent1_columnIndex = Table_getColumnIndexFromColumnLabel (me, dependent1_columnLabel);
+		integer dependent2_columnIndex = Table_getColumnIndexFromColumnLabel (me, dependent2_columnLabel);
 		autoLogisticRegression thee = _Table_to_LogisticRegression (me, factors_columnIndices.peek(), numberOfFactors, dependent1_columnIndex, dependent2_columnIndex);
 		return thee;
 	} catch (MelderError) {
@@ -285,8 +285,8 @@ static inline double NUMmax2 (double a, double b) {
 	return a > b ? a : b;
 }
 
-void LogisticRegression_drawBoundary (LogisticRegression me, Graphics graphics, long colx, double xleft, double xright,
-	long coly, double ybottom, double ytop, bool garnish)
+void LogisticRegression_drawBoundary (LogisticRegression me, Graphics graphics, integer colx, double xleft, double xright,
+	integer coly, double ybottom, double ytop, bool garnish)
 {
 	RegressionParameter parmx = my parameters.at [colx];
 	RegressionParameter parmy = my parameters.at [coly];
@@ -299,7 +299,7 @@ void LogisticRegression_drawBoundary (LogisticRegression me, Graphics graphics,
 		ytop = parmy -> maximum;
 	}
 	double intercept = my intercept;
-	for (long iparm = 1; iparm <= my parameters.size; iparm ++) {
+	for (integer iparm = 1; iparm <= my parameters.size; iparm ++) {
 		if (iparm != colx && iparm != coly) {
 			RegressionParameter parm = my parameters.at [iparm];
 			intercept += parm -> value * (0.5 * (parm -> minimum + parm -> maximum));
diff --git a/stat/LogisticRegression.h b/stat/LogisticRegression.h
index 36e3ea5..5a47402 100644
--- a/stat/LogisticRegression.h
+++ b/stat/LogisticRegression.h
@@ -2,7 +2,7 @@
 #define _LogisticRegression_h_
 /* LogisticRegression.h
  *
- * Copyright (C) 2005-2011,2015 Paul Boersma
+ * Copyright (C) 2005-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,8 +27,8 @@ autoLogisticRegression LogisticRegression_create (const char32 *dependent1, cons
 autoLogisticRegression Table_to_LogisticRegression (Table me, const char32 *columnsWithFactors_string,
 	const char32 *columnWithDependent1_string, const char32 *columnWithDependent2_string);
 
-void LogisticRegression_drawBoundary (LogisticRegression me, Graphics graphics, long colx, double xmin, double xmax,
-	long coly, double ymin, double ymax, bool garnish);
+void LogisticRegression_drawBoundary (LogisticRegression me, Graphics graphics, integer colx, double xmin, double xmax,
+	integer coly, double ymin, double ymax, bool garnish);
 
 /* End of file LogisticRegression.h */
 #endif
diff --git a/stat/Makefile b/stat/Makefile
index 39a36ad..c5f3317 100644
--- a/stat/Makefile
+++ b/stat/Makefile
@@ -1,9 +1,9 @@
 # Makefile of the library "stat"
-# Paul Boersma, 22 October 2016
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../num -I ../kar -I ../sys -I ../dwsys -I ../dwtools -I ../fon -I ../stat
+CPPFLAGS = -I ../kar -I ../sys -I ../dwsys -I ../dwtools -I ../fon -I ../stat
 
 OBJECTS = Table.o TableEditor.o Regression.o manual_statistics.o \
    praat_TableOfReal.o praat_Stat.o \
@@ -24,4 +24,4 @@ clean:
 	$(RM) $(OBJECTS)
 	$(RM) libstat.a
 
-$(OBJECTS): *.h ../num/NUM.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../dwtools/*.h ../fon/*.h
+$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../dwtools/*.h ../fon/*.h ../stat/*.h
diff --git a/stat/Regression.cpp b/stat/Regression.cpp
index 5b3ba46..7c2a0b6 100644
--- a/stat/Regression.cpp
+++ b/stat/Regression.cpp
@@ -86,7 +86,7 @@ long Regression_getFactorIndexFromFactorName_e (Regression me, const char32 *fac
 		RegressionParameter parm = my parameters.at [iparm];
 		if (Melder_equ (factorName, parm -> label)) return iparm;
 	}
-	Melder_throw (Thing_messageName (me), U" has no parameter named \"", factorName, U"\".");
+	Melder_throw (me, U" has no parameter named \"", factorName, U"\".");
 }
 
 Thing_implement (LinearRegression, Regression, 0);
diff --git a/stat/Table.cpp b/stat/Table.cpp
index d53aed5..4eaa6d8 100644
--- a/stat/Table.cpp
+++ b/stat/Table.cpp
@@ -1,6 +1,6 @@
 /* Table.cpp
  *
- * Copyright (C) 2002-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 2002-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -57,10 +57,10 @@ const char32 * structTable :: v_getColStr (long columnNumber) {
 }
 
 double structTable :: v_getMatrix (long rowNumber, long columnNumber) {
-	if (rowNumber < 1 || rowNumber > our rows.size) return NUMundefined;
-	if (columnNumber < 1 || columnNumber > our numberOfColumns) return NUMundefined;
+	if (rowNumber < 1 || rowNumber > our rows.size) return undefined;
+	if (columnNumber < 1 || columnNumber > our numberOfColumns) return undefined;
 	char32 *stringValue = our rows.at [rowNumber] -> cells [columnNumber]. string;
-	return stringValue ? Melder_atof (stringValue) : NUMundefined;
+	return stringValue ? Melder_atof (stringValue) : undefined;
 }
 
 const char32 * structTable :: v_getMatrixStr (long rowNumber, long columnNumber) {
@@ -74,24 +74,24 @@ double structTable :: v_getColIndex (const char32 *columnLabel) {
 	return Table_findColumnIndexFromColumnLabel (this, columnLabel);
 }
 
-static autoTableRow TableRow_create (long numberOfColumns) {
+static autoTableRow TableRow_create (integer numberOfColumns) {
 	autoTableRow me = Thing_new (TableRow);
 	my numberOfColumns = numberOfColumns;
 	my cells = NUMvector <structTableCell> (1, numberOfColumns);
 	return me;
 }
 
-void Table_initWithoutColumnNames (Table me, long numberOfRows, long numberOfColumns) {
+void Table_initWithoutColumnNames (Table me, integer numberOfRows, integer numberOfColumns) {
 	if (numberOfColumns < 1)
 		Melder_throw (U"Cannot create table without columns.");
 	my numberOfColumns = numberOfColumns;
 	my columnHeaders = NUMvector <structTableColumnHeader> (1, numberOfColumns);
-	for (long irow = 1; irow <= numberOfRows; irow ++) {
+	for (integer irow = 1; irow <= numberOfRows; irow ++) {
 		Table_appendRow (me);
 	}
 }
 
-autoTable Table_createWithoutColumnNames (long numberOfRows, long numberOfColumns) {
+autoTable Table_createWithoutColumnNames (integer numberOfRows, integer numberOfColumns) {
 	try {
 		autoTable me = Thing_new (Table);
 		Table_initWithoutColumnNames (me.get(), numberOfRows, numberOfColumns);
@@ -101,16 +101,16 @@ autoTable Table_createWithoutColumnNames (long numberOfRows, long numberOfColumn
 	}
 }
 
-void Table_initWithColumnNames (Table me, long numberOfRows, const char32 *columnNames) {
+void Table_initWithColumnNames (Table me, integer numberOfRows, const char32 *columnNames) {
 	Table_initWithoutColumnNames (me, numberOfRows, Melder_countTokens (columnNames));
-	long icol = 0;
+	integer icol = 0;
 	for (char32 *columnName = Melder_firstToken (columnNames); columnName; columnName = Melder_nextToken ()) {
 		icol ++;
 		Table_setColumnLabel (me, icol, columnName);
 	}
 }
 
-autoTable Table_createWithColumnNames (long numberOfRows, const char32 *columnNames) {
+autoTable Table_createWithColumnNames (integer numberOfRows, const char32 *columnNames) {
 	try {
 		autoTable me = Thing_new (Table);
 		Table_initWithColumnNames (me.get(), numberOfRows, columnNames);
@@ -137,34 +137,34 @@ void Table_appendColumn (Table me, const char32 *label) {
 	}
 }
 
-void Table_checkSpecifiedRowNumberWithinRange (Table me, long rowNumber) {
+void Table_checkSpecifiedRowNumberWithinRange (Table me, integer rowNumber) {
 	if (rowNumber < 1)
 		Melder_throw (me, U": the specified row number is ", rowNumber, U", but should be at least 1.");
 	if (rowNumber > my rows.size)
 		Melder_throw (me, U": the specified row number (", rowNumber, U") exceeds my number of rows (", my rows.size, U").");
 }
 
-void Table_removeRow (Table me, long rowNumber) {
+void Table_removeRow (Table me, integer rowNumber) {
 	try {
 		if (my rows.size == 1)
 			Melder_throw (me, U": cannot remove my only row.");
 		Table_checkSpecifiedRowNumberWithinRange (me, rowNumber);
 		my rows. removeItem (rowNumber);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++)
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 			my columnHeaders [icol]. numericized = false;
 	} catch (MelderError) {
 		Melder_throw (me, U": row ", rowNumber, U" not removed.");
 	}
 }
 
-void Table_checkSpecifiedColumnNumberWithinRange (Table me, long columnNumber) {
+void Table_checkSpecifiedColumnNumberWithinRange (Table me, integer columnNumber) {
 	if (columnNumber < 1)
 		Melder_throw (me, U": the specified column number is ", columnNumber, U", but should be at least 1.");
 	if (columnNumber > my numberOfColumns)
 		Melder_throw (me, U": the specified column number is ", columnNumber, U", but should be at most my number of columns (", my numberOfColumns, U").");
 }
 
-void Table_removeColumn (Table me, long columnNumber) {
+void Table_removeColumn (Table me, integer columnNumber) {
 	try {
 		if (my numberOfColumns == 1)
 			Melder_throw (me, U": cannot remove my only column.");
@@ -173,12 +173,12 @@ void Table_removeColumn (Table me, long columnNumber) {
 		 * Changes without error.
 		 */
 		Melder_free (my columnHeaders [columnNumber]. label);
-		for (long icol = columnNumber; icol < my numberOfColumns; icol ++)
+		for (integer icol = columnNumber; icol < my numberOfColumns; icol ++)
 			my columnHeaders [icol] = my columnHeaders [icol + 1];
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			Melder_free (row -> cells [columnNumber]. string);
-			for (long icol = columnNumber; icol < row -> numberOfColumns; icol ++)
+			for (integer icol = columnNumber; icol < row -> numberOfColumns; icol ++)
 				row -> cells [icol] = row -> cells [icol + 1];
 			row -> numberOfColumns --;
 		}
@@ -188,7 +188,7 @@ void Table_removeColumn (Table me, long columnNumber) {
 	}
 }
 
-void Table_insertRow (Table me, long rowNumber) {
+void Table_insertRow (Table me, integer rowNumber) {
 	try {
 		/*
 		 * Check without changes.
@@ -205,14 +205,14 @@ void Table_insertRow (Table me, long rowNumber) {
 		/*
 		 * Changes without error.
 		 */
-		for (long icol = 1; icol <= my numberOfColumns; icol ++)
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 			my columnHeaders [icol]. numericized = false;
 	} catch (MelderError) {
 		Melder_throw (me, U": row ", rowNumber, U" not inserted.");
 	}
 }
 
-void Table_insertColumn (Table me, long columnNumber, const char32 *label /* cattable */) {
+void Table_insertColumn (Table me, integer columnNumber, const char32 *label /* cattable */) {
 	try {
 		/*
 		 * Check without changes.
@@ -229,14 +229,14 @@ void Table_insertColumn (Table me, long columnNumber, const char32 *label /* cat
 		/*
 		 * Transfer column headers to larger structure.
 		 */
-		for (long icol = 1; icol < columnNumber; icol ++) {
+		for (integer icol = 1; icol < columnNumber; icol ++) {
 			Melder_assert (! thy columnHeaders [icol]. label);   // make room...
 			thy columnHeaders [icol] = my columnHeaders [icol];   // ...fill in and dangle...
 			my columnHeaders [icol]. label = nullptr;   // ...undangle
 		}
 		thy columnHeaders [columnNumber]. label = newLabel.transfer();
 		thy columnHeaders [columnNumber]. numericized = false;
-		for (long icol = my numberOfColumns + 1; icol > columnNumber; icol --) {
+		for (integer icol = my numberOfColumns + 1; icol > columnNumber; icol --) {
 			Melder_assert (! thy columnHeaders [icol]. label);   // make room...
 			thy columnHeaders [icol] = my columnHeaders [icol - 1];   // ...fill in and dangle...
 			my columnHeaders [icol - 1]. label = nullptr;   // ...undangle
@@ -244,17 +244,17 @@ void Table_insertColumn (Table me, long columnNumber, const char32 *label /* cat
 		/*
 		 * Transfer rows to larger structure.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			TableRow thyRow = thy rows.at [irow];
-			for (long icol = 1; icol < columnNumber; icol ++) {
+			for (integer icol = 1; icol < columnNumber; icol ++) {
 				Melder_assert (! thyRow -> cells [icol]. string);   // make room...
 				thyRow -> cells [icol] = myRow -> cells [icol];   // ...fill in and dangle...
 				myRow -> cells [icol]. string = nullptr;   // ...undangle
 			}
 			Melder_assert (! thyRow -> cells [columnNumber]. string);
 			Melder_assert (thyRow -> cells [columnNumber]. number == 0.0);
-			for (long icol = myRow -> numberOfColumns + 1; icol > columnNumber; icol --) {
+			for (integer icol = myRow -> numberOfColumns + 1; icol > columnNumber; icol --) {
 				Melder_assert (! thyRow -> cells [icol]. string);   // make room...
 				thyRow -> cells [icol] = myRow -> cells [icol - 1];   // ...fill in and dangle...
 				myRow -> cells [icol - 1]. string = nullptr;   // ...undangle
@@ -279,7 +279,7 @@ void Table_insertColumn (Table me, long columnNumber, const char32 *label /* cat
 	}
 }
 
-void Table_setColumnLabel (Table me, long columnNumber, const char32 *label /* cattable */) {
+void Table_setColumnLabel (Table me, integer columnNumber, const char32 *label /* cattable */) {
 	try {
 		/*
 		 * Check without changes.
@@ -296,34 +296,34 @@ void Table_setColumnLabel (Table me, long columnNumber, const char32 *label /* c
 	}
 }
 
-long Table_findColumnIndexFromColumnLabel (Table me, const char32 *label) noexcept {
-	for (long icol = 1; icol <= my numberOfColumns; icol ++)
+integer Table_findColumnIndexFromColumnLabel (Table me, const char32 *label) noexcept {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 		if (my columnHeaders [icol]. label && str32equ (my columnHeaders [icol]. label, label))
 			return icol;
 	return 0;
 }
 
-long Table_getColumnIndexFromColumnLabel (Table me, const char32 *columnLabel) {
-	long columnNumber = Table_findColumnIndexFromColumnLabel (me, columnLabel);
+integer Table_getColumnIndexFromColumnLabel (Table me, const char32 *columnLabel) {
+	integer columnNumber = Table_findColumnIndexFromColumnLabel (me, columnLabel);
 	if (columnNumber == 0)
 		Melder_throw (me, U": there is no column named \"", columnLabel, U"\".");
 	return columnNumber;
 }
 
-long * Table_getColumnIndicesFromColumnLabelString (Table me, const char32 *string, long *ptr_numberOfTokens) {
+integer * Table_getColumnIndicesFromColumnLabelString (Table me, const char32 *string, integer *ptr_numberOfTokens) {
 	autoMelderTokens tokens (string);
 	if (tokens.count() < 1)
 		Melder_throw (me, U": you specified an empty list of columns.");
-	autoNUMvector <long> columns (1, tokens.count());
-	for (long icol = 1; icol <= tokens.count(); icol ++) {
+	autoNUMvector <integer> columns (1, tokens.count());
+	for (integer icol = 1; icol <= tokens.count(); icol ++) {
 		columns [icol] = Table_getColumnIndexFromColumnLabel (me, tokens [icol]);
 	}
 	*ptr_numberOfTokens = tokens.count();
 	return columns.transfer();
 }
 
-long Table_searchColumn (Table me, long columnNumber, const char32 *value) noexcept {
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+integer Table_searchColumn (Table me, integer columnNumber, const char32 *value) noexcept {
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
 		if (row -> cells [columnNumber]. string && str32equ (row -> cells [columnNumber]. string, value))
 			return irow;
@@ -331,7 +331,7 @@ long Table_searchColumn (Table me, long columnNumber, const char32 *value) noexc
 	return 0;
 }
 
-void Table_setStringValue (Table me, long rowNumber, long columnNumber, const char32 *value /* cattable */) {
+void Table_setStringValue (Table me, integer rowNumber, integer columnNumber, const char32 *value /* cattable */) {
 	try {
 		/*
 		 * Check without changes.
@@ -351,7 +351,7 @@ void Table_setStringValue (Table me, long rowNumber, long columnNumber, const ch
 	}
 }
 
-void Table_setNumericValue (Table me, long rowNumber, long columnNumber, double value) {
+void Table_setNumericValue (Table me, integer rowNumber, integer columnNumber, double value) {
 	try {
 		/*
 		 * Check without changes.
@@ -371,7 +371,7 @@ void Table_setNumericValue (Table me, long rowNumber, long columnNumber, double
 	}
 }
 
-bool Table_isCellNumeric_ErrorFalse (Table me, long rowNumber, long columnNumber) {
+bool Table_isCellNumeric_ErrorFalse (Table me, integer rowNumber, integer columnNumber) {
 	if (rowNumber < 1 || rowNumber > my rows.size) return false;
 	if (columnNumber < 1 || columnNumber > my numberOfColumns) return false;
 	TableRow row = my rows.at [rowNumber];
@@ -393,15 +393,15 @@ bool Table_isCellNumeric_ErrorFalse (Table me, long rowNumber, long columnNumber
 	return Melder_isStringNumeric_nothrow (cell);
 }
 
-bool Table_isColumnNumeric_ErrorFalse (Table me, long columnNumber) {
+bool Table_isColumnNumeric_ErrorFalse (Table me, integer columnNumber) {
 	if (columnNumber < 1 || columnNumber > my numberOfColumns) return false;
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		if (! Table_isCellNumeric_ErrorFalse (me, irow, columnNumber)) return false;
 	}
 	return true;
 }
 
-static long stringCompare_column;
+static integer stringCompare_column;
 
 static int stringCompare_NoError (const void *first, const void *second) {
 	TableRow me = * (TableRow *) first, thee = * (TableRow *) second;
@@ -410,7 +410,7 @@ static int stringCompare_NoError (const void *first, const void *second) {
 	return str32cmp (firstString ? firstString : U"", secondString ? secondString : U"");
 }
 
-static void sortRowsByStrings_Assert (Table me, long columnNumber) {
+static void sortRowsByStrings_Assert (Table me, integer columnNumber) {
 	Melder_assert (columnNumber >= 1 && columnNumber <= my numberOfColumns);
 	stringCompare_column = columnNumber;
 	qsort (& my rows.at [1], (unsigned long) my rows.size, sizeof (TableRow), stringCompare_NoError);
@@ -427,26 +427,26 @@ static void sortRowsByIndex_NoError (Table me) {
 	qsort (& my rows.at [1], (unsigned long) my rows.size, sizeof (TableRow), indexCompare_NoError);
 }
 
-void Table_numericize_Assert (Table me, long columnNumber) {
+void Table_numericize_Assert (Table me, integer columnNumber) {
 	Melder_assert (columnNumber >= 1 && columnNumber <= my numberOfColumns);
 	if (my columnHeaders [columnNumber]. numericized) return;
 	if (Table_isColumnNumeric_ErrorFalse (me, columnNumber)) {
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			const char32 *string = row -> cells [columnNumber]. string;
 			row -> cells [columnNumber]. number =
-				! string || string [0] == U'\0' || (string [0] == U'?' && string [1] == U'\0') ? NUMundefined :
+				! string || string [0] == U'\0' || (string [0] == U'?' && string [1] == U'\0') ? undefined :
 				Melder_atof (string);
 		}
 	} else {
-		long iunique = 0;
+		integer iunique = 0;
 		const char32 *previousString = nullptr;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			row -> sortingIndex = irow;
 		}
 		sortRowsByStrings_Assert (me, columnNumber);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			const char32 *string = row -> cells [columnNumber]. string;
 			if (! string) string = U"";
@@ -461,25 +461,25 @@ void Table_numericize_Assert (Table me, long columnNumber) {
 	my columnHeaders [columnNumber]. numericized = true;
 }
 
-static void Table_numericize_checkDefined (Table me, long columnNumber) {
+static void Table_numericize_checkDefined (Table me, integer columnNumber) {
 	Table_numericize_Assert (me, columnNumber);
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
-		if (row -> cells [columnNumber]. number == NUMundefined)
+		if (isundef (row -> cells [columnNumber]. number))
 			Melder_throw (me, U": the cell in row ", irow,
 				U" of column \"", my columnHeaders [columnNumber]. label ? my columnHeaders [columnNumber]. label : Melder_integer (columnNumber),
 				U"\" is undefined.");
 	}
 }
 
-const char32 * Table_getStringValue_Assert (Table me, long rowNumber, long columnNumber) {
+const char32 * Table_getStringValue_Assert (Table me, integer rowNumber, integer columnNumber) {
 	Melder_assert (rowNumber >= 1 && rowNumber <= my rows.size);
 	Melder_assert (columnNumber >= 1 && columnNumber <= my numberOfColumns);
 	TableRow row = my rows.at [rowNumber];
 	return row -> cells [columnNumber]. string ? row -> cells [columnNumber]. string : U"";
 }
 
-double Table_getNumericValue_Assert (Table me, long rowNumber, long columnNumber) {
+double Table_getNumericValue_Assert (Table me, integer rowNumber, integer columnNumber) {
 	Melder_assert (rowNumber >= 1 && rowNumber <= my rows.size);
 	Melder_assert (columnNumber >= 1 && columnNumber <= my numberOfColumns);
 	TableRow row = my rows.at [rowNumber];
@@ -487,32 +487,32 @@ double Table_getNumericValue_Assert (Table me, long rowNumber, long columnNumber
 	return row -> cells [columnNumber]. number;
 }
 
-double Table_getMean (Table me, long columnNumber) {
+double Table_getMean (Table me, integer columnNumber) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_checkDefined (me, columnNumber);
 		if (my rows.size < 1)
-			return NUMundefined;
-		double sum = 0.0;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+			return undefined;
+		real80 sum = 0.0;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			sum += row -> cells [columnNumber]. number;
 		}
-		return sum / my rows.size;
+		return (real) sum / my rows.size;
 	} catch (MelderError) {
 		Melder_throw (me, U": cannot compute mean of column ", columnNumber, U".");
 	}
 }
 
-double Table_getMaximum (Table me, long columnNumber) {
+double Table_getMaximum (Table me, integer columnNumber) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_checkDefined (me, columnNumber);
 		if (my rows.size < 1)
-			return NUMundefined;
+			return undefined;
 		TableRow firstRow = my rows.at [1];
 		double maximum = firstRow -> cells [columnNumber]. number;
-		for (long irow = 2; irow <= my rows.size; irow ++) {
+		for (integer irow = 2; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (row -> cells [columnNumber]. number > maximum)
 				maximum = row -> cells [columnNumber]. number;
@@ -523,15 +523,15 @@ double Table_getMaximum (Table me, long columnNumber) {
 	}
 }
 
-double Table_getMinimum (Table me, long columnNumber) {
+double Table_getMinimum (Table me, integer columnNumber) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_checkDefined (me, columnNumber);
 		if (my rows.size < 1)
-			return NUMundefined;
+			return undefined;
 		TableRow firstRow = my rows.at [1];
 		double minimum = firstRow -> cells [columnNumber]. number;
-		for (long irow = 2; irow <= my rows.size; irow ++) {
+		for (integer irow = 2; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (row -> cells [columnNumber]. number < minimum)
 				minimum = row -> cells [columnNumber]. number;
@@ -542,35 +542,35 @@ double Table_getMinimum (Table me, long columnNumber) {
 	}
 }
 
-double Table_getGroupMean (Table me, long columnNumber, long groupColumnNumber, const char32 *group) {
+double Table_getGroupMean (Table me, integer columnNumber, integer groupColumnNumber, const char32 *group) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_checkDefined (me, columnNumber);
-		long n = 0;
-		double sum = 0.0;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		integer n = 0;
+		real80 sum = 0.0;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (Melder_equ (row -> cells [groupColumnNumber]. string, group)) {
 				n += 1;
 				sum += row -> cells [columnNumber]. number;
 			}
 		}
-		if (n < 1) return NUMundefined;
-		double mean = sum / n;
+		if (n < 1) return undefined;
+		real mean = (real) sum / n;
 		return mean;
 	} catch (MelderError) {
 		Melder_throw (me, U": cannot compute mean of column ", columnNumber, U" for group \"", group, U"\" of column ", groupColumnNumber, U".");
 	}
 }
 
-double Table_getQuantile (Table me, long columnNumber, double quantile) {
+double Table_getQuantile (Table me, integer columnNumber, double quantile) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_checkDefined (me, columnNumber);
 		if (my rows.size < 1)
-			return NUMundefined;
+			return undefined;
 		autoNUMvector <double> sortingColumn (1, my rows.size);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			sortingColumn [irow] = row -> cells [columnNumber]. number;
 		}
@@ -581,39 +581,40 @@ double Table_getQuantile (Table me, long columnNumber, double quantile) {
 	}
 }
 
-double Table_getStdev (Table me, long columnNumber) {
+double Table_getStdev (Table me, integer columnNumber) {
 	try {
 		double mean = Table_getMean (me, columnNumber);   // already checks for columnNumber and undefined cells
 		if (my rows.size < 2)
-			return NUMundefined;
-		double sum = 0.0;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+			return undefined;
+		real80 sum = 0.0;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			double d = row -> cells [columnNumber]. number - mean;
 			sum += d * d;
 		}
-		return sqrt (sum / (my rows.size - 1));
+		return sqrt ((real) sum / (my rows.size - 1));
 	} catch (MelderError) {
 		Melder_throw (me, U": cannot compute the standard deviation of column ", columnNumber, U".");
 	}
 }
 
-long Table_drawRowFromDistribution (Table me, long columnNumber) {
+integer Table_drawRowFromDistribution (Table me, integer columnNumber) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_checkDefined (me, columnNumber);
 		if (my rows.size < 1)
 			Melder_throw (me, U": no rows.");
-		double total = 0.0;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		real80 total = 0.0;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			total += row -> cells [columnNumber]. number;
 		}
 		if (total <= 0.0)
 			Melder_throw (me, U": the total weight of column ", columnNumber, U" is not positive.");
-		long irow;
+		integer irow;
 		do {
-			double rand = NUMrandomUniform (0, total), sum = 0.0;
+			double rand = NUMrandomUniform (0, (real) total);
+			real80 sum = 0.0;
 			for (irow = 1; irow <= my rows.size; irow ++) {
 				TableRow row = my rows.at [irow];
 				sum += row -> cells [columnNumber]. number;
@@ -626,15 +627,15 @@ long Table_drawRowFromDistribution (Table me, long columnNumber) {
 	}
 }
 
-autoTable Table_extractRowsWhereColumn_number (Table me, long columnNumber, int which_Melder_NUMBER, double criterion) {
+autoTable Table_extractRowsWhereColumn_number (Table me, integer columnNumber, int which_Melder_NUMBER, double criterion) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		Table_numericize_Assert (me, columnNumber);   // extraction should work even if cells are not defined
 		autoTable thee = Table_create (0, my numberOfColumns);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			thy columnHeaders [icol]. label = Melder_dup (my columnHeaders [icol]. label);
 		}
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (Melder_numberMatchesCriterion (row -> cells [columnNumber]. number, which_Melder_NUMBER, criterion)) {
 				autoTableRow newRow = Data_copy (row);
@@ -650,15 +651,15 @@ autoTable Table_extractRowsWhereColumn_number (Table me, long columnNumber, int
 	}
 }
 
-autoTable Table_extractRowsWhereColumn_string (Table me, long columnNumber, int which_Melder_STRING, const char32 *criterion) {
+autoTable Table_extractRowsWhereColumn_string (Table me, integer columnNumber, int which_Melder_STRING, const char32 *criterion) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, columnNumber);
 		autoTable thee = Table_create (0, my numberOfColumns);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			autostring32 newLabel = Melder_dup (my columnHeaders [icol]. label);
 			thy columnHeaders [icol]. label = newLabel.transfer();
 		}
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (Melder_stringMatchesCriterion (row -> cells [columnNumber]. string, which_Melder_STRING, criterion)) {
 				autoTableRow newRow = Data_copy (row);
@@ -674,16 +675,16 @@ autoTable Table_extractRowsWhereColumn_string (Table me, long columnNumber, int
 	}
 }
 
-static void Table_columns_checkExist (Table me, char32 **columnNames, long n) {
-	for (long i = 1; i <= n; i ++) {
+static void Table_columns_checkExist (Table me, char32 **columnNames, integer n) {
+	for (integer i = 1; i <= n; i ++) {
 		if (Table_findColumnIndexFromColumnLabel (me, columnNames [i]) == 0)
 			Melder_throw (me, U": column \"", columnNames [i], U"\" does not exist.");
 	}
 }
 
-static void Table_columns_checkCrossSectionEmpty (char32 **factors, long nfactors, char32 **vars, long nvars) {
-	for (long ifactor = 1; ifactor <= nfactors; ifactor ++) {
-		for (long ivar = 1; ivar <= nvars; ivar ++) {
+static void Table_columns_checkCrossSectionEmpty (char32 **factors, integer nfactors, char32 **vars, integer nvars) {
+	for (integer ifactor = 1; ifactor <= nfactors; ifactor ++) {
+		for (integer ivar = 1; ivar <= nvars; ivar ++) {
 			if (str32equ (factors [ifactor], vars [ivar]))
 				Melder_throw (U"Factor \"", factors [ifactor], U"\" is also used as dependent variable.");
 		}
@@ -702,13 +703,13 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 		 * Parse the six strings of tokens.
 		 */
 		autoMelderTokens factors (factors_string);
-		long numberOfFactors = factors.count();
+		integer numberOfFactors = factors.count();
 		if (numberOfFactors < 1)
 			Melder_throw (U"In order to pool table data, you must supply at least one independent variable.");
 		Table_columns_checkExist (me, factors.peek(), numberOfFactors);
 
 		autoMelderTokens columnsToSum;
-		long numberToSum = 0;
+		integer numberToSum = 0;
 		if (columnsToSum_string) {
 			columnsToSum.reset (columnsToSum_string);
 			numberToSum = columnsToSum.count();
@@ -716,7 +717,7 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 			Table_columns_checkCrossSectionEmpty (factors.peek(), numberOfFactors, columnsToSum.peek(), numberToSum);
 		}
 		autoMelderTokens columnsToAverage;
-		long numberToAverage = 0;
+		integer numberToAverage = 0;
 		if (columnsToAverage_string) {
 			columnsToAverage.reset (columnsToAverage_string);
 			numberToAverage = columnsToAverage.count();
@@ -724,7 +725,7 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 			Table_columns_checkCrossSectionEmpty (factors.peek(), numberOfFactors, columnsToAverage.peek(), numberToAverage);
 		}
 		autoMelderTokens columnsToMedianize;
-		long numberToMedianize = 0;
+		integer numberToMedianize = 0;
 		if (columnsToMedianize_string) {
 			columnsToMedianize.reset (columnsToMedianize_string);
 			numberToMedianize = columnsToMedianize.count();
@@ -732,7 +733,7 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 			Table_columns_checkCrossSectionEmpty (factors.peek(), numberOfFactors, columnsToMedianize.peek(), numberToMedianize);
 		}
 		autoMelderTokens columnsToAverageLogarithmically;
-		long numberToAverageLogarithmically = 0;
+		integer numberToAverageLogarithmically = 0;
 		if (columnsToAverageLogarithmically_string) {
 			columnsToAverageLogarithmically.reset (columnsToAverageLogarithmically_string);
 			numberToAverageLogarithmically = columnsToAverageLogarithmically.count();
@@ -740,7 +741,7 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 			Table_columns_checkCrossSectionEmpty (factors.peek(), numberOfFactors, columnsToAverageLogarithmically.peek(), numberToAverageLogarithmically);
 		}
 		autoMelderTokens columnsToMedianizeLogarithmically;
-		long numberToMedianizeLogarithmically = 0;
+		integer numberToMedianizeLogarithmically = 0;
 		if (columnsToMedianizeLogarithmically_string) {
 			columnsToMedianizeLogarithmically.reset (columnsToMedianizeLogarithmically_string);
 			numberToMedianizeLogarithmically = columnsToMedianizeLogarithmically.count();
@@ -759,30 +760,30 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 		/*
 		 * Set the column names. Within the dependent variables, the same name may occur more than once.
 		 */
-		autoNUMvector <long> columns (1, thy numberOfColumns);
+		autoNUMvector <integer> columns (1, thy numberOfColumns);
 		{
-			long icol = 0;
-			for (long i = 1; i <= numberOfFactors; i ++) {
+			integer icol = 0;
+			for (integer i = 1; i <= numberOfFactors; i ++) {
 				Table_setColumnLabel (thee.get(), ++ icol, factors [i]);
 				columns [icol] = Table_findColumnIndexFromColumnLabel (me, factors [i]);
 			}
-			for (long i = 1; i <= numberToSum; i ++) {
+			for (integer i = 1; i <= numberToSum; i ++) {
 				Table_setColumnLabel (thee.get(), ++ icol, columnsToSum [i]);
 				columns [icol] = Table_findColumnIndexFromColumnLabel (me, columnsToSum [i]);
 			}
-			for (long i = 1; i <= numberToAverage; i ++) {
+			for (integer i = 1; i <= numberToAverage; i ++) {
 				Table_setColumnLabel (thee.get(), ++ icol, columnsToAverage [i]);
 				columns [icol] = Table_findColumnIndexFromColumnLabel (me, columnsToAverage [i]);
 			}
-			for (long i = 1; i <= numberToMedianize; i ++) {
+			for (integer i = 1; i <= numberToMedianize; i ++) {
 				Table_setColumnLabel (thee.get(), ++ icol, columnsToMedianize [i]);
 				columns [icol] = Table_findColumnIndexFromColumnLabel (me, columnsToMedianize [i]);
 			}
-			for (long i = 1; i <= numberToAverageLogarithmically; i ++) {
+			for (integer i = 1; i <= numberToAverageLogarithmically; i ++) {
 				Table_setColumnLabel (thee.get(), ++ icol, columnsToAverageLogarithmically [i]);
 				columns [icol] = Table_findColumnIndexFromColumnLabel (me, columnsToAverageLogarithmically [i]);
 			}
-			for (long i = 1; i <= numberToMedianizeLogarithmically; i ++) {
+			for (integer i = 1; i <= numberToMedianizeLogarithmically; i ++) {
 				Table_setColumnLabel (thee.get(), ++ icol, columnsToMedianizeLogarithmically [i]);
 				columns [icol] = Table_findColumnIndexFromColumnLabel (me, columnsToMedianizeLogarithmically [i]);
 			}
@@ -791,7 +792,7 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 		/*
 		 * Make sure that all the columns in the original table that we will use in the pooled table are defined.
 		 */
-		for (long icol = 1; icol <= thy numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= thy numberOfColumns; icol ++) {
 			Table_numericize_checkDefined (me, columns [icol]);
 		}
 		/*
@@ -799,7 +800,7 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 		 * (This is safe: the sorting index may change only vacuously when numericizing.)
 		 * But this cannot be done before the previous block!
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			row -> sortingIndex = irow;
 		}
@@ -811,12 +812,12 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 		/*
 		 * Find stretches of identical factors.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
-			long rowmin = irow, rowmax = irow;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
+			integer rowmin = irow, rowmax = irow;
 			for (;;) {
 				bool identical = true;
 				if (++ rowmax > my rows.size) break;
-				for (long icol = 1; icol <= numberOfFactors; icol ++) {
+				for (integer icol = 1; icol <= numberOfFactors; icol ++) {
 					if (my rows.at [rowmax] -> cells [columns [icol]]. number !=
 						my rows.at [rowmin] -> cells [columns [icol]]. number)
 					{
@@ -832,41 +833,41 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 			 */
 			Table_insertRow (thee.get(), thy rows.size + 1);
 			{
-				long icol = 0;
-				for (long i = 1; i <= numberOfFactors; i ++) {
+				integer icol = 0;
+				for (integer i = 1; i <= numberOfFactors; i ++) {
 					++ icol;
 					Table_setStringValue (thee.get(), thy rows.size, icol,
 						my rows.at [rowmin] -> cells [columns [icol]]. string);
 				}
-				for (long i = 1; i <= numberToSum; i ++) {
+				for (integer i = 1; i <= numberToSum; i ++) {
 					++ icol;
-					double sum = 0.0;
-					for (long jrow = rowmin; jrow <= rowmax; jrow ++) {
+					real80 sum = 0.0;
+					for (integer jrow = rowmin; jrow <= rowmax; jrow ++) {
 						sum += my rows.at [jrow] -> cells [columns [icol]]. number;
 					}
-					Table_setNumericValue (thee.get(), thy rows.size, icol, sum);
+					Table_setNumericValue (thee.get(), thy rows.size, icol, (real) sum);
 				}
-				for (long i = 1; i <= numberToAverage; i ++) {
+				for (integer i = 1; i <= numberToAverage; i ++) {
 					++ icol;
 					double sum = 0.0;
-					for (long jrow = rowmin; jrow <= rowmax; jrow ++) {
+					for (integer jrow = rowmin; jrow <= rowmax; jrow ++) {
 						sum += my rows.at [jrow] -> cells [columns [icol]]. number;
 					}
 					Table_setNumericValue (thee.get(), thy rows.size, icol, sum / (rowmax - rowmin + 1));
 				}
-				for (long i = 1; i <= numberToMedianize; i ++) {
+				for (integer i = 1; i <= numberToMedianize; i ++) {
 					++ icol;
-					for (long jrow = rowmin; jrow <= rowmax; jrow ++) {
+					for (integer jrow = rowmin; jrow <= rowmax; jrow ++) {
 						sortingColumn [jrow] = my rows.at [jrow] -> cells [columns [icol]]. number;
 					}
 					NUMsort_d (rowmax - rowmin + 1, & sortingColumn [rowmin - 1]);
 					double median = NUMquantile (rowmax - rowmin + 1, & sortingColumn [rowmin - 1], 0.5);
 					Table_setNumericValue (thee.get(), thy rows.size, icol, median);
 				}
-				for (long i = 1; i <= numberToAverageLogarithmically; i ++) {
+				for (integer i = 1; i <= numberToAverageLogarithmically; i ++) {
 					++ icol;
-					double sum = 0.0;
-					for (long jrow = rowmin; jrow <= rowmax; jrow ++) {
+					real80 sum = 0.0;
+					for (integer jrow = rowmin; jrow <= rowmax; jrow ++) {
 						double value = my rows.at [jrow] -> cells [columns [icol]]. number;
 						if (value <= 0.0)
 							Melder_throw (
@@ -875,11 +876,11 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 								U" is not positive.\nCannot average logarithmically.");
 						sum += log (value);
 					}
-					Table_setNumericValue (thee.get(), thy rows.size, icol, exp (sum / (rowmax - rowmin + 1)));
+					Table_setNumericValue (thee.get(), thy rows.size, icol, exp (real (sum / (rowmax - rowmin + 1))));
 				}
-				for (long i = 1; i <= numberToMedianizeLogarithmically; i ++) {
+				for (integer i = 1; i <= numberToMedianizeLogarithmically; i ++) {
 					++ icol;
-					for (long jrow = rowmin; jrow <= rowmax; jrow ++) {
+					for (integer jrow = rowmin; jrow <= rowmax; jrow ++) {
 						double value = my rows.at [jrow] -> cells [columns [icol]]. number;
 						if (value <= 0.0)
 							Melder_throw (
@@ -904,16 +905,16 @@ autoTable Table_collapseRows (Table me, const char32 *factors_string, const char
 	}
 }
 
-static char32 ** _Table_getLevels (Table me, long column, long *numberOfLevels) {
+static char32 ** _Table_getLevels (Table me, integer column, integer *numberOfLevels) {
 	try {
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			row -> sortingIndex = irow;
 		}
-		long columns [2] = { 0, column };
+		integer columns [2] = { 0, column };
 		Table_sortRows_Assert (me, columns, 1);
 		*numberOfLevels = 0;
-		long irow = 1;
+		integer irow = 1;
 		while (irow <= my rows.size) {
 			double value = my rows.at [irow] -> cells [column]. number;
 			(*numberOfLevels) ++;
@@ -935,7 +936,7 @@ static char32 ** _Table_getLevels (Table me, long column, long *numberOfLevels)
 	}
 }
 
-autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long columnToTranspose, const char32 *columnsToExpand_string) {
+autoTable Table_rowsToColumns (Table me, const char32 *factors_string, integer columnToTranspose, const char32 *columnsToExpand_string) {
 	bool originalChanged = false;
 	try {
 		Melder_assert (factors_string);
@@ -945,24 +946,24 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 		 * Parse the two strings of tokens.
 		 */
 		autoMelderTokens factors_names (factors_string);
-		long numberOfFactors = factors_names.count();
+		integer numberOfFactors = factors_names.count();
 		if (numberOfFactors < 1)
 			Melder_throw (U"In order to nest table data, you must supply at least one independent variable.");
 		Table_columns_checkExist (me, factors_names.peek(), numberOfFactors);
 		autoMelderTokens columnsToExpand_names (columnsToExpand_string);
-		long numberToExpand = columnsToExpand_names.count();
+		integer numberToExpand = columnsToExpand_names.count();
 		if (numberToExpand < 1)
 			Melder_throw (U"In order to nest table data, you must supply at least one dependent variable (to expand).");
 		Table_columns_checkExist (me, columnsToExpand_names.peek(), numberToExpand);
 		Table_columns_checkCrossSectionEmpty (factors_names.peek(), numberOfFactors, columnsToExpand_names.peek(), numberToExpand);
-		long numberOfLevels = 0;
+		integer numberOfLevels = 0;
 		char32 ** dummy = _Table_getLevels (me, columnToTranspose, & numberOfLevels);
 		autostring32vector levels_names (dummy, 1, numberOfLevels);
 		/*
 		 * Get the column numbers for the factors.
 		 */
-		autoNUMvector <long> factorColumns (1, numberOfFactors);
-		for (long ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
+		autoNUMvector <integer> factorColumns (1, numberOfFactors);
+		for (integer ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
 			factorColumns [ifactor] = Table_findColumnIndexFromColumnLabel (me, factors_names [ifactor]);
 			/*
 			 * Make sure that all the columns in the original table that we will use in the nested table are defined.
@@ -972,8 +973,8 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 		/*
 		 * Get the column numbers for the expandable variables.
 		 */
-		autoNUMvector <long> columnsToExpand (1, numberToExpand);
-		for (long iexpand = 1; iexpand <= numberToExpand; iexpand ++) {
+		autoNUMvector <integer> columnsToExpand (1, numberToExpand);
+		for (integer iexpand = 1; iexpand <= numberToExpand; iexpand ++) {
 			columnsToExpand [iexpand] = Table_findColumnIndexFromColumnLabel (me, columnsToExpand_names [iexpand]);
 			Table_numericize_checkDefined (me, columnsToExpand [iexpand]);
 		}
@@ -982,14 +983,14 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 		 */
 		autoTable thee = Table_createWithoutColumnNames (0, numberOfFactors + (numberOfLevels * numberToExpand));
 		Melder_assert (thy numberOfColumns > 0);
-		for (long ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
+		for (integer ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
 			Table_setColumnLabel (thee.get(), ifactor, factors_names [ifactor]);
 		}
-		for (long iexpand = 1; iexpand <= numberToExpand; iexpand ++) {
-			for (long ilevel = 1; ilevel <= numberOfLevels; ilevel ++) {
+		for (integer iexpand = 1; iexpand <= numberToExpand; iexpand ++) {
+			for (integer ilevel = 1; ilevel <= numberOfLevels; ilevel ++) {
 				//Melder_casual (U"Number of factors: ", numberOfFactors);
 				//Melder_casual (U"Level: ", ilevel, U" out of ", numberOfLevels);
-				long columnNumber = numberOfFactors + (iexpand - 1) * numberOfLevels + ilevel;
+				integer columnNumber = numberOfFactors + (iexpand - 1) * numberOfLevels + ilevel;
 				//Melder_casual (U"Column number: ", columnNumber);
 				Table_setColumnLabel (thee.get(), columnNumber, Melder_cat (columnsToExpand_names [iexpand], U".", levels_names [ilevel]));
 			}
@@ -999,7 +1000,7 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 		 * (This is safe: the sorting index may change only vacuously when numericizing.)
 		 * But this cannot be done before the previous blocks that numericize!
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			row -> sortingIndex = irow;
 		}
@@ -1011,12 +1012,12 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 		/*
 		 * Find stretches of identical factors.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
-			long rowmin = irow, rowmax = irow;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
+			integer rowmin = irow, rowmax = irow;
 			for (;;) {
 				bool identical = true;
 				if (++ rowmax > my rows.size) break;
-				for (long ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
+				for (integer ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
 					if (my rows.at [rowmax] -> cells [factorColumns [ifactor]]. number !=
 						my rows.at [rowmin] -> cells [factorColumns [ifactor]]. number)
 					{
@@ -1039,16 +1040,16 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 			 */
 			Table_insertRow (thee.get(), thy rows.size + 1);
 			TableRow thyRow = thy rows.at [thy rows.size];
-			for (long ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
+			for (integer ifactor = 1; ifactor <= numberOfFactors; ifactor ++) {
 				Table_setStringValue (thee.get(), thy rows.size, ifactor,
 					my rows.at [rowmin] -> cells [factorColumns [ifactor]]. string);
 			}
-			for (long iexpand = 1; iexpand <= numberToExpand; iexpand ++) {
-				for (long jrow = rowmin; jrow <= rowmax; jrow ++) {
+			for (integer iexpand = 1; iexpand <= numberToExpand; iexpand ++) {
+				for (integer jrow = rowmin; jrow <= rowmax; jrow ++) {
 					TableRow myRow = my rows.at [jrow];
 					double value = myRow -> cells [columnsToExpand [iexpand]]. number;
-					long level = lround (myRow -> cells [columnToTranspose]. number);
-					long thyColumn = numberOfFactors + (iexpand - 1) * numberOfLevels + level;
+					integer level = lround (myRow -> cells [columnToTranspose]. number);
+					integer thyColumn = numberOfFactors + (iexpand - 1) * numberOfLevels + level;
 					if (thyRow -> cells [thyColumn]. string && ! warned) {
 						Melder_warning (U"Some information from the original table has not been included in the new table. "
 							U"You could perhaps add more factors.");
@@ -1070,11 +1071,11 @@ autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long colu
 autoTable Table_transpose (Table me) {
 	try {
 		autoTable thee = Table_createWithoutColumnNames (my numberOfColumns, 1 + my rows.size);
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 				Table_setStringValue (thee.get(), icol, 1, my columnHeaders [icol]. label);
 			}
-		for (long irow = 1; irow <= my rows.size; irow ++) {
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 				Table_setStringValue (thee.get(), icol, 1 + irow, Table_getStringValue_Assert (me, irow, icol));
 			}
 		}
@@ -1084,19 +1085,19 @@ autoTable Table_transpose (Table me) {
 	}
 }
 
-static long *cellCompare_columns, cellCompare_numberOfColumns;
+static integer *cellCompare_columns, cellCompare_numberOfColumns;
 
 static int cellCompare_NoError (const void *first, const void *second) {
 	TableRow me = * (TableRow *) first, thee = * (TableRow *) second;
-	for (long icol = 1; icol <= cellCompare_numberOfColumns; icol ++) {
+	for (integer icol = 1; icol <= cellCompare_numberOfColumns; icol ++) {
 		if (my cells [cellCompare_columns [icol]]. number < thy cells [cellCompare_columns [icol]]. number) return -1;
 		if (my cells [cellCompare_columns [icol]]. number > thy cells [cellCompare_columns [icol]]. number) return +1;
 	}
 	return 0;
 }
 
-void Table_sortRows_Assert (Table me, long *columns, long numberOfColumns) {
-	for (long icol = 1; icol <= numberOfColumns; icol ++) {
+void Table_sortRows_Assert (Table me, integer *columns, integer numberOfColumns) {
+	for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 		Table_numericize_Assert (me, columns [icol]);
 	}
 	cellCompare_columns = columns;
@@ -1107,11 +1108,11 @@ void Table_sortRows_Assert (Table me, long *columns, long numberOfColumns) {
 void Table_sortRows_string (Table me, const char32 *columns_string) {
 	try {
 		autoMelderTokens columns_tokens (columns_string);
-		long numberOfColumns = columns_tokens.count();
+		integer numberOfColumns = columns_tokens.count();
 		if (numberOfColumns < 1)
 			Melder_throw (me, U": you specified an empty list of columns.");
-		autoNUMvector <long> columns (1, numberOfColumns);
-		for (long icol = 1; icol <= numberOfColumns; icol ++) {
+		autoNUMvector <integer> columns (1, numberOfColumns);
+		for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 			columns [icol] = Table_findColumnIndexFromColumnLabel (me, columns_tokens [icol]);
 			if (columns [icol] == 0)
 				Melder_throw (U"Column \"", columns_tokens [icol], U"\" does not exist.");
@@ -1123,8 +1124,8 @@ void Table_sortRows_string (Table me, const char32 *columns_string) {
 }
 
 void Table_randomizeRows (Table me) noexcept {
-	for (long irow = 1; irow <= my rows.size; irow ++) {
-		long jrow = NUMrandomInteger (irow, my rows.size);
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
+		integer jrow = NUMrandomInteger (irow, my rows.size);
 		TableRow tmp = my rows.at [irow];
 		my rows.at [irow] = my rows.at [jrow];
 		my rows.at [jrow] = tmp;
@@ -1132,8 +1133,8 @@ void Table_randomizeRows (Table me) noexcept {
 }
 
 void Table_reflectRows (Table me) noexcept {
-	for (long irow = 1; irow <= my rows.size / 2; irow ++) {
-		long jrow = my rows.size + 1 - irow;
+	for (integer irow = 1; irow <= my rows.size / 2; irow ++) {
+		integer jrow = my rows.size + 1 - irow;
 		TableRow tmp = my rows.at [irow];
 		my rows.at [irow] = my rows.at [jrow];
 		my rows.at [jrow] = tmp;
@@ -1144,15 +1145,15 @@ autoTable Tables_append (OrderedOf<structTable>* me) {
 	try {
 		if (my size == 0) Melder_throw (U"Cannot add zero tables.");
 		Table thee = my at [1];
-		long nrow = thy rows.size;
-		long ncol = thy numberOfColumns;
+		integer nrow = thy rows.size;
+		integer ncol = thy numberOfColumns;
 		Table firstTable = thee;
-		for (long itab = 2; itab <= my size; itab ++) {
+		for (integer itab = 2; itab <= my size; itab ++) {
 			thee = my at [itab];
 			nrow += thy rows.size;
 			if (thy numberOfColumns != ncol)
 				Melder_throw (U"Numbers of columns do not match.");
-			for (long icol = 1; icol <= ncol; icol ++) {
+			for (integer icol = 1; icol <= ncol; icol ++) {
 				if (! Melder_equ (thy columnHeaders [icol]. label, firstTable -> columnHeaders [icol]. label))
 					Melder_throw (U"The label of column ", icol, U" of ", thee,
 						U" (", thy columnHeaders [icol]. label, U") does not match the label of column ", icol,
@@ -1160,15 +1161,15 @@ autoTable Tables_append (OrderedOf<structTable>* me) {
 			}
 		}
 		autoTable him = Table_createWithoutColumnNames (nrow, ncol);
-		for (long icol = 1; icol <= ncol; icol ++) {
+		for (integer icol = 1; icol <= ncol; icol ++) {
 			Table_setColumnLabel (him.get(), icol, thy columnHeaders [icol]. label);
 		}
 		nrow = 0;
-		for (long itab = 1; itab <= my size; itab ++) {
+		for (integer itab = 1; itab <= my size; itab ++) {
 			thee = my at [itab];
-			for (long irow = 1; irow <= thy rows.size; irow ++) {
+			for (integer irow = 1; irow <= thy rows.size; irow ++) {
 				nrow ++;
-				for (long icol = 1; icol <= ncol; icol ++) {
+				for (integer icol = 1; icol <= ncol; icol ++) {
 					Table_setStringValue (him.get(), nrow, icol, Table_getStringValue_Assert (thee, irow, icol));
 				}
 			}
@@ -1179,7 +1180,7 @@ autoTable Tables_append (OrderedOf<structTable>* me) {
 	}
 }
 
-void Table_appendSumColumn (Table me, long column1, long column2, const char32 *label) {   // safe
+void Table_appendSumColumn (Table me, integer column1, integer column2, const char32 *label) {   // safe
 	try {
 		/*
 		 * Check without change.
@@ -1189,7 +1190,7 @@ void Table_appendSumColumn (Table me, long column1, long column2, const char32 *
 		Table_numericize_checkDefined (me, column1);
 		Table_numericize_checkDefined (me, column2);
 		autoTable thee = Table_createWithoutColumnNames (my rows.size, 1);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			Table_setNumericValue (thee.get(), irow, 1, myRow -> cells [column1]. number + myRow -> cells [column2]. number);
 		}
@@ -1200,7 +1201,7 @@ void Table_appendSumColumn (Table me, long column1, long column2, const char32 *
 		/*
 		 * Change without error.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			TableRow thyRow = thy rows.at [irow];
 			TableCell myCell = & myRow -> cells [my numberOfColumns];
@@ -1214,7 +1215,7 @@ void Table_appendSumColumn (Table me, long column1, long column2, const char32 *
 	}
 }
 
-void Table_appendDifferenceColumn (Table me, long column1, long column2, const char32 *label) {   // safe
+void Table_appendDifferenceColumn (Table me, integer column1, integer column2, const char32 *label) {   // safe
 	try {
 		/*
 		 * Check without change.
@@ -1224,7 +1225,7 @@ void Table_appendDifferenceColumn (Table me, long column1, long column2, const c
 		Table_numericize_checkDefined (me, column1);
 		Table_numericize_checkDefined (me, column2);
 		autoTable thee = Table_createWithoutColumnNames (my rows.size, 1);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			Table_setNumericValue (thee.get(), irow, 1, myRow -> cells [column1]. number - myRow -> cells [column2]. number);
 		}
@@ -1235,7 +1236,7 @@ void Table_appendDifferenceColumn (Table me, long column1, long column2, const c
 		/*
 		 * Change without error.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			TableRow thyRow = thy rows.at [irow];
 			TableCell myCell = & myRow -> cells [my numberOfColumns];
@@ -1249,7 +1250,7 @@ void Table_appendDifferenceColumn (Table me, long column1, long column2, const c
 	}
 }
 
-void Table_appendProductColumn (Table me, long column1, long column2, const char32 *label) {   // safe
+void Table_appendProductColumn (Table me, integer column1, integer column2, const char32 *label) {   // safe
 	try {
 		/*
 		 * Check without change.
@@ -1259,7 +1260,7 @@ void Table_appendProductColumn (Table me, long column1, long column2, const char
 		Table_numericize_checkDefined (me, column1);
 		Table_numericize_checkDefined (me, column2);
 		autoTable thee = Table_createWithoutColumnNames (my rows.size, 1);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			Table_setNumericValue (thee.get(), irow, 1, myRow -> cells [column1]. number * myRow -> cells [column2]. number);
 		}
@@ -1270,7 +1271,7 @@ void Table_appendProductColumn (Table me, long column1, long column2, const char
 		/*
 		 * Change without error.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			TableRow thyRow = thy rows.at [irow];
 			TableCell myCell = & myRow -> cells [my numberOfColumns];
@@ -1284,7 +1285,7 @@ void Table_appendProductColumn (Table me, long column1, long column2, const char
 	}
 }
 
-void Table_appendQuotientColumn (Table me, long column1, long column2, const char32 *label) {   // safe
+void Table_appendQuotientColumn (Table me, integer column1, integer column2, const char32 *label) {   // safe
 	try {
 		/*
 		 * Check without change.
@@ -1294,9 +1295,9 @@ void Table_appendQuotientColumn (Table me, long column1, long column2, const cha
 		Table_numericize_checkDefined (me, column1);
 		Table_numericize_checkDefined (me, column2);
 		autoTable thee = Table_createWithoutColumnNames (my rows.size, 1);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
-			double value = myRow -> cells [column2]. number == 0.0 ? NUMundefined :
+			double value = myRow -> cells [column2]. number == 0.0 ? undefined :
 				myRow -> cells [column1]. number / myRow -> cells [column2]. number;
 			Table_setNumericValue (thee.get(), irow, 1, value);
 		}
@@ -1307,7 +1308,7 @@ void Table_appendQuotientColumn (Table me, long column1, long column2, const cha
 		/*
 		 * Change without error.
 		 */
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow myRow = my rows.at [irow];
 			TableRow thyRow = thy rows.at [irow];
 			TableCell myCell = & myRow -> cells [my numberOfColumns];
@@ -1321,14 +1322,14 @@ void Table_appendQuotientColumn (Table me, long column1, long column2, const cha
 	}
 }
 
-void Table_formula_columnRange (Table me, long fromColumn, long toColumn, const char32 *expression, Interpreter interpreter) {
+void Table_formula_columnRange (Table me, integer fromColumn, integer toColumn, const char32 *expression, Interpreter interpreter) {
 	try {
 		Table_checkSpecifiedColumnNumberWithinRange (me, fromColumn);
 		Table_checkSpecifiedColumnNumberWithinRange (me, toColumn);
 		Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_UNKNOWN, true);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
-			for (long icol = fromColumn; icol <= toColumn; icol ++) {
-				struct Formula_Result result;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
+			for (integer icol = fromColumn; icol <= toColumn; icol ++) {
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
 				if (result. expressionType == kFormula_EXPRESSION_TYPE_STRING) {
 					Table_setStringValue (me, irow, icol, result. result.stringResult);
@@ -1349,22 +1350,22 @@ void Table_formula_columnRange (Table me, long fromColumn, long toColumn, const
 	}
 }
 
-void Table_formula (Table me, long icol, const char32 *expression, Interpreter interpreter) {
+void Table_formula (Table me, integer icol, const char32 *expression, Interpreter interpreter) {
 	Table_formula_columnRange (me, icol, icol, expression, interpreter);
 }
 
-double Table_getCorrelation_pearsonR (Table me, long column1, long column2, double significanceLevel,
+double Table_getCorrelation_pearsonR (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_significance, double *out_lowerLimit, double *out_upperLimit)
 {
-	long n = my rows.size, irow;
+	integer n = my rows.size, irow;
 	double correlation;
 	double sum1 = 0.0, sum2 = 0.0, sum12 = 0.0, sum11 = 0.0, sum22 = 0.0, mean1, mean2;
-	if (out_significance) *out_significance = NUMundefined;
-	if (out_lowerLimit) *out_lowerLimit = NUMundefined;
-	if (out_upperLimit) *out_upperLimit = NUMundefined;
-	if (column1 < 1 || column1 > my numberOfColumns) return NUMundefined;
-	if (column2 < 1 || column2 > my numberOfColumns) return NUMundefined;
-	if (n < 2) return NUMundefined;
+	if (out_significance) *out_significance = undefined;
+	if (out_lowerLimit) *out_lowerLimit = undefined;
+	if (out_upperLimit) *out_upperLimit = undefined;
+	if (column1 < 1 || column1 > my numberOfColumns) return undefined;
+	if (column2 < 1 || column2 > my numberOfColumns) return undefined;
+	if (n < 2) return undefined;
 	Table_numericize_Assert (me, column1);
 	Table_numericize_Assert (me, column2);
 	for (irow = 1; irow <= n; irow ++) {
@@ -1381,12 +1382,12 @@ double Table_getCorrelation_pearsonR (Table me, long column1, long column2, doub
 		sum11 += d1 * d1;
 		sum22 += d2 * d2;
 	}
-	correlation = sum11 == 0.0 || sum22 == 0.0 ? NUMundefined : sum12 / sqrt (sum11 * sum22);
-	if (out_significance && NUMdefined (correlation) && n >= 3)
+	correlation = sum11 == 0.0 || sum22 == 0.0 ? undefined : sum12 / sqrt (sum11 * sum22);
+	if (out_significance && isdefined (correlation) && n >= 3)
 		*out_significance = fabs (correlation) == 1.0 ? 0.0 :
 			/* One-sided: */
 			NUMstudentQ (fabs (correlation) * sqrt ((n - 2) / (1 - correlation * correlation)), n - 2);
-	if ((out_lowerLimit || out_upperLimit) && NUMdefined (correlation) && n >= 4) {
+	if ((out_lowerLimit || out_upperLimit) && isdefined (correlation) && n >= 4) {
 		if (fabs (correlation) == 1.0) {
 			if (out_lowerLimit) *out_lowerLimit = correlation;
 			if (out_upperLimit) *out_upperLimit = correlation;
@@ -1402,22 +1403,22 @@ double Table_getCorrelation_pearsonR (Table me, long column1, long column2, doub
 	return correlation;
 }
 
-double Table_getCorrelation_kendallTau (Table me, long column1, long column2, double significanceLevel,
+double Table_getCorrelation_kendallTau (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_significance, double *out_lowerLimit, double *out_upperLimit)
 {
-	long n = my rows.size, irow, jrow;
+	integer n = my rows.size;
 	double correlation, denominator;
-	long numberOfConcordants = 0, numberOfDiscordants = 0, numberOfExtra1 = 0, numberOfExtra2 = 0;
-	if (out_significance) *out_significance = NUMundefined;
-	if (out_lowerLimit) *out_lowerLimit = NUMundefined;
-	if (out_upperLimit) *out_upperLimit = NUMundefined;
-	if (column1 < 1 || column1 > my numberOfColumns) return NUMundefined;
-	if (column2 < 1 || column2 > my numberOfColumns) return NUMundefined;
+	integer numberOfConcordants = 0, numberOfDiscordants = 0, numberOfExtra1 = 0, numberOfExtra2 = 0;
+	if (out_significance) *out_significance = undefined;
+	if (out_lowerLimit) *out_lowerLimit = undefined;
+	if (out_upperLimit) *out_upperLimit = undefined;
+	if (column1 < 1 || column1 > my numberOfColumns) return undefined;
+	if (column2 < 1 || column2 > my numberOfColumns) return undefined;
 	Table_numericize_Assert (me, column1);
 	Table_numericize_Assert (me, column2);
-	for (irow = 1; irow < n; irow ++) {
+	for (integer irow = 1; irow < n; irow ++) {
 		TableRow rowi = my rows.at [irow];
-		for (jrow = irow + 1; jrow <= n; jrow ++) {
+		for (integer jrow = irow + 1; jrow <= n; jrow ++) {
 			TableRow rowj = my rows.at [jrow];
 			double diff1 = rowi -> cells [column1]. number - rowj -> cells [column1]. number;
 			double diff2 = rowi -> cells [column2]. number - rowj -> cells [column2]. number;
@@ -1435,8 +1436,8 @@ double Table_getCorrelation_kendallTau (Table me, long column1, long column2, do
 	}
 	denominator = sqrt ((numberOfConcordants + numberOfDiscordants + numberOfExtra1) *
 		(numberOfConcordants + numberOfDiscordants + numberOfExtra2));
-	correlation = denominator == 0.0 ? NUMundefined : (numberOfConcordants - numberOfDiscordants) / denominator;
-	if ((out_significance || out_lowerLimit || out_upperLimit) && NUMdefined (correlation) && n >= 2) {
+	correlation = denominator == 0.0 ? undefined : (numberOfConcordants - numberOfDiscordants) / denominator;
+	if ((out_significance || out_lowerLimit || out_upperLimit) && isdefined (correlation) && n >= 2) {
 		double standardError = sqrt ((4 * n + 10.0) / (9 * n * (n - 1)));
 		if (out_significance)
 			*out_significance = NUMgaussQ (fabs (correlation) / standardError);   // one-sided
@@ -1448,36 +1449,36 @@ double Table_getCorrelation_kendallTau (Table me, long column1, long column2, do
 	return correlation;
 }
 
-double Table_getDifference_studentT (Table me, long column1, long column2, double significanceLevel,
+double Table_getDifference_studentT (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_t, double *out_numberOfDegreesOfFreedom, double *out_significance, double *out_lowerLimit, double *out_upperLimit)
 {
-	if (out_t) *out_t = NUMundefined;
-	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = NUMundefined;
-	if (out_significance) *out_significance = NUMundefined;
-	if (out_lowerLimit) *out_lowerLimit = NUMundefined;
-	if (out_upperLimit) *out_upperLimit = NUMundefined;
-	long n = my rows.size;
-	if (n < 1) return NUMundefined;
-	if (column1 < 1 || column1 > my numberOfColumns) return NUMundefined;
-	if (column2 < 1 || column2 > my numberOfColumns) return NUMundefined;
+	if (out_t) *out_t = undefined;
+	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = undefined;
+	if (out_significance) *out_significance = undefined;
+	if (out_lowerLimit) *out_lowerLimit = undefined;
+	if (out_upperLimit) *out_upperLimit = undefined;
+	integer n = my rows.size;
+	if (n < 1) return undefined;
+	if (column1 < 1 || column1 > my numberOfColumns) return undefined;
+	if (column2 < 1 || column2 > my numberOfColumns) return undefined;
 	Table_numericize_Assert (me, column1);
 	Table_numericize_Assert (me, column2);
-	double sum = 0.0;
-	for (long irow = 1; irow <= n; irow ++) {
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= n; irow ++) {
 		TableRow row = my rows.at [irow];
 		sum += row -> cells [column1]. number - row -> cells [column2]. number;
 	}
-	double meanDifference = sum / n;
-	long degreesOfFreedom = n - 1;
+	real meanDifference = (real) sum / n;
+	integer degreesOfFreedom = n - 1;
 	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = degreesOfFreedom;
 	if (degreesOfFreedom >= 1 && (out_t || out_significance || out_lowerLimit || out_upperLimit)) {
-		double sumOfSquares = 0.0;
-		for (long irow = 1; irow <= n; irow ++) {
+		real80 sumOfSquares = 0.0;
+		for (integer irow = 1; irow <= n; irow ++) {
 			TableRow row = my rows.at [irow];
-			double diff = (row -> cells [column1]. number - row -> cells [column2]. number) - meanDifference;
+			real diff = (row -> cells [column1]. number - row -> cells [column2]. number) - meanDifference;
 			sumOfSquares += diff * diff;
 		}
-		double standardError = sqrt (sumOfSquares / degreesOfFreedom / n);
+		real standardError = sqrt ((real) sumOfSquares / degreesOfFreedom / n);
 		if (out_t && standardError != 0.0 ) *out_t = meanDifference / standardError;
 		if (out_significance) *out_significance =
 			standardError == 0.0 ? 0.0 : NUMstudentQ (fabs (meanDifference) / standardError, degreesOfFreedom);
@@ -1489,33 +1490,34 @@ double Table_getDifference_studentT (Table me, long column1, long column2, doubl
 	return meanDifference;
 }
 
-double Table_getMean_studentT (Table me, long column, double significanceLevel,
+double Table_getMean_studentT (Table me, integer column, double significanceLevel,
 	double *out_tFromZero, double *out_numberOfDegreesOfFreedom, double *out_significanceFromZero, double *out_lowerLimit, double *out_upperLimit)
 {
-	double mean = 0.0, var = 0.0, standardError;
-	long n = my rows.size;
-	if (out_tFromZero) *out_tFromZero = NUMundefined;
-	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = NUMundefined;
-	if (out_significanceFromZero) *out_significanceFromZero = NUMundefined;
-	if (out_lowerLimit) *out_lowerLimit = NUMundefined;
-	if (out_upperLimit) *out_upperLimit = NUMundefined;
-	if (n < 1) return NUMundefined;
-	if (column < 1 || column > my numberOfColumns) return NUMundefined;
-	long degreesOfFreedom = n - 1;
+	integer n = my rows.size;
+	if (out_tFromZero) *out_tFromZero = undefined;
+	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = undefined;
+	if (out_significanceFromZero) *out_significanceFromZero = undefined;
+	if (out_lowerLimit) *out_lowerLimit = undefined;
+	if (out_upperLimit) *out_upperLimit = undefined;
+	if (n < 1) return undefined;
+	if (column < 1 || column > my numberOfColumns) return undefined;
+	integer degreesOfFreedom = n - 1;
 	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = degreesOfFreedom;
 	Table_numericize_Assert (me, column);
-	for (long irow = 1; irow <= n; irow ++) {
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= n; irow ++) {
 		TableRow row = my rows.at [irow];
-		mean += row -> cells [column]. number;
+		sum += row -> cells [column]. number;
 	}
-	mean /= n;
+	real mean = real (sum / n);
 	if (n >= 2 && (out_tFromZero || out_significanceFromZero || out_lowerLimit || out_upperLimit)) {
-		for (long irow = 1; irow <= n; irow ++) {
+		real80 sumOfSquares = 0.0;
+		for (integer irow = 1; irow <= n; irow ++) {
 			TableRow row = my rows.at [irow];
-			double diff = row -> cells [column]. number - mean;
-			var += diff * diff;
+			real diff = row -> cells [column]. number - mean;
+			sumOfSquares += diff * diff;
 		}
-		standardError = sqrt (var / degreesOfFreedom / n);
+		real standardError = sqrt ((real) sumOfSquares / degreesOfFreedom / n);
 		if (out_tFromZero && standardError != 0.0 ) *out_tFromZero = mean / standardError;
 		if (out_significanceFromZero) *out_significanceFromZero =
 			standardError == 0.0 ? 0.0 : NUMstudentQ (fabs (mean) / standardError, degreesOfFreedom);
@@ -1527,19 +1529,19 @@ double Table_getMean_studentT (Table me, long column, double significanceLevel,
 	return mean;
 }
 
-double Table_getGroupMean_studentT (Table me, long column, long groupColumn, const char32 *group, double significanceLevel,
+double Table_getGroupMean_studentT (Table me, integer column, integer groupColumn, const char32 *group, double significanceLevel,
 	double *out_tFromZero, double *out_numberOfDegreesOfFreedom, double *out_significanceFromZero, double *out_lowerLimit, double *out_upperLimit)
 {
-	if (out_tFromZero) *out_tFromZero = NUMundefined;
-	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = NUMundefined;
-	if (out_significanceFromZero) *out_significanceFromZero = NUMundefined;
-	if (out_lowerLimit) *out_lowerLimit = NUMundefined;
-	if (out_upperLimit) *out_upperLimit = NUMundefined;
-	if (column < 1 || column > my numberOfColumns) return NUMundefined;
+	if (out_tFromZero) *out_tFromZero = undefined;
+	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = undefined;
+	if (out_significanceFromZero) *out_significanceFromZero = undefined;
+	if (out_lowerLimit) *out_lowerLimit = undefined;
+	if (out_upperLimit) *out_upperLimit = undefined;
+	if (column < 1 || column > my numberOfColumns) return undefined;
 	Table_numericize_Assert (me, column);
-	long n = 0;
-	double sum = 0.0;
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	integer n = 0;
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
 		if (row -> cells [groupColumn]. string) {
 			if (str32equ (row -> cells [groupColumn]. string, group)) {
@@ -1548,22 +1550,22 @@ double Table_getGroupMean_studentT (Table me, long column, long groupColumn, con
 			}
 		}
 	}
-	if (n < 1) return NUMundefined;
-	double mean = sum / n;
-	long degreesOfFreedom = n - 1;
+	if (n < 1) return undefined;
+	real mean = (real) sum / n;
+	integer degreesOfFreedom = n - 1;
 	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = degreesOfFreedom;
 	if (degreesOfFreedom >= 1 && (out_tFromZero || out_significanceFromZero || out_lowerLimit || out_upperLimit)) {
-		double sumOfSquares = 0.0;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		real80 sumOfSquares = 0.0;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (row -> cells [groupColumn]. string) {
 				if (str32equ (row -> cells [groupColumn]. string, group)) {
-					double diff = row -> cells [column]. number - mean;
+					real diff = row -> cells [column]. number - mean;
 					sumOfSquares += diff * diff;
 				}
 			}
 		}
-		double standardError = sqrt (sumOfSquares / degreesOfFreedom / n);
+		real standardError = sqrt ((real) sumOfSquares / degreesOfFreedom / n);
 		if (out_tFromZero && standardError != 0.0 ) *out_tFromZero = mean / standardError;
 		if (out_significanceFromZero) *out_significanceFromZero =
 			standardError == 0.0 ? 0.0 : NUMstudentQ (fabs (mean) / standardError, degreesOfFreedom);
@@ -1575,20 +1577,20 @@ double Table_getGroupMean_studentT (Table me, long column, long groupColumn, con
 	return mean;
 }
 
-double Table_getGroupDifference_studentT (Table me, long column, long groupColumn, const char32 *group1, const char32 *group2, double significanceLevel,
+double Table_getGroupDifference_studentT (Table me, integer column, integer groupColumn, const char32 *group1, const char32 *group2, double significanceLevel,
 	double *out_tFromZero, double *out_numberOfDegreesOfFreedom, double *out_significanceFromZero, double *out_lowerLimit, double *out_upperLimit)
 {
-	if (out_tFromZero) *out_tFromZero = NUMundefined;
-	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = NUMundefined;
-	if (out_significanceFromZero) *out_significanceFromZero = NUMundefined;
-	if (out_lowerLimit) *out_lowerLimit = NUMundefined;
-	if (out_upperLimit) *out_upperLimit = NUMundefined;
-	if (column < 1 || column > my numberOfColumns) return NUMundefined;
-	if (groupColumn < 1 || groupColumn > my numberOfColumns) return NUMundefined;
+	if (out_tFromZero) *out_tFromZero = undefined;
+	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = undefined;
+	if (out_significanceFromZero) *out_significanceFromZero = undefined;
+	if (out_lowerLimit) *out_lowerLimit = undefined;
+	if (out_upperLimit) *out_upperLimit = undefined;
+	if (column < 1 || column > my numberOfColumns) return undefined;
+	if (groupColumn < 1 || groupColumn > my numberOfColumns) return undefined;
 	Table_numericize_Assert (me, column);
-	long n1 = 0, n2 = 0;
-	double sum1 = 0.0, sum2 = 0.0;
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	integer n1 = 0, n2 = 0;
+	real80 sum1 = 0.0, sum2 = 0.0;
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
 		if (row -> cells [groupColumn]. string) {
 			if (str32equ (row -> cells [groupColumn]. string, group1)) {
@@ -1600,27 +1602,27 @@ double Table_getGroupDifference_studentT (Table me, long column, long groupColum
 			}
 		}
 	}
-	if (n1 < 1 || n2 < 1) return NUMundefined;
-	long degreesOfFreedom = n1 + n2 - 2;
+	if (n1 < 1 || n2 < 1) return undefined;
+	integer degreesOfFreedom = n1 + n2 - 2;
 	if (out_numberOfDegreesOfFreedom) *out_numberOfDegreesOfFreedom = degreesOfFreedom;
-	double mean1 = sum1 / n1;
-	double mean2 = sum2 / n2;
-	double difference = mean1 - mean2;
+	real mean1 = (real) sum1 / n1;
+	real mean2 = (real) sum2 / n2;
+	real difference = mean1 - mean2;
 	if (degreesOfFreedom >= 1 && (out_tFromZero || out_significanceFromZero || out_lowerLimit || out_upperLimit)) {
-		double sumOfSquares = 0.0;
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		real80 sumOfSquares = 0.0;
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			TableRow row = my rows.at [irow];
 			if (row -> cells [groupColumn]. string) {
 				if (str32equ (row -> cells [groupColumn]. string, group1)) {
-					double diff = row -> cells [column]. number - mean1;
+					real diff = row -> cells [column]. number - mean1;
 					sumOfSquares += diff * diff;
 				} else if (str32equ (row -> cells [groupColumn]. string, group2)) {
-					double diff = row -> cells [column]. number - mean2;
+					real diff = row -> cells [column]. number - mean2;
 					sumOfSquares += diff * diff;
 				}
 			}
 		}
-		double standardError = sqrt (sumOfSquares / degreesOfFreedom * (1.0 / n1 + 1.0 / n2));
+		real standardError = sqrt ((real) sumOfSquares / degreesOfFreedom * (1.0 / n1 + 1.0 / n2));
 		if (out_tFromZero && standardError != 0.0 ) *out_tFromZero = difference / standardError;
 		if (out_significanceFromZero) *out_significanceFromZero =
 			standardError == 0.0 ? 0.0 : NUMstudentQ (fabs (difference) / standardError, degreesOfFreedom);
@@ -1632,16 +1634,16 @@ double Table_getGroupDifference_studentT (Table me, long column, long groupColum
 	return difference;
 }
 
-double Table_getGroupDifference_wilcoxonRankSum (Table me, long column, long groupColumn, const char32 *group1, const char32 *group2,
+double Table_getGroupDifference_wilcoxonRankSum (Table me, integer column, integer groupColumn, const char32 *group1, const char32 *group2,
 	double *out_rankSum, double *out_significanceFromZero)
 {
-	if (out_rankSum) *out_rankSum = NUMundefined;
-	if (out_significanceFromZero) *out_significanceFromZero = NUMundefined;
-	if (column < 1 || column > my numberOfColumns) return NUMundefined;
-	if (groupColumn < 1 || groupColumn > my numberOfColumns) return NUMundefined;
+	if (out_rankSum) *out_rankSum = undefined;
+	if (out_significanceFromZero) *out_significanceFromZero = undefined;
+	if (column < 1 || column > my numberOfColumns) return undefined;
+	if (groupColumn < 1 || groupColumn > my numberOfColumns) return undefined;
 	Table_numericize_Assert (me, column);
-	long n1 = 0, n2 = 0;
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	integer n1 = 0, n2 = 0;
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
 		if (row -> cells [groupColumn]. string) {
 			if (str32equ (row -> cells [groupColumn]. string, group1)) {
@@ -1651,10 +1653,10 @@ double Table_getGroupDifference_wilcoxonRankSum (Table me, long column, long gro
 			}
 		}
 	}
-	long n = n1 + n2;
-	if (n1 < 1 || n2 < 1 || n < 3) return NUMundefined;
+	integer n = n1 + n2;
+	if (n1 < 1 || n2 < 1 || n < 3) return undefined;
 	autoTable ranks = Table_createWithoutColumnNames (n, 3);   // column 1 = group, 2 = value, 3 = rank
-	for (long irow = 1, jrow = 0; irow <= my rows.size; irow ++) {
+	for (integer irow = 1, jrow = 0; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
 		if (row -> cells [groupColumn]. string) {
 			if (str32equ (row -> cells [groupColumn]. string, group1)) {
@@ -1669,13 +1671,13 @@ double Table_getGroupDifference_wilcoxonRankSum (Table me, long column, long gro
 	Table_numericize_Assert (ranks.get(), 1);
 	Table_numericize_Assert (ranks.get(), 2);
 	Table_numericize_Assert (ranks.get(), 3);
-	long columns [1+1] = { 0, 2 };   // we're gonna sort by column 2
+	integer columns [1+1] = { 0, 2 };   // we're gonna sort by column 2
 	Table_sortRows_Assert (ranks.get(), columns, 1);   // we sort by one column only
 	double totalNumberOfTies3 = 0.0;
-	for (long irow = 1; irow <= ranks -> rows.size; irow ++) {
+	for (integer irow = 1; irow <= ranks -> rows.size; irow ++) {
 		TableRow row = ranks -> rows.at [irow];
 		double value = row -> cells [2]. number;
-		long rowOfLastTie = irow + 1;
+		integer rowOfLastTie = irow + 1;
 		for (; rowOfLastTie <= ranks -> rows.size; rowOfLastTie ++) {
 			TableRow row2 = ranks -> rows.at [rowOfLastTie];
 			double value2 = row2 -> cells [2]. number;
@@ -1683,39 +1685,40 @@ double Table_getGroupDifference_wilcoxonRankSum (Table me, long column, long gro
 		}
 		rowOfLastTie --;
 		double averageRank = 0.5 * ((double) irow + (double) rowOfLastTie);
-		for (long jrow = irow; jrow <= rowOfLastTie; jrow ++) {
+		for (integer jrow = irow; jrow <= rowOfLastTie; jrow ++) {
 			Table_setNumericValue (ranks.get(), jrow, 3, averageRank);
 		}
-		long numberOfTies = rowOfLastTie - irow + 1;
+		integer numberOfTies = rowOfLastTie - irow + 1;
 		totalNumberOfTies3 += (double) (numberOfTies - 1) * (double) numberOfTies * (double) (numberOfTies + 1);
 	}
 	Table_numericize_Assert (ranks.get(), 3);
-	double maximumRankSum = (double) n1 * (double) n2, rankSum = 0.0;
-	for (long irow = 1; irow <= ranks -> rows.size; irow ++) {
+	double maximumRankSum = (double) n1 * (double) n2;
+	real80 rankSum = 0.0;
+	for (integer irow = 1; irow <= ranks -> rows.size; irow ++) {
 		TableRow row = ranks -> rows.at [irow];
 		if (row -> cells [1]. number == 1.0) rankSum += row -> cells [3]. number;
 	}
 	rankSum -= 0.5 * (double) n1 * ((double) n1 + 1.0);
 	double stdev = sqrt (maximumRankSum * ((double) n + 1.0 - totalNumberOfTies3 / n / (n - 1)) / 12.0);
-	if (out_rankSum) *out_rankSum = rankSum;
-	if (out_significanceFromZero) *out_significanceFromZero = NUMgaussQ (fabs (rankSum - 0.5 * maximumRankSum) / stdev);
-	return rankSum / maximumRankSum;
+	if (out_rankSum) *out_rankSum = (real) rankSum;
+	if (out_significanceFromZero) *out_significanceFromZero = NUMgaussQ (fabs ((real) rankSum - 0.5 * maximumRankSum) / stdev);
+	return (real) rankSum / maximumRankSum;
 }
 
-double Table_getFisherF (Table me, long col1, long col2);
-double Table_getOneWayAnovaSignificance (Table me, long col1, long col2);
-double Table_getFisherFLowerLimit (Table me, long col1, long col2, double significanceLevel);
-double Table_getFisherFUpperLimit (Table me, long col1, long col2, double significanceLevel);
+double Table_getFisherF (Table me, integer col1, integer col2);
+double Table_getOneWayAnovaSignificance (Table me, integer col1, integer col2);
+double Table_getFisherFLowerLimit (Table me, integer col1, integer col2, double significanceLevel);
+double Table_getFisherFUpperLimit (Table me, integer col1, integer col2, double significanceLevel);
 
-bool Table_getExtrema (Table me, long icol, double *minimum, double *maximum) {
-	long n = my rows.size, irow;
+bool Table_getExtrema (Table me, integer icol, double *minimum, double *maximum) {
+	integer n = my rows.size;
 	if (icol < 1 || icol > my numberOfColumns || n == 0) {
-		*minimum = *maximum = NUMundefined;
+		*minimum = *maximum = undefined;
 		return false;
 	}
 	Table_numericize_Assert (me, icol);
 	*minimum = *maximum = my rows.at [1] -> cells [icol]. number;
-	for (irow = 2; irow <= n; irow ++) {
+	for (integer irow = 2; irow <= n; irow ++) {
 		double value = my rows.at [irow] -> cells [icol]. number;
 		if (value < *minimum) *minimum = value;
 		if (value > *maximum) *maximum = value;
@@ -1723,10 +1726,9 @@ bool Table_getExtrema (Table me, long icol, double *minimum, double *maximum) {
 	return true;
 }
 
-void Table_scatterPlot_mark (Table me, Graphics g, long xcolumn, long ycolumn,
-	double xmin, double xmax, double ymin, double ymax, double markSize_mm, const char32 *mark, int garnish)
+void Table_scatterPlot_mark (Table me, Graphics g, integer xcolumn, integer ycolumn,
+	double xmin, double xmax, double ymin, double ymax, double markSize_mm, const char32 *mark, bool garnish)
 {
-	long n = my rows.size, irow;
 	if (xcolumn < 1 || xcolumn > my numberOfColumns || ycolumn < 1 || ycolumn > my numberOfColumns) return;
 	Table_numericize_Assert (me, xcolumn);
 	Table_numericize_Assert (me, ycolumn);
@@ -1742,7 +1744,8 @@ void Table_scatterPlot_mark (Table me, Graphics g, long xcolumn, long ycolumn,
 	Graphics_setWindow (g, xmin, xmax, ymin, ymax);
 
 	Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
-	for (irow = 1; irow <= n; irow ++) {
+	integer n = my rows.size;
+	for (integer irow = 1; irow <= n; irow ++) {
 		TableRow row = my rows.at [irow];
 		Graphics_mark (g, row -> cells [xcolumn]. number, row -> cells [ycolumn]. number, markSize_mm, mark);
 	}
@@ -1758,10 +1761,9 @@ void Table_scatterPlot_mark (Table me, Graphics g, long xcolumn, long ycolumn,
 	}
 }
 
-void Table_scatterPlot (Table me, Graphics g, long xcolumn, long ycolumn,
-	double xmin, double xmax, double ymin, double ymax, long markColumn, int fontSize, int garnish)
+void Table_scatterPlot (Table me, Graphics g, integer xcolumn, integer ycolumn,
+	double xmin, double xmax, double ymin, double ymax, integer markColumn, int fontSize, bool garnish)
 {
-	long n = my rows.size;
 	int saveFontSize = Graphics_inqFontSize (g);
 	if (xcolumn < 1 || xcolumn > my numberOfColumns || ycolumn < 1 || ycolumn > my numberOfColumns) return;
 	Table_numericize_Assert (me, xcolumn);
@@ -1779,7 +1781,8 @@ void Table_scatterPlot (Table me, Graphics g, long xcolumn, long ycolumn,
 
 	Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
 	Graphics_setFontSize (g, fontSize);
-	for (long irow = 1; irow <= n; irow ++) {
+	integer n = my rows.size;
+	for (integer irow = 1; irow <= n; irow ++) {
 		TableRow row = my rows.at [irow];
 		const char32 *mark = row -> cells [markColumn]. string;
 		if (mark)
@@ -1798,8 +1801,8 @@ void Table_scatterPlot (Table me, Graphics g, long xcolumn, long ycolumn,
 	}
 }
 
-void Table_drawEllipse_e (Table me, Graphics g, long xcolumn, long ycolumn,
-	double xmin, double xmax, double ymin, double ymax, double numberOfSigmas, int garnish)
+void Table_drawEllipse_e (Table me, Graphics g, integer xcolumn, integer ycolumn,
+	double xmin, double xmax, double ymin, double ymax, double numberOfSigmas, bool garnish)
 {
 	try {
 		if (xcolumn < 1 || xcolumn > my numberOfColumns || ycolumn < 1 || ycolumn > my numberOfColumns) return;
@@ -1814,7 +1817,7 @@ void Table_drawEllipse_e (Table me, Graphics g, long xcolumn, long ycolumn,
 			if (ymin == ymax) ymin -= 0.5, ymax += 0.5;
 		}
 		autoTableOfReal tableOfReal = TableOfReal_create (my rows.size, 2);
-		for (long irow = 1; irow <= my rows.size; irow ++) {
+		for (integer irow = 1; irow <= my rows.size; irow ++) {
 			tableOfReal -> data [irow] [1] = Table_getNumericValue_Assert (me, irow, xcolumn);
 			tableOfReal -> data [irow] [2] = Table_getNumericValue_Assert (me, irow, ycolumn);
 		}
@@ -1835,18 +1838,18 @@ void Table_list (Table me, bool includeRowNumbers) {
 		MelderInfo_write (U"row");
 		if (my numberOfColumns > 0) MelderInfo_write (U"\t");
 	}
-	for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 		if (icol > 1) MelderInfo_write (U"\t");
 		MelderInfo_write (visibleString (my columnHeaders [icol]. label));
 	}
 	MelderInfo_write (U"\n");
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		if (includeRowNumbers) {
 			MelderInfo_write (irow);
 			if (my numberOfColumns > 0) MelderInfo_write (U"\t");
 		}
 		TableRow row = my rows.at [irow];
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			if (icol > 1) MelderInfo_write (U"\t");
 			MelderInfo_write (visibleString (row -> cells [icol]. string));
 		}
@@ -1857,15 +1860,15 @@ void Table_list (Table me, bool includeRowNumbers) {
 
 static void _Table_writeToCharacterSeparatedFile (Table me, MelderFile file, char32 kar) {
 	autoMelderString buffer;
-	for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 		if (icol != 1) MelderString_appendCharacter (& buffer, kar);
 		char32 *s = my columnHeaders [icol]. label;
 		MelderString_append (& buffer, ( s && s [0] != U'\0' ? s : U"?" ));
 	}
 	MelderString_appendCharacter (& buffer, U'\n');
-	for (long irow = 1; irow <= my rows.size; irow ++) {
+	for (integer irow = 1; irow <= my rows.size; irow ++) {
 		TableRow row = my rows.at [irow];
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			if (icol != 1) MelderString_appendCharacter (& buffer, kar);
 			char32 *s = row -> cells [icol]. string;
 			MelderString_append (& buffer, ( s && s [0] != U'\0' ? s : U"?" ));
@@ -1894,11 +1897,10 @@ void Table_writeToCommaSeparatedFile (Table me, MelderFile file) {
 autoTable Table_readFromTableFile (MelderFile file) {
 	try {
 		autostring32 string = MelderFile_readText (file);
-		long nrow, ncol, nelements;
 		/*
 		 * Count columns.
 		 */
-		ncol = 0;
+		integer ncol = 0;
 		char32 *p = & string [0];
 		for (;;) {
 			char32 kar = *p++;
@@ -1914,7 +1916,7 @@ autoTable Table_readFromTableFile (MelderFile file) {
 		 * Count elements.
 		 */
 		p = & string [0];
-		nelements = 0;
+		integer nelements = 0;
 		for (;;) {
 			char32 kar = *p++;
 			if (kar == U'\0') break;
@@ -1933,26 +1935,26 @@ autoTable Table_readFromTableFile (MelderFile file) {
 		/*
 		 * Create empty table.
 		 */
-		nrow = nelements / ncol - 1;
+		integer nrow = nelements / ncol - 1;
 		autoTable me = Table_create (nrow, ncol);
 
 		/*
 		 * Read elements.
 		 */
 		p = & string [0];
-		for (long icol = 1; icol <= ncol; icol ++) {
+		for (integer icol = 1; icol <= ncol; icol ++) {
 			while (*p == U' ' || *p == U'\t') { Melder_assert (*p != U'\0'); p ++; }
-			static MelderString buffer { 0 };
+			static MelderString buffer { };
 			MelderString_empty (& buffer);
 			while (*p != U' ' && *p != U'\t' && *p != U'\n') { MelderString_appendCharacter (& buffer, *p); p ++; }
 			Table_setColumnLabel (me.get(), icol, buffer.string);
 			MelderString_empty (& buffer);
 		}
-		for (long irow = 1; irow <= nrow; irow ++) {
+		for (integer irow = 1; irow <= nrow; irow ++) {
 			TableRow row = my rows.at [irow];
-			for (long icol = 1; icol <= ncol; icol ++) {
+			for (integer icol = 1; icol <= ncol; icol ++) {
 				while (*p == U' ' || *p == U'\t' || *p == U'\n') { Melder_assert (*p != U'\0'); p ++; }
-				static MelderString buffer { 0 };
+				static MelderString buffer { };
 				MelderString_empty (& buffer);
 				while (*p != U' ' && *p != U'\t' && *p != U'\n' && *p != U'\0') { MelderString_appendCharacter (& buffer, *p); p ++; }
 				row -> cells [icol]. string = Melder_dup_f (buffer.string);
@@ -1972,12 +1974,17 @@ autoTable Table_readFromCharacterSeparatedTextFile (MelderFile file, char32 sepa
 		/*
 		 * Kill final new-line symbols.
 		 */
-		for (int64 length = str32len (string.peek()); length > 0 && string [length - 1] == U'\n'; length = str32len (string.peek())) string [length - 1] = U'\0';
+		for (int64 length = str32len (string.peek());
+		     length > 0 && string [length - 1] == U'\n';
+			 length = str32len (string.peek()))
+		{
+			string [length - 1] = U'\0';
+		}
 
 		/*
 		 * Count columns.
 		 */
-		long ncol = 1;
+		integer ncol = 1;
 		const char32 *p = & string [0];
 		for (;;) {
 			char32 kar = *p++;
@@ -1989,7 +1996,7 @@ autoTable Table_readFromCharacterSeparatedTextFile (MelderFile file, char32 sepa
 		/*
 		 * Count rows.
 		 */
-		long nrow = 1;
+		integer nrow = 1;
 		for (;;) {
 			char32 kar = *p++;
 			if (kar == U'\0') break;
@@ -2006,7 +2013,7 @@ autoTable Table_readFromCharacterSeparatedTextFile (MelderFile file, char32 sepa
 		 */
 		autoMelderString buffer;
 		p = & string [0];
-		for (long icol = 1; icol <= ncol; icol ++) {
+		for (integer icol = 1; icol <= ncol; icol ++) {
 			MelderString_empty (& buffer);
 			while (*p != separator && *p != U'\n') {
 				Melder_assert (*p != U'\0');
@@ -2020,9 +2027,9 @@ autoTable Table_readFromCharacterSeparatedTextFile (MelderFile file, char32 sepa
 		/*
 		 * Read cells.
 		 */
-		for (long irow = 1; irow <= nrow; irow ++) {
+		for (integer irow = 1; irow <= nrow; irow ++) {
 			TableRow row = my rows.at [irow];
-			for (long icol = 1; icol <= ncol; icol ++) {
+			for (integer icol = 1; icol <= ncol; icol ++) {
 				MelderString_empty (& buffer);
 				while (*p != separator && *p != U'\n' && *p != U'\0') {
 					MelderString_appendCharacter (& buffer, *p);
diff --git a/stat/Table.h b/stat/Table.h
index 95c8ff0..790de83 100644
--- a/stat/Table.h
+++ b/stat/Table.h
@@ -24,85 +24,85 @@ Thing_declare (Interpreter);
 
 #include "Table_def.h"
 
-void Table_initWithColumnNames (Table me, long numberOfRows, const char32 *columnNames);
-autoTable Table_createWithColumnNames (long numberOfRows, const char32 *columnNames);
-void Table_initWithoutColumnNames (Table me, long numberOfRows, long numberOfColumns);
-autoTable Table_createWithoutColumnNames (long numberOfRows, long numberOfColumns);
+void Table_initWithColumnNames (Table me, integer numberOfRows, const char32 *columnNames);
+autoTable Table_createWithColumnNames (integer numberOfRows, const char32 *columnNames);
+void Table_initWithoutColumnNames (Table me, integer numberOfRows, integer numberOfColumns);
+autoTable Table_createWithoutColumnNames (integer numberOfRows, integer numberOfColumns);
 #define Table_create Table_createWithoutColumnNames
 
 autoTable Tables_append (OrderedOf<structTable>* me);
 void Table_appendRow (Table me);
 void Table_appendColumn (Table me, const char32 *label);
-void Table_appendSumColumn (Table me, long column1, long column2, const char32 *label);
-void Table_appendDifferenceColumn (Table me, long column1, long column2, const char32 *label);
-void Table_appendProductColumn (Table me, long column1, long column2, const char32 *label);
-void Table_appendQuotientColumn (Table me, long column1, long column2, const char32 *label);
-void Table_removeRow (Table me, long row);
-void Table_removeColumn (Table me, long column);
-void Table_insertRow (Table me, long row);
-void Table_insertColumn (Table me, long column, const char32 *label /* cattable */);
-void Table_setColumnLabel (Table me, long column, const char32 *label /* cattable */);
-long Table_findColumnIndexFromColumnLabel (Table me, const char32 *label) noexcept;
-long Table_getColumnIndexFromColumnLabel (Table me, const char32 *columnLabel);
-long * Table_getColumnIndicesFromColumnLabelString (Table me, const char32 *string, long *numberOfTokens);
-long Table_searchColumn (Table me, long column, const char32 *value) noexcept;
+void Table_appendSumColumn (Table me, integer column1, integer column2, const char32 *label);
+void Table_appendDifferenceColumn (Table me, integer column1, integer column2, const char32 *label);
+void Table_appendProductColumn (Table me, integer column1, integer column2, const char32 *label);
+void Table_appendQuotientColumn (Table me, integer column1, integer column2, const char32 *label);
+void Table_removeRow (Table me, integer row);
+void Table_removeColumn (Table me, integer column);
+void Table_insertRow (Table me, integer row);
+void Table_insertColumn (Table me, integer column, const char32 *label /* cattable */);
+void Table_setColumnLabel (Table me, integer column, const char32 *label /* cattable */);
+integer Table_findColumnIndexFromColumnLabel (Table me, const char32 *label) noexcept;
+integer Table_getColumnIndexFromColumnLabel (Table me, const char32 *columnLabel);
+integer * Table_getColumnIndicesFromColumnLabelString (Table me, const char32 *string, integer *numberOfTokens);
+integer Table_searchColumn (Table me, integer column, const char32 *value) noexcept;
 
 /*
  * Procedure for reading strings or numbers from table cells:
  * use the following two calls exclusively.
  */
-const char32 * Table_getStringValue_Assert (Table me, long row, long column);
-double Table_getNumericValue_Assert (Table me, long row, long column);
+const char32 * Table_getStringValue_Assert (Table me, integer row, integer column);
+double Table_getNumericValue_Assert (Table me, integer row, integer column);
 
 /*
  * Procedure for writing strings or numbers into table cells:
  * use the following two calls exclusively.
  */
-void Table_setStringValue (Table me, long rowNumber, long columnNumber, const char32 *value /* cattable */);
-void Table_setNumericValue (Table me, long row, long column, double value);
+void Table_setStringValue (Table me, integer rowNumber, integer columnNumber, const char32 *value /* cattable */);
+void Table_setNumericValue (Table me, integer row, integer column, double value);
 
 /* For optimizations only (e.g. conversion to Matrix or TableOfReal). */
-void Table_numericize_Assert (Table me, long columnNumber);
+void Table_numericize_Assert (Table me, integer columnNumber);
 
-double Table_getQuantile (Table me, long column, double quantile);
-double Table_getMean (Table me, long column);
-double Table_getMaximum (Table me, long icol);
-double Table_getMinimum (Table me, long icol);
-double Table_getGroupMean (Table me, long column, long groupColumn, const char32 *group);
-double Table_getStdev (Table me, long column);
-long Table_drawRowFromDistribution (Table me, long column);
-double Table_getCorrelation_pearsonR (Table me, long column1, long column2, double significanceLevel,
+double Table_getQuantile (Table me, integer column, double quantile);
+double Table_getMean (Table me, integer column);
+double Table_getMaximum (Table me, integer icol);
+double Table_getMinimum (Table me, integer icol);
+double Table_getGroupMean (Table me, integer column, integer groupColumn, const char32 *group);
+double Table_getStdev (Table me, integer column);
+integer Table_drawRowFromDistribution (Table me, integer column);
+double Table_getCorrelation_pearsonR (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_significance, double *out_lowerLimit, double *out_upperLimit);
-double Table_getCorrelation_kendallTau (Table me, long column1, long column2, double significanceLevel,
+double Table_getCorrelation_kendallTau (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_significance, double *out_lowerLimit, double *out_upperLimit);
-double Table_getMean_studentT (Table me, long column, double significanceLevel,
+double Table_getMean_studentT (Table me, integer column, double significanceLevel,
 	double *out_tFromZero, double *out_numberOfDegreesOfFreedom, double *out_significanceFromZero, double *out_lowerLimit, double *out_upperLimit);
-double Table_getDifference_studentT (Table me, long column1, long column2, double significanceLevel,
+double Table_getDifference_studentT (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_t, double *out_numberOfDegreesOfFreedom, double *out_significance, double *out_lowerLimit, double *out_upperLimit);
-double Table_getGroupMean_studentT (Table me, long column, long groupColumn, const char32 *group1, double significanceLevel,
+double Table_getGroupMean_studentT (Table me, integer column, integer groupColumn, const char32 *group1, double significanceLevel,
 	double *out_tFromZero, double *out_numberOfDegreesOfFreedom, double *out_significanceFromZero, double *out_lowerLimit, double *out_upperLimit);
-double Table_getGroupDifference_studentT (Table me, long column, long groupColumn, const char32 *group1, const char32 *group2, double significanceLevel,
+double Table_getGroupDifference_studentT (Table me, integer column, integer groupColumn, const char32 *group1, const char32 *group2, double significanceLevel,
 	double *out_tFromZero, double *out_numberOfDegreesOfFreedom, double *out_significanceFromZero, double *out_lowerLimit, double *out_upperLimit);
-double Table_getGroupDifference_wilcoxonRankSum (Table me, long column, long groupColumn, const char32 *group1, const char32 *group2,
+double Table_getGroupDifference_wilcoxonRankSum (Table me, integer column, integer groupColumn, const char32 *group1, const char32 *group2,
 	double *out_rankSum, double *out_significanceFromZero);
-double Table_getVarianceRatio (Table me, long column1, long column2, double significanceLevel,
+double Table_getVarianceRatio (Table me, integer column1, integer column2, double significanceLevel,
 	double *out_significance, double *out_lowerLimit, double *out_upperLimit);
-bool Table_getExtrema (Table me, long icol, double *minimum, double *maximum);
+bool Table_getExtrema (Table me, integer icol, double *minimum, double *maximum);
 
-void Table_formula (Table me, long column, const char32 *formula, Interpreter interpreter);
-void Table_formula_columnRange (Table me, long column1, long column2, const char32 *expression, Interpreter interpreter);
+void Table_formula (Table me, integer column, const char32 *formula, Interpreter interpreter);
+void Table_formula_columnRange (Table me, integer column1, integer column2, const char32 *expression, Interpreter interpreter);
 
-void Table_sortRows_Assert (Table me, long *columns, long numberOfColumns);
+void Table_sortRows_Assert (Table me, integer *columns, integer numberOfColumns);
 void Table_sortRows_string (Table me, const char32 *columns_string);
 void Table_randomizeRows (Table me) noexcept;
 void Table_reflectRows (Table me) noexcept;
 
-void Table_scatterPlot (Table me, Graphics g, long xcolumn, long ycolumn,
-	double xmin, double xmax, double ymin, double ymax, long markColumn, int fontSize, int garnish);
-void Table_scatterPlot_mark (Table me, Graphics g, long xcolumn, long ycolumn,
-	double xmin, double xmax, double ymin, double ymax, double markSize_mm, const char32 *mark, int garnish);
-void Table_drawEllipse_e (Table me, Graphics g, long xcolumn, long ycolumn,
-	double xmin, double xmax, double ymin, double ymax, double numberOfSigmas, int garnish);
+void Table_scatterPlot (Table me, Graphics g, integer xcolumn, integer ycolumn,
+	double xmin, double xmax, double ymin, double ymax, integer markColumn, int fontSize, bool garnish);
+void Table_scatterPlot_mark (Table me, Graphics g, integer xcolumn, integer ycolumn,
+	double xmin, double xmax, double ymin, double ymax, double markSize_mm, const char32 *mark, bool garnish);
+void Table_drawEllipse_e (Table me, Graphics g, integer xcolumn, integer ycolumn,
+	double xmin, double xmax, double ymin, double ymax, double numberOfSigmas, bool garnish);
 
 void Table_list (Table me, bool includeRowNumbers);
 void Table_writeToTabSeparatedFile (Table me, MelderFile file);
@@ -110,18 +110,18 @@ void Table_writeToCommaSeparatedFile (Table me, MelderFile file);
 autoTable Table_readFromTableFile (MelderFile file);
 autoTable Table_readFromCharacterSeparatedTextFile (MelderFile file, char32 separator);
 
-autoTable Table_extractRowsWhereColumn_number (Table me, long column, int which_Melder_NUMBER, double criterion);
-autoTable Table_extractRowsWhereColumn_string (Table me, long column, int which_Melder_STRING, const char32 *criterion);
+autoTable Table_extractRowsWhereColumn_number (Table me, integer column, int which_Melder_NUMBER, double criterion);
+autoTable Table_extractRowsWhereColumn_string (Table me, integer column, int which_Melder_STRING, const char32 *criterion);
 autoTable Table_collapseRows (Table me, const char32 *factors_string, const char32 *columnsToSum_string,
 	const char32 *columnsToAverage_string, const char32 *columnsToMedianize_string,
 	const char32 *columnsToAverageLogarithmically_string, const char32 *columnsToMedianizeLogarithmically_string);
-autoTable Table_rowsToColumns (Table me, const char32 *factors_string, long columnToTranspose, const char32 *columnsToExpand_string);
+autoTable Table_rowsToColumns (Table me, const char32 *factors_string, integer columnToTranspose, const char32 *columnsToExpand_string);
 autoTable Table_transpose (Table me);
 
-void Table_checkSpecifiedRowNumberWithinRange (Table me, long rowNumber);
-void Table_checkSpecifiedColumnNumberWithinRange (Table me, long columnNumber);
-bool Table_isCellNumeric_ErrorFalse (Table me, long rowNumber, long columnNumber);
-bool Table_isColumnNumeric_ErrorFalse (Table me, long columnNumber);
+void Table_checkSpecifiedRowNumberWithinRange (Table me, integer rowNumber);
+void Table_checkSpecifiedColumnNumberWithinRange (Table me, integer columnNumber);
+bool Table_isCellNumeric_ErrorFalse (Table me, integer rowNumber, integer columnNumber);
+bool Table_isColumnNumeric_ErrorFalse (Table me, integer columnNumber);
 
 /* End of file Table.h */
 #endif
diff --git a/stat/TableEditor.cpp b/stat/TableEditor.cpp
index 5097d79..7d1380b 100644
--- a/stat/TableEditor.cpp
+++ b/stat/TableEditor.cpp
@@ -45,12 +45,12 @@ void structTableEditor :: v_info () {
 
 static void updateVerticalScrollBar (TableEditor me) {
 	Table table = static_cast<Table> (my data);
-	GuiScrollBar_set (my verticalScrollBar, NUMundefined, table -> rows.size + 1, my topRow, NUMundefined, NUMundefined, NUMundefined);
+	GuiScrollBar_set (my verticalScrollBar, undefined, table -> rows.size + 1, my topRow, undefined, undefined, undefined);
 }
 
 static void updateHorizontalScrollBar (TableEditor me) {
 	Table table = static_cast<Table> (my data);
-	GuiScrollBar_set (my horizontalScrollBar, NUMundefined, table -> numberOfColumns + 1, my leftColumn, NUMundefined, NUMundefined, NUMundefined);
+	GuiScrollBar_set (my horizontalScrollBar, undefined, table -> numberOfColumns + 1, my leftColumn, undefined, undefined, undefined);
 }
 
 void structTableEditor :: v_dataChanged () {
diff --git a/stat/TableOfReal.cpp b/stat/TableOfReal.cpp
index 6989604..12cc54f 100644
--- a/stat/TableOfReal.cpp
+++ b/stat/TableOfReal.cpp
@@ -1,6 +1,6 @@
 /* TableOfReal.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,19 +47,19 @@ static void fprintquotedstring (MelderFile file, const char32 *s) {
 }
 
 void structTableOfReal :: v_writeText (MelderFile file) {
-	texputi4 (file, numberOfColumns, U"numberOfColumns", 0,0,0,0,0);
+	texputi32 (file, numberOfColumns, U"numberOfColumns", 0,0,0,0,0);
 	MelderFile_write (file, U"\ncolumnLabels []: ");
 	if (numberOfColumns < 1) MelderFile_write (file, U"(empty)");
 	MelderFile_write (file, U"\n");
-	for (long i = 1; i <= numberOfColumns; i ++) {
+	for (integer i = 1; i <= numberOfColumns; i ++) {
 		fprintquotedstring (file, columnLabels [i]);
 		MelderFile_writeCharacter (file, U'\t');
 	}
-	texputi4 (file, numberOfRows, U"numberOfRows", 0,0,0,0,0);
-	for (long i = 1; i <= numberOfRows; i ++) {
+	texputi32 (file, numberOfRows, U"numberOfRows", 0,0,0,0,0);
+	for (integer i = 1; i <= numberOfRows; i ++) {
 		MelderFile_write (file, U"\nrow [", i, U"]: ");
 		fprintquotedstring (file, rowLabels [i]);
-		for (long j = 1; j <= numberOfColumns; j ++) {
+		for (integer j = 1; j <= numberOfColumns; j ++) {
 			double x = data [i] [j];
 			MelderFile_write (file, U"\t", x);
 		}
@@ -67,22 +67,22 @@ void structTableOfReal :: v_writeText (MelderFile file) {
 }
 
 void structTableOfReal :: v_readText (MelderReadText a_text, int /*formatVersion*/) {
-	numberOfColumns = texgeti4 (a_text);
+	numberOfColumns = texgeti32 (a_text);
 	if (numberOfColumns >= 1) {
 		columnLabels = NUMvector <char32*> (1, numberOfColumns);
-		for (long i = 1; i <= numberOfColumns; i ++)
-			columnLabels [i] = texgetw2 (a_text);
+		for (integer i = 1; i <= numberOfColumns; i ++)
+			columnLabels [i] = texgetw16 (a_text);
 	}
-	numberOfRows = texgeti4 (a_text);
+	numberOfRows = texgeti32 (a_text);
 	if (numberOfRows >= 1) {
 		rowLabels = NUMvector <char32*> (1, numberOfRows);
 	}
 	if (numberOfRows >= 1 && numberOfColumns >= 1) {
 		data = NUMmatrix <double> (1, numberOfRows, 1, numberOfColumns);
-		for (long i = 1; i <= numberOfRows; i ++) {
-			rowLabels [i] = texgetw2 (a_text);
-			for (long j = 1; j <= numberOfColumns; j ++)
-				data [i] [j] = texgetr8 (a_text);
+		for (integer i = 1; i <= numberOfRows; i ++) {
+			rowLabels [i] = texgetw16 (a_text);
+			for (integer j = 1; j <= numberOfColumns; j ++)
+				data [i] [j] = texgetr64 (a_text);
 		}
 	}
 }
@@ -102,8 +102,8 @@ const char32 * structTableOfReal :: v_getColStr (long icol) {
 	return columnLabels [icol] ? columnLabels [icol] : U"";
 }
 double structTableOfReal :: v_getMatrix (long irow, long icol) {
-	if (irow < 1 || irow > numberOfRows) return NUMundefined;
-	if (icol < 1 || icol > numberOfColumns) return NUMundefined;
+	if (irow < 1 || irow > numberOfRows) return undefined;
+	if (icol < 1 || icol > numberOfColumns) return undefined;
 	return data [irow] [icol];
 }
 double structTableOfReal :: v_getRowIndex (const char32 *rowLabel) {
@@ -113,7 +113,7 @@ double structTableOfReal :: v_getColIndex (const char32 *columnLabel) {
 	return TableOfReal_columnLabelToIndex (this, columnLabel);
 }
 
-void TableOfReal_init (TableOfReal me, long numberOfRows, long numberOfColumns) {
+void TableOfReal_init (TableOfReal me, integer numberOfRows, integer numberOfColumns) {
 	if (numberOfRows < 1 || numberOfColumns < 1)
 		Melder_throw (U"Cannot create cell-less table.");
 	my numberOfRows = numberOfRows;
@@ -123,7 +123,7 @@ void TableOfReal_init (TableOfReal me, long numberOfRows, long numberOfColumns)
 	my data = NUMmatrix <double> (1, my numberOfRows, 1, my numberOfColumns);
 }
 
-autoTableOfReal TableOfReal_create (long numberOfRows, long numberOfColumns) {
+autoTableOfReal TableOfReal_create (integer numberOfRows, integer numberOfColumns) {
 	try {
 		autoTableOfReal me = Thing_new (TableOfReal);
 		TableOfReal_init (me.get(), numberOfRows, numberOfColumns);
@@ -135,58 +135,61 @@ autoTableOfReal TableOfReal_create (long numberOfRows, long numberOfColumns) {
 
 /***** QUERY *****/
 
-long TableOfReal_rowLabelToIndex (TableOfReal me, const char32 *label) {
-	for (long irow = 1; irow <= my numberOfRows; irow ++)
+integer TableOfReal_rowLabelToIndex (TableOfReal me, const char32 *label) {
+	for (integer irow = 1; irow <= my numberOfRows; irow ++)
 		if (my rowLabels [irow] && str32equ (my rowLabels [irow], label))
 			return irow;
 	return 0;
 }
 
-long TableOfReal_columnLabelToIndex (TableOfReal me, const char32 *label) {
-	for (long icol = 1; icol <= my numberOfColumns; icol ++)
+integer TableOfReal_columnLabelToIndex (TableOfReal me, const char32 *label) {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 		if (my columnLabels [icol] && str32equ (my columnLabels [icol], label))
 			return icol;
 	return 0;
 }
 
-double TableOfReal_getColumnMean (TableOfReal me, long columnNumber) {
-	double sum = 0.0;
-	if (columnNumber < 1 || columnNumber > my numberOfColumns) return NUMundefined;
-	if (my numberOfRows < 1) return NUMundefined;
-	for (long irow = 1; irow <= my numberOfRows; irow ++)
+double TableOfReal_getColumnMean (TableOfReal me, integer columnNumber) {
+	if (columnNumber < 1 || columnNumber > my numberOfColumns) return undefined;
+	if (my numberOfRows < 1) return undefined;
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= my numberOfRows; irow ++)
 		sum += my data [irow] [columnNumber];
-	return sum / my numberOfRows;
+	return (real) sum / my numberOfRows;
 }
 
-double TableOfReal_getColumnStdev (TableOfReal me, long columnNumber) {
-	double mean = TableOfReal_getColumnMean (me, columnNumber), sum = 0.0, d;
-	if (columnNumber < 1 || columnNumber > my numberOfColumns) return NUMundefined;
-	if (my numberOfRows < 2) return NUMundefined;
-	for (long irow = 1; irow <= my numberOfRows; irow ++)
-		sum += ( d = my data [irow] [columnNumber] - mean, d * d );
-	return sqrt (sum / (my numberOfRows - 1));
+double TableOfReal_getColumnStdev (TableOfReal me, integer columnNumber) {
+	if (columnNumber < 1 || columnNumber > my numberOfColumns) return undefined;
+	if (my numberOfRows < 2) return undefined;
+	double mean = TableOfReal_getColumnMean (me, columnNumber);
+	real80 sum = 0.0;
+	for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+		real d = my data [irow] [columnNumber] - mean;
+		sum += d * d;
+	}
+	return sqrt ((real) sum / (my numberOfRows - 1));
 }
 
 /***** MODIFY *****/
 
-void TableOfReal_removeRow (TableOfReal me, long rowNumber) {
+void TableOfReal_removeRow (TableOfReal me, integer rowNumber) {
 	try {
 		if (my numberOfRows == 1)
-			Melder_throw (Thing_messageName (me), U" has only one row, and a TableOfReal without rows cannot exist.");
+			Melder_throw (me, U" has only one row, and a TableOfReal without rows cannot exist.");
 		if (rowNumber < 1 || rowNumber > my numberOfRows)
 			Melder_throw (U"No row ", rowNumber, U".");
 		autoNUMmatrix <double> data (1, my numberOfRows - 1, 1, my numberOfColumns);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
-			for (long irow = 1; irow < rowNumber; irow ++)
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer irow = 1; irow < rowNumber; irow ++)
 				data [irow] [icol] = my data [irow] [icol];
-			for (long irow = rowNumber; irow < my numberOfRows; irow ++)
+			for (integer irow = rowNumber; irow < my numberOfRows; irow ++)
 				data [irow] [icol] = my data [irow + 1] [icol];
 		}
 		/*
-		 * Change without error.
-		 */
+			Change without error.
+		*/
 		Melder_free (my rowLabels [rowNumber]);
-		for (long irow = rowNumber; irow < my numberOfRows; irow ++)
+		for (integer irow = rowNumber; irow < my numberOfRows; irow ++)
 			my rowLabels [irow] = my rowLabels [irow + 1];
 		NUMmatrix_free (my data, 1, 1);
 		my data = data.transfer();
@@ -196,25 +199,25 @@ void TableOfReal_removeRow (TableOfReal me, long rowNumber) {
 	}
 }
 
-void TableOfReal_insertRow (TableOfReal me, long rowNumber) {
+void TableOfReal_insertRow (TableOfReal me, integer rowNumber) {
 	try {
 		if (rowNumber < 1 || rowNumber > my numberOfRows + 1)
 			Melder_throw (U"Cannot create row ", rowNumber, U".");
 		autoNUMmatrix <double> data (1, my numberOfRows + 1, 1, my numberOfColumns);
 		autoNUMvector <char32 *> rowLabels (1, my numberOfRows + 1);   // not autostringvector...
-		for (long irow = 1; irow < rowNumber; irow ++)	{
+		for (integer irow = 1; irow < rowNumber; irow ++)	{
 			rowLabels [irow] = my rowLabels [irow];   // ...because this is a dangling copy
-			for (long icol = 1; icol <= my numberOfColumns; icol ++)
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 				data [irow] [icol] = my data [irow] [icol];
 		}
-		for (long irow = my numberOfRows + 1; irow > rowNumber; irow --) {
+		for (integer irow = my numberOfRows + 1; irow > rowNumber; irow --) {
 			rowLabels [irow] = my rowLabels [irow - 1];
-			for (long icol = 1; icol <= my numberOfColumns; icol ++)
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 				data [irow] [icol] = my data [irow - 1] [icol];
 		}
 		/*
-		 * Change without error.
-		 */
+			Change without error.
+		*/
 		NUMvector_free (my rowLabels, 1);
 		my rowLabels = rowLabels.transfer();
 		NUMmatrix_free (my data, 1, 1);
@@ -225,24 +228,24 @@ void TableOfReal_insertRow (TableOfReal me, long rowNumber) {
 	}
 }
 
-void TableOfReal_removeColumn (TableOfReal me, long columnNumber) {
+void TableOfReal_removeColumn (TableOfReal me, integer columnNumber) {
 	try {
 		if (my numberOfColumns == 1)
 			Melder_throw (U"Cannot remove the only column.");
 		if (columnNumber < 1 || columnNumber > my numberOfColumns)
 			Melder_throw (U"No column ", columnNumber, U".");
 		autoNUMmatrix <double> data (1, my numberOfRows, 1, my numberOfColumns - 1);
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
-			for (long icol = 1; icol < columnNumber; icol ++)
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+			for (integer icol = 1; icol < columnNumber; icol ++)
 				data [irow] [icol] = my data [irow] [icol];
-			for (long icol = columnNumber; icol < my numberOfColumns; icol ++)
+			for (integer icol = columnNumber; icol < my numberOfColumns; icol ++)
 				data [irow] [icol] = my data [irow] [icol + 1];
 		}
 		/*
-		 * Change without error.
-		 */
+			Change without error.
+		*/
 		Melder_free (my columnLabels [columnNumber]);
-		for (long icol = columnNumber; icol < my numberOfColumns; icol ++)
+		for (integer icol = columnNumber; icol < my numberOfColumns; icol ++)
 			my columnLabels [icol] = my columnLabels [icol + 1];
 		NUMmatrix_free (my data, 1, 1);
 		my data = data.transfer();
@@ -252,23 +255,23 @@ void TableOfReal_removeColumn (TableOfReal me, long columnNumber) {
 	}
 }
 
-void TableOfReal_insertColumn (TableOfReal me, long columnNumber) {
+void TableOfReal_insertColumn (TableOfReal me, integer columnNumber) {
 	try {
 		if (columnNumber < 1 || columnNumber > my numberOfColumns + 1)
 			Melder_throw (U"Cannot create column ", columnNumber, U".");
 		autoNUMmatrix <double> data (1, my numberOfRows, 1, my numberOfColumns + 1);
 		autoNUMvector <char32*> columnLabels (1, my numberOfColumns + 1);   // not autostringvector...
-		for (long j = 1; j < columnNumber; j ++) {
+		for (integer j = 1; j < columnNumber; j ++) {
 			columnLabels [j] = my columnLabels [j];   // ...because this is a dangling copy
-			for (long i = 1; i <= my numberOfRows; i ++) data [i] [j] = my data [i] [j];
+			for (integer i = 1; i <= my numberOfRows; i ++) data [i] [j] = my data [i] [j];
 		}
-		for (long j = my numberOfColumns + 1; j > columnNumber; j --) {
+		for (integer j = my numberOfColumns + 1; j > columnNumber; j --) {
 			columnLabels [j] = my columnLabels [j - 1];
-			for (long i = 1; i <= my numberOfRows; i ++) data [i] [j] = my data [i] [j - 1];
+			for (integer i = 1; i <= my numberOfRows; i ++) data [i] [j] = my data [i] [j - 1];
 		}
 		/*
-		 * Change without error.
-		 */
+			Change without error.
+		*/
 		NUMvector_free (my columnLabels, 1);
 		my columnLabels = columnLabels.transfer();
 		NUMmatrix_free (my data, 1, 1);
@@ -279,13 +282,13 @@ void TableOfReal_insertColumn (TableOfReal me, long columnNumber) {
 	}
 }
 
-void TableOfReal_setRowLabel (TableOfReal me, long rowNumber, const char32 *label) {
+void TableOfReal_setRowLabel (TableOfReal me, integer rowNumber, const char32 *label) {
 	try {
 		if (rowNumber < 1 || rowNumber > my numberOfRows) return;
 		autostring32 newLabel = Melder_dup (label);
 		/*
-		 * Change without error.
-		 */
+			Change without error.
+		*/
 		Melder_free (my rowLabels [rowNumber]);
 		my rowLabels [rowNumber] = newLabel.transfer();
 	} catch (MelderError) {
@@ -293,13 +296,13 @@ void TableOfReal_setRowLabel (TableOfReal me, long rowNumber, const char32 *labe
 	}
 }
 
-void TableOfReal_setColumnLabel (TableOfReal me, long columnNumber, const char32 *label) {
+void TableOfReal_setColumnLabel (TableOfReal me, integer columnNumber, const char32 *label) {
 	try {
 		if (columnNumber < 1 || columnNumber > my numberOfColumns) return;
 		autostring32 newLabel = Melder_dup (label);
 		/*
-		 * Change without error.
-		 */
+			Change without error.
+		*/
 		Melder_free (my columnLabels [columnNumber]);
 		my columnLabels [columnNumber] = newLabel.transfer();
 	} catch (MelderError) {
@@ -311,9 +314,9 @@ void TableOfReal_formula (TableOfReal me, const char32 *expression, Interpreter
 	try {
 		Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		if (! thee) thee = me;
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
-				struct Formula_Result result;
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
 				thy data [irow] [icol] = result. result.numericResult;
 			}
@@ -328,7 +331,7 @@ void TableOfReal_formula (TableOfReal me, const char32 *expression, Interpreter
 static void copyRowLabels (TableOfReal me, TableOfReal thee) {
 	Melder_assert (me != thee);
 	Melder_assert (my numberOfRows == thy numberOfRows);
-	for (long irow = 1; irow <= my numberOfRows; irow ++) {
+	for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 		thy rowLabels [irow] = Melder_dup (my rowLabels [irow]);
 	}
 }
@@ -336,35 +339,35 @@ static void copyRowLabels (TableOfReal me, TableOfReal thee) {
 static void copyColumnLabels (TableOfReal me, TableOfReal thee) {
 	Melder_assert (me != thee);
 	Melder_assert (my numberOfColumns == thy numberOfColumns);
-	for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 		thy columnLabels [icol] = Melder_dup (my columnLabels [icol]);
 	}
 }
 
-static void copyRow (TableOfReal me, long myRow, TableOfReal thee, long thyRow) {
+static void copyRow (TableOfReal me, integer myRow, TableOfReal thee, integer thyRow) {
 	Melder_assert (me != thee);
 	Melder_assert (my numberOfColumns == thy numberOfColumns);
 	thy rowLabels [thyRow] = Melder_dup (my rowLabels [myRow]);
-	for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 		thy data [thyRow] [icol] = my data [myRow] [icol];
 	}
 }
 
-static void copyColumn (TableOfReal me, long myCol, TableOfReal thee, long thyCol) {
+static void copyColumn (TableOfReal me, integer myCol, TableOfReal thee, integer thyCol) {
 	Melder_assert (me != thee);
 	Melder_assert (my numberOfRows == thy numberOfRows);
 	thy columnLabels [thyCol] = Melder_dup (my columnLabels [myCol]);
-	for (long irow = 1; irow <= my numberOfRows; irow ++) {
+	for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 		thy data [irow] [thyCol] = my data [irow] [myCol];
 	}
 }
 
-autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, long column, int which_Melder_NUMBER, double criterion) {
+autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, integer column, int which_Melder_NUMBER, double criterion) {
 	try {
 		if (column < 1 || column > my numberOfColumns)
 			Melder_throw (U"No such column: ", column, U".");
-		long n = 0;
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+		integer n = 0;
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 			if (Melder_numberMatchesCriterion (my data [irow] [column], which_Melder_NUMBER, criterion)) {
 				n ++;
 			}
@@ -373,7 +376,7 @@ autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, long column,
 		autoTableOfReal thee = TableOfReal_create (n, my numberOfColumns);
 		copyColumnLabels (me, thee.get());
 		n = 0;
-		for (long irow = 1; irow <= my numberOfRows; irow ++)
+		for (integer irow = 1; irow <= my numberOfRows; irow ++)
 			if (Melder_numberMatchesCriterion (my data [irow] [column], which_Melder_NUMBER, criterion))
 				copyRow (me, irow, thee.get(), ++ n);
 		return thee;
@@ -384,8 +387,8 @@ autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, long column,
 
 autoTableOfReal TableOfReal_extractRowsWhereLabel (TableOfReal me, int which_Melder_STRING, const char32 *criterion) {
 	try {
-		long n = 0;
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+		integer n = 0;
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 			if (Melder_stringMatchesCriterion (my rowLabels [irow], which_Melder_STRING, criterion)) {
 				n ++;
 			}
@@ -395,7 +398,7 @@ autoTableOfReal TableOfReal_extractRowsWhereLabel (TableOfReal me, int which_Mel
 		autoTableOfReal thee = TableOfReal_create (n, my numberOfColumns);
 		copyColumnLabels (me, thee.get());
 		n = 0;
-		for (long irow = 1; irow <= my numberOfRows; irow ++)
+		for (integer irow = 1; irow <= my numberOfRows; irow ++)
 			if (Melder_stringMatchesCriterion (my rowLabels [irow], which_Melder_STRING, criterion))
 				copyRow (me, irow, thee.get(), ++ n);
 		return thee;
@@ -404,12 +407,12 @@ autoTableOfReal TableOfReal_extractRowsWhereLabel (TableOfReal me, int which_Mel
 	}
 }
 
-autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, long row, int which_Melder_NUMBER, double criterion) {
+autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, integer row, int which_Melder_NUMBER, double criterion) {
 	try {
 		if (row < 1 || row > my numberOfRows)
 			Melder_throw (U"No such row: ", row, U".");
-		long n = 0;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		integer n = 0;
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			if (Melder_numberMatchesCriterion (my data [row] [icol], which_Melder_NUMBER, criterion)) {
 				n ++;
 			}
@@ -419,7 +422,7 @@ autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, long row, in
 		autoTableOfReal thee = TableOfReal_create (my numberOfRows, n);
 		copyRowLabels (me, thee.get());
 		n = 0;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++)
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 			if (Melder_numberMatchesCriterion (my data [row] [icol], which_Melder_NUMBER, criterion))
 				copyColumn (me, icol, thee.get(), ++ n);
 		return thee;
@@ -430,8 +433,8 @@ autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, long row, in
 
 autoTableOfReal TableOfReal_extractColumnsWhereLabel (TableOfReal me, int which_Melder_STRING, const char32 *criterion) {
 	try {
-		long n = 0;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		integer n = 0;
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			if (Melder_stringMatchesCriterion (my columnLabels [icol], which_Melder_STRING, criterion)) {
 				n ++;
 			}
@@ -441,7 +444,7 @@ autoTableOfReal TableOfReal_extractColumnsWhereLabel (TableOfReal me, int which_
 		autoTableOfReal thee = TableOfReal_create (my numberOfRows, n);
 		copyRowLabels (me, thee.get());
 		n = 0;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			if (Melder_stringMatchesCriterion (my columnLabels [icol], which_Melder_STRING, criterion)) {
 				copyColumn (me, icol, thee.get(), ++ n);
 			}
@@ -457,18 +460,18 @@ autoTableOfReal TableOfReal_extractColumnsWhereLabel (TableOfReal me, int which_
  * 1, 4, 2, 3, 4, 5, 6, 7, 4, 3, 3, 4, 5, 4, 3, 2
  * Overlap is allowed. Ranges can go up and down.
  */
-static long *getElementsOfRanges (const char32 *ranges, long maximumElement, long *numberOfElements, const char32 *elementType) {
+static integer *getElementsOfRanges (const char32 *ranges, integer maximumElement, integer *numberOfElements, const char32 *elementType) {
 	/*
-	 * Count the elements.
-	 */
-	long previousElement = 0;
+		Count the elements.
+	*/
+	integer previousElement = 0;
 	*numberOfElements = 0;
 	const char32 *p = & ranges [0];
 	for (;;) {
 		while (*p == U' ' || *p == U'\t') p ++;
 		if (*p == U'\0') break;
 		if (isdigit ((int) *p)) {
-			long currentElement = Melder_atoi (p);
+			integer currentElement = Melder_atoi (p);
 			if (currentElement == 0)
 				Melder_throw (U"No such ", elementType, U": 0 (minimum is 1).");
 			if (currentElement > maximumElement)
@@ -484,7 +487,7 @@ static long *getElementsOfRanges (const char32 *ranges, long maximumElement, lon
 				Melder_throw (U"Cannot end range with colon.");
 			if (! isdigit ((int) *p))
 				Melder_throw (U"End of range should be a positive whole number.");
-			long currentElement = Melder_atoi (p);
+			integer currentElement = Melder_atoi (p);
 			if (currentElement == 0)
 				Melder_throw (U"No such ", elementType, U": 0 (minimum is 1).");
 			if (currentElement > maximumElement)
@@ -501,12 +504,12 @@ static long *getElementsOfRanges (const char32 *ranges, long maximumElement, lon
 		}
 	}
 	/*
-	 * Create room for the elements.
-	 */
-	autoNUMvector <long> elements (1, *numberOfElements);
+		Create room for the elements.
+	*/
+	autoNUMvector <integer> elements (1, *numberOfElements);
 	/*
-	 * Store the elements.
-	 */
+		Store the elements.
+	*/
 	previousElement = 0;
 	*numberOfElements = 0;
 	p = & ranges [0];
@@ -514,19 +517,19 @@ static long *getElementsOfRanges (const char32 *ranges, long maximumElement, lon
 		while (*p == U' ' || *p == U'\t') p ++;
 		if (*p == U'\0') break;
 		if (isdigit ((int) *p)) {
-			long currentElement = Melder_atoi (p);
+			integer currentElement = Melder_atoi (p);
 			elements [++ *numberOfElements] = currentElement;
 			previousElement = currentElement;
 			do { p ++; } while (isdigit ((int) *p));
 		} else if (*p == ':') {
 			do { p ++; } while (*p == U' ' || *p == U'\t');
-			long currentElement = Melder_atoi (p);
+			integer currentElement = Melder_atoi (p);
 			if (currentElement > previousElement) {
-				for (long ielement = previousElement + 1; ielement <= currentElement; ielement ++) {
+				for (integer ielement = previousElement + 1; ielement <= currentElement; ielement ++) {
 					elements [++ *numberOfElements] = ielement;
 				}
 			} else {
-				for (long ielement = previousElement - 1; ielement >= currentElement; ielement --) {
+				for (integer ielement = previousElement - 1; ielement >= currentElement; ielement --) {
 					elements [++ *numberOfElements] = ielement;
 				}
 			}
@@ -539,11 +542,11 @@ static long *getElementsOfRanges (const char32 *ranges, long maximumElement, lon
 
 autoTableOfReal TableOfReal_extractRowRanges (TableOfReal me, const char32 *ranges) {
 	try {
-		long numberOfElements;
-		autoNUMvector <long> elements (getElementsOfRanges (ranges, my numberOfRows, & numberOfElements, U"row"), 1);
+		integer numberOfElements;
+		autoNUMvector <integer> elements (getElementsOfRanges (ranges, my numberOfRows, & numberOfElements, U"row"), 1);
 		autoTableOfReal thee = TableOfReal_create (numberOfElements, my numberOfColumns);
 		copyColumnLabels (me, thee.get());
-		for (long ielement = 1; ielement <= numberOfElements; ielement ++)
+		for (integer ielement = 1; ielement <= numberOfElements; ielement ++)
 			copyRow (me, elements [ielement], thee.get(), ielement);
 		return thee;
 	} catch (MelderError) {
@@ -553,11 +556,11 @@ autoTableOfReal TableOfReal_extractRowRanges (TableOfReal me, const char32 *rang
 
 autoTableOfReal TableOfReal_extractColumnRanges (TableOfReal me, const char32 *ranges) {
 	try {
-		long numberOfElements;
-		autoNUMvector <long> elements (getElementsOfRanges (ranges, my numberOfColumns, & numberOfElements, U"column"), 1);
+		integer numberOfElements;
+		autoNUMvector <integer> elements (getElementsOfRanges (ranges, my numberOfColumns, & numberOfElements, U"column"), 1);
 		autoTableOfReal thee = TableOfReal_create (my numberOfRows, numberOfElements);
 		copyRowLabels (me, thee.get());
-		for (long ielement = 1; ielement <= numberOfElements; ielement ++)
+		for (integer ielement = 1; ielement <= numberOfElements; ielement ++)
 			copyColumn (me, elements [ielement], thee.get(), ielement);
 		return thee;
 	} catch (MelderError) {
@@ -569,12 +572,12 @@ autoTableOfReal TableOfReal_extractRowsWhere (TableOfReal me, const char32 *cond
 	try {
 		Formula_compile (interpreter, me, condition, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		/*
-		 * Count the new number of rows.
-		 */
-		long numberOfElements = 0;
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
-				struct Formula_Result result;
+			Count the new number of rows.
+		*/
+		integer numberOfElements = 0;
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
 				if (result. result.numericResult != 0.0) {
 					numberOfElements ++;
@@ -585,17 +588,17 @@ autoTableOfReal TableOfReal_extractRowsWhere (TableOfReal me, const char32 *cond
 		if (numberOfElements < 1) Melder_throw (U"No rows match this condition.");
 
 		/*
-		 * Create room for the result.
-		 */	
+			Create room for the result.
+		*/
 		autoTableOfReal thee = TableOfReal_create (numberOfElements, my numberOfColumns);
 		copyColumnLabels (me, thee.get());
 		/*
-		 * Store the result.
-		 */
+			Store the result.
+		*/
 		numberOfElements = 0;
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
-				struct Formula_Result result;
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
 				if (result. result.numericResult != 0.0) {
 					copyRow (me, irow, thee.get(), ++ numberOfElements);
@@ -613,12 +616,12 @@ autoTableOfReal TableOfReal_extractColumnsWhere (TableOfReal me, const char32 *c
 	try {
 		Formula_compile (interpreter, me, condition, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		/*
-		 * Count the new number of columns.
-		 */
-		long numberOfElements = 0;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
-			for (long irow = 1; irow <= my numberOfRows; irow ++) {
-				struct Formula_Result result;
+			Count the new number of columns.
+		*/
+		integer numberOfElements = 0;
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
 				if (result. result.numericResult != 0.0) {
 					numberOfElements ++;
@@ -629,17 +632,17 @@ autoTableOfReal TableOfReal_extractColumnsWhere (TableOfReal me, const char32 *c
 		if (numberOfElements < 1) Melder_throw (U"No columns match this condition.");
 
 		/*
-		 * Create room for the result.
-		 */	
+			Create room for the result.
+		*/
 		autoTableOfReal thee = TableOfReal_create (my numberOfRows, numberOfElements);
 		copyRowLabels (me, thee.get());
 		/*
-		 * Store the result.
-		 */
+			Store the result.
+		*/
 		numberOfElements = 0;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
-			for (long irow = 1; irow <= my numberOfRows; irow ++) {
-				struct Formula_Result result;
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+				Formula_Result result;
 				Formula_run (irow, icol, & result);
 				if (result. result.numericResult != 0.0) {
 					copyColumn (me, icol, thee.get(), ++ numberOfElements);
@@ -660,7 +663,7 @@ autoStrings TableOfReal_extractRowLabelsAsStrings (TableOfReal me) {
 		autoStrings thee = Thing_new (Strings);
 		thy strings = NUMvector <char32 *> (1, my numberOfRows);
 		thy numberOfStrings = my numberOfRows;
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 			thy strings [irow] = Melder_dup (my rowLabels [irow] ? my rowLabels [irow] : U"");
 		}
 		return thee;
@@ -674,7 +677,7 @@ autoStrings TableOfReal_extractColumnLabelsAsStrings (TableOfReal me) {
 		autoStrings thee = Thing_new (Strings);
 		thy strings = NUMvector <char32 *> (1, my numberOfColumns);
 		thy numberOfStrings = my numberOfColumns;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			thy strings [icol] = Melder_dup (my columnLabels [icol] ? my columnLabels [icol] : U"");
 		}
 		return thee;
@@ -685,12 +688,12 @@ autoStrings TableOfReal_extractColumnLabelsAsStrings (TableOfReal me) {
 
 /***** DRAW *****/
 
-static void NUMrationalize (double x, long *numerator, long *denominator) {
+static void NUMrationalize (double x, integer *numerator, integer *denominator) {
 	double epsilon = 1e-6;
 	*numerator = 1;
 	for (*denominator = 1; *denominator <= 100000; (*denominator) ++) {
 		double numerator_d = x * *denominator;
-		long rounded = lround (numerator_d);
+		integer rounded = lround (numerator_d);
 		if (fabs (rounded - numerator_d) < epsilon) {
 			*numerator = rounded;
 			return;
@@ -702,12 +705,12 @@ static void NUMrationalize (double x, long *numerator, long *denominator) {
 static void print4 (char *buffer, double value, int iformat, int width, int precision) {
 	char formatString [40];
 	if (iformat == 4) {
-		long numerator, denominator;
+		integer numerator, denominator;
 		NUMrationalize (value, & numerator, & denominator);
 		if (numerator == 0)
 			snprintf (buffer, 40, "0");
 		else if (denominator > 1)
-			snprintf (buffer, 40, "%ld/%ld", numerator, denominator);
+			snprintf (buffer, 40, "%s/%s", Melder8_integer (numerator), Melder8_integer (denominator));
 		else
 			snprintf (buffer, 40, "%.7g", value);
 	} else {
@@ -716,21 +719,21 @@ static void print4 (char *buffer, double value, int iformat, int width, int prec
 	}
 }
 
-static void fixRows (TableOfReal me, long *rowmin, long *rowmax) {
+static void fixRows (TableOfReal me, integer *rowmin, integer *rowmax) {
 	if (*rowmax < *rowmin) { *rowmin = 1; *rowmax = my numberOfRows; }
 	else if (*rowmin < 1) *rowmin = 1;
 	else if (*rowmax > my numberOfRows) *rowmax = my numberOfRows;
 }
-static void fixColumns (TableOfReal me, long *colmin, long *colmax) {
+static void fixColumns (TableOfReal me, integer *colmin, integer *colmax) {
 	if (*colmax < *colmin) { *colmin = 1; *colmax = my numberOfColumns; }
 	else if (*colmin < 1) *colmin = 1;
 	else if (*colmax > my numberOfColumns) *colmax = my numberOfColumns;
 }
-static double getMaxRowLabelWidth (TableOfReal me, Graphics graphics, long rowmin, long rowmax) {
+static double getMaxRowLabelWidth (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
 	double maxWidth = 0.0;
 	if (! my rowLabels) return 0.0;
 	fixRows (me, & rowmin, & rowmax);
-	for (long irow = rowmin; irow <= rowmax; irow ++) if (my rowLabels [irow] && my rowLabels [irow] [0]) {
+	for (integer irow = rowmin; irow <= rowmax; irow ++) if (my rowLabels [irow] && my rowLabels [irow] [0]) {
 		double textWidth = Graphics_textWidth_ps (graphics, my rowLabels [irow], true);   // SILIPA is bigger than XIPA
 		if (textWidth > maxWidth) maxWidth = textWidth;
 	}
@@ -742,17 +745,17 @@ static double getLeftMargin (Graphics graphics) {
 static double getLineSpacing (Graphics graphics) {
 	return Graphics_dyMMtoWC (graphics, 1.5 * Graphics_inqFontSize (graphics) * 25.4 / 72.0);
 }
-static double getMaxColumnLabelHeight (TableOfReal me, Graphics graphics, long colmin, long colmax) {
+static double getMaxColumnLabelHeight (TableOfReal me, Graphics graphics, integer colmin, integer colmax) {
 	double maxHeight = 0.0, lineSpacing = getLineSpacing (graphics);
 	if (! my columnLabels) return 0.0;
 	fixRows (me, & colmin, & colmax);
-	for (long icol = colmin; icol <= colmax; icol ++) if (my columnLabels [icol] && my columnLabels [icol] [0]) {
+	for (integer icol = colmin; icol <= colmax; icol ++) if (my columnLabels [icol] && my columnLabels [icol] [0]) {
 		if (maxHeight == 0.0) maxHeight = lineSpacing;
 	}
 	return maxHeight;
 }
 
-void TableOfReal_drawAsNumbers (TableOfReal me, Graphics graphics, long rowmin, long rowmax, int iformat, int precision) {
+void TableOfReal_drawAsNumbers (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax, int iformat, int precision) {
 	fixRows (me, & rowmin, & rowmax);
 	Graphics_setInner (graphics);
 	Graphics_setWindow (graphics, 0.5, my numberOfColumns + 0.5, 0.0, 1.0);
@@ -762,17 +765,17 @@ void TableOfReal_drawAsNumbers (TableOfReal me, Graphics graphics, long rowmin,
 	double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
 
 	Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_BOTTOM);
-	for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+	for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 		if (my columnLabels && my columnLabels [icol] && my columnLabels [icol] [0])
 			Graphics_text (graphics, icol, 1, my columnLabels [icol]);
 	}
-	for (long irow = rowmin; irow <= rowmax; irow ++) {
-		double y = 1 - lineSpacing * (irow - rowmin + 0.6);
+	for (integer irow = rowmin; irow <= rowmax; irow ++) {
+		double y = 1.0 - lineSpacing * (irow - rowmin + 0.6);
 		Graphics_setTextAlignment (graphics, Graphics_RIGHT, Graphics_HALF);
 		if (my rowLabels && my rowLabels [irow] && my rowLabels [irow] [0])
 			Graphics_text (graphics, 0.5 - leftMargin, y, my rowLabels [irow]);
 		Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_HALF);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			char text [40];
 			print4 (text, my data [irow] [icol], iformat, 0, precision);
 			Graphics_text (graphics, icol, y, Melder_peek8to32 (text));
@@ -786,7 +789,7 @@ void TableOfReal_drawAsNumbers (TableOfReal me, Graphics graphics, long rowmin,
 	Graphics_unsetInner (graphics);
 }
 
-void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics graphics, long rowmin, long rowmax, int iformat, int precision,
+void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax, int iformat, int precision,
 	const char32 *conditionFormula, Interpreter interpreter)
 {
 	try {
@@ -802,17 +805,17 @@ void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics graphics, long rowmi
 		Matrix_formula (original.get(), conditionFormula, interpreter, conditions.get());
 
 		Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_BOTTOM);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			if (my columnLabels && my columnLabels [icol] && my columnLabels [icol] [0])
 				Graphics_text (graphics, icol, 1, my columnLabels [icol]);
 		}
-		for (long irow = rowmin; irow <= rowmax; irow ++) {
-			double y = 1 - lineSpacing * (irow - rowmin + 0.6);
+		for (integer irow = rowmin; irow <= rowmax; irow ++) {
+			double y = 1.0 - lineSpacing * (irow - rowmin + 0.6);
 			Graphics_setTextAlignment (graphics, Graphics_RIGHT, Graphics_HALF);
 			if (my rowLabels && my rowLabels [irow] && my rowLabels [irow] [0])
 				Graphics_text (graphics, 0.5 - leftMargin, y, my rowLabels [irow]);
 			Graphics_setTextAlignment (graphics, Graphics_CENTRE, Graphics_HALF);
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) if (conditions -> z [irow] [icol] != 0.0) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) if (conditions -> z [irow] [icol] != 0.0) {
 				char text [40];
 				print4 (text, my data [irow] [icol], iformat, 0, precision);
 				Graphics_text (graphics, icol, y, Melder_peek8to32 (text));
@@ -829,8 +832,8 @@ void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics graphics, long rowmi
 	}
 }
 
-void TableOfReal_drawVerticalLines (TableOfReal me, Graphics graphics, long rowmin, long rowmax) {
-	long colmin = 1, colmax = my numberOfColumns;
+void TableOfReal_drawVerticalLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
+	integer colmin = 1, colmax = my numberOfColumns;
 	fixRows (me, & rowmin, & rowmax);
 	Graphics_setInner (graphics);
 	Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0, 1);
@@ -839,13 +842,13 @@ void TableOfReal_drawVerticalLines (TableOfReal me, Graphics graphics, long rowm
 	double maxTextHeight = getMaxColumnLabelHeight (me, graphics, 1, my numberOfColumns);
 
 	if (maxTextWidth > 0.0) colmin -= 1;
-	for (long col = colmin + 1; col <= colmax; col ++)
+	for (integer col = colmin + 1; col <= colmax; col ++)
 		Graphics_line (graphics, col - 0.5, 1.0 + maxTextHeight, col - 0.5, 1.0 - lineSpacing * (rowmax - rowmin + 1));
 	Graphics_unsetInner (graphics);
 }
 
-void TableOfReal_drawLeftAndRightLines (TableOfReal me, Graphics graphics, long rowmin, long rowmax) {
-	long colmin = 1, colmax = my numberOfColumns;
+void TableOfReal_drawLeftAndRightLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
+	integer colmin = 1, colmax = my numberOfColumns;
 	fixRows (me, & rowmin, & rowmax);
 	Graphics_setInner (graphics);
 	Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0.0, 1.0);
@@ -863,8 +866,8 @@ void TableOfReal_drawLeftAndRightLines (TableOfReal me, Graphics graphics, long
 	Graphics_unsetInner (graphics);
 }
 
-void TableOfReal_drawHorizontalLines (TableOfReal me, Graphics graphics, long rowmin, long rowmax) {
-	long colmin = 1, colmax = my numberOfColumns;
+void TableOfReal_drawHorizontalLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
+	integer colmin = 1, colmax = my numberOfColumns;
 	fixRows (me, & rowmin, & rowmax);
 	Graphics_setInner (graphics);
 	Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0, 1);
@@ -877,15 +880,15 @@ void TableOfReal_drawHorizontalLines (TableOfReal me, Graphics graphics, long ro
 	if (maxTextWidth > 0.0) left -= maxTextWidth + 2.0 * lineSpacing;
 	if (maxTextHeight > 0.0) rowmin -= 1;
 	double right = colmax + 0.5;
-	for (long irow = rowmin; irow < rowmax; irow ++) {
+	for (integer irow = rowmin; irow < rowmax; irow ++) {
 		double y = 1.0 - lineSpacing * (irow - top + 1);
 		Graphics_line (graphics, left, y, right, y);
 	}
 	Graphics_unsetInner (graphics);
 }
 
-void TableOfReal_drawTopAndBottomLines (TableOfReal me, Graphics graphics, long rowmin, long rowmax) {
-	long colmin = 1, colmax = my numberOfColumns;
+void TableOfReal_drawTopAndBottomLines (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax) {
+	integer colmin = 1, colmax = my numberOfColumns;
 	fixRows (me, & rowmin, & rowmax);
 	Graphics_setInner (graphics);
 	Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, 0.0, 1.0);
@@ -903,8 +906,8 @@ void TableOfReal_drawTopAndBottomLines (TableOfReal me, Graphics graphics, long
 	Graphics_unsetInner (graphics);
 }
 
-void TableOfReal_drawAsSquares (TableOfReal me, Graphics graphics, long rowmin, long rowmax,
-	long colmin, long colmax, int garnish)
+void TableOfReal_drawAsSquares (TableOfReal me, Graphics graphics, integer rowmin, integer rowmax,
+	integer colmin, integer colmax, bool garnish)
 {
 	double dx = 1.0, dy = 1.0;
 	Graphics_Colour colour = Graphics_inqColour (graphics);
@@ -914,13 +917,13 @@ void TableOfReal_drawAsSquares (TableOfReal me, Graphics graphics, long rowmin,
 	Graphics_setInner (graphics);
 	Graphics_setWindow (graphics, colmin - 0.5, colmax + 0.5, rowmin - 0.5, rowmax + 0.5);
 	double datamax = my data [rowmin] [colmin];
-	for (long irow = 1; irow <= my numberOfRows; irow ++)
-		for (long icol = 1; icol <= my numberOfColumns; icol ++)
+	for (integer irow = 1; irow <= my numberOfRows; irow ++)
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 			if (fabs (my data [irow] [icol]) > datamax) datamax = fabs (my data [irow] [icol]);
 	
-	for (long irow = rowmin; irow <= rowmax; irow ++) {
+	for (integer irow = rowmin; irow <= rowmax; irow ++) {
 		double y = rowmax + rowmin - irow;
-		for (long icol = colmin; icol <= colmax; icol ++) {
+		for (integer icol = colmin; icol <= colmax; icol ++) {
 			double x = icol;
 			/* two neighbouring squares should not touch -> 0.95 */
 			double d = 0.95 * sqrt (fabs (my data [irow] [icol]) / datamax);
@@ -935,9 +938,9 @@ void TableOfReal_drawAsSquares (TableOfReal me, Graphics graphics, long rowmin,
 	Graphics_setGrey (graphics, 0.0);
 	Graphics_unsetInner (graphics);
 	if (garnish) {
-		for (long irow = rowmin; irow <= rowmax; irow ++) if (my rowLabels [irow]) 
+		for (integer irow = rowmin; irow <= rowmax; irow ++) if (my rowLabels [irow])
 			Graphics_markLeft (graphics, rowmax + rowmin - irow, false, false, false, my rowLabels [irow]);
-		for (long icol = colmin; icol <= colmax; icol ++) if (my columnLabels [icol])
+		for (integer icol = colmin; icol <= colmax; icol ++) if (my columnLabels [icol])
 			Graphics_markTop (graphics, icol, false, false, false, my columnLabels [icol]);
 	}
 }
@@ -949,18 +952,18 @@ autoTableOfReal TablesOfReal_append (TableOfReal me, TableOfReal thee) {
 		autoTableOfReal him = Thing_newFromClass (my classInfo).static_cast_move <structTableOfReal> ();
 		TableOfReal_init (him.get(), my numberOfRows + thy numberOfRows, my numberOfColumns);
 		/* Unsafe: new attributes not initialized. */
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			TableOfReal_setColumnLabel (him.get(), icol, my columnLabels [icol]);
 		}
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 			TableOfReal_setRowLabel (him.get(), irow, my rowLabels [irow]);
-			for (long icol = 1; icol <= my numberOfColumns; icol ++)
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 				his data [irow] [icol] = my data [irow] [icol];
 		}
-		for (long irow = 1; irow <= thy numberOfRows; irow ++) {
-			long hisRow = irow + my numberOfRows;
+		for (integer irow = 1; irow <= thy numberOfRows; irow ++) {
+			integer hisRow = irow + my numberOfRows;
 			TableOfReal_setRowLabel (him.get(), hisRow, thy rowLabels [irow]);
-			for (long icol = 1; icol <= my numberOfColumns; icol ++)
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 				his data [hisRow] [icol] = thy data [irow] [icol];
 		}
 		return him;
@@ -973,9 +976,9 @@ autoTableOfReal TablesOfReal_appendMany (OrderedOf<structTableOfReal>* me) {
 	try {
 		if (my size == 0) Melder_throw (U"Cannot add zero tables.");
 		TableOfReal thee = my at [1];
-		long totalNumberOfRows = thy numberOfRows;
-		long numberOfColumns = thy numberOfColumns;
-		for (long itab = 2; itab <= my size; itab ++) {
+		integer totalNumberOfRows = thy numberOfRows;
+		integer numberOfColumns = thy numberOfColumns;
+		for (integer itab = 2; itab <= my size; itab ++) {
 			thee = my at [itab];
 			totalNumberOfRows += thy numberOfRows;
 			if (thy numberOfColumns != numberOfColumns) Melder_throw (U"Numbers of columns do not match.");
@@ -983,16 +986,16 @@ autoTableOfReal TablesOfReal_appendMany (OrderedOf<structTableOfReal>* me) {
 		autoTableOfReal him = Thing_newFromClass (thy classInfo).static_cast_move <structTableOfReal> ();
 		TableOfReal_init (him.get(), totalNumberOfRows, numberOfColumns);
 		/* Unsafe: new attributes not initialized. */
-		for (long icol = 1; icol <= numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 			TableOfReal_setColumnLabel (him.get(), icol, thy columnLabels [icol]);
 		}
 		totalNumberOfRows = 0;
-		for (long itab = 1; itab <= my size; itab ++) {
+		for (integer itab = 1; itab <= my size; itab ++) {
 			thee = my at [itab];
-			for (long irow = 1; irow <= thy numberOfRows; irow ++) {
+			for (integer irow = 1; irow <= thy numberOfRows; irow ++) {
 				totalNumberOfRows ++;
 				TableOfReal_setRowLabel (him.get(), totalNumberOfRows, thy rowLabels [irow]);
-				for (long icol = 1; icol <= numberOfColumns; icol ++)
+				for (integer icol = 1; icol <= numberOfColumns; icol ++)
 					his data [totalNumberOfRows] [icol] = thy data [irow] [icol];
 			}
 		}
@@ -1003,8 +1006,8 @@ autoTableOfReal TablesOfReal_appendMany (OrderedOf<structTableOfReal>* me) {
 	}
 }
 
-static void TableOfReal_sort (TableOfReal me, bool useLabels, long column1, long column2) {
-	for (long irow = 1; irow < my numberOfRows; irow ++) for (long jrow = irow + 1; jrow <= my numberOfRows; jrow ++) {
+static void TableOfReal_sort (TableOfReal me, bool useLabels, integer column1, integer column2) {
+	for (integer irow = 1; irow < my numberOfRows; irow ++) for (integer jrow = irow + 1; jrow <= my numberOfRows; jrow ++) {
 		char32 *tmpString;
 		if (useLabels) {
 			if (my rowLabels [irow]) {
@@ -1034,7 +1037,7 @@ static void TableOfReal_sort (TableOfReal me, bool useLabels, long column1, long
 		tmpString = my rowLabels [irow];
 		my rowLabels [irow] = my rowLabels [jrow];
 		my rowLabels [jrow] = tmpString;
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			double tmpValue = my data [irow] [icol];
 			my data [irow] [icol] = my data [jrow] [icol];
 			my data [jrow] [icol] = tmpValue;
@@ -1042,48 +1045,48 @@ static void TableOfReal_sort (TableOfReal me, bool useLabels, long column1, long
 	}
 }
 
-void TableOfReal_sortByLabel (TableOfReal me, long column1, long column2) {
+void TableOfReal_sortByLabel (TableOfReal me, integer column1, integer column2) {
 	TableOfReal_sort (me, true, column1, column2);
 }
 
-void TableOfReal_sortByColumn (TableOfReal me, long column1, long column2) {
+void TableOfReal_sortByColumn (TableOfReal me, integer column1, integer column2) {
 	TableOfReal_sort (me, false, column1, column2);
 }
 
-autoTableOfReal Table_to_TableOfReal (Table me, long labelColumn) {
+autoTableOfReal Table_to_TableOfReal (Table me, integer labelColumn) {
 	try {
 		if (labelColumn < 1 || labelColumn > my numberOfColumns) labelColumn = 0;
 		autoTableOfReal thee = TableOfReal_create (my rows.size, labelColumn ? my numberOfColumns - 1 : my numberOfColumns);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			Table_numericize_Assert (me, icol);
 		}
 		if (labelColumn) {
-			for (long icol = 1; icol < labelColumn; icol ++) {
+			for (integer icol = 1; icol < labelColumn; icol ++) {
 				TableOfReal_setColumnLabel (thee.get(), icol, my columnHeaders [icol]. label);
 			}
-			for (long icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) {
+			for (integer icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) {
 				TableOfReal_setColumnLabel (thee.get(), icol - 1, my columnHeaders [icol]. label);
 			}
-			for (long irow = 1; irow <= my rows.size; irow ++) {
+			for (integer irow = 1; irow <= my rows.size; irow ++) {
 				TableRow row = my rows.at [irow];
 				char32 *string = row -> cells [labelColumn]. string;
 				TableOfReal_setRowLabel (thee.get(), irow, string ? string : U"");
-				for (long icol = 1; icol < labelColumn; icol ++) {
+				for (integer icol = 1; icol < labelColumn; icol ++) {
 					thy data [irow] [icol] = row -> cells [icol]. number;   // Optimization.
 					//thy data [irow] [icol] = Table_getNumericValue_Assert (me, irow, icol);
 				}
-				for (long icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) {
+				for (integer icol = labelColumn + 1; icol <= my numberOfColumns; icol ++) {
 					thy data [irow] [icol - 1] = row -> cells [icol]. number;   // Optimization.
 					//thy data [irow] [icol - 1] = Table_getNumericValue_Assert (me, irow, icol);
 				}
 			}
 		} else {
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 				TableOfReal_setColumnLabel (thee.get(), icol, my columnHeaders [icol]. label);
 			}
-			for (long irow = 1; irow <= my rows.size; irow ++) {
+			for (integer irow = 1; irow <= my rows.size; irow ++) {
 				TableRow row = my rows.at [irow];
-				for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+				for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 					thy data [irow] [icol] = row -> cells [icol]. number;   // Optimization.
 					//thy data [irow] [icol] = Table_getNumericValue_Assert (me, irow, icol);
 				}
@@ -1099,15 +1102,15 @@ autoTable TableOfReal_to_Table (TableOfReal me, const char32 *labelOfFirstColumn
 	try {
 		autoTable thee = Table_createWithoutColumnNames (my numberOfRows, my numberOfColumns + 1);
 		Table_setColumnLabel (thee.get(), 1, labelOfFirstColumn);
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			char32 *columnLabel = my columnLabels [icol];
 			thy columnHeaders [icol + 1]. label = Melder_dup (columnLabel && columnLabel [0] ? columnLabel : U"?");
 		}
-		for (long irow = 1; irow <= thy rows.size; irow ++) {
+		for (integer irow = 1; irow <= thy rows.size; irow ++) {
 			char32 *stringValue = my rowLabels [irow];
 			TableRow row = thy rows.at [irow];
 			row -> cells [1]. string = Melder_dup (stringValue && stringValue [0] ? stringValue : U"?");
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 				double numericValue = my data [irow] [icol];
 				row -> cells [icol + 1]. string = Melder_dup (Melder_double (numericValue));
 			}
@@ -1122,16 +1125,16 @@ void TableOfReal_writeToHeaderlessSpreadsheetFile (TableOfReal me, MelderFile fi
 	try {
 		autoMelderString buffer;
 		MelderString_copy (& buffer, U"rowLabel");
-		for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+		for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 			MelderString_appendCharacter (& buffer, U'\t');
 			char32 *s = my columnLabels [icol];
 			MelderString_append (& buffer, ( s && s [0] != U'\0' ? s : U"?" ));
 		}
 		MelderString_appendCharacter (& buffer, U'\n');
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 			char32 *s = my rowLabels [irow];
 			MelderString_append (& buffer, ( s && s [0] != U'\0' ? s : U"?" ));
-			for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+			for (integer icol = 1; icol <= my numberOfColumns; icol ++) {
 				MelderString_appendCharacter (& buffer, U'\t');
 				double x = my data [irow] [icol];
 				MelderString_append (& buffer, x);
@@ -1147,12 +1150,11 @@ void TableOfReal_writeToHeaderlessSpreadsheetFile (TableOfReal me, MelderFile fi
 autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file) {
 	try {
 		autostring32 string = MelderFile_readText (file);
-		long nrow, ncol, nelements;
 
 		/*
-		 * Count columns.
-		 */
-		ncol = 0;
+			Count columns.
+		*/
+		integer ncol = 0;
 		char32 *p = & string [0];
 		for (;;) {
 			char32 kar = *p++;
@@ -1166,10 +1168,10 @@ autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file)
 		if (ncol < 1) Melder_throw (U"No columns.");
 
 		/*
-		 * Count elements.
-		 */
+			Count elements.
+		*/
 		p = & string [0];
-		nelements = 0;
+		integer nelements = 0;
 		for (;;) {
 			char32 kar = *p++;
 			if (kar == U'\0') break;
@@ -1180,25 +1182,25 @@ autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file)
 		}
 
 		/*
-		 * Check if all columns are complete.
-		 */
+			Check if all columns are complete.
+		*/
 		if (nelements == 0 || nelements % (ncol + 1) != 0)
 			Melder_throw (U"The number of elements (", nelements, U") is not a multiple of the number of columns plus 1 (", ncol + 1, U").");
 
 		/*
-		 * Create empty table.
-		 */
-		nrow = nelements / (ncol + 1) - 1;
+			Create empty table.
+		*/
+		integer nrow = nelements / (ncol + 1) - 1;
 		autoTableOfReal me = TableOfReal_create (nrow, ncol);
 
 		/*
-		 * Read elements.
-		 */
+			Read elements.
+		*/
 		autoMelderString buffer;
 		p = & string [0];
 		while (*p == U' ' || *p == U'\t') { Melder_assert (*p != U'\0'); p ++; }
 		while (*p != U' ' && *p != U'\t') { Melder_assert (*p != U'\0'); p ++; }   // ignore the header of the zeroth column ("rowLabel" perhaps)
-		for (long icol = 1; icol <= ncol; icol ++) {
+		for (integer icol = 1; icol <= ncol; icol ++) {
 			while (*p == U' ' || *p == U'\t') { Melder_assert (*p != U'\0'); p ++; }
 			MelderString_empty (& buffer);
 			while (*p != U' ' && *p != U'\t' && *p != U'\n') {
@@ -1207,7 +1209,7 @@ autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file)
 			}
 			TableOfReal_setColumnLabel (me.get(), icol, buffer.string);
 		}
-		for (long irow = 1; irow <= nrow; irow ++) {
+		for (integer irow = 1; irow <= nrow; irow ++) {
 			while (*p == U' ' || *p == U'\t' || *p == U'\n') { Melder_assert (*p != U'\0'); p ++; }
 			MelderString_empty (& buffer);
 			while (*p != U' ' && *p != U'\t') {
@@ -1215,7 +1217,7 @@ autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file)
 				p ++;
 			}
 			TableOfReal_setRowLabel (me.get(), irow, buffer.string);
-			for (long icol = 1; icol <= ncol; icol ++) {
+			for (integer icol = 1; icol <= ncol; icol ++) {
 				while (*p == U' ' || *p == U'\t' || *p == U'\n') { Melder_assert (*p != U'\0'); p ++; }
 				MelderString_empty (& buffer);
 				while (*p != U' ' && *p != U'\t' && *p != U'\n' && *p != U'\0') {
diff --git a/stat/TableOfReal.h b/stat/TableOfReal.h
index 57e669e..20821c7 100644
--- a/stat/TableOfReal.h
+++ b/stat/TableOfReal.h
@@ -2,7 +2,7 @@
 #define _TableOfReal_h_
 /* TableOfReal.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,36 +26,36 @@ Thing_declare (Interpreter);
 
 #include "TableOfReal_def.h"
 
-void TableOfReal_init (TableOfReal me, long numberOfRows, long numberOfColumns);
-autoTableOfReal TableOfReal_create (long numberOfRows, long numberOfColumns);
-void TableOfReal_removeRow (TableOfReal me, long irow);
-void TableOfReal_removeColumn (TableOfReal me, long icol);
-void TableOfReal_insertRow (TableOfReal me, long irow);
-void TableOfReal_insertColumn (TableOfReal me, long icol);
-void TableOfReal_setRowLabel    (TableOfReal me, long irow, const char32 *label /* cattable */);
-void TableOfReal_setColumnLabel (TableOfReal me, long icol, const char32 *label /* cattable */);
-long TableOfReal_rowLabelToIndex    (TableOfReal me, const char32 *label /* cattable */);
-long TableOfReal_columnLabelToIndex (TableOfReal me, const char32 *label /* cattable */);
-double TableOfReal_getColumnMean (TableOfReal me, long icol);
-double TableOfReal_getColumnStdev (TableOfReal me, long icol);
+void TableOfReal_init (TableOfReal me, integer numberOfRows, integer numberOfColumns);
+autoTableOfReal TableOfReal_create (integer numberOfRows, integer numberOfColumns);
+void TableOfReal_removeRow (TableOfReal me, integer rowNumber);
+void TableOfReal_removeColumn (TableOfReal me, integer columnNumber);
+void TableOfReal_insertRow (TableOfReal me, integer rowNumber);
+void TableOfReal_insertColumn (TableOfReal me, integer columnNumber);
+void TableOfReal_setRowLabel    (TableOfReal me, integer rowNumber, const char32 *label /* cattable */);
+void TableOfReal_setColumnLabel (TableOfReal me, integer columnNumber, const char32 *label /* cattable */);
+integer TableOfReal_rowLabelToIndex    (TableOfReal me, const char32 *label /* cattable */);
+integer TableOfReal_columnLabelToIndex (TableOfReal me, const char32 *label /* cattable */);
+double TableOfReal_getColumnMean (TableOfReal me, integer columnNumber);
+double TableOfReal_getColumnStdev (TableOfReal me, integer columnNumber);
 
-autoTableOfReal Table_to_TableOfReal (Table me, long labelColumn);
+autoTableOfReal Table_to_TableOfReal (Table me, integer labelColumn);
 autoTable TableOfReal_to_Table (TableOfReal me, const char32 *labelOfFirstColumn);
 void TableOfReal_formula (TableOfReal me, const char32 *expression, Interpreter interpreter, TableOfReal target);
-void TableOfReal_drawAsNumbers (TableOfReal me, Graphics g, long rowmin, long rowmax, int iformat, int precision);
-void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics g, long rowmin, long rowmax, int iformat, int precision,
+void TableOfReal_drawAsNumbers (TableOfReal me, Graphics g, integer rowmin, integer rowmax, int iformat, int precision);
+void TableOfReal_drawAsNumbers_if (TableOfReal me, Graphics g, integer rowmin, integer rowmax, int iformat, int precision,
 	const char32 *conditionFormula, Interpreter interpreter);
-void TableOfReal_drawAsSquares (TableOfReal me, Graphics g, long rowmin, long rowmax,
-	long colmin, long colmax, int garnish);
-void TableOfReal_drawVerticalLines (TableOfReal me, Graphics g, long rowmin, long rowmax);
-void TableOfReal_drawHorizontalLines (TableOfReal me, Graphics g, long rowmin, long rowmax);
-void TableOfReal_drawLeftAndRightLines (TableOfReal me, Graphics g, long rowmin, long rowmax);
-void TableOfReal_drawTopAndBottomLines (TableOfReal me, Graphics g, long rowmin, long rowmax);
+void TableOfReal_drawAsSquares (TableOfReal me, Graphics g, integer rowmin, integer rowmax,
+	integer colmin, integer colmax, bool garnish);
+void TableOfReal_drawVerticalLines (TableOfReal me, Graphics g, integer rowmin, integer rowmax);
+void TableOfReal_drawHorizontalLines (TableOfReal me, Graphics g, integer rowmin, integer rowmax);
+void TableOfReal_drawLeftAndRightLines (TableOfReal me, Graphics g, integer rowmin, integer rowmax);
+void TableOfReal_drawTopAndBottomLines (TableOfReal me, Graphics g, integer rowmin, integer rowmax);
 
 autoTableOfReal TablesOfReal_append (TableOfReal me, TableOfReal thee);
 autoTableOfReal TablesOfReal_appendMany (OrderedOf<structTableOfReal>* me);
-void TableOfReal_sortByLabel (TableOfReal me, long column1, long column2);
-void TableOfReal_sortByColumn (TableOfReal me, long column1, long column2);
+void TableOfReal_sortByLabel (TableOfReal me, integer column1, integer column2);
+void TableOfReal_sortByColumn (TableOfReal me, integer column1, integer column2);
 
 void TableOfReal_writeToHeaderlessSpreadsheetFile (TableOfReal me, MelderFile file);
 autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file);
@@ -63,8 +63,8 @@ autoTableOfReal TableOfReal_readFromHeaderlessSpreadsheetFile (MelderFile file);
 autoTableOfReal TableOfReal_extractRowRanges (TableOfReal me, const char32 *ranges);
 autoTableOfReal TableOfReal_extractColumnRanges (TableOfReal me, const char32 *ranges);
 
-autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, long icol, int which_Melder_NUMBER, double criterion);
-autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, long icol, int which_Melder_NUMBER, double criterion);
+autoTableOfReal TableOfReal_extractRowsWhereColumn (TableOfReal me, integer icol, int which_Melder_NUMBER, double criterion);
+autoTableOfReal TableOfReal_extractColumnsWhereRow (TableOfReal me, integer icol, int which_Melder_NUMBER, double criterion);
 
 autoTableOfReal TableOfReal_extractRowsWhereLabel (TableOfReal me, int which_Melder_STRING, const char32 *criterion);
 autoTableOfReal TableOfReal_extractColumnsWhereLabel (TableOfReal me, int which_Melder_STRING, const char32 *criterion);
diff --git a/stat/Table_def.h b/stat/Table_def.h
index 97800e6..75cbd19 100644
--- a/stat/Table_def.h
+++ b/stat/Table_def.h
@@ -50,7 +50,7 @@ oo_DEFINE_STRUCT (TableColumnHeader)
 	oo_STRING (label)
 
 	#if oo_DECLARING || oo_COPYING
-		oo_INT (numericized)
+		oo_INT16 (numericized)
 	#endif
 
 oo_END_STRUCT (TableColumnHeader)
diff --git a/stat/praat_Stat.cpp b/stat/praat_Stat.cpp
index bb7d40a..67bf634 100644
--- a/stat/praat_Stat.cpp
+++ b/stat/praat_Stat.cpp
@@ -933,7 +933,7 @@ DO
 		long columnNumber = Table_getColumnIndexFromColumnLabel (me, extractAllRowsWhereColumn___);
 		autoTable result = Table_extractRowsWhereColumn_number (me, columnNumber, ___is___, ___theNumber);
 	CONVERT_EACH_END (my name, U"_", Table_messageColumn (me, columnNumber), U"_",
-		NUMdefined (___theNumber) ? Melder_integer (lround (___theNumber)) : U"undefined")
+		isdefined (___theNumber) ? Melder_integer (lround (___theNumber)) : U"undefined")
 }
 
 FORM (NEW_Table_extractRowsWhereColumn_text, U"Table: Extract rows where column (text)", nullptr) {
diff --git a/sys/ButtonEditor.cpp b/sys/ButtonEditor.cpp
index f792eac..c18aab1 100644
--- a/sys/ButtonEditor.cpp
+++ b/sys/ButtonEditor.cpp
@@ -33,7 +33,7 @@ Thing_implement (ButtonEditor, HyperPage, 0);
 #endif
 
 static void drawMenuCommand (ButtonEditor me, Praat_Command cmd, long i) {
-	static MelderString text { 0 };
+	static MelderString text { };
 	bool isAdded = cmd -> uniqueID != 0 || cmd -> script != nullptr;
 	bool isHidden = cmd -> hidden;
 	bool isToggled = cmd -> toggled;
@@ -69,7 +69,7 @@ static void drawMenuCommand (ButtonEditor me, Praat_Command cmd, long i) {
 }
 
 static void drawAction (ButtonEditor me, Praat_Command cmd, long i) {
-	static MelderString text { 0 };
+	static MelderString text { };
 	bool isAdded = cmd -> uniqueID != 0 || cmd -> script != nullptr;
 	bool isHidden = cmd -> hidden, isToggled = cmd -> toggled;
 	const char32 *clickText = isHidden ? (isToggled ? (isAdded ? U"REMOVED" : U"HIDDEN") : U"hidden") :
diff --git a/sys/Collection.cpp b/sys/Collection.cpp
index bc9bf6b..d5fe4f0 100644
--- a/sys/Collection.cpp
+++ b/sys/Collection.cpp
@@ -1,6 +1,6 @@
 /* Collection.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -73,7 +73,7 @@ bool _CollectionOfDaata_v_canWriteAsEncoding (_CollectionOfDaata* me, int encodi
 }
 
 void _CollectionOfDaata_v_writeText (_CollectionOfDaata* me, MelderFile file) {
-	texputi4 (file, my size, U"size", 0,0,0,0,0);
+	texputi32 (file, my size, U"size", 0,0,0,0,0);
 	texputintro (file, U"item []: ", my size ? nullptr : U"(empty)", 0,0,0,0);
 	for (long i = 1; i <= my size; i ++) {
 		Daata thing = my at [i];
@@ -81,12 +81,12 @@ void _CollectionOfDaata_v_writeText (_CollectionOfDaata* me, MelderFile file) {
 		texputintro (file, U"item [", Melder_integer (i), U"]:", 0,0,0);
 		if (! Thing_isa (thing, classDaata) || ! Data_canWriteText (thing))
 			Melder_throw (U"Objects of class ", classInfo -> className, U" cannot be written.");
-		texputw2 (file,
+		texputw16 (file,
 			classInfo -> version > 0 ?
 				Melder_cat (classInfo -> className, U" ", classInfo -> version) :
 				classInfo -> className,
 			U"class", 0,0,0,0,0);
-		texputw2 (file, thing -> name, U"name", 0,0,0,0,0);
+		texputw16 (file, thing -> name, U"name", 0,0,0,0,0);
 		Data_writeText (thing, file);
 		texexdent (file);
 	}
@@ -131,16 +131,16 @@ void _CollectionOfDaata_v_readText (_CollectionOfDaata* me, MelderReadText text,
 			}
 		}
 	} else {
-		int32_t l_size = texgeti4 (text);
+		int32_t l_size = texgeti32 (text);
 		my _grow (l_size);
 		for (int32_t i = 1; i <= l_size; i ++) {
-			autostring32 className = texgetw2 (text);
+			autostring32 className = texgetw16 (text);
 			int elementFormatVersion;
 			my at [i] = (Daata) Thing_newFromClassName (className.peek(), & elementFormatVersion).releaseToAmbiguousOwner();
 			my size ++;
 			if (! Thing_isa (my at [i], classDaata) || ! Data_canReadText (my at [i]))
 				Melder_throw (U"Cannot read item of class ", Thing_className (my at [i]), U" in collection.");
-			autostring32 objectName = texgetw2 (text);
+			autostring32 objectName = texgetw16 (text);
 			Thing_setName (my at [i], objectName.peek());
 			Data_readText (my at [i], text, elementFormatVersion);
 		}
@@ -148,22 +148,22 @@ void _CollectionOfDaata_v_readText (_CollectionOfDaata* me, MelderReadText text,
 }
 
 void _CollectionOfDaata_v_writeBinary (_CollectionOfDaata* me, FILE *f) {
-	binputi4 (my size, f);
+	binputi32 (my size, f);
 	for (long i = 1; i <= my size; i ++) {
 		Daata thing = my at [i];
 		ClassInfo classInfo = thing -> classInfo;
 		if (! Thing_isa (thing, classDaata) || ! Data_canWriteBinary (thing))
 			Melder_throw (U"Objects of class ", classInfo -> className, U" cannot be written.");
-		binputw1 (classInfo -> version > 0 ?
+		binputw8 (classInfo -> version > 0 ?
 			Melder_cat (classInfo -> className, U" ", classInfo -> version) : classInfo -> className, f);
-		binputw2 (thing -> name, f);
+		binputw16 (thing -> name, f);
 		Data_writeBinary ((Daata) thing, f);
 	}
 }
 
 void _CollectionOfDaata_v_readBinary (_CollectionOfDaata* me, FILE *f, int formatVersion) {
 	if (formatVersion < 0) {
-		int32 l_size = bingeti4 (f);
+		int32 l_size = bingeti32 (f);
 		if (l_size < 0)
 			Melder_throw (U"Empty collection.");
 		my _grow (l_size);
@@ -182,12 +182,12 @@ void _CollectionOfDaata_v_readBinary (_CollectionOfDaata* me, FILE *f, int forma
 				Thing_setName (my at [i], Melder_peek8to32 (name));
 		}
 	} else {
-		int32_t l_size = bingeti4 (f);
+		int32_t l_size = bingeti32 (f);
 		if (Melder_debug == 44)
 			Melder_casual (U"structCollection :: v_readBinary: Reading ", l_size, U" objects");
 		my _grow (l_size);
 		for (int32_t i = 1; i <= l_size; i ++) {
-			autostring8 klas = bingets1 (f);
+			autostring8 klas = bingets8 (f);
 			if (Melder_debug == 44)
 				Melder_casual (U"structCollection :: v_readBinary: Reading object of type ", Melder_peek8to32 (klas.peek()));
 			int elementFormatVersion;
@@ -195,7 +195,7 @@ void _CollectionOfDaata_v_readBinary (_CollectionOfDaata* me, FILE *f, int forma
 			my size ++;
 			if (! Thing_isa (my at [i], classDaata) || ! Data_canReadBinary (my at [i]))
 				Melder_throw (U"Objects of class ", Thing_className (my at [i]), U" cannot be read.");
-			autostring32 name = bingetw2 (f);
+			autostring32 name = bingetw16 (f);
 			if (Melder_debug == 44)
 				Melder_casual (U"structCollection :: v_readBinary: Reading object with name ", name.peek());
 			Thing_setName (my at [i], name.peek());
diff --git a/sys/Data.cpp b/sys/Data.cpp
index e43aafb..e63be1b 100644
--- a/sys/Data.cpp
+++ b/sys/Data.cpp
@@ -1,6 +1,6 @@
 /* Data.cpp
  *
- * Copyright (C) 1992-2012,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
 
 Thing_implement (Daata, Thing, 0);
 
-structMelderDir Data_directoryBeingRead { { 0 } };
+structMelderDir Data_directoryBeingRead { };
 
 void structDaata :: v_copy (Daata /* thee */) {
 }
@@ -91,7 +91,7 @@ MelderFile Data_createTextFile (Daata me, MelderFile file, bool verbose) {
 	else if (file -> outputEncoding == kMelder_textOutputEncoding_ISO_LATIN1_THEN_UTF16)
 		file -> outputEncoding = Data_canWriteAsEncoding (me, kMelder_textOutputEncoding_ISO_LATIN1) ? kMelder_textOutputEncoding_ISO_LATIN1 : kMelder_textOutputEncoding_UTF16;
 	if (file -> outputEncoding == kMelder_textOutputEncoding_UTF16) {
-		binputu2 (0xfeff, file -> filePointer);
+		binputu16 (0xfeff, file -> filePointer);
 	}
 	return mfile.transfer();
 }
@@ -155,7 +155,7 @@ void Data_writeToBinaryFile (Daata me, MelderFile file) {
 		autoMelderFile mfile = MelderFile_create (file);
 		if (fprintf (file -> filePointer, "ooBinaryFile") < 0)
 			Melder_throw (U"Cannot write first bytes of file.");
-		binputw1 (
+		binputw8 (
 			my classInfo -> version > 0 ?
 				Melder_cat (my classInfo -> className, U" ", my classInfo -> version) :
 				my classInfo -> className,
@@ -190,7 +190,7 @@ autoDaata Data_readFromTextFile (MelderFile file) {
 		autoDaata me;
 		int formatVersion;
 		if (end) {
-			autostring32 klas = texgetw2 (text.peek());
+			autostring32 klas = texgetw16 (text.peek());
 			me = Thing_newFromClassName (klas.peek(), & formatVersion).static_cast_move <structDaata> ();
 		} else {
 			end = str32str (line, U"TextFile");
@@ -236,7 +236,7 @@ autoDaata Data_readFromBinaryFile (MelderFile file) {
 		int formatVersion;
 		if (end) {
 			fseek (f, strlen ("ooBinaryFile"), 0);
-			autostring8 klas = bingets1 (f);
+			autostring8 klas = bingets8 (f);
 			me = Thing_newFromClassName (Melder_peek8to32 (klas.peek()), & formatVersion).static_cast_move <structDaata> ();
 		} else {
 			end = strstr (line, "BinaryFile");
@@ -381,6 +381,7 @@ Data_Description Data_Description_findNumberUse (Data_Description structDescript
 int64 Data_Description_integer (void *address, Data_Description description) {
 	switch (description -> type) {
 		case bytewa:           return * (signed char *)    ((char *) address + description -> offset);
+		case int16wa:          return * (int16 *)          ((char *) address + description -> offset);
 		case intwa:            return * (int *)            ((char *) address + description -> offset);
 		case longwa:           return * (long *)           ((char *) address + description -> offset);
 		case ubytewa:          return * (unsigned char *)  ((char *) address + description -> offset);
diff --git a/sys/Data.h b/sys/Data.h
index f5011c7..970c9a0 100644
--- a/sys/Data.h
+++ b/sys/Data.h
@@ -2,7 +2,7 @@
 #define _Data_h_
 /* Data.h
  *
- * Copyright (C) 1992-2012,2015 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -51,31 +51,31 @@ Thing_define (Daata, Thing) {
 	virtual void v_readBinary (FILE *f, int formatVersion);
 	virtual void v_repair () { }   // after reading Praat data files created by others
 	// methods for scripting:
-	virtual bool v_hasGetNrow      () { return false; }   virtual double        v_getNrow      ()                                 { return NUMundefined; }
-	virtual bool v_hasGetNcol      () { return false; }   virtual double        v_getNcol      ()                                 { return NUMundefined; }
-	virtual bool v_hasGetXmin      () { return false; }   virtual double        v_getXmin      ()                                 { return NUMundefined; }
-	virtual bool v_hasGetXmax      () { return false; }   virtual double        v_getXmax      ()                                 { return NUMundefined; }
-	virtual bool v_hasGetYmin      () { return false; }   virtual double        v_getYmin      ()                                 { return NUMundefined; }
-	virtual bool v_hasGetYmax      () { return false; }   virtual double        v_getYmax      ()                                 { return NUMundefined; }
-	virtual bool v_hasGetNx        () { return false; }   virtual double        v_getNx        ()                                 { return NUMundefined; }
-	virtual bool v_hasGetNy        () { return false; }   virtual double        v_getNy        ()                                 { return NUMundefined; }
-	virtual bool v_hasGetDx        () { return false; }   virtual double        v_getDx        ()                                 { return NUMundefined; }
-	virtual bool v_hasGetDy        () { return false; }   virtual double        v_getDy        ()                                 { return NUMundefined; }
-	virtual bool v_hasGetX         () { return false; }   virtual double        v_getX         (long /* ix */)                    { return NUMundefined; }
-	virtual bool v_hasGetY         () { return false; }   virtual double        v_getY         (long /* iy */)                    { return NUMundefined; }
+	virtual bool v_hasGetNrow      () { return false; }   virtual double        v_getNrow      ()                                 { return undefined; }
+	virtual bool v_hasGetNcol      () { return false; }   virtual double        v_getNcol      ()                                 { return undefined; }
+	virtual bool v_hasGetXmin      () { return false; }   virtual double        v_getXmin      ()                                 { return undefined; }
+	virtual bool v_hasGetXmax      () { return false; }   virtual double        v_getXmax      ()                                 { return undefined; }
+	virtual bool v_hasGetYmin      () { return false; }   virtual double        v_getYmin      ()                                 { return undefined; }
+	virtual bool v_hasGetYmax      () { return false; }   virtual double        v_getYmax      ()                                 { return undefined; }
+	virtual bool v_hasGetNx        () { return false; }   virtual double        v_getNx        ()                                 { return undefined; }
+	virtual bool v_hasGetNy        () { return false; }   virtual double        v_getNy        ()                                 { return undefined; }
+	virtual bool v_hasGetDx        () { return false; }   virtual double        v_getDx        ()                                 { return undefined; }
+	virtual bool v_hasGetDy        () { return false; }   virtual double        v_getDy        ()                                 { return undefined; }
+	virtual bool v_hasGetX         () { return false; }   virtual double        v_getX         (long /* ix */)                    { return undefined; }
+	virtual bool v_hasGetY         () { return false; }   virtual double        v_getY         (long /* iy */)                    { return undefined; }
 	virtual bool v_hasGetRowStr    () { return false; }   virtual const char32 *v_getRowStr    (long /* irow */)                  { return nullptr;      }
 	virtual bool v_hasGetColStr    () { return false; }   virtual const char32 *v_getColStr    (long /* icol */)                  { return nullptr;      }
-	virtual bool v_hasGetCell      () { return false; }   virtual double        v_getCell      ()                                 { return NUMundefined; }
+	virtual bool v_hasGetCell      () { return false; }   virtual double        v_getCell      ()                                 { return undefined; }
 	virtual bool v_hasGetCellStr   () { return false; }   virtual const char32 *v_getCellStr   ()                                 { return nullptr; }
-	virtual bool v_hasGetVector    () { return false; }   virtual double        v_getVector    (long /* irow */, long /* icol */) { return NUMundefined; }
+	virtual bool v_hasGetVector    () { return false; }   virtual double        v_getVector    (long /* irow */, long /* icol */) { return undefined; }
 	virtual bool v_hasGetVectorStr () { return false; }   virtual const char32 *v_getVectorStr (long /* icol */)                  { return nullptr;      }
-	virtual bool v_hasGetMatrix    () { return false; }   virtual double        v_getMatrix    (long /* irow */, long /* icol */) { return NUMundefined; }
+	virtual bool v_hasGetMatrix    () { return false; }   virtual double        v_getMatrix    (long /* irow */, long /* icol */) { return undefined; }
 	virtual bool v_hasGetMatrixStr () { return false; }   virtual const char32 *v_getMatrixStr (long /* irow */, long /* icol */) { return nullptr;      }
-	virtual bool v_hasGetFunction0 () { return false; }   virtual double        v_getFunction0 ()                                 { return NUMundefined; }
-	virtual bool v_hasGetFunction1 () { return false; }   virtual double        v_getFunction1 (long /* irow */, double /* x */)  { return NUMundefined; }
-	virtual bool v_hasGetFunction2 () { return false; }   virtual double        v_getFunction2 (double /* x */, double /* y */)   { return NUMundefined; }
-	virtual bool v_hasGetRowIndex  () { return false; }   virtual double        v_getRowIndex  (const char32 * /* rowLabel */)    { return NUMundefined; }
-	virtual bool v_hasGetColIndex  () { return false; }   virtual double        v_getColIndex  (const char32 * /* colLabel */)    { return NUMundefined; }
+	virtual bool v_hasGetFunction0 () { return false; }   virtual double        v_getFunction0 ()                                 { return undefined; }
+	virtual bool v_hasGetFunction1 () { return false; }   virtual double        v_getFunction1 (long /* irow */, double /* x */)  { return undefined; }
+	virtual bool v_hasGetFunction2 () { return false; }   virtual double        v_getFunction2 (double /* x */, double /* y */)   { return undefined; }
+	virtual bool v_hasGetRowIndex  () { return false; }   virtual double        v_getRowIndex  (const char32 * /* rowLabel */)    { return undefined; }
+	virtual bool v_hasGetColIndex  () { return false; }   virtual double        v_getColIndex  (const char32 * /* colLabel */)    { return undefined; }
 };
 
 template <class T> _Thing_auto<T> Data_copy (T* data) {
@@ -328,30 +328,31 @@ void Data_setPublishProc (int (*publish) (autoDaata));
 /* The values of 'type' in struct descriptions. */
 
 #define bytewa  1
-#define intwa  2
-#define longwa  3
-#define ubytewa  4
-#define uintwa  5
-#define ulongwa  6
-#define boolwa 7
-#define floatwa  8
-#define doublewa  9
-#define fcomplexwa  10
-#define dcomplexwa  11
-#define enumwa  12
-#define lenumwa  13
-#define booleanwa  14
-#define questionwa  15
-#define stringwa  16
-#define lstringwa  17
+#define int16wa  2
+#define intwa  3
+#define longwa  4
+#define ubytewa  5
+#define uintwa  6
+#define ulongwa  7
+#define boolwa 8
+#define floatwa  9
+#define doublewa  10
+#define fcomplexwa  11
+#define dcomplexwa  12
+#define enumwa  13
+#define lenumwa  14
+#define booleanwa  15
+#define questionwa  16
+#define stringwa  17
+#define lstringwa  18
 #define maxsingletypewa lstringwa
-#define structwa  18
-#define widgetwa  19
-#define objectwa  20
-#define autoobjectwa  21
-#define collectionofwa  22
-#define autocollectionwa  23
-#define inheritwa  24
+#define structwa  19
+#define widgetwa  20
+#define objectwa  21
+#define autoobjectwa  22
+#define collectionofwa  23
+#define autocollectionwa  24
+#define inheritwa  25
 
 /* Recursive routines for working with struct members. */
 
diff --git a/sys/DataEditor.cpp b/sys/DataEditor.cpp
index d672159..fab971b 100644
--- a/sys/DataEditor.cpp
+++ b/sys/DataEditor.cpp
@@ -35,16 +35,6 @@ static Data_Description Class_getDescription (ClassInfo table) {
 	return ((Daata) _Thing_dummyObject (table)) -> v_description ();
 }
 
-/*static const char * typeStrings [] = { "none",
-	"byte", "int", "long", "ubyte", "ushort", "uint", "ulong", "bool",
-	"float", "double", "fcomplex", "dcomplex",
-	"enum", "lenum", "boolean", "question", "stringw", "lstringw",
-	"struct", "widget", "object", "collection" };*/
-static int stringLengths [] = { 0,
-	4, 6, 11, 3, 5, 10, 1,
-	15, 27, 35, 59,
-	33, 33, 8, 6, 60, 60 };
-
 static void VectorEditor_create (DataEditor root, const char32 *title, void *address,
 	Data_Description description, long minimum, long maximum);
 
@@ -137,6 +127,22 @@ static void gui_button_cb_change (DataSubEditor me, GuiButtonEvent /* event */)
 						}
 					}
 				} break;
+				case int16wa: {
+					int16 oldValue = * (int16 *) my d_fieldData [irow]. address;
+					int64 newValue = Melder_atoi (text);
+					if (newValue != oldValue) {
+						Data_Description numberUse = DataSubEditor_findNumberUse (me, my d_fieldData [irow]. description -> name);
+						if (numberUse) {
+							Melder_flushError (U"Changing field \"", strip_d (my d_fieldData [irow]. description -> name),
+								U"\" would damage the array \"", strip_d (numberUse -> name), U"\".");
+						} else if (newValue < INT16_MIN || newValue > INT16_MAX) {
+							Melder_flushError (U"Field \"", strip_d (my d_fieldData [irow]. description -> name),
+								U"\" can have no values less than ", INT16_MIN, U" or greater than ", INT16_MAX, U".");
+						} else {
+							* (int16 *) my d_fieldData [irow]. address = (int16) newValue;   // guarded conversion
+						}
+					}
+				} break;
 				case intwa: {
 					int oldValue = * (int *) my d_fieldData [irow]. address, newValue = Melder_atoi (text);
 					if (newValue != oldValue) {
@@ -186,14 +192,26 @@ static void gui_button_cb_change (DataSubEditor me, GuiButtonEvent /* event */)
 					* (signed short *) my d_fieldData [irow]. address = (signed short) value;
 				} break;
 				case booleanwa: {
-					int value = str32nequ (text, U"<true>", 6) ? 1 : str32nequ (text, U"<false>", 7) ? 0 : -1;
-					if (value < 0) goto error;
-					* (signed char *) my d_fieldData [irow]. address = (signed char) value;
+					bool value;
+					if (str32nequ (text, U"<true>", 6)) {
+						value = true;
+					} else if (str32nequ (text, U"<false>", 7)) {
+						value = false;
+					} else {
+						goto error;
+					}
+					* (bool *) my d_fieldData [irow]. address = value;
 				} break;
 				case questionwa: {
-					int value = str32nequ (text, U"<yes>", 5) ? 1 : str32nequ (text, U"<no>", 4) ? 0 : -1;
-					if (value < 0) goto error;
-					* (signed char *) my d_fieldData [irow]. address = (signed char) value;
+					bool value;
+					if (str32nequ (text, U"<yes>", 5)) {
+						value = true;
+					} else if (str32nequ (text, U"<no>", 4)) {
+						value = false;
+					} else {
+						goto error;
+					}
+					* (bool *) my d_fieldData [irow]. address = value;
 				} break;
 				case stringwa:
 				case lstringwa: {
@@ -232,7 +250,7 @@ static void gui_cb_scroll (DataSubEditor me, GuiScrollBarEvent event) {
 
 static void gui_button_cb_open (DataSubEditor me, GuiButtonEvent event) {
 	int ifield = 0;
-	static MelderString name { 0 };
+	static MelderString name { };
 	MelderString_empty (& name);
 
 	/* Identify the pressed button; it must be one of those created in the list. */
@@ -341,6 +359,7 @@ long structStructEditor :: v_countFields () {
 static const char32 * singleTypeToText (void *address, int type, void *tagType, MelderString *buffer) {
 	switch (type) {
 		case bytewa:   MelderString_append (buffer, Melder_integer (* (signed char *)    address)); break;
+		case int16wa:  MelderString_append (buffer, Melder_integer (* (int16 *)          address)); break;
 		case intwa:    MelderString_append (buffer, Melder_integer (* (int *)            address)); break;
 		case longwa:   MelderString_append (buffer, Melder_integer (* (long *)           address)); break;
 		case ubytewa:  MelderString_append (buffer, Melder_integer (* (unsigned char *)  address)); break;
@@ -355,8 +374,8 @@ static const char32 * singleTypeToText (void *address, int type, void *tagType,
 			MelderString_append (buffer, Melder_double (value. re), U" + ", Melder_double (value. im), U" i"); } break;
 		case enumwa:  MelderString_append (buffer, U"<", ((const char32 * (*) (int)) tagType) (* (signed char *)  address), U">"); break;
 		case lenumwa: MelderString_append (buffer, U"<", ((const char32 * (*) (int)) tagType) (* (signed short *) address), U">"); break;
-		case booleanwa:  MelderString_append (buffer, * (signed char *) address ? U"<true>" : U"<false>"); break;
-		case questionwa: MelderString_append (buffer, * (signed char *) address ? U"<yes>"  : U"<no>"   ); break;
+		case booleanwa:  MelderString_append (buffer, * (bool *) address ? U"<true>" : U"<false>"); break;
+		case questionwa: MelderString_append (buffer, * (bool *) address ? U"<yes>"  : U"<no>"   ); break;
 		case stringwa:
 		case lstringwa: {
 			char32 *string = * (char32 **) address;
@@ -391,7 +410,7 @@ static void showStructMember (
 	/* Show the value (for a single type) or a button (for a composite type). */
 	if (isSingleType) {
 		#if motif
-			XtVaSetValues (fieldData -> text -> d_widget, XmNcolumns, stringLengths [type], nullptr);   // TODO: change to GuiObject_size
+			XtVaSetValues (fieldData -> text -> d_widget, XmNcolumns, 60, nullptr);   // TODO: change to GuiObject_size
 		#endif
 		autoMelderString buffer;
 		const char32 *text = singleTypeToText (memberAddress, type, memberDescription -> tagType, & buffer);
@@ -554,14 +573,14 @@ void structVectorEditor :: v_showMembers () {
 			autoMelderString buffer;
 			const char32 *text = singleTypeToText (elementAddress, type, d_description -> tagType, & buffer);
 			#if motif
-				XtVaSetValues (fieldData -> text -> d_widget, XmNcolumns, stringLengths [type], nullptr);   // TODO: change to GuiObject_size
+				XtVaSetValues (fieldData -> text -> d_widget, XmNcolumns, 60, nullptr);   // TODO: change to GuiObject_size
 			#endif
 			GuiText_setString (fieldData -> text, text);
 			GuiThing_show (fieldData -> text);
 			fieldData -> address = elementAddress;
 			fieldData -> description = d_description;
 		} else if (type == structwa) {
-			static MelderString history { 0 };
+			static MelderString history { };
 			MelderString_copy (& history, name);
 
 			/* Replace things like [1..100] by things like [19]. */
@@ -584,7 +603,7 @@ void structVectorEditor :: v_showMembers () {
 			}
 			showStructMembers (this, elementAddress, * (Data_Description *) d_description -> tagType, skip, history.string);
 		} else if (type == objectwa || type == autoobjectwa) {
-			static MelderString history { 0 };
+			static MelderString history { };
 			MelderString_copy (& history, name);
 			if (history.string [history.length - 1] == U']') {
 				char32 *openingBracket = str32rchr (history.string, U'[');
@@ -660,7 +679,7 @@ void structMatrixEditor :: v_showMembers () {
 			autoMelderString buffer;
 			const char32 *text = singleTypeToText (elementAddress, type, d_description -> tagType, & buffer);
 			#if motif
-				XtVaSetValues (fieldData -> text -> d_widget, XmNcolumns, stringLengths [type], nullptr);   // TODO: change to GuiObject_size
+				XtVaSetValues (fieldData -> text -> d_widget, XmNcolumns, 60, nullptr);   // TODO: change to GuiObject_size
 			#endif
 			GuiText_setString (fieldData -> text, text);
 			GuiThing_show (fieldData -> text);
diff --git a/sys/DemoEditor.cpp b/sys/DemoEditor.cpp
index 131a375..46a5f49 100644
--- a/sys/DemoEditor.cpp
+++ b/sys/DemoEditor.cpp
@@ -339,7 +339,7 @@ bool Demo_clicked () {
 }
 
 double Demo_x () {
-	if (! theReferenceToTheOnlyDemoEditor) return NUMundefined;
+	if (! theReferenceToTheOnlyDemoEditor) return undefined;
 	if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
 		Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
 			U"Please click or type into the Demo window or close it.");
@@ -356,7 +356,7 @@ double Demo_x () {
 }
 
 double Demo_y () {
-	if (! theReferenceToTheOnlyDemoEditor) return NUMundefined;
+	if (! theReferenceToTheOnlyDemoEditor) return undefined;
 	if (theReferenceToTheOnlyDemoEditor -> waitingForInput) {
 		Melder_throw (U"You cannot work with the Demo window while it is waiting for input. "
 			U"Please click or type into the Demo window or close it.");
diff --git a/sys/Editor.cpp b/sys/Editor.cpp
index 4bba83c..ced210a 100644
--- a/sys/Editor.cpp
+++ b/sys/Editor.cpp
@@ -139,7 +139,7 @@ GuiMenuItem Editor_addCommandScript (Editor me, const char32 *menuTitle, const c
 			if (str32len (script) == 0) {
 				cmd -> script = Melder_dup_f (U"");
 			} else {
-				structMelderFile file = { 0 };
+				structMelderFile file { };
 				Melder_relativePathToFile (script, & file);
 				cmd -> script = Melder_dup_f (Melder_fileToPath (& file));
 			}
@@ -263,7 +263,7 @@ void structEditor :: v_restoreData () {
 static void menu_cb_sendBackToCallingProgram (Editor me, EDITOR_ARGS_DIRECT) {
 	if (my data) {
 		extern structMelderDir praatDir;
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		MelderDir_getFile (& praatDir, U"praat_backToCaller.Data", & file);
 		Data_writeToTextFile (my data, & file);
 		sendsocket (my callbackSocket, Melder_peek32to8 (my data -> name));
diff --git a/sys/EditorM.h b/sys/EditorM.h
index 909c9f9..626e641 100644
--- a/sys/EditorM.h
+++ b/sys/EditorM.h
@@ -2,7 +2,7 @@
 #define _EditorM_h_
 /* EditorM.h
  *
- * Copyright (C) 1992-2011,2013,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2013,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -92,7 +92,7 @@
 		cmd -> d_uiform = autoUiForm (UiOutfile_createE (cmd, title, cmd -> itemTitle, helpTitle)); \
 		} if (! sendingForm && ! args && ! sendingString) { char32 defaultName [300]; defaultName [0] = U'\0';
 #define EDITOR_DO_SAVE \
-	UiOutfile_do (cmd -> d_uiform.get(), defaultName); } else { MelderFile file; structMelderFile file2 { 0 }; \
+	UiOutfile_do (cmd -> d_uiform.get(), defaultName); } else { MelderFile file; structMelderFile file2 { }; \
 		if (! args && ! sendingString) file = UiFile_getFile (sendingForm); \
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 
@@ -101,7 +101,7 @@
 		cmd -> d_uiform = autoUiForm (UiInfile_createE (cmd, title, cmd -> itemTitle, helpTitle)); \
 		} if (! sendingForm && ! args && ! sendingString) {
 #define EDITOR_DO_READ \
-	UiInfile_do (cmd -> d_uiform.get()); } else { MelderFile file; structMelderFile file2 { 0 }; \
+	UiInfile_do (cmd -> d_uiform.get()); } else { MelderFile file; structMelderFile file2 { }; \
 		if (! args && ! sendingString) file = UiFile_getFile (sendingForm); \
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 
diff --git a/sys/Formula.cpp b/sys/Formula.cpp
index 3fad0d7..125de2b 100644
--- a/sys/Formula.cpp
+++ b/sys/Formula.cpp
@@ -21,7 +21,6 @@
 #if defined (UNIX)
 	#include <sys/stat.h>
 #endif
-#include "NUM.h"
 #include "NUM2.h"
 #include "regularExp.h"
 #include "Formula.h"
@@ -43,9 +42,6 @@ static int theLevel = 1;
 static int theExpressionType [1 + MAXIMUM_NUMBER_OF_LEVELS];
 static bool theOptimize;
 
-static numvec theZeroNumericVector = { 0, nullptr };
-static nummat theZeroNumericMatrix = { 0, 0, nullptr };
-
 typedef struct structFormulaInstruction {
 	int symbol;
 	int position;
@@ -119,8 +115,8 @@ enum { GEENSYMBOOL_,
 		INV_CHI_SQUARE_Q_, STUDENT_P_, STUDENT_Q_, INV_STUDENT_Q_,
 		BETA_, BETA2_, BESSEL_I_, BESSEL_K_, LN_BETA_,
 		SOUND_PRESSURE_TO_PHON_, OBJECTS_ARE_IDENTICAL_,
-		OUTER_NUMMAT_, MUL_NUMVEC_,
-	#define HIGH_FUNCTION_2  MUL_NUMVEC_
+		INNER_, OUTER_NUMMAT_, MUL_NUMVEC_, REPEAT_NUMVEC_,
+	#define HIGH_FUNCTION_2  REPEAT_NUMVEC_
 
 	/* Functions of 3 variables; if you add, update the #defines. */
 	#define LOW_FUNCTION_3  FISHER_P_
@@ -134,7 +130,7 @@ enum { GEENSYMBOOL_,
 		WRITE_INFO_, WRITE_INFO_LINE_, APPEND_INFO_, APPEND_INFO_LINE_,
 		WRITE_FILE_, WRITE_FILE_LINE_, APPEND_FILE_, APPEND_FILE_LINE_,
 		PAUSE_SCRIPT_, EXIT_SCRIPT_, RUN_SCRIPT_, RUN_SYSTEM_, RUN_SYSTEM_NOCHECK_, RUN_SUBPROCESS_,
-		MIN_, MAX_, IMIN_, IMAX_,
+		MIN_, MAX_, IMIN_, IMAX_, NORM_,
 		LEFTSTR_, RIGHTSTR_, MIDSTR_,
 		SELECTED_, SELECTEDSTR_, NUMBER_OF_SELECTED_, SELECT_OBJECT_, PLUS_OBJECT_, MINUS_OBJECT_, REMOVE_OBJECT_,
 		BEGIN_PAUSE_FORM_, PAUSE_FORM_ADD_REAL_, PAUSE_FORM_ADD_POSITIVE_, PAUSE_FORM_ADD_INTEGER_, PAUSE_FORM_ADD_NATURAL_,
@@ -150,7 +146,8 @@ enum { GEENSYMBOOL_,
 		RANDOM_UNIFORM_NUMVEC_, RANDOM_UNIFORM_NUMMAT_,
 		RANDOM_INTEGER_NUMVEC_, RANDOM_INTEGER_NUMMAT_,
 		RANDOM_GAUSS_NUMVEC_, RANDOM_GAUSS_NUMMAT_,
-		NUMBER_OF_ROWS_, NUMBER_OF_COLUMNS_, EDITOR_, HASH_,
+		PEAKS_NUMMAT_,
+		SIZE_, NUMBER_OF_ROWS_, NUMBER_OF_COLUMNS_, EDITOR_, HASH_,
 	#define HIGH_FUNCTION_N  HASH_
 
 	/* String functions. */
@@ -239,7 +236,7 @@ static const char32 *Formula_instructionNames [1 + hoogsteSymbool] = { U"",
 	U"chiSquareP", U"chiSquareQ", U"incompleteGammaP", U"invChiSquareQ", U"studentP", U"studentQ", U"invStudentQ",
 	U"beta", U"beta2", U"besselI", U"besselK", U"lnBeta",
 	U"soundPressureToPhon", U"objectsAreIdentical",
-	U"outer##", U"mul#",
+	U"inner", U"outer##", U"mul#", U"repeat#",
 	U"fisherP", U"fisherQ", U"invFisherQ",
 	U"binomialP", U"binomialQ", U"incompleteBeta", U"invBinomialP", U"invBinomialQ",
 
@@ -247,7 +244,7 @@ static const char32 *Formula_instructionNames [1 + hoogsteSymbool] = { U"",
 	U"writeInfo", U"writeInfoLine", U"appendInfo", U"appendInfoLine",
 	U"writeFile", U"writeFileLine", U"appendFile", U"appendFileLine",
 	U"pauseScript", U"exitScript", U"runScript", U"runSystem", U"runSystem_nocheck", U"runSubprocess",
-	U"min", U"max", U"imin", U"imax",
+	U"min", U"max", U"imin", U"imax", U"norm",
 	U"left$", U"right$", U"mid$",
 	U"selected", U"selected$", U"numberOfSelected", U"selectObject", U"plusObject", U"minusObject", U"removeObject",
 	U"beginPause", U"real", U"positive", U"integer", U"natural",
@@ -263,7 +260,8 @@ static const char32 *Formula_instructionNames [1 + hoogsteSymbool] = { U"",
 	U"randomUniform#", U"randomUniform##",
 	U"randomInteger#", U"randomInteger##",
 	U"randomGauss#", U"randomGauss##",
-	U"numberOfRows", U"numberOfColumns", U"editor", U"hash",
+	U"peaks##",
+	U"size", U"numberOfRows", U"numberOfColumns", U"editor", U"hash",
 
 	U"length", U"number", U"fileReadable",	U"deleteFile", U"createDirectory", U"variableExists",
 	U"readFile", U"readFile$", U"unicodeToBackslashTrigraphs$", U"backslashTrigraphsToUnicode$", U"environment$",
@@ -302,7 +300,7 @@ static const char32 *Formula_instructionNames [1 + hoogsteSymbool] = { U"",
 #define oudlees  (-- ilexan)
 
 static void formulefout (const char32 *message, int position) {
-	static MelderString truncatedExpression { 0 };
+	static MelderString truncatedExpression { };
 	MelderString_ncopy (& truncatedExpression, theExpression, position + 1);
 	Melder_throw (message, U":\n" U_LEFT_GUILLEMET U" ", truncatedExpression.string);
 }
@@ -364,7 +362,7 @@ static void Formula_lexan () {
 #define tokgetal(g)  lexan [itok]. content.number = (g)
 #define tokmatriks(m)  lexan [itok]. content.object = (m)
 
-	static MelderString token { 0 };   /* String to collect a symbol name in. */
+	static MelderString token { };   /* String to collect a symbol name in. */
 #define stokaan MelderString_empty (& token);
 #define stokkar { MelderString_appendCharacter (& token, kar); nieuwkar; }
 #define stokuit (void) 0
@@ -446,7 +444,7 @@ static void Formula_lexan () {
 					tokgetal (NUMe);
 				} else if (tok == NUMBER_UNDEFINED_) {
 					nieuwtok (NUMBER_)
-					tokgetal (NUMundefined);
+					tokgetal (undefined);
 				/*
 				 * One very common language name must be converted to a synonym.
 				 */
@@ -824,7 +822,7 @@ static void pas (int symbol) {
 		const char32 *symbolName2 = Formula_instructionNames [lexan [ilexan]. symbol];
 		bool needQuotes1 = ( str32chr (symbolName1, U' ') == nullptr );
 		bool needQuotes2 = ( str32chr (symbolName2, U' ') == nullptr );
-		static MelderString melding { 0 };
+		static MelderString melding { };
 		MelderString_copy (& melding,
 			U"Expected ", needQuotes1 ? U"\"" : nullptr, symbolName1, needQuotes1 ? U"\"" : nullptr,
 			U", but found ", needQuotes2 ? U"\"" : nullptr, symbolName2, needQuotes2 ? U"\"" : nullptr);
@@ -838,7 +836,7 @@ static bool pasArguments () {
     if (symbol == COLON_) return false;   // success: a function call like: myFunction: ...
     const char32 *symbolName2 = Formula_instructionNames [lexan [ilexan]. symbol];
     bool needQuotes2 = ( str32chr (symbolName2, U' ') == nullptr );
-    static MelderString melding { 0 };
+    static MelderString melding { };
     MelderString_copy (& melding,
 		U"Expected \"(\" or \":\", but found ", needQuotes2 ? U"\"" : nullptr, symbolName2, needQuotes2 ? U"\"" : nullptr);
     formulefout (melding.string, lexan [ilexan]. position);
@@ -1910,7 +1908,7 @@ static int praat_findObjectFromString (const char32 *name) {
 		/*
 		 * Find the object by its name.
 		 */
-		static MelderString buffer { 0 };
+		static MelderString buffer { };
 		MelderString_copy (& buffer, name);
 		char32 *space = str32chr (buffer.string, U' ');
 		if (space == nullptr)
@@ -2128,47 +2126,44 @@ static void Stackel_cleanUp (Stackel me) {
 	if (my which == Stackel_STRING) {
 		Melder_free (my string);
 	} else if (my which == Stackel_NUMERIC_VECTOR) {
-		NUMvector_free (my numericVector.data, 1);
-		my numericVector = theZeroNumericVector;
+		NUMvector_free (my numericVector.at, 1);
+		my numericVector = empty_numvec;
 	} else if (my which == Stackel_NUMERIC_MATRIX) {
-		NUMmatrix_free (my numericMatrix.data, 1, 1);
-		my numericMatrix = theZeroNumericMatrix;
+		NUMmatrix_free (my numericMatrix.at, 1, 1);
+		my numericMatrix = empty_nummat;
 	}
 }
 static Stackel theStack;
 static int w, wmax;   /* w = stack pointer; */
 #define pop  & theStack [w --]
-static inline void pushNumber (double x) {
-	/* inline runs 10 to 20 percent faster on i386; here's the test script:
+inline static void pushNumber (double x) {
+	/* inline runs 10 to 20 percent faster; here's the test script:
 		stopwatch
-		Create Sound from formula... test mono 0 100 44100 1/2 * (2*pi*377*x)
-		t = stopwatch
-		echo 't'
-	 * Mac: 0.75 -> 0.67 seconds
-	 * Win: 1.10 -> 0.90 seconds (20100107)
+		Create Sound from formula: "test", 1, 0.0, 1000.0, 44100, "x + 1 + 2 + 3 + 4 + 5 + 6"
+		writeInfoLine: stopwatch
+		Remove
+	 * Mac: 3.76 -> 3.20 seconds
 	 */
 	Stackel stackel = & theStack [++ w];
 	if (stackel -> which > Stackel_NUMBER) Stackel_cleanUp (stackel);
 	if (w > wmax) wmax ++;
 	stackel -> which = Stackel_NUMBER;
-	stackel -> number = x;
+	stackel -> number = isdefined (x) ? x : undefined;
+	//stackel -> number = x;   // this one would be 2 percent faster
 }
-static void pushNumericVector (long numberOfElements, double *x) {
+static void pushNumericVector (autonumvec x) {
 	Stackel stackel = & theStack [++ w];
 	if (stackel -> which > Stackel_NUMBER) Stackel_cleanUp (stackel);
 	if (w > wmax) wmax ++;
 	stackel -> which = Stackel_NUMERIC_VECTOR;
-	stackel -> numericVector.size = numberOfElements;
-	stackel -> numericVector.data = x;
+	stackel -> numericVector = x.releaseToAmbiguousOwner();
 }
-static void pushNumericMatrix (long numberOfRows, long numberOfColumns, double **x) {
+static void pushNumericMatrix (autonummat x) {
 	Stackel stackel = & theStack [++ w];
 	if (stackel -> which > Stackel_NUMBER) Stackel_cleanUp (stackel);
 	if (w > wmax) wmax ++;
 	stackel -> which = Stackel_NUMERIC_MATRIX;
-	stackel -> numericMatrix.nrow = numberOfRows;
-	stackel -> numericMatrix.ncol = numberOfColumns;
-	stackel -> numericMatrix.data = x;
+	stackel -> numericMatrix = x.releaseToAmbiguousOwner();
 }
 static void pushString (char32 *x) {
 	Stackel stackel = & theStack [++ w];
@@ -2205,7 +2200,7 @@ const char32 *Stackel_whichText (Stackel me) {
 static void do_not () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : x->number == 0.0 ? 1.0 : 0.0);
+		pushNumber (isundef (x->number) ? undefined : x->number == 0.0 ? 1.0 : 0.0);
 	} else {
 		Melder_throw (U"Cannot negate (\"not\") ", Stackel_whichText (x), U".");
 	}
@@ -2213,10 +2208,31 @@ static void do_not () {
 static void do_eq () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == y->number ? 1.0 : 0.0);   /* Even if undefined. */
+		/*
+			It is possible that we are comparing a value against --undefined--.
+			Any defined value is unequal to --undefined--,
+			but any undefined value (inf or NaN) *is* equal to --undefined--.
+			Note that this is different from how "==" works in C.
+		*/
+		double xvalue = x->number, yvalue = y->number;
+		if (isdefined (xvalue)) {
+			if (isdefined (yvalue)) {
+				pushNumber (x->number == y->number ? 1.0 : 0.0);
+			} else {
+				pushNumber (0.0);   // defined is not equal to undefined
+			}
+		} else {
+			if (isdefined (yvalue)) {
+				pushNumber (0.0);   // undefined is not equal to defined
+			} else {
+				pushNumber (1.0);   // undefined is equal to undefined
+			}
+		}
 	} else if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
 		double result = str32equ (x->string, y->string) ? 1.0 : 0.0;
 		pushNumber (result);
+	} else if (x->which == Stackel_NUMERIC_VECTOR && y->which == Stackel_NUMERIC_VECTOR) {
+		pushNumber (equal_numvec (x->numericVector, y->numericVector));
 	} else {
 		Melder_throw (U"Cannot compare (=) ", Stackel_whichText (x), U" to ", Stackel_whichText (y), U".");
 	}
@@ -2224,7 +2240,23 @@ static void do_eq () {
 static void do_ne () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number != y->number ? 1.0 : 0.0);   /* Even if undefined. */
+		/*
+			Unequal is defined as the opposite of equal.
+		*/
+		double xvalue = x->number, yvalue = y->number;
+		if (isdefined (xvalue)) {
+			if (isdefined (yvalue)) {
+				pushNumber (x->number != y->number ? 1.0 : 0.0);
+			} else {
+				pushNumber (1.0);   // defined is unequal to undefined
+			}
+		} else {
+			if (isdefined (yvalue)) {
+				pushNumber (1.0);   // undefined is unequal to defined
+			} else {
+				pushNumber (0.0);   // undefined is not unequal to undefined
+			}
+		}
 	} else if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
 		double result = str32equ (x->string, y->string) ? 0.0 : 1.0;
 		pushNumber (result);
@@ -2235,8 +2267,20 @@ static void do_ne () {
 static void do_le () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			x->number <= y->number ? 1.0 : 0.0);
+		double xvalue = x->number, yvalue = y->number;
+		if (isdefined (xvalue)) {
+			if (isdefined (yvalue)) {
+				pushNumber (x->number <= y->number ? 1.0 : 0.0);
+			} else {
+				pushNumber (0.0);   // defined is not equal to, nor less than, undefined
+			}
+		} else {
+			if (isdefined (yvalue)) {
+				pushNumber (0.0);   // undefined is not equal to, nor less than, defined
+			} else {
+				pushNumber (1.0);   // undefined is equal to undefined
+			}
+		}
 	} else if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
 		double result = str32cmp (x->string, y->string) <= 0 ? 1.0 : 0.0;
 		pushNumber (result);
@@ -2247,8 +2291,20 @@ static void do_le () {
 static void do_lt () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			x->number < y->number ? 1.0 : 0.0);
+		double xvalue = x->number, yvalue = y->number;
+		if (isdefined (xvalue)) {
+			if (isdefined (yvalue)) {
+				pushNumber (x->number < y->number ? 1.0 : 0.0);
+			} else {
+				pushNumber (0.0);   // defined is not less than undefined
+			}
+		} else {
+			if (isdefined (yvalue)) {
+				pushNumber (0.0);   // undefined is not less than defined
+			} else {
+				pushNumber (0.0);   // undefined is not less than undefined
+			}
+		}
 	} else if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
 		double result = str32cmp (x->string, y->string) < 0 ? 1.0 : 0.0;
 		pushNumber (result);
@@ -2259,8 +2315,20 @@ static void do_lt () {
 static void do_ge () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			x->number >= y->number ? 1.0 : 0.0);
+		double xvalue = x->number, yvalue = y->number;
+		if (isdefined (xvalue)) {
+			if (isdefined (yvalue)) {
+				pushNumber (x->number >= y->number ? 1.0 : 0.0);
+			} else {
+				pushNumber (0.0);   // defined is not equal to, nor greater than, undefined
+			}
+		} else {
+			if (isdefined (yvalue)) {
+				pushNumber (0.0);   // undefined is not equal to, nor greater than, defined
+			} else {
+				pushNumber (1.0);   // undefined is equal to undefined
+			}
+		}
 	} else if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
 		double result = str32cmp (x->string, y->string) >= 0 ? 1.0 : 0.0;
 		pushNumber (result);
@@ -2271,8 +2339,20 @@ static void do_ge () {
 static void do_gt () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			x->number > y->number ? 1.0 : 0.0);
+		double xvalue = x->number, yvalue = y->number;
+		if (isdefined (xvalue)) {
+			if (isdefined (yvalue)) {
+				pushNumber (x->number > y->number ? 1.0 : 0.0);
+			} else {
+				pushNumber (0.0);   // defined is not greater than undefined
+			}
+		} else {
+			if (isdefined (yvalue)) {
+				pushNumber (0.0);   // undefined is not greater than defined
+			} else {
+				pushNumber (0.0);   // undefined is not greater than undefined
+			}
+		}
 	} else if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
 		double result = str32cmp (x->string, y->string) > 0 ? 1.0 : 0.0;
 		pushNumber (result);
@@ -2292,7 +2372,7 @@ static void do_add () {
 				result = x + y
 			*/
 			double yvalue = y->number;
-			pushNumber (xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue + yvalue);
+			pushNumber (xvalue + yvalue);
 			return;
 		}
 		if (y->which == Stackel_NUMERIC_VECTOR) {
@@ -2300,18 +2380,12 @@ static void do_add () {
 				result# = x + y#
 			*/
 			long ny = y->numericVector.size;
-			double *result = NUMvector<double> (1, ny);
-			if (xvalue == NUMundefined) {
-				for (long i = 1; i <= ny; i ++) {
-					result [i] = NUMundefined;
-				}
-			} else {
-				for (long i = 1; i <= ny; i ++) {
-					double yvalue = y->numericVector.data [i];
-					result [i] = yvalue == NUMundefined ? NUMundefined : xvalue + yvalue;
-				}
+			autonumvec result (ny, false);
+			for (long i = 1; i <= ny; i ++) {
+				double yvalue = y->numericVector [i];
+				result [i] = xvalue + yvalue;
 			}
-			pushNumericVector (ny, result);
+			pushNumericVector (result.move());
 			return;
 		}
 		if (y->which == Stackel_NUMERIC_MATRIX) {
@@ -2319,37 +2393,41 @@ static void do_add () {
 				result## = x + y##
 			*/
 			long nrow = y->numericMatrix.nrow, ncol = y->numericMatrix.ncol;
-			double **result = NUMmatrix<double> (1, nrow, 1, ncol);
-			if (xvalue == NUMundefined) {
-				for (long irow = 1; irow <= nrow; irow ++) {
-					for (long icol = 1; icol <= ncol; icol ++) {
-						result [irow] [icol] = NUMundefined;
-					}
-				}
-			} else {
-				for (long irow = 1; irow <= nrow; irow ++) {
-					for (long icol = 1; icol <= ncol; icol ++) {
-						double yvalue = y->numericMatrix.data [irow] [icol];
-						result [irow] [icol] = yvalue == NUMundefined ? NUMundefined : xvalue + yvalue;
-					}
+			autonummat result (nrow, ncol, false);
+			for (long irow = 1; irow <= nrow; irow ++) {
+				for (long icol = 1; icol <= ncol; icol ++) {
+					double yvalue = y->numericMatrix [irow] [icol];
+					result [irow] [icol] = xvalue + yvalue;
 				}
 			}
-			pushNumericMatrix (nrow, ncol, result);
+			pushNumericMatrix (result.move());
 			return;
 		}
 	}
-	if (x->which == Stackel_NUMERIC_VECTOR && y->which == Stackel_NUMERIC_VECTOR) {
-		long nx = x->numericVector.size, ny = y->numericVector.size;
-		if (nx != ny)
-			Melder_throw (U"When adding vectors, their numbers of elements should be equal, instead of ", nx, U" and ", ny, U".");
-		double *result = NUMvector<double> (1, nx);
-		for (long i = 1; i <= nx; i ++) {
-			double xvalue = x->numericVector.data [i];
-			double yvalue = y->numericVector.data [i];
-			result [i] = xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue + yvalue;
+	if (x->which == Stackel_NUMERIC_VECTOR) {
+		if (y->which == Stackel_NUMBER) {
+			/*
+				result# = x# + y
+				i.e.
+				result# [i] = x# [i] + y
+			*/
+			integer size = x->numericVector.size;
+			autonumvec result (size, false);
+			real yvalue = y->number;
+			for (integer i = 1; i <= size; i ++) {
+				double xvalue = x->numericVector [i];
+				result [i] = xvalue + yvalue;
+			}
+			pushNumericVector (result.move());
+			return;
+		}
+		if (y->which == Stackel_NUMERIC_VECTOR) {
+			long nx = x->numericVector.size, ny = y->numericVector.size;
+			if (nx != ny)
+				Melder_throw (U"When adding vectors, their numbers of elements should be equal, instead of ", nx, U" and ", ny, U".");
+			pushNumericVector (add_numvec (x->numericVector, y->numericVector));
+			return;
 		}
-		pushNumericVector (nx, result);
-		return;
 	}
 	if (x->which == Stackel_NUMERIC_MATRIX && y->which == Stackel_NUMERIC_MATRIX) {
 		long xnrow = x->numericMatrix.nrow, xncol = x->numericMatrix.ncol;
@@ -2358,15 +2436,15 @@ static void do_add () {
 			Melder_throw (U"When adding matrices, their numbers of rows should be equal, instead of ", xnrow, U" and ", ynrow, U".");
 		if (xncol != yncol)
 			Melder_throw (U"When adding matrices, their numbers of columns should be equal, instead of ", xncol, U" and ", yncol, U".");
-		double **result = NUMmatrix<double> (1, xnrow, 1, xncol);
+		autonummat result (xnrow, xncol, false);
 		for (long irow = 1; irow <= xnrow; irow ++) {
 			for (long icol = 1; icol <= xncol; icol ++) {
-				double xvalue = x->numericMatrix.data [irow] [icol];
-				double yvalue = y->numericMatrix.data [irow] [icol];
-				result [irow] [icol] = xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue + yvalue;
+				double xvalue = x->numericMatrix [irow] [icol];
+				double yvalue = y->numericMatrix [irow] [icol];
+				result [irow] [icol] = xvalue + yvalue;
 			}
 		}
-		pushNumericMatrix (xnrow, xncol, result);
+		pushNumericMatrix (result.move());
 		return;
 	}
 	if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
@@ -2391,7 +2469,7 @@ static void do_sub () {
 				result = x - y
 			*/
 			double yvalue = y->number;
-			pushNumber (xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue - yvalue);
+			pushNumber (xvalue - yvalue);
 			return;
 		}
 		if (y->which == Stackel_NUMERIC_VECTOR) {
@@ -2399,18 +2477,12 @@ static void do_sub () {
 				result# = x - y#
 			*/
 			long ny = y->numericVector.size;
-			double *result = NUMvector<double> (1, ny);
-			if (xvalue == NUMundefined) {
-				for (long i = 1; i <= ny; i ++) {
-					result [i] = NUMundefined;
-				}
-			} else {
-				for (long i = 1; i <= ny; i ++) {
-					double yvalue = y->numericVector.data [i];
-					result [i] = yvalue == NUMundefined ? NUMundefined : xvalue - yvalue;
-				}
+			autonumvec result (ny, false);
+			for (long i = 1; i <= ny; i ++) {
+				double yvalue = y->numericVector [i];
+				result [i] = xvalue - yvalue;
 			}
-			pushNumericVector (ny, result);
+			pushNumericVector (result.move());
 			return;
 		}
 		if (y->which == Stackel_NUMERIC_MATRIX) {
@@ -2418,37 +2490,41 @@ static void do_sub () {
 				result## = x - y##
 			*/
 			long nrow = y->numericMatrix.nrow, ncol = y->numericMatrix.ncol;
-			double **result = NUMmatrix<double> (1, nrow, 1, ncol);
-			if (xvalue == NUMundefined) {
-				for (long irow = 1; irow <= nrow; irow ++) {
-					for (long icol = 1; icol <= ncol; icol ++) {
-						result [irow] [icol] = NUMundefined;
-					}
-				}
-			} else {
-				for (long irow = 1; irow <= nrow; irow ++) {
-					for (long icol = 1; icol <= ncol; icol ++) {
-						double yvalue = y->numericMatrix.data [irow] [icol];
-						result [irow] [icol] = yvalue == NUMundefined ? NUMundefined : xvalue - yvalue;
-					}
+			autonummat result (nrow, ncol, false);
+			for (long irow = 1; irow <= nrow; irow ++) {
+				for (long icol = 1; icol <= ncol; icol ++) {
+					double yvalue = y->numericMatrix [irow] [icol];
+					result [irow] [icol] = xvalue - yvalue;
 				}
 			}
-			pushNumericMatrix (nrow, ncol, result);
+			pushNumericMatrix (result.move());
 			return;
 		}
 	}
-	if (x->which == Stackel_NUMERIC_VECTOR && y->which == Stackel_NUMERIC_VECTOR) {
-		long nx = x->numericVector.size, ny = y->numericVector.size;
-		if (nx != ny)
-			Melder_throw (U"When subtracting vectors, their numbers of elements should be equal, instead of ", nx, U" and ", ny, U".");
-		double *result = NUMvector<double> (1, nx);
-		for (long i = 1; i <= nx; i ++) {
-			double xvalue = x->numericVector.data [i];
-			double yvalue = y->numericVector.data [i];
-			result [i] = xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue - yvalue;
+	if (x->which == Stackel_NUMERIC_VECTOR) {
+		if (y->which == Stackel_NUMBER) {
+			/*
+				result# = x# - y
+				i.e.
+				result# [i] = x# [i] - y
+			*/
+			integer size = x->numericVector.size;
+			autonumvec result (size, false);
+			real yvalue = y->number;
+			for (integer i = 1; i <= size; i ++) {
+				double xvalue = x->numericVector [i];
+				result [i] = xvalue - yvalue;
+			}
+			pushNumericVector (result.move());
+			return;
+		}
+		if (y->which == Stackel_NUMERIC_VECTOR) {
+			long nx = x->numericVector.size, ny = y->numericVector.size;
+			if (nx != ny)
+				Melder_throw (U"When subtracting vectors, their numbers of elements should be equal, instead of ", nx, U" and ", ny, U".");
+			pushNumericVector (sub_numvec (x->numericVector, y->numericVector));
+			return;
 		}
-		pushNumericVector (nx, result);
-		return;
 	}
 	if (x->which == Stackel_NUMERIC_MATRIX && y->which == Stackel_NUMERIC_MATRIX) {
 		long xnrow = x->numericMatrix.nrow, xncol = x->numericMatrix.ncol;
@@ -2457,15 +2533,15 @@ static void do_sub () {
 			Melder_throw (U"When subtracting matrices, their numbers of rows should be equal, instead of ", xnrow, U" and ", ynrow, U".");
 		if (xncol != yncol)
 			Melder_throw (U"When subtracting matrices, their numbers of columns should be equal, instead of ", xncol, U" and ", yncol, U".");
-		double **result = NUMmatrix<double> (1, xnrow, 1, xncol);
+		autonummat result (xnrow, xncol, false);
 		for (long irow = 1; irow <= xnrow; irow ++) {
 			for (long icol = 1; icol <= xncol; icol ++) {
-				double xvalue = x->numericMatrix.data [irow] [icol];
-				double yvalue = y->numericMatrix.data [irow] [icol];
-				result [irow] [icol] = xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue - yvalue;
+				double xvalue = x->numericMatrix [irow] [icol];
+				double yvalue = y->numericMatrix [irow] [icol];
+				result [irow] [icol] = xvalue - yvalue;
 			}
 		}
-		pushNumericMatrix (xnrow, xncol, result);
+		pushNumericMatrix (result.move());
 		return;
 	}
 	if (x->which == Stackel_STRING && y->which == Stackel_STRING) {
@@ -2495,7 +2571,7 @@ static void do_mul () {
 				result = x * y
 			*/
 			double yvalue = y->number;
-			pushNumber (xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue * yvalue);
+			pushNumber (xvalue * yvalue);
 			return;
 		}
 		if (y->which == Stackel_NUMERIC_VECTOR) {
@@ -2503,18 +2579,12 @@ static void do_mul () {
 				result# = x * y#
 			*/
 			long ny = y->numericVector.size;
-			double *result = NUMvector<double> (1, ny);
-			if (xvalue == NUMundefined) {
-				for (long i = 1; i <= ny; i ++) {
-					result [i] = NUMundefined;
-				}
-			} else {
-				for (long i = 1; i <= ny; i ++) {
-					double yvalue = y->numericVector.data [i];
-					result [i] = yvalue == NUMundefined ? NUMundefined : xvalue * yvalue;
-				}
+			autonumvec result { ny, false };
+			for (long i = 1; i <= ny; i ++) {
+				double yvalue = y->numericVector [i];
+				result [i] = xvalue * yvalue;
 			}
-			pushNumericVector (ny, result);
+			pushNumericVector (result.move());
 			return;
 		}
 		if (y->which == Stackel_NUMERIC_MATRIX) {
@@ -2522,22 +2592,14 @@ static void do_mul () {
 				result## = x * y##
 			*/
 			long nrow = y->numericMatrix.nrow, ncol = y->numericMatrix.ncol;
-			double **result = NUMmatrix<double> (1, nrow, 1, ncol);
-			if (xvalue == NUMundefined) {
-				for (long irow = 1; irow <= nrow; irow ++) {
-					for (long icol = 1; icol <= ncol; icol ++) {
-						result [irow] [icol] = NUMundefined;
-					}
-				}
-			} else {
-				for (long irow = 1; irow <= nrow; irow ++) {
-					for (long icol = 1; icol <= ncol; icol ++) {
-						double yvalue = y->numericMatrix.data [irow] [icol];
-						result [irow] [icol] = yvalue == NUMundefined ? NUMundefined : xvalue * yvalue;
-					}
+			autonummat result (nrow, ncol, false);
+			for (long irow = 1; irow <= nrow; irow ++) {
+				for (long icol = 1; icol <= ncol; icol ++) {
+					double yvalue = y->numericMatrix [irow] [icol];
+					result [irow] [icol] = xvalue * yvalue;
 				}
 			}
-			pushNumericMatrix (nrow, ncol, result);
+			pushNumericMatrix (result.move());
 			return;
 		}
 	}
@@ -2548,13 +2610,13 @@ static void do_mul () {
 		long nx = x->numericVector.size, ny = y->numericVector.size;
 		if (nx != ny)
 			Melder_throw (U"When multiplying vectors, their numbers of elements should be equal, instead of ", nx, U" and ", ny, U".");
-		double *result = NUMvector<double> (1, nx);
+		autonumvec result { nx, false };
 		for (long i = 1; i <= nx; i ++) {
-			double xvalue = x->numericVector.data [i];
-			double yvalue = y->numericVector.data [i];
-			result [i] = xvalue == NUMundefined || yvalue == NUMundefined ? NUMundefined : xvalue * yvalue;
+			double xvalue = x->numericVector [i];
+			double yvalue = y->numericVector [i];
+			result [i] = xvalue * yvalue;
 		}
-		pushNumericVector (nx, result);
+		pushNumericVector (result.move());
 		return;
 	}
 	Melder_throw (U"Cannot multiply (*) ", Stackel_whichText (x), U" by ", Stackel_whichText (y), U".");
@@ -2562,9 +2624,7 @@ static void do_mul () {
 static void do_rdiv () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			y->number == 0.0 ? NUMundefined :
-			x->number / y->number);
+		pushNumber (x->number / y->number);   // result could be inf (1/0) or NaN (0/0), which is OK
 		return;
 	}
 	if (x->which == Stackel_NUMERIC_VECTOR) {
@@ -2572,10 +2632,10 @@ static void do_rdiv () {
 			long nelem1 = x->numericVector.size, nelem2 = y->numericVector.size;
 			if (nelem1 != nelem2)
 				Melder_throw (U"When dividing vectors, their numbers of elements should be equal, instead of ", nelem1, U" and ", nelem2, U".");
-			double *result = NUMvector<double> (1, nelem1);
+			autonumvec result { nelem1, false };
 			for (long ielem = 1; ielem <= nelem1; ielem ++)
-				result [ielem] = y->numericVector.data [ielem] == 0.0 ? NUMundefined : x->numericVector.data [ielem] / y->numericVector.data [ielem];
-			pushNumericVector (nelem1, result);
+				result [ielem] = x->numericVector [ielem] / y->numericVector [ielem];
+			pushNumericVector (result.move());
 			return;
 		}
 		if (y->which == Stackel_NUMBER) {
@@ -2583,17 +2643,17 @@ static void do_rdiv () {
 				result# = x# / y
 			*/
 			long xn = x->numericVector.size;
-			double *result = NUMvector<double> (1, xn);
+			autonumvec result { xn, false };
 			double yvalue = y->number;
 			if (yvalue == 0.0) {
 				Melder_throw (U"Cannot divide (/) ", Stackel_whichText (x), U" by zero.");
 			} else {
 				for (long i = 1; i <= xn; i ++) {
-					double xvalue = x->numericVector.data [i];
+					double xvalue = x->numericVector [i];
 					result [i] = xvalue / yvalue;
 				}
 			}
-			pushNumericVector (xn, result);
+			pushNumericVector (result.move());
 			return;
 		}
 	}
@@ -2602,9 +2662,7 @@ static void do_rdiv () {
 static void do_idiv () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			y->number == 0.0 ? NUMundefined :
-			floor (x->number / y->number));
+		pushNumber (floor (x->number / y->number));
 		return;
 	}
 	Melder_throw (U"Cannot divide (\"div\") ", Stackel_whichText (x), U" by ", Stackel_whichText (y), U".");
@@ -2612,9 +2670,7 @@ static void do_idiv () {
 static void do_mod () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			y->number == 0.0 ? NUMundefined :
-			x->number - floor (x->number / y->number) * y->number);
+		pushNumber (x->number - floor (x->number / y->number) * y->number);
 		return;
 	}
 	Melder_throw (U"Cannot divide (\"mod\") ", Stackel_whichText (x), U" by ", Stackel_whichText (y), U".");
@@ -2622,7 +2678,7 @@ static void do_mod () {
 static void do_minus () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : - x->number);
+		pushNumber (- x->number);
 	} else {
 		Melder_throw (U"Cannot take the opposite (-) of ", Stackel_whichText (x), U".");
 	}
@@ -2630,8 +2686,7 @@ static void do_minus () {
 static void do_power () {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			pow (x->number, y->number));
+		pushNumber (isundef (x->number) || isundef (y->number) ? undefined : pow (x->number, y->number));
 	} else {
 		Melder_throw (U"Cannot exponentiate (^) ", Stackel_whichText (x), U" to ", Stackel_whichText (y), U".");
 	}
@@ -2639,7 +2694,7 @@ static void do_power () {
 static void do_sqr () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : x->number * x->number);
+		pushNumber (isundef (x->number) ? undefined : x->number * x->number);
 	} else {
 		Melder_throw (U"Cannot take the square (^ 2) of ", Stackel_whichText (x), U".");
 	}
@@ -2647,7 +2702,7 @@ static void do_sqr () {
 static void do_function_n_n (double (*f) (double)) {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : f (x->number));
+		pushNumber (isundef (x->number) ? undefined : f (x->number));
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
 			U" requires a numeric argument, not ", Stackel_whichText (x), U".");
@@ -2672,7 +2727,7 @@ static void do_functionvec_n_n (double (*f) (double)) {
 	if (x->which == Stackel_NUMERIC_VECTOR) {
 		long nelm = x->numericVector.size;
 		for (long i = 1; i <= nelm; i ++) {
-			x->numericVector.data [i] = f (x->numericVector.data [i]);
+			x->numericVector [i] = f (x->numericVector [i]);
 		}
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
@@ -2686,20 +2741,20 @@ static void do_softmax () {
 		long nelm = x->numericVector.size;
 		double maximum = -1e308;
 		for (long i = 1; i <= nelm; i ++) {
-			if (x->numericVector.data [i] > maximum) {
-				maximum = x->numericVector.data [i];
+			if (x->numericVector [i] > maximum) {
+				maximum = x->numericVector [i];
 			}
 		}
 		for (long i = 1; i <= nelm; i ++) {
-			x->numericVector.data [i] -= maximum;
+			x->numericVector [i] -= maximum;
 		}
 		double sum = 0.0;
 		for (long i = 1; i <= nelm; i ++) {
-			x->numericVector.data [i] = exp (x->numericVector.data [i]);
-			sum += x->numericVector.data [i];
+			x->numericVector [i] = exp (x->numericVector [i]);
+			sum += x->numericVector [i];
 		}
 		for (long i = 1; i <= nelm; i ++) {
-			x->numericVector.data [i] /= sum;
+			x->numericVector [i] /= sum;
 		}
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
@@ -2709,7 +2764,7 @@ static void do_softmax () {
 static void do_abs () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : fabs (x->number));
+		pushNumber (isundef (x->number) ? undefined : fabs (x->number));
 	} else {
 		Melder_throw (U"Cannot take the absolute value (abs) of ", Stackel_whichText (x), U".");
 	}
@@ -2717,7 +2772,7 @@ static void do_abs () {
 static void do_round () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : floor (x->number + 0.5));
+		pushNumber (isundef (x->number) ? undefined : floor (x->number + 0.5));
 	} else {
 		Melder_throw (U"Cannot round ", Stackel_whichText (x), U".");
 	}
@@ -2725,7 +2780,7 @@ static void do_round () {
 static void do_floor () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : floor (x->number));
+		pushNumber (isundef (x->number) ? undefined : floor (x->number));
 	} else {
 		Melder_throw (U"Cannot round down (floor) ", Stackel_whichText (x), U".");
 	}
@@ -2733,7 +2788,7 @@ static void do_floor () {
 static void do_ceiling () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : ceil (x->number));
+		pushNumber (isundef (x->number) ? undefined : ceil (x->number));
 	} else {
 		Melder_throw (U"Cannot round up (ceiling) ", Stackel_whichText (x), U".");
 	}
@@ -2741,7 +2796,7 @@ static void do_ceiling () {
 static void do_rectify () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : x->number > 0.0 ? x->number : 0.0);
+		pushNumber (isundef (x->number) ? undefined : x->number > 0.0 ? x->number : 0.0);
 	} else {
 		Melder_throw (U"Cannot rectify ", Stackel_whichText (x), U".");
 	}
@@ -2750,12 +2805,12 @@ static void do_rectify_numvec () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
 		long nelm = x->numericVector.size;
-		double *result = NUMvector<double> (1, nelm);
+		autonumvec result { nelm, false };
 		for (long i = 1; i <= nelm; i ++) {
-			double xvalue = x->numericVector.data [i];
-			result [i] = xvalue == NUMundefined ? NUMundefined : xvalue > 0.0 ? xvalue : 0.0;
+			double xvalue = x->numericVector [i];
+			result [i] = isundef (xvalue) ? undefined : xvalue > 0.0 ? xvalue : 0.0;
 		}
-		pushNumericVector (nelm, result);
+		pushNumericVector (result.move());
 	} else {
 		Melder_throw (U"Cannot rectify ", Stackel_whichText (x), U".");
 	}
@@ -2763,8 +2818,8 @@ static void do_rectify_numvec () {
 static void do_sqrt () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined :
-			x->number < 0.0 ? NUMundefined : sqrt (x->number));
+		pushNumber (isundef (x->number) ? undefined :
+			x->number < 0.0 ? undefined : sqrt (x->number));
 	} else {
 		Melder_throw (U"Cannot take the square root (sqrt) of ", Stackel_whichText (x), U".");
 	}
@@ -2772,7 +2827,7 @@ static void do_sqrt () {
 static void do_sin () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : sin (x->number));
+		pushNumber (isundef (x->number) ? undefined : sin (x->number));
 	} else {
 		Melder_throw (U"Cannot take the sine (sin) of ", Stackel_whichText (x), U".");
 	}
@@ -2780,7 +2835,7 @@ static void do_sin () {
 static void do_cos () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : cos (x->number));
+		pushNumber (isundef (x->number) ? undefined : cos (x->number));
 	} else {
 		Melder_throw (U"Cannot take the cosine (cos) of ", Stackel_whichText (x), U".");
 	}
@@ -2788,7 +2843,7 @@ static void do_cos () {
 static void do_tan () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : tan (x->number));
+		pushNumber (isundef (x->number) ? undefined : tan (x->number));
 	} else {
 		Melder_throw (U"Cannot take the tangent (tan) of ", Stackel_whichText (x), U".");
 	}
@@ -2796,8 +2851,8 @@ static void do_tan () {
 static void do_arcsin () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined :
-			fabs (x->number) > 1.0 ? NUMundefined : asin (x->number));
+		pushNumber (isundef (x->number) ? undefined :
+			fabs (x->number) > 1.0 ? undefined : asin (x->number));
 	} else {
 		Melder_throw (U"Cannot take the arcsine (arcsin) of ", Stackel_whichText (x), U".");
 	}
@@ -2805,8 +2860,8 @@ static void do_arcsin () {
 static void do_arccos () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined :
-			fabs (x->number) > 1.0 ? NUMundefined : acos (x->number));
+		pushNumber (isundef (x->number) ? undefined :
+			fabs (x->number) > 1.0 ? undefined : acos (x->number));
 	} else {
 		Melder_throw (U"Cannot take the arccosine (arccos) of ", Stackel_whichText (x), U".");
 	}
@@ -2814,7 +2869,7 @@ static void do_arccos () {
 static void do_arctan () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : atan (x->number));
+		pushNumber (isundef (x->number) ? undefined : atan (x->number));
 	} else {
 		Melder_throw (U"Cannot take the arctangent (arctan) of ", Stackel_whichText (x), U".");
 	}
@@ -2822,7 +2877,7 @@ static void do_arctan () {
 static void do_exp () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : exp (x->number));
+		pushNumber (isundef (x->number) ? undefined : exp (x->number));
 	} else {
 		Melder_throw (U"Cannot exponentiate (exp) ", Stackel_whichText (x), U".");
 	}
@@ -2831,11 +2886,11 @@ static void do_exp_numvec () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
 		long nelm = x->numericVector.size;
-		double *result = NUMvector<double> (1, nelm);
+		autonumvec result (nelm, false);
 		for (long i = 1; i <= nelm; i ++) {
-			result [i] = exp (x->numericVector.data [i]);
+			result [i] = exp (x->numericVector [i]);
 		}
-		pushNumericVector (nelm, result);
+		pushNumericVector (result.move());
 	} else {
 		Melder_throw (U"Cannot exponentiate (exp) ", Stackel_whichText (x), U".");
 	}
@@ -2844,13 +2899,13 @@ static void do_exp_nummat () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_MATRIX) {
 		long nrow = x->numericMatrix.nrow, ncol = x->numericMatrix.ncol;
-		double **result = NUMmatrix<double> (1, nrow, 1, ncol);
+		autonummat result (nrow, ncol, false);
 		for (long irow = 1; irow <= nrow; irow ++) {
 			for (long icol = 1; icol <= ncol; icol ++) {
-				result [irow] [icol] = exp (x->numericMatrix.data [irow] [icol]);
+				result [irow] [icol] = exp (x->numericMatrix [irow] [icol]);
 			}
 		}
-		pushNumericMatrix (nrow, ncol, result);
+		pushNumericMatrix (result.move());
 	} else {
 		Melder_throw (U"Cannot exponentiate (exp) ", Stackel_whichText (x), U".");
 	}
@@ -2858,7 +2913,7 @@ static void do_exp_nummat () {
 static void do_sinh () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : sinh (x->number));
+		pushNumber (isundef (x->number) ? undefined : sinh (x->number));
 	} else {
 		Melder_throw (U"Cannot take the hyperbolic sine (sinh) of ", Stackel_whichText (x), U".");
 	}
@@ -2866,7 +2921,7 @@ static void do_sinh () {
 static void do_cosh () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : cosh (x->number));
+		pushNumber (isundef (x->number) ? undefined : cosh (x->number));
 	} else {
 		Melder_throw (U"Cannot take the hyperbolic cosine (cosh) of ", Stackel_whichText (x), U".");
 	}
@@ -2874,7 +2929,7 @@ static void do_cosh () {
 static void do_tanh () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined : tanh (x->number));
+		pushNumber (isundef (x->number) ? undefined : tanh (x->number));
 	} else {
 		Melder_throw (U"Cannot take the hyperbolic tangent (tanh) of ", Stackel_whichText (x), U".");
 	}
@@ -2882,8 +2937,8 @@ static void do_tanh () {
 static void do_log2 () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined :
-			x->number <= 0.0 ? NUMundefined : log (x->number) * NUMlog2e);
+		pushNumber (isundef (x->number) ? undefined :
+			x->number <= 0.0 ? undefined : log (x->number) * NUMlog2e);
 	} else {
 		Melder_throw (U"Cannot take the base-2 logarithm (log2) of ", Stackel_whichText (x), U".");
 	}
@@ -2891,8 +2946,8 @@ static void do_log2 () {
 static void do_ln () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined :
-			x->number <= 0.0 ? NUMundefined : log (x->number));
+		pushNumber (isundef (x->number) ? undefined :
+			x->number <= 0.0 ? undefined : log (x->number));
 	} else {
 		Melder_throw (U"Cannot take the natural logarithm (ln) of ", Stackel_whichText (x), U".");
 	}
@@ -2900,8 +2955,8 @@ static void do_ln () {
 static void do_log10 () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined ? NUMundefined :
-			x->number <= 0.0 ? NUMundefined : log10 (x->number));
+		pushNumber (isundef (x->number) ? undefined :
+			x->number <= 0.0 ? undefined : log10 (x->number));
 	} else {
 		Melder_throw (U"Cannot take the base-10 logarithm (log10) of ", Stackel_whichText (x), U".");
 	}
@@ -2909,12 +2964,7 @@ static void do_log10 () {
 static void do_sum () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
-		long numberOfElements = x->numericVector.size;
-		double result = 0.0;
-		for (long i = 1; i <= numberOfElements; i ++) {
-			result += x->numericVector.data [i];
-		}
-		pushNumber (result);
+		pushNumber (sum_scalar (x->numericVector));
 	} else {
 		Melder_throw (U"Cannot compute the sum of ", Stackel_whichText (x), U".");
 	}
@@ -2922,13 +2972,7 @@ static void do_sum () {
 static void do_mean () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
-		long numberOfElements = x->numericVector.size;
-		double result = 0.0;
-		for (long i = 1; i <= numberOfElements; i ++) {
-			result += x->numericVector.data [i];
-		}
-		result /= numberOfElements;
-		pushNumber (result);
+		pushNumber (mean_scalar (x->numericVector));
 	} else {
 		Melder_throw (U"Cannot compute the mean of ", Stackel_whichText (x), U".");
 	}
@@ -2936,20 +2980,7 @@ static void do_mean () {
 static void do_stdev () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
-		long numberOfElements = x->numericVector.size;
-		double mean = 0.0;
-		for (long i = 1; i <= numberOfElements; i ++) {
-			mean += x->numericVector.data [i];
-		}
-		mean /= numberOfElements;
-		double result = 0.0;
-		for (long i = 1; i <= numberOfElements; i ++) {
-			double diff = x->numericVector.data [i] - mean;
-			result += diff * diff;
-		}
-		result /= numberOfElements - 1;
-		result = sqrt (result);
-		pushNumber (result);
+		pushNumber (stdev_scalar (x->numericVector));
 	} else {
 		Melder_throw (U"Cannot compute the mean of ", Stackel_whichText (x), U".");
 	}
@@ -2957,14 +2988,7 @@ static void do_stdev () {
 static void do_center () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
-		long numberOfElements = x->numericVector.size;
-		double result = 0.0, sumOfWeights = 0.0;
-		for (long i = 1; i <= numberOfElements; i ++) {
-			result += i * x->numericVector.data [i];
-			sumOfWeights += x->numericVector.data [i];
-		}
-		result /= sumOfWeights;
-		pushNumber (result);
+		pushNumber (center_scalar (x->numericVector));
 	} else {
 		Melder_throw (U"Cannot compute the center of ", Stackel_whichText (x), U".");
 	}
@@ -2972,8 +2996,7 @@ static void do_center () {
 static void do_function_dd_d (double (*f) (double, double)) {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
-			f (x->number, y->number));
+		pushNumber (isundef (x->number) || isundef (y->number) ? undefined : f (x->number, y->number));
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
 			U" requires two numeric arguments, not ",
@@ -2988,11 +3011,11 @@ static void do_function_dd_d_numvec (double (*f) (double, double)) {
 	Stackel y = pop, x = pop, a = pop;
 	if (a->which == Stackel_NUMERIC_VECTOR && x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
 		long numberOfElements = a->numericVector.size;
-		double *newData = NUMvector <double> (1, numberOfElements);
+		autonumvec newData (numberOfElements, false);
 		for (long ielem = 1; ielem <= numberOfElements; ielem ++) {
 			newData [ielem] = f (x->number, y->number);
 		}
-		pushNumericVector (numberOfElements, newData);
+		pushNumericVector (newData.move());
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
 			U" requires one vector argument and two numeric arguments, not ",
@@ -3008,13 +3031,13 @@ static void do_function_dd_d_nummat (double (*f) (double, double)) {
 	if (a->which == Stackel_NUMERIC_MATRIX && x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
 		long numberOfRows = a->numericMatrix.nrow;
 		long numberOfColumns = a->numericMatrix.ncol;
-		double **newData = NUMmatrix <double> (1, numberOfRows, 1, numberOfColumns);
+		autonummat newData (numberOfRows, numberOfColumns, false);
 		for (long irow = 1; irow <= numberOfRows; irow ++) {
 			for (long icol = 1; icol <= numberOfColumns; icol ++) {
 				newData [irow] [icol] = f (x->number, y->number);
 			}
 		}
-		pushNumericMatrix (numberOfRows, numberOfColumns, newData);
+		pushNumericMatrix (newData.move());
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
 			U" requires one matrix argument and two numeric arguments, not ",
@@ -3029,11 +3052,11 @@ static void do_function_ll_l_numvec (long (*f) (long, long)) {
 	Stackel y = pop, x = pop, a = pop;
 	if (a->which == Stackel_NUMERIC_VECTOR && x->which == Stackel_NUMBER) {
 		long numberOfElements = a->numericVector.size;
-		double *newData = NUMvector <double> (1, numberOfElements);
+		autonumvec newData (numberOfElements, false);
 		for (long ielem = 1; ielem <= numberOfElements; ielem ++) {
 			newData [ielem] = f (lround (x->number), lround (y->number));
 		}
-		pushNumericVector (numberOfElements, newData);
+		pushNumericVector (newData.move());
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
 			U" requires one vector argument and two numeric arguments, not ",
@@ -3049,13 +3072,13 @@ static void do_function_ll_l_nummat (long (*f) (long, long)) {
 	if (a->which == Stackel_NUMERIC_MATRIX && x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
 		long numberOfRows = a->numericMatrix.nrow;
 		long numberOfColumns = a->numericMatrix.ncol;
-		double **newData = NUMmatrix <double> (1, numberOfRows, 1, numberOfColumns);
+		autonummat newData (numberOfRows, numberOfColumns, false);
 		for (long irow = 1; irow <= numberOfRows; irow ++) {
 			for (long icol = 1; icol <= numberOfColumns; icol ++) {
 				newData [irow] [icol] = f (lround (x->number), lround (y->number));
 			}
 		}
-		pushNumericMatrix (numberOfRows, numberOfColumns, newData);
+		pushNumericMatrix (newData.move());
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
 			U" requires one matrix argument and two numeric arguments, not ",
@@ -3065,7 +3088,7 @@ static void do_function_ll_l_nummat (long (*f) (long, long)) {
 static void do_function_dl_d (double (*f) (double, long)) {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
+		pushNumber (isundef (x->number) || isundef (y->number) ? undefined :
 			f (x->number, lround (y->number)));
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
@@ -3076,7 +3099,7 @@ static void do_function_dl_d (double (*f) (double, long)) {
 static void do_function_ld_d (double (*f) (long, double)) {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
+		pushNumber (isundef (x->number) || isundef (y->number) ? undefined :
 			f (lround (x->number), y->number));
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
@@ -3087,7 +3110,7 @@ static void do_function_ld_d (double (*f) (long, double)) {
 static void do_function_ll_l (long (*f) (long, long)) {
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined :
+		pushNumber (isundef (x->number) || isundef (y->number) ? undefined :
 			f (lround (x->number), lround (y->number)));
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
@@ -3107,7 +3130,7 @@ static void do_objects_are_identical () {
 		while (i > 0 && id2 != theCurrentPraatObjects -> list [i]. id) i --;
 		if (i == 0) Melder_throw (U"Object #", id2, U" does not exist in function objectsAreIdentical.");
 		Daata object2 = (Daata) theCurrentPraatObjects -> list [i]. object;
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined ? NUMundefined : Data_equal (object1, object2));
+		pushNumber (isundef (x->number) || isundef (y->number) ? undefined : Data_equal (object1, object2));
 	} else {
 		Melder_throw (U"The function objectsAreIdentical requires two numeric arguments (object IDs), not ",
 			Stackel_whichText (x), U" and ", Stackel_whichText (y), U".");
@@ -3116,7 +3139,7 @@ static void do_objects_are_identical () {
 static void do_function_ddd_d (double (*f) (double, double, double)) {
 	Stackel z = pop, y = pop, x = pop;
 	if (x->which == Stackel_NUMBER && y->which == Stackel_NUMBER && z->which == Stackel_NUMBER) {
-		pushNumber (x->number == NUMundefined || y->number == NUMundefined || z->number == NUMundefined ? NUMundefined :
+		pushNumber (isundef (x->number) || isundef (y->number) || isundef (z->number) ? undefined :
 			f (x->number, y->number, z->number));
 	} else {
 		Melder_throw (U"The function ", Formula_instructionNames [parse [programPointer]. symbol],
@@ -3162,7 +3185,7 @@ static void do_do () {
 			Melder_throw (U"Command \"", command, U"\" not available for current selection.");
 		}
 		//praat_updateSelection ();
-		double value = NUMundefined;
+		double value = undefined;
 		if (valueString.string [0] == 1) {   // nothing written with MelderInfo by praat_doAction or praat_doMenuCommand? then the return value is the ID of the selected object
 			int IOBJECT, result = 0, found = 0;
 			WHERE (SELECTED) { result = IOBJECT; found += 1; }
@@ -3231,14 +3254,14 @@ static void shared_do_writeInfo (int numberOfArguments) {
 			MelderInfo_write (arg->string);
 		} else if (arg->which == Stackel_NUMERIC_VECTOR) {
 			long numberOfElements = arg->numericVector.size;
-			double *data = arg->numericVector.data;
+			double *data = arg->numericVector.at;
 			for (long i = 1; i <= numberOfElements; i ++) {
 				MelderInfo_write (data [i], i == numberOfElements ? U"" : U" ");
 			}
 		} else if (arg->which == Stackel_NUMERIC_MATRIX) {
 			long numberOfRows = arg->numericMatrix.nrow;
 			long numberOfColumns = arg->numericMatrix.ncol;
-			double **data = arg->numericMatrix.data;
+			double **data = arg->numericMatrix.at;
 			for (long irow = 1; irow <= numberOfRows; irow ++) {
 				for (long icol = 1; icol <= numberOfRows; icol ++) {
 					MelderInfo_write (data [irow] [icol], icol == numberOfColumns ? U"" : U" ");
@@ -3307,7 +3330,7 @@ static void do_writeFile () {
 		else if (arg->which == Stackel_STRING)
 			MelderString_append (& text, arg->string);
 	}
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	Melder_relativePathToFile (fileName -> string, & file);
 	MelderFile_writeText (& file, text.string, Melder_getOutputEncoding ());
 	pushNumber (1);
@@ -3332,7 +3355,7 @@ static void do_writeFileLine () {
 			MelderString_append (& text, arg->string);
 	}
 	MelderString_appendCharacter (& text, U'\n');
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	Melder_relativePathToFile (fileName -> string, & file);
 	MelderFile_writeText (& file, text.string, Melder_getOutputEncoding ());
 	pushNumber (1);
@@ -3356,7 +3379,7 @@ static void do_appendFile () {
 		else if (arg->which == Stackel_STRING)
 			MelderString_append (& text, arg->string);
 	}
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	Melder_relativePathToFile (fileName -> string, & file);
 	MelderFile_appendText (& file, text.string);
 	pushNumber (1);
@@ -3381,7 +3404,7 @@ static void do_appendFileLine () {
 			MelderString_append (& text, arg->string);
 	}
 	MelderString_appendCharacter (& text, '\n');
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	Melder_relativePathToFile (fileName -> string, & file);
 	MelderFile_appendText (& file, text.string);
 	pushNumber (1);
@@ -3526,7 +3549,7 @@ static void do_min () {
 		Stackel previous = pop;
 		if (previous->which != Stackel_NUMBER)
 			Melder_throw (U"The function \"min\" can only have numeric arguments, not ", Stackel_whichText (previous), U".");
-		result = result == NUMundefined || previous->number == NUMundefined ? NUMundefined :
+		result = isundef (result) || isundef (previous->number) ? undefined :
 			result < previous->number ? result : previous->number;
 	}
 	pushNumber (result);
@@ -3545,7 +3568,7 @@ static void do_max () {
 		Stackel previous = pop;
 		if (previous->which != Stackel_NUMBER)
 			Melder_throw (U"The function \"max\" can only have numeric arguments, not ", Stackel_whichText (previous), U".");
-		result = result == NUMundefined || previous->number == NUMundefined ? NUMundefined :
+		result = isundef (result) || isundef (previous->number) ? undefined :
 			result > previous->number ? result : previous->number;
 	}
 	pushNumber (result);
@@ -3565,9 +3588,9 @@ static void do_imin () {
 		Stackel previous = pop;
 		if (previous->which != Stackel_NUMBER)
 			Melder_throw (U"The function \"imin\" can only have numeric arguments, not ", Stackel_whichText (previous), U".");
-		if (minimum == NUMundefined || previous->number == NUMundefined) {
-			minimum = NUMundefined;
-			result = NUMundefined;
+		if (isundef (minimum) || isundef (previous->number)) {
+			minimum = undefined;
+			result = undefined;
 		} else if (previous->number < minimum) {
 			minimum = previous->number;
 			result = j;
@@ -3587,10 +3610,10 @@ static void do_imax () {
 		for (int j = lround (n->number) - 1; j > 0; j --) {
 			Stackel previous = pop;
 			if (previous->which != Stackel_NUMBER)
-				Melder_throw (U"The function \"imax\" can only have numeric arguments, not ", Stackel_whichText (previous), U".");
-			if (maximum == NUMundefined || previous->number == NUMundefined) {
-				maximum = NUMundefined;
-				result = NUMundefined;
+				Melder_throw (U"The function \"imax\" cannot mix a numeric argument with ", Stackel_whichText (previous), U".");
+			if (isundef (maximum) || isundef (previous->number)) {
+				maximum = undefined;
+				result = undefined;
 			} else if (previous->number > maximum) {
 				maximum = previous->number;
 				result = j;
@@ -3602,11 +3625,11 @@ static void do_imax () {
 			Melder_throw (U"The function \"imax\" requires exactly one vector argument.");
 		long numberOfElements = last->numericVector.size;
 		long result = 1;
-		double maximum = last->numericVector.data [1];
+		double maximum = last->numericVector [1];
 		for (long i = 2; i <= numberOfElements; i ++) {
-			if (last->numericVector.data [i] > maximum) {
+			if (last->numericVector [i] > maximum) {
 				result = i;
-				maximum = last->numericVector.data [i];
+				maximum = last->numericVector [i];
 			}
 		}
 		pushNumber (result);
@@ -3615,6 +3638,27 @@ static void do_imax () {
 		Melder_throw (U"Cannot compute the imax of ", Stackel_whichText (nn), U".");
 	}
 }
+static void do_norm () {
+	Stackel n = pop;
+	Melder_assert (n->which == Stackel_NUMBER);
+	if (n->number < 1 || n->number > 2)
+		Melder_throw (U"The function \"norm\" requires one or two arguments.");
+	real powerNumber = 2.0;
+	if (n->number == 2) {
+		Stackel power = pop;
+		if (power->which != Stackel_NUMBER)
+			Melder_throw (U"The second argument to \"norm\" should be a number, not ", Stackel_whichText (power), U".");
+		powerNumber = power->number;
+	}
+	Stackel x = pop;
+	if (x->which == Stackel_NUMERIC_VECTOR) {
+		pushNumber (norm_scalar (x->numericVector, powerNumber));
+	} else if (x->which == Stackel_NUMERIC_MATRIX) {
+		pushNumber (norm_scalar (x->numericMatrix, powerNumber));
+	} else {
+		Melder_throw (U"Cannot compute the norm of ", Stackel_whichText (x), U".");
+	}
+}
 static void do_zeroNumvec () {
 	Stackel n = pop;
 	Melder_assert (n -> which == Stackel_NUMBER);
@@ -3624,17 +3668,16 @@ static void do_zeroNumvec () {
 	if (rank > 1) {
 		Melder_throw (U"The function \"zero#\" cannot have more than one argument (consider using zero##).");
 	}
-	long numberOfElements;
 	Stackel nelem = pop;
 	if (nelem -> which != Stackel_NUMBER)
 		Melder_throw (U"In the function \"zero#\", the number of elements has to be a number, not ", Stackel_whichText (nelem), U".");
-	numberOfElements = lround (nelem -> number);
-	if (numberOfElements == NUMundefined)
+	double numberOfElements = nelem -> number;
+	if (isundef (numberOfElements))
 		Melder_throw (U"In the function \"zero#\", the number of elements is undefined.");
-	if (numberOfElements <= 0)
-		Melder_throw (U"In the function \"zero#\", the number of elements has to be positive.");
-	autoNUMvector <double> data (1, numberOfElements);
-	pushNumericVector (numberOfElements, data.transfer());
+	if (numberOfElements < 0.0)
+		Melder_throw (U"In the function \"zero#\", the number of elements should not be negative.");
+	autonumvec result (lround (numberOfElements), true);
+	pushNumericVector (result.move());
 }
 static void do_zeroNummat () {
 	Stackel n = pop;
@@ -3642,25 +3685,24 @@ static void do_zeroNummat () {
 	int rank = lround (n -> number);
 	if (rank != 2)
 		Melder_throw (U"The function \"zero##\" requires two arguments.");
-	long numberOfRows = 1, numberOfColumns = 1;
 	Stackel ncol = pop;
 	if (ncol -> which != Stackel_NUMBER)
 		Melder_throw (U"In the function \"zero##\", the number of columns has to be a number, not ", Stackel_whichText (ncol), U".");
-	numberOfColumns = lround (ncol -> number);
+	double numberOfColumns = ncol -> number;
 	Stackel nrow = pop;
 	if (nrow -> which != Stackel_NUMBER)
 		Melder_throw (U"In the function \"zero##\", the number of rows has to be a number, not ", Stackel_whichText (nrow), U".");
-	numberOfRows = lround (nrow -> number);
-	if (numberOfRows == NUMundefined)
+	double numberOfRows = nrow -> number;
+	if (isundef (numberOfRows))
 		Melder_throw (U"In the function \"zero##\", the number of rows is undefined.");
-	if (numberOfColumns == NUMundefined)
+	if (isundef (numberOfColumns))
 		Melder_throw (U"In the function \"zero##\", the number of columns is undefined.");
-	if (numberOfRows <= 0)
-		Melder_throw (U"In the function \"zero##\", the number of rows has to be positive.");
-	if (numberOfColumns <= 0)
-		Melder_throw (U"In the function \"zero##\", the number of columns has to be positive.");
-	autoNUMmatrix <double> data (1, numberOfRows, 1, numberOfColumns);
-	pushNumericMatrix (numberOfRows, numberOfColumns, data.transfer());
+	if (numberOfRows < 0.0)
+		Melder_throw (U"In the function \"zero##\", the number of rows should not be negative.");
+	if (numberOfColumns < 0.0)
+		Melder_throw (U"In the function \"zero##\", the number of columns should not be negative.");
+	autonummat result (lround (numberOfRows), lround (numberOfColumns), true);
+	pushNumericMatrix (result.move());
 }
 static void do_linearNumvec () {
 	Stackel stackel_narg = pop;
@@ -3679,30 +3721,65 @@ static void do_linearNumvec () {
 	if (stack_minimum -> which != Stackel_NUMBER)
 		Melder_throw (U"In the function \"linear#\", the minimum (first argument) has to be a number, not ", Stackel_whichText (stack_minimum), U".");
 	double minimum = stack_minimum -> number;
-	if (minimum == NUMundefined)
+	if (isundef (minimum))
 		Melder_throw (U"Undefined minimum in the function \"linear#\" (first argument).");
 	if (stack_maximum -> which != Stackel_NUMBER)
 		Melder_throw (U"In the function \"linear#\", the maximum (second argument) has to be a number, not ", Stackel_whichText (stack_maximum), U".");
 	double maximum = stack_maximum -> number;
-	if (maximum == NUMundefined)
+	if (isundef (maximum))
 		Melder_throw (U"Undefined maximum in the function \"linear#\" (second argument).");
 	if (maximum < minimum)
 		Melder_throw (U"Maximum (", maximum, U") smaller than minimum (", minimum, U") in function \"linear#\".");
 	if (stack_numberOfSteps -> which != Stackel_NUMBER)
 		Melder_throw (U"In the function \"linear#\", the number of steps (third argument) has to be a number, not ", Stackel_whichText (stack_numberOfSteps), U".");
-	if (stack_numberOfSteps -> number == NUMundefined)
+	if (isundef (stack_numberOfSteps -> number))
 		Melder_throw (U"Undefined number of steps in the function \"linear#\" (third argument).");
 	long numberOfSteps = lround (stack_numberOfSteps -> number);
 	if (numberOfSteps <= 0)
 		Melder_throw (U"In the function \"linear#\", the number of steps (third argument) has to be positive, not ", numberOfSteps, U".");
-	autoNUMvector <double> data (1, numberOfSteps);
+	autonumvec result { numberOfSteps, false };
 	for (long ielem = 1; ielem <= numberOfSteps; ielem ++) {
-		data [ielem] = excludeEdges ?
+		result [ielem] = excludeEdges ?
 			minimum + (ielem - 0.5) * (maximum - minimum) / numberOfSteps :
 			minimum + (ielem - 1) * (maximum - minimum) / (numberOfSteps - 1);
 	}
-	if (! excludeEdges) data [numberOfSteps] = maximum;   // remove rounding problems
-	pushNumericVector (numberOfSteps, data.transfer());
+	if (! excludeEdges) result [numberOfSteps] = maximum;   // remove rounding problems
+	pushNumericVector (result.move());
+}
+static void do_peaksNummat () {
+	Stackel n = pop;
+	Melder_assert (n->which == Stackel_NUMBER);
+	if (n->number != 4)
+		Melder_throw (U"The function peaks## requires four arguments (vector, edges, interpolation, sortByHeight).");
+	Stackel s = pop;
+	if (s->which != Stackel_NUMBER)
+		Melder_throw (U"The fourth argument to peaks## has to be a number, not ", Stackel_whichText (s), U".");
+	bool sortByHeight = s->number != 0.0;
+	Stackel i = pop;
+	if (i->which != Stackel_NUMBER)
+		Melder_throw (U"The third argument to peaks## has to be a number, not ", Stackel_whichText (i), U".");
+	int interpolation = lround (i->number);
+	Stackel e = pop;
+	if (e->which != Stackel_NUMBER)
+		Melder_throw (U"The second argument to peaks## has to be a number, not ", Stackel_whichText (e), U".");
+	bool includeEdges = e->number != 0.0;
+	Stackel vec = pop;
+	if (vec->which != Stackel_NUMERIC_VECTOR)
+		Melder_throw (U"The first argument to peaks## has to be a numeric vector, not ", Stackel_whichText (vec), U".");
+	autonummat result = peaks_nummat (vec->numericVector, includeEdges, interpolation, sortByHeight);
+	pushNumericMatrix (result.move());
+}
+static void do_size () {
+	Stackel n = pop;
+	Melder_assert (n->which == Stackel_NUMBER);
+	if (n->number != 1)
+		Melder_throw (U"The function \"size\" requires one (vector) argument.");
+	Stackel array = pop;
+	if (array->which == Stackel_NUMERIC_VECTOR) {
+		pushNumber (array->numericVector.size);
+	} else {
+		Melder_throw (U"The function size requires a vector argument, not ", Stackel_whichText (array), U".");
+	}
 }
 static void do_numberOfRows () {
 	Stackel n = pop;
@@ -3776,14 +3853,14 @@ static void do_numericVectorElement () {
 	Stackel r = pop;
 	if (r -> which != Stackel_NUMBER)
 		Melder_throw (U"In vector indexing, the index has to be a number, not ", Stackel_whichText (r), U".");
-	if (r -> number == NUMundefined)
+	if (isundef (r -> number))
 		Melder_throw (U"The element index is undefined.");
 	element = lround (r -> number);
 	if (element <= 0)
 		Melder_throw (U"In vector indexing, the element index has to be positive.");
-	if (element > vector -> numericVectorValue. size)
+	if (element > vector -> numericVectorValue.size)
 		Melder_throw (U"Element index out of bounds.");
-	pushNumber (vector -> numericVectorValue. data [element]);
+	pushNumber (vector -> numericVectorValue [element]);
 }
 static void do_numericMatrixElement () {
 	InterpreterVariable matrix = parse [programPointer]. content.variable;
@@ -3791,7 +3868,7 @@ static void do_numericMatrixElement () {
 	Stackel c = pop;
 	if (c -> which != Stackel_NUMBER)
 		Melder_throw (U"In matrix indexing, the column index has to be a number, not ", Stackel_whichText (c), U".");
-	if (c -> number == NUMundefined)
+	if (isundef (c -> number))
 		Melder_throw (U"The column index is undefined.");
 	column = lround (c -> number);
 	if (column <= 0)
@@ -3801,14 +3878,14 @@ static void do_numericMatrixElement () {
 	Stackel r = pop;
 	if (r -> which != Stackel_NUMBER)
 		Melder_throw (U"In matrix indexing, the row index has to be a number, not ", Stackel_whichText (r), U".");
-	if (r -> number == NUMundefined)
+	if (isundef (r -> number))
 		Melder_throw (U"The row index is undefined.");
 	row = lround (r -> number);
 	if (row <= 0)
 		Melder_throw (U"In matrix indexing, the row index has to be positive.");
 	if (row > matrix -> numericMatrixValue. nrow)
 		Melder_throw (U"Row index out of bounds.");
-	pushNumber (matrix -> numericMatrixValue. data [row] [column]);
+	pushNumber (matrix -> numericMatrixValue [row] [column]);
 }
 static void do_indexedNumericVariable () {
 	Stackel n = pop;
@@ -3817,7 +3894,7 @@ static void do_indexedNumericVariable () {
 	if (nindex < 1)
 		Melder_throw (U"Indexed variables require at least one index.");
 	char32 *indexedVariableName = parse [programPointer]. content.string;
-	static MelderString totalVariableName { 0 };
+	static MelderString totalVariableName { };
 	MelderString_copy (& totalVariableName, indexedVariableName, U"[");
 	w -= nindex;
 	for (int iindex = 1; iindex <= nindex; iindex ++) {
@@ -3842,7 +3919,7 @@ static void do_indexedStringVariable () {
 	if (nindex < 1)
 		Melder_throw (U"Indexed variables require at least one index.");
 	char32 *indexedVariableName = parse [programPointer]. content.string;
-	static MelderString totalVariableName { 0 };
+	static MelderString totalVariableName { };
 	MelderString_copy (& totalVariableName, indexedVariableName, U"[");
 	w -= nindex;
 	for (int iindex = 1; iindex <= nindex; iindex ++) {
@@ -3882,7 +3959,7 @@ static void do_number () {
 static void do_fileReadable () {
 	Stackel s = pop;
 	if (s->which == Stackel_STRING) {
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (s->string, & file);
 		pushNumber (MelderFile_readable (& file));
 	} else {
@@ -3987,9 +4064,12 @@ static void do_backslashTrigraphsToUnicodeStr () {
 	Stackel s = pop;
 	if (s->which == Stackel_STRING) {
 		long length = str32len (s->string);
-		autostring32 unicode = Melder_calloc (char32, length + 1);
-		Longchar_nativize32 (s->string, unicode.peek(), false);
-		pushString (unicode.transfer());
+		//autostring32 unicode = Melder_calloc (char32, length + 1);
+		//Longchar_nativize32 (s->string, unicode.peek(), false);
+		//pushString (unicode.transfer());
+		char32 *unicode = Melder_calloc (char32, length + 1);   // OPTIMIZE
+		Longchar_nativize32 (s->string, unicode, false);   // noexcept
+		pushString (unicode);
 	} else {
 		Melder_throw (U"The function \"unicodeToBackslashTrigraphs$\" requires a string, not ", Stackel_whichText (s), U".");
 	}
@@ -3998,8 +4078,9 @@ static void do_environmentStr () {
 	Stackel s = pop;
 	if (s->which == Stackel_STRING) {
 		char32 *value = Melder_getenv (s->string);
-		autostring32 result = Melder_dup (value ? value : U"");
-		pushString (result.transfer());
+		//autostring32 result = Melder_dup (value ? value : U"");
+		//pushString (result.transfer());
+		pushString (Melder_dup (value ? value : U""));
 	} else {
 		Melder_throw (U"The function \"environment$\" requires a string, not ", Stackel_whichText (s), U".");
 	}
@@ -4072,8 +4153,10 @@ static void do_replaceStr () {
 	Stackel x = pop, u = pop, t = pop, s = pop;
 	if (s->which == Stackel_STRING && t->which == Stackel_STRING && u->which == Stackel_STRING && x->which == Stackel_NUMBER) {
 		long numberOfMatches;
-		autostring32 result = str_replace_literal (s->string, t->string, u->string, lround (x->number), & numberOfMatches);
-		pushString (result.transfer());
+		//autostring32 result = str_replace_literal (s->string, t->string, u->string, lround (x->number), & numberOfMatches);
+		//pushString (result.transfer());
+		char32 *result = str_replace_literal (s->string, t->string, u->string, lround (x->number), & numberOfMatches);
+		pushString (result);
 	} else {
 		Melder_throw (U"The function \"replace$\" requires three strings and a number.");
 	}
@@ -4087,8 +4170,10 @@ static void do_replace_regexStr () {
 			Melder_throw (U"replace_regex$(): ", errorMessage, U".");
 		} else {
 			long numberOfMatches;
-			autostring32 result = str_replace_regexp (s->string, compiled_regexp, u->string, lround (x->number), & numberOfMatches);
-			pushString (result.transfer());
+			//autostring32 result = str_replace_regexp (s->string, compiled_regexp, u->string, lround (x->number), & numberOfMatches);
+			//pushString (result.transfer());
+			char32 *result = str_replace_regexp (s->string, compiled_regexp, u->string, lround (x->number), & numberOfMatches);
+			pushString (result);
 		}
 	} else {
 		Melder_throw (U"The function \"replace_regex$\" requires three strings and a number.");
@@ -4099,14 +4184,14 @@ static void do_extractNumber () {
 	if (s->which == Stackel_STRING && t->which == Stackel_STRING) {
 		char32 *substring = str32str (s->string, t->string);
 		if (! substring) {
-			pushNumber (NUMundefined);
+			pushNumber (undefined);
 		} else {
 			/* Skip the prompt. */
 			substring += str32len (t->string);
 			/* Skip white space. */
 			while (*substring == U' ' || *substring == U'\t' || *substring == U'\n' || *substring == U'\r') substring ++;
 			if (substring [0] == U'\0' || str32nequ (substring, U"--undefined--", 13)) {
-				pushNumber (NUMundefined);
+				pushNumber (undefined);
 			} else {
 				char32 buffer [101], *slash;
 				int i;
@@ -4199,6 +4284,7 @@ static void do_selected () {
 	}
 	pushNumber (result);
 }
+#if 0
 static void do_selectedStr () {
 	Stackel n = pop;
 	autostring32 result;
@@ -4220,11 +4306,43 @@ static void do_selectedStr () {
 			ClassInfo klas = Thing_classFromClassName (s->string, nullptr);
 			result.reset (Melder_dup (praat_nameOfSelected (klas, lround (x->number))));
 		} else {
-			Melder_throw (U"The function \"selected$\" requires 0, 1, or 2 arguments, not ", n->number, U".");
+			Melder_throw (U"The function \"selected$\" requires a string (an object type name) and a number.");
 		}
+	} else {
+		Melder_throw (U"The function \"selected$\" requires 0, 1, or 2 arguments, not ", n->number, U".");
 	}
 	pushString (result.transfer());
 }
+#else
+static void do_selectedStr () {
+	Stackel n = pop;
+	char32 *resultSource;   // purposefully don't initialize, so that the compiler can check that has been assigned to when used
+	if (n->number == 0) {
+		resultSource = praat_nameOfSelected (nullptr, 0);
+	} else if (n->number == 1) {
+		Stackel a = pop;
+		if (a->which == Stackel_STRING) {
+			ClassInfo klas = Thing_classFromClassName (a->string, nullptr);
+			resultSource = praat_nameOfSelected (klas, 0);
+		} else if (a->which == Stackel_NUMBER) {
+			resultSource = praat_nameOfSelected (nullptr, lround (a->number));
+		} else {
+			Melder_throw (U"The function \"selected$\" requires a string (an object type name) and/or a number.");
+		}
+	} else if (n->number == 2) {
+		Stackel x = pop, s = pop;
+		if (s->which == Stackel_STRING && x->which == Stackel_NUMBER) {
+			ClassInfo klas = Thing_classFromClassName (s->string, nullptr);
+			resultSource = praat_nameOfSelected (klas, lround (x->number));
+		} else {
+			Melder_throw (U"The function \"selected$\" requires a string (an object type name) and a number.");
+		}
+	} else {
+		Melder_throw (U"The function \"selected$\" requires 0, 1, or 2 arguments, not ", n->number, U".");
+	}
+	pushString (Melder_dup (resultSource));
+}
+#endif
 static void do_numberOfSelected () {
 	Stackel n = pop;
 	long result = 0;
@@ -4523,8 +4641,8 @@ static void do_object_colstr () {
 static void do_stringStr () {
 	Stackel value = pop;
 	if (value->which == Stackel_NUMBER) {
-		autostring32 result = Melder_dup (Melder_double (value->number));
-		pushString (result.transfer());
+		//autostring32 result = Melder_dup (Melder_double (value->number));
+		pushString (Melder_dup (Melder_double (value->number)));
 	} else {
 		Melder_throw (U"The function \"string$\" requires a number, not ", Stackel_whichText (value), U".");
 	}
@@ -4541,8 +4659,8 @@ static void do_sleep () {
 static void do_fixedStr () {
 	Stackel precision = pop, value = pop;
 	if (value->which == Stackel_NUMBER && precision->which == Stackel_NUMBER) {
-		autostring32 result = Melder_dup (Melder_fixed (value->number, lround (precision->number)));
-		pushString (result.transfer());
+		//autostring32 result = Melder_dup (Melder_fixed (value->number, lround (precision->number)));
+		pushString (Melder_dup (Melder_fixed (value->number, lround (precision->number))));
 	} else {
 		Melder_throw (U"The function \"fixed$\" requires two numbers (value and precision), not ", Stackel_whichText (value), U" and ", Stackel_whichText (precision), U".");
 	}
@@ -4561,7 +4679,7 @@ static void do_deleteFile () {
 		Melder_throw (U"The function \"deleteFile\" is not available inside manuals.");
 	Stackel f = pop;
 	if (f->which == Stackel_STRING) {
-		structMelderFile file { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (f->string, & file);
 		MelderFile_delete (& file);
 		pushNumber (1);
@@ -4574,7 +4692,7 @@ static void do_createDirectory () {
 		Melder_throw (U"The function \"createDirectory\" is not available inside manuals.");
 	Stackel f = pop;
 	if (f->which == Stackel_STRING) {
-		structMelderDir currentDirectory { { 0 } };
+		structMelderDir currentDirectory { };
 		Melder_getDefaultDir (& currentDirectory);
 		#if defined (UNIX) || defined (macintosh)
 			Melder_createDirectory (& currentDirectory, f->string, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
@@ -4598,7 +4716,7 @@ static void do_variableExists () {
 static void do_readFile () {
 	Stackel f = pop;
 	if (f->which == Stackel_STRING) {
-		structMelderFile file { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (f->string, & file);
 		autostring32 text = MelderFile_readText (& file);
 		pushNumber (Melder_atof (text.peek()));
@@ -4609,7 +4727,7 @@ static void do_readFile () {
 static void do_readFileStr () {
 	Stackel f = pop;
 	if (f->which == Stackel_STRING) {
-		structMelderFile file { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (f->string, & file);
 		autostring32 text = MelderFile_readText (& file);
 		pushString (text.transfer());
@@ -4622,14 +4740,25 @@ static void do_numericVectorLiteral () {
 	Melder_assert (n->which == Stackel_NUMBER);
 	long numberOfElements = lround (n->number);
 	Melder_assert (numberOfElements > 0);
-	double *result = NUMvector<double> (1, numberOfElements);
+	autonumvec result { numberOfElements, false };
 	for (long ielement = numberOfElements; ielement > 0; ielement --) {
 		Stackel e = pop;
 		if (e->which != Stackel_NUMBER)
 			Melder_throw (U"Vector element has to be a number, not ", Stackel_whichText (e));
 		result [ielement] = e->number;
 	}
-	pushNumericVector (numberOfElements, result);
+	pushNumericVector (result.move());
+}
+static void do_inner () {
+	/*
+		result = inner (x#, y#)
+	*/
+	Stackel y = pop, x = pop;
+	if (x->which == Stackel_NUMERIC_VECTOR && y->which == Stackel_NUMERIC_VECTOR) {
+		pushNumber (inner_scalar (x->numericVector, y->numericVector));
+	} else {
+		Melder_throw (U"The function \"inner\" requires two vectors, not ", Stackel_whichText (x), U" and ", Stackel_whichText (y), U".");
+	}
 }
 static void do_outerNummat () {
 	/*
@@ -4637,22 +4766,8 @@ static void do_outerNummat () {
 	*/
 	Stackel y = pop, x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR && y->which == Stackel_NUMERIC_VECTOR) {
-		long xn = x->numericVector.size, yn = y->numericVector.size;
-		double **result = NUMmatrix<double> (1, xn, 1, yn);
-		for (long irow = 1; irow <= xn; irow ++) {
-			double xvalue = x->numericVector.data [irow];
-			if (xvalue == NUMundefined) {
-				for (long icol = 1; icol <= yn; icol ++) {
-					result [irow] [icol] = NUMundefined;
-				}
-			} else {
-				for (long icol = 1; icol <= yn; icol ++) {
-					double yvalue = y->numericVector.data [icol];
-					result [irow] [icol] = /*yvalue == NUMundefined ? NUMundefined :*/ xvalue * yvalue;
-				}
-			}
-		}
-		pushNumericMatrix (xn, yn, result);
+		autonummat result = outer_nummat (x->numericVector, y->numericVector);
+		pushNumericMatrix (result.move());
 	} else {
 		Melder_throw (U"The function \"outer##\" requires two vectors, not ", Stackel_whichText (x), U" and ", Stackel_whichText (y), U".");
 	}
@@ -4670,76 +4785,52 @@ static void do_mulNumvec () {
 		if (ynrow != xn)
 			Melder_throw (U"In the function \"mul#\", the dimension of the vector and the number of rows of the matrix should be equal, "
 				"not ", xn, U" and ", ynrow);
-		bool xundefined = false;
-		for (long i = 1; i <= xn; i ++) {
-			double xvalue = x->numericVector.data [i];
-			if (xvalue == NUMundefined) {
-				xundefined = true;
-				break;
-			}
-		}
-		double *result = NUMvector<double> (1, yncol);
-		if (xundefined) {
-			for (long j = 1; j <= yncol; j ++) {
-				result [j] = NUMundefined;
-			}
-		} else {
-			for (long j = 1; j <= yncol; j ++) {
-				result [j] = 0.0;
-				for (long i = 1; i <= ynrow; i ++) {
-					double xvalue = x->numericVector.data [i];
-					double yvalue = y->numericMatrix.data [i] [j];
-					#if 0
-					if (yvalue == NUMundefined) {
-						result [j] = NUMundefined;
-						break;
-					}
-					#endif
-					result [j] += xvalue * yvalue;
-				}
+		autonumvec result { yncol, false };
+		for (long j = 1; j <= yncol; j ++) {
+			result [j] = 0.0;
+			for (long i = 1; i <= ynrow; i ++) {
+				double xvalue = x->numericVector [i];
+				double yvalue = y->numericMatrix [i] [j];
+				result [j] += xvalue * yvalue;
 			}
 		}
-		pushNumericVector (yncol, result);
+		pushNumericVector (result.move());
 	} else if (x->which == Stackel_NUMERIC_MATRIX && y->which == Stackel_NUMERIC_VECTOR) {
 		/*
 			result# = mul# (x##, y#)
 		*/
 		long xnrow = x->numericMatrix.nrow, xncol = x->numericMatrix.ncol, yn = y->numericVector.size;
 		if (yn != xncol)
-			Melder_throw (U"In the function \"mul#\", the the number of columns of the matrix and the dimension of the vector should be equal, "
+			Melder_throw (U"In the function \"mul#\", the number of columns of the matrix and the dimension of the vector should be equal, "
 				"not ", xncol, U" and ", yn);
-		bool yundefined = false;
-		for (long i = 1; i <= yn; i ++) {
-			double yvalue = y->numericVector.data [i];
-			if (yvalue == NUMundefined) {
-				yundefined = true;
-				break;
+		autonumvec result { xnrow, false };
+		for (long i = 1; i <= xnrow; i ++) {
+			result [i] = 0.0;
+			for (long j = 1; j <= xncol; j ++) {
+				double xvalue = x->numericMatrix [i] [j];
+				double yvalue = y->numericVector [j];
+				result [i] += xvalue * yvalue;
 			}
 		}
-		double *result = NUMvector<double> (1, xnrow);
-		if (yundefined) {
-			for (long i = 1; i <= xnrow; i ++) {
-				result [i] = NUMundefined;
-			}
-		} else {
-			for (long i = 1; i <= xnrow; i ++) {
-				result [i] = 0.0;
-				for (long j = 1; j <= xncol; j ++) {
-					double xvalue = x->numericMatrix.data [i] [j];
-					double yvalue = y->numericVector.data [j];
-					#if 0
-					if (xvalue == NUMundefined) {
-						result [i] = NUMundefined;
-						break;
-					}
-					#endif
-					result [i] += xvalue * yvalue;
-				}
+		pushNumericVector (result.move());
+	} else {
+		Melder_throw (U"The function \"mul#\" requires a vector and a matrix, not ", Stackel_whichText (x), U" and ", Stackel_whichText (y), U".");
+	}
+}
+static void do_repeatNumvec () {
+	Stackel n = pop, x = pop;
+	if (x->which == Stackel_NUMERIC_VECTOR && n->which == Stackel_NUMBER) {
+		long n_old = x->numericVector.size;
+		long times = lround (n->number);
+		autonumvec result { n_old * times, false };
+		for (long i = 1; i <= times; i ++) {
+			for (long j = 1; j <= n_old; j ++) {
+				result [(i - 1) * n_old + j] = x->numericVector [j];
 			}
 		}
-		pushNumericVector (xnrow, result);
+		pushNumericVector (result.move());
 	} else {
-		Melder_throw (U"The function \"mul#\" requires a vector and a matrix, not ", Stackel_whichText (x), U" and ", Stackel_whichText (y), U".");
+		Melder_throw (U"The function \"repeat#\" requires a vector and a number, not ", Stackel_whichText (x), U" and ", Stackel_whichText (n), U".");
 	}
 }
 static void do_beginPauseForm () {
@@ -5791,16 +5882,16 @@ static double NUMarcsinh (double x) {
 	return log (x + sqrt (1.0 + x * x));
 }
 static double NUMarccosh (double x) {
-	return x < 1.0 ? NUMundefined : log (x + sqrt (x * x - 1.0));
+	return x < 1.0 ? undefined : log (x + sqrt (x * x - 1.0));
 }
 static double NUMarctanh (double x) {
-	return x <= -1.0 || x >= 1.0 ? NUMundefined : 0.5 * log ((1.0 + x) / (1.0 - x));
+	return x <= -1.0 || x >= 1.0 ? undefined : 0.5 * log ((1.0 + x) / (1.0 - x));
 }
 static double NUMerf (double x) {
 	return 1.0 - NUMerfcc (x);
 }
 
-void Formula_run (long row, long col, struct Formula_Result *result) {
+void Formula_run (long row, long col, Formula_Result *result) {
 	FormulaInstruction f = parse;
 	programPointer = 1;   // first symbol of the program
 	if (! theStack) theStack = Melder_calloc_f (struct structStackel, 10000);
@@ -5945,6 +6036,7 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
 } break; case MAX_: { do_max ();
 } break; case IMIN_: { do_imin ();
 } break; case IMAX_: { do_imax ();
+} break; case NORM_: { do_norm ();
 } break; case ZERO_NUMVEC_: { do_zeroNumvec ();
 } break; case ZERO_NUMMAT_: { do_zeroNummat ();
 } break; case LINEAR_NUMVEC_: { do_linearNumvec ();
@@ -5954,6 +6046,8 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
 } break; case RANDOM_INTEGER_NUMMAT_: { do_function_ll_l_nummat (NUMrandomInteger);
 } break; case RANDOM_GAUSS_NUMVEC_: { do_function_dd_d_numvec (NUMrandomGauss);
 } break; case RANDOM_GAUSS_NUMMAT_: { do_function_dd_d_nummat (NUMrandomGauss);
+} break; case PEAKS_NUMMAT_: { do_peaksNummat ();
+} break; case SIZE_: { do_size ();
 } break; case NUMBER_OF_ROWS_: { do_numberOfRows ();
 } break; case NUMBER_OF_COLUMNS_: { do_numberOfColumns ();
 } break; case EDITOR_: { do_editor ();
@@ -6010,8 +6104,10 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
 } break; case READ_FILE_: { do_readFile ();
 } break; case READ_FILESTR_: { do_readFileStr ();
 /********** Matrix functions: **********/
+} break; case INNER_: { do_inner ();
 } break; case OUTER_NUMMAT_: { do_outerNummat ();
 } break; case MUL_NUMVEC_: { do_mulNumvec ();
+} break; case REPEAT_NUMVEC_: { do_repeatNumvec ();
 /********** Pause window functions: **********/
 } break; case BEGIN_PAUSE_FORM_: { do_beginPauseForm ();
 } break; case PAUSE_FORM_ADD_REAL_: { do_pauseFormAddReal ();
@@ -6149,14 +6245,12 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
 	pushNumber (var -> numericValue);
 } break; case NUMERIC_VECTOR_VARIABLE_: {
 	InterpreterVariable var = f [programPointer]. content.variable;
-	double *data = NUMvector_copy (var -> numericVectorValue. data,
-		1, var -> numericVectorValue. size);
-	pushNumericVector (var -> numericVectorValue. size, data);
+	autonumvec vec = copy_numvec (var -> numericVectorValue);
+	pushNumericVector (vec.move());
 } break; case NUMERIC_MATRIX_VARIABLE_: {
 	InterpreterVariable var = f [programPointer]. content.variable;
-	double **data = NUMmatrix_copy (var -> numericMatrixValue. data,
-		1, var -> numericMatrixValue. nrow, 1, var -> numericMatrixValue. ncol);
-	pushNumericMatrix (var -> numericMatrixValue. nrow, var -> numericMatrixValue. ncol, data);
+	autonummat mat = copy_nummat (var -> numericMatrixValue);
+	pushNumericMatrix (mat.move());
 } break; case STRING_VARIABLE_: {
 	InterpreterVariable var = f [programPointer]. content.variable;
 	autostring32 string = Melder_dup (var -> stringValue);
@@ -6186,24 +6280,33 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
 			if (theStack [1]. which == Stackel_NUMERIC_MATRIX) Melder_throw (U"Found a matrix expression instead of a vector expression.");
 			result -> expressionType = kFormula_EXPRESSION_TYPE_NUMERIC_VECTOR;
 			result -> result.numericVectorResult = theStack [1]. numericVector;   // dangle
-			theStack [1]. numericVector = theZeroNumericVector;   // ...undangle (and disown)
+			theStack [1]. numericVector = empty_numvec;   // ...undangle (and disown)
 		} else if (theExpressionType [theLevel] == kFormula_EXPRESSION_TYPE_NUMERIC_MATRIX) {
 			if (theStack [1]. which == Stackel_NUMBER) Melder_throw (U"Found a numeric expression instead of a matrix expression.");
 			if (theStack [1]. which == Stackel_STRING) Melder_throw (U"Found a string expression instead of a matrix expression.");
 			if (theStack [1]. which == Stackel_NUMERIC_VECTOR) Melder_throw (U"Found a vector expression instead of a matrix expression.");
 			result -> expressionType = kFormula_EXPRESSION_TYPE_NUMERIC_MATRIX;
 			result -> result.numericMatrixResult = theStack [1]. numericMatrix;   // dangle
-			theStack [1]. numericMatrix = theZeroNumericMatrix;   // ...undangle (and disown)
+			theStack [1]. numericMatrix = empty_nummat;   // ...undangle (and disown)
 		} else {
 			Melder_assert (theExpressionType [theLevel] == kFormula_EXPRESSION_TYPE_UNKNOWN);
 			if (theStack [1]. which == Stackel_NUMBER) {
 				result -> expressionType = kFormula_EXPRESSION_TYPE_NUMERIC;
 				result -> result.numericResult = theStack [1]. number;
-			} else {
-				Melder_assert (theStack [1]. which == Stackel_STRING);
+			} else if (theStack [1]. which == Stackel_STRING) {
 				result -> expressionType = kFormula_EXPRESSION_TYPE_STRING;
 				result -> result.stringResult = theStack [1]. string;   // dangle...
 				theStack [1]. string = nullptr;   // ...undangle (and disown)
+			} else if (theStack [1]. which == Stackel_NUMERIC_VECTOR) {
+				result -> expressionType = kFormula_EXPRESSION_TYPE_NUMERIC_VECTOR;
+				result -> result.numericVectorResult = theStack [1]. numericVector;   // dangle...
+				theStack [1]. numericVector = empty_numvec;   // ...undangle (and disown)
+			} else if (theStack [1]. which == Stackel_NUMERIC_MATRIX) {
+				result -> expressionType = kFormula_EXPRESSION_TYPE_NUMERIC_MATRIX;
+				result -> result.numericMatrixResult = theStack [1]. numericMatrix;   // dangle...
+				theStack [1]. numericMatrix = empty_nummat;   // ...undangle (and disown)
+			} else {
+				Melder_throw (U"Don't know yet how to write ", Stackel_whichText (& theStack [1]), U".");
 			}
 		}
 		/*
diff --git a/sys/Formula.h b/sys/Formula.h
index 02bf250..b61dd36 100644
--- a/sys/Formula.h
+++ b/sys/Formula.h
@@ -68,7 +68,7 @@ Thing_declare (Interpreter);
 
 void Formula_compile (Interpreter interpreter, Daata data, const char32 *expression, int expressionType, bool optimize);
 
-void Formula_run (long row, long col, struct Formula_Result *result);
+void Formula_run (long row, long col, Formula_Result *result);
 
 /* End of file Formula.h */
 #endif
diff --git a/sys/Graphics.h b/sys/Graphics.h
index dc870bf..eec6fb4 100644
--- a/sys/Graphics.h
+++ b/sys/Graphics.h
@@ -134,7 +134,7 @@ Thing_define (Graphics, Thing) {
 	virtual void v_fillRoundedRectangle (double x1DC, double x2DC, double y1DC, double y2DC, double r);
 	virtual void v_arrowHead (double xDC, double yDC, double angle);
 	virtual bool v_mouseStillDown () { return false; }
-	virtual void v_getMouseLocation (double *xWC, double *yWC) { *xWC = *yWC = NUMundefined; }
+	virtual void v_getMouseLocation (double *xWC, double *yWC) { *xWC = *yWC = undefined; }
 	virtual void v_flushWs () { }
 	virtual void v_clearWs () { }
 	virtual void v_updateWs () { }
diff --git a/sys/GraphicsScreen.cpp b/sys/GraphicsScreen.cpp
index a48c01b..fb6c233 100644
--- a/sys/GraphicsScreen.cpp
+++ b/sys/GraphicsScreen.cpp
@@ -675,22 +675,22 @@ autoGraphics Graphics_create_pdffile (MelderFile file, int resolution,
 	Graphics_init (me.get(), resolution);
 	#if cairo
 		my d_cairoSurface = cairo_pdf_surface_create (Melder_peek32to8 (file -> path),
-			(NUMdefined (x1inches) ? x2inches - x1inches : x2inches) * 72.0,
-			(NUMdefined (y1inches) ? y2inches - y1inches : y2inches) * 72.0);
+			( isdefined (x1inches) ? x2inches - x1inches : x2inches ) * 72.0,
+			( isdefined (y1inches) ? y2inches - y1inches : y2inches ) * 72.0);
 		my d_cairoGraphicsContext = cairo_create (my d_cairoSurface);
 		my d_x1DC = my d_x1DCmin = 0;
-		my d_x2DC = my d_x2DCmax = (NUMdefined (x1inches) ?  7.5 : x2inches) * resolution;
+		my d_x2DC = my d_x2DCmax = ( isdefined (x1inches) ?  7.5 : x2inches ) * resolution;
 		my d_y1DC = my d_y1DCmin = 0;
-		my d_y2DC = my d_y2DCmax = (NUMdefined (y1inches) ? 11.0 : y2inches) * resolution;
+		my d_y2DC = my d_y2DCmax = ( isdefined (y1inches) ? 11.0 : y2inches ) * resolution;
 		Graphics_setWsWindow (me.get(),
-			NUMdefined (x1inches) ? 0.0 : 0.0, NUMdefined (x1inches) ?  7.5 : x2inches,
-			NUMdefined (y1inches) ? 1.0 : 0.0, NUMdefined (y1inches) ? 12.0 : y2inches);
+			isdefined (x1inches) ? 0.0 : 0.0, isdefined (x1inches) ?  7.5 : x2inches,
+			isdefined (y1inches) ? 1.0 : 0.0, isdefined (y1inches) ? 12.0 : y2inches);
 		cairo_scale (my d_cairoGraphicsContext, 72.0 / resolution, 72.0 / resolution);
 	#elif quartz
 		CFURLRef url = CFURLCreateWithFileSystemPath (nullptr, (CFStringRef) Melder_peek32toCfstring (file -> path), kCFURLPOSIXPathStyle, false);
 		CGRect rect = CGRectMake (0, 0,
-			(NUMdefined (x1inches) ? x2inches - x1inches : x2inches) * 72.0,
-			(NUMdefined (y1inches) ? y2inches - y1inches : y2inches) * 72.0);   // don't tire PDF viewers with funny origins
+			( isdefined (x1inches) ? x2inches - x1inches : x2inches ) * 72.0,
+			( isdefined (y1inches) ? y2inches - y1inches : y2inches ) * 72.0);   // don't tire PDF viewers with funny origins
 		CFStringRef key = (CFStringRef) Melder_peek32toCfstring (U"Creator");
 		CFStringRef value = (CFStringRef) Melder_peek32toCfstring (U"Praat");
 		CFIndex numberOfValues = 1;
@@ -702,17 +702,17 @@ autoGraphics Graphics_create_pdffile (MelderFile file, int resolution,
     	if (! my d_macGraphicsContext)
 			Melder_throw (U"Could not create PDF file ", file, U".");
 		my d_x1DC = my d_x1DCmin = 0;
-		my d_x2DC = my d_x2DCmax = (NUMdefined (x1inches) ?  7.5 : x2inches) * resolution;
+		my d_x2DC = my d_x2DCmax = ( isdefined (x1inches) ?  7.5 : x2inches ) * resolution;
 		my d_y1DC = my d_y1DCmin = 0;
-		my d_y2DC = my d_y2DCmax = (NUMdefined (y1inches) ? 11.0 : y2inches) * resolution;
+		my d_y2DC = my d_y2DCmax = ( isdefined (y1inches) ? 11.0 : y2inches ) * resolution;
 		Graphics_setWsWindow (me.get(),
-			NUMdefined (x1inches) ? 0.0 : 0.0, NUMdefined (x1inches) ?  7.5 : x2inches,
-			NUMdefined (y1inches) ? 1.0 : 0.0, NUMdefined (y1inches) ? 12.0 : y2inches);
+			( isdefined (x1inches) ? 0.0 : 0.0 ), ( isdefined (x1inches) ?  7.5 : x2inches ),
+			( isdefined (y1inches) ? 1.0 : 0.0 ), ( isdefined (y1inches) ? 12.0 : y2inches ));
 		CGContextBeginPage (my d_macGraphicsContext, & rect);
 		CGContextScaleCTM (my d_macGraphicsContext, 72.0 / resolution, 72.0 / resolution);
 		CGContextTranslateCTM (my d_macGraphicsContext,
-			(NUMdefined (x1inches) ? - x1inches : 0.0) * resolution,
-			(NUMdefined (y1inches) ? (12.0 - y1inches) : y2inches) * resolution);
+			( isdefined (x1inches) ? - x1inches : 0.0 ) * resolution,
+			( isdefined (y1inches) ? (12.0 - y1inches) : y2inches ) * resolution);
 		CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
 	#endif
 	return me.move();
diff --git a/sys/Graphics_colour.cpp b/sys/Graphics_colour.cpp
index 275dc4c..79b50f7 100644
--- a/sys/Graphics_colour.cpp
+++ b/sys/Graphics_colour.cpp
@@ -40,7 +40,7 @@ Graphics_Colour
 	Graphics_WINDOW_BACKGROUND_COLOUR = { 0.90, 0.90, 0.85 };
 
 inline static const char32 * rgbColourName (Graphics_Colour colour) {
-	static MelderString buffer;
+	static MelderString buffer { };
 	MelderString_copy (& buffer,
 		U"{", Melder_fixed (colour. red, 6),
 		U",", Melder_fixed (colour. green, 6),
diff --git a/sys/Graphics_grey.cpp b/sys/Graphics_grey.cpp
index 77d54c6..7b26af6 100644
--- a/sys/Graphics_grey.cpp
+++ b/sys/Graphics_grey.cpp
@@ -1,6 +1,6 @@
 /* Graphics_grey.cpp
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -129,14 +129,13 @@ static void fillGrey (int numberOfPoints, double *x, double *y, int igrey)
 }
 
 static void makeEdgeContour (int row0, int col0, int ori0) {
-	int row, col, ori, clockwise = 0, edge = 0, up = 0, iPoint;
-	EdgeContour e;
-
 	numberOfPoints = 0;
-	row = row0; col = col0; ori = ori0;
+	int row = row0, col = col0, ori = ori0;
 	note (row0, col0, ori0);
+
+	bool edge = false;
 	do {
-		clockwise = ! (ori & 1);
+		bool clockwise = ! (ori & 1);
 		do {   /* Preference for contours perpendicular to x == y. */
 			ori = (clockwise ? ori : ori + 2) % 4 + 1;
 		} while (! empty (row, col, ori));
@@ -157,15 +156,18 @@ static void makeEdgeContour (int row0, int col0, int ori0) {
 		}
 		note (row, col, ori);
 	}
-	while (edge == 0);
+	while (! edge);
 	Melder_assert (numberOfEdgeContours < MAXGREYEDGECONTOURS * numberOfBorders);
-	e = edgeContours [++ numberOfEdgeContours] = EdgeContour_create (numberOfPoints);
+
+	EdgeContour e = edgeContours [++ numberOfEdgeContours] = EdgeContour_create (numberOfPoints);
 	e -> beginRow = row0;
 	e -> beginCol = col0;
 	e -> beginOri = ori0;
 	e -> endRow = row;
 	e -> endCol = col;
 	e -> endOri = ori;
+
+	bool up = false;
 	switch (ori0) {
 		case 1: up = data [row0] [col0 + 1] > data [row0] [col0]; break;
 		case 2: up = data [row0 + 1] [col0 + 1] > data [row0] [col0 + 1]; break;
@@ -174,21 +176,20 @@ static void makeEdgeContour (int row0, int col0, int ori0) {
 	}
 	if (up) { e -> lowerGrey = iBorder; e -> upperGrey = iBorder + 1; }
 	else { e -> lowerGrey = iBorder + 1; e -> upperGrey = iBorder; }
-	for (iPoint = 1; iPoint <= numberOfPoints; iPoint ++) {
+	for (integer iPoint = 1; iPoint <= numberOfPoints; iPoint ++) {
 		e -> x [iPoint] = x [iPoint];
 		e -> y [iPoint] = y [iPoint];
 	}
 }
 
 static void makeClosedContour (int row0, int col0, int ori0) {
-	int row, col, ori, clockwise = 0, up = 0;
 	double x1, y1;
 	ClosedContour c;
 
 	numberOfPoints = 0;
-	row = row0; col = col0; ori = ori0;
+	int row = row0, col = col0, ori = ori0;
 	do {
-		clockwise = ! (ori & 1);
+		bool clockwise = ! (ori & 1);
 		do {   /* Preference for contours perpendicular to x == y. */
 			ori = (clockwise ? ori : ori + 2) % 4 + 1;
 		} while (! empty (row, col, ori));
@@ -210,6 +211,7 @@ static void makeClosedContour (int row0, int col0, int ori0) {
 
 	x1 = x [numberOfPoints];
 	y1 = y [numberOfPoints];
+	bool up = false;
 	if (ori == 3) { row ++; ori = 1; }
 	else if (ori == 2) { col ++; ori = 4; }
 	if (ori == 1) {
@@ -232,55 +234,51 @@ static void makeClosedContour (int row0, int col0, int ori0) {
 
 	if (! NUMrotationsPointInPolygon (x1, y1, numberOfPoints, x, y)) up = ! up;
 
-	{
-		int i;
-		double xmin = 1e308, xmax = -1e308, ymin = 1e308, ymax = -1e308;
-		c -> grey = up ? iBorder + 1 : iBorder;
-		for (i = 1; i <= numberOfPoints; i ++) {
-			c -> x [i] = x [i];
-			c -> y [i] = y [i];
-			if (x [i] < xmin) xmin = x [i];
-			if (x [i] > xmax) xmax = x [i];
-			if (y [i] < ymin) ymin = y [i];
-			if (y [i] > ymax) ymax = y [i];
-		}
-		c -> xmin = xmin;
-		c -> xmax = xmax;
-		c -> ymin = ymin;
-		c -> ymax = ymax;
+	double xmin = 1e308, xmax = -1e308, ymin = 1e308, ymax = -1e308;
+	c -> grey = up ? iBorder + 1 : iBorder;
+	for (int i = 1; i <= numberOfPoints; i ++) {
+		c -> x [i] = x [i];
+		c -> y [i] = y [i];
+		if (x [i] < xmin) xmin = x [i];
+		if (x [i] > xmax) xmax = x [i];
+		if (y [i] < ymin) ymin = y [i];
+		if (y [i] > ymax) ymax = y [i];
 	}
+	c -> xmin = xmin;
+	c -> xmax = xmax;
+	c -> ymin = ymin;
+	c -> ymax = ymax;
 }
 
 static void smallGrey () {
-	int row, col, i;
 	numberOfEdgeContours = 0;
 	numberOfClosedContours = 0;
 	for (iBorder = 1; iBorder <= numberOfBorders; iBorder ++) {
-		for (row = 0; row < MAXGREYSIDE; row ++) for (col = 0; col < MAXGREYSIDE; col ++)
+		for (int row = 0; row < MAXGREYSIDE; row ++) for (int col = 0; col < MAXGREYSIDE; col ++)
 			right [row] [col] = below [row] [col] = 0;
 
 		/* Find all the edge contours of this border value. */
 
-		for (col = col1; col < col2; col ++)
+		for (int col = col1; col < col2; col ++)
 			if (empty (row1, col, 1))
 				makeEdgeContour (row1, col, 1);
-		for (row = row1; row < row2; row ++)
+		for (int row = row1; row < row2; row ++)
 			if (empty (row, col2 - 1, 2))
 				makeEdgeContour (row, col2 - 1, 2);
-		for (col = col2 - 1; col >= col1; col --)
+		for (int col = col2 - 1; col >= col1; col --)
 			if (empty (row2 - 1, col, 3))
 				makeEdgeContour (row2 - 1, col, 3);
-		for (row = row2 - 1; row >= row1; row --)
+		for (int row = row2 - 1; row >= row1; row --)
 			if (empty (row, col1, 4))
 				makeEdgeContour (row, col1, 4);
 
 		/* Find all the closed contours of this border value. */
 
-		for (row = row1 + 1; row < row2; row ++)
-			for (col = col1; col < col2; col ++)
+		for (int row = row1 + 1; row < row2; row ++)
+			for (int col = col1; col < col2; col ++)
 				if (empty (row, col, 1)) makeClosedContour (row, col, 1);
-		for (col = col1 + 1; col < col2; col ++)
-			for (row = row1; row < row2; row ++)
+		for (int col = col1 + 1; col < col2; col ++)
+			for (int row = row1; row < row2; row ++)
 				if (empty (row, col, 4)) makeClosedContour (row, col, 4);
 	}
 	numberOfEdgePoints = 2 * numberOfEdgeContours + 4;
@@ -290,7 +288,7 @@ static void smallGrey () {
 
 		/* The edge points include the four corner points. */
 
-	for (i = 1; i <= 4; i ++) {
+	for (int i = 1; i <= 4; i ++) {
 		EdgePoint p = & edgePoints [i];
 		p -> ori = i;
 		p -> val = 0;
@@ -302,7 +300,7 @@ static void smallGrey () {
 
 		/* The edge points include the first points of the edge contours. */
 
-	for (i = 1; i <= numberOfEdgeContours; i ++) {
+	for (int i = 1; i <= numberOfEdgeContours; i ++) {
 		EdgeContour c = edgeContours [i];
 		EdgePoint p = & edgePoints [i + i + 3];
 		switch (p -> ori = c -> beginOri) {
@@ -319,7 +317,7 @@ static void smallGrey () {
 
 		/* The edge points include the last points of the edge contours. */
 
-	for (i = 1; i <= numberOfEdgeContours; i ++) {
+	for (int i = 1; i <= numberOfEdgeContours; i ++) {
 		EdgeContour c = edgeContours [i];
 		EdgePoint p = & edgePoints [i + i + 4];
 		switch (p -> ori = c -> endOri) {
@@ -335,27 +333,24 @@ static void smallGrey () {
 	}
 
 	/* Sort the list of edge points with keys Ori and Val. */
-	{
-		int i;
-		for (i = 1; i < numberOfEdgePoints; i ++) {
-			structEdgePoint p;
-			int min = i, j;
-			for (j = i + 1; j <= numberOfEdgePoints; j ++)
-				if (edgePoints [min]. ori > edgePoints [j]. ori ||
-					(edgePoints [min]. ori == edgePoints [j]. ori && edgePoints [min]. val > edgePoints [j]. val))
-					min = j;
-			p = edgePoints [i];
-			edgePoints [i] = edgePoints [min];
-			edgePoints [min] = p;
-		}
+	for (int i = 1; i < numberOfEdgePoints; i ++) {
+		structEdgePoint p;
+		int min = i, j;
+		for (j = i + 1; j <= numberOfEdgePoints; j ++)
+			if (edgePoints [min]. ori > edgePoints [j]. ori ||
+				(edgePoints [min]. ori == edgePoints [j]. ori && edgePoints [min]. val > edgePoints [j]. val))
+				min = j;
+		p = edgePoints [i];
+		edgePoints [i] = edgePoints [min];
+		edgePoints [min] = p;
 	}
 
 	{
-		int edge0, edge1, darkness;
-		for (edge0 = 1; edge0 <= numberOfEdgePoints; edge0 ++)
+		for (int edge0 = 1; edge0 <= numberOfEdgePoints; edge0 ++)
 		if (edgePoints [edge0].grey > -1 && ! edgePoints [edge0].usedAsEntry) {
 			int iPoint = 0;
-			edge1 = edge0;
+			int edge1 = edge0;
+			int darkness;
 			do {
 				/* Follow one edge contour.
 				 */
@@ -366,22 +361,22 @@ static void smallGrey () {
 				darkness = p -> grey;
 				p -> usedAsEntry = 1;
 				if (p -> start) {
-					for (i = 1; i <= c -> numberOfPoints; i ++) {
+					for (int i = 1; i <= c -> numberOfPoints; i ++) {
 						Melder_assert (iPoint < MAXGREYPATH);
 						x [++ iPoint] = c -> x [i];
 						y [iPoint] = c -> y [i];
 					}
-					for (i = edge1 + 1; i <= numberOfEdgePoints; i ++)
+					for (int i = edge1 + 1; i <= numberOfEdgePoints; i ++)
 						if (edgePoints [i].iContour == iContour)
 							edge1 = i;
 				} else {
 					int edge1dummy = edge1;
-					for (i = c -> numberOfPoints; i >= 1; i --) {
+					for (int i = c -> numberOfPoints; i >= 1; i --) {
 						Melder_assert (iPoint < MAXGREYPATH);
 						x [++ iPoint] = c -> x [i];
 						y [iPoint] = c -> y [i];
 					}
-					for (i = 1; i <= edge1dummy - 1; i ++)
+					for (int i = 1; i <= edge1dummy - 1; i ++)
 						if (edgePoints [i].iContour == iContour)
 							edge1 = i;
 				}
@@ -419,14 +414,13 @@ static void smallGrey () {
 	 * Those that are not enclosed by any other contour, are filled first.
 	 */
 	{
-		int enclosed, found;
+		bool found = false;
 		do {
-			found = 0;
-			for (i = 1; i <= numberOfClosedContours; i ++) {
+			for (int i = 1; i <= numberOfClosedContours; i ++) {
 				ClosedContour ci = closedContours [i];
 				if (! ci -> drawn) {
+					bool enclosed = false;
 					int j = 1;
-					enclosed = 0;
 					while (j <= numberOfClosedContours && ! enclosed) {
 						ClosedContour cj = closedContours [j];
 						if ((! cj -> drawn) && j != i &&
@@ -436,8 +430,8 @@ static void smallGrey () {
 										cj -> numberOfPoints, cj -> x, cj -> y);
 						j ++;
 					}
-					if (enclosed == 0) {
-						found = 1;
+					if (! enclosed) {
+						found = true;
 						fillGrey (ci -> numberOfPoints, ci -> x, ci -> y, ci -> grey);
 						ci -> drawn = 1;
 					}
@@ -446,9 +440,9 @@ static void smallGrey () {
 		} while (found);
 	}
 	Graphics_setGrey (theGraphics, 0.0);
-	for (i = 1; i <= numberOfEdgeContours; i ++)
+	for (int i = 1; i <= numberOfEdgeContours; i ++)
 		EdgeContour_delete (edgeContours [i]);
-	for (i = 1; i <= numberOfClosedContours; i ++)
+	for (int i = 1; i <= numberOfClosedContours; i ++)
 		ClosedContour_delete (closedContours [i]);
 }
 
diff --git a/sys/Graphics_image.cpp b/sys/Graphics_image.cpp
index 0b19e32..abf26de 100644
--- a/sys/Graphics_image.cpp
+++ b/sys/Graphics_image.cpp
@@ -700,7 +700,7 @@ static void _GraphicsScreen_imageFromFile (GraphicsScreen me, const char32 *rela
 	long x1DC = wdx (x1), x2DC = wdx (x2), y1DC = wdy (y1), y2DC = wdy (y2);
 	long width = x2DC - x1DC, height = my yIsZeroAtTheTop ? y1DC - y2DC : y2DC - y1DC;
 	#if 0
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (relativeFileName, & file);
 		try {
 			autoPhoto photo = Photo_readFromImageFile (& file);
@@ -734,7 +734,7 @@ static void _GraphicsScreen_imageFromFile (GraphicsScreen me, const char32 *rela
 		}
 	#elif gdi
 		if (my d_useGdiplus) {
-			structMelderFile file = { 0 };
+			structMelderFile file { };
 			Melder_relativePathToFile (relativeFileName, & file);
 			Gdiplus::Bitmap image (Melder_peek32toW (file. path));
 			if (x1 == x2 && y1 == y2) {
@@ -753,7 +753,7 @@ static void _GraphicsScreen_imageFromFile (GraphicsScreen me, const char32 *rela
 		} else {
 		}
 	#elif quartz
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		Melder_relativePathToFile (relativeFileName, & file);
 		char utf8 [500];
 		Melder_str32To8bitFileRepresentation_inline (file. path, utf8);
diff --git a/sys/Graphics_record.cpp b/sys/Graphics_record.cpp
index dcc6695..04b52aa 100644
--- a/sys/Graphics_record.cpp
+++ b/sys/Graphics_record.cpp
@@ -1,6 +1,6 @@
 /* Graphics_record.cpp
  *
- * Copyright (C) 1992-2011,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -384,47 +384,43 @@ void Graphics_play (Graphics me, Graphics thee) {
 	my recording = wasRecording;
 }
 
-/* For debugging:
-#define binputi4(o,f) ascputi4(o,f,"")
-#define binputr4(o,f) ascputr4(o,f,"")
-*/
 void Graphics_writeRecordings (Graphics me, FILE *f) {
 	double *p = my record, *endp = p + my irecord;
 	if (! p) return;
-	binputi4 (my irecord, f);
+	binputi32 (my irecord, f);
 	while (p < endp) {
 		#define get  (* ++ p)
 		int opcode = (int) get;
-		binputr4 ((float) opcode, f);
+		binputr32 ((float) opcode, f);
 		long numberOfArguments = (long) get;
 		const long largestIntegerRepresentableAs32BitFloat = 0x00FFFFFF;
 		if (numberOfArguments > largestIntegerRepresentableAs32BitFloat) {
-			binputr4 (-1.0, f);
-			binputi4 (numberOfArguments, f);
+			binputr32 (-1.0, f);
+			binputi32 (numberOfArguments, f);
 			//Melder_warning ("This picture is very large!");
 		} else {
-			binputr4 ((float) numberOfArguments, f);
+			binputr32 ((float) numberOfArguments, f);
 		}
 		if (opcode == TEXT) {
-			binputr4 (get, f);   // x
-			binputr4 (get, f);   // y
-			binputr4 (get, f);   // length
+			binputr32 (get, f);   // x
+			binputr32 (get, f);   // y
+			binputr32 (get, f);   // length
 			Melder_assert (sizeof (double) == 8);
 			if ((long) fwrite (++ p, 8, numberOfArguments - 3, f) < numberOfArguments - 3)   // text
 				Melder_throw (U"Error writing graphics recordings.");
 			p += numberOfArguments - 4;
 		} else if (opcode == IMAGE_FROM_FILE) {
-			binputr4 (get, f);   // x1
-			binputr4 (get, f);   // x2
-			binputr4 (get, f);   // y1
-			binputr4 (get, f);   // y2
-			binputr4 (get, f);   // length
+			binputr32 (get, f);   // x1
+			binputr32 (get, f);   // x2
+			binputr32 (get, f);   // y1
+			binputr32 (get, f);   // y2
+			binputr32 (get, f);   // length
 			Melder_assert (sizeof (double) == 8);
 			if ((long) fwrite (++ p, 8, numberOfArguments - 5, f) < numberOfArguments - 5)   // text
 				Melder_throw (U"Error writing graphics recordings.");
 			p += numberOfArguments - 6;
 		} else {
-			for (long i = numberOfArguments; i > 0; i --) binputr4 (get, f);
+			for (long i = numberOfArguments; i > 0; i --) binputr32 (get, f);
 		}
 	}
 }
@@ -437,37 +433,37 @@ void Graphics_readRecordings (Graphics me, FILE *f) {
 	signed long numberOfArguments = 0;
 	int opcode = 0;
 	try {
-		added_irecord = bingeti4 (f);
+		added_irecord = bingeti32 (f);
 		p = _Graphics_check (me, added_irecord - RECORDING_HEADER_LENGTH);
 		if (! p) return;
 		Melder_assert (my irecord == old_irecord + added_irecord);
 		endp = p + added_irecord;
 		while (p < endp) {
-			opcode = (int) bingetr4 (f);
+			opcode = (int) bingetr32 (f);
 			put (opcode);
-			numberOfArguments = (signed long) bingetr4 (f);
+			numberOfArguments = (signed long) bingetr32 (f);
 			if (numberOfArguments == -1) {
-				numberOfArguments = bingeti4 (f);
+				numberOfArguments = bingeti32 (f);
 			}
 			put (numberOfArguments);
 			if (opcode == TEXT) {
-				put (bingetr4 (f));   // x
-				put (bingetr4 (f));   // y
-				put (bingetr4 (f));   // length
+				put (bingetr32 (f));   // x
+				put (bingetr32 (f));   // y
+				put (bingetr32 (f));   // length
 				if (fread (++ p, 8, (size_t) numberOfArguments - 3, f) < (size_t) numberOfArguments - 3)   // text
 					Melder_throw (U"Error reading graphics recordings.");
 				p += numberOfArguments - 4;
 			} else if (opcode == IMAGE_FROM_FILE) {
-				put (bingetr4 (f));   // x1
-				put (bingetr4 (f));   // x2
-				put (bingetr4 (f));   // y1
-				put (bingetr4 (f));   // y2
-				put (bingetr4 (f));   // length
+				put (bingetr32 (f));   // x1
+				put (bingetr32 (f));   // x2
+				put (bingetr32 (f));   // y1
+				put (bingetr32 (f));   // y2
+				put (bingetr32 (f));   // length
 				if (fread (++ p, 8, (size_t) numberOfArguments - 5, f) < (size_t) numberOfArguments - 5)   // text
 					Melder_throw (U"Error reading graphics recordings.");
 				p += numberOfArguments - 6;
 			} else {
-				for (long i = numberOfArguments; i > 0; i --) put (bingetr4 (f));
+				for (long i = numberOfArguments; i > 0; i --) put (bingetr32 (f));
 			}
 		}   
 	} catch (MelderError) {
diff --git a/sys/Graphics_text.cpp b/sys/Graphics_text.cpp
index e54f302..d3d759c 100644
--- a/sys/Graphics_text.cpp
+++ b/sys/Graphics_text.cpp
@@ -1538,7 +1538,7 @@ static void _Graphics_text (Graphics me, double xWC, double yWC, const char32 *t
 	}
 }
 
-static MelderString theGraphicsTextBuffer { 0 };
+static MelderString theGraphicsTextBuffer { };
 void Graphics_text (Graphics me, double x, double y, Melder_1_ARG) {
 	MelderString_copy (& theGraphicsTextBuffer, Melder_1_ARG_CALL);   // even in the one-argument case, make a copy because s1 may be a temporary string (Melder_integer or so)
 	_Graphics_text (me, x, y, theGraphicsTextBuffer.string);
diff --git a/sys/GuiFileSelect.cpp b/sys/GuiFileSelect.cpp
index 1eba6f2..051c543 100644
--- a/sys/GuiFileSelect.cpp
+++ b/sys/GuiFileSelect.cpp
@@ -23,12 +23,12 @@
 #endif
 
 autoStringSet GuiFileSelect_getInfileNames (GuiWindow parent, const char32 *title, bool allowMultipleFiles) {
-	structMelderDir saveDir { { 0 } };
+	structMelderDir saveDir { };
 	Melder_getDefaultDir (& saveDir);
 	autoStringSet me = StringSet_create ();
 	#if gtk
 		(void) parent;
-		static structMelderDir dir;
+		static structMelderDir dir { };
 		GuiObject dialog = gtk_file_chooser_dialog_new (Melder_peek32to8 (title), nullptr, GTK_FILE_CHOOSER_ACTION_OPEN,
 			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, nullptr);
 		gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), allowMultipleFiles);
@@ -93,10 +93,10 @@ autoStringSet GuiFileSelect_getInfileNames (GuiWindow parent, const char32 *titl
 				 * The user selected multiple files.
 				 * 'fullFileNameW' is a directory name; the file names follow.
 				 */
-				structMelderDir dir;
+				structMelderDir dir { };
 				Melder_pathToDir (Melder_peekWto32 (fullFileNameW), & dir);
 				for (const WCHAR *p = & fullFileNameW [firstFileNameLength + 1]; *p != L'\0'; p += wcslen (p) + 1) {
-					structMelderFile file { 0 };
+					structMelderFile file { };
 					MelderDir_getFile (& dir, Melder_peekWto32 (p), & file);
 					my addString_copy (Melder_fileToPath (& file));
 				}
@@ -111,7 +111,7 @@ autoStringSet GuiFileSelect_getInfileNames (GuiWindow parent, const char32 *titl
 		[openPanel setCanChooseDirectories: NO];
 		if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
 			for (NSURL *url in [openPanel URLs]) {
-				structMelderFile file { 0 };
+				structMelderFile file { };
 				Melder_8bitFileRepresentationToStr32_inline ([[url path] UTF8String], file. path);   // BUG: unsafe buffer
 				my addString_copy (file. path);
 			}
@@ -123,7 +123,7 @@ autoStringSet GuiFileSelect_getInfileNames (GuiWindow parent, const char32 *titl
 }
 
 char32 * GuiFileSelect_getOutfileName (GuiWindow parent, const char32 *title, const char32 *defaultName) {
-	structMelderDir saveDir { { 0 } };
+	structMelderDir saveDir { };
 	Melder_getDefaultDir (& saveDir);
 	char32 *outfileName = nullptr;
 	#if gtk
@@ -178,7 +178,7 @@ char32 * GuiFileSelect_getOutfileName (GuiWindow parent, const char32 *title, co
 			const char *outfileName_utf8 = [path UTF8String];
 			if (outfileName_utf8 == nullptr)
 				Melder_throw (U"Don't understand where you want to save (2).");
-			structMelderFile file { 0 };
+			structMelderFile file { };
 			Melder_8bitFileRepresentationToStr32_inline (outfileName_utf8, file. path);   // BUG: unsafe buffer
 			outfileName = Melder_dup (file. path);
 		}
@@ -189,7 +189,7 @@ char32 * GuiFileSelect_getOutfileName (GuiWindow parent, const char32 *title, co
 }
 
 char32 * GuiFileSelect_getDirectoryName (GuiWindow parent, const char32 *title) {
-	structMelderDir saveDir { { 0 } };
+	structMelderDir saveDir { };
 	Melder_getDefaultDir (& saveDir);
 	char32 *directoryName = nullptr;
 	#if gtk
@@ -237,7 +237,7 @@ char32 * GuiFileSelect_getDirectoryName (GuiWindow parent, const char32 *title)
 		if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
 			for (NSURL *url in [openPanel URLs]) {
 				const char *directoryName_utf8 = [[url path] UTF8String];
-				structMelderDir dir { { 0 } };
+				structMelderDir dir { };
 				Melder_8bitFileRepresentationToStr32_inline (directoryName_utf8, dir. path);   // BUG: unsafe buffer
 				directoryName = Melder_dup (dir. path);
 			}
diff --git a/sys/GuiList.cpp b/sys/GuiList.cpp
index 824a49c..7d6fce6 100644
--- a/sys/GuiList.cpp
+++ b/sys/GuiList.cpp
@@ -17,7 +17,6 @@
  */
 
 #include "GuiP.h"
-#include "NUM.h"
 
 Thing_implement (GuiList, GuiControl, 0);
 
diff --git a/sys/GuiMenu.cpp b/sys/GuiMenu.cpp
index 936b681..db1f6ea 100644
--- a/sys/GuiMenu.cpp
+++ b/sys/GuiMenu.cpp
@@ -189,7 +189,7 @@ void structGuiMenu :: v_destroy () noexcept {
 		if (praatP.userWantsToOpen) return;
 		for (NSUInteger i = 1; i <= [fileNames count]; i ++) {
 			NSString *cocoaFileName = [fileNames objectAtIndex: i - 1];
-			structMelderFile file = { 0 };
+			structMelderFile file { };
 			Melder_8bitFileRepresentationToStr32_inline ([cocoaFileName UTF8String], file. path);
 			if (theOpenDocumentCallback)
 				theOpenDocumentCallback (& file);
diff --git a/sys/GuiMenuItem.cpp b/sys/GuiMenuItem.cpp
index 35caae2..e771835 100644
--- a/sys/GuiMenuItem.cpp
+++ b/sys/GuiMenuItem.cpp
@@ -1,6 +1,6 @@
 /* GuiMenuItem.cpp
  *
- * Copyright (C) 1992-2012,2013,2015,2016 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2012,2013,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,7 +38,7 @@ Thing_implement (GuiMenuItem, GuiThing, 0);
 #if motif
 	static void NativeMenuItem_setText (GuiObject me) {
 		int acc = my motiff.pushButton.acceleratorChar, modifiers = my motiff.pushButton.acceleratorModifiers;
-		static MelderString title { 0 };
+		static MelderString title { };
 		if (acc == 0) {
 			MelderString_copy (& title, _GuiWin_expandAmpersands (my name));
 		} else {
diff --git a/sys/GuiP.h b/sys/GuiP.h
index 2f3ccd5..bb88dca 100644
--- a/sys/GuiP.h
+++ b/sys/GuiP.h
@@ -114,8 +114,6 @@ class GuiControlBlockValueChangedCallbacks {
 		void *userData;
 	};
 
-	#define my  me ->
-
 	extern struct Gui {
 		GuiObject textFocus;
 		bool duringUpdate;
diff --git a/sys/GuiScrollBar.cpp b/sys/GuiScrollBar.cpp
index e2bf50d..adaebbf 100644
--- a/sys/GuiScrollBar.cpp
+++ b/sys/GuiScrollBar.cpp
@@ -82,8 +82,8 @@ Thing_implement (GuiScrollBar, GuiControl, 0);
 		Melder_assert (userData == nullptr || Thing_isa (userData, classGuiScrollBar));
 		d_userData = static_cast <GuiScrollBar> (userData);
 	}
-	- (void) setMinimum:(double)minimum maximum:(double)maximum value:(double)value sliderSize:(double)sliderSize increment:(double)increment pageIncrement:(double)pageIncrement {
-		Melder_assert (NUMdefined (minimum));
+	- (void) setMinimum: (double)minimum maximum:(double)maximum value:(double)value sliderSize:(double)sliderSize increment:(double)increment pageIncrement:(double)pageIncrement {
+		Melder_assert (isdefined (minimum));
 		_m_minimum = minimum;
 		_m_maximum = maximum;
 		_m_value = value;
@@ -273,27 +273,27 @@ void GuiScrollBar_set (GuiScrollBar me, double minimum, double maximum, double v
 		my d_blockValueChangedCallbacks = true;
 		GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (my d_widget));
 		gtk_adjustment_configure (GTK_ADJUSTMENT (adj),
-			NUMdefined (value)         ? value         : gtk_adjustment_get_value          (GTK_ADJUSTMENT (adj)),
-			NUMdefined (minimum)       ? minimum       : gtk_adjustment_get_lower          (GTK_ADJUSTMENT (adj)),
-			NUMdefined (maximum)       ? maximum       : gtk_adjustment_get_upper          (GTK_ADJUSTMENT (adj)),
-			NUMdefined (increment)     ? increment     : gtk_adjustment_get_step_increment (GTK_ADJUSTMENT (adj)),
-			NUMdefined (pageIncrement) ? pageIncrement : gtk_adjustment_get_page_increment (GTK_ADJUSTMENT (adj)),
-			NUMdefined (sliderSize)    ? sliderSize    : gtk_adjustment_get_page_size      (GTK_ADJUSTMENT (adj)));
+			isdefined (value)         ? value         : gtk_adjustment_get_value          (GTK_ADJUSTMENT (adj)),
+			isdefined (minimum)       ? minimum       : gtk_adjustment_get_lower          (GTK_ADJUSTMENT (adj)),
+			isdefined (maximum)       ? maximum       : gtk_adjustment_get_upper          (GTK_ADJUSTMENT (adj)),
+			isdefined (increment)     ? increment     : gtk_adjustment_get_step_increment (GTK_ADJUSTMENT (adj)),
+			isdefined (pageIncrement) ? pageIncrement : gtk_adjustment_get_page_increment (GTK_ADJUSTMENT (adj)),
+			isdefined (sliderSize)    ? sliderSize    : gtk_adjustment_get_page_size      (GTK_ADJUSTMENT (adj)));
 		/*
 		 * We don't set d_blockValueChangedCallbacks back to false yet, because GTK calls the valueChangedCallback with a delay.
 		 */
 	#elif motif
-		if (NUMdefined (minimum))
+		if (isdefined (minimum))
 			XtVaSetValues (my d_widget, XmNminimum, (int) minimum, nullptr);
-		if (NUMdefined (maximum))
+		if (isdefined (maximum))
 			XtVaSetValues (my d_widget, XmNmaximum, (int) maximum, nullptr);
 		int oldValue, oldSliderSize, oldIncrement, oldPageIncrement;
 		XmScrollBarGetValues (my d_widget, & oldValue, & oldSliderSize, & oldIncrement, & oldPageIncrement);
 		XmScrollBarSetValues (my d_widget,
-			NUMdefined (value)         ? value         : oldValue,
-			NUMdefined (sliderSize)    ? sliderSize    : oldSliderSize,
-			NUMdefined (increment)     ? increment     : oldIncrement,
-			NUMdefined (pageIncrement) ? pageIncrement : oldPageIncrement,
+			isdefined (value)         ? value         : oldValue,
+			isdefined (sliderSize)    ? sliderSize    : oldSliderSize,
+			isdefined (increment)     ? increment     : oldIncrement,
+			isdefined (pageIncrement) ? pageIncrement : oldPageIncrement,
 			False);
 	#elif cocoa
 		/*
@@ -304,12 +304,12 @@ void GuiScrollBar_set (GuiScrollBar me, double minimum, double maximum, double v
 		GuiControlBlockValueChangedCallbacks block (me);
 		GuiCocoaScrollBar *scroller = (GuiCocoaScrollBar *) my d_widget;
 		[scroller
-			setMinimum:    NUMdefined (minimum)       ? minimum       : [scroller m_minimum]
-			maximum:       NUMdefined (maximum)       ? maximum       : [scroller m_maximum]
-			value:         NUMdefined (value)         ? value         : [scroller m_value]
-			sliderSize:    NUMdefined (sliderSize)    ? sliderSize    : [scroller m_sliderSize]
-			increment:     NUMdefined (increment)     ? increment     : [scroller m_increment]
-			pageIncrement: NUMdefined (pageIncrement) ? pageIncrement : [scroller m_pageIncrement]];
+			setMinimum:    isdefined (minimum)       ? minimum       : [scroller m_minimum]
+			maximum:       isdefined (maximum)       ? maximum       : [scroller m_maximum]
+			value:         isdefined (value)         ? value         : [scroller m_value]
+			sliderSize:    isdefined (sliderSize)    ? sliderSize    : [scroller m_sliderSize]
+			increment:     isdefined (increment)     ? increment     : [scroller m_increment]
+			pageIncrement: isdefined (pageIncrement) ? pageIncrement : [scroller m_pageIncrement]];
 	#endif
 	trace (U"exit");
 }
diff --git a/sys/HyperPage.cpp b/sys/HyperPage.cpp
index 432a89c..8f865c7 100644
--- a/sys/HyperPage.cpp
+++ b/sys/HyperPage.cpp
@@ -772,7 +772,7 @@ static void updateVerticalScrollBar (HyperPage me)
 /* This has to be called after changing 'my topParagraph'. */
 {
 	int sliderSize = 25;
-	GuiScrollBar_set (my verticalScrollBar, NUMundefined, NUMundefined, my top, sliderSize, 1, sliderSize - 1);
+	GuiScrollBar_set (my verticalScrollBar, undefined, undefined, my top, sliderSize, 1, sliderSize - 1);
 	my history [my historyPointer]. top = 0/*my top*/;
 }
 
diff --git a/sys/Interpreter.cpp b/sys/Interpreter.cpp
index 153b8a5..b09876b 100644
--- a/sys/Interpreter.cpp
+++ b/sys/Interpreter.cpp
@@ -44,8 +44,8 @@ Thing_implement (InterpreterVariable, SimpleString, 0);
 void structInterpreterVariable :: v_destroy () noexcept {
 	Melder_free (our string);
 	Melder_free (our stringValue);
-	NUMvector_free (our numericVectorValue. data, 1);
-	NUMmatrix_free (our numericMatrixValue. data, 1, 1);
+	NUMvector_free (our numericVectorValue.at, 1);
+	NUMmatrix_free (our numericMatrixValue.at, 1, 1);
 	InterpreterVariable_Parent :: v_destroy ();
 }
 
@@ -134,7 +134,7 @@ void Melder_includeIncludeFiles (char32 **text) {
 			/*
 				Get the contents of the include file.
 			 */
-			structMelderFile includeFile = { 0 };
+			structMelderFile includeFile { };
 			Melder_relativePathToFile (includeFileName, & includeFile);
 			autostring32 includeText;
 			try {
@@ -695,8 +695,8 @@ void Interpreter_run (Interpreter me, char32 *text) {
 	long lineNumber = 0;
 	bool assertionFailed = false;
 	try {
-		static MelderString valueString { 0 };   // to divert the info
-		static MelderString assertErrorString { 0 };
+		static MelderString valueString { };   // to divert the info
+		static MelderString assertErrorString { };
 		char32 *command = text;
 		autoMelderString command2;
 		autoMelderString buffer;
@@ -793,7 +793,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 		Interpreter_addStringVariable (me, U"newline$", U"\n");
 		Interpreter_addStringVariable (me, U"tab$", U"\t");
 		Interpreter_addStringVariable (me, U"shellDirectory$", Melder_getShellDirectory ());
-		structMelderDir dir { { 0 } }; Melder_getDefaultDir (& dir);
+		structMelderDir dir { }; Melder_getDefaultDir (& dir);
 		Interpreter_addStringVariable (me, U"defaultDirectory$", Melder_dirToPath (& dir));
 		Interpreter_addStringVariable (me, U"preferencesDirectory$", Melder_dirToPath (& praatDir));
 		Melder_getHomeDir (& dir);
@@ -954,7 +954,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 									if (*q == U'(' || *q == U':') q ++;   // step over parenthesis or colon
 								}
 								while (*q && *q != U')') {
-									static MelderString argument { 0 };
+									static MelderString argument { };
 									MelderString_empty (& argument);
 									while (Melder_isblank (*p)) p ++;
 									while (Melder_isblank (*q)) q ++;
@@ -1008,6 +1008,26 @@ void Interpreter_run (Interpreter me, char32 *text) {
 										InterpreterVariable var = Interpreter_lookUpVariable (me, parameterName); *q = save;
 										Melder_free (var -> stringValue);
 										var -> stringValue = value;
+									} else if (q [-1] == U'#') {
+										if (q [-2] == U'#') {
+											nummat value;
+											my callDepth --;
+											Interpreter_numericMatrixExpression (me, argument.string, & value);
+											my callDepth ++;
+											char32 save = *q; *q = U'\0';
+											InterpreterVariable var = Interpreter_lookUpVariable (me, parameterName); *q = save;
+											var -> numericMatrixValue. reset();
+											var -> numericMatrixValue = value;
+										} else {
+											numvec value;
+											my callDepth --;
+											Interpreter_numericVectorExpression (me, argument.string, & value);
+											my callDepth ++;
+											char32 save = *q; *q = U'\0';
+											InterpreterVariable var = Interpreter_lookUpVariable (me, parameterName); *q = save;
+											var -> numericVectorValue. reset();
+											var -> numericVectorValue = value;
+										}
 									} else {
 										double value;
 										my callDepth --;
@@ -1033,7 +1053,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 						if (str32nequ (command2.string, U"assert ", 7)) {
 							double value;
 							Interpreter_numericExpression (me, command2.string + 7, & value);
-							if (value == 0.0 || value == NUMundefined) {
+							if (value == 0.0 || isundef (value)) {
 								assertionFailed = true;
 								Melder_throw (U"Script assertion fails in line ", lineNumber,
 									U" (", value == 0.0 ? U"false" : U"undefined", U"):\n   ", command2.string + 7);
@@ -1089,7 +1109,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 										++ p;   // first argument
 										while (*q && *q != ')') {
 											char32 *par, save;
-											static MelderString arg { 0 };
+											static MelderString arg { };
 											MelderString_empty (& arg);
 											while (Melder_isblank (*p)) p ++;
 											while (*q == U' ' || *q == U'\t' || *q == U',' || *q == U')') q ++;
@@ -1332,7 +1352,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 									}
 								}
 								if (iline > numberOfLines) Melder_throw (U"Unmatched 'if'.");
-							} else if (value == NUMundefined) {
+							} else if (isundef (value)) {
 								Melder_throw (U"The value of the 'if' condition is undefined.");
 							}
 						} else if (str32nequ (command2.string, U"inc ", 4)) {
@@ -1474,11 +1494,11 @@ void Interpreter_run (Interpreter me, char32 *text) {
 							 * This must be an assignment to an indexed string variable.
 							 */
 							*endOfVariable = U'\0';
-							static MelderString indexedVariableName { 0 };
+							static MelderString indexedVariableName { };
 							MelderString_copy (& indexedVariableName, command2.string, U"[");
 							for (;;) {
 								p ++;   // skip opening bracket or comma
-								static MelderString index { 0 };
+								static MelderString index { };
 								MelderString_empty (& index);
 								int depth = 0;
 								bool inString = false;
@@ -1494,7 +1514,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								}
 								if (*p == U'\n' || *p == U'\0')
 									Melder_throw (U"Missing closing bracket (]) in indexed variable.");
-								struct Formula_Result result;
+								Formula_Result result;
 								Interpreter_anyExpression (me, index.string, & result);
 								if (result.expressionType == kFormula_EXPRESSION_TYPE_NUMERIC) {
 									double numericIndexValue = result.result.numericResult;
@@ -1532,7 +1552,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								Melder_throw (U"Missing expression after variable ", variableName, U".");
 						}
 						if (withFile) {
-							structMelderFile file = { 0 };
+							structMelderFile file { };
 							Melder_relativePathToFile (p, & file);
 							if (withFile == 1) {
 								char32 *stringValue = MelderFile_readText (& file);
@@ -1582,7 +1602,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 							/*
 								Assign to a numeric matrix variable or to a matrix element.
 							*/
-							static MelderString matrixName { 0 };
+							static MelderString matrixName { };
 							p ++;   // go to second '#'
 							*p = U'\0';   // erase the last number sign temporarily
 							MelderString_copy (& matrixName, command2.string, U'#');
@@ -1600,7 +1620,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								nummat value;
 								Interpreter_numericMatrixExpression (me, p, & value);
 								InterpreterVariable var = Interpreter_lookUpVariable (me, matrixName.string);
-								NUMmatrix_free (var -> numericMatrixValue. data, 1, 1);
+								NUMmatrix_free (var -> numericMatrixValue.at, 1, 1);
 								var -> numericMatrixValue = value;
 							} else if (*p == U'[') {
 								/*
@@ -1611,7 +1631,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								/*
 									Get the row number.
 								*/
-								static MelderString rowFormula { 0 };
+								static MelderString rowFormula { };
 								MelderString_empty (& rowFormula);
 								int depth = 0;
 								bool inString = false;
@@ -1627,7 +1647,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								}
 								if (*p == U'\n' || *p == U'\0')
 									Melder_throw (U"Missing comma in matrix indexing.");
-								struct Formula_Result result;
+								Formula_Result result;
 								Interpreter_anyExpression (me, rowFormula.string, & result);
 								if (result.expressionType == kFormula_EXPRESSION_TYPE_NUMERIC) {
 									rowNumber = lround (result.result.numericResult);
@@ -1639,7 +1659,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								/*
 									Get the column number.
 								*/
-								static MelderString columnFormula { 0 };
+								static MelderString columnFormula { };
 								MelderString_empty (& columnFormula);
 								depth = 0;
 								inString = false;
@@ -1687,13 +1707,13 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								if (columnNumber > var -> numericMatrixValue. ncol)
 									Melder_throw (U"A column number cannot be greater than the number of columns (here ",
 										var -> numericMatrixValue. ncol, U"). The column number you supplied is ", columnNumber, U".");
-								var -> numericMatrixValue. data [rowNumber] [columnNumber] = value;
+								var -> numericMatrixValue.at [rowNumber] [columnNumber] = value;
 							} else Melder_throw (U"Missing '=' after matrix variable ", matrixName.string, U".");
 						} else {
 							/*
 								Assign to a numeric vector variable or to a vector element.
 							*/
-							static MelderString vectorName { 0 };
+							static MelderString vectorName { };
 							*p = U'\0';   // erase the number sign temporarily
 							MelderString_copy (& vectorName, command2.string, U"#");
 							*p = U'#';   // put the number sign back
@@ -1710,7 +1730,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								numvec value;
 								Interpreter_numericVectorExpression (me, p, & value);
 								InterpreterVariable var = Interpreter_lookUpVariable (me, vectorName.string);
-								NUMvector_free (var -> numericVectorValue. data, 1);
+								NUMvector_free (var -> numericVectorValue.at, 1);
 								var -> numericVectorValue = value;
 							} else if (*p == U'[') {
 								/*
@@ -1718,7 +1738,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								 */
 								long indexValue = 0;
 								p ++;   // step over opening bracket
-								static MelderString index { 0 };
+								static MelderString index { };
 								MelderString_empty (& index);
 								int depth = 0;
 								bool inString = false;
@@ -1734,7 +1754,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								}
 								if (*p == U'\n' || *p == U'\0')
 									Melder_throw (U"Missing closing bracket (]) in array element.");
-								struct Formula_Result result;
+								Formula_Result result;
 								Interpreter_anyExpression (me, index.string, & result);
 								if (result.expressionType == kFormula_EXPRESSION_TYPE_NUMERIC) {
 									indexValue = lround (result.result.numericResult);
@@ -1757,10 +1777,10 @@ void Interpreter_run (Interpreter me, char32 *text) {
 									Melder_throw (U"Vector ", vectorName.string, U" does not exist.");
 								if (indexValue < 1)
 									Melder_throw (U"A vector index cannot be less than 1 (the index you supplied is ", indexValue, U").");
-								if (indexValue > var -> numericVectorValue. size)
+								if (indexValue > var -> numericVectorValue.size)
 									Melder_throw (U"A vector index cannot be greater than the number of elements (here ",
-										var -> numericVectorValue. size, U"). The index you supplied is ", indexValue, U".");
-								var -> numericVectorValue. data [indexValue] = value;
+										var -> numericVectorValue.size, U"). The index you supplied is ", indexValue, U".");
+								var -> numericVectorValue.at [indexValue] = value;
 							} else Melder_throw (U"Missing '=' after vector variable ", vectorName.string, U".");
 						}
 					} else {
@@ -1790,11 +1810,11 @@ void Interpreter_run (Interpreter me, char32 *text) {
 							 * This must be an assignment to an indexed numeric variable.
 							 */
 							*endOfVariable = U'\0';
-							static MelderString indexedVariableName { 0 };
+							static MelderString indexedVariableName { };
 							MelderString_copy (& indexedVariableName, command2.string, U"[");
 							for (;;) {
 								p ++;   // skip opening bracket or comma
-								static MelderString index { 0 };
+								static MelderString index { };
 								MelderString_empty (& index);
 								int depth = 0;
 								bool inString = false;
@@ -1810,7 +1830,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								}
 								if (*p == U'\n' || *p == U'\0')
 									Melder_throw (U"Missing closing bracket (]) in indexed variable.");
-								struct Formula_Result result;
+								Formula_Result result;
 								Interpreter_anyExpression (me, index.string, & result);
 								if (result.expressionType == kFormula_EXPRESSION_TYPE_NUMERIC) {
 									double numericIndexValue = result.result.numericResult;
@@ -1855,7 +1875,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 							MelderString_appendCharacter (& valueString, 1);   // will be overwritten by something totally different if any MelderInfo function is called...
 							int status = praat_executeCommand (me, p);
 							if (status == 0) {
-								value = NUMundefined;
+								value = undefined;
 							} else if (valueString.string [0] == 1) {   // ...not overwritten by any MelderInfo function? then the return value will be the selected object
 								int IOBJECT, result = 0, found = 0;
 								WHERE (SELECTED) { result = IOBJECT; found += 1; }
@@ -1891,7 +1911,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 							 */
 							InterpreterVariable var = Interpreter_hasVariable (me, variableName);
 							if (! var) Melder_throw (U"Unknown variable ", variableName, U".");
-							if (var -> numericValue == NUMundefined) {
+							if (isundef (var -> numericValue)) {
 								/* Keep it that way. */
 							} else {
 								if (typeOfAssignment == 1) {
@@ -1901,7 +1921,7 @@ void Interpreter_run (Interpreter me, char32 *text) {
 								} else if (typeOfAssignment == 3) {
 									var -> numericValue *= value;
 								} else if (value == 0) {
-									var -> numericValue = NUMundefined;
+									var -> numericValue = undefined;
 								} else {
 									var -> numericValue /= value;
 								}
@@ -1973,7 +1993,7 @@ void Interpreter_stop (Interpreter me) {
 
 void Interpreter_voidExpression (Interpreter me, const char32 *expression) {
 	Formula_compile (me, nullptr, expression, kFormula_EXPRESSION_TYPE_NUMERIC, false);
-	struct Formula_Result result;
+	Formula_Result result;
 	Formula_run (0, 0, & result);
 }
 
@@ -1983,7 +2003,7 @@ void Interpreter_numericExpression (Interpreter me, const char32 *expression, do
 		*value = Melder_atof (expression);
 	} else {
 		Formula_compile (me, nullptr, expression, kFormula_EXPRESSION_TYPE_NUMERIC, false);
-		struct Formula_Result result;
+		Formula_Result result;
 		Formula_run (0, 0, & result);
 		*value = result. result.numericResult;
 	}
@@ -1991,26 +2011,26 @@ void Interpreter_numericExpression (Interpreter me, const char32 *expression, do
 
 void Interpreter_numericVectorExpression (Interpreter me, const char32 *expression, numvec *value) {
 	Formula_compile (me, nullptr, expression, kFormula_EXPRESSION_TYPE_NUMERIC_VECTOR, false);
-	struct Formula_Result result;
+	Formula_Result result;
 	Formula_run (0, 0, & result);
 	*value = result. result.numericVectorResult;
 }
 
 void Interpreter_numericMatrixExpression (Interpreter me, const char32 *expression, nummat *value) {
 	Formula_compile (me, nullptr, expression, kFormula_EXPRESSION_TYPE_NUMERIC_MATRIX, false);
-	struct Formula_Result result;
+	Formula_Result result;
 	Formula_run (0, 0, & result);
 	*value = result. result.numericMatrixResult;
 }
 
 void Interpreter_stringExpression (Interpreter me, const char32 *expression, char32 **value) {
 	Formula_compile (me, nullptr, expression, kFormula_EXPRESSION_TYPE_STRING, false);
-	struct Formula_Result result;
+	Formula_Result result;
 	Formula_run (0, 0, & result);
 	*value = result. result.stringResult;
 }
 
-void Interpreter_anyExpression (Interpreter me, const char32 *expression, struct Formula_Result *result) {
+void Interpreter_anyExpression (Interpreter me, const char32 *expression, Formula_Result *result) {
 	Formula_compile (me, nullptr, expression, kFormula_EXPRESSION_TYPE_UNKNOWN, false);
 	Formula_run (0, 0, result);
 }
diff --git a/sys/Interpreter.h b/sys/Interpreter.h
index 91aa497..9a2ace7 100644
--- a/sys/Interpreter.h
+++ b/sys/Interpreter.h
@@ -82,7 +82,7 @@ void Interpreter_numericExpression (Interpreter me, const char32 *expression, do
 void Interpreter_numericVectorExpression (Interpreter me, const char32 *expression, numvec *value);
 void Interpreter_numericMatrixExpression (Interpreter me, const char32 *expression, nummat *value);
 void Interpreter_stringExpression (Interpreter me, const char32 *expression, char32 **value);
-void Interpreter_anyExpression (Interpreter me, const char32 *expression, struct Formula_Result *result);
+void Interpreter_anyExpression (Interpreter me, const char32 *expression, Formula_Result *result);
 
 InterpreterVariable Interpreter_hasVariable (Interpreter me, const char32 *key);
 InterpreterVariable Interpreter_lookUpVariable (Interpreter me, const char32 *key);
diff --git a/sys/Makefile b/sys/Makefile
index de4be0b..dbc03a6 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -1,11 +1,11 @@
 # Makefile of the library "sys"
-# Paul Boersma, 22 July 2017
+# Paul Boersma, 8 August 2017
 
 include ../makefile.defs
 
-CPPFLAGS = -I ../sys -I ../num -I ../dwsys -I ../kar -I ../external/portaudio -I ../external/flac -I ../external/mp3
+CPPFLAGS = -I ../kar -I ../sys -I ../dwsys -I ../external/portaudio -I ../external/flac -I ../external/mp3
 
-OBJECTS = abcio.o complex.o \
+OBJECTS = abcio.o complex.o tensor.o \
    melder_ftoa.o melder_atof.o melder_error.o melder_alloc.o melder.o melder_strings.o \
    melder_token.o melder_files.o melder_audio.o melder_audiofiles.o \
    melder_debug.o melder_sysenv.o melder_info.o melder_quantity.o \
@@ -43,4 +43,4 @@ libsys.a: $(OBJECTS)
 	$(AR) cq libsys.a $(OBJECTS)
 	$(RANLIB) libsys.a
 
-$(OBJECTS): *.h ../num/NUM.h ../dwsys/*.h ../kar/*.h ../external/portaudio/*.h ../external/flac/*.h ../external/mp3/mp3.h
+$(OBJECTS): *.h ../kar/*.h ../dwsys/*.h ../external/portaudio/*.h ../external/flac/*.h ../external/mp3/mp3.h
diff --git a/sys/ManPages.cpp b/sys/ManPages.cpp
index a58b296..b2d32e2 100644
--- a/sys/ManPages.cpp
+++ b/sys/ManPages.cpp
@@ -101,7 +101,7 @@ static const char32 *extractLink (const char32 *text, const char32 *p, char32 *l
 static void readOnePage (ManPages me, MelderReadText text) {
 	char32 *title;
 	try {
-		title = texgetw2 (text);
+		title = texgetw16 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Cannot find page title.");
 	}
@@ -124,17 +124,17 @@ static void readOnePage (ManPages me, MelderReadText text) {
 	my pages. addItem_move (autopage.move());
 
 	try {
-		page -> author = texgetw2 (text);
+		page -> author = texgetw16 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Cannot find author.");
 	}
 	try {
-		page -> date = texgetu4 (text);
+		page -> date = texgetu32 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Cannot find date.");
 	}
 	try {
-		page -> recordingTime = texgetr8 (text);
+		page -> recordingTime = texgetr64 (text);
 	} catch (MelderError) {
 		Melder_throw (U"Cannot find recording time.");
 	}
@@ -144,7 +144,7 @@ static void readOnePage (ManPages me, MelderReadText text) {
 	for (;; par ++) {
 		char32 link [501], fileName [256];
 		try {
-			par -> type = texgete1 (text, kManPage_type_getValue);
+			par -> type = texgete8 (text, kManPage_type_getValue);
 		} catch (MelderError) {
 			if (Melder_hasError (U"end of text")) {
 				Melder_clearError ();
@@ -154,11 +154,11 @@ static void readOnePage (ManPages me, MelderReadText text) {
 			}
 		}
 		if (par -> type == kManPage_type_SCRIPT) {
-			par -> width = texgetr4 (text);
-			par -> height = texgetr4 (text);
+			par -> width = texgetr64 (text);
+			par -> height = texgetr64 (text);
 		}
 		try {
-			par -> text = texgetw2 (text);
+			par -> text = texgetw16 (text);
 		} catch (MelderError) {
 			Melder_throw (U"Cannot find text.");
 		}
@@ -167,7 +167,7 @@ static void readOnePage (ManPages me, MelderReadText text) {
 			 * Now, `link' contains the link text, with spaces and all.
 			 * Transform it into a file name.
 			 */
-			structMelderFile file2 = { 0 };
+			structMelderFile file2 { };
 			if (link [0] == U'\\' && link [1] == U'F' && link [2] == U'I') {
 				/*
 				 * A link to a sound file: see if it exists.
@@ -831,14 +831,14 @@ static void writePageAsHtml (ManPages me, MelderFile file, long ipage, MelderStr
 }
 
 void ManPages_writeOneToHtmlFile (ManPages me, long ipage, MelderFile file) {
-	static MelderString buffer { 0 };
+	static MelderString buffer { };
 	MelderString_empty (& buffer);
 	writePageAsHtml (me, file, ipage, & buffer);
 	MelderFile_writeText (file, buffer.string, kMelder_textOutputEncoding_UTF8);
 }
 
 void ManPages_writeAllToHtmlDir (ManPages me, const char32 *dirPath) {
-	structMelderDir dir;
+	structMelderDir dir { };
 	Melder_pathToDir (dirPath, & dir);
 	for (long ipage = 1; ipage <= my pages.size; ipage ++) {
 		ManPage page = my pages.at [ipage];
@@ -853,9 +853,9 @@ void ManPages_writeAllToHtmlDir (ManPages me, const char32 *dirPath) {
 			str32cpy (fileName, U"_");   // no empty file names please
 		fileName [LONGEST_FILE_NAME] = U'\0';
 		str32cpy (fileName + str32len (fileName), U".html");
-		static MelderString buffer { 0 };
+		static MelderString buffer { };
 		MelderString_empty (& buffer);
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		MelderDir_getFile (& dir, fileName, & file);
 		writePageAsHtml (me, & file, ipage, & buffer);
 		/*
diff --git a/sys/ManPagesM.h b/sys/ManPagesM.h
index 54c955f..3a4c766 100644
--- a/sys/ManPagesM.h
+++ b/sys/ManPagesM.h
@@ -2,7 +2,7 @@
 #define _ManPagesM_h_
 /* ManPagesM.h
  *
- * Copyright (C) 1996-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1996-2011,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,32 +26,32 @@
 
 #define MAN_BEGIN(t,a,d)  { const char32 *title = t, *author = a; long date = d; \
 	static struct structManPage_Paragraph page [] = {
-#define INTRO(text)  { kManPage_type_INTRO, text },
-#define ENTRY(text)  { kManPage_type_ENTRY, text },
-#define NORMAL(text)  { kManPage_type_NORMAL, text },
-#define LIST_ITEM(text)  { kManPage_type_LIST_ITEM, text },
-#define LIST_ITEM1(text)  { kManPage_type_LIST_ITEM1, text },
-#define LIST_ITEM2(text)  { kManPage_type_LIST_ITEM2, text },
-#define LIST_ITEM3(text)  { kManPage_type_LIST_ITEM3, text },
-#define TAG(text)  { kManPage_type_TAG, text },
-#define TAG1(text)  { kManPage_type_TAG1, text },
-#define TAG2(text)  { kManPage_type_TAG2, text },
-#define TAG3(text)  { kManPage_type_TAG3, text },
-#define DEFINITION(text)  { kManPage_type_DEFINITION, text },
-#define DEFINITION1(text)  { kManPage_type_DEFINITION1, text },
-#define DEFINITION2(text)  { kManPage_type_DEFINITION2, text },
-#define DEFINITION3(text)  { kManPage_type_DEFINITION3, text },
-#define CODE(text)  { kManPage_type_CODE, text },
-#define CODE1(text)  { kManPage_type_CODE1, text },
-#define CODE2(text)  { kManPage_type_CODE2, text },
-#define CODE3(text)  { kManPage_type_CODE3, text },
-#define CODE4(text)  { kManPage_type_CODE4, text },
-#define CODE5(text)  { kManPage_type_CODE5, text },
-#define PROTOTYPE(text)  { kManPage_type_PROTOTYPE, text },
-#define FORMULA(text)  { kManPage_type_FORMULA, text },
+#define INTRO(text)  { kManPage_type_INTRO, text, 0.0, 0.0, nullptr },
+#define ENTRY(text)  { kManPage_type_ENTRY, text, 0.0, 0.0, nullptr },
+#define NORMAL(text)  { kManPage_type_NORMAL, text, 0.0, 0.0, nullptr },
+#define LIST_ITEM(text)  { kManPage_type_LIST_ITEM, text, 0.0, 0.0, nullptr },
+#define LIST_ITEM1(text)  { kManPage_type_LIST_ITEM1, text, 0.0, 0.0, nullptr },
+#define LIST_ITEM2(text)  { kManPage_type_LIST_ITEM2, text, 0.0, 0.0, nullptr },
+#define LIST_ITEM3(text)  { kManPage_type_LIST_ITEM3, text, 0.0, 0.0, nullptr },
+#define TAG(text)  { kManPage_type_TAG, text, 0.0, 0.0, nullptr },
+#define TAG1(text)  { kManPage_type_TAG1, text, 0.0, 0.0, nullptr },
+#define TAG2(text)  { kManPage_type_TAG2, text, 0.0, 0.0, nullptr },
+#define TAG3(text)  { kManPage_type_TAG3, text, 0.0, 0.0, nullptr },
+#define DEFINITION(text)  { kManPage_type_DEFINITION, text, 0.0, 0.0, nullptr },
+#define DEFINITION1(text)  { kManPage_type_DEFINITION1, text, 0.0, 0.0, nullptr },
+#define DEFINITION2(text)  { kManPage_type_DEFINITION2, text, 0.0, 0.0, nullptr },
+#define DEFINITION3(text)  { kManPage_type_DEFINITION3, text, 0.0, 0.0, nullptr },
+#define CODE(text)  { kManPage_type_CODE, text, 0.0, 0.0, nullptr },
+#define CODE1(text)  { kManPage_type_CODE1, text, 0.0, 0.0, nullptr },
+#define CODE2(text)  { kManPage_type_CODE2, text, 0.0, 0.0, nullptr },
+#define CODE3(text)  { kManPage_type_CODE3, text, 0.0, 0.0, nullptr },
+#define CODE4(text)  { kManPage_type_CODE4, text, 0.0, 0.0, nullptr },
+#define CODE5(text)  { kManPage_type_CODE5, text, 0.0, 0.0, nullptr },
+#define PROTOTYPE(text)  { kManPage_type_PROTOTYPE, text, 0.0, 0.0, nullptr },
+#define FORMULA(text)  { kManPage_type_FORMULA, text, 0.0, 0.0, nullptr },
 #define PICTURE(width,height,draw)  { kManPage_type_PICTURE, nullptr, width, height, draw },
 #define SCRIPT(width,height,text)  { kManPage_type_SCRIPT, text, width, height },
-#define MAN_END  { 0 } }; ManPages_addPage (me, title, author, date, page); }
+#define MAN_END  { } }; ManPages_addPage (me, title, author, date, page); }
 
 #define Manual_DRAW_WINDOW(height,title,menu) \
 	"Select inner viewport... 0.2 5.8 0.2 " #height "-0.2\n" \
diff --git a/sys/Manual.cpp b/sys/Manual.cpp
index 141d2e6..1734c40 100644
--- a/sys/Manual.cpp
+++ b/sys/Manual.cpp
@@ -55,7 +55,7 @@ static void menu_cb_writeAllToHtmlDir (Manual me, EDITOR_ARGS_FORM) {
 		LABEL (U"", U"Type a directory name:")
 		TEXTFIELD (U"directory", U"")
 	EDITOR_OK
-		structMelderDir currentDirectory { { 0 } };
+		structMelderDir currentDirectory { };
 		Melder_getDefaultDir (& currentDirectory);
 		SET_STRING (U"directory", Melder_dirToPath (& currentDirectory))
 	EDITOR_DO
@@ -266,7 +266,7 @@ static double searchToken (ManPages me, long ipage, char32 *token) {
 	/*
 	 * Try to find a match in the title, case insensitively.
 	 */
-	static MelderString buffer { 0 };
+	static MelderString buffer { };
 	MelderString_copy (& buffer, page -> title);
 	for (char32 *p = & buffer.string [0]; *p != U'\0'; p ++) *p = tolower32 (*p);
 	if (str32str (buffer.string, token)) {
@@ -298,7 +298,7 @@ static double searchToken (ManPages me, long ipage, char32 *token) {
 static void search (Manual me, const char32 *query) {
 	ManPages manPages = (ManPages) my data;
 	long numberOfPages = manPages -> pages.size;
-	static MelderString searchText { 0 };
+	static MelderString searchText { };
 	MelderString_copy (& searchText, query);
 	for (char32 *p = & searchText.string [0]; *p != U'\0'; p ++) {
 		if (*p == U'\n') *p = U' ';
@@ -483,7 +483,7 @@ void structManual :: v_goToPage_i (long pageNumber) {
 int structManual :: v_goToPage (const char32 *title) {
 	ManPages manPages = (ManPages) our data;
 	if (title [0] == U'\\' && title [1] == U'F' && title [2] == U'I') {
-		structMelderFile file = { 0 };
+		structMelderFile file { };
 		MelderDir_relativePathToFile (& manPages -> rootDirectory, title + 3, & file);
 		Melder_recordFromFile (& file);
 		return -1;
diff --git a/sys/MelderGui.cpp b/sys/MelderGui.cpp
index ed50f7a..8e1648b 100644
--- a/sys/MelderGui.cpp
+++ b/sys/MelderGui.cpp
@@ -96,7 +96,7 @@ static bool waitWhileProgress (double progress, const char32 *message, GuiDialog
 		GuiThing_show (dia);   // TODO: prevent raising to the front
 		const char32 *newline = str32chr (message, U'\n');
 		if (newline) {
-			static MelderString buffer { 0 };
+			static MelderString buffer { };
 			MelderString_copy (& buffer, message);
 			buffer.string [newline - message] = U'\0';
 			GuiLabel_setText (label1, buffer.string);
diff --git a/sys/Preferences.cpp b/sys/Preferences.cpp
index baa5c79..6e03b65 100644
--- a/sys/Preferences.cpp
+++ b/sys/Preferences.cpp
@@ -1,6 +1,6 @@
 /* Preferences.cpp
  *
- * Copyright (C) 1996-2012,2013,2015,2016 Paul Boersma
+ * Copyright (C) 1996-2012,2013,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,6 +55,9 @@ static void Preferences_add (const char32 *string, int type, void *value, int mi
 void Preferences_addByte (const char32 *string, signed char *value, signed char defaultValue)
 	{ *value = defaultValue; Preferences_add (string, bytewa, value, 0, 0, nullptr, nullptr); }
 
+void Preferences_addInt16 (const char32 *string, int *value, int defaultValue)
+	{ *value = defaultValue; Preferences_add (string, int16wa, value, 0, 0, nullptr, nullptr); }
+
 void Preferences_addInt (const char32 *string, int *value, int defaultValue)
 	{ *value = defaultValue; Preferences_add (string, intwa, value, 0, 0, nullptr, nullptr); }
 
@@ -114,13 +117,15 @@ void Preferences_read (MelderFile file) {
 			Preference pref = thePreferences.at [ipref];
 			switch (pref -> type) {
 				case bytewa: * (signed char *) pref -> value =
-					strtol (Melder_peek32to8 (value), nullptr, 10); break;
+					(int8) strtol (Melder_peek32to8 (value), nullptr, 10); break;
+				case int16wa: * (int16 *) pref -> value =
+					(int16) strtol (Melder_peek32to8 (value), nullptr, 10); break;
 				case intwa: * (int *) pref -> value =
 					strtol (Melder_peek32to8 (value), nullptr, 10); break;
 				case longwa: * (long *) pref -> value =
 					strtol (Melder_peek32to8 (value), nullptr, 10); break;
 				case ubytewa: * (unsigned char *) pref -> value =
-					strtoul (Melder_peek32to8 (value), nullptr, 10); break;
+					(uint8) strtoul (Melder_peek32to8 (value), nullptr, 10); break;
 				case uintwa: * (unsigned int *) pref -> value =
 					strtoul (Melder_peek32to8 (value), nullptr, 10); break;
 				case ulongwa: * (unsigned long *) pref -> value =
@@ -150,12 +155,13 @@ void Preferences_read (MelderFile file) {
 
 void Preferences_write (MelderFile file) {
 	if (thePreferences.size == 0) return;
-	static MelderString buffer { 0 };
+	static MelderString buffer { };
 	for (long ipref = 1; ipref <= thePreferences.size; ipref ++) {
 		Preference pref = thePreferences.at [ipref];
 		MelderString_append (& buffer, pref -> string, U": ");
 		switch (pref -> type) {
 			case bytewa:   MelderString_append (& buffer, (int) (* (signed char *)    pref -> value)); break;
+			case int16wa:  MelderString_append (& buffer,       (* (int16 *)          pref -> value)); break;
 			case intwa:    MelderString_append (& buffer,       (* (int *)            pref -> value)); break;
 			case longwa:   MelderString_append (& buffer,       (* (long *)           pref -> value)); break;
 			case ubytewa:  MelderString_append (& buffer, (int) (* (unsigned char *)  pref -> value)); break;
diff --git a/sys/Preferences.h b/sys/Preferences.h
index e6f7d69..88a1cca 100644
--- a/sys/Preferences.h
+++ b/sys/Preferences.h
@@ -2,7 +2,7 @@
 #define _Preferences_h_
 /* Preferences.h
  *
- * Copyright (C) 1996-2011,2013,2015 Paul Boersma
+ * Copyright (C) 1996-2011,2013,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@ enum kPreferences_dummy { dummy1 = 1, dummy2 = 2 };
 
 void Preferences_addByte   (const char32 *string /* cattable */, signed char *value, signed char defaultValue);
 void Preferences_addShort  (const char32 *string /* cattable */, short *value, short defaultValue);
+void Preferences_addInt16  (const char32 *string /* cattable */, int *value, int defaultValue);
 void Preferences_addInt    (const char32 *string /* cattable */, int *value, int defaultValue);
 void Preferences_addLong   (const char32 *string /* cattable */, long *value, long defaultValue);
 void Preferences_addUbyte  (const char32 *string /* cattable */, unsigned char *value, unsigned char defaultValue);
diff --git a/sys/Printer.cpp b/sys/Printer.cpp
index 55ebdea..cfd9f25 100644
--- a/sys/Printer.cpp
+++ b/sys/Printer.cpp
@@ -1,6 +1,6 @@
 /* Printer.cpp
  *
- * Copyright (C) 1998-2011,2012,2013,2014,2015 Paul Boersma
+ * Copyright (C) 1998-2011,2012,2013,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -272,7 +272,7 @@ int Printer_postScriptSettings () {
 int Printer_print (void (*draw) (void *boss, Graphics g), void *boss) {
 	try {
 		#if defined (UNIX)
-			structMelderFile tempFile = { 0 };
+			structMelderFile tempFile { };
 			char tempPath_utf8 [] = "/tmp/picXXXXXX";
 			close (mkstemp (tempPath_utf8));
 			Melder_pathToFile (Melder_peek8to32 (tempPath_utf8), & tempFile);
diff --git a/sys/ScriptEditor.cpp b/sys/ScriptEditor.cpp
index a33759f..f1f2fa5 100644
--- a/sys/ScriptEditor.cpp
+++ b/sys/ScriptEditor.cpp
@@ -42,7 +42,7 @@ void structScriptEditor :: v_destroy () noexcept {
 
 void structScriptEditor :: v_nameChanged () {
 	bool dirtinessAlreadyShown = GuiWindow_setDirty (our windowForm, dirty);
-	static MelderString buffer { 0 };
+	static MelderString buffer { };
 	MelderString_copy (& buffer, name [0] ? U"Script" : U"untitled script");
 	if (editorClass)
 		MelderString_append (& buffer, U" [", environmentName, U"]");
@@ -66,7 +66,7 @@ static void args_ok (UiForm sendingForm, int /* narg */, Stackel /* args */, con
 {
 	iam (ScriptEditor);
 	autostring32 text = GuiText_getString (my textWidget);
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	if (my name [0]) {
 		Melder_pathToFile (my name, & file);
 		MelderFile_setDefaultDir (& file);
@@ -87,7 +87,7 @@ static void args_ok_selectionOnly (UiForm sendingForm, int /* narg */, Stackel /
 	autostring32 text = GuiText_getSelection (my textWidget);
 	if (! text.peek())
 		Melder_throw (U"No text is selected any longer.\nPlease reselect or click Cancel.");
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	if (my name [0]) {
 		Melder_pathToFile (my name, & file);
 		MelderFile_setDefaultDir (& file);
@@ -106,7 +106,7 @@ static void menu_cb_run (ScriptEditor me, EDITOR_ARGS_DIRECT) {
 		Melder_throw (U"The script is already running (paused). Please close or continue the pause or demo window.");
 	autostring32 text = GuiText_getString (my textWidget);
 	trace (U"Running the following script (1):\n", text.peek());
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	if (my name [0]) {
 		Melder_pathToFile (my name, & file);
 		MelderFile_setDefaultDir (& file);
@@ -133,7 +133,7 @@ static void menu_cb_runSelection (ScriptEditor me, EDITOR_ARGS_DIRECT) {
 	autostring32 text = GuiText_getSelection (my textWidget);
 	if (! text.peek())
 		Melder_throw (U"No text selected.");
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	if (my name [0]) {
 		Melder_pathToFile (my name, & file);
 		MelderFile_setDefaultDir (& file);
@@ -254,7 +254,7 @@ static void menu_cb_pasteHistory (ScriptEditor me, EDITOR_ARGS_DIRECT) {
 }
 
 static void menu_cb_expandIncludeFiles (ScriptEditor me, EDITOR_ARGS_DIRECT) {
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	autostring32 text = GuiText_getString (my textWidget);
 	if (my name [0]) {
 		Melder_pathToFile (my name, & file);
diff --git a/sys/Simple_def.h b/sys/Simple_def.h
index 57b58d9..d12d368 100644
--- a/sys/Simple_def.h
+++ b/sys/Simple_def.h
@@ -1,6 +1,6 @@
 /* Simple_def.h
  *
- * Copyright (C) 1992-2012,2015 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 
 #define ooSTRUCT SimpleInt
 oo_DEFINE_CLASS (SimpleInt, Daata)
-	oo_INT (number)
+	oo_INT16 (number)
 oo_END_CLASS (SimpleInt)
 #undef ooSTRUCT
 
diff --git a/sys/Tensor.h b/sys/Tensor.h
deleted file mode 100644
index bbf3e36..0000000
--- a/sys/Tensor.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _tensor_h_
-#define _tensor_h_
-/* tensor.h
- *
- * Copyright (C) 2017 Paul Boersma
- *
- * This code 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.
- *
- * This code is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this work. If not, see <http://www.gnu.org/licenses/>.
- */
-
-struct numvec {
-	long size;
-	double *data;
-};
-
-struct nummat {
-	long nrow, ncol;
-	double **data;
-};
-
-/* End of file tensor.h */
-#endif
diff --git a/sys/TextEditor.cpp b/sys/TextEditor.cpp
index 891be96..c31d6d6 100644
--- a/sys/TextEditor.cpp
+++ b/sys/TextEditor.cpp
@@ -45,7 +45,7 @@ void structTextEditor :: v_destroy () noexcept {
 void structTextEditor :: v_nameChanged () {
 	if (v_fileBased ()) {
 		bool dirtinessAlreadyShown = GuiWindow_setDirty (our windowForm, our dirty);
-		static MelderString windowTitle { 0 };
+		static MelderString windowTitle { };
 		if (our name [0] == U'\0') {
 			MelderString_copy (& windowTitle, U"(untitled");
 			if (dirty && ! dirtinessAlreadyShown)
diff --git a/sys/Thing.cpp b/sys/Thing.cpp
index bd25e57..78b992f 100644
--- a/sys/Thing.cpp
+++ b/sys/Thing.cpp
@@ -1,6 +1,6 @@
 /* Thing.cpp
  *
- * Copyright (C) 1992-2012,2015 Paul Boersma
+ * Copyright (C) 1992-2012,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -213,10 +213,10 @@ void Thing_info (Thing me) {
 	Thing_infoWithIdAndFile (me, 0, nullptr);
 }
 
-char32 * Thing_getName (Thing me) { return my name; }
+const char32 * Thing_getName (Thing me) { return my name; }
 
-char32 * Thing_messageName (Thing me) {
-	static MelderString buffers [19] { { 0 } };
+const char32 * Thing_messageName (Thing me) {
+	static MelderString buffers [19] { };
 	static int ibuffer = 0;
 	if (++ ibuffer == 19) ibuffer = 0;
 	if (my name) {
diff --git a/sys/Thing.h b/sys/Thing.h
index 2596dbc..25cdcac 100644
--- a/sys/Thing.h
+++ b/sys/Thing.h
@@ -2,7 +2,7 @@
 #define _Thing_h_
 /* Thing.h
  *
- * Copyright (C) 1992-2011,2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,34 +21,15 @@
 /* The root class of all objects. */
 
 /* Anyone who uses Thing can also use: */
-	/* Arrays with any bounds and 1 or 2 indices, math, and numerics: */
-		#include "../num/NUM.h"   /* Including math.h */
-	/* The messaging mechanism: */
-		#include "melder.h"   /* Including stdio.h string.h etc. */
+	/* The messaging mechanism, arrays with any bounds and 1 or 2 indices, math, and numerics: */
+		#include "melder.h"   /* Including stdio.h string.h math.h etc. */
 	/* The macros for struct and class definitions: */
 		#include "oo.h"
 	/* The input/output mechanism: */
 		#include "abcio.h"
 
-//#include <string>
-
 #define _Thing_auto_DEBUG  0
 
-/*
-	Use the macro 'iam'
-	as the first declaration in a function definition.
-	After this, the object 'me' has the right class (for the compiler),
-	so that you can use the macro 'my' to refer to members.
-	Example: int Person_getAge (void *void_me) { iam (Person); return my age; }
-*/
-#define iam(klas)  klas me = (klas) void_me
-#define my  me ->
-#define thy  thee ->
-#define your  you ->
-#define his  him ->
-#define her  she ->
-#define our  this ->
-
 typedef struct structClassInfo *ClassInfo;
 struct structClassInfo {
 	/*
@@ -204,9 +185,9 @@ ClassInfo Thing_classFromClassName (const char32 *className, int *formatVersion)
 	((klas) _Thing_dummyObject (class##klas))
 Thing _Thing_dummyObject (ClassInfo classInfo);
 
-char32 * Thing_getName (Thing me);
+const char32 * Thing_getName (Thing me);
 /* Return a pointer to your internal name (which can be null). */
-char32 * Thing_messageName (Thing me);
+const char32 * Thing_messageName (Thing me);
 
 void Thing_setName (Thing me, const char32 *name /* cattable */);
 /*
@@ -339,17 +320,6 @@ public:
 		our ptr = nullptr;   // make the pointer non-automatic again
 		return temp;
 	}
-	#if 0
-		operator T* () {
-			return our ptr;
-		}
-	#endif
-	/*
-	 * An autoThing can be cloned. This can be used for giving ownership without losing ownership.
-	 */
-	T* clone () const {
-		return static_cast<T *> (Data_copy (our ptr));
-	}
 	void reset () noexcept {
 		_Thing_forget (our ptr);
 		our ptr = nullptr;
@@ -525,7 +495,7 @@ class autoThingVector {
 	long d_from, d_to;
 public:
 	autoThingVector<T> (long from, long to) : d_from (from), d_to (to) {
-		d_ptr = static_cast <_Thing_auto<T>*> (NUMvector (sizeof (_Thing_auto<T>), from, to));
+		d_ptr = static_cast <_Thing_auto<T>*> (NUMvector (sizeof (_Thing_auto<T>), from, to, true));
 	}
 	autoThingVector (_Thing_auto<T> *ptr, long from, long to) : d_ptr (ptr), d_from (from), d_to (to) {
 	}
diff --git a/sys/Ui.cpp b/sys/Ui.cpp
index a92c7fb..09a2c0f 100644
--- a/sys/Ui.cpp
+++ b/sys/Ui.cpp
@@ -187,7 +187,7 @@ static void UiField_widgetToValue (UiField me) {
 				}
 				GuiText_setString (my text, clean);
 			}
-			if (my realValue == NUMundefined && my type != UI_REAL_OR_UNDEFINED)
+			if (isundef (my realValue) && my type != UI_REAL_OR_UNDEFINED)
 				Melder_throw (U_LEFT_DOUBLE_QUOTE, my name, U_RIGHT_DOUBLE_QUOTE U" has the value \"undefined\".");
 			if (my type == UI_POSITIVE && my realValue <= 0.0)
 				Melder_throw (U_LEFT_DOUBLE_QUOTE, my name, U_RIGHT_DOUBLE_QUOTE U" must be greater than 0.0.");
@@ -273,7 +273,7 @@ static void UiField_stringToValue (UiField me, const char32 *string, Interpreter
 			if (str32spn (string, U" \t") == str32len (string))
 				Melder_throw (U"Argument “", my name, U"” empty.");
 			Interpreter_numericExpression (interpreter, string, & my realValue);
-			if (my realValue == NUMundefined && my type != UI_REAL_OR_UNDEFINED)
+			if (isundef (my realValue) && my type != UI_REAL_OR_UNDEFINED)
 				Melder_throw (U"\"", my name, U"\" has the value \"undefined\".");
 			if (my type == UI_POSITIVE && my realValue <= 0.0)
 				Melder_throw (U"\"", my name, U"\" must be greater than 0.");
@@ -361,7 +361,7 @@ static void UiField_stringToValue (UiField me, const char32 *string, Interpreter
 
 /***** History mechanism. *****/
 
-static MelderString theHistory { 0 };
+static MelderString theHistory { };
 void UiHistory_write (const char32 *string) { MelderString_append (& theHistory, string); }
 void UiHistory_write_expandQuotes (const char32 *string) {
 	if (! string) return;
@@ -828,7 +828,7 @@ UiField UiForm_addChannel4 (UiForm me, long *variable, const char32 *variableNam
 #define HELP_BUTTON_X  20
 #define LIST_HEIGHT  192
 
-static MelderString theFinishBuffer { 0 };
+static MelderString theFinishBuffer { };
 
 static void appendColon () {
 	long length = theFinishBuffer.length;
@@ -1231,7 +1231,7 @@ static void UiField_argToValue (UiField me, Stackel arg, Interpreter /* interpre
 			if (arg -> which != Stackel_NUMBER)
 				Melder_throw (U"Argument \"", my name, U"\" should be a number, not ", Stackel_whichText(arg), U".");
 			my realValue = arg -> number;
-			if (my realValue == NUMundefined && my type != UI_REAL_OR_UNDEFINED)
+			if (isundef (my realValue) && my type != UI_REAL_OR_UNDEFINED)
 				Melder_throw (U"Argument \"", my name, U"\" has the value \"undefined\".");
 			if (my type == UI_POSITIVE && my realValue <= 0.0)
 				Melder_throw (U"Argument \"", my name, U"\" must be greater than 0.");
diff --git a/sys/UiFile.cpp b/sys/UiFile.cpp
index 7549552..c09f31a 100644
--- a/sys/UiFile.cpp
+++ b/sys/UiFile.cpp
@@ -55,7 +55,7 @@ void UiInfile_do (UiForm me) {
 			UiHistory_write (U" \"");
 			UiHistory_write_expandQuotes (infileName -> string);
 			UiHistory_write (U"\"");
-			structMelderFile file;
+			structMelderFile file { };
 			MelderFile_copy (& my file, & file);
 			try {
 				my okCallback (me, 0, nullptr, nullptr, nullptr, my invokingButtonTitle, false, my buttonClosure);
@@ -113,7 +113,7 @@ void UiOutfile_do (UiForm me, const char32 *defaultName) {
 		return;
 	}
 	Melder_pathToFile (outfileName, & my file);
-	structMelderFile file;
+	structMelderFile file { };
 	MelderFile_copy (& my file, & file);   // save, because okCallback could destroy me
 	UiHistory_write (U"\n");
 	UiHistory_write_colonize (my invokingButtonTitle);
diff --git a/sys/abcio.cpp b/sys/abcio.cpp
index 12f0632..a0d7667 100644
--- a/sys/abcio.cpp
+++ b/sys/abcio.cpp
@@ -1,6 +1,6 @@
 /* abcio.cpp
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -33,7 +33,6 @@
  */
 
 #include "melder.h"
-#include "NUM.h"
 #include <ctype.h>
 #ifdef macintosh
 	#include <TargetConditionals.h>
@@ -42,7 +41,7 @@
 
 /********** text I/O **********/
 
-static long getInteger (MelderReadText me) {
+static int64 getInteger (MelderReadText me) {
 	char buffer [41];
 	char32 c;
 	/*
@@ -79,10 +78,10 @@ static long getInteger (MelderReadText me) {
 	if (i >= 40)
 		Melder_throw (U"Found long text while looking for an integer in text (line ", MelderReadText_getLineNumber (me), U").");
 	buffer [i + 1] = '\0';
-	return strtol (buffer, nullptr, 10);
+	return strtoll (buffer, nullptr, 10);
 }
 
-static unsigned long getUnsigned (MelderReadText me) {
+static uint64 getUnsigned (MelderReadText me) {
 	char buffer [41];
 	char32 c;
 	for (c = MelderReadText_getChar (me); ! isdigit ((int) c) && c != U'+'; c = MelderReadText_getChar (me)) {
@@ -118,7 +117,7 @@ static unsigned long getUnsigned (MelderReadText me) {
 	if (i >= 40)
 		Melder_throw (U"Found long text while searching for an unsigned integer in text (line ", MelderReadText_getLineNumber (me), U").");
 	buffer [i + 1] = '\0';
-	return strtoul (buffer, nullptr, 10);
+	return strtoull (buffer, nullptr, 10);
 }
 
 static double getReal (MelderReadText me) {
@@ -211,7 +210,7 @@ static short getEnum (MelderReadText me, int (*getValue) (const char32 *)) {
 }
 
 static char32 * getString (MelderReadText me) {
-	static MelderString buffer { 0 };
+	static MelderString buffer { };
 	MelderString_empty (& buffer);
 	for (char32 c = MelderReadText_getChar (me); c != U'\"'; c = MelderReadText_getChar (me)) {
 		if (c == U'\0')
@@ -262,10 +261,10 @@ static char32 * getString (MelderReadText me) {
 #include "enums_getValue.h"
 #include "abcio_enums.h"
 
-int texgeti1 (MelderReadText text) {
+int texgeti8 (MelderReadText text) {
 	try {
-		long externalValue = getInteger (text);
-		if (externalValue < -128 || externalValue > +127)
+		int64 externalValue = getInteger (text);
+		if (externalValue < INT8_MIN || externalValue > INT8_MAX)
 			Melder_throw (U"Value (", externalValue, U") out of range (-128 .. +127).");
 		return (int) externalValue;
 	} catch (MelderError) {
@@ -273,30 +272,32 @@ int texgeti1 (MelderReadText text) {
 	}
 }
 
-int texgeti2 (MelderReadText text) {
+int16 texgeti16 (MelderReadText text) {
 	try {
-		long externalValue = getInteger (text);
-		if (externalValue < -32768 || externalValue > +32767)
+		int64 externalValue = getInteger (text);
+		if (externalValue < INT16_MIN || externalValue > INT16_MAX)
 			Melder_throw (U"Value (", externalValue, U") out of range (-32768 .. +32767).");
-		return (int) externalValue;
+		return (int16) externalValue;
 	} catch (MelderError) {
 		Melder_throw (U"Signed short integer not read from text file.");
 	}
 }
 
-long texgeti4 (MelderReadText text) {
+int32 texgeti32 (MelderReadText text) {
 	try {
-		long externalValue = getInteger (text);
-		return externalValue;
+		int64 externalValue = getInteger (text);
+		if (externalValue < INT32_MIN || externalValue > INT32_MAX)
+			Melder_throw (U"Value (", externalValue, U") out of range (-2147483648 .. +2147483647).");
+		return (int32) externalValue;
 	} catch (MelderError) {
 		Melder_throw (U"Signed integer not read from text file.");
 	}
 }
 
-unsigned int texgetu1 (MelderReadText text) {
+unsigned int texgetu8 (MelderReadText text) {
 	try {
-		unsigned long externalValue = getUnsigned (text);
-		if (externalValue > 255)
+		uint64 externalValue = getUnsigned (text);
+		if (externalValue > UINT8_MAX)
 			Melder_throw (U"Value (", externalValue, U") out of range (0 .. 255).");
 		return (unsigned int) externalValue;
 	} catch (MelderError) {
@@ -304,41 +305,43 @@ unsigned int texgetu1 (MelderReadText text) {
 	}
 }
 
-unsigned int texgetu2 (MelderReadText text) {
+uint16 texgetu16 (MelderReadText text) {
 	try {
-		unsigned long externalValue = getUnsigned (text);
-		if (externalValue > 65535)
+		uint64 externalValue = getUnsigned (text);
+		if (externalValue > UINT16_MAX)
 			Melder_throw (U"Value (", externalValue, U") out of range (0 .. 65535).");
-		return (unsigned int) externalValue;
+		return (uint16) externalValue;
 	} catch (MelderError) {
 		Melder_throw (U"Unsigned short integer not read from text file.");
 	}
 }
 
-unsigned long texgetu4 (MelderReadText text) {
+uint32 texgetu32 (MelderReadText text) {
 	try {
-		unsigned long externalValue = getUnsigned (text);
-		return externalValue;
+		uint64 externalValue = getUnsigned (text);
+		if (externalValue > UINT32_MAX)
+			Melder_throw (U"Value (", externalValue, U") out of range (0 .. 4294967295).");
+		return (uint32) externalValue;
 	} catch (MelderError) {
 		Melder_throw (U"Unsigned integer not read from text file.");
 	}
 }
 
-double texgetr4 (MelderReadText text) { return getReal (text); }
-double texgetr8 (MelderReadText text) { return getReal (text); }
-double texgetr10 (MelderReadText text) { return getReal (text); }
-fcomplex texgetc8 (MelderReadText text) { fcomplex z; z.re = getReal (text); z.im = getReal (text); return z; }
-dcomplex texgetc16 (MelderReadText text) { dcomplex z; z.re = getReal (text); z.im = getReal (text); return z; }
+double texgetr32 (MelderReadText text) { return getReal (text); }
+double texgetr64 (MelderReadText text) { return getReal (text); }
+double texgetr80 (MelderReadText text) { return getReal (text); }
+fcomplex texgetc64 (MelderReadText text) { fcomplex z; z.re = getReal (text); z.im = getReal (text); return z; }
+dcomplex texgetc128 (MelderReadText text) { dcomplex z; z.re = getReal (text); z.im = getReal (text); return z; }
 
-short texgete1 (MelderReadText text, int (*getValue) (const char32 *)) { return getEnum (text, getValue); }
-short texgete2 (MelderReadText text, int (*getValue) (const char32 *)) { return getEnum (text, getValue); }
-short texgeteb (MelderReadText text) { return getEnum (text, kBoolean_getValue); }
-short texgeteq (MelderReadText text) { return getEnum (text, kQuestion_getValue); }
-short texgetex (MelderReadText text) { return getEnum (text, kExistence_getValue); }
-char *texgets2 (MelderReadText text) { return (char *) Melder_32to8 (getString (text)); }
-char *texgets4 (MelderReadText text) { return (char *) Melder_32to8 (getString (text)); }
-char32 *texgetw2 (MelderReadText text) { return Melder_dup   (getString (text)); }
-char32 *texgetw4 (MelderReadText text) { return Melder_dup   (getString (text)); }
+short texgete8 (MelderReadText text, int (*getValue) (const char32 *)) { return getEnum (text, getValue); }
+short texgete16 (MelderReadText text, int (*getValue) (const char32 *)) { return getEnum (text, getValue); }
+bool texgeteb (MelderReadText text) { return getEnum (text, kBoolean_getValue); }
+bool texgeteq (MelderReadText text) { return getEnum (text, kQuestion_getValue); }
+bool texgetex (MelderReadText text) { return getEnum (text, kExistence_getValue); }
+char *texgets16 (MelderReadText text) { return (char *) Melder_32to8 (getString (text)); }
+char *texgets32 (MelderReadText text) { return (char *) Melder_32to8 (getString (text)); }
+char32 *texgetw16 (MelderReadText text) { return Melder_dup   (getString (text)); }
+char32 *texgetw32 (MelderReadText text) { return Melder_dup   (getString (text)); }
 
 void texindent (MelderFile file) { file -> indent += 4; }
 void texexdent (MelderFile file) { file -> indent -= 4; }
@@ -376,53 +379,53 @@ void texputintro (MelderFile file, const char32 *s1, const char32 *s2, const cha
 			s6 && s6 [0] == U'd' && s6 [1] == U'_' ? & s6 [2] : & s6 [0]); \
 	}
 
-void texputi1 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputi8 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, i, file -> verbose ? U" " : nullptr);
 }
-void texputi2 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputi16 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, i, file -> verbose ? U" " : nullptr);
 }
-void texputi4 (MelderFile file, long i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputi32 (MelderFile file, long i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, i, file -> verbose ? U" " : nullptr);
 }
-void texputu1 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputu8 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, u, file -> verbose ? U" " : nullptr);
 }
-void texputu2 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputu16 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, u, file -> verbose ? U" " : nullptr);
 }
-void texputu4 (MelderFile file, unsigned long u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputu32 (MelderFile file, unsigned long u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, u, file -> verbose ? U" " : nullptr);
 }
-void texputr4 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputr32 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, Melder_single (x), file -> verbose ? U" " : nullptr);
 }
-void texputr8 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputr64 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, x, file -> verbose ? U" " : nullptr);
 }
-void texputc8 (MelderFile file, fcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputc64 (MelderFile file, fcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, Melder_single (z.re),
 		file -> verbose ? U" + " : U" ", Melder_single (z.im), file -> verbose ? U" i " : nullptr);
 }
-void texputc16 (MelderFile file, dcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputc128 (MelderFile file, dcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = " : nullptr, z.re,
 		file -> verbose ? U" + " : U" ", z.im, file -> verbose ? U" i " : nullptr);
 }
-void texpute1 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texpute8 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = <" : U"<", getText (i), file -> verbose ? U"> " : U">");
 }
-void texpute2 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texpute16 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = <" : U"<", getText (i), file -> verbose ? U"> " : U">");
 }
@@ -438,7 +441,7 @@ void texputex (MelderFile file, bool i, const char32 *s1, const char32 *s2, cons
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U"? " : nullptr, i ? U"<exists>" : U"<absent>", file -> verbose ? U" " : nullptr);
 }
-void texputs1 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputs8 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
 	if (s) {
@@ -450,7 +453,7 @@ void texputs1 (MelderFile file, const char *s, const char32 *s1, const char32 *s
 	}
 	MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
 }
-void texputs2 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputs16 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
 	if (s) {
@@ -462,7 +465,7 @@ void texputs2 (MelderFile file, const char *s, const char32 *s1, const char32 *s
 	}
 	MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
 }
-void texputs4 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputs32 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
 	if (s) {
@@ -474,7 +477,7 @@ void texputs4 (MelderFile file, const char *s, const char32 *s1, const char32 *s
 	}
 	MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
 }
-void texputw2 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputw16 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
 	if (s) {
@@ -486,7 +489,7 @@ void texputw2 (MelderFile file, const char32 *s, const char32 *s1, const char32
 	}
 	MelderFile_write (file, file -> verbose ? U"\" " : U"\"");
 }
-void texputw4 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
+void texputw32 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6) {
 	PUTLEADER
 	MelderFile_write (file, file -> verbose ? U" = \"" : U"\"");
 	if (s) {
@@ -556,7 +559,7 @@ void texputw4 (MelderFile file, const char32 *s, const char32 *s1, const char32
 #endif
 
 /*
-	The routines bingetr4, bingetr8, binputr4, and binputr8,
+	The routines bingetr32, bingetr64, binputr32, and binputr64,
 	were implemented by Paul Boersma from the descriptions of the IEEE floating-point formats,
 	as found in the MC68881/MC68882 User's Manual by Motorola (second edition, 1989).
 	The following copyright notice only refers to the code of bingetr10 and binputr10.
@@ -637,7 +640,7 @@ static void writeError (const char32 *text) {
 	Melder_throw (U"Error in file while trying to write ", text);
 }
 
-unsigned int bingetu1 (FILE *f) {
+unsigned int bingetu8 (FILE *f) {
 	try {
 		int externalValue = getc (f);   // either -1 (EOF) or in the range 0..255
 		if (externalValue < 0) readError (f, U"a byte.");
@@ -647,7 +650,7 @@ unsigned int bingetu1 (FILE *f) {
 	}
 }
 
-void binputu1 (unsigned int u, FILE *f) {
+void binputu8 (unsigned int u, FILE *f) {
 	try {
 		if (putc ((int) u, f) < 0) writeError (U"a byte.");
 	} catch (MelderError) {
@@ -655,7 +658,7 @@ void binputu1 (unsigned int u, FILE *f) {
 	}
 }
 
-int bingeti1 (FILE *f) {
+int bingeti8 (FILE *f) {
 	try {
 		int externalValue = getc (f);
 		if (externalValue < 0) readError (f, U"a byte.");
@@ -665,7 +668,7 @@ int bingeti1 (FILE *f) {
 	}
 }
 
-void binputi1 (int u, FILE *f) {
+void binputi8 (int u, FILE *f) {
 	try {
 		if (putc (u, f) < 0) writeError (U"a byte.");
 	} catch (MelderError) {
@@ -673,7 +676,25 @@ void binputi1 (int u, FILE *f) {
 	}
 }
 
-int bingete1 (FILE *f, int min, int max, const char32 *type) {
+bool bingeteb (FILE *f) {
+	try {
+		int externalValue = getc (f);
+		if (externalValue < 0) readError (f, U"a byte.");
+		return (bool) externalValue;   // this converts e.g. 200 to true
+	} catch (MelderError) {
+		Melder_throw (U"Boolean not read from 1 byte in binary file.");
+	}
+}
+
+void binputeb (bool value, FILE *f) {
+	try {
+		if (putc (value, f) < 0) writeError (U"a byte.");
+	} catch (MelderError) {
+		Melder_throw (U"Boolean not written to 1 byte in binary file.");
+	}
+}
+
+int bingete8 (FILE *f, int min, int max, const char32 *type) {
 	try {
 		int externalValue = getc (f);
 		if (externalValue < 0) readError (f, U"a byte.");
@@ -686,7 +707,7 @@ int bingete1 (FILE *f, int min, int max, const char32 *type) {
 	}
 }
 
-void binpute1 (int value, FILE *f) {
+void binpute8 (int value, FILE *f) {
 	try {
 		if (putc (value, f) < 0) writeError (U"a byte.");
 	} catch (MelderError) {
@@ -719,7 +740,7 @@ macro_bingetb (7)
 
 void bingetb (FILE *f) { (void) f; bitsInReadBuffer = 0; }
 
-int16 bingeti2 (FILE *f) {
+int16 bingeti16 (FILE *f) {
 	try {
 		if (binario_16bitBE && Melder_debug != 18) {
 			int16 s;
@@ -737,7 +758,7 @@ int16 bingeti2 (FILE *f) {
 	}
 }
 
-int16 bingeti2LE (FILE *f) {
+int16 bingeti16LE (FILE *f) {
 	try {
 		if (binario_16bitLE && Melder_debug != 18) {
 			int16 s;
@@ -755,7 +776,7 @@ int16 bingeti2LE (FILE *f) {
 	}
 }
 
-uint16 bingetu2 (FILE *f) {
+uint16 bingetu16 (FILE *f) {
 	try {
 		if (binario_16bitBE && Melder_debug != 18) {
 			uint16 s;
@@ -773,7 +794,7 @@ uint16 bingetu2 (FILE *f) {
 	}
 }
 
-uint16 bingetu2LE (FILE *f) {
+uint16 bingetu16LE (FILE *f) {
 	try {
 		if (binario_16bitLE && Melder_debug != 18) {
 			uint16 s;
@@ -812,7 +833,7 @@ int bingete2 (FILE *f, int min, int max, const char32 *type) {
 	}
 }
 
-int32 bingeti3 (FILE *f) {
+int32 bingeti24 (FILE *f) {
 	try {
 		uint8 bytes [3];
 		if (fread (bytes, sizeof (uint8), 3, f) != 3) readError (f, U"three bytes.");
@@ -828,7 +849,7 @@ int32 bingeti3 (FILE *f) {
 	}
 }
 
-int32 bingeti3LE (FILE *f) {
+int32 bingeti24LE (FILE *f) {
 	try {
 		uint8 bytes [3];
 		if (fread (bytes, sizeof (uint8), 3, f) != 3) readError (f, U"three bytes.");
@@ -844,7 +865,7 @@ int32 bingeti3LE (FILE *f) {
 	}
 }
 
-int32 bingeti4 (FILE *f) {
+int32 bingeti32 (FILE *f) {
 	try {
 		if (binario_32bitBE && Melder_debug != 18) {
 			int32 l;
@@ -864,7 +885,7 @@ int32 bingeti4 (FILE *f) {
 	}
 }
 
-int32 bingeti4LE (FILE *f) {
+int32 bingeti32LE (FILE *f) {
 	try {
 		if (binario_32bitLE && Melder_debug != 18) {
 			int32 l;
@@ -884,7 +905,7 @@ int32 bingeti4LE (FILE *f) {
 	}
 }
 
-uint32 bingetu4 (FILE *f) {
+uint32 bingetu32 (FILE *f) {
 	try {
 		if (binario_32bitBE && Melder_debug != 18) {
 			uint32_t l;
@@ -904,7 +925,7 @@ uint32 bingetu4 (FILE *f) {
 	}
 }
 
-uint32 bingetu4LE (FILE *f) {
+uint32 bingetu32LE (FILE *f) {
 	try {
 		if (binario_32bitLE && Melder_debug != 18) {
 			uint32 l;
@@ -924,7 +945,7 @@ uint32 bingetu4LE (FILE *f) {
 	}
 }
 
-double bingetr4 (FILE *f) {
+double bingetr32 (FILE *f) {
 	try {
 		if (binario_floatIEEE4msb && Melder_debug != 18) {
 			float x;
@@ -955,7 +976,7 @@ double bingetr4 (FILE *f) {
 	}
 }
 
-double bingetr4LE (FILE *f) {
+double bingetr32LE (FILE *f) {
 	try {
 		if (binario_floatIEEE4lsb && Melder_debug != 18) {
 			float x;
@@ -986,7 +1007,7 @@ double bingetr4LE (FILE *f) {
 	}
 }
 
-double bingetr8 (FILE *f) {
+double bingetr64 (FILE *f) {
 	try {
 		if (binario_doubleIEEE8msb && Melder_debug != 18) {
 			double x;
@@ -1024,7 +1045,7 @@ double bingetr8 (FILE *f) {
 	}
 }
 
-double bingetr10 (FILE *f) {
+double bingetr80 (FILE *f) {
 	try {
 		uint8 bytes [10];
 		if (fread (bytes, sizeof (uint8), 10, f) != 10) readError (f, U"ten bytes.");
@@ -1082,7 +1103,7 @@ void binputb (FILE *f) {
 	writeBuffer = 0;
 }
 
-void binputi2 (int16 i, FILE *f) {
+void binputi16 (int16 i, FILE *f) {
 	try {
 		if (binario_16bitBE && Melder_debug != 18) {
 			if (fwrite (& i, sizeof (short), 1, f) != 1) writeError (U"a signed 16-bit integer.");
@@ -1097,7 +1118,7 @@ void binputi2 (int16 i, FILE *f) {
 	}
 }
 
-void binputi2LE (int16 i, FILE *f) {
+void binputi16LE (int16 i, FILE *f) {
 	try {
 		if (binario_16bitLE && Melder_debug != 18) {
 			if (fwrite (& i, sizeof (short), 1, f) != 1) writeError (U"a signed 16-bit integer.");
@@ -1112,7 +1133,7 @@ void binputi2LE (int16 i, FILE *f) {
 	}
 }
 
-void binputu2 (uint16 u, FILE *f) {
+void binputu16 (uint16 u, FILE *f) {
 	try {
 		if (binario_16bitBE && Melder_debug != 18) {
 			if (fwrite (& u, sizeof (uint16_t), 1, f) != 1) writeError (U"an unsigned 16-bit integer.");
@@ -1127,7 +1148,7 @@ void binputu2 (uint16 u, FILE *f) {
 	}
 }
 
-void binputu2LE (uint16 u, FILE *f) {
+void binputu16LE (uint16 u, FILE *f) {
 	try {
 		if (binario_16bitLE && Melder_debug != 18) {
 			if (fwrite (& u, sizeof (uint16_t), 1, f) != 1) writeError (U"an unsigned 16-bit integer.");
@@ -1142,7 +1163,7 @@ void binputu2LE (uint16 u, FILE *f) {
 	}
 }
 
-void binpute2 (int value, FILE *f) {
+void binpute16 (int value, FILE *f) {
 	try {
 		if (binario_16bitBE && Melder_debug != 18) {
 			short s = value;
@@ -1158,7 +1179,7 @@ void binpute2 (int value, FILE *f) {
 	}
 }
 
-void binputi3 (int32 i, FILE *f) {
+void binputi24 (int32 i, FILE *f) {
 	try {
 		char bytes [3];
 		bytes [0] = (char) (i >> 16);   // truncate
@@ -1170,7 +1191,7 @@ void binputi3 (int32 i, FILE *f) {
 	}
 }
 
-void binputi3LE (int32 i, FILE *f) {
+void binputi24LE (int32 i, FILE *f) {
 	try {
 		char bytes [3];
 		bytes [2] = (char) (i >> 16);   // truncate
@@ -1182,7 +1203,7 @@ void binputi3LE (int32 i, FILE *f) {
 	}
 }
 
-void binputi4 (int32 i, FILE *f) {
+void binputi32 (int32 i, FILE *f) {
 	try {
 		if (binario_32bitBE && Melder_debug != 18) {
 			if (fwrite (& i, sizeof (int32), 1, f) != 1) writeError (U"a signed 32-bit integer.");
@@ -1199,7 +1220,7 @@ void binputi4 (int32 i, FILE *f) {
 	}
 }
 
-void binputi4LE (int32 i, FILE *f) {
+void binputi32LE (int32 i, FILE *f) {
 	try {
 		if (binario_32bitLE && Melder_debug != 18) {
 			if (fwrite (& i, sizeof (int32), 1, f) != 1) writeError (U"a signed 32-bit integer.");
@@ -1216,7 +1237,7 @@ void binputi4LE (int32 i, FILE *f) {
 	}
 }
 
-void binputu4 (uint32 u, FILE *f) {
+void binputu32 (uint32 u, FILE *f) {
 	try {
 		if (binario_32bitBE && Melder_debug != 18) {
 			if (fwrite (& u, sizeof (uint32), 1, f) != 1) writeError (U"an unsigned 32-bit integer.");
@@ -1233,7 +1254,7 @@ void binputu4 (uint32 u, FILE *f) {
 	}
 }
 
-void binputu4LE (uint32 u, FILE *f) {
+void binputu32LE (uint32 u, FILE *f) {
 	try {
 		if (binario_32bitLE && Melder_debug != 18) {
 			if (fwrite (& u, sizeof (uint32), 1, f) != 1) writeError (U"an unsigned 32-bit integer.");
@@ -1250,7 +1271,7 @@ void binputu4LE (uint32 u, FILE *f) {
 	}
 }
 
-void binputr4 (double x, FILE *f) {
+void binputr32 (double x, FILE *f) {
 	try {
 		if (binario_floatIEEE4msb && Melder_debug != 18) {
 			float x4 = (float) x;   // convert down, with loss of precision
@@ -1290,7 +1311,7 @@ void binputr4 (double x, FILE *f) {
 	}
 }
 
-void binputr4LE (double x, FILE *f) {
+void binputr32LE (double x, FILE *f) {
 	try {
 		if (binario_floatIEEE4lsb && Melder_debug != 18) {
 			float x4 = (float) x;   // convert down, with loss of precision
@@ -1330,7 +1351,7 @@ void binputr4LE (double x, FILE *f) {
 	}
 }
 
-void binputr8 (double x, FILE *f) {
+void binputr64 (double x, FILE *f) {
 	try {
 		if (binario_doubleIEEE8msb && Melder_debug != 18) {
 			if (fwrite (& x, sizeof (double), 1, f) != 1) writeError (U"a 64-bit floating-point number.");
@@ -1376,7 +1397,7 @@ void binputr8 (double x, FILE *f) {
 	}
 }
 
-void binputr10 (double x, FILE *f) {
+void binputr80 (double x, FILE *f) {
 	try {
 		unsigned char bytes [10];
 		Melder_assert (sizeof (int) > 2);
@@ -1421,53 +1442,53 @@ void binputr10 (double x, FILE *f) {
 	}
 }
 
-fcomplex bingetc8 (FILE *f) {
+fcomplex bingetc64 (FILE *f) {
 	try {
 		fcomplex result;
-		result. re = bingetr4 (f);
-		result. im = bingetr4 (f);
+		result. re = bingetr32 (f);
+		result. im = bingetr32 (f);
 		return result;
 	} catch (MelderError) {
 		Melder_throw (U"Complex number not read from 8 bytes in binary file.");
-		fcomplex result = { 0 };
+		fcomplex result { };
 		return result;
 	}
 }
 
-dcomplex bingetc16 (FILE *f) {
+dcomplex bingetc128 (FILE *f) {
 	try {
 		dcomplex result;
-		result. re = bingetr8 (f);
-		result. im = bingetr8 (f);
+		result. re = bingetr64 (f);
+		result. im = bingetr64 (f);
 		return result;
 	} catch (MelderError) {
 		Melder_throw (U"Complex number not read from 16 bytes in binary file.");
-		dcomplex result = { 0 };
+		dcomplex result { };
 		return result;
 	}
 }
 
-void binputc8 (fcomplex z, FILE *f) {
+void binputc64 (fcomplex z, FILE *f) {
 	try {
-		binputr4 (z. re, f);
-		binputr4 (z. im, f);
+		binputr32 (z. re, f);
+		binputr32 (z. im, f);
 	} catch (MelderError) {
 		Melder_throw (U"Complex number not written to 8 bytes in binary file.");
 	}
 }
 
-void binputc16 (dcomplex z, FILE *f) {
+void binputc128 (dcomplex z, FILE *f) {
 	try {
-		binputr8 (z. re, f);
-		binputr8 (z. im, f);
+		binputr64 (z. re, f);
+		binputr64 (z. im, f);
 	} catch (MelderError) {
 		Melder_throw (U"Complex number not written to 16 bytes in binary file.");
 	}
 }
 
-char * bingets1 (FILE *f) {
+char * bingets8 (FILE *f) {
 	try {
-		unsigned int length = bingetu1 (f);
+		unsigned int length = bingetu8 (f);
 		autostring8 result = Melder_malloc (char, length + 1);
 		if (fread (result.peek(), sizeof (char), length, f) != length)
 			Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", length, U" one-byte characters.");
@@ -1478,9 +1499,9 @@ char * bingets1 (FILE *f) {
 	}
 }
 
-char * bingets2 (FILE *f) {
+char * bingets16 (FILE *f) {
 	try {
-		uint16_t length = bingetu2 (f);
+		uint16_t length = bingetu16 (f);
 		autostring8 result = Melder_malloc (char, (int64) length + 1);
 		if (fread (result.peek(), sizeof (char), length, f) != length)
 			Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", length, U" one-byte characters.");
@@ -1491,9 +1512,9 @@ char * bingets2 (FILE *f) {
 	}
 }
 
-char * bingets4 (FILE *f) {
+char * bingets32 (FILE *f) {
 	try {
-		uint32_t length = bingetu4 (f);
+		uint32_t length = bingetu32 (f);
 		autostring8 result = Melder_malloc (char, (int64) length + 1);
 		if (fread (result.peek(), sizeof (char), length, f) != length)
 			Melder_throw (feof (f) ? U"Reached end of file" : U"Error in file", U" while trying to read ", length, U" one-byte characters.");
@@ -1504,22 +1525,22 @@ char * bingets4 (FILE *f) {
 	}
 }
 
-char32 * bingetw1 (FILE *f) {
+char32 * bingetw8 (FILE *f) {
 	try {
 		autostring32 result;
-		unsigned short length = bingetu1 (f);
+		unsigned short length = bingetu8 (f);
 		if (length == 0xFF) {   // an escape for encoding
 			/*
 			 * UTF-16
 			 */
-			length = bingetu1 (f);
+			length = bingetu8 (f);
 			result.reset (Melder_malloc (char32, (int64) length + 1));
 			for (unsigned short i = 0; i < length; i ++) {
-				char32 kar = bingetu2 (f);
+				char32 kar = bingetu16 (f);
 				if ((kar & 0x00F800) == 0x00D800) {
 					if (kar > 0x00DBFF)
 						Melder_throw (U"Incorrect Unicode value (first surrogate member ", kar, U").");
-					char32 kar2 = bingetu2 (f);
+					char32 kar2 = bingetu16 (f);
 					if (kar2 < 0x00DC00 || kar2 > 0x00DFFF)
 						Melder_throw (U"Incorrect Unicode value (second surrogate member ", kar2, U").");
 					result [i] = (((kar & 0x0003FF) << 10) | (kar2 & 0x0003FF)) + 0x010000;
@@ -1533,7 +1554,7 @@ char32 * bingetw1 (FILE *f) {
 			 */
 			result.reset (Melder_malloc (char32, (int64) length + 1));
 			for (unsigned short i = 0; i < length; i ++) {
-				result [i] = bingetu1 (f);
+				result [i] = bingetu8 (f);
 			}
 		}
 		result [length] = U'\0';
@@ -1543,22 +1564,22 @@ char32 * bingetw1 (FILE *f) {
 	}
 }
 
-char32 * bingetw2 (FILE *f) {
+char32 * bingetw16 (FILE *f) {
 	try {
 		autostring32 result;
-		uint16 length = bingetu2 (f);
+		uint16 length = bingetu16 (f);
 		if (length == 0xFFFF) {   // an escape for encoding
 			/*
 			 * UTF-16
 			 */
-			length = bingetu2 (f);
+			length = bingetu16 (f);
 			result.reset (Melder_malloc (char32, (int64) length + 1));
 			for (uint16 i = 0; i < length; i ++) {
-				char32 kar = (char32) (char16) bingetu2 (f);
+				char32 kar = (char32) (char16) bingetu16 (f);
 				if ((kar & 0x00F800) == 0x00D800) {
 					if (kar > 0x00DBFF)
 						Melder_throw (U"Incorrect Unicode value (first surrogate member ", kar, U").");
-					char32 kar2 = (char32) (char16) bingetu2 (f);
+					char32 kar2 = (char32) (char16) bingetu16 (f);
 					if (kar2 < 0x00DC00 || kar2 > 0x00DFFF)
 						Melder_throw (U"Incorrect Unicode value (second surrogate member ", kar2, U").");
 					result [i] = (((kar & 0x0003FF) << 10) | (kar2 & 0x0003FF)) + 0x010000;
@@ -1572,7 +1593,7 @@ char32 * bingetw2 (FILE *f) {
 			 */
 			result.reset (Melder_malloc (char32, length + 1));
 			for (unsigned short i = 0; i < length; i ++) {
-				result [i] = (char32) (char8) bingetu1 (f);
+				result [i] = (char32) (char8) bingetu8 (f);
 			}
 		}
 		result [length] = U'\0';
@@ -1582,22 +1603,22 @@ char32 * bingetw2 (FILE *f) {
 	}
 }
 
-char32 * bingetw4 (FILE *f) {
+char32 * bingetw32 (FILE *f) {
 	try {
 		autostring32 result;
-		uint32 length = bingetu4 (f);
+		uint32 length = bingetu32 (f);
 		if (length == 0xFFFFFFFF) {   // an escape for encoding
 			/*
 			 * UTF-16
 			 */
-			length = bingetu4 (f);
+			length = bingetu32 (f);
 			result.reset (Melder_malloc (char32, (int64) length + 1));
 			for (uint32 i = 0; i < length; i ++) {
-				char32 kar = bingetu2 (f);
+				char32 kar = bingetu16 (f);
 				if ((kar & 0x00F800) == 0x00D800) {
 					if (kar > 0x00DBFF)
 						Melder_throw (U"Incorrect Unicode value (first surrogate member ", kar, U").");
-					char32 kar2 = bingetu2 (f);
+					char32 kar2 = bingetu16 (f);
 					if (kar2 < 0x00DC00 || kar2 > 0x00DFFF)
 						Melder_throw (U"Incorrect Unicode value (second surrogate member ", kar2, U").");
 					result [i] = (((kar & 0x0003FF) << 10) | (kar2 & 0x0003FF)) + 0x010000;
@@ -1611,7 +1632,7 @@ char32 * bingetw4 (FILE *f) {
 			 */
 			result.reset (Melder_malloc (char32, (int64) length + 1));
 			for (uint32 i = 0; i < length; i ++) {
-				result [i] = bingetu1 (f);
+				result [i] = bingetu8 (f);
 			}
 		}
 		result [length] = U'\0';
@@ -1621,17 +1642,17 @@ char32 * bingetw4 (FILE *f) {
 	}
 }
 
-void binputs1 (const char *s, FILE *f) {
+void binputs8 (const char *s, FILE *f) {
 	try {
 		if (! s) {
-			binputu1 (0, f);
+			binputu8 (0, f);
 		} else {
 			size_t length = strlen (s);
 			if (length > UINT8_MAX) {
 				Melder_warning (U"Text of ", length, U" characters truncated to 255 characters.");
 				length = UINT8_MAX;
 			}
-			binputu1 (length, f);
+			binputu8 (length, f);
 			if (fwrite (s, sizeof (char), length, f) != length)
 				Melder_throw (U"Error in file while trying to write ", length, U" one-byte characters.");
 		}
@@ -1640,17 +1661,17 @@ void binputs1 (const char *s, FILE *f) {
 	}
 }
 
-void binputs2 (const char *s, FILE *f) {
+void binputs16 (const char *s, FILE *f) {
 	try {
 		if (! s) {
-			binputu2 (0, f);
+			binputu16 (0, f);
 		} else {
 			size_t length = strlen (s);
 			if (length > UINT16_MAX) {
 				Melder_warning (U"Text of ", length, U" characters truncated to 65535 characters.");
 				length = UINT16_MAX;
 			}
-			binputu2 ((uint16_t) length, f);   // safe conversion down
+			binputu16 ((uint16_t) length, f);   // safe conversion down
 			if (fwrite (s, sizeof (char), length, f) != length)
 				Melder_throw (U"Error in file while trying to write ", length, U" one-byte characters.");
 		}
@@ -1659,17 +1680,17 @@ void binputs2 (const char *s, FILE *f) {
 	}
 }
 
-void binputs4 (const char *s, FILE *f) {
+void binputs32 (const char *s, FILE *f) {
 	try {
 		if (! s) {
-			binputu4 (0, f);
+			binputu32 (0, f);
 		} else {
 			size_t length = strlen (s);
 			if (length > UINT32_MAX) {
 				Melder_warning (U"Text of ", length, U" characters truncated to 4,294,967,295 characters.");
 				length = UINT32_MAX;
 			}
-			binputu4 (length, f);
+			binputu32 (length, f);
 			if (fwrite (s, sizeof (char), length, f) != length)
 				Melder_throw (U"Error in file while trying to write ", length, U" one-byte characters.");
 		}
@@ -1680,20 +1701,20 @@ void binputs4 (const char *s, FILE *f) {
 
 static inline void binpututf16 (char32 kar, FILE *f) {
 	if (kar <= 0x00FFFF) {
-		binputu2 ((uint16) kar, f);   // truncate to lower 16 bits
+		binputu16 ((uint16) kar, f);   // truncate to lower 16 bits
 	} else if (kar <= 0x10FFFF) {
 		kar -= 0x010000;
-		binputu2 ((uint16) (0x00D800 | (kar >> 10)), f);
-		binputu2 ((uint16) (0x00DC00 | (kar & 0x0003FF)), f);
+		binputu16 ((uint16) (0x00D800 | (kar >> 10)), f);
+		binputu16 ((uint16) (0x00DC00 | (kar & 0x0003FF)), f);
 	} else {
 		Melder_fatal (U"Impossible Unicode value.");
 	}
 }
 
-void binputw1 (const char32 *s, FILE *f) {
+void binputw8 (const char32 *s, FILE *f) {
 	try {
 		if (! s) {
-			binputu1 (0, f);
+			binputu8 (0, f);
 		} else {
 			uint32 length = str32len (s);
 			if (length > UINT8_MAX - 1) {
@@ -1704,16 +1725,16 @@ void binputw1 (const char32 *s, FILE *f) {
 				/*
 				 * ASCII
 				 */
-				binputu1 (length, f);
+				binputu8 (length, f);
 				for (size_t i = 0; i < length; i ++) {
-					binputu1 ((unsigned int) (char) s [i], f);
+					binputu8 ((unsigned int) (char) s [i], f);
 				}
 			} else {
 				/*
 				 * UTF-16
 				 */
-				binputu1 (0xFF, f);   // an escape for multibyte encoding
-				binputu1 (length, f);
+				binputu8 (0xFF, f);   // an escape for multibyte encoding
+				binputu8 (length, f);
 				for (size_t i = 0; i < length; i ++) {
 					binpututf16 (s [i], f);
 				}
@@ -1724,10 +1745,10 @@ void binputw1 (const char32 *s, FILE *f) {
 	}
 }
 
-void binputw2 (const char32 *s, FILE *f) {
+void binputw16 (const char32 *s, FILE *f) {
 	try {
 		if (! s) {
-			binputu2 (0, f);
+			binputu16 (0, f);
 		} else {
 			int64 length = str32len (s);
 			if (length > UINT16_MAX - 1) {
@@ -1738,16 +1759,16 @@ void binputw2 (const char32 *s, FILE *f) {
 				/*
 				 * ASCII
 				 */
-				binputu2 ((uint16) length, f);
+				binputu16 ((uint16) length, f);
 				for (int64 i = 0; i < length; i ++) {
-					binputu1 ((unsigned int) (char8) s [i], f);
+					binputu8 ((unsigned int) (char8) s [i], f);
 				}
 			} else {
 				/*
 				 * UTF-16
 				 */
-				binputu2 (0xFFFF, f);   // an escape for multibyte encoding
-				binputu2 ((uint16) length, f);
+				binputu16 (0xFFFF, f);   // an escape for multibyte encoding
+				binputu16 ((uint16) length, f);
 				for (int64 i = 0; i < length; i ++) {
 					binpututf16 (s [i], f);
 				}
@@ -1758,10 +1779,10 @@ void binputw2 (const char32 *s, FILE *f) {
 	}
 }
 
-void binputw4 (const char32 *s, FILE *f) {
+void binputw32 (const char32 *s, FILE *f) {
 	try {
 		if (! s) {
-			binputu4 (0, f);
+			binputu32 (0, f);
 		} else {
 			int64 length = str32len (s);
 			if (length > UINT32_MAX - 1) {
@@ -1772,16 +1793,16 @@ void binputw4 (const char32 *s, FILE *f) {
 				/*
 				 * ASCII
 				 */
-				binputu4 ((uint32) length, f);
+				binputu32 ((uint32) length, f);
 				for (int64 i = 0; i < length; i ++) {
-					binputu1 ((unsigned int) (char) s [i], f);
+					binputu8 ((unsigned int) (char) s [i], f);
 				}
 			} else {
 				/*
 				 * UTF-16
 				 */
-				binputu4 (0xFFFFFFFF, f);   // an escape for multibyte encoding
-				binputu4 ((uint32) length, f);
+				binputu32 (0xFFFFFFFF, f);   // an escape for multibyte encoding
+				binputu32 ((uint32) length, f);
 				for (int64 i = 0; i < length; i ++) {
 					binpututf16 (s [i], f);
 				}
diff --git a/sys/abcio.h b/sys/abcio.h
index 2222718..788981a 100644
--- a/sys/abcio.h
+++ b/sys/abcio.h
@@ -2,7 +2,7 @@
 #define _abcio_h_
 /* abcio.h
  *
- * Copyright (C) 1992-2011,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,55 +25,52 @@
 
 /* Numeric text input and output. */
 
-int texgeti1 (MelderReadText text);
-int texgeti2 (MelderReadText text);
-long texgeti32 (MelderReadText text);
-#define texgeti4 texgeti32
-unsigned int texgetu1 (MelderReadText text);
-unsigned int texgetu2 (MelderReadText text);
-unsigned long texgetu4 (MelderReadText text);
-double texgetr4 (MelderReadText text);
-double texgetr8 (MelderReadText text);
-double texgetr10 (MelderReadText text);
-fcomplex texgetc8 (MelderReadText text);
-dcomplex texgetc16 (MelderReadText text);
-short texgete1 (MelderReadText text, int (*getValue) (const char32 *));
-short texgete2 (MelderReadText text, int (*getValue) (const char32 *));
-short texgeteb (MelderReadText text);
-short texgeteq (MelderReadText text);
-short texgetex (MelderReadText text);
-char *texgets2 (MelderReadText text);
-char *texgets4 (MelderReadText text);
-char32 *texgetw2 (MelderReadText text);
-char32 *texgetw4 (MelderReadText text);
+int texgeti8 (MelderReadText text);
+int16 texgeti16 (MelderReadText text);
+int32 texgeti32 (MelderReadText text);
+unsigned int texgetu8 (MelderReadText text);
+uint16 texgetu16 (MelderReadText text);
+uint32 texgetu32 (MelderReadText text);
+double texgetr32 (MelderReadText text);
+double texgetr64 (MelderReadText text);
+double texgetr80 (MelderReadText text);
+fcomplex texgetc64 (MelderReadText text);
+dcomplex texgetc128 (MelderReadText text);
+short texgete8 (MelderReadText text, int (*getValue) (const char32 *));
+short texgete16 (MelderReadText text, int (*getValue) (const char32 *));
+bool texgeteb (MelderReadText text);
+bool texgeteq (MelderReadText text);
+bool texgetex (MelderReadText text);
+char *texgets16 (MelderReadText text);
+char *texgets32 (MelderReadText text);
+char32 *texgetw16 (MelderReadText text);
+char32 *texgetw32 (MelderReadText text);
 
 void texindent (MelderFile file);
 void texexdent (MelderFile file);
 void texresetindent (MelderFile file);
 void texputintro (MelderFile file, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
 
-void texputi1 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputi2 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputi8 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputi16 (MelderFile file, int i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
 void texputi32 (MelderFile file, long i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-#define texputi4 texputi32
-void texputu1 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputu2 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputu4 (MelderFile file, unsigned long u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputr4 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputr8 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputc8 (MelderFile file, fcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputc16 (MelderFile file, dcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texpute1 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texpute2 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputu8 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputu16 (MelderFile file, unsigned int u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputu32 (MelderFile file, unsigned long u, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputr32 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputr64 (MelderFile file, double x, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputc64 (MelderFile file, fcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputc128 (MelderFile file, dcomplex z, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texpute8 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texpute16 (MelderFile file, int i, const char32 * (*getText) (int), const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
 void texputeb (MelderFile file, bool i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
 void texputeq (MelderFile file, bool i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
 void texputex (MelderFile file, bool i, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputs1 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputs2 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputs4 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputw2 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputw2 (MelderFile file, const char32  *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
-void texputw4 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputs8 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputs16 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputs32 (MelderFile file, const char *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputw16 (MelderFile file, const char32  *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
+void texputw32 (MelderFile file, const char32 *s, const char32 *s1, const char32 *s2, const char32 *s3, const char32 *s4, const char32 *s5, const char32 *s6);
 
 /* Portable device-independent binary input and output. */
 /* Works on all machines with 8-bit bytes and chars, and 2's complement integers. */
@@ -82,27 +79,25 @@ void texputw4 (MelderFile file, const char32 *s, const char32 *s1, const char32
 	The 42 routines are analogous to fgetc and fputc, who read or write one character:
 		int fgetc (FILE *f);   int fputc (int c, FILE *f);   // 0..255
 */
-unsigned int bingetu1 (FILE *f);   void binputu1 (unsigned int i, FILE *f);   // 0..255
-uint16 bingetu2 (FILE *f);   void binputu2 (uint16 i, FILE *f);   // 0..65535
-uint32 bingetu4 (FILE *f);   void binputu4 (uint32 i, FILE *f);   // 0..4294967295
+unsigned int bingetu8 (FILE *f);   void binputu8 (unsigned int i, FILE *f);   // 0..255
+uint16 bingetu16 (FILE *f);   void binputu16 (uint16 i, FILE *f);   // 0..65535
+uint32 bingetu32 (FILE *f);   void binputu32 (uint32 i, FILE *f);   // 0..4294967295
 
-int bingeti1 (FILE *f);   void binputi1 (int i, FILE *f);   /* -128..127 */
-int16 bingeti2 (FILE *f);   void binputi2 (int16 i, FILE *f);   // -32768..32767
-int32 bingeti3 (FILE *f);   void binputi3 (int32 i, FILE *f);   // -8388608..8388607
+int bingeti8 (FILE *f);   void binputi8 (int i, FILE *f);   /* -128..127 */
+int16 bingeti16 (FILE *f);   void binputi16 (int16 i, FILE *f);   // -32768..32767
+int32 bingeti24 (FILE *f);   void binputi24 (int32 i, FILE *f);   // -8388608..8388607
 int32 bingeti32 (FILE *f);   void binputi32 (int32 i, FILE *f);   // -2147483648..2147483647
-#define bingeti4 bingeti32
-#define binputi4 binputi32
 /*
 	Read or write signed or unsigned integers from or to 2 or 4 bytes in the stream 'f',
 	in big-endian byte order (most significant byte first).
 	This is the native integer format on Macintosh and Silicon Graphics Iris.
 */
 
-int16 bingeti2LE (FILE *f);   void binputi2LE (int16 i, FILE *f);   // -32768..32767
-int32 bingeti3LE (FILE *f);   void binputi3LE (int32 i, FILE *f);   // -8388608..8388607
-int32 bingeti4LE (FILE *f);   void binputi4LE (int32 i, FILE *f);   // -2147483648..2147483647
-uint16 bingetu2LE (FILE *f);   void binputu2LE (uint16 i, FILE *f);   // 0..65535
-uint32 bingetu4LE (FILE *f);   void binputu4LE (uint32 i, FILE *f);   // 0..4294967295
+int16 bingeti16LE (FILE *f);   void binputi16LE (int16 i, FILE *f);   // -32768..32767
+int32 bingeti24LE (FILE *f);   void binputi24LE (int32 i, FILE *f);   // -8388608..8388607
+int32 bingeti32LE (FILE *f);   void binputi32LE (int32 i, FILE *f);   // -2147483648..2147483647
+uint16 bingetu16LE (FILE *f);   void binputu16LE (uint16 i, FILE *f);   // 0..65535
+uint32 bingetu32LE (FILE *f);   void binputu32LE (uint32 i, FILE *f);   // 0..4294967295
 /*
 	Read or write signed or unsigned integers from or to 2 or 4 bytes in the stream 'f',
 	in little-endian byte order (least significant byte first).
@@ -133,19 +128,19 @@ void bingetb (FILE *f);   void binputb (FILE *f);
 		binputb (f);
 */
 
-int bingete1 (FILE *f, int min, int max, const char32 *type);
-int bingete2 (FILE *f, int min, int max, const char32 *type);
-#define bingeteb bingeti1
-#define bingeteq bingeti1
-#define bingetex bingeti1
+int bingete8 (FILE *f, int min, int max, const char32 *type);
+int bingete16 (FILE *f, int min, int max, const char32 *type);
+bool bingeteb (FILE *f);
+#define bingeteq bingeteb
+#define bingetex bingeteb
 
-void binpute1 (int value, FILE *f);
-void binpute2 (int value, FILE *f);
-#define binputeb binputi1
-#define binputeq binputi1
-#define binputex binputi1
+void binpute8 (int value, FILE *f);
+void binpute16 (int value, FILE *f);
+void binputeb (bool value, FILE *f);
+#define binputeq binputeb
+#define binputex binputeb
 
-double bingetr4 (FILE *f);   void binputr4 (double x, FILE *f);
+double bingetr32 (FILE *f);   void binputr32 (double x, FILE *f);
 /*
 	Read or write a real number from or to 4 bytes in the stream `f`,
 	in IEEE single-precision binary real format, with the most significant bit first.
@@ -154,9 +149,9 @@ double bingetr4 (FILE *f);   void binputr4 (double x, FILE *f);
 	Denormalized: from 1.4e-45.
 	This is the native format of a `float` on Macintosh and Silicon Graphics Iris.
 */
-double bingetr4LE (FILE *f);   void binputr4LE (double x, FILE *f);   // least significant bit first
+double bingetr32LE (FILE *f);   void binputr32LE (double x, FILE *f);   // least significant bit first
 
-double bingetr8 (FILE *f);   void binputr8 (double x, FILE *f);
+double bingetr64 (FILE *f);   void binputr64 (double x, FILE *f);
 /*
 	Read or write a real number from or to 8 bytes in the stream `f`,
 	in IEEE double-precision binary real format, with the most significant bit first.
@@ -166,7 +161,7 @@ double bingetr8 (FILE *f);   void binputr8 (double x, FILE *f);
 	This is the native format of a `double` on Silicon Graphics Iris and PowerMac.
 */
 
-double bingetr10 (FILE *f);   void binputr10 (double x, FILE *f);
+double bingetr80 (FILE *f);   void binputr80 (double x, FILE *f);
 /*
 	Read or write a real number from or to 10 bytes in the stream `f`,
 	in IEEE extended-precision binary real format, with the most significant bit first,
@@ -178,14 +173,14 @@ double bingetr10 (FILE *f);   void binputr10 (double x, FILE *f);
 	and is the native format of a `double` on 68k Macintosh.
 */
 
-fcomplex bingetc8 (FILE *f);
-dcomplex bingetc16 (FILE *f);
-void binputc8 (fcomplex z, FILE *f);
-void binputc16 (dcomplex z, FILE *f);
+fcomplex bingetc64 (FILE *f);
+dcomplex bingetc128 (FILE *f);
+void binputc64 (fcomplex z, FILE *f);
+void binputc128 (dcomplex z, FILE *f);
 
-char * bingets1 (FILE *f);   void binputs1 (const char *s, FILE *f);   // 0..255 characters
-char * bingets2 (FILE *f);   void binputs2 (const char *s, FILE *f);   // 0..65535 characters
-char * bingets4 (FILE *f);   void binputs4 (const char *s, FILE *f);   // 0..4294967295 characters
+char * bingets8 (FILE *f);   void binputs8 (const char *s, FILE *f);   // 0..255 characters
+char * bingets16 (FILE *f);   void binputs16 (const char *s, FILE *f);   // 0..65535 characters
+char * bingets32 (FILE *f);   void binputs32 (const char *s, FILE *f);   // 0..4294967295 characters
 /*
 	Read or write a string from or to `str32len(s)` UTF-16LE or ASCII characters plus 1, 2, or 4 bytes in the stream `f`,
 	in a Pascal-style format: first the length, then the characters, without a trailing null byte.
@@ -193,9 +188,9 @@ char * bingets4 (FILE *f);   void binputs4 (const char *s, FILE *f);   // 0..429
 	Fail if out of memory.
 	binputsxxx expects a null-terminated C string whose `str32len` fits in 1, 2, or 4 bytes.
 */
-char32 * bingetw1 (FILE *f);   void binputw1 (const char32 *s, FILE *f);
-char32 * bingetw2 (FILE *f);   void binputw2 (const char32 *s, FILE *f);
-char32 * bingetw4 (FILE *f);   void binputw4 (const char32 *s, FILE *f);
+char32 * bingetw8 (FILE *f);   void binputw8 (const char32 *s, FILE *f);
+char32 * bingetw16 (FILE *f);   void binputw16 (const char32 *s, FILE *f);
+char32 * bingetw32 (FILE *f);   void binputw32 (const char32 *s, FILE *f);
 
 /* End of file abcio.h */
 #endif
diff --git a/sys/complex.h b/sys/complex.h
index 1f06769..bc7f966 100644
--- a/sys/complex.h
+++ b/sys/complex.h
@@ -2,7 +2,7 @@
 #define _complex_h_
 /* complex.h
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,8 +18,8 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-typedef struct fcomplex { float re, im; } fcomplex;
-typedef struct dcomplex { double re, im; } dcomplex;
+struct fcomplex { float re, im; };
+struct dcomplex { double re, im; };
 
 /*
  * Stack-based complex arithmetic.
diff --git a/sys/enums_getValue.h b/sys/enums_getValue.h
index 5ebdbc3..fb079dd 100644
--- a/sys/enums_getValue.h
+++ b/sys/enums_getValue.h
@@ -1,6 +1,6 @@
 /* enums_getValue.h
  *
- * Copyright (C) 2007-2009,2015 Paul Boersma
+ * Copyright (C) 2007-2009,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,8 +25,8 @@
 #undef enums_alt
 #undef enums_end
 #define enums_begin(type,minimum)  int type##_getValue (const char32 *testText) {
-#define enums_add(type,value,which,text)  if (Melder_str32equ_firstCharacterCaseInsensitive (testText, text)) return type##_##which;
-#define enums_alt(type,which,text)  if (Melder_str32equ_firstCharacterCaseInsensitive (testText, text)) return type##_##which;
+#define enums_add(type,value,which,text)  if (Melder_equ_firstCharacterCaseInsensitive (testText, text)) return type##_##which;
+#define enums_alt(type,which,text)  if (Melder_equ_firstCharacterCaseInsensitive (testText, text)) return type##_##which;
 #define enums_end(type,maximum,def) \
 	if (str32equ (testText, U"\t")) return type##_DEFAULT; \
 	if (str32equ (testText, U"\n")) return maximum; \
diff --git a/sys/melder.cpp b/sys/melder.cpp
index 55da8f2..c8b25f7 100644
--- a/sys/melder.cpp
+++ b/sys/melder.cpp
@@ -125,7 +125,7 @@ static void _Melder_progress (double progress, const char32 *message) {
 	}
 }
 
-static MelderString theProgressBuffer = { 0 };
+static MelderString theProgressBuffer { };
 
 void Melder_progress (double progress) {
 	_Melder_progress (progress, U"");
diff --git a/sys/melder.h b/sys/melder.h
index c70efa7..980b6af 100644
--- a/sys/melder.h
+++ b/sys/melder.h
@@ -21,10 +21,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-	#define strequ  ! strcmp
-	#define strnequ  ! strncmp
-	#define Melder_equ  ! Melder_cmp
-	#define Melder_nequ  ! Melder_ncmp
 #include <stdarg.h>
 #include <stddef.h>
 #include <wchar.h>
@@ -34,33 +30,47 @@
 #endif
 #include <stdbool.h>
 #include <functional>
+
+#pragma mark - INTEGERS
 /*
  * The following two lines are for obsolete (i.e. C99) versions of stdint.h
  */
 #define __STDC_LIMIT_MACROS
 #define __STDC_CONSTANT_MACROS
 #include <stdint.h>
-#ifndef INT54_MAX
-	#define INT54_MAX   9007199254740991LL
-	#define INT54_MIN  -9007199254740991LL
-#endif
-
-typedef unsigned char char8;
-typedef char16_t char16;
-typedef char32_t char32;
 typedef int8_t int8;
 typedef int16_t int16;
 typedef int32_t int32;
 typedef int64_t int64;
+typedef intptr_t integer;   // the default size of an integer (a "long" is only 32 bits on 64-bit Windows)
+typedef uintptr_t uinteger;
 typedef uint8_t uint8;
 typedef uint16_t uint16;
 typedef uint32_t uint32;
+typedef uint64_t uint64;
+#ifndef INT12_MAX
+	#define INT12_MAX   2047
+	#define INT12_MIN  -2048
+#endif
+#ifndef UINT12_MAX
+	#define UINT12_MAX   4096
+#endif
+#ifndef INT24_MAX
+	#define INT24_MAX   8388607
+	#define INT24_MIN  -8388608
+#endif
+#ifndef UINT24_MAX
+	#define UINT24_MAX   16777216
+#endif
+/*
+	The bounds of the contiguous set of integers that in a "double" can represent only themselves.
+*/
+#ifndef INT54_MAX
+	#define INT54_MAX   9007199254740991LL
+	#define INT54_MIN  -9007199254740991LL
+#endif
 
-bool Melder_str32equ_firstCharacterCaseInsensitive (const char32 *string1, const char32 *string2);
-
-#include "enums.h"
-
-#include "melder_enums.h"
+#pragma mark - BOOLEANS
 
 #ifndef TRUE
 	#define TRUE  1
@@ -72,9 +82,27 @@ bool Melder_str32equ_firstCharacterCaseInsensitive (const char32 *string1, const
 	#define NULL  ((void *) 0)
 #endif
 
+#pragma mark - REALS
 /*
- * Debugging.
- */
+	The following are checked in praat.h.
+*/
+typedef float real32;
+typedef double real64;
+typedef long double real80;   // at least 80 bits ("extended") precision, but stored in 96 or 128 bits
+typedef double real;
+
+#pragma mark - LAW OF DEMETER FOR CLASS FUNCTIONS DEFINED OUTSIDE CLASS DEFINITION
+
+#define our  this ->
+/* The single most useful macro in Praat: */
+#define my  me ->
+#define thy  thee ->
+#define your  you ->
+#define his  him ->
+#define her  she ->
+#define iam(klas)  klas me = (klas) void_me
+
+#pragma mark - DEBUGGING
 
 void Melder_assert_ (const char *fileName, int lineNumber, const char *condition);
 	/* Call Melder_fatal with a message based on the following template: */
@@ -83,49 +111,53 @@ void Melder_assert_ (const char *fileName, int lineNumber, const char *condition
 void Melder_setTracing (bool tracing);
 extern bool Melder_isTracing;
 
-/*
- * char16 handling.
- */
-inline static int64 str16len (const char16 *string) {
+#pragma mark - STRINGS
+
+typedef unsigned char char8;
+typedef char16_t char16;
+typedef char32_t char32;
+
+#define strequ  ! strcmp
+#define strnequ  ! strncmp
+
+inline static int64 str16len (const char16 *string) noexcept {
 	const char16 *p = string;
 	while (*p != u'\0') ++ p;
 	return (int64) (p - string);
 }
-inline static char16 * str16cpy (char16 *target, const char16 *source) {
+inline static char16 * str16cpy (char16 *target, const char16 *source) noexcept {
 	char16 *p = target;
 	while (* source != u'\0') * p ++ = * source ++;
 	*p = u'\0';
 	return target;
 }
-/*
- * char32 handling.
- */
-inline static int64 str32len (const char32 *string) {
+
+inline static int64 str32len (const char32 *string) noexcept {
 	const char32 *p = string;
 	while (*p != U'\0') ++ p;
 	return (int64) (p - string);
 }
-inline static char32 * str32cpy (char32 *target, const char32 *source) {
+inline static char32 * str32cpy (char32 *target, const char32 *source) noexcept {
 	char32 *p = target;
 	while (* source != U'\0') * p ++ = * source ++;
 	*p = U'\0';
 	return target;
 }
-inline static char32 * str32ncpy (char32 *target, const char32 *source, int64 n) {
+inline static char32 * str32ncpy (char32 *target, const char32 *source, int64 n) noexcept {
 	char32 *p = target;
 	for (; n > 0 && *source != U'\0'; -- n) * p ++ = * source ++;
 	for (; n > 0; -- n) * p ++ = U'\0';
 	return target;
 }
-inline static int str32cmp (const char32 *string1, const char32 *string2) {
+
+inline static int str32cmp (const char32 *string1, const char32 *string2) noexcept {
 	for (;; ++ string1, ++ string2) {
 		int32 diff = (int32) *string1 - (int32) *string2;
 		if (diff) return (int) diff;
 		if (*string1 == U'\0') return 0;
 	}
 }
-#define str32equ  ! str32cmp
-inline static int str32ncmp (const char32 *string1, const char32 *string2, int64 n) {
+inline static int str32ncmp (const char32 *string1, const char32 *string2, int64 n) noexcept {
 	for (; n > 0; -- n, ++ string1, ++ string2) {
 		int32 diff = (int32) *string1 - (int32) *string2;
 		if (diff) return (int) diff;
@@ -133,22 +165,30 @@ inline static int str32ncmp (const char32 *string1, const char32 *string2, int64
 	}
 	return 0;
 }
+int Melder_cmp (const char32 *string1, const char32 *string2);   // regards null string as empty string
+int Melder_ncmp (const char32 *string1, const char32 *string2, int64 n);
+
+#define str32equ  ! str32cmp
 #define str32nequ  ! str32ncmp
-inline static char32 * str32chr (const char32 *string, char32 kar) {
+#define Melder_equ  ! Melder_cmp
+bool Melder_equ_firstCharacterCaseInsensitive (const char32 *string1, const char32 *string2);
+#define Melder_nequ  ! Melder_ncmp
+
+inline static char32 * str32chr (const char32 *string, char32 kar) noexcept {
 	for (; *string != kar; ++ string) {
 		if (*string == U'\0')
 			return nullptr;
 	}
 	return (char32 *) string;
 }
-inline static char32 * str32rchr (const char32 *string, char32 kar) {
+inline static char32 * str32rchr (const char32 *string, char32 kar) noexcept {
 	char32 *result = nullptr;
 	for (; *string != U'\0'; ++ string) {
 		if (*string == kar) result = (char32 *) string;
 	}
 	return result;
 }
-inline static char32 * str32str (const char32 *string, const char32 *find) {
+inline static char32 * str32str (const char32 *string, const char32 *find) noexcept {
 	int64 length = str32len (find);
 	if (length == 0) return (char32 *) string;
 	char32 firstCharacter = * find ++;   // optimization
@@ -161,7 +201,7 @@ inline static char32 * str32str (const char32 *string, const char32 *find) {
 	} while (str32ncmp (string, find, length - 1));
 	return (char32 *) (string - 1);
 }
-inline static int64 str32spn (const char32 *string1, const char32 *string2) {
+inline static int64 str32spn (const char32 *string1, const char32 *string2) noexcept {
 	const char32 *p = string1;
 	char32 kar1, kar2;
 cont:
@@ -175,14 +215,13 @@ inline static bool islower32 (char32 kar) { return iswlower ((int) kar); }
 inline static bool isupper32 (char32 kar) { return iswupper ((int) kar); }
 inline static char32 tolower32 (char32 kar) { return (char32) towlower ((int) kar); }
 inline static char32 toupper32 (char32 kar) { return (char32) towupper ((int) kar); }
-extern "C" char * Melder_peek32to8 (const char32 *string);
-inline static long a32tol (const char32 *string) {
-	if (sizeof (wchar_t) == 4) {
-		return wcstol ((const wchar_t *) string, nullptr, 10);
-	} else {
-		return atol (Melder_peek32to8 (string));
-	}
-}
+
+char32 * Melder_tok (char32 *string, const char32 *delimiter);
+
+#pragma mark - ENUMERATED TYPES
+
+#include "enums.h"
+#include "melder_enums.h"
 
 /*
  * Operating system version control.
@@ -192,77 +231,77 @@ inline static long a32tol (const char32 *string) {
 
 typedef struct { double red, green, blue, transparency; } double_rgbt;
 
-/********** NUMBER TO STRING CONVERSION **********/
+#pragma mark - NUMBER TO STRING CONVERSION
 
 /**
-	The following routines return a static string, chosen from a circularly used set of 11 buffers.
-	You can call at most 11 of them in one Melder_casual call, for instance.
+	The following routines return a static string, chosen from a circularly used set of 32 buffers.
+	You can call at most 32 of them in one Melder_casual call, for instance.
 */
 
-const  char32 * Melder_integer  (int64 value);
-const  char   * Melder8_integer (int64 value);
+const  char32 * Melder_integer  (int64 value) noexcept;
+const  char   * Melder8_integer (int64 value) noexcept;
 
-const  char32 * Melder_bigInteger  (int64 value);
-const  char   * Melder8_bigInteger (int64 value);
+const  char32 * Melder_bigInteger  (int64 value) noexcept;
+const  char   * Melder8_bigInteger (int64 value) noexcept;
 
-const  char32 * Melder_boolean  (bool value);
-const  char   * Melder8_boolean (bool value);
+const  char32 * Melder_boolean  (bool value) noexcept;
+const  char   * Melder8_boolean (bool value) noexcept;
 	// "yes" or "no"
 
 /**
 	Format a double value as "--undefined--" or something in the "%.15g", "%.16g", or "%.17g" formats.
 */
-const  char32 * Melder_double  (double value);
-const  char   * Melder8_double (double value);
+const  char32 * Melder_double  (double value) noexcept;
+const  char   * Melder8_double (double value) noexcept;
 
 /**
 	Format a double value as "--undefined--" or something in the "%.9g" format.
 */
-const  char32 * Melder_single  (double value);
-const  char   * Melder8_single (double value);
+const  char32 * Melder_single  (double value) noexcept;
+const  char   * Melder8_single (double value) noexcept;
 
 /**
 	Format a double value as "--undefined--" or something in the "%.4g" format.
 */
-const  char32 * Melder_half  (double value);
-const  char   * Melder8_half (double value);
+const  char32 * Melder_half  (double value) noexcept;
+const  char   * Melder8_half (double value) noexcept;
 
 /**
 	Format a double value as "--undefined--" or something in the "%.*f" format.
 */
-const  char32 * Melder_fixed  (double value, int precision);
-const  char   * Melder8_fixed (double value, int precision);
+const  char32 * Melder_fixed  (double value, int precision) noexcept;
+const  char   * Melder8_fixed (double value, int precision) noexcept;
 
 /**
 	Format a double value with a specified precision. If exponent is -2 and precision is 2, you get things like 67E-2 or 0.00024E-2.
 */
-const  char32 * Melder_fixedExponent  (double value, int exponent, int precision);
-const  char   * Melder8_fixedExponent (double value, int exponent, int precision);
+const  char32 * Melder_fixedExponent  (double value, int exponent, int precision) noexcept;
+const  char   * Melder8_fixedExponent (double value, int exponent, int precision) noexcept;
 
 /**
 	Format a double value as a percentage. If precision is 3, you get things like "0" or "34.400%" or "0.014%" or "0.001%" or "0.0000007%".
 */
-const  char32 * Melder_percent  (double value, int precision);
-const  char   * Melder8_percent (double value, int precision);
+const  char32 * Melder_percent  (double value, int precision) noexcept;
+const  char   * Melder8_percent (double value, int precision) noexcept;
 
 /**
 	Convert a formatted floating-point string to something suitable for visualization with the Graphics library.
 	For instance, "1e+4" is turned into "10^^4", and "-1.23456e-78" is turned into "-1.23456\.c10^^-78".
 */
-const char32 * Melder_float (const char32 *number);
+const char32 * Melder_float (const char32 *number) noexcept;
 
 /**
 	Format the number that is specified by its natural logarithm.
 	For instance, -10000 is formatted as "1.135483865315339e-4343", which is a floating-point representation of exp(-10000).
 */
-const  char32 * Melder_naturalLogarithm  (double lnNumber);
-const  char   * Melder8_naturalLogarithm (double lnNumber);
+const  char32 * Melder_naturalLogarithm  (double lnNumber) noexcept;
+const  char   * Melder8_naturalLogarithm (double lnNumber) noexcept;
 
-const  char32 * Melder_pointer  (void *pointer);
-const  char   * Melder8_pointer (void *pointer);
+const  char32 * Melder_pointer  (void *pointer) noexcept;
+const  char   * Melder8_pointer (void *pointer) noexcept;
 
-const  char32 * Melder_character  (char32_t kar);
-const  char   * Melder8_character (char32_t kar);
+const  char32 * Melder_character  (char32_t kar) noexcept;
+const  char   * Melder8_character (char32_t kar) noexcept;
 
 const char32 * Melder_pad (int64 width, const char32 *string);   // will append spaces to the left of 'string' until 'width' is reached; no truncation
 const char32 * Melder_pad (const char32 *string, int64 width);   // will append spaces to the right of 'string' until 'width' is reached; no truncation
@@ -271,24 +310,11 @@ const char32 * Melder_truncate (const char32 *string, int64 width);   // will cu
 const char32 * Melder_padOrTruncate (int64 width, const char32 *string);   // will cut away, or append spaces to, the left of 'string' until 'width' is reached
 const char32 * Melder_padOrTruncate (const char32 *string, int64 width);   // will cut away, or append spaces to, the right of 'string' until 'width' is reached
 
-
-/********** STRING TO NUMBER CONVERSION **********/
-
-bool Melder_isStringNumeric_nothrow (const char32 *string);
-double Melder_a8tof (const char *string);
-double Melder_atof (const char32 *string);
-int64 Melder_atoi (const char32 *string);
-	/*
-	 * "3.14e-3" -> 3.14e-3
-	 * "15.6%" -> 0.156
-	 * "fghfghj" -> NUMundefined
-	 */
-
 /********** CONSOLE **********/
 
 void Melder_writeToConsole (const char32 *message, bool useStderr);
 
-/********** MEMORY ALLOCATION ROUTINES **********/
+#pragma mark - MEMORY ALLOCATION
 
 /* These routines call malloc, free, realloc, and calloc. */
 /* If out of memory, the non-f versions throw an error message (like "Out of memory"); */
@@ -310,9 +336,37 @@ void * _Melder_calloc_f (int64 numberOfElements, int64 elementSize);
 char * Melder_strdup (const char *string);
 char * Melder_strdup_f (const char *string);
 
-int Melder_cmp (const char32 *string1, const char32 *string2);   // regards null string as empty string
-int Melder_ncmp (const char32 *string1, const char32 *string2, int64 n);
-char32 * Melder_tok (char32 *string, const char32 *delimiter);
+#define Melder_free(pointer)  _Melder_free ((void **) & (pointer))
+void _Melder_free (void **pointer) noexcept;
+/*
+	Preconditions:
+		none (*pointer may be null).
+	Postconditions:
+		*pointer == nullptr;
+*/
+
+int64 Melder_allocationCount ();
+/*
+	Returns the total number of successful calls to
+	Melder_malloc, Melder_realloc (if 'ptr' is null), Melder_calloc, and Melder_strdup,
+	since the start of the process. Mainly for debugging purposes.
+*/
+
+int64 Melder_deallocationCount ();
+/*
+	Returns the total number of successful calls to Melder_free,
+	since the start of the process. Mainly for debugging purposes.
+*/
+
+int64 Melder_allocationSize ();
+/*
+	Returns the total number of bytes allocated in calls to
+	Melder_malloc, Melder_realloc (if moved), Melder_calloc, and Melder_strdup,
+	since the start of the process. Mainly for debugging purposes.
+*/
+
+int64 Melder_reallocationsInSituCount ();
+int64 Melder_movingReallocationsCount ();
 
 /**
  * Text encodings.
@@ -342,7 +396,8 @@ extern char32 Melder_decodeWindowsLatin1 [256];
 long Melder_killReturns_inline (char32 *text);
 long Melder_killReturns_inline (char *text);
 /*
-	 Replaces all bare returns (Mac) or return / linefeed sequences (Win) with bare linefeeds (generic = Unix).
+	 Replaces all bare returns (old Mac) or return-plus-linefeed sequences (Win) with bare linefeeds
+	 (generic: Unix and modern Mac).
 	 Returns new length of string (equal to or less than old length).
 */
 
@@ -381,6 +436,24 @@ void Melder_8bitFileRepresentationToStr32_inline (const char *utf8, char32 *stri
 const void * Melder_peek32toCfstring (const char32 *string);
 void Melder_fwrite32to8 (const char32 *ptr, FILE *f);
 
+#pragma mark - STRING TO NUMBER CONVERSION
+
+bool Melder_isStringNumeric_nothrow (const char32 *string);
+double Melder_a8tof (const char *string);
+double Melder_atof (const char32 *string);
+int64 Melder_atoi (const char32 *string);
+	/*
+	 * "3.14e-3" -> 3.14e-3
+	 * "15.6%" -> 0.156
+	 * "fghfghj" -> undefined
+	 */
+inline static long a32tol (const char32 *string) {
+	if (sizeof (wchar_t) == 4) {
+		return wcstol ((const wchar_t *) string, nullptr, 10);
+	} else {
+		return atol (Melder_peek32to8 (string));
+	}
+}
 
 /********** FILES **********/
 
@@ -454,14 +527,938 @@ void Melder_files_cleanUp ();
 /* The trick is that they return one of 11 cyclically used static strings, */
 /* so you can use up to 11 strings in a single Melder_* call. */
 char32 * Melder_peekExpandBackslashes (const char32 *message);
-const char32 * MelderFile_messageName (MelderFile file);   // Calls Melder_peekExpandBackslashes ().
+const char32 * MelderFile_messageName (MelderFile file);   // calls Melder_peekExpandBackslashes ()
+
+struct structMelderReadText {
+	char32 *string32, *readPointer32;
+	char *string8, *readPointer8;
+	unsigned long input8Encoding;
+};
+typedef struct structMelderReadText *MelderReadText;
+
+MelderReadText MelderReadText_createFromFile (MelderFile file);
+MelderReadText MelderReadText_createFromString (const char32 *string);
+char32 MelderReadText_getChar (MelderReadText text);
+char32 * MelderReadText_readLine (MelderReadText text);
+wchar_t * MelderReadText_readLineW (MelderReadText text);
+int64 MelderReadText_getNumberOfLines (MelderReadText me);
+const char32 * MelderReadText_getLineNumber (MelderReadText text);
+void MelderReadText_delete (MelderReadText text);
+
+/* "NUM" = "NUMerics" */
+/* More mathematical and numerical things than there are in <math.h>. */
+
+/********** Inherit all the ANSI routines from math.h **********/
+
+/* On the sgi, math.h declares some bessel functions. */
+/* The following statements suppress these declarations */
+/* so that the compiler will give no warnings */
+/* when you redeclare y0 etc. in your code. */
+#ifdef sgi
+	#define y0 sgi_y0
+	#define y1 sgi_y1
+	#define yn sgi_yn
+	#define j0 sgi_j0
+	#define j1 sgi_j1
+	#define jn sgi_jn
+#endif
+#include <math.h>
+#ifdef sgi
+	#undef y0
+	#undef y1
+	#undef yn
+	#undef j0
+	#undef j1
+	#undef jn
+#endif
+#include <stdio.h>
+#include <wchar.h>
+#include "../sys/abcio.h"
+#define NUMlog2(x)  (log (x) * NUMlog2e)
+
+void NUMinit ();
+
+double NUMpow (double base, double exponent);   /* Zero for non-positive base. */
+void NUMshift (double *x, double xfrom, double xto);
+void NUMscale (double *x, double xminfrom, double xmaxfrom, double xminto, double xmaxto);
+
+/********** Constants **********
+ * Forty-digit constants computed by e.g.:
+ *    bc -l
+ *       scale=42
+ *       print e(1)
+ * Then rounding away the last two digits.
+ */
+//      print e(1)
+#define NUMe  2.7182818284590452353602874713526624977572
+//      print 1/l(2)
+#define NUMlog2e  1.4426950408889634073599246810018921374266
+//      print l(10)/l(2)
+#define NUMlog2_10  3.3219280948873623478703194294893901758648
+//      print 1/l(10)
+#define NUMlog10e  0.4342944819032518276511289189166050822944
+//      print l(2)/l(10)
+#define NUMlog10_2  0.3010299956639811952137388947244930267682
+//      print l(2)
+#define NUMln2  0.6931471805599453094172321214581765680755
+//      print l(10)
+#define NUMln10  2.3025850929940456840179914546843642076011
+//      print a(1)*8
+#define NUM2pi  6.2831853071795864769252867665590057683943
+//      print a(1)*4
+#define NUMpi  3.1415926535897932384626433832795028841972
+//      print a(1)*2
+#define NUMpi_2  1.5707963267948966192313216916397514420986
+//      print a(1)
+#define NUMpi_4  0.7853981633974483096156608458198757210493
+//      print 0.25/a(1)
+#define NUM1_pi  0.3183098861837906715377675267450287240689
+//      print 0.5/a(1)
+#define NUM2_pi  0.6366197723675813430755350534900574481378
+//      print sqrt(a(1)*4)
+#define NUMsqrtpi  1.7724538509055160272981674833411451827975
+//      print sqrt(a(1)*8)
+#define NUMsqrt2pi  2.5066282746310005024157652848110452530070
+//      print 1/sqrt(a(1)*8)
+#define NUM1_sqrt2pi  0.3989422804014326779399460599343818684759
+//      print 1/sqrt(a(1))
+#define NUM2_sqrtpi  1.1283791670955125738961589031215451716881
+//      print l(a(1)*4)
+#define NUMlnpi  1.1447298858494001741434273513530587116473
+//      print sqrt(2)
+#define NUMsqrt2  1.4142135623730950488016887242096980785697
+//      print sqrt(0.5)
+#define NUMsqrt1_2  0.7071067811865475244008443621048490392848
+//      print sqrt(3)
+#define NUMsqrt3  1.7320508075688772935274463415058723669428
+//      print sqrt(5)
+#define NUMsqrt5  2.2360679774997896964091736687312762354406
+//      print sqrt(6)
+#define NUMsqrt6  2.4494897427831780981972840747058913919659
+//      print sqrt(7)
+#define NUMsqrt7  2.6457513110645905905016157536392604257102
+//      print sqrt(8)
+#define NUMsqrt8  2.8284271247461900976033774484193961571393
+//      print sqrt(10)
+#define NUMsqrt10  3.1622776601683793319988935444327185337196
+//      print sqrt(5)/2-0.5
+#define NUM_goldenSection  0.6180339887498948482045868343656381177203
+// The Euler-Mascheroni constant cannot be computed by bc.
+// Instead we use the 40 digits computed by Johann von Soldner in 1809.
+#define NUM_euler  0.5772156649015328606065120900824024310422
+
+/*
+	Ideally, `undefined` should be #defined as NAN (or 0.0/0.0),
+	because that would make sure that
+		1.0 / undefined
+	evaluates as undefined.
+	However, we cannot do that as long as Praat contains any instances of
+		if (x == undefined) { ... }
+	because that condition would evaluate as false even if x were undefined
+	(because NAN is unequal to NAN).
+	Therefore, we must define, for the moment, `undefined` as positive infinity,
+	because positive infinity can be compared to itself
+	(i.e. Inf is equal to Inf). The drawback is that
+		1.0 / undefined
+	will evaluate as 0.0, i.e. this version of `undefined` does not propagate properly.
+*/
+#define undefined  (0.0/0.0)
+//#define undefined  NAN   /* a future definition? */
+//#define undefined  (0.0/0.0)   /* an alternative future definition */
+
+/*
+	Ideally, isdefined() should capture not only `undefined`, but all infinities and nans.
+	This can be done with a single test for the set bits in 0x7FF0000000000000,
+	at least for 64-bit IEEE implementations. The correctness of this assumption is checked in sys/praat.cpp.
+	The portable version of isdefined() would involve both isinf() and isnan(),
+	but that would be slower (as tested in fon/Praat_tests.cpp)
+	and it would also get into problems on some platforms whenever both <cmath> and <math.h> are included,
+	as in dwsys/NUMcomplex.cpp.
+*/
+//#define isdefined(x)  ((x) != NUMundefined)   /* an old definition, not good at capturing nans */
+//inline static bool isdefined (double x) { return ! isinf (x) && ! isnan (x); }   /* portable */
+inline static bool isdefined (double x) { return ((* (uint64_t *) & x) & 0x7FF0000000000000) != 0x7FF0000000000000; }
+inline static bool isundef (double x) { return ((* (uint64_t *) & x) & 0x7FF0000000000000) == 0x7FF0000000000000; }
+
+/********** Arrays with one index (NUMarrays.cpp) **********/
+
+void * NUMvector (integer elementSize, integer lo, integer hi, bool zero);
+/*
+	Function:
+		create a vector [lo...hi]; if `zero`, then all values are initialized to 0.
+	Preconditions:
+		hi >= lo;
+*/
+
+void NUMvector_free (integer elementSize, void *v, integer lo) noexcept;
+/*
+	Function:
+		destroy a vector v that was created with NUMvector.
+	Preconditions:
+		lo must have the same values as with the creation of the vector.
+*/
+
+void * NUMvector_copy (integer elementSize, void *v, integer lo, integer hi);
+/*
+	Function:
+		copy (part of) a vector v, which need not have been created with NUMvector, to a new one.
+	Preconditions:
+		if v != nullptr, the values v [lo..hi] must exist.
+*/
+
+void NUMvector_copyElements (integer elementSize, void *v, void *to, integer lo, integer hi);
+/*
+	copy the vector elements v [lo..hi] to those of a vector 'to'.
+	These vectors need not have been created by NUMvector.
+*/
+
+bool NUMvector_equal (integer elementSize, void *v1, void *v2, integer lo, integer hi);
+/*
+	return true if the vector elements v1 [lo..hi] are equal
+	to the corresponding elements of the vector v2; otherwise, return false.
+	The vectors need not have been created by NUMvector.
+*/
+
+void NUMvector_append (integer elementSize, void **v, integer lo, integer *hi);
+void NUMvector_insert (integer elementSize, void **v, integer lo, integer *hi, integer position);
+/*
+	add one element to the vector *v.
+	The new element is initialized to zero.
+	On success, *v points to the new vector, and *hi is incremented by 1.
+	On failure, *v and *hi are not changed.
+*/
+
+/********** Arrays with two indices (NUMarrays.cpp) **********/
+
+void * NUMmatrix (integer elementSize, integer row1, integer row2, integer col1, integer col2, bool zero);
+/*
+	Function:
+		create a matrix [row1...row2] [col1...col2]; if `zero`, then all values are initialized to 0.
+	Preconditions:
+		row2 >= row1;
+		col2 >= col1;
+*/
+
+void NUMmatrix_free (integer elementSize, void *m, integer row1, integer col1) noexcept;
+/*
+	Function:
+		destroy a matrix m created with NUM...matrix.
+	Preconditions:
+		if m != nullptr: row1 and col1
+		must have the same value as with the creation of the matrix.
+*/
+
+void * NUMmatrix_copy (integer elementSize, void *m, integer row1, integer row2, integer col1, integer col2);
+/*
+	Function:
+		copy (part of) a matrix m, wich does not have to be created with NUMmatrix, to a new one.
+	Preconditions:
+		if m != nullptr: the values m [rowmin..rowmax] [colmin..colmax] must exist.
+*/
+
+void NUMmatrix_copyElements (integer elementSize, void *m, void *to, integer row1, integer row2, integer col1, integer col2);
+/*
+	copy the matrix elements m [r1..r2] [c1..c2] to those of a matrix 'to'.
+	These matrices need not have been created by NUMmatrix.
+*/
+
+bool NUMmatrix_equal (integer elementSize, void *m1, void *m2, integer row1, integer row2, integer col1, integer col2);
+/*
+	return 1 if the matrix elements m1 [r1..r2] [c1..c2] are equal
+	to the corresponding elements of the matrix m2; otherwise, return 0.
+	The matrices need not have been created by NUM...matrix.
+*/
+
+integer NUM_getTotalNumberOfArrays ();   // for debugging
+
+/********** Special functions (NUM.cpp) **********/
+
+double NUMlnGamma (double x);
+double NUMbeta (double z, double w);
+double NUMbesselI (long n, double x);   // precondition: n >= 0
+double NUMbessel_i0_f (double x);
+double NUMbessel_i1_f (double x);
+double NUMbesselK (long n, double x);   // preconditions: n >= 0 && x > 0.0
+double NUMbessel_k0_f (double x);
+double NUMbessel_k1_f (double x);
+double NUMbesselK_f (long n, double x);
+double NUMsigmoid (double x);   // correct also for large positive or negative x
+double NUMinvSigmoid (double x);
+double NUMerfcc (double x);
+double NUMgaussP (double z);
+double NUMgaussQ (double z);
+double NUMincompleteGammaP (double a, double x);
+double NUMincompleteGammaQ (double a, double x);
+double NUMchiSquareP (double chiSquare, double degreesOfFreedom);
+double NUMchiSquareQ (double chiSquare, double degreesOfFreedom);
+double NUMcombinations (long n, long k);
+double NUMincompleteBeta (double a, double b, double x);   // incomplete beta function Ix(a,b). Preconditions: a, b > 0; 0 <= x <= 1
+double NUMbinomialP (double p, double k, double n);
+double NUMbinomialQ (double p, double k, double n);
+double NUMinvBinomialP (double p, double k, double n);
+double NUMinvBinomialQ (double p, double k, double n);
+
+/********** Auditory modelling (NUMear.cpp) **********/
+
+double NUMhertzToBark (double hertz);
+double NUMbarkToHertz (double bark);
+double NUMphonToDifferenceLimens (double phon);
+double NUMdifferenceLimensToPhon (double ndli);
+double NUMsoundPressureToPhon (double soundPressure, double bark);
+double NUMhertzToMel (double hertz);
+double NUMmelToHertz (double mel);
+double NUMhertzToSemitones (double hertz);
+double NUMsemitonesToHertz (double semitones);
+double NUMerb (double f);
+double NUMhertzToErb (double hertz);
+double NUMerbToHertz (double erb);
+
+/********** Sorting (NUMsort.cpp) **********/
+
+void NUMsort_d (long n, double ra []);   // heap sort
+void NUMsort_i (long n, int ra []);
+void NUMsort_l (long n, long ra []);
+void NUMsort_str (long n, char32 *a []);
+void NUMsort_p (long n, void *a [], int (*compare) (const void *, const void *));
+
+double NUMquantile (long n, double a [], double factor);
+/*
+	An estimate of the quantile 'factor' (between 0 and 1) of the distribution
+	from which the set 'a [1..n]' is a sorted array of random samples.
+	For instance, if 'factor' is 0.5, this function returns an estimate of
+	the median of the distribution underlying the sorted set a [].
+	If your array has not been sorted, first sort it with NUMsort (n, a).
+*/
+
+/********** Interpolation and optimization (NUM.cpp) **********/
+
+// Special values for interpolationDepth:
+#define NUM_VALUE_INTERPOLATE_NEAREST  0
+#define NUM_VALUE_INTERPOLATE_LINEAR  1
+#define NUM_VALUE_INTERPOLATE_CUBIC  2
+// Higher values than 2 yield a true sinc interpolation. Here are some examples:
+#define NUM_VALUE_INTERPOLATE_SINC70  70
+#define NUM_VALUE_INTERPOLATE_SINC700  700
+double NUM_interpolate_sinc (double y [], long nx, double x, long interpolationDepth);
+
+#define NUM_PEAK_INTERPOLATE_NONE  0
+#define NUM_PEAK_INTERPOLATE_PARABOLIC  1
+#define NUM_PEAK_INTERPOLATE_CUBIC  2
+#define NUM_PEAK_INTERPOLATE_SINC70  3
+#define NUM_PEAK_INTERPOLATE_SINC700  4
+
+double NUMimproveExtremum (double *y, long nx, long ixmid, int interpolation, double *ixmid_real, int isMaximum);
+double NUMimproveMaximum (double *y, long nx, long ixmid, int interpolation, double *ixmid_real);
+double NUMimproveMinimum (double *y, long nx, long ixmid, int interpolation, double *ixmid_real);
+
+void NUM_viterbi (
+	long numberOfFrames, long maxnCandidates,
+	long (*getNumberOfCandidates) (long iframe, void *closure),
+	double (*getLocalCost) (long iframe, long icand, void *closure),
+	double (*getTransitionCost) (long iframe, long icand1, long icand2, void *closure),
+	void (*putResult) (long iframe, long place, void *closure),
+	void *closure);
+
+void NUM_viterbi_multi (
+	long nframe, long ncand, int ntrack,
+	double (*getLocalCost) (long iframe, long icand, int itrack, void *closure),
+	double (*getTransitionCost) (long iframe, long icand1, long icand2, int itrack, void *closure),
+	void (*putResult) (long iframe, long place, int itrack, void *closure),
+	void *closure);
+
+/********** Metrics (NUM.cpp) **********/
+
+int NUMrotationsPointInPolygon
+	(double x0, double y0, long n, double x [], double y []);
+/*
+	Returns the number of times that the closed polygon
+	(x [1], y [1]), (x [2], y [2]),..., (x [n], y [n]), (x [1], y [1]) encloses the point (x0, y0).
+	The result is positive if the polygon encloses the point in the
+	anti-clockwise direction, and negative if the direction is clockwise.
+	The result is 0 if the point is outside the polygon.
+	If the point is on the polygon, the result is unpredictable.
+*/
+
+/********** Random numbers (NUMrandom.cpp) **********/
+
+void NUMrandom_init ();   // automatically called by NUMinit ();
+
+double NUMrandomFraction ();
+double NUMrandomFraction_mt (int threadNumber);
+
+double NUMrandomUniform (double lowest, double highest);
+
+long NUMrandomInteger (long lowest, long highest);
+
+bool NUMrandomBernoulli (double probability);
+double NUMrandomBernoulli_real (double probability);
+
+double NUMrandomGauss (double mean, double standardDeviation);
+double NUMrandomGauss_mt (int threadNumber, double mean, double standardDeviation);
+
+double NUMrandomPoisson (double mean);
+
+uint32 NUMhashString (const char32 *string);
+
+void NUMfbtoa (double formant, double bandwidth, double dt, double *a1, double *a2);
+void NUMfilterSecondOrderSection_a (double x [], long n, double a1, double a2);
+void NUMfilterSecondOrderSection_fb (double x [], long n, double dt, double formant, double bandwidth);
+double NUMftopreemphasis (double f, double dt);
+void NUMpreemphasize_a (double x [], long n, double preemphasis);
+void NUMdeemphasize_a (double x [], long n, double preemphasis);
+void NUMpreemphasize_f (double x [], long n, double dt, double frequency);
+void NUMdeemphasize_f (double x [], long n, double dt, double frequency);
+void NUMautoscale (double x [], long n, double scale);
+
+/* The following ANSI-C power trick generates the declarations of 156 functions. */
+#define FUNCTION(type,storage)  \
+	void NUMvector_writeText_##storage (const type *v, integer lo, integer hi, MelderFile file, const char32 *name); \
+	void NUMvector_writeBinary_##storage (const type *v, integer lo, integer hi, FILE *f); \
+	type * NUMvector_readText_##storage (integer lo, integer hi, MelderReadText text, const char *name); \
+	type * NUMvector_readBinary_##storage (integer lo, integer hi, FILE *f); \
+	void NUMmatrix_writeText_##storage (type **v, integer r1, integer r2, integer c1, integer c2, MelderFile file, const char32 *name); \
+	void NUMmatrix_writeBinary_##storage (type **v, integer r1, integer r2, integer c1, integer c2, FILE *f); \
+	type ** NUMmatrix_readText_##storage (integer r1, integer r2, integer c1, integer c2, MelderReadText text, const char *name); \
+	type ** NUMmatrix_readBinary_##storage (integer r1, integer r2, integer c1, integer c2, FILE *f);
+FUNCTION (signed char, i8)
+FUNCTION (int, i16)
+FUNCTION (long, i32)
+FUNCTION (unsigned char, u8)
+FUNCTION (unsigned int, u16)
+FUNCTION (unsigned long, u32)
+FUNCTION (double, r32)
+FUNCTION (double, r64)
+FUNCTION (fcomplex, c64)
+FUNCTION (dcomplex, c128)
+#undef FUNCTION
+
+/*
+void NUMvector_writeBinary_r64 (const double *v, integer lo, integer hi, FILE *f);   // etc
+	write the vector elements v [lo..hi] as machine-independent
+	binary data to the stream f.
+	Throw an error message if anything went wrong.
+	The vectors need not have been created by NUM...vector.
+double * NUMvector_readText_r64 (integer lo, integer hi, MelderReadText text, const char *name);   // etc
+	create and read a vector as text.
+	Throw an error message if anything went wrong.
+	Every element is supposed to be on the beginning of a line.
+double * NUMvector_readBinary_r64 (integer lo, integer hi, FILE *f);   // etc
+	create and read a vector as machine-independent binary data from the stream f.
+	Throw an error message if anything went wrong.
+void NUMvector_writeText_r64 (const double *v, integer lo, integer hi, MelderFile file, const char32 *name);   // etc
+	write the vector elements v [lo..hi] as text to the open file,
+	each element on its own line, preceded by "name [index]: ".
+	Throw an error message if anything went wrong.
+	The vectors need not have been created by NUMvector.
+void NUMmatrix_writeText_r64 (double **m, integer r1, integer r2, integer c1, integer c2, MelderFile file, const char32 *name);   // etc
+	write the matrix elements m [r1..r2] [c1..c2] as text to the open file.
+	Throw an error message if anything went wrong.
+	The matrices need not have been created by NUMmatrix.
+void NUMmatrix_writeBinary_r64 (double **m, integer r1, integer r2, integer c1, integer c2, FILE *f);   // etc
+	write the matrix elements m [r1..r2] [c1..c2] as machine-independent
+	binary data to the stream f.
+	Throw an error message if anything went wrong.
+	The matrices need not have been created by NUMmatrix.
+double ** NUMmatrix_readText_r64 (integer r1, integer r2, integer c1, integer c2, MelderReadText text, const char *name);   // etc
+	create and read a matrix as text.
+	Throw an error message if anything went wrong.
+double ** NUMmatrix_readBinary_r64 (integer r1, integer r2, integer c1, integer c2, FILE *f);   // etc
+	create and read a matrix as machine-independent binary data from the stream f.
+	Throw an error message if anything went wrong.
+*/
+
+typedef struct structNUMlinprog *NUMlinprog;
+void NUMlinprog_delete (NUMlinprog me);
+NUMlinprog NUMlinprog_new (bool maximize);
+void NUMlinprog_addVariable (NUMlinprog me, double lowerBound, double upperBound, double coeff);
+void NUMlinprog_addConstraint (NUMlinprog me, double lowerBound, double upperBound);
+void NUMlinprog_addConstraintCoefficient (NUMlinprog me, double coefficient);
+void NUMlinprog_run (NUMlinprog me);
+double NUMlinprog_getPrimalValue (NUMlinprog me, long ivar);
+
+template <class T>
+T* NUMvector (integer from, integer to) {
+	T* result = static_cast <T*> (NUMvector (sizeof (T), from, to, true));
+	return result;
+}
+
+template <class T>
+T* NUMvector (integer from, integer to, bool zero) {
+	T* result = static_cast <T*> (NUMvector (sizeof (T), from, to, zero));
+	return result;
+}
+
+template <class T>
+void NUMvector_free (T* ptr, integer from) noexcept {
+	NUMvector_free (sizeof (T), ptr, from);
+}
+
+template <class T>
+T* NUMvector_copy (T* ptr, integer lo, integer hi) {
+	T* result = static_cast <T*> (NUMvector_copy (sizeof (T), ptr, lo, hi));
+	return result;
+}
+
+template <class T>
+bool NUMvector_equal (T* v1, T* v2, integer lo, integer hi) {
+	return NUMvector_equal (sizeof (T), v1, v2, lo, hi);
+}
+
+template <class T>
+void NUMvector_copyElements (T* vfrom, T* vto, integer lo, integer hi) {
+	NUMvector_copyElements (sizeof (T), vfrom, vto, lo, hi);
+}
+
+template <class T>
+void NUMvector_append (T** v, integer lo, integer *hi) {
+	NUMvector_append (sizeof (T), (void**) v, lo, hi);
+}
+
+template <class T>
+void NUMvector_insert (T** v, integer lo, integer *hi, integer position) {
+	NUMvector_insert (sizeof (T), (void**) v, lo, hi, position);
+}
+
+template <class T>
+class autoNUMvector {
+	T* d_ptr;
+	integer d_from;
+public:
+	autoNUMvector<T> (integer from, integer to) : d_from (from) {
+		d_ptr = NUMvector<T> (from, to, true);
+	}
+	autoNUMvector<T> (integer from, integer to, bool zero) : d_from (from) {
+		d_ptr = NUMvector<T> (from, to, zero);
+	}
+	autoNUMvector (T *ptr, integer from) : d_ptr (ptr), d_from (from) {
+	}
+	autoNUMvector () : d_ptr (nullptr), d_from (1) {
+	}
+	~autoNUMvector<T> () {
+		if (d_ptr) NUMvector_free (sizeof (T), d_ptr, d_from);
+	}
+	T& operator[] (integer i) {
+		return d_ptr [i];
+	}
+	T* peek () const {
+		return d_ptr;
+	}
+	T* transfer () {
+		T* temp = d_ptr;
+		d_ptr = nullptr;   // make the pointer non-automatic again
+		return temp;
+	}
+	void reset (integer from, integer to) {
+		if (d_ptr) {
+			NUMvector_free (sizeof (T), d_ptr, d_from);
+			d_ptr = nullptr;
+		}
+		d_from = from;
+		d_ptr = NUMvector<T> (from, to, true);
+	}
+	void reset (integer from, integer to, bool zero) {
+		if (d_ptr) {
+			NUMvector_free (sizeof (T), d_ptr, d_from);
+			d_ptr = nullptr;
+		}
+		d_from = from;
+		d_ptr = NUMvector<T> (from, to, zero);
+	}
+};
+
+template <class T>
+T** NUMmatrix (integer row1, integer row2, integer col1, integer col2) {
+	T** result = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2, true));
+	return result;
+}
+
+template <class T>
+T** NUMmatrix (integer row1, integer row2, integer col1, integer col2, bool zero) {
+	T** result = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2, zero));
+	return result;
+}
+
+template <class T>
+void NUMmatrix_free (T** ptr, integer row1, integer col1) noexcept {
+	NUMmatrix_free (sizeof (T), ptr, row1, col1);
+}
+
+template <class T>
+T** NUMmatrix_copy (T** ptr, integer row1, integer row2, integer col1, integer col2) {
+	#if 1
+	T** result = static_cast <T**> (NUMmatrix_copy (sizeof (T), ptr, row1, row2, col1, col2));
+	#else
+	T** result = static_cast <T**> (NUMmatrix (sizeof (T), row1, row2, col1, col2));
+	for (integer irow = row1; irow <= row2; irow ++)
+		for (integer icol = col1; icol <= col2; icol ++)
+			result [irow] [icol] = ptr [irow] [icol];
+	#endif
+	return result;
+}
+
+template <class T>
+bool NUMmatrix_equal (T** m1, T** m2, integer row1, integer row2, integer col1, integer col2) {
+	return NUMmatrix_equal (sizeof (T), m1, m2, row1, row2, col1, col2);
+}
+
+template <class T>
+void NUMmatrix_copyElements (T** mfrom, T** mto, integer row1, integer row2, integer col1, integer col2) {
+	NUMmatrix_copyElements (sizeof (T), mfrom, mto, row1, row2, col1, col2);
+}
+
+template <class T>
+class autoNUMmatrix {
+	T** d_ptr;
+	integer d_row1, d_col1;
+public:
+	autoNUMmatrix (integer row1, integer row2, integer col1, integer col2) : d_row1 (row1), d_col1 (col1) {
+		d_ptr = NUMmatrix<T> (row1, row2, col1, col2, true);
+	}
+	autoNUMmatrix (integer row1, integer row2, integer col1, integer col2, bool zero) : d_row1 (row1), d_col1 (col1) {
+		d_ptr = NUMmatrix<T> (row1, row2, col1, col2, zero);
+	}
+	autoNUMmatrix (T **ptr, integer row1, integer col1) : d_ptr (ptr), d_row1 (row1), d_col1 (col1) {
+	}
+	autoNUMmatrix () : d_ptr (nullptr), d_row1 (0), d_col1 (0) {
+	}
+	~autoNUMmatrix () {
+		if (d_ptr) NUMmatrix_free (sizeof (T), d_ptr, d_row1, d_col1);
+	}
+	T*& operator[] (integer row) {
+		return d_ptr [row];
+	}
+	T** peek () const {
+		return d_ptr;
+	}
+	T** transfer () {
+		T** temp = d_ptr;
+		d_ptr = nullptr;
+		return temp;
+	}
+	void reset (integer row1, integer row2, integer col1, integer col2) {
+		if (d_ptr) {
+			NUMmatrix_free (sizeof (T), d_ptr, d_row1, d_col1);
+			d_ptr = nullptr;
+		}
+		d_row1 = row1;
+		d_col1 = col1;
+		d_ptr = NUMmatrix<T> (row1, row2, col1, col2, true);
+	}
+	void reset (integer row1, integer row2, integer col1, integer col2, bool zero) {
+		if (d_ptr) {
+			NUMmatrix_free (sizeof (T), d_ptr, d_row1, d_col1);
+			d_ptr = nullptr;
+		}
+		d_row1 = row1;
+		d_col1 = col1;
+		d_ptr = NUMmatrix<T> (row1, row2, col1, col2, zero);
+	}
+};
+
+template <class T>
+class autodatavector {
+	T* d_ptr;
+	integer d_from, d_to;
+public:
+	autodatavector<T> (integer from, integer to) : d_from (from), d_to (to) {
+		d_ptr = NUMvector<T> (from, to, true);
+	}
+	autodatavector<T> (integer from, integer to, bool zero) : d_from (from), d_to (to) {
+		d_ptr = NUMvector<T> (from, to, zero);
+	}
+	autodatavector (T *ptr, integer from, integer to) : d_ptr (ptr), d_from (from), d_to (to) {
+	}
+	autodatavector () : d_ptr (nullptr), d_from (1), d_to (0) {
+	}
+	~autodatavector<T> () {
+		if (d_ptr) {
+			for (integer i = d_from; i <= d_to; i ++)
+				Melder_free (d_ptr [i]);
+			NUMvector_free (sizeof (T), d_ptr, d_from);
+		}
+	}
+	T& operator[] (integer i) {
+		return d_ptr [i];
+	}
+	T* peek () const {
+		return d_ptr;
+	}
+	T* transfer () {
+		T* temp = d_ptr;
+		d_ptr = nullptr;   // make the pointer non-automatic again
+		return temp;
+	}
+	void reset (integer from, integer to) {
+		if (d_ptr) {
+			for (integer i = d_from; i <= d_to; i ++)
+				Melder_free (d_ptr [i]);
+			NUMvector_free (sizeof (T), d_ptr, d_from);
+			d_ptr = nullptr;
+		}
+		d_from = from;   // this assignment is safe, because d_ptr is null
+		d_to = to;
+		d_ptr = NUMvector<T> (from, to, true);
+	}
+	void reset (integer from, integer to, bool zero) {
+		if (d_ptr) {
+			for (integer i = d_from; i <= d_to; i ++)
+				Melder_free (d_ptr [i]);
+			NUMvector_free (sizeof (T), d_ptr, d_from);
+			d_ptr = nullptr;
+		}
+		d_from = from;   // this assignment is safe, because d_ptr is null
+		d_to = to;
+		d_ptr = NUMvector<T> (from, to, zero);
+	}
+};
+
+typedef autodatavector <char32 *> autostring32vector;
+typedef autodatavector <char *> autostring8vector;
+
+#pragma mark - TENSOR
+/*
+	numvec and nummat: the type declarations are in melder.h, the function declarations in tensor.h
+
+	Initialization (tested in praat.cpp):
+		numvec x;                  // does not initialize x
+		numvec x { };              // initializes x.at to nullptr and x.size to 0
+		numvec x { 100, false };   // initializes x to 100 uninitialized values
+		numvec x { 100, true };    // initializes x to 100 zeroes
+		NUMvector<double> a (1, 100);
+		numvec x { a, 100 };       // initializes x to 100 values from a base-1 array
+
+		autonumvec y;                  // initializes y.at to nullptr and y.size to 0
+		autonumvec y { 100, false };   // initializes y to 100 uninitialized values, having ownership
+		autonumvec y { 100, true };    // initializes y to 100 zeroes, having ownership
+		autonumvec y { x };            // initializes y to the content of x, taking ownership (explicit, so not "y = x")
+		numvec z = releaseToAmbiguousOwner();   // releases ownership, x.at becoming nullptr
+		"}"                            // end of scope destroys x.at if not nullptr
+		autonumvec z = y.move()        // moves the content of y to z, emptying y
+
+	To return an autonumvec from a function, transfer ownership like this:
+		autonumvec foo () {
+			autonumvec x { 100, false };
+			... // fill in the 100 values
+			return x;
+		}
+*/
+
+class autonumvec;   // forward declaration, needed in the declaration of numvec
+
+class numvec {
+public:
+	double *at;
+	integer size;
+public:
+	numvec () = default;   // for use in a union
+	numvec (double *givenAt, integer givenSize): at (givenAt), size (givenSize) { }
+	numvec (integer givenSize, bool zero) {
+		our _initAt (givenSize, zero);
+		our size = givenSize;
+	}
+	numvec (const numvec& other) = default;
+	numvec (const autonumvec& other) = delete;
+	numvec& operator= (const numvec&) = default;
+	numvec& operator= (const autonumvec&) = delete;
+	double& operator[] (integer i) {
+		return our at [i];
+	}
+	void reset () noexcept {
+		if (our at) {
+			our _freeAt ();
+			our at = nullptr;
+		}
+		our size = 0;
+	}
+protected:
+	void _initAt (integer givenSize, bool zero);
+	void _freeAt () noexcept;
+};
+
+#define empty_numvec  numvec { nullptr, 0 }
+
+/*
+	An autonumvec is the sole owner of its payload, which is a numvec.
+	When the autonumvec ends its life (goes out of scope),
+	it should destroy its payload (if it has not sold it),
+	because keeping a payload alive when the owner is dead
+	would continue to use some of the computer's resources (namely, memory).
+*/
+class autonumvec : public numvec {
+public:
+	autonumvec (): numvec (nullptr, 0) { }   // come into existence without a payload
+	autonumvec (integer givenSize, bool zero): numvec (givenSize, zero) { }   // come into existence and manufacture a payload
+	autonumvec (double *givenAt, integer givenSize): numvec (givenAt, givenSize) { }   // come into existence and buy a payload from a non-autonumvec
+	explicit autonumvec (numvec x): numvec (x.at, x.size) { }   // come into existence and buy a payload from a non-autonumvec (disable implicit conversion)
+	~autonumvec () {   // destroy the payload (if any)
+		if (our at) our _freeAt ();
+	}
+	numvec get () const { return { our at, our size }; }   // let the public use the payload (they may change the values of the elements but not the at-pointer or the size)
+	numvec releaseToAmbiguousOwner () {   // sell the payload to a non-autonumvec
+		double *oldAt = our at;
+		our at = nullptr;   // disown ourselves, preventing automatic destruction of the payload
+		return { oldAt, our size };
+	}
+	void reset () {   // destroy the current payload (if any) and have no new payload
+		our numvec :: reset ();
+	}
+	void reset (integer newSize, bool zero) {   // destroy the current payload (if any) and manufacture a new payload
+		our numvec :: reset ();   // exception guarantee: leave *this in a reasonable state...
+		our _initAt (newSize, zero);   // ...in case this line throws an exception
+		our size = newSize;
+	}
+	void reset (double *newAt, integer newSize) {   // destroy the current payload (if any) and buy a new payload
+		if (our at) our _freeAt ();
+		our at = newAt;
+		our size = newSize;
+	}
+	void reset (numvec newX) {   // destroy the current payload (if any) and buy a new payload
+		if (our at) our _freeAt ();
+		our at = newX.at;
+		our size = newX.size;
+	}
+	/*
+		Disable copying via construction or assignment (which would violate unique ownership of the payload).
+	*/
+	autonumvec (const autonumvec&) = delete;   // disable copy constructor
+	autonumvec& operator= (const autonumvec&) = delete;   // disable copy assignment
+	/*
+		Enable moving of temporaries or (for variables) via an explicit move().
+		This implements buying a payload from another autonumvec (which involves destroying our current payload).
+	*/
+	autonumvec (autonumvec&& other) noexcept : numvec { other.get() } {   // enable move constructor for r-values (temporaries)
+		other.at = nullptr;   // disown source
+	}
+	autonumvec& operator= (autonumvec&& other) noexcept {   // enable move assignment for r-values (temporaries)
+		if (other.at != our at) {
+			if (our at) our _freeAt ();
+			our at = other.at;
+			our size = other.size;
+			other.at = nullptr;   // disown source
+			other.size = 0;   // needed only if you insist on keeping the source in a valid state
+		}
+		return *this;
+	}
+	autonumvec&& move () noexcept { return static_cast <autonumvec&&> (*this); }   // enable constriction and assignment for l-values (variables) via explicit move()
+};
+
+class autonummat;   // forward declaration, needed in the declaration of nummat
+
+class nummat {
+public:
+	double **at;
+	integer nrow, ncol;
+public:
+	nummat () = default;   // for use in a union
+	nummat (double **givenAt, integer givenNrow, integer givenNcol): at (givenAt), nrow (givenNrow), ncol (givenNcol) { }
+	nummat (integer givenNrow, integer givenNcol, bool zero) {
+		our _initAt (givenNrow, givenNcol, zero);
+		our nrow = givenNrow;
+		our ncol = givenNcol;
+	}
+	nummat (const nummat& other) = default;
+	nummat (const autonummat& other) = delete;
+	nummat& operator= (const nummat&) = default;
+	nummat& operator= (const autonummat&) = delete;
+	double *& operator[] (integer i) {
+		return our at [i];
+	}
+	void reset () noexcept {
+		if (our at) {
+			our _freeAt ();
+			our at = nullptr;
+		}
+		our nrow = 0;
+		our ncol = 0;
+	}
+protected:
+	void _initAt (integer givenNrow, integer givenNcol, bool zero);
+	void _freeAt () noexcept;
+};
+
+#define empty_nummat  nummat { nullptr, 0, 0 }
+
+/*
+	An autonummat is the sole owner of its payload, which is a nummat.
+	When the autonummat ends its life (goes out of scope),
+	it should destroy its payload (if it has not sold it),
+	because keeping a payload alive when the owner is dead
+	would continue to use some of the computer's resources (namely, memory).
+*/
+class autonummat : public nummat {
+public:
+	autonummat (): nummat { nullptr, 0, 0 } { }   // come into existence without a payload
+	autonummat (integer givenNrow, integer givenNcol, bool zero): nummat { givenNrow, givenNcol, zero } { }   // come into existence and manufacture a payload
+	autonummat (double **givenAt, integer givenNrow, integer givenNcol): nummat (givenAt, givenNrow, givenNcol) { }   // come into existence and buy a payload from a non-autonummat
+	explicit autonummat (nummat x): nummat (x.at, x.nrow, x.ncol) { }   // come into existence and buy a payload from a non-autonummat (disable implicit conversion)
+	~autonummat () {   // destroy the payload (if any)
+		if (our at) our _freeAt ();
+	}
+	nummat get () { return { our at, our nrow, our ncol }; }   // let the public use the payload (they may change the values in the cells but not the at-pointer, nrow or ncol)
+	nummat releaseToAmbiguousOwner () {   // sell the payload to a non-autonummat
+		double **oldAt = our at;
+		our at = nullptr;   // disown ourselves, preventing automatic destruction of the payload
+		return { oldAt, our nrow, our ncol };
+	}
+	void reset () {   // destroy the current payload (if any) and have no new payload
+		our nummat :: reset ();
+	}
+	void reset (integer newNrow, integer newNcol, bool zero) {   // destroy the current payload (if any) and manufacture a new payload
+		our nummat :: reset ();   // exception guarantee: leave *this in a reasonable state...
+		our _initAt (newNrow, newNcol, zero);   // ...in case this line throws an exception
+		our nrow = newNrow;
+		our ncol = newNcol;
+	}
+	void reset (double **newAt, integer newNrow, integer newNcol) {   // destroy the current payload (if any) and buy a new payload
+		if (our at) our _freeAt ();
+		our at = newAt;
+		our nrow = newNrow;
+		our ncol = newNcol;
+	}
+	void reset (nummat newX) {   // destroy the current payload (if any) and buy a new payload
+		if (our at) our _freeAt ();
+		our at = newX.at;
+		our nrow = newX.nrow;
+		our ncol = newX.ncol;
+	}
+	/*
+		Disable copying via construction or assignment (which would violate unique ownership of the payload).
+	*/
+	autonummat (const autonummat&) = delete;   // disable copy constructor
+	autonummat& operator= (const autonummat&) = delete;   // disable copy assignment
+	/*
+		Enable moving of temporaries or (for variables) via an explicit move().
+		This implements buying a payload from another autonummat (which involves destroying our current payload).
+	*/
+	autonummat (autonummat&& other) noexcept : nummat { other.get() } {   // enable move constructor for r-values (temporaries)
+		other.at = nullptr;   // disown source
+	}
+	autonummat& operator= (autonummat&& other) noexcept {   // enable move assignment for r-values (temporaries)
+		if (other.at != our at) {
+			if (our at) our _freeAt ();
+			our at = other.at;
+			our nrow = other.nrow;
+			our ncol = other.ncol;
+			other.at = nullptr;   // disown source
+			other.nrow = 0;   // needed only if you insist on keeping the source in a valid state
+			other.ncol = 0;
+		}
+		return *this;
+	}
+	autonummat&& move () noexcept { return static_cast <autonummat&&> (*this); }
+};
 
-/* The arguments to all messaging functions. */
+#pragma mark - ARGUMENTS
 
-typedef class structThing *Thing;
-char32 *Thing_messageName (Thing me);
+const  char32 * Melder_numvec  (numvec value);
+const  char32 * Melder_nummat  (nummat value);
+typedef class structThing *Thing;   // forward declaration
+const char32 * Thing_messageName (Thing me);
 struct MelderArg {
 	const char32 *_arg;
+	/*
+		The types of arguments that never involve memory allocation:
+	*/
 	MelderArg (const char32 *            arg) : _arg (arg) { }
 	//MelderArg (const char   *            arg) : _arg (Melder_peek8to32 (arg)) { }
 	MelderArg (const double              arg) : _arg (Melder_double          (arg)) { }
@@ -474,9 +1471,14 @@ struct MelderArg {
 	MelderArg (const          short      arg) : _arg (Melder_integer         (arg)) { }
 	MelderArg (const unsigned short      arg) : _arg (Melder_integer         (arg)) { }
 	MelderArg (const char32_t            arg) : _arg (Melder_character       (arg)) { }
+	MelderArg (void *                    arg) : _arg (Melder_integer         ((int64) arg)) { }
+	/*
+		The types of arguments that sometimes involve memory allocation:
+	*/
+	MelderArg (numvec                    arg) : _arg (Melder_numvec          (arg)) { }
+	MelderArg (nummat                    arg) : _arg (Melder_nummat          (arg)) { }
 	MelderArg (Thing                     arg) : _arg (Thing_messageName      (arg)) { }
 	MelderArg (MelderFile                arg) : _arg (MelderFile_messageName (arg)) { }
-	//MelderArg (void *                    arg) : _arg (Melder_integer         ((int64) arg)) { }
 };
 
 #define Melder_1_ARG \
@@ -655,38 +1657,6 @@ void MelderFile_setDefaultDir (MelderFile file);
 #define U_LEFT_GUILLEMET  U"\u00ab"
 #define U_RIGHT_GUILLEMET  U"\u00bb"
 
-#define Melder_free(pointer)  _Melder_free ((void **) & (pointer))
-void _Melder_free (void **pointer);
-/*
-	Preconditions:
-		none (*pointer may be null).
-	Postconditions:
-		*pointer == nullptr;
-*/
-
-int64 Melder_allocationCount ();
-/*
-	Returns the total number of successful calls to
-	Melder_malloc, Melder_realloc (if 'ptr' is null), Melder_calloc, and Melder_strdup,
-	since the start of the process. Mainly for debugging purposes.
-*/
-
-int64 Melder_deallocationCount ();
-/*
-	Returns the total number of successful calls to Melder_free,
-	since the start of the process. Mainly for debugging purposes.
-*/
-
-int64 Melder_allocationSize ();
-/*
-	Returns the total number of bytes allocated in calls to
-	Melder_malloc, Melder_realloc (if moved), Melder_calloc, and Melder_strdup,
-	since the start of the process. Mainly for debugging purposes.
-*/
-
-int64 Melder_reallocationsInSituCount ();
-int64 Melder_movingReallocationsCount ();
-
 /********** STRINGS **********/
 
 /* These are routines for never having to check string boundaries again. */
@@ -751,22 +1721,6 @@ int64 MelderString_deallocationCount ();
 int64 MelderString_allocationSize ();
 int64 MelderString_deallocationSize ();
 
-struct structMelderReadText {
-	char32 *string32, *readPointer32;
-	char *string8, *readPointer8;
-	unsigned long input8Encoding;
-};
-typedef struct structMelderReadText *MelderReadText;
-
-MelderReadText MelderReadText_createFromFile (MelderFile file);
-MelderReadText MelderReadText_createFromString (const char32 *string);
-char32 MelderReadText_getChar (MelderReadText text);
-char32 * MelderReadText_readLine (MelderReadText text);
-wchar_t * MelderReadText_readLineW (MelderReadText text);
-int64 MelderReadText_getNumberOfLines (MelderReadText me);
-const char32 * MelderReadText_getLineNumber (MelderReadText text);
-void MelderReadText_delete (MelderReadText text);
-
 const char32 * Melder_cat (Melder_2_ARGS);
 const char32 * Melder_cat (Melder_3_ARGS);
 const char32 * Melder_cat (Melder_4_ARGS);
@@ -1019,7 +1973,7 @@ int Melder_fatal (Melder_12_OR_13_ARGS);
 int Melder_fatal (Melder_14_OR_15_ARGS);
 int Melder_fatal (Melder_16_TO_19_ARGS);
 
-/********** PROGRESS ROUTINES **********/
+#pragma mark - PROGRESS
 
 void Melder_progress (double progress);
 void Melder_progress (double progress, Melder_1_ARG);
@@ -1055,7 +2009,7 @@ void Melder_progressOn ();
 	Usage:
 		- call with 'progress' = 0.0 before the process starts:
 		      (void) Melder_progress (0.0, U"Starting work...");
-		- at every turn in your loop, call with 'progress' between 0 and 1:
+		- at every turn in your loop, call with 'progress' between 0.0 and 1.0:
 		      Melder_progress (i / (n + 1.0), U"Working on part ", i, U" out of ", n, U"...");
 		  an exception is thrown if the user clicks Cancel; if you don't want that, catch it:
 		      try {
@@ -1118,7 +2072,7 @@ void * Melder_monitor (double progress, Melder_16_TO_19_ARGS);
 		          Graphics_polyline (graphics, ...);
 		          Graphics_text (graphics, ...);
 		      }
-		- immediately after this in your loop, call with 'progress' between 0 and 1:
+		- immediately after this in your loop, call with 'progress' between 0.0 and 1.0:
 		      Melder_monitor (i / (n + 1.0), U"Working on part ", i, U" out of ", n, U"...");
 		  an exception is thrown if the user clicks Cancel; if you don't want that, catch it:
 		      try {
@@ -1205,7 +2159,7 @@ void Melder_setPublishPlayedProc (int (*publishPlayed) ());
 double Melder_stopwatch ();
 void Melder_sleep (double duration);
 
-/********** AUDIO **********/
+#pragma mark - AUDIO
 
 void MelderAudio_setInputSoundSystem (enum kMelder_inputSoundSystem inputSoundSystem);
 enum kMelder_inputSoundSystem MelderAudio_getInputSoundSystem ();
@@ -1253,7 +2207,7 @@ bool MelderAudio_stopWasExplicit ();
 
 void Melder_audio_prefs ();   // in init file
 
-/********** AUDIO FILES **********/
+#pragma mark - AUDIO FILES
 
 /* Audio file types. */
 #define Melder_AIFF  1
@@ -1407,38 +2361,53 @@ public:
 };
 
 class autoMelderSaveDefaultDir {
-	structMelderDir saveDir;
+	structMelderDir _savedDir;
 public:
 	autoMelderSaveDefaultDir () {
-		Melder_getDefaultDir (& saveDir);
+		Melder_getDefaultDir (& our _savedDir);
 	}
 	~autoMelderSaveDefaultDir () {
-		Melder_setDefaultDir (& saveDir);
+		Melder_setDefaultDir (& our _savedDir);
 	}
+	/*
+		Disable copying.
+	*/
+	autoMelderSaveDefaultDir (const autoMelderSaveDefaultDir&) = delete;   // disable copy constructor
+	autoMelderSaveDefaultDir& operator= (const autoMelderSaveDefaultDir&) = delete;   // disable copy assignment
 };
 
 class autoMelderSetDefaultDir {
-	structMelderDir saveDir;
+	structMelderDir _savedDir;
 public:
 	autoMelderSetDefaultDir (MelderDir dir) {
-		Melder_getDefaultDir (& saveDir);
+		Melder_getDefaultDir (& our _savedDir);
 		Melder_setDefaultDir (dir);
 	}
 	~autoMelderSetDefaultDir () {
-		Melder_setDefaultDir (& saveDir);
+		Melder_setDefaultDir (& our _savedDir);
 	}
+	/*
+		Disable copying.
+	*/
+	autoMelderSetDefaultDir (const autoMelderSetDefaultDir&) = delete;   // disable copy constructor
+	autoMelderSetDefaultDir& operator= (const autoMelderSetDefaultDir&) = delete;   // disable copy assignment
 };
 
 class autoMelderFileSetDefaultDir {
-	structMelderDir saveDir;
+	structMelderDir _savedDir;
 public:
 	autoMelderFileSetDefaultDir (MelderFile file) {
-		Melder_getDefaultDir (& saveDir);
+		Melder_getDefaultDir (& our _savedDir);
 		MelderFile_setDefaultDir (file);
 	}
 	~autoMelderFileSetDefaultDir () {
-		Melder_setDefaultDir (& saveDir);
+		Melder_setDefaultDir (& our _savedDir);
 	}
+	/*
+		Disable copying.
+	*/
+	autoMelderFileSetDefaultDir (const autoMelderFileSetDefaultDir&) = delete;   // disable copy constructor
+	autoMelderFileSetDefaultDir& operator= (const autoMelderFileSetDefaultDir&) = delete;   // disable copy assignment
 };
 
 class autoMelderTokens {
@@ -1522,10 +2491,9 @@ public:
 		T *tmp = (T *) Melder_realloc (ptr, new_size * (int64) sizeof (T));
 		ptr = tmp;
 	}
-private:
-	_autostring& operator= (const _autostring&);   // disable copy assignment
-	//_autostring (_autostring &);   // disable copy constructor (trying it this way also disables good things like autostring s1 = str32dup(U"hello");)
-	template <class Y> _autostring (_autostring<Y> &);   // disable copy constructor
+	_autostring& operator= (const _autostring&) = delete;   // disable copy assignment
+	//_autostring (_autostring &) = delete;   // disable copy constructor (trying it this way also disables good things like autostring s1 = str32dup(U"hello");)
+	template <class Y> _autostring (_autostring<Y> &) = delete;   // disable copy constructor
 };
 
 typedef _autostring <char> autostring8;
@@ -1533,21 +2501,84 @@ typedef _autostring <char16> autostring16;
 typedef _autostring <char32> autostring32;
 
 class autoMelderAudioSaveMaximumAsynchronicity {
-	enum kMelder_asynchronicityLevel d_saveAsynchronicity;
+	bool _disowned;
+	enum kMelder_asynchronicityLevel _savedAsynchronicity;
 public:
 	autoMelderAudioSaveMaximumAsynchronicity () {
-		d_saveAsynchronicity = MelderAudio_getOutputMaximumAsynchronicity ();
-		trace (U"value was ", d_saveAsynchronicity);
+		our _savedAsynchronicity = MelderAudio_getOutputMaximumAsynchronicity ();
+		trace (U"value was ", our _savedAsynchronicity);
+		our _disowned = false;
 	}
 	~autoMelderAudioSaveMaximumAsynchronicity () {
-		MelderAudio_setOutputMaximumAsynchronicity (d_saveAsynchronicity);
-		trace (U"value set to ", d_saveAsynchronicity);
+		MelderAudio_setOutputMaximumAsynchronicity (our _savedAsynchronicity);
+		trace (U"value set to ", our _savedAsynchronicity);
+	}
+	/*
+		Disable copying.
+	*/
+	autoMelderAudioSaveMaximumAsynchronicity (const autoMelderAudioSaveMaximumAsynchronicity&) = delete;   // disable copy constructor
+	autoMelderAudioSaveMaximumAsynchronicity& operator= (const autoMelderAudioSaveMaximumAsynchronicity&) = delete;   // disable copy assignment
+	/*
+		Enable moving.
+	*/
+	autoMelderAudioSaveMaximumAsynchronicity (autoMelderAudioSaveMaximumAsynchronicity&& other) noexcept {   // enable move constructor
+		our _disowned = other._disowned;
+		our _savedAsynchronicity = other._savedAsynchronicity;
+		other._disowned = true;
+	}
+	autoMelderAudioSaveMaximumAsynchronicity& operator= (autoMelderAudioSaveMaximumAsynchronicity&& other) noexcept {   // enable move assignment
+		if (& other != this) {
+			our _disowned = other._disowned;
+			our _savedAsynchronicity = other._savedAsynchronicity;
+			other._disowned = true;   // needed only if you insist on keeping the source in a valid state
+		}
+		return *this;
+	}
+	autoMelderAudioSaveMaximumAsynchronicity&& move () noexcept { return static_cast <autoMelderAudioSaveMaximumAsynchronicity&&> (*this); }
+	void releaseToAmbiguousOwner () {
+		our _disowned = true;
 	}
 };
 
-struct autoMelderAsynchronous {
-	autoMelderAsynchronous () { Melder_asynchronous = true; }
-	~autoMelderAsynchronous () { Melder_asynchronous = false; }
+class autoMelderAsynchronous {
+	bool _disowned;
+	bool _savedAsynchronicity;
+public:
+	autoMelderAsynchronous () {
+		our _savedAsynchronicity = Melder_asynchronous;
+		Melder_asynchronous = true;
+		our _disowned = false;
+	}
+	~autoMelderAsynchronous () {
+		if (! _disowned) {
+			Melder_asynchronous = _savedAsynchronicity;
+		}
+	}
+	/*
+		Disable copying.
+	*/
+	autoMelderAsynchronous (const autoMelderAsynchronous&) = delete;   // disable copy constructor
+	autoMelderAsynchronous& operator= (const autoMelderAsynchronous&) = delete;   // disable copy assignment
+	/*
+		Enable moving.
+	*/
+	autoMelderAsynchronous (autoMelderAsynchronous&& other) noexcept {   // enable move constructor
+		our _disowned = other._disowned;
+		our _savedAsynchronicity = other._savedAsynchronicity;
+		other._disowned = true;
+	}
+	autoMelderAsynchronous& operator= (autoMelderAsynchronous&& other) noexcept {   // enable move assignment
+		if (& other != this) {
+			our _disowned = other._disowned;
+			our _savedAsynchronicity = other._savedAsynchronicity;
+			other._disowned = true;   // needed only if you insist on keeping the source in a valid state
+		}
+		return *this;
+	}
+	autoMelderAsynchronous&& move () noexcept { return static_cast <autoMelderAsynchronous&&> (*this); }
+	void releaseToAmbiguousOwner () {
+		our _disowned = true;
+	}
 };
 
 #define Melder_ENABLE_IF_ISA(A,B)  , class = typename std::enable_if<std::is_base_of<B,A>::value>::type
diff --git a/sys/melder_alloc.cpp b/sys/melder_alloc.cpp
index fb9ae52..7e6818f 100644
--- a/sys/melder_alloc.cpp
+++ b/sys/melder_alloc.cpp
@@ -1,6 +1,6 @@
 /* melder_alloc.cpp
  *
- * Copyright (C) 1992-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@ void * _Melder_malloc_f (int64 size) {
 	return result;
 }
 
-void _Melder_free (void **ptr) {
+void _Melder_free (void **ptr) noexcept {
 	if (! *ptr) return;
 	if (Melder_debug == 34) { Melder_casual (U"Melder_free\t", Melder_pointer (*ptr), U"\t?\t?"); }
 	free (*ptr);
@@ -287,7 +287,7 @@ int Melder_ncmp (const char32 *string1, const char32 *string2, int64 n) {
 	return str32ncmp (string1, string2, n);
 }
 
-bool Melder_str32equ_firstCharacterCaseInsensitive (const char32 *string1, const char32 *string2) {
+bool Melder_equ_firstCharacterCaseInsensitive (const char32 *string1, const char32 *string2) {
 	if (! string1) string1 = U"";
 	if (! string2) string2 = U"";
 	if (*string1 == U'\0') return *string2 == U'\0';
diff --git a/sys/melder_atof.cpp b/sys/melder_atof.cpp
index 0456702..16cdf3f 100644
--- a/sys/melder_atof.cpp
+++ b/sys/melder_atof.cpp
@@ -1,6 +1,6 @@
 /* melder_atof.cpp
  *
- * Copyright (C) 2003-2011,2015 Paul Boersma
+ * Copyright (C) 2003-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
  */
 
 #include "melder.h"
-#include "NUM.h"
 
 static const char32 *findEndOfNumericString_nothrow (const char32 *string) {
 	const char32 *p = & string [0];
@@ -154,9 +153,9 @@ bool Melder_isStringNumeric_nothrow (const char32 *string) {
 }
 
 double Melder_a8tof (const char *string) {
-	if (! string) return NUMundefined;
+	if (! string) return undefined;
 	const char *p = findEndOfNumericString_nothrow (string);
-	if (! p) return NUMundefined;
+	if (! p) return undefined;
 	Melder_assert (p - string > 0);
 	return p [-1] == '%' ? 0.01 * strtod (string, nullptr) : strtod (string, nullptr);
 }
diff --git a/sys/melder_audio.cpp b/sys/melder_audio.cpp
index 3f1910a..6853826 100644
--- a/sys/melder_audio.cpp
+++ b/sys/melder_audio.cpp
@@ -18,10 +18,8 @@
 
 #if defined (macintosh)
 	#include <sys/time.h>
-	#include <math.h>
 #elif defined (_WIN32)
 	#include <windows.h>
-	#include <math.h>
 #elif defined (linux)
 	#include <sys/time.h>
 	#include <signal.h>
@@ -45,9 +43,8 @@
 
 #include "Gui.h"
 #include "Preferences.h"
-#include "NUM.h"
+#include "melder.h"
 #include <time.h>
-#define my me ->
 
 #include "../external/portaudio/portaudio.h"
 
diff --git a/sys/melder_audiofiles.cpp b/sys/melder_audiofiles.cpp
index 10d8b67..a103a00 100644
--- a/sys/melder_audiofiles.cpp
+++ b/sys/melder_audiofiles.cpp
@@ -1,6 +1,6 @@
 /* melder_audiofiles.cpp
  *
- * Copyright (C) 1992-2011,2013,2015,2016 Paul Boersma & David Weenink, 2007 Erez Volk (for FLAC)
+ * Copyright (C) 1992-2011,2013,2015,2016,2017 Paul Boersma & David Weenink, 2007 Erez Volk (for FLAC)
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,27 +47,27 @@ void MelderFile_writeAudioFileHeader (MelderFile file, int audioFileType, long s
 
 					/* Form Chunk: contains all other chunks. */
 					if (fwrite ("FORM", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the FORM statement.");
-					binputi4 (4 + (8 + 4) + (8 + 18) + (8 + 8 + dataSize), f);   // the size of the Form Chunk
+					binputi32 (4 + (8 + 4) + (8 + 18) + (8 + 8 + dataSize), f);   // the size of the Form Chunk
 					if (fwrite ("AIFF", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the AIFF file type.");
 
 					/* Format Version Chunk: 8 + 4 bytes. */
 					if (fwrite ("FVER", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the FVER statement.");
-					binputu4 (4, f);   // the size of what follows
-					binputu4 (0xA2805140, f);   // time of version
+					binputu32 (4, f);   // the size of what follows
+					binputu32 (0xA2805140, f);   // time of version
 
 					/* Common Chunk: 8 + 18 bytes. */
 					if (fwrite ("COMM", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the COMM statement.");
-					binputi4 (18, f);   // the size of what follows
-					binputi2 (numberOfChannels, f);
-					binputi4 (numberOfSamples, f);
-					binputi2 (numberOfBitsPerSamplePoint, f);
-					binputr10 (sampleRate, f);
+					binputi32 (18, f);   // the size of what follows
+					binputi16 (numberOfChannels, f);
+					binputi32 (numberOfSamples, f);
+					binputi16 (numberOfBitsPerSamplePoint, f);
+					binputr80 (sampleRate, f);
 
 					/* Sound Data Chunk: 8 + 8 bytes + samples. */
 					if (fwrite ("SSND", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the SSND statement.");
-					binputi4 (8 + dataSize, f);   // the size of what follows
-					binputi4 (0, f);   // offset
-					binputi4 (0, f);   // block size
+					binputi32 (8 + dataSize, f);   // the size of what follows
+					binputi32 (0, f);   // offset
+					binputi32 (0, f);   // block size
 				} catch (MelderError) {
 					Melder_throw (U"AIFF header not written.");
 				}
@@ -78,29 +78,29 @@ void MelderFile_writeAudioFileHeader (MelderFile file, int audioFileType, long s
 
 					/* Form Chunk: contains all other chunks. */
 					if (fwrite ("FORM", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the FORM statement.");
-					binputi4 (4 + (8 + 4) + (8 + 24) + (8 + 8 + dataSize), f);   // the size of the Form Chunk
+					binputi32 (4 + (8 + 4) + (8 + 24) + (8 + 8 + dataSize), f);   // the size of the Form Chunk
 					if (fwrite ("AIFC", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the AIFC file type.");
 
 					/* Format Version Chunk: 8 + 4 bytes. */
 					if (fwrite ("FVER", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the FVER statement.");
-					binputu4 (4, f);   // the size of what follows
-					binputu4 (0xA2805140, f);   // time of version
+					binputu32 (4, f);   // the size of what follows
+					binputu32 (0xA2805140, f);   // time of version
 
 					/* Common Chunk: 8 + 24 bytes. */
 					if (fwrite ("COMM", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the COMM statement.");
-					binputi4 (24, f);   // the size of what follows
-					binputi2 (numberOfChannels, f);
-					binputi4 (numberOfSamples, f);
-					binputi2 (numberOfBitsPerSamplePoint, f);
-					binputr10 (sampleRate, f);
+					binputi32 (24, f);   // the size of what follows
+					binputi16 (numberOfChannels, f);
+					binputi32 (numberOfSamples, f);
+					binputi16 (numberOfBitsPerSamplePoint, f);
+					binputr80 (sampleRate, f);
 					if (fwrite ("NONE", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the compression type.");
-					binputi2 (0, f);   // name of compression
+					binputi16 (0, f);   // name of compression
 
 					/* Sound Data Chunk: 8 + 8 bytes + samples. */
 					if (fwrite ("SSND", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the SSND statement.");
-					binputi4 (8 + dataSize, f);   // the size of what follows
-					binputi4 (0, f);   // offset
-					binputi4 (0, f);   // block size
+					binputi32 (8 + dataSize, f);   // the size of what follows
+					binputi32 (0, f);   // offset
+					binputi32 (0, f);   // block size
 				} catch (MelderError) {
 					Melder_throw (U"AIFC header not written.");
 				}
@@ -123,30 +123,30 @@ void MelderFile_writeAudioFileHeader (MelderFile file, int audioFileType, long s
 					if (sizeOfRiffChunk_i64 > UINT32_MAX)
 						Melder_throw (U"Cannot save a WAV file with more than ", UINT32_MAX, U" bytes.");
 					uint32_t sizeOfRiffChunk_u32 = (uint32_t) sizeOfRiffChunk_i64;
-					binputu4LE (sizeOfRiffChunk_u32, f);
+					binputu32LE (sizeOfRiffChunk_u32, f);
 					if (fwrite ("WAVE", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the WAV file type.");
 
 					/* Format Chunk: if 16-bits audio, then 8 + 16 bytes; else 8 + 40 bytes. */
 					if (fwrite ("fmt ", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the FMT statement.");
-					binputi4LE (formatSize, f);
-					binputi2LE (needExtensibleFormat ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM, f);
-					binputi2LE (numberOfChannels, f);
-					binputi4LE (sampleRate, f);   // number of samples per second
-					binputi4LE (sampleRate * numberOfBytesPerSamplePoint * numberOfChannels, f);   // average number of bytes per second
-					binputi2LE (numberOfBytesPerSamplePoint * numberOfChannels, f);   // block alignment
-					binputi2LE (numberOfBytesPerSamplePoint * 8, f);   // padded bits per sample
+					binputi32LE (formatSize, f);
+					binputi16LE (needExtensibleFormat ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM, f);
+					binputi16LE (numberOfChannels, f);
+					binputi32LE (sampleRate, f);   // number of samples per second
+					binputi32LE (sampleRate * numberOfBytesPerSamplePoint * numberOfChannels, f);   // average number of bytes per second
+					binputi16LE (numberOfBytesPerSamplePoint * numberOfChannels, f);   // block alignment
+					binputi16LE (numberOfBytesPerSamplePoint * 8, f);   // padded bits per sample
 					if (needExtensibleFormat) {
-						binputi2LE (22, f);   // extensionSize
-						binputi2LE (numberOfBitsPerSamplePoint, f);   // valid bits per sample
-						binputi4LE (0, f);   // speaker position mask
-						binputi2LE (WAVE_FORMAT_PCM, f);
+						binputi16LE (22, f);   // extensionSize
+						binputi16LE (numberOfBitsPerSamplePoint, f);   // valid bits per sample
+						binputi32LE (0, f);   // speaker position mask
+						binputi16LE (WAVE_FORMAT_PCM, f);
 						if (fwrite ("\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71",
 							1, 14, f) != 14) Melder_throw (U"Error in file while trying to write the subformat.");
 					}
 
 					/* Data Chunk: 8 bytes + samples. */
 					if (fwrite ("data", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the DATA statement.");
-					binputi4LE (dataSize, f);
+					binputi32LE (dataSize, f);
 				} catch (MelderError) {
 					Melder_throw (U"WAV header not written.");
 				}
@@ -154,13 +154,13 @@ void MelderFile_writeAudioFileHeader (MelderFile file, int audioFileType, long s
 			case Melder_NEXT_SUN: {
 				try {
 					if (fwrite (".snd", 1, 4, f) != 4) Melder_throw (U"Error in file while trying to write the .snd file type tag.");
-					binputi4 (32, f);   // length of header
-					binputi4 (numberOfSamples * 2 * numberOfChannels, f);   // length of data
-					binputi4 (3, f);   // 16-bits linear, not mu-law or A-law
-					binputi4 (sampleRate, f);
-					binputi4 (numberOfChannels, f);
-					binputi4 (0, f);
-					binputi4 (0, f);
+					binputi32 (32, f);   // length of header
+					binputi32 (numberOfSamples * 2 * numberOfChannels, f);   // length of data
+					binputi32 (3, f);   // 16-bits linear, not mu-law or A-law
+					binputi32 (sampleRate, f);
+					binputi32 (numberOfChannels, f);
+					binputi32 (0, f);
+					binputi32 (0, f);
 				} catch (MelderError) {
 					Melder_throw (U"NeXT/Sun header not written.");
 				}
@@ -221,7 +221,7 @@ void MelderFile_writeAudioFileTrailer (MelderFile file, int audioFileType, long
 	bool numberOfBytesPerSamplePointIsOdd = (numberOfBytesPerSamplePoint & 1) != 0;
 	bool needToPadOneByte = shouldPadTheDataToAnEvenNumberOfBytes && numberOfSamplesIsOdd && numberOfChannelsIsOdd && numberOfBytesPerSamplePointIsOdd;
 	if (needToPadOneByte && file -> filePointer)
-		binputi1 (0, file -> filePointer);
+		binputi8 (0, file -> filePointer);
 }
 
 static const char32 *audioFileTypeString [] = { U"none", U"AIFF", U"AIFC", U"WAV", U"NeXT/Sun", U"NIST", U"FLAC", U"MP3" };
@@ -362,7 +362,7 @@ static void Melder_checkAiffFile (FILE *f, int *numberOfChannels, int *encoding,
 	/* Search for Common Chunk and Data Chunk. */
 
 	while (fread (chunkID, 1, 4, f) == 4) {
-		long chunkSize = bingeti4 (f);
+		long chunkSize = bingeti32 (f);
 		if (chunkSize & 1) ++ chunkSize;   // round up to nearest even number
 		/* IN SOUND FILES PRODUCED BY THE SGI'S soundeditor PROGRAM, */
 		/* THE COMMON CHUNK HAS A chunkSize OF 18 INSTEAD OF 38, */
@@ -378,18 +378,18 @@ static void Melder_checkAiffFile (FILE *f, int *numberOfChannels, int *encoding,
 			 * Found a Common Chunk.
 			 */
 			commonChunkPresent = true;
-			*numberOfChannels = bingeti2 (f);
+			*numberOfChannels = bingeti16 (f);
 			if (*numberOfChannels < 1) Melder_throw (U"Too few sound channels (", *numberOfChannels, U").");
-			*numberOfSamples = bingeti4 (f);
+			*numberOfSamples = bingeti32 (f);
 			if (*numberOfSamples <= 0) Melder_throw (U"Too few samples ", *numberOfSamples, U").");
-			numberOfBitsPerSamplePoint = bingeti2 (f);
+			numberOfBitsPerSamplePoint = bingeti16 (f);
 			if (numberOfBitsPerSamplePoint > 32) Melder_throw (U"Too many bits per sample (", numberOfBitsPerSamplePoint, U"; the maximum is 32).");
 			*encoding =
 				numberOfBitsPerSamplePoint > 24 ? Melder_LINEAR_32_BIG_ENDIAN :
 				numberOfBitsPerSamplePoint > 16 ? Melder_LINEAR_24_BIG_ENDIAN :
 				numberOfBitsPerSamplePoint > 8 ? Melder_LINEAR_16_BIG_ENDIAN :
 				Melder_LINEAR_8_SIGNED;
-			*sampleRate = bingetr10 (f);
+			*sampleRate = bingetr80 (f);
 			if (*sampleRate <= 0.0) Melder_throw (U"Wrong sampling frequency (", *sampleRate, U" Hz).");
 			if (isAifc) {
 				/*
@@ -448,7 +448,7 @@ static void Melder_checkWavFile (FILE *f, int *numberOfChannels, int *encoding,
 	/* Search for Format Chunk and Data Chunk. */
 
 	while (fread (chunkID, 1, 4, f) == 4) {
-		uint32_t chunkSize = bingetu4LE (f);
+		uint32_t chunkSize = bingetu32LE (f);
 		if (Melder_debug == 23) {
 			Melder_warning (chunkID [0], U" ", chunkID [1], U" ",
 				chunkID [2], U" ", chunkID [3], U" ", chunkSize);
@@ -457,15 +457,15 @@ static void Melder_checkWavFile (FILE *f, int *numberOfChannels, int *encoding,
 			/*
 			 * Found a Format Chunk.
 			 */
-			uint16_t winEncoding = bingetu2LE (f);
+			uint16_t winEncoding = bingetu16LE (f);
 			formatChunkPresent = true;			
-			*numberOfChannels = bingeti2LE (f);
+			*numberOfChannels = bingeti16LE (f);
 			if (*numberOfChannels < 1) Melder_throw (U"Too few sound channels (", *numberOfChannels, U").");
-			*sampleRate = (double) bingeti4LE (f);
+			*sampleRate = (double) bingeti32LE (f);
 			if (*sampleRate <= 0.0) Melder_throw (U"Wrong sampling frequency (", *sampleRate, U" Hz).");
-			(void) bingeti4LE (f);   // avgBytesPerSec
-			(void) bingeti2LE (f);   // blockAlign
-			numberOfBitsPerSamplePoint = bingeti2LE (f);
+			(void) bingeti32LE (f);   // avgBytesPerSec
+			(void) bingeti16LE (f);   // blockAlign
+			numberOfBitsPerSamplePoint = bingeti16LE (f);
 			if (numberOfBitsPerSamplePoint == 0)
 				numberOfBitsPerSamplePoint = 16;   // the default
 			else if (numberOfBitsPerSamplePoint < 4)
@@ -497,10 +497,10 @@ static void Melder_checkWavFile (FILE *f, int *numberOfChannels, int *encoding,
 				case WAVE_FORMAT_EXTENSIBLE: {
 					if (chunkSize < 40)
 						Melder_throw (U"Not enough format data in extensible WAV format");
-					(void) bingeti2LE (f);   // extensionSize
-					(void) bingeti2LE (f);   // validBitsPerSample
-					(void) bingeti4LE (f);   // channelMask
-					uint16_t winEncoding2 = bingetu2LE (f);   // override
+					(void) bingeti16LE (f);   // extensionSize
+					(void) bingeti16LE (f);   // validBitsPerSample
+					(void) bingeti32LE (f);   // channelMask
+					uint16_t winEncoding2 = bingetu16LE (f);   // override
 					switch (winEncoding2) {
 						case WAVE_FORMAT_PCM:
 							*encoding =
@@ -575,10 +575,10 @@ static void Melder_checkNextSunFile (FILE *f, int *numberOfChannels, int *encodi
 	char tag [4];
 	fread (tag, 1, 4, f);
 	if (strncmp (tag, ".snd", 4)) Melder_throw (U"Not a Sun audio file.");
-	*startOfData = bingeti4 (f);
+	*startOfData = bingeti32 (f);
 	if (*startOfData < 24 || *startOfData > 320)
 		Melder_throw (U"Cannot read header of audio file. Length ", *startOfData, U".");
-	long dataSize = bingeti4 (f);
+	long dataSize = bingeti32 (f);
 	if (dataSize <= 0) {
 		/*
 		 * Incorrect information. Get it from file length.
@@ -588,7 +588,7 @@ static void Melder_checkNextSunFile (FILE *f, int *numberOfChannels, int *encodi
 		dataSize = ftell (f) - *startOfData;
 		fseek (f, save, SEEK_SET);
 	}
-	long sunEncoding = bingeti4 (f);
+	long sunEncoding = bingeti32 (f);
 	switch (sunEncoding) {
 		case 1: *encoding = Melder_MULAW; break;
 		case 2: *encoding = Melder_LINEAR_8_SIGNED; break;
@@ -596,9 +596,9 @@ static void Melder_checkNextSunFile (FILE *f, int *numberOfChannels, int *encodi
 		case 27: *encoding = Melder_ALAW; break;
 		default: Melder_throw (U"Cannot translate audio file encoding ", sunEncoding, U".");
 	}
-	*sampleRate = bingeti4 (f);
+	*sampleRate = bingeti32 (f);
 	if (*sampleRate <= 0) Melder_throw (U"Impossible sampling frequency ", *sampleRate, U" Hz.");
-	*numberOfChannels = bingeti4 (f);
+	*numberOfChannels = bingeti32 (f);
 	if (*numberOfChannels < 1)
 		Melder_throw (U"Wrong number of channels in audio file (", *numberOfChannels, U").");
 	*numberOfSamples = dataSize / Melder_bytesPerSamplePoint (*encoding) / *numberOfChannels;
@@ -873,7 +873,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
 				try {
 					for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 						for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
-							buffer [ichan] [isamp] = bingetu1 (f) * (1.0 / 128) - 1.0;
+							buffer [ichan] [isamp] = bingetu8 (f) * (1.0 / 128) - 1.0;
 						}
 					}
 				} catch (MelderError) {
@@ -1156,7 +1156,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
 				try {
 					for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 						for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
-							buffer [ichan] [isamp] = bingetr4 (f);
+							buffer [ichan] [isamp] = bingetr32 (f);
 						}
 					}
 				} catch (MelderError) {
@@ -1168,7 +1168,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
 				try {
 					for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 						for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
-							buffer [ichan] [isamp] = bingetr4LE (f);
+							buffer [ichan] [isamp] = bingetr32LE (f);
 						}
 					}
 				} catch (MelderError) {
@@ -1180,7 +1180,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
 				try {
 					for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 						for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
-							buffer [ichan] [isamp] = ulaw2linear [bingetu1 (f)] * (1.0 / 32768);
+							buffer [ichan] [isamp] = ulaw2linear [bingetu8 (f)] * (1.0 / 32768);
 						}
 					}
 				} catch (MelderError) {
@@ -1192,7 +1192,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
 				try {
 					for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 						for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
-							buffer [ichan] [isamp] = alaw2linear [bingetu1 (f)] * (1.0 / 32768);
+							buffer [ichan] [isamp] = alaw2linear [bingetu8 (f)] * (1.0 / 32768);
 						}
 					}
 				} catch (MelderError) {
@@ -1232,7 +1232,7 @@ void Melder_readAudioToShort (FILE *f, int numberOfChannels, int encoding, short
 				break;
 			case Melder_LINEAR_8_UNSIGNED:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingetu1 (f) * 256L - 32768;
+					buffer [i] = bingetu8 (f) * 256L - 32768;
 				}
 				break;
 			case Melder_LINEAR_16_BIG_ENDIAN:
@@ -1255,42 +1255,42 @@ void Melder_readAudioToShort (FILE *f, int numberOfChannels, int encoding, short
 				break;
 			case Melder_LINEAR_24_BIG_ENDIAN:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingeti3 (f) / 256;   // BUG: truncation; not ideal
+					buffer [i] = bingeti24 (f) / 256;   // BUG: truncation; not ideal
 				}
 				break;
 			case Melder_LINEAR_24_LITTLE_ENDIAN:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingeti3LE (f) / 256;   // BUG: truncation; not ideal
+					buffer [i] = bingeti24LE (f) / 256;   // BUG: truncation; not ideal
 				}
 				break;
 			case Melder_LINEAR_32_BIG_ENDIAN:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingeti4 (f) / 65536;   // BUG: truncation; not ideal
+					buffer [i] = bingeti32 (f) / 65536;   // BUG: truncation; not ideal
 				}
 				break;
 			case Melder_LINEAR_32_LITTLE_ENDIAN:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingeti4LE (f) / 65536;   // BUG: truncation; not ideal
+					buffer [i] = bingeti32LE (f) / 65536;   // BUG: truncation; not ideal
 				}
 				break;
 			case Melder_IEEE_FLOAT_32_BIG_ENDIAN:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingetr4 (f) * 32768;   // BUG: truncation; not ideal
+					buffer [i] = bingetr32 (f) * 32768;   // BUG: truncation; not ideal
 				}
 				break;
 			case Melder_IEEE_FLOAT_32_LITTLE_ENDIAN:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = bingetr4LE (f) * 32768;   // BUG: truncation; not ideal
+					buffer [i] = bingetr32LE (f) * 32768;   // BUG: truncation; not ideal
 				}
 				break;
 			case Melder_MULAW:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = ulaw2linear [bingetu1 (f)];
+					buffer [i] = ulaw2linear [bingetu8 (f)];
 				}
 				break;
 			case Melder_ALAW:
 				for (i = 0; i < n; i ++) {
-					buffer [i] = alaw2linear [bingetu1 (f)];
+					buffer [i] = alaw2linear [bingetu8 (f)];
 				}
 				break;
 			default:
@@ -1318,34 +1318,34 @@ void MelderFile_writeShortToAudio (MelderFile file, int numberOfChannels, int en
 		switch (encoding) {
 			case Melder_LINEAR_8_SIGNED:
 				for (i = start; i < n; i += step)
-					binputi1 (buffer [i] >> 8, f);
+					binputi8 (buffer [i] >> 8, f);
 			break; case Melder_LINEAR_8_UNSIGNED:
 				for (i = start; i < n; i += step)
-					binputu1 ((buffer [i] >> 8) + 128, f);
+					binputu8 ((buffer [i] >> 8) + 128, f);
 			break; case Melder_LINEAR_16_BIG_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputi2 (buffer [i], f);
+					binputi16 (buffer [i], f);
 			break; case Melder_LINEAR_16_LITTLE_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputi2LE (buffer [i], f);
+					binputi16LE (buffer [i], f);
 			break; case Melder_LINEAR_24_BIG_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputi3 (buffer [i] << 8, f);
+					binputi24 (buffer [i] << 8, f);
 			break; case Melder_LINEAR_24_LITTLE_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputi3LE (buffer [i] << 8, f);
+					binputi24LE (buffer [i] << 8, f);
 			break; case Melder_LINEAR_32_BIG_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputi4 (buffer [i] << 16, f);
+					binputi32 (buffer [i] << 16, f);
 			break; case Melder_LINEAR_32_LITTLE_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputi4LE (buffer [i] << 16, f);
+					binputi32LE (buffer [i] << 16, f);
 			break; case Melder_IEEE_FLOAT_32_BIG_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputr4 (buffer [i] / 32768.0, f);
+					binputr32 (buffer [i] / 32768.0, f);
 			break; case Melder_IEEE_FLOAT_32_LITTLE_ENDIAN:
 				for (i = start; i < n; i += step)
-					binputr4LE (buffer [i] / 32768.0, f);
+					binputr32LE (buffer [i] / 32768.0, f);
 			break;
 			case Melder_FLAC_COMPRESSION_16:
 			case Melder_FLAC_COMPRESSION_24:
@@ -1379,7 +1379,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 128.0);
 						if (value < -128.0) { value = -128.0; nclipped ++; }
 						if (value > 127.0) { value = 127.0; nclipped ++; }
-						binputi1 ((int) value, f);
+						binputi8 ((int) value, f);
 					}
 				}
 				break;
@@ -1389,7 +1389,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = floor ((buffer [ichan] [isamp] + 1.0) * 128.0);
 						if (value < 0.0) { value = 0.0; nclipped ++; }
 						if (value > 255.0) { value = 255.0; nclipped ++; }
-						binputu1 ((int) value, f);
+						binputu8 ((int) value, f);
 					}
 				}
 				break;
@@ -1399,7 +1399,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 32768.0);
 						if (value < -32768.0) { value = -32768.0; nclipped ++; }
 						if (value > 32767.0) { value = 32767.0; nclipped ++; }
-						binputi2 ((int16) value, f);
+						binputi16 ((int16) value, f);
 					}
 				}
 				break;
@@ -1409,7 +1409,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 32768.0);
 						if (value < -32768.0) { value = -32768.0; nclipped ++; }
 						if (value > 32767.0) { value = 32767.0; nclipped ++; }
-						binputi2LE ((int16) value, f);
+						binputi16LE ((int16) value, f);
 					}
 				}
 				break;
@@ -1419,7 +1419,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 8388608.0);
 						if (value < -8388608.0) { value = -8388608.0; nclipped ++; }
 						if (value > 8388607.0) { value = 8388607.0; nclipped ++; }
-						binputi3 ((int32) value, f);
+						binputi24 ((int32) value, f);
 					}
 				}
 				break;
@@ -1429,7 +1429,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 8388608.0);
 						if (value < -8388608.0) { value = -8388608.0; nclipped ++; }
 						if (value > 8388607.0) { value = 8388607.0; nclipped ++; }
-						binputi3LE ((int32) value, f);
+						binputi24LE ((int32) value, f);
 					}
 				}
 				break;
@@ -1439,7 +1439,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 2147483648.0);
 						if (value < -2147483648.0) { value = -2147483648.0; nclipped ++; }
 						if (value > 2147483647.0) { value = 2147483647.0; nclipped ++; }
-						binputi4 ((int32) value, f);   // safe cast: rounding and range already handled
+						binputi32 ((int32) value, f);   // safe cast: rounding and range already handled
 					}
 				}
 				break;
@@ -1449,7 +1449,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 						double value = round (buffer [ichan] [isamp] * 2147483648.0);
 						if (value < -2147483648.0) { value = -2147483648.0; nclipped ++; }
 						if (value > 2147483647.0) { value = 2147483647.0; nclipped ++; }
-						binputi4LE ((int32) value, f);
+						binputi32LE ((int32) value, f);
 					}
 				}
 				break;
@@ -1457,7 +1457,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 				for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 					for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
 						double value = buffer [ichan] [isamp];
-						binputr4 (value, f);
+						binputr32 (value, f);
 					}
 				}
 				break;
@@ -1465,7 +1465,7 @@ void MelderFile_writeFloatToAudio (MelderFile file, int numberOfChannels, int en
 				for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
 					for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
 						double value = buffer [ichan] [isamp];
-						binputr4LE (value, f);
+						binputr32LE (value, f);
 					}
 				}
 				break;
diff --git a/sys/melder_console.cpp b/sys/melder_console.cpp
index 9d49c5b..ccc6454 100644
--- a/sys/melder_console.cpp
+++ b/sys/melder_console.cpp
@@ -1,6 +1,6 @@
 /* melder_console.cpp
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
  */
 
 #include "melder.h"
-#include "NUM.h"
 
 #if defined (_WIN32) && defined (CONSOLE_APPLICATION)
 int main (int argc, char *argvA []);
diff --git a/sys/melder_debug.cpp b/sys/melder_debug.cpp
index 4a6dec8..43f1427 100644
--- a/sys/melder_debug.cpp
+++ b/sys/melder_debug.cpp
@@ -29,11 +29,12 @@
 #endif
 
 int Melder_debug = 0;
-
 /*
-
-If Melder_debug is set to the following values in Praat,
-the behaviour of that program changes in the following way:
+Melder_debug will always be set to 0 when Praat starts up.
+If Melder_debug is temporarily set to the following values
+(preferably with the "Debug..." command under Praat->Technical,
+ which you can use from a script),
+the behaviour of Praat will temporarily change in the following ways:
 
 1: Windows: use C-clock instead of multimedia-clock in melder_audio.cpp.
 2: Windows: always reset waveOut, even when played to end, in melder_audio.cpp.
@@ -77,6 +78,15 @@ the behaviour of that program changes in the following way:
 45: tracing structMatrix :: read ()
 46: trace GTK parent sizes in _GuiObject_position ()
 47: force resampling in OTGrammar RIP
+48: compute sum, mean, stdev, inner, and so on, with naive implementation in real64
+49: compute sum, mean, stdev, inner, and so on, with naive implementation in real80
+50: compute sum, mean, stdev with first-element offset (80 bits)
+51: compute sum, mean, stdev with Chan, Golub & LeVeque's pairwise algorithm (80 bits)
+52: compute sum, mean, stdev, inner and so on with simple pairwise algorithm, base case 8 (80 bits)
+53: compute sum, mean, stdev, inner and so on with simple pairwise algorithm, base case 16 (80 bits)
+54: compute sum, mean, stdev, inner and so on with two cycles, as in R (80 bits)
+55: compute sum, mean, stdev, inner and so on with simple pairwise algorithm, base case 32 (80 bits)
+(other numbers than 48-55: compute sum, mean, stdev, inner and so on with simple pairwise algorithm, base case 64 [80 bits])
 900: use DG Meta Serif Science instead of Palatino
 1264: Mac: Sound_record_fixedTime uses microphone "FW Solo (1264)"
 
@@ -211,7 +221,7 @@ void Melder_writeToConsole (const char32 *message, bool useStderr) {
 		for (const char32* p = message; *p != U'\0'; p ++) {
 			char32 kar = *p;
 			if (kar <= 0x00007F) {
-				fputc ((int) kar, f);   // because fputc wants an int instead of an uint8 (guarded conversion)
+				fputc ((int) kar, f);   // because fputc wants an int instead of a uint8 (guarded conversion)
 			} else if (kar <= 0x0007FF) {
 				fputc (0xC0 | (kar >> 6), f);
 				fputc (0x80 | (kar & 0x00003F), f);
@@ -390,7 +400,7 @@ void Melder_casual (Melder_19_ARGS) {
 /********** TRACE **********/
 
 bool Melder_isTracing = false;
-static structMelderFile theTracingFile = { 0 };
+static structMelderFile theTracingFile { };
 
 void Melder_tracingToFile (MelderFile file) {
 	MelderFile_copy (file, & theTracingFile);
diff --git a/sys/melder_files.cpp b/sys/melder_files.cpp
index e28361f..a668d75 100644
--- a/sys/melder_files.cpp
+++ b/sys/melder_files.cpp
@@ -1,6 +1,6 @@
 /* melder_files.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -42,9 +42,6 @@
  * pb 2012/10/07 
  */
 
-#include <cstdio>
-using namespace std;
-
 #if defined (UNIX)
 	#include <unistd.h>
 	#include <sys/stat.h>
@@ -77,7 +74,7 @@ extern "C" void FLAC__stream_encoder_delete (FLAC__StreamEncoder *);
 
 static char32 theShellDirectory [kMelder_MAXPATH+1];
 void Melder_rememberShellDirectory () {
-	structMelderDir shellDir { { 0 } };
+	structMelderDir shellDir { };
 	Melder_getDefaultDir (& shellDir);
 	str32cpy (theShellDirectory, Melder_dirToPath (& shellDir));
 }
@@ -211,7 +208,7 @@ void Melder_relativePathToFile (const char32 *path, MelderFile file) {
 		} else if (path [0] == U'/' || str32equ (path, U"<stdout>") || str32str (path, U"://")) {
 			str32cpy (file -> path, path);
 		} else {
-			structMelderDir dir = { { 0 } };
+			structMelderDir dir { };
 			Melder_getDefaultDir (& dir);   // BUG
 			if (dir. path [0] == U'/' && dir. path [1] == U'\0') {
 				Melder_sprint (file -> path,kMelder_MAXPATH+1, U"/", path);
@@ -226,7 +223,7 @@ void Melder_relativePathToFile (const char32 *path, MelderFile file) {
 		 *    LPT1:
 		 *    \\host\path
 		 */
-		structMelderDir dir { { 0 } };
+		structMelderDir dir { };
 		if (path [0] == U'~' && path [1] == U'/') {
 			Melder_getHomeDir (& dir);
 			Melder_sprint (file -> path,kMelder_MAXPATH+1, dir. path, & path [1]);
@@ -317,7 +314,7 @@ void MelderDir_getFile (MelderDir parent, const char32 *fileName, MelderFile fil
 }
 
 void MelderDir_relativePathToFile (MelderDir dir, const char32 *path, MelderFile file) {
-	structMelderDir saveDir { { 0 } };
+	structMelderDir saveDir { };
 	Melder_getDefaultDir (& saveDir);
 	Melder_setDefaultDir (dir);
 	Melder_relativePathToFile (path, file);
@@ -496,7 +493,7 @@ void Melder_getHomeDir (MelderDir homeDir) {
 
 void Melder_getPrefDir (MelderDir prefDir) {
 	#if defined (macintosh)
-		structMelderDir homeDir;
+		structMelderDir homeDir { };
 		Melder_getHomeDir (& homeDir);
 		Melder_sprint (prefDir -> path,kMelder_MAXPATH+1, homeDir. path, U"/Library/Preferences");
 	#elif defined (UNIX)
@@ -777,14 +774,14 @@ void Melder_setDefaultDir (MelderDir dir) {
 }
 
 void MelderFile_setDefaultDir (MelderFile file) {
-	structMelderDir dir { { 0 } };
+	structMelderDir dir { };
 	MelderFile_getParentDir (file, & dir);
 	Melder_setDefaultDir (& dir);
 }
 
 void Melder_createDirectory (MelderDir parent, const char32 *dirName, int mode) {
 #if defined (UNIX)
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	if (dirName [0] == U'/') {
 		Melder_sprint (file. path,kMelder_MAXPATH+1, dirName);   // absolute path
 	} else if (parent -> path [0] == U'/' && parent -> path [1] == U'\0') {
@@ -797,7 +794,7 @@ void Melder_createDirectory (MelderDir parent, const char32 *dirName, int mode)
 	if (mkdir (utf8path, mode) == -1 && errno != EEXIST)   // ignore if directory already exists
 		Melder_throw (U"Cannot create directory ", & file, U".");
 #elif defined (_WIN32)
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	SECURITY_ATTRIBUTES sa;
 	(void) mode;
 	sa. nLength = sizeof (SECURITY_ATTRIBUTES);
@@ -819,8 +816,6 @@ void Melder_createDirectory (MelderDir parent, const char32 *dirName, int mode)
  * Routines for wrapping the file pointers.
  */
 
-#define my  me ->
-
 MelderFile MelderFile_open (MelderFile me) {
 	my filePointer = Melder_fopen (me, "rb");
 	my openForReading = true;
@@ -836,7 +831,7 @@ char * MelderFile_readLine (MelderFile me) {
 	if (! buffer) {
 		buffer = Melder_malloc (char, capacity = 100);
 	}
-	for (i = 0; 1; i ++) {
+	for (i = 0; true; i ++) {
 		if (i >= capacity) {
 			buffer = (char *) Melder_realloc (buffer, capacity *= 2);
 		}
diff --git a/sys/melder_ftoa.cpp b/sys/melder_ftoa.cpp
index 7e4acd7..664322f 100644
--- a/sys/melder_ftoa.cpp
+++ b/sys/melder_ftoa.cpp
@@ -1,6 +1,6 @@
 /* melder_ftoa.cpp
  *
- * Copyright (C) 1992-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2011,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
  */
 
 #include "melder.h"
-#include "NUM.h"
 
 /********** NUMBER TO STRING CONVERSION **********/
 
@@ -26,8 +25,8 @@
 #define MAXIMUM_NUMERIC_STRING_LENGTH  400
 	/* = sign + 324 + point + 60 + e + sign + 3 + null byte + ("·10^^" - "e") + 4 extra */
 
-static  char   buffers8  [NUMBER_OF_BUFFERS] [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
-static  char32 buffers32 [NUMBER_OF_BUFFERS] [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
+static char   buffers8  [NUMBER_OF_BUFFERS] [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
+static char32 buffers32 [NUMBER_OF_BUFFERS] [MAXIMUM_NUMERIC_STRING_LENGTH + 1];
 static int ibuffer = 0;
 
 #define CONVERT_BUFFER_TO_CHAR32 \
@@ -36,7 +35,7 @@ static int ibuffer = 0;
 	*q = U'\0'; \
 	return buffers32 [ibuffer];
 
-const char * Melder8_integer (int64 value) {
+const char * Melder8_integer (int64 value) noexcept {
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	if (sizeof (long) == 8) {
 		int n = snprintf (buffers8 [ibuffer], MAXIMUM_NUMERIC_STRING_LENGTH + 1, "%ld", (long) value);   // cast to identical type, to make compiler happy
@@ -70,12 +69,12 @@ const char * Melder8_integer (int64 value) {
 	}
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_integer (int64 value) {
+const char32 * Melder_integer (int64 value) noexcept {
 	const char *p = Melder8_integer (value);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_bigInteger (int64 value) {
+const char * Melder8_bigInteger (int64 value) noexcept {
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	char *text = buffers8 [ibuffer];
 	text [0] = '\0';
@@ -124,20 +123,20 @@ const char * Melder8_bigInteger (int64 value) {
 	sprintf (text + strlen (text), firstDigitPrinted ? "%03d" : "%d", units);
 	return text;
 }
-const char32 * Melder_bigInteger (int64 value) {
+const char32 * Melder_bigInteger (int64 value) noexcept {
 	const char *p = Melder8_bigInteger (value);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_boolean (bool value) {
+const char * Melder8_boolean (bool value) noexcept {
 	return value ? "yes" : "no";
 }
-const char32 * Melder_boolean (bool value) {
+const char32 * Melder_boolean (bool value) noexcept {
 	return value ? U"yes" : U"no";
 }
 
-const char * Melder8_double (double value) {
-	if (value == NUMundefined) return "--undefined--";
+const char * Melder8_double (double value) noexcept {
+	if (isundef (value)) return "--undefined--";
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	sprintf (buffers8 [ibuffer], "%.15g", value);
 	if (strtod (buffers8 [ibuffer], nullptr) != value) {
@@ -148,36 +147,36 @@ const char * Melder8_double (double value) {
 	}
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_double (double value) {
+const char32 * Melder_double (double value) noexcept {
 	const char *p = Melder8_double (value);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_single (double value) {
-	if (value == NUMundefined) return "--undefined--";
+const char * Melder8_single (double value) noexcept {
+	if (isundef (value)) return "--undefined--";
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	sprintf (buffers8 [ibuffer], "%.9g", value);
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_single (double value) {
+const char32 * Melder_single (double value) noexcept {
 	const char *p = Melder8_single (value);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_half (double value) {
-	if (value == NUMundefined) return "--undefined--";
+const char * Melder8_half (double value) noexcept {
+	if (isundef (value)) return "--undefined--";
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	sprintf (buffers8 [ibuffer], "%.4g", value);
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_half (double value) {
+const char32 * Melder_half (double value) noexcept {
 	const char *p = Melder8_half (value);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_fixed (double value, int precision) {
+const char * Melder8_fixed (double value, int precision) noexcept {
 	int minimumPrecision;
-	if (value == NUMundefined) return "--undefined--";
+	if (isundef (value)) return "--undefined--";
 	if (value == 0.0) return "0";
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	if (precision > 60) precision = 60;
@@ -188,15 +187,15 @@ const char * Melder8_fixed (double value, int precision) {
 	Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_fixed (double value, int precision) {
+const char32 * Melder_fixed (double value, int precision) noexcept {
 	const char *p = Melder8_fixed (value, precision);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_fixedExponent (double value, int exponent, int precision) {
+const char * Melder8_fixedExponent (double value, int exponent, int precision) noexcept {
 	double factor = pow (10, exponent);
 	int minimumPrecision;
-	if (value == NUMundefined) return "--undefined--";
+	if (isundef (value)) return "--undefined--";
 	if (value == 0.0) return "0";
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	if (precision > 60) precision = 60;
@@ -208,14 +207,14 @@ const char * Melder8_fixedExponent (double value, int exponent, int precision) {
 	Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_fixedExponent (double value, int exponent, int precision) {
+const char32 * Melder_fixedExponent (double value, int exponent, int precision) noexcept {
 	const char *p = Melder8_fixedExponent (value, exponent, precision);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_percent (double value, int precision) {
+const char * Melder8_percent (double value, int precision) noexcept {
 	int minimumPrecision;
-	if (value == NUMundefined) return "--undefined--";
+	if (isundef (value)) return "--undefined--";
 	if (value == 0.0) return "0";
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	if (precision > 60) precision = 60;
@@ -227,12 +226,12 @@ const char * Melder8_percent (double value, int precision) {
 	Melder_assert (n <= MAXIMUM_NUMERIC_STRING_LENGTH);
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_percent (double value, int precision) {
+const char32 * Melder_percent (double value, int precision) noexcept {
 	const char *p = Melder8_percent (value, precision);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char32 * Melder_float (const char32 *number) {
+const char32 * Melder_float (const char32 *number) noexcept {
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	if (! str32chr (number, 'e')) {
 		str32cpy (buffers32 [ibuffer], number);
@@ -257,9 +256,9 @@ const char32 * Melder_float (const char32 *number) {
 	return buffers32 [ibuffer];
 }
 
-const char * Melder8_naturalLogarithm (double lnNumber) {
-	if (lnNumber == NUMundefined) return "--undefined--";
-	if (lnNumber == -INFINITY) return "0";
+const char * Melder8_naturalLogarithm (double lnNumber) noexcept {
+	//if (lnNumber == -INFINITY) return "0";   // this would have been nice, but cannot be relied upon
+	if (isundef (lnNumber)) return "--undefined--";
 	double log10Number = lnNumber * NUMlog10e;
 	if (log10Number < -41.0) {
 		if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
@@ -275,34 +274,69 @@ const char * Melder8_naturalLogarithm (double lnNumber) {
 			sprintf (buffers8 [ibuffer], "%.16g", remainder10);
 			if (strtod (buffers8 [ibuffer], nullptr) != remainder10) sprintf (buffers8 [ibuffer], "%.17g", remainder10);
 		}
-		sprintf (buffers8 [ibuffer] + strlen (buffers8 [ibuffer]), "e-%ld", ceiling);
+		sprintf (buffers8 [ibuffer] + strlen (buffers8 [ibuffer]), "e-%ld", (long) ceiling);
 	} else {
 		return Melder8_double (exp (lnNumber));
 	}
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_naturalLogarithm (double lnNumber) {
+const char32 * Melder_naturalLogarithm (double lnNumber) noexcept {
 	const char *p = Melder8_naturalLogarithm (lnNumber);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char * Melder8_pointer (void *pointer) {
+const char * Melder8_pointer (void *pointer) noexcept {
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	sprintf (buffers8 [ibuffer], "%p", pointer);
 	return buffers8 [ibuffer];
 }
-const char32 * Melder_pointer (void *pointer) {
+const char32 * Melder_pointer (void *pointer) noexcept {
 	const char *p = Melder8_pointer (pointer);
 	CONVERT_BUFFER_TO_CHAR32
 }
 
-const char32 * Melder_character (char32 kar) {
+const char32 * Melder_character (char32 kar) noexcept {
 	if (++ ibuffer == NUMBER_OF_BUFFERS) ibuffer = 0;
 	buffers32 [ibuffer] [0] = kar;
 	buffers32 [ibuffer] [1] = U'\0';
 	return buffers32 [ibuffer];
 }
 
+/********** TENSOR TO STRING CONVERSION **********/
+
+#define NUMBER_OF_TENSOR_BUFFERS  3
+static MelderString theTensorBuffers [NUMBER_OF_TENSOR_BUFFERS] { };
+static int iTensorBuffer { 0 };
+
+const char32 * Melder_numvec (numvec value) {
+	if (++ iTensorBuffer == NUMBER_OF_TENSOR_BUFFERS) iTensorBuffer = 0;
+	MelderString *string = & theTensorBuffers [iTensorBuffer];
+	MelderString_empty (string);
+	if (value.at) {
+		for (long i = 1; i <= value.size; i ++) {
+			MelderString_append (string, value [i], U'\n');
+		}
+	}
+	return string -> string;
+}
+const char32 * Melder_nummat  (nummat value) {
+	if (++ iTensorBuffer == NUMBER_OF_TENSOR_BUFFERS) iTensorBuffer = 0;
+	MelderString *string = & theTensorBuffers [iTensorBuffer];
+	MelderString_empty (string);
+	if (value.at) {
+		for (long irow = 1; irow <= value.nrow; irow ++) {
+			for (long icol = 1; icol <= value.ncol; icol ++) {
+				MelderString_append (string, value [irow] [icol]);
+				if (icol < value.ncol) MelderString_appendCharacter (string, U' ');
+			}
+			if (irow < value.nrow) MelderString_appendCharacter (string, U'\n');
+		}
+	}
+	return string -> string;
+}
+
+/********** STRING TO STRING CONVERSION **********/
+
 static MelderString thePadBuffers [NUMBER_OF_BUFFERS];
 static int iPadBuffer { 0 };
 
diff --git a/sys/melder_info.cpp b/sys/melder_info.cpp
index 8f39beb..b87dc85 100644
--- a/sys/melder_info.cpp
+++ b/sys/melder_info.cpp
@@ -1,6 +1,6 @@
 /* melder_info.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
  */
 
 #include "melder.h"
-#include "NUM.h"   // NUMundefined
 
 static void defaultInformation (const char32 *message) {
 	Melder_writeToConsole (message, false);
diff --git a/sys/melder_readtext.cpp b/sys/melder_readtext.cpp
index de89840..f7b5c14 100644
--- a/sys/melder_readtext.cpp
+++ b/sys/melder_readtext.cpp
@@ -1,6 +1,6 @@
 /* melder_readtext.cpp
  *
- * Copyright (C) 2008-2011,2014,2015 Paul Boersma
+ * Copyright (C) 2008-2011,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,6 @@
 #include "melder.h"
 #include "UnicodeData.h"
 #include "abcio.h"
-#define my  me ->
 
 char32 MelderReadText_getChar (MelderReadText me) {
 	if (my string32) {
@@ -222,12 +221,12 @@ static char32 * _MelderFile_readText (MelderFile file, char **string8) {
 			text.reset (Melder_malloc (char32, length + 1));
 			if (type == 1) {
 				for (int64 i = 0; i < length; i ++) {
-					char16 kar1 = bingetu2 (f);
+					char16 kar1 = bingetu16 (f);
 					if (kar1 < 0xD800) {
 						text [i] = (char32) kar1;   // convert up without sign extension
 					} else if (kar1 < 0xDC00) {
 						length --;
-						char16 kar2 = bingetu2 (f);
+						char16 kar2 = bingetu16 (f);
 						if (kar2 >= 0xDC00 && kar2 <= 0xDFFF) {
 							text [i] = (char32) (0x010000 +
 								(char32) (((char32) kar1 & 0x0003FF) << 10) +
@@ -243,12 +242,12 @@ static char32 * _MelderFile_readText (MelderFile file, char **string8) {
 				}
 			} else {
 				for (int64 i = 0; i < length; i ++) {
-					char16 kar1 = bingetu2LE (f);
+					char16 kar1 = bingetu16LE (f);
 					if (kar1 < 0xD800) {
 						text [i] = (char32) kar1;   // convert up without sign extension
 					} else if (kar1 < 0xDC00) {
 						length --;
-						char16 kar2 = bingetu2LE (f);
+						char16 kar2 = bingetu16LE (f);
 						if (kar2 >= 0xDC00 && kar2 <= 0xDFFF) {
 							text [i] = (char32) (0x010000 +
 								(char32) (((char32) kar1 & 0x0003FF) << 10) +
diff --git a/sys/melder_strings.cpp b/sys/melder_strings.cpp
index f028aaf..e1e969a 100644
--- a/sys/melder_strings.cpp
+++ b/sys/melder_strings.cpp
@@ -1,6 +1,6 @@
 /* melder_strings.cpp
  *
- * Copyright (C) 2006-2011,2015 Paul Boersma
+ * Copyright (C) 2006-2011,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,7 +18,6 @@
 
 #include "melder.h"
 #include "UnicodeData.h"
-#define my  me ->
 #define FREE_THRESHOLD_BYTES 10000LL
 
 static int64 totalNumberOfAllocations = 0, totalNumberOfDeallocations = 0, totalAllocationSize = 0, totalDeallocationSize = 0;
diff --git a/sys/melder_sysenv.cpp b/sys/melder_sysenv.cpp
index 6e1cf81..8680355 100644
--- a/sys/melder_sysenv.cpp
+++ b/sys/melder_sysenv.cpp
@@ -1,6 +1,6 @@
 /* melder_sysenv.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,7 +39,6 @@
 	#include <sys/wait.h>
 #endif
 #include "melder.h"
-#include "NUM.h"
 
 char32 * Melder_getenv (const char32 *variableName) {
 	#if defined (macintosh) || defined (UNIX) || defined (__MINGW32__) || defined (__CYGWIN__)
diff --git a/sys/melder_textencoding.cpp b/sys/melder_textencoding.cpp
index c276e18..3aeb484 100644
--- a/sys/melder_textencoding.cpp
+++ b/sys/melder_textencoding.cpp
@@ -1,6 +1,6 @@
 /* melder_textencoding.cpp
  *
- * Copyright (C) 2007-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 2007-2011,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -189,7 +189,7 @@ size_t str32len_utf16 (const char32 *string, bool nativizeNewlines) {
 
 char32 * Melder_peek8to32 (const char *textA) {
 	if (! textA) return nullptr;
-	static MelderString buffers [19] { { 0 } };
+	static MelderString buffers [19] { };
 	static int ibuffer = 0;
 	if (++ ibuffer == 11) ibuffer = 0;
 	MelderString_empty (& buffers [ibuffer]);
@@ -416,7 +416,7 @@ char32 * Melder_8to32 (const char *string) {
 
 char32 * Melder_peek16to32 (const char16 *text) {
 	if (! text) return nullptr;
-	static MelderString buffers [19] { { 0 } };
+	static MelderString buffers [19] { };
 	static int ibuffer = 0;
 	if (++ ibuffer == 19) ibuffer = 0;
 	MelderString_empty (& buffers [ibuffer]);
@@ -502,7 +502,7 @@ char * Melder_peek32to8 (const char32 *text) {
 
 char16 * Melder_peek32to16 (const char32 *text, bool nativizeNewlines) {
 	if (! text) return nullptr;
-	static MelderString16 buffers [19] { { 0 } };
+	static MelderString16 buffers [19] { };
 	static int ibuffer = 0;
 	if (++ ibuffer == 19) ibuffer = 0;
 	MelderString16_empty (& buffers [ibuffer]);
diff --git a/sys/melder_token.cpp b/sys/melder_token.cpp
index b5b4793..b8faf51 100644
--- a/sys/melder_token.cpp
+++ b/sys/melder_token.cpp
@@ -17,7 +17,6 @@
  */
 
 #include "melder.h"
-#include "NUM.h"
 
 long Melder_countTokens (const char32 *string) {
 	long numberOfTokens = 0;
diff --git a/sys/melder_writetext.cpp b/sys/melder_writetext.cpp
index 5e33a78..d4fec92 100644
--- a/sys/melder_writetext.cpp
+++ b/sys/melder_writetext.cpp
@@ -1,6 +1,6 @@
 /* melder_writetext.cpp
  *
- * Copyright (C) 2007-2011,2015,2016 Paul Boersma
+ * Copyright (C) 2007-2011,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -76,21 +76,21 @@ void MelderFile_writeText (MelderFile file, const char32 *text, enum kMelder_tex
 		}
 		funlockfile (f);
 	} else {
-		binputu2 (0xFEFF, f);   // Byte Order Mark
+		binputu16 (0xFEFF, f);   // Byte Order Mark
 		size_t n = str32len (text);
 		for (size_t i = 0; i < n; i ++) {
 			char32 kar = text [i];
 			#ifdef _WIN32
-				if (kar == U'\n') binputu2 (13, f);
+				if (kar == U'\n') binputu16 (13, f);
 			#endif
 			if (kar <= 0x00FFFF) {
-				binputu2 ((char16) kar, f);   // guarded conversion down
+				binputu16 ((char16) kar, f);   // guarded conversion down
 			} else if (kar <= 0x10FFFF) {
 				kar -= 0x010000;
-				binputu2 (0xD800 | (uint16) (kar >> 10), f);
-				binputu2 (0xDC00 | (uint16) ((char16) kar & 0x3ff), f);
+				binputu16 (0xD800 | (uint16) (kar >> 10), f);
+				binputu16 (0xDC00 | (uint16) ((char16) kar & 0x3ff), f);
 			} else {
-				binputu2 (UNICODE_REPLACEMENT_CHARACTER, f);
+				binputu16 (UNICODE_REPLACEMENT_CHARACTER, f);
 			}
 		}
 	}
@@ -146,37 +146,37 @@ void MelderFile_appendText (MelderFile file, const char32 *text) {
 			 */
 			autostring32 oldText = MelderFile_readText (file);
 			autofile f2 = Melder_fopen (file, "wb");
-			binputu2 (0xfeff, f2);
+			binputu16 (0xfeff, f2);
 			int64 n = str32len (oldText.peek());
 			for (int64 i = 0; i < n; i ++) {
 				char32 kar = oldText [i];
 				#ifdef _WIN32
-					if (kar == U'\n') binputu2 (13, f2);
+					if (kar == U'\n') binputu16 (13, f2);
 				#endif
 				if (kar <= 0x00FFFF) {
-					binputu2 ((uint16) kar, f2);   // guarded conversion down
+					binputu16 ((uint16) kar, f2);   // guarded conversion down
 				} else if (kar <= 0x10FFFF) {
 					kar -= 0x010000;
-					binputu2 ((uint16) (0x00D800 | (kar >> 10)), f2);
-					binputu2 ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
+					binputu16 ((uint16) (0x00D800 | (kar >> 10)), f2);
+					binputu16 ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
 				} else {
-					binputu2 (UNICODE_REPLACEMENT_CHARACTER, f2);
+					binputu16 (UNICODE_REPLACEMENT_CHARACTER, f2);
 				}
 			}
 			n = str32len (text);
 			for (int64 i = 0; i < n; i ++) {
 				char32 kar = text [i];
 				#ifdef _WIN32
-					if (kar == U'\n') binputu2 (13, f2);
+					if (kar == U'\n') binputu16 (13, f2);
 				#endif
 				if (kar <= 0x00FFFF) {
-					binputu2 ((uint16) kar, f2);   // guarded conversion down
+					binputu16 ((uint16) kar, f2);   // guarded conversion down
 				} else if (kar <= 0x10FFFF) {
 					kar -= 0x010000;
-					binputu2 ((uint16) (0x00D800 | (kar >> 10)), f2);
-					binputu2 ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
+					binputu16 ((uint16) (0x00D800 | (kar >> 10)), f2);
+					binputu16 ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
 				} else {
-					binputu2 (UNICODE_REPLACEMENT_CHARACTER, f2);
+					binputu16 (UNICODE_REPLACEMENT_CHARACTER, f2);
 				}
 			}
 			f2.close (file);
@@ -188,30 +188,30 @@ void MelderFile_appendText (MelderFile file, const char32 *text) {
 			if (type == 1) {
 				char32 kar = text [i];
 				#ifdef _WIN32
-					if (kar == U'\n') binputu2 (13, f2);
+					if (kar == U'\n') binputu16 (13, f2);
 				#endif
 				if (kar <= 0x00FFFF) {
-					binputu2 ((uint16) kar, f2);   // guarded conversion down
+					binputu16 ((uint16) kar, f2);   // guarded conversion down
 				} else if (kar <= 0x10FFFF) {
 					kar -= 0x010000;
-					binputu2 ((uint16) (0x00D800 | (kar >> 10)), f2);
-					binputu2 ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
+					binputu16 ((uint16) (0x00D800 | (kar >> 10)), f2);
+					binputu16 ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
 				} else {
-					binputu2 (UNICODE_REPLACEMENT_CHARACTER, f2);
+					binputu16 (UNICODE_REPLACEMENT_CHARACTER, f2);
 				}
 			} else {
 				char32 kar = text [i];
 				#ifdef _WIN32
-					if (kar == U'\n') binputu2LE (13, f2);
+					if (kar == U'\n') binputu16LE (13, f2);
 				#endif
 				if (kar <= 0x00FFFF) {
-					binputu2LE ((uint16) kar, f2);   // guarded conversion down
+					binputu16LE ((uint16) kar, f2);   // guarded conversion down
 				} else if (kar <= 0x10FFFF) {
 					kar -= 0x010000;
-					binputu2LE ((uint16) (0x00D800 | (kar >> 10)), f2);
-					binputu2LE ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
+					binputu16LE ((uint16) (0x00D800 | (kar >> 10)), f2);
+					binputu16LE ((uint16) (0x00DC00 | (kar & 0x0003ff)), f2);
 				} else {
-					binputu2LE (UNICODE_REPLACEMENT_CHARACTER, f2);
+					binputu16LE (UNICODE_REPLACEMENT_CHARACTER, f2);
 				}
 			}
 		}
@@ -252,15 +252,15 @@ static void _MelderFile_write (MelderFile file, const char32 *string) {
 	} else {
 		for (int64 i = 0; i < length; i ++) {
 			char32 kar = string [i];
-			if (kar == U'\n' && file -> requiresCRLF) binputu2 (13, f);
+			if (kar == U'\n' && file -> requiresCRLF) binputu16 (13, f);
 			if (kar <= 0x00FFFF) {
-				binputu2 ((char16) kar, f);
+				binputu16 ((char16) kar, f);
 			} else if (kar <= 0x10FFFF) {
 				kar -= 0x010000;
-				binputu2 (0xD800 | (char16) (kar >> 10), f);
-				binputu2 (0xDC00 | (char16) ((char16) kar & 0x03ff), f);
+				binputu16 (0xD800 | (char16) (kar >> 10), f);
+				binputu16 (0xDC00 | (char16) ((char16) kar & 0x03ff), f);
 			} else {
-				binputu2 (UNICODE_REPLACEMENT_CHARACTER, f);
+				binputu16 (UNICODE_REPLACEMENT_CHARACTER, f);
 			}
 		}
 	}
@@ -289,15 +289,15 @@ void MelderFile_writeCharacter (MelderFile file, char32 kar) {
 			putc (0x80 | (kar & 0x00003F), f);
 		}
 	} else {
-		if (kar == U'\n' && file -> requiresCRLF) binputu2 (13, f);
+		if (kar == U'\n' && file -> requiresCRLF) binputu16 (13, f);
 		if (kar <= 0x00FFFF) {
-			binputu2 ((uint16) kar, f);
+			binputu16 ((uint16) kar, f);
 		} else if (kar <= 0x10FFFF) {
 			kar -= 0x010000;
-			binputu2 (0xD800 | (uint16) (kar >> 10), f);
-			binputu2 (0xDC00 | (uint16) ((uint16) kar & 0x0003ff), f);
+			binputu16 (0xD800 | (uint16) (kar >> 10), f);
+			binputu16 (0xDC00 | (uint16) ((uint16) kar & 0x0003ff), f);
 		} else {
-			binputu2 (UNICODE_REPLACEMENT_CHARACTER, f);
+			binputu16 (UNICODE_REPLACEMENT_CHARACTER, f);
 		}
 	}
 }
diff --git a/sys/motifEmulator.cpp b/sys/motifEmulator.cpp
index 3507786..6c5ca6b 100644
--- a/sys/motifEmulator.cpp
+++ b/sys/motifEmulator.cpp
@@ -1,6 +1,6 @@
 /* motifEmulator.cpp
  *
- * Copyright (C) 1993-2011,2012,2015,2016 Paul Boersma
+ * Copyright (C) 1993-2011,2012,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -468,7 +468,7 @@ static void NativeMenuItem_setSensitive (GuiObject me) {
 
 static void NativeMenuItem_setText (GuiObject me) {
 	int acc = my motiff.pushButton.acceleratorChar, modifiers = my motiff.pushButton.acceleratorModifiers;
-	static MelderString title = { 0 };
+	static MelderString title { };
 	if (acc == 0) {
 		MelderString_copy (& title, _GuiWin_expandAmpersands (my name));
 	} else {
@@ -1687,10 +1687,10 @@ void GuiAppInitialize (const char *name, unsigned int argc, char **argv)
 			if (theOpenDocumentCallback) {
 				for (unsigned int iarg = 1; iarg < argc; iarg ++) {
 					if (argv [iarg] [0] != '-') {
-						structMelderDir dir { 0 };
+						structMelderDir dir { };
 						Melder_sprint (dir. path,kMelder_MAXPATH+1, Melder_getShellDirectory ());
 						Melder_setDefaultDir (& dir);
-						structMelderFile file = { 0 };
+						structMelderFile file { };
 						Melder_relativePathToFile (Melder_peek8to32 (argv [iarg]), & file);
 						theOpenDocumentCallback (& file);
 					}
diff --git a/sys/oo.h b/sys/oo.h
index cbc2e32..f1776ff 100644
--- a/sys/oo.h
+++ b/sys/oo.h
@@ -20,30 +20,32 @@
 
 /*** Single types. ***/
 
-/* The possible storage types give these binary formats: */
-/*    i1: store as signed big-endian integer in 1 byte (-128..127). */
-/*    i2: store as signed big-endian integer in 2 bytes (-32768..32767). */
-/*    i4: store as signed big-endian integer in 4 bytes. */
-/*    u1: store as unsigned big-endian integer in 1 byte (0..255). */
-/*    u2: store as unsigned big-endian integer in 2 bytes (0..65535). */
-/*    u4: store as unsigned big-endian integer in 4 bytes. */
-/*    i1LE ... u4LE: store as little-endian integers. */
-/*    r4: store as 4-byte IEEE MSB-first floating point format. */
-/*    r8: store as 8-byte IEEE MSB-first floating point format. */
-/*    r10: store as 10-byte IEEE/Apple MSB-first floating point format. */
-/*    c8: store real and imaginary part as r4. */
-/*    c16: store real and imaginary part as r4. */
-/* For text format, reading imposes the same restrictions for the integer types, */
-/* and the real numbers are written with a precision of 8, 17, or 20 characters. */
+/*
+	The possible storage types give these binary formats:
+		i8: store as signed big-endian integer in 8 bits (-128..+127).
+		i16: store as signed big-endian integer in 16 bits (-32768..+32767).
+		i32: store as signed big-endian integer in 32 bits (-2147483648..+2147483647).
+		u8: store as unsigned big-endian integer in 8 bits (0..255).
+		u16: store as unsigned big-endian integer in 16 bits (0..65535).
+		u32: store as unsigned big-endian integer in 32 bits (0..4294967295).
+		i8LE ... u32LE: store as little-endian integers.
+		r32: store as 32-bits IEEE MSB-first floating point format.
+		r64: store as 64-bits IEEE MSB-first floating point format.
+		r80: store as 80-bits IEEE/Apple MSB-first floating point format.
+		c64: store real and imaginary part as r32.
+		c128: store real and imaginary part as r64.
+	For text format, reading imposes the same restrictions for the integer types,
+	and the real numbers are written with a precision of 8, 17 (or 16 or 15), or 20 characters.
+*/
 
 /* Single types. Declarations like: int x; */
 
-#define oo_BYTE(x)  oo_SIMPLE (signed char, i1, x)
-#define oo_INT(x)  oo_SIMPLE (int, i2, x)
-#define oo_LONG(x)  oo_SIMPLE (long, i4, x)
-#define oo_UBYTE(x)  oo_SIMPLE (unsigned char, u1, x)
-#define oo_UINT(x)  oo_SIMPLE (unsigned int, u2, x)
-#define oo_ULONG(x)  oo_SIMPLE (unsigned long, u4, x)
+#define oo_BYTE(x)  oo_SIMPLE (signed char, i8, x)
+#define oo_INT(x)  oo_SIMPLE (int, i16, x)
+#define oo_LONG(x)  oo_SIMPLE (long, i32, x)
+#define oo_UBYTE(x)  oo_SIMPLE (unsigned char, u8, x)
+#define oo_UINT(x)  oo_SIMPLE (unsigned int, u16, x)
+#define oo_ULONG(x)  oo_SIMPLE (unsigned long, u32, x)
 #define oo_INT8(x)  oo_SIMPLE (int8, i8, x)
 #define oo_INT16(x)  oo_SIMPLE (int16, i16, x)
 #define oo_INT32(x)  oo_SIMPLE (int32, i32, x)
@@ -51,11 +53,11 @@
 #define oo_UINT8(x)  oo_SIMPLE (uint8, u8, x)
 #define oo_UINT16(x)  oo_SIMPLE (uint16, u16, x)
 #define oo_UINT32(x)  oo_SIMPLE (uint32, u32, x)
-#define oo_BOOL(x)  oo_SIMPLE (unsigned char, u1, x)
-#define oo_FLOAT(x)  oo_SIMPLE (double, r4, x)
-#define oo_DOUBLE(x)  oo_SIMPLE (double, r8, x)
-#define oo_FCOMPLEX(x)  oo_SIMPLE (fcomplex, c8, x)
-#define oo_DCOMPLEX(x)  oo_SIMPLE (dcomplex, c16, x)
+#define oo_BOOL(x)  oo_SIMPLE (unsigned char, u8, x)
+#define oo_FLOAT(x)  oo_SIMPLE (double, r32, x)
+#define oo_DOUBLE(x)  oo_SIMPLE (double, r64, x)
+//#define oo_FCOMPLEX(x)  oo_SIMPLE (fcomplex, c64, x)
+//#define oo_DCOMPLEX(x)  oo_SIMPLE (dcomplex, c128, x)
 #define oo_POINTER(x)  oo_SIMPLE (void *, dummy, x)
 
 /* Arrays with compile-time allocation of capacity. Declarations like: int x [cap]; */
@@ -64,147 +66,147 @@
 /* Actual number of elements 'n' may vary during run-time and while structure exists, */
 /* but must never be greater than 'cap'. */
 
-#define oo_BYTE_ARRAY(x,cap,n)  oo_ARRAY (signed char, i1, x, cap, n)
-#define oo_INT_ARRAY(x,cap,n)  oo_ARRAY (int, i2, x, cap, n)
-#define oo_LONG_ARRAY(x,cap,n)  oo_ARRAY (long, i4, x, cap, n)
-#define oo_UBYTE_ARRAY(x,cap,n)  oo_ARRAY (unsigned char, u1, x, cap, n)
-#define oo_UINT_ARRAY(x,cap,n)  oo_ARRAY (unsigned int, u2, x, cap, n)
-#define oo_ULONG_ARRAY(x,cap,n)  oo_ARRAY (unsigned long, u4, x, cap, n)
-#define oo_BOOL_ARRAY(x,cap,n)  oo_ARRAY (unsigned char, u1, x, cap, n)
-#define oo_FLOAT_ARRAY(x,cap,n)  oo_ARRAY (double, r4, x, cap, n)
-#define oo_DOUBLE_ARRAY(x,cap,n)  oo_ARRAY (double, r8, x, cap, n)
-#define oo_FCOMPLEX_ARRAY(x,cap,n)  oo_ARRAY (fcomplex, c8, x, cap, n)
-#define oo_DCOMPLEX_ARRAY(x,cap,n)  oo_ARRAY (dcomplex, c16, x, cap, n)
+//#define oo_BYTE_ARRAY(x,cap,n)  oo_ARRAY (signed char, i8, x, cap, n)
+//#define oo_INT_ARRAY(x,cap,n)  oo_ARRAY (int, i16, x, cap, n)
+//#define oo_LONG_ARRAY(x,cap,n)  oo_ARRAY (long, i32, x, cap, n)
+//#define oo_UBYTE_ARRAY(x,cap,n)  oo_ARRAY (unsigned char, u8, x, cap, n)
+//#define oo_UINT_ARRAY(x,cap,n)  oo_ARRAY (unsigned int, u16, x, cap, n)
+//#define oo_ULONG_ARRAY(x,cap,n)  oo_ARRAY (unsigned long, u32, x, cap, n)
+//#define oo_BOOL_ARRAY(x,cap,n)  oo_ARRAY (unsigned char, u8, x, cap, n)
+//#define oo_FLOAT_ARRAY(x,cap,n)  oo_ARRAY (double, r32, x, cap, n)
+#define oo_DOUBLE_ARRAY(x,cap,n)  oo_ARRAY (double, r64, x, cap, n)
+//#define oo_FCOMPLEX_ARRAY(x,cap,n)  oo_ARRAY (fcomplex, c64, x, cap, n)
+//#define oo_DCOMPLEX_ARRAY(x,cap,n)  oo_ARRAY (dcomplex, c128, x, cap, n)
 #define oo_POINTER_ARRAY(x,cap,n)  oo_ARRAY (void *, dummy, x, cap, n)
 
 /* Sets with compile-time allocation of capacity. Declarations like: int x [1 + setType_MAX]; */
 /* First index is always 0, last index is setType_MAX. */
 
-#define oo_BYTE_SET(x,setType)  oo_SET (signed char, i1, x, setType)
-#define oo_INT_SET(x,setType)  oo_SET (int, i2, x, setType)
-#define oo_LONG_SET(x,setType)  oo_SET (long, i4, x, setType)
-#define oo_UBYTE_SET(x,setType)  oo_SET (unsigned char, u1, x, setType)
-#define oo_UINT_SET(x,setType)  oo_SET (unsigned int, u2, x, setType)
-#define oo_ULONG_SET(x,setType)  oo_SET (unsigned long, u4, x, setType)
-#define oo_BOOL_SET(x,setType)  oo_SET (unsigned char, u1, x, setType)
-#define oo_FLOAT_SET(x,setType)  oo_SET (double, r4, x, setType)
-#define oo_DOUBLE_SET(x,setType)  oo_SET (double, r8, x, setType)
-#define oo_FCOMPLEX_SET(x,setType)  oo_SET (fcomplex, c8, x, setType)
-#define oo_DCOMPLEX_SET(x,setType)  oo_SET (dcomplex, c16, x, setType)
+//#define oo_BYTE_SET(x,setType)  oo_SET (signed char, i8, x, setType)
+//#define oo_INT_SET(x,setType)  oo_SET (int, i16, x, setType)
+//#define oo_LONG_SET(x,setType)  oo_SET (long, i32, x, setType)
+//#define oo_UBYTE_SET(x,setType)  oo_SET (unsigned char, u8, x, setType)
+//#define oo_UINT_SET(x,setType)  oo_SET (unsigned int, u16, x, setType)
+//#define oo_ULONG_SET(x,setType)  oo_SET (unsigned long, u32, x, setType)
+//#define oo_BOOL_SET(x,setType)  oo_SET (unsigned char, u8, x, setType)
+//#define oo_FLOAT_SET(x,setType)  oo_SET (double, r32, x, setType)
+#define oo_DOUBLE_SET(x,setType)  oo_SET (double, r64, x, setType)
+//#define oo_FCOMPLEX_SET(x,setType)  oo_SET (fcomplex, c64, x, setType)
+//#define oo_DCOMPLEX_SET(x,setType)  oo_SET (dcomplex, c128, x, setType)
 #define oo_POINTER_SET(x,setType)  oo_SET (void *, dummy, x, setType)
 
 /* Arrays with run-time allocation of size. Declarations like: int *x; */
 /* First index is 'min', last index is 'max'. */
 /* While the structure exists, 'max' may become less than the value it had at the time of allocation. */
 
-#define oo_BYTE_VECTOR_FROM(x,min,max)  oo_VECTOR (signed char, i1, x, min, max)
-#define oo_INT_VECTOR_FROM(x,min,max)  oo_VECTOR (int, i2, x, min, max)
-#define oo_LONG_VECTOR_FROM(x,min,max)  oo_VECTOR (long, i4, x, min, max)
-#define oo_UBYTE_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned char, u1, x, min, max)
-#define oo_UINT_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned int, u2, x, min, max)
-#define oo_ULONG_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned long, u4, x, min, max)
-#define oo_BOOL_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned char, u1, x, min, max)
-#define oo_FLOAT_VECTOR_FROM(x,min,max)  oo_VECTOR (double, r4, x, min, max)
-#define oo_DOUBLE_VECTOR_FROM(x,min,max)  oo_VECTOR (double, r8, x, min, max)
-#define oo_FCOMPLEX_VECTOR_FROM(x,min,max)  oo_VECTOR (fcomplex, c8, x, min, max)
-#define oo_DCOMPLEX_VECTOR_FROM(x,min,max)  oo_VECTOR (dcomplex, c16, x, min, max)
+//#define oo_BYTE_VECTOR_FROM(x,min,max)  oo_VECTOR (signed char, i8, x, min, max)
+#define oo_INT_VECTOR_FROM(x,min,max)  oo_VECTOR (int, i16, x, min, max)
+#define oo_LONG_VECTOR_FROM(x,min,max)  oo_VECTOR (long, i32, x, min, max)
+//#define oo_UBYTE_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned char, u8, x, min, max)
+//#define oo_UINT_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned int, u16, x, min, max)
+//#define oo_ULONG_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned long, u32, x, min, max)
+//#define oo_BOOL_VECTOR_FROM(x,min,max)  oo_VECTOR (unsigned char, u8, x, min, max)
+#define oo_FLOAT_VECTOR_FROM(x,min,max)  oo_VECTOR (double, r32, x, min, max)
+#define oo_DOUBLE_VECTOR_FROM(x,min,max)  oo_VECTOR (double, r64, x, min, max)
+//#define oo_FCOMPLEX_VECTOR_FROM(x,min,max)  oo_VECTOR (fcomplex, c64, x, min, max)
+#define oo_DCOMPLEX_VECTOR_FROM(x,min,max)  oo_VECTOR (dcomplex, c128, x, min, max)
 #define oo_POINTER_VECTOR_FROM(x,min,max)  oo_VECTOR (void *, dummy, x, min, max)
 
-#define oo_BYTE_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (signed char, i1, x, row1, row2, col1, col2)
-#define oo_INT_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (int, i2, x, row1, row2, col1, col2)
-#define oo_LONG_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (long, i4, x, row1, row2, col1, col2)
-#define oo_UBYTE_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned char, u1, x, row1, row2, col1, col2)
-#define oo_UINT_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned int, u2, x, row1, row2, col1, col2)
-#define oo_ULONG_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned long, u4, x, row1, row2, col1, col2)
-#define oo_BOOL_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned char, u1, x, row1, row2, col1, col2)
-#define oo_FLOAT_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (double, r4, x, row1, row2, col1, col2)
-#define oo_DOUBLE_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (double, r8, x, row1, row2, col1, col2)
-#define oo_FCOMPLEX_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (fcomplex, c8, x, row1, row2, col1, col2)
-#define oo_DCOMPLEX_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (dcomplex, c16, x, row1, row2, col1, col2)
+//#define oo_BYTE_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (signed char, i8, x, row1, row2, col1, col2)
+//#define oo_INT_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (int, i16, x, row1, row2, col1, col2)
+//#define oo_LONG_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (long, i32, x, row1, row2, col1, col2)
+//#define oo_UBYTE_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned char, u8, x, row1, row2, col1, col2)
+//#define oo_UINT_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned int, u16, x, row1, row2, col1, col2)
+//#define oo_ULONG_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned long, u32, x, row1, row2, col1, col2)
+//#define oo_BOOL_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (unsigned char, u8, x, row1, row2, col1, col2)
+//#define oo_FLOAT_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (double, r32, x, row1, row2, col1, col2)
+#define oo_DOUBLE_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (double, r64, x, row1, row2, col1, col2)
+//#define oo_FCOMPLEX_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (fcomplex, c64, x, row1, row2, col1, col2)
+//#define oo_DCOMPLEX_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (dcomplex, c128, x, row1, row2, col1, col2)
 #define oo_POINTER_MATRIX_FROM(x,row1,row2,col1,col2)  oo_MATRIX (void *, dummy, x, row1, row2, col1, col2)
 
 /* The same arrays, with the first index fixed at 1. */
 
-#define oo_BYTE_VECTOR(x,n)  oo_VECTOR (signed char, i1, x, 1, n)
-#define oo_INT_VECTOR(x,n)  oo_VECTOR (int, i2, x, 1, n)
-#define oo_LONG_VECTOR(x,n)  oo_VECTOR (long, i4, x, 1, n)
-#define oo_UBYTE_VECTOR(x,n)  oo_VECTOR (unsigned char, u1, x, 1, n)
-#define oo_UINT_VECTOR(x,n)  oo_VECTOR (unsigned int, u2, x, 1, n)
-#define oo_ULONG_VECTOR(x,n)  oo_VECTOR (unsigned long, u4, x, 1, n)
-#define oo_BOOL_VECTOR(x,n)  oo_VECTOR (unsigned char, u1, x, 1, n)
-#define oo_FLOAT_VECTOR(x,n)  oo_VECTOR (double, r4, x, 1, n)
-#define oo_DOUBLE_VECTOR(x,n)  oo_VECTOR (double, r8, x, 1, n)
-#define oo_FCOMPLEX_VECTOR(x,n)  oo_VECTOR (fcomplex, c8, x, 1, n)
-#define oo_DCOMPLEX_VECTOR(x,n)  oo_VECTOR (dcomplex, c16, x, 1, n)
+//#define oo_BYTE_VECTOR(x,n)  oo_VECTOR (signed char, i8, x, 1, n)
+#define oo_INT_VECTOR(x,n)  oo_VECTOR (int, i16, x, 1, n)
+#define oo_LONG_VECTOR(x,n)  oo_VECTOR (long, i32, x, 1, n)
+//#define oo_UBYTE_VECTOR(x,n)  oo_VECTOR (unsigned char, u8, x, 1, n)
+//#define oo_UINT_VECTOR(x,n)  oo_VECTOR (unsigned int, u16, x, 1, n)
+//#define oo_ULONG_VECTOR(x,n)  oo_VECTOR (unsigned long, u32, x, 1, n)
+//#define oo_BOOL_VECTOR(x,n)  oo_VECTOR (unsigned char, u8, x, 1, n)
+#define oo_FLOAT_VECTOR(x,n)  oo_VECTOR (double, r32, x, 1, n)
+#define oo_DOUBLE_VECTOR(x,n)  oo_VECTOR (double, r64, x, 1, n)
+//#define oo_FCOMPLEX_VECTOR(x,n)  oo_VECTOR (fcomplex, c64, x, 1, n)
+//#define oo_DCOMPLEX_VECTOR(x,n)  oo_VECTOR (dcomplex, c128, x, 1, n)
 #define oo_POINTER_VECTOR(x,n)  oo_VECTOR (void *, dummy, x, 1, n)
 
-#define oo_BYTE_MATRIX(x,nrow,ncol)  oo_MATRIX (signed char, i1, x, 1, nrow, 1, ncol)
-#define oo_INT_MATRIX(x,nrow,ncol)  oo_MATRIX (int, i2, x, 1, nrow, 1, ncol)
-#define oo_LONG_MATRIX(x,nrow,ncol)  oo_MATRIX (long, i4, x, 1, nrow, 1, ncol)
-#define oo_UBYTE_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned char, u1, x, 1, nrow, 1, ncol)
-#define oo_UINT_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned int, u2, x, 1, nrow, 1, ncol)
-#define oo_ULONG_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned long, u4, x, 1, nrow, 1, ncol)
-#define oo_BOOL_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned char, u1, x, 1, nrow, 1, ncol)
-#define oo_FLOAT_MATRIX(x,nrow,ncol)  oo_MATRIX (double, r4, x, 1, nrow, 1, ncol)
-#define oo_DOUBLE_MATRIX(x,nrow,ncol)  oo_MATRIX (double, r8, x, 1, nrow, 1, ncol)
-#define oo_FCOMPLEX_MATRIX(x,nrow,ncol)  oo_MATRIX (fcomplex, c8, x, 1, nrow, 1, ncol)
-#define oo_DCOMPLEX_MATRIX(x,nrow,ncol)  oo_MATRIX (dcomplex, c16, x, 1, nrow, 1, ncol)
+//#define oo_BYTE_MATRIX(x,nrow,ncol)  oo_MATRIX (signed char, i8, x, 1, nrow, 1, ncol)
+//#define oo_INT_MATRIX(x,nrow,ncol)  oo_MATRIX (int, i16, x, 1, nrow, 1, ncol)
+#define oo_LONG_MATRIX(x,nrow,ncol)  oo_MATRIX (long, i32, x, 1, nrow, 1, ncol)
+#define oo_UBYTE_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned char, u8, x, 1, nrow, 1, ncol)
+//#define oo_UINT_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned int, u16, x, 1, nrow, 1, ncol)
+//#define oo_ULONG_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned long, u32, x, 1, nrow, 1, ncol)
+//#define oo_BOOL_MATRIX(x,nrow,ncol)  oo_MATRIX (unsigned char, u8, x, 1, nrow, 1, ncol)
+#define oo_FLOAT_MATRIX(x,nrow,ncol)  oo_MATRIX (double, r32, x, 1, nrow, 1, ncol)
+#define oo_DOUBLE_MATRIX(x,nrow,ncol)  oo_MATRIX (double, r64, x, 1, nrow, 1, ncol)
+//#define oo_FCOMPLEX_MATRIX(x,nrow,ncol)  oo_MATRIX (fcomplex, c64, x, 1, nrow, 1, ncol)
+//#define oo_DCOMPLEX_MATRIX(x,nrow,ncol)  oo_MATRIX (dcomplex, c128, x, 1, nrow, 1, ncol)
 #define oo_POINTER_MATRIX(x,nrow,ncol)  oo_MATRIX (void *, dummy, x, 1, nrow, 1, ncol)
 
 
 /*** Enumerated types. ***/
 
 /* The possible storage types give these binary formats: */
-/*    e1: store as signed integer in 1 byte. */
-/*    e2: store in signed big-endian integer in 2 bytes. */
+/*    e8: store as signed integer in 8 bits. */
+/*    e16: store in signed big-endian integer in 16 bits. */
 /*    eb: store as byte 170 (false) or byte 185 (true). */
 /*    eq: store as byte 150 (no) or byte 165 (yes). */
 /*    ex: store as byte 226 (absent) or byte 241 (present). */
 /* For text format, the value is written as a string between '<' and '>'. */
 
-#define oo_ENUM(Type,x)  oo_ENUMx (signed char, e1, Type, x)
-#define oo_LENUM(Type,x)  oo_ENUMx (short, e2, Type, x)
-#define oo_ENUM_ARRAY(Type,x,cap,n)  oo_ENUMx_ARRAY (signed char, e1, Type, x, cap, n)
-#define oo_LENUM_ARRAY(Type,x,cap,n)  oo_ENUMx_ARRAY (short, e2, Type, x, cap, n)
-#define oo_ENUM_SET(Type,x,setType)  oo_ENUMx_SET (signed char, e1, Type, x, setType)
-#define oo_LENUM_SET(Type,x,setType)  oo_ENUMx_SET (short, e2, Type, x, setType)
-#define oo_ENUM_VECTOR_FROM(Type,x,min,max)  oo_ENUMx_VECTOR (signed char, e1, Type, x, min, max)
-#define oo_LENUM_VECTOR_FROM(Type,x,min,max)  oo_ENUMx_VECTOR (short, e2, Type, x, min, max)
-#define oo_ENUM_VECTOR(Type,x,n)  oo_ENUMx_VECTOR (signed char, e1, Type, x, 1, n)
-#define oo_LENUM_VECTOR(Type,x,n)  oo_ENUMx_VECTOR (short, e2, Type, x, 1, n)
-#define oo_BOOLEAN(x)  oo_SIMPLE (signed char, eb, x)
-#define oo_BOOLEAN_ARRAY(x,cap,n)  oo_ARRAY (signed char, eb, x, cap, n)
-#define oo_BOOLEAN_SET(x,setType)  oo_ARRAY (signed char, eb, x, setType)
-#define oo_BOOLEAN_VECTOR_FROM(x,min,max)  oo_VECTOR (signed char, eb, x, min, max)
-#define oo_BOOLEAN_VECTOR(x,n)  oo_VECTOR (signed char, eb, x, 1, n)
-#define oo_QUESTION(x)  oo_SIMPLE (signed char, eq, x)
-#define oo_QUESTION_ARRAY(x,cap,n)  oo_ARRAY (signed char, eq, x, cap, n)
-#define oo_QUESTION_SET(x,setType)  oo_ARRAY (signed char, eq, x, setType)
-#define oo_QUESTION_VECTOR_FROM(x,min,max)  oo_VECTOR (signed char, eq, x, min, max)
-#define oo_QUESTION_VECTOR(x,n)  oo_VECTOR (signed char, eq, x, 1, n)
+#define oo_ENUM(Type,x)  oo_ENUMx (signed char, e8, Type, x)
+//#define oo_LENUM(Type,x)  oo_ENUMx (short, e16, Type, x)
+//#define oo_ENUM_ARRAY(Type,x,cap,n)  oo_ENUMx_ARRAY (signed char, e8, Type, x, cap, n)
+//#define oo_LENUM_ARRAY(Type,x,cap,n)  oo_ENUMx_ARRAY (short, e16, Type, x, cap, n)
+//#define oo_ENUM_SET(Type,x,setType)  oo_ENUMx_SET (signed char, e8, Type, x, setType)
+//#define oo_LENUM_SET(Type,x,setType)  oo_ENUMx_SET (short, e16, Type, x, setType)
+//#define oo_ENUM_VECTOR_FROM(Type,x,min,max)  oo_ENUMx_VECTOR (signed char, e8, Type, x, min, max)
+//#define oo_LENUM_VECTOR_FROM(Type,x,min,max)  oo_ENUMx_VECTOR (short, e16, Type, x, min, max)
+//#define oo_ENUM_VECTOR(Type,x,n)  oo_ENUMx_VECTOR (signed char, e8, Type, x, 1, n)
+//#define oo_LENUM_VECTOR(Type,x,n)  oo_ENUMx_VECTOR (short, e16, Type, x, 1, n)
+#define oo_BOOLEAN(x)  oo_SIMPLE (bool, eb, x)
+//#define oo_BOOLEAN_ARRAY(x,cap,n)  oo_ARRAY (bool, eb, x, cap, n)
+//#define oo_BOOLEAN_SET(x,setType)  oo_ARRAY (bool, eb, x, setType)
+//#define oo_BOOLEAN_VECTOR_FROM(x,min,max)  oo_VECTOR (bool, eb, x, min, max)
+#define oo_BOOLEAN_VECTOR(x,n)  oo_VECTOR (bool, eb, x, 1, n)
+#define oo_QUESTION(x)  oo_SIMPLE (bool, eq, x)
+//#define oo_QUESTION_ARRAY(x,cap,n)  oo_ARRAY (bool, eq, x, cap, n)
+//#define oo_QUESTION_SET(x,setType)  oo_ARRAY (bool, eq, x, setType)
+//#define oo_QUESTION_VECTOR_FROM(x,min,max)  oo_VECTOR (bool, eq, x, min, max)
+//#define oo_QUESTION_VECTOR(x,n)  oo_VECTOR (bool, eq, x, 1, n)
 
 /*** Strings. ***/
 
 /* The possible storage types give these binary formats: */
-/*    s2: store as sequence of bytes, preceded with 2 bytes (u2) to denote length. */
-/*    w2: store as sequence of characters (u2), preceded with 2 bytes (u2) to denote length. */
-/*    s4: store as sequence of bytes, preceded with 4 bytes (u4) to denote length. */
-/*    w4: store as sequence of characters (u2), preceded with 4 bytes (u4) to denote length. */
+/*    s16: store as sequence of bytes, preceded with 16 bits (u16) to denote length. */
+/*    w16: store as sequence of characters (u16), preceded with 16 bits (u16) to denote length. */
+/*    s32: store as sequence of bytes, preceded with 32 bits (u32) to denote length. */
+/*    w32: store as sequence of characters (u16), preceded with 32 bits (u32) to denote length. */
 
-#define oo_STRING(x)  oo_STRINGx (w2, x)
-#define oo_LSTRING(x)  oo_STRINGx (w4, x)
+#define oo_STRING(x)  oo_STRINGx (w16, x)
+#define oo_LSTRING(x)  oo_STRINGx (w32, x)
 
-#define oo_STRING_ARRAY(x,cap,n)  oo_STRINGx_ARRAY (w2, x, cap, n)
-#define oo_LSTRING_ARRAY(x,cap,n)  oo_STRINGx_ARRAY (w4, x, cap, n)
+//#define oo_STRING_ARRAY(x,cap,n)  oo_STRINGx_ARRAY (w16, x, cap, n)
+//#define oo_LSTRING_ARRAY(x,cap,n)  oo_STRINGx_ARRAY (w32, x, cap, n)
 
-#define oo_STRING_SET(x,setType)  oo_STRINGx_SET (w2, x, setType)
-#define oo_LSTRING_SET(x,setType)  oo_STRINGx_SET (w4, x, setType)
+//#define oo_STRING_SET(x,setType)  oo_STRINGx_SET (w16, x, setType)
+//#define oo_LSTRING_SET(x,setType)  oo_STRINGx_SET (w32, x, setType)
 
-#define oo_STRING_VECTOR_FROM(x,min,max)  oo_STRINGx_VECTOR (w2, x, min, max)
-#define oo_LSTRING_VECTOR_FROM(x,min,max)  oo_STRINGx_VECTOR (w4, x, min, max)
+//#define oo_STRING_VECTOR_FROM(x,min,max)  oo_STRINGx_VECTOR (w16, x, min, max)
+//#define oo_LSTRING_VECTOR_FROM(x,min,max)  oo_STRINGx_VECTOR (w32, x, min, max)
 
-#define oo_STRING_VECTOR(x,n)  oo_STRINGx_VECTOR (w2, x, 1, n)
-#define oo_LSTRING_VECTOR(x,n)  oo_STRINGx_VECTOR (w4, x, 1, n)
+#define oo_STRING_VECTOR(x,n)  oo_STRINGx_VECTOR (w16, x, 1, n)
+//#define oo_LSTRING_VECTOR(x,n)  oo_STRINGx_VECTOR (w32, x, 1, n)
 
 /*** Structs. ***/
 
diff --git a/sys/oo_DESCRIPTION.h b/sys/oo_DESCRIPTION.h
index d192d79..d672768 100644
--- a/sys/oo_DESCRIPTION.h
+++ b/sys/oo_DESCRIPTION.h
@@ -1,6 +1,6 @@
 /* oo_DESCRIPTION.h
  *
- * Copyright (C) 1994-2012,2013,2015 Paul Boersma
+ * Copyright (C) 1994-2012,2013,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,98 +19,100 @@
 #include "oo_undef.h"
 
 #undef oo_BYTE
-#define oo_BYTE(x)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char) },
+#define oo_BYTE(x)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
+#undef oo_INT16
+#define oo_INT16(x)  { U"" #x, int16wa, Melder_offsetof (ooSTRUCT, x), sizeof (int16), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_INT
-#define oo_INT(x)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int) },
+#define oo_INT(x)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_INT32
-#define oo_INT32(x)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int32) },
+#define oo_INT32(x)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int32), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_LONG
-#define oo_LONG(x)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long) },
+#define oo_LONG(x)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_UBYTE
-#define oo_UBYTE(x)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char) },
+#define oo_UBYTE(x)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_UINT
-#define oo_UINT(x)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int) },
+#define oo_UINT(x)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_ULONG
-#define oo_ULONG(x)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long) },
+#define oo_ULONG(x)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_BOOL
-#define oo_BOOL(x)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool) },
+#define oo_BOOL(x)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_FLOAT
-#define oo_FLOAT(x)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double) },
+#define oo_FLOAT(x)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_DOUBLE
-#define oo_DOUBLE(x)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double) },
+#define oo_DOUBLE(x)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_FCOMPLEX
-#define oo_FCOMPLEX(x)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex) },
+#define oo_FCOMPLEX(x)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_DCOMPLEX
-#define oo_DCOMPLEX(x)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex) },
+#define oo_DCOMPLEX(x)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 0, nullptr, nullptr, nullptr, nullptr },
 
 #undef oo_BYTE_ARRAY
-#define oo_BYTE_ARRAY(x,cap,n)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_BYTE_ARRAY(x,cap,n)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_INT_ARRAY
-#define oo_INT_ARRAY(x,cap,n)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_INT_ARRAY(x,cap,n)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_LONG_ARRAY
-#define oo_LONG_ARRAY(x,cap,n)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_LONG_ARRAY(x,cap,n)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_UBYTE_ARRAY
-#define oo_UBYTE_ARRAY(x,cap,n)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_UBYTE_ARRAY(x,cap,n)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_UINT_ARRAY
-#define oo_UINT_ARRAY(x,cap,n)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_UINT_ARRAY(x,cap,n)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_ULONG_ARRAY
-#define oo_ULONG_ARRAY(x,cap,n)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_ULONG_ARRAY(x,cap,n)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_BOOL_ARRAY
-#define oo_BOOL_ARRAY(x,cap,n)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_BOOL_ARRAY(x,cap,n)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_FLOAT_ARRAY
-#define oo_FLOAT_ARRAY(x,cap,n)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_FLOAT_ARRAY(x,cap,n)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_DOUBLE_ARRAY
-#define oo_DOUBLE_ARRAY(x,cap,n)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_DOUBLE_ARRAY(x,cap,n)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_FCOMPLEX_ARRAY
-#define oo_FCOMPLEX_ARRAY(x,cap,n)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_FCOMPLEX_ARRAY(x,cap,n)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_DCOMPLEX_ARRAY
-#define oo_DCOMPLEX_ARRAY(x,cap,n)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_DCOMPLEX_ARRAY(x,cap,n)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, - cap, nullptr, U"" #n, nullptr, nullptr },
 
 #undef oo_BYTE_SET
-#define oo_BYTE_SET(x,setType)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue }, /* BUG function pointer to pointer */
+#define oo_BYTE_SET(x,setType)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr }, /* BUG function pointer to pointer */
 #undef oo_INT_SET
-#define oo_INT_SET(x,setType)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_INT_SET(x,setType)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_LONG_SET
-#define oo_LONG_SET(x,setType)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_LONG_SET(x,setType)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_UBYTE_SET
-#define oo_UBYTE_SET(x,setType)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_UBYTE_SET(x,setType)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_UINT_SET
-#define oo_UINT_SET(x,setType)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_UINT_SET(x,setType)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_ULONG_SET
-#define oo_ULONG_SET(x,setType)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_ULONG_SET(x,setType)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_BOOL_SET
-#define oo_BOOL_SET(x,setType)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_BOOL_SET(x,setType)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_FLOAT_SET
-#define oo_FLOAT_SET(x,setType)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_FLOAT_SET(x,setType)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_DOUBLE_SET
-#define oo_DOUBLE_SET(x,setType)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_DOUBLE_SET(x,setType)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_FCOMPLEX_SET
-#define oo_FCOMPLEX_SET(x,setType)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_FCOMPLEX_SET(x,setType)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_DCOMPLEX_SET
-#define oo_DCOMPLEX_SET(x,setType)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_DCOMPLEX_SET(x,setType)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 
 #undef oo_BYTE_VECTOR_FROM
-#define oo_BYTE_VECTOR_FROM(x,min,max)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, U"" #min, U"" #max },
+#define oo_BYTE_VECTOR_FROM(x,min,max)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_INT_VECTOR_FROM
-#define oo_INT_VECTOR_FROM(x,min,max)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 1, U"" #min, U"" #max },
+#define oo_INT_VECTOR_FROM(x,min,max)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_LONG_VECTOR_FROM
-#define oo_LONG_VECTOR_FROM(x,min,max)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 1, U"" #min, U"" #max },
+#define oo_LONG_VECTOR_FROM(x,min,max)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_UBYTE_VECTOR_FROM
-#define oo_UBYTE_VECTOR_FROM(x,min,max)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 1, U"" #min, U"" #max },
+#define oo_UBYTE_VECTOR_FROM(x,min,max)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_UINT_VECTOR_FROM
-#define oo_UINT_VECTOR_FROM(x,min,max)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 1, U"" #min, U"" #max },
+#define oo_UINT_VECTOR_FROM(x,min,max)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_ULONG_VECTOR_FROM
-#define oo_ULONG_VECTOR_FROM(x,min,max)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 1, U"" #min, U"" #max },
+#define oo_ULONG_VECTOR_FROM(x,min,max)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_BOOL_VECTOR_FROM
-#define oo_BOOL_VECTOR_FROM(x,min,max)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, U"" #min, U"" #max },
+#define oo_BOOL_VECTOR_FROM(x,min,max)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_FLOAT_VECTOR_FROM
-#define oo_FLOAT_VECTOR_FROM(x,min,max)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, U"" #min, U"" #max },
+#define oo_FLOAT_VECTOR_FROM(x,min,max)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_DOUBLE_VECTOR_FROM
-#define oo_DOUBLE_VECTOR_FROM(x,min,max)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, U"" #min, U"" #max },
+#define oo_DOUBLE_VECTOR_FROM(x,min,max)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_FCOMPLEX_VECTOR_FROM
-#define oo_FCOMPLEX_VECTOR_FROM(x,min,max)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 1, U"" #min, U"" #max },
+#define oo_FCOMPLEX_VECTOR_FROM(x,min,max)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_DCOMPLEX_VECTOR_FROM
-#define oo_DCOMPLEX_VECTOR_FROM(x,min,max)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 1, U"" #min, U"" #max },
+#define oo_DCOMPLEX_VECTOR_FROM(x,min,max)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 
 #undef oo_BYTE_MATRIX_FROM
 #define oo_BYTE_MATRIX_FROM(x,r1,r2,c1,c2)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 2, U"" #r1, U"" #r2, U"" #c1, U"" #c2 },
@@ -136,145 +138,145 @@
 #define oo_DCOMPLEX_MATRIX_FROM(x,r1,r2,c1,c2)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 2, U"" #r1, U"" #r2, U"" #c1, U"" #c2 },
 
 #undef oo_BYTE_VECTOR
-#define oo_BYTE_VECTOR(x,n)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_BYTE_VECTOR(x,n)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_INT_VECTOR
-#define oo_INT_VECTOR(x,n)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_INT_VECTOR(x,n)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_LONG_VECTOR
-#define oo_LONG_VECTOR(x,n)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_LONG_VECTOR(x,n)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_UBYTE_VECTOR
-#define oo_UBYTE_VECTOR(x,n)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_UBYTE_VECTOR(x,n)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_UINT_VECTOR
-#define oo_UINT_VECTOR(x,n)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_UINT_VECTOR(x,n)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_ULONG_VECTOR
-#define oo_ULONG_VECTOR(x,n)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_ULONG_VECTOR(x,n)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_BOOL_VECTOR
-#define oo_BOOL_VECTOR(x,n)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_BOOL_VECTOR(x,n)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_FLOAT_VECTOR
-#define oo_FLOAT_VECTOR(x,n)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_FLOAT_VECTOR(x,n)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_DOUBLE_VECTOR
-#define oo_DOUBLE_VECTOR(x,n)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_DOUBLE_VECTOR(x,n)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_FCOMPLEX_VECTOR
-#define oo_FCOMPLEX_VECTOR(x,n)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_FCOMPLEX_VECTOR(x,n)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 #undef oo_DCOMPLEX_VECTOR
-#define oo_DCOMPLEX_VECTOR(x,n)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_DCOMPLEX_VECTOR(x,n)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 1, nullptr, U"" #n, nullptr, nullptr },
 
 #undef oo_BYTE_MATRIX
-#define oo_BYTE_MATRIX(x,nrow,ncol)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_BYTE_MATRIX(x,nrow,ncol)  { U"" #x, bytewa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_INT_MATRIX
-#define oo_INT_MATRIX(x,nrow,ncol)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_INT_MATRIX(x,nrow,ncol)  { U"" #x, intwa, Melder_offsetof (ooSTRUCT, x), sizeof (int), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_LONG_MATRIX
-#define oo_LONG_MATRIX(x,nrow,ncol)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_LONG_MATRIX(x,nrow,ncol)  { U"" #x, longwa, Melder_offsetof (ooSTRUCT, x), sizeof (long), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_UBYTE_MATRIX
-#define oo_UBYTE_MATRIX(x,nrow,ncol)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_UBYTE_MATRIX(x,nrow,ncol)  { U"" #x, ubytewa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned char), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_UINT_MATRIX
-#define oo_UINT_MATRIX(x,nrow,ncol)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_UINT_MATRIX(x,nrow,ncol)  { U"" #x, uintwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned int), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_ULONG_MATRIX
-#define oo_ULONG_MATRIX(x,nrow,ncol)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_ULONG_MATRIX(x,nrow,ncol)  { U"" #x, ulongwa, Melder_offsetof (ooSTRUCT, x), sizeof (unsigned long), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_BOOL_MATRIX
-#define oo_BOOL_MATRIX(x,nrow,ncol)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_BOOL_MATRIX(x,nrow,ncol)  { U"" #x, boolwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_FLOAT_MATRIX
-#define oo_FLOAT_MATRIX(x,nrow,ncol)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_FLOAT_MATRIX(x,nrow,ncol)  { U"" #x, floatwa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_DOUBLE_MATRIX
-#define oo_DOUBLE_MATRIX(x,nrow,ncol)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_DOUBLE_MATRIX(x,nrow,ncol)  { U"" #x, doublewa, Melder_offsetof (ooSTRUCT, x), sizeof (double), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_FCOMPLEX_MATRIX
-#define oo_FCOMPLEX_MATRIX(x,nrow,ncol)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_FCOMPLEX_MATRIX(x,nrow,ncol)  { U"" #x, fcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (fcomplex), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 #undef oo_DCOMPLEX_MATRIX
-#define oo_DCOMPLEX_MATRIX(x,nrow,ncol)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_DCOMPLEX_MATRIX(x,nrow,ncol)  { U"" #x, dcomplexwa, Melder_offsetof (ooSTRUCT, x), sizeof (dcomplex), 0, 0, 2, nullptr, U"" #nrow, (const char32 *) 0, U"" #ncol },
 
 #undef oo_ENUM
-#define oo_ENUM(Type,x)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText },
+#define oo_ENUM(Type,x)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_LENUM
-#define oo_LENUM(Type,x)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText },
+#define oo_LENUM(Type,x)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_ENUM_ARRAY
-#define oo_ENUM_ARRAY(Type,x,cap,n)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, - cap, (const char32 *) 0, U"" #n },
+#define oo_ENUM_ARRAY(Type,x,cap,n)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_LENUM_ARRAY
-#define oo_LENUM_ARRAY(Type,x,cap,n)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, - cap, (const char32 *) 0, U"" #n },
+#define oo_LENUM_ARRAY(Type,x,cap,n)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_ENUM_SET
-#define oo_ENUM_SET(Type,x,setType)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_ENUM_SET(Type,x,setType)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_LENUM_SET
-#define oo_LENUM_SET(Type,x,setType)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_LENUM_SET(Type,x,setType)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_ENUM_VECTOR_FROM
-#define oo_ENUM_VECTOR_FROM(Type,x,min,max)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 1, U"" #min, U"" #max },
+#define oo_ENUM_VECTOR_FROM(Type,x,min,max)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_LENUM_VECTOR_FROM
-#define oo_LENUM_VECTOR_FROM(Type,x,min,max)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 1, U"" #min, U"" #max },
+#define oo_LENUM_VECTOR_FROM(Type,x,min,max)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_ENUM_VECTOR
-#define oo_ENUM_VECTOR(Type,x,n)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 1, (const char32 *) 0, U"" #n },
+#define oo_ENUM_VECTOR(Type,x,n)  { U"" #x, enumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), U"" #Type, (void *) Type##_getText, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_LENUM_VECTOR
-#define oo_LENUM_VECTOR(Type,x,n)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 1, (const char32 *) 0, U"" #n },
+#define oo_LENUM_VECTOR(Type,x,n)  { U"" #x, lenumwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed short), U"" #Type, (void *) Type##_getText, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_BOOLEAN
-#define oo_BOOLEAN(x)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char) },
+#define oo_BOOLEAN(x)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_BOOLEAN_ARRAY
-#define oo_BOOLEAN_ARRAY(x,cap,n)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_BOOLEAN_ARRAY(x,cap,n)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_BOOLEAN_SET
-#define oo_BOOLEAN_SET(x,setType)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_BOOLEAN_SET(x,setType)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_BOOLEAN_VECTOR_FROM
-#define oo_BOOLEAN_VECTOR_FROM(x,min,max)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, (const char32 *) 1, U"" #min, U"" #max },
+#define oo_BOOLEAN_VECTOR_FROM(x,min,max)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, (const char32 *) 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_BOOLEAN_VECTOR
-#define oo_BOOLEAN_VECTOR(x,n)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_BOOLEAN_VECTOR(x,n)  { U"" #x, booleanwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_QUESTION
-#define oo_QUESTION(x)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char) },
+#define oo_QUESTION(x)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_QUESTION_ARRAY
-#define oo_QUESTION_ARRAY(x,cap,n)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_QUESTION_ARRAY(x,cap,n)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_QUESTION_SET
-#define oo_QUESTION_SET(x,setType)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_QUESTION_SET(x,setType)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_QUESTION_VECTOR_FROM
-#define oo_QUESTION_VECTOR_FROM(x,min,max)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, U"" #min, U"" #max },
+#define oo_QUESTION_VECTOR_FROM(x,min,max)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_QUESTION_VECTOR
-#define oo_QUESTION_VECTOR(x,n)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (signed char), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_QUESTION_VECTOR(x,n)  { U"" #x, questionwa, Melder_offsetof (ooSTRUCT, x), sizeof (bool), 0, 0, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 
 #undef oo_STRING
-#define oo_STRING(x)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *) },
+#define oo_STRING(x)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr },
 #undef oo_LSTRING
-#define oo_LSTRING(x)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *) },
+#define oo_LSTRING(x)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr },
 
 #undef oo_STRING_ARRAY
-#define oo_STRING_ARRAY(x,cap,n)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_STRING_ARRAY(x,cap,n)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_LSTRING_ARRAY
-#define oo_LSTRING_ARRAY(x,cap,n)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, - cap, (const char32 *) 0, U"" #n },
+#define oo_LSTRING_ARRAY(x,cap,n)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
 
 #undef oo_STRING_SET
-#define oo_STRING_SET(x,setType)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_STRING_SET(x,setType)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 #undef oo_LSTRING_SET
-#define oo_LSTRING_SET(x,setType)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
+#define oo_LSTRING_SET(x,setType)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
 
 #undef oo_STRING_VECTOR_FROM
-#define oo_STRING_VECTOR_FROM(x,min,max)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, U"" #min, U"" #max },
+#define oo_STRING_VECTOR_FROM(x,min,max)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_LSTRING_VECTOR_FROM
-#define oo_LSTRING_VECTOR_FROM(x,min,max)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, U"" #min, U"" #max },
+#define oo_LSTRING_VECTOR_FROM(x,min,max)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, U"" #min, U"" #max, nullptr, nullptr },
 
 #undef oo_STRING_VECTOR
-#define oo_STRING_VECTOR(x,n)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_STRING_VECTOR(x,n)  { U"" #x, stringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #undef oo_LSTRING_VECTOR
-#define oo_LSTRING_VECTOR(x,n)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, (const char32 *) 0, U"" #n },
+#define oo_LSTRING_VECTOR(x,n)  { U"" #x, lstringwa, Melder_offsetof (ooSTRUCT, x), sizeof (char32 *), 0, 0, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 
-#define oo_STRUCT(Type,x)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description },
-#define oo_STRUCT_ARRAY(Type,x,cap,n)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, - cap, (const char32 *) 0, U"" #n },
-#define oo_STRUCT_SET(Type,x,setType)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue },
-#define oo_STRUCT_VECTOR_FROM(Type,x,min,max)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 1, U"" #min, U"" #max },
+#define oo_STRUCT(Type,x)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 0, nullptr, nullptr, nullptr, nullptr },
+#define oo_STRUCT_ARRAY(Type,x,cap,n)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, - cap, (const char32 *) 0, U"" #n, nullptr, nullptr },
+#define oo_STRUCT_SET(Type,x,setType)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 3, (const char32 *) setType##_getText, (const char32 *) setType##_getValue, nullptr, nullptr },
+#define oo_STRUCT_VECTOR_FROM(Type,x,min,max)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 1, U"" #min, U"" #max, nullptr, nullptr },
 #undef oo_STRUCT_VECTOR
-#define oo_STRUCT_VECTOR(Type,x,n)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 1, (const char32 *) 0, U"" #n },
+#define oo_STRUCT_VECTOR(Type,x,n)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 1, (const char32 *) 0, U"" #n, nullptr, nullptr },
 #define oo_STRUCT_MATRIX_FROM(Type,x,r1,r2,c1,c2)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 2, U"" #r1, U"" #r2, U"" #c1, U"" #c2 },
 #undef oo_STRUCT_MATRIX
-#define oo_STRUCT_MATRIX(Type,x,nrow,ncol)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 2, (const char32 *) 0, U"" #nrow, (const char32 *) 0, U"" #ncol },
+#define oo_STRUCT_MATRIX(Type,x,nrow,ncol)  { U"" #x, structwa, Melder_offsetof (ooSTRUCT, x), sizeof (struct struct##Type), U"" #Type, & struct##Type :: s_description, 2, nullptr, U"" #nrow, nullptr, U"" #ncol },
 
-#define oo_AUTO_OBJECT(Type,version,x)  { U"" #x, autoobjectwa, Melder_offsetof (ooSTRUCT, x), sizeof (Type), U"" #Type, & theClassInfo_##Type },
-#define oo_COLLECTION_OF(Type,x,ItemType,version)  { U"" #x, collectionofwa, Melder_offsetof (ooSTRUCT, x), sizeof (class struct##ItemType), U"" #Type, & theClassInfo_Collection, 0, (const char32 *) & theClassInfo_##ItemType },
-#define oo_AUTO_COLLECTION(Type,x,ItemType,version)  { U"" #x, autocollectionwa, Melder_offsetof (ooSTRUCT, x), sizeof (class struct##ItemType), U"" #Type, & theClassInfo_##Type, 0, (const char32 *) & theClassInfo_##ItemType },
+#define oo_AUTO_OBJECT(Type,version,x)  { U"" #x, autoobjectwa, Melder_offsetof (ooSTRUCT, x), sizeof (Type), U"" #Type, & theClassInfo_##Type, 0, nullptr, nullptr, nullptr, nullptr },
+#define oo_COLLECTION_OF(Type,x,ItemType,version)  { U"" #x, collectionofwa, Melder_offsetof (ooSTRUCT, x), sizeof (class struct##ItemType), U"" #Type, & theClassInfo_Collection, 0, (const char32 *) & theClassInfo_##ItemType, nullptr, nullptr, nullptr },
+#define oo_AUTO_COLLECTION(Type,x,ItemType,version)  { U"" #x, autocollectionwa, Melder_offsetof (ooSTRUCT, x), sizeof (class struct##ItemType), U"" #Type, & theClassInfo_##Type, 0, (const char32 *) & theClassInfo_##ItemType, nullptr, nullptr, nullptr },
 #define oo_FILE(x)
 #define oo_DIR(x)
 
 #define oo_DEFINE_STRUCT(Type) \
 	static struct structData_Description the##Type##_description [] = {
 #define oo_END_STRUCT(Type) \
-		{ 0 } \
+		{ } \
 	}; \
 	Data_Description struct##Type :: s_description = & the##Type##_description [0];
 
 #define oo_DEFINE_CLASS(Class,Parent) \
 	static struct structData_Description the##Class##_description [] = { \
-		{ U"" #Class, inheritwa, 0, sizeof (class struct##Class), U"" #Class, & theClassInfo_##Parent },
+		{ U"" #Class, inheritwa, 0, sizeof (class struct##Class), U"" #Class, & theClassInfo_##Parent, 0, nullptr, nullptr, nullptr, nullptr },
 #define oo_END_CLASS(Class) \
-		{ 0 } \
+		{ } \
 	}; \
 	Data_Description struct##Class :: s_description = & the##Class##_description [0];
 
diff --git a/sys/oo_READ_BINARY.h b/sys/oo_READ_BINARY.h
index 50d7e68..b14f4fa 100644
--- a/sys/oo_READ_BINARY.h
+++ b/sys/oo_READ_BINARY.h
@@ -1,6 +1,6 @@
 /* oo_READ_BINARY.h
  *
- * Copyright (C) 1994-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1994-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -125,7 +125,7 @@
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,formatVersion)  \
 	{ \
-		int32 n = bingeti4 (f); \
+		int32 n = bingeti32 (f); \
 		for (int32 i = 1; i <= n; i ++) { \
 			auto##ItemClass item = Thing_new (ItemClass); \
 			item -> v_readBinary (f, formatVersion); \
@@ -135,7 +135,7 @@
 
 #define oo_AUTO_COLLECTION(Class,x,ItemClass,formatVersion)  \
 	{ \
-		int32 n = bingeti4 (f); \
+		int32 n = bingeti32 (f); \
 		our x = Class##_create (); \
 		for (int32 i = 1; i <= n; i ++) { \
 			auto##ItemClass item = Thing_new (ItemClass); \
diff --git a/sys/oo_READ_TEXT.h b/sys/oo_READ_TEXT.h
index 3d00d0c..752a263 100644
--- a/sys/oo_READ_TEXT.h
+++ b/sys/oo_READ_TEXT.h
@@ -1,6 +1,6 @@
 /* oo_READ_TEXT.h
  *
- * Copyright (C) 1994-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1994-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -146,7 +146,7 @@
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,formatVersion)  \
 	{ \
-		long n = texgeti4 (a_text); \
+		long n = texgeti32 (a_text); \
 		for (long i = 1; i <= n; i ++) { \
 			auto##ItemClass item = Thing_new (ItemClass); \
 			item -> v_readText (a_text, formatVersion); \
@@ -156,7 +156,7 @@
 
 #define oo_AUTO_COLLECTION(Class,x,ItemClass,formatVersion)  \
 	{ \
-		long n = texgeti4 (a_text); \
+		long n = texgeti32 (a_text); \
 		our x = Class##_create (); \
 		for (long i = 1; i <= n; i ++) { \
 			auto##ItemClass item = Thing_new (ItemClass); \
diff --git a/sys/oo_WRITE_BINARY.h b/sys/oo_WRITE_BINARY.h
index 90d614f..a281e49 100644
--- a/sys/oo_WRITE_BINARY.h
+++ b/sys/oo_WRITE_BINARY.h
@@ -1,6 +1,6 @@
 /* oo_WRITE_BINARY.h
  *
- * Copyright (C) 1994-2012,2013,2014,2015 Paul Boersma
+ * Copyright (C) 1994-2012,2013,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -93,14 +93,14 @@
 		Data_writeBinary (our x.get(), f);
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,version)  \
-	binputi4 (our x.size, f); \
+	binputi32 (our x.size, f); \
 	for (long i = 1; i <= our x.size; i ++) { \
 		ItemClass data = our x.at [i]; \
 		data -> struct##ItemClass :: v_writeBinary (f); \
 	}
 
 #define oo_AUTO_COLLECTION(Class,x,ItemClass,version)  \
-	binputi4 (our x ? our x->size : 0, f); \
+	binputi32 (our x ? our x->size : 0, f); \
 	if (our x) { \
 		for (long i = 1; i <= our x->size; i ++) { \
 			ItemClass data = our x->at [i]; \
diff --git a/sys/oo_WRITE_TEXT.h b/sys/oo_WRITE_TEXT.h
index 9dae4fb..ce9d615 100644
--- a/sys/oo_WRITE_TEXT.h
+++ b/sys/oo_WRITE_TEXT.h
@@ -1,6 +1,6 @@
 /* oo_WRITE_TEXT.h
  *
- * Copyright (C) 1994-2012,2013,2014,2015 Paul Boersma
+ * Copyright (C) 1994-2012,2013,2014,2015,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -134,7 +134,7 @@
 		Data_writeText (our x.get(), file);
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,version)  \
-	texputi4 (file, our x.size, U"" #x U": size", 0,0,0,0,0); \
+	texputi32 (file, our x.size, U"" #x U": size", 0,0,0,0,0); \
 	for (long i = 1; i <= our x.size; i ++) { \
 		ItemClass data = our x.at [i]; \
 		texputintro (file, U"" #x U" [", Melder_integer (i), U"]:", 0,0,0); \
@@ -143,7 +143,7 @@
 	}
 
 #define oo_AUTO_COLLECTION(Class,x,ItemClass,version)  \
-	texputi4 (file, our x ? our x->size : 0, U"" #x U": size", 0,0,0,0,0); \
+	texputi32 (file, our x ? our x->size : 0, U"" #x U": size", 0,0,0,0,0); \
 	if (our x) { \
 		for (long i = 1; i <= our x->size; i ++) { \
 			ItemClass data = our x->at [i]; \
diff --git a/sys/praat.cpp b/sys/praat.cpp
index 3d2ace5..1cf3776 100644
--- a/sys/praat.cpp
+++ b/sys/praat.cpp
@@ -63,7 +63,7 @@ structPraatPicture theForegroundPraatPicture;
 PraatPicture theCurrentPraatPicture = & theForegroundPraatPicture;
 struct PraatP praatP;
 static char32 programName [64];
-static structMelderDir homeDir { { 0 } };
+static structMelderDir homeDir { };
 /*
  * praatDirectory: preferences file, buttons file, message files, tracing file, plugins.
  *    Unix:   /u/miep/.myProg-dir   (without slash)
@@ -72,7 +72,7 @@ static structMelderDir homeDir { { 0 } };
  *    Mac X:   /Users/Miep/Library/Preferences/MyProg Prefs
  */
 extern structMelderDir praatDir;
-structMelderDir praatDir { { 0 } };
+structMelderDir praatDir { };
 /*
  * prefsFile: preferences file.
  *    Unix:   /u/miep/.myProg-dir/prefs5
@@ -80,7 +80,7 @@ structMelderDir praatDir { { 0 } };
  *                       or:   C:\Users\Miep\MyProg\Preferences5.ini
  *    Mac X:   /Users/Miep/Library/Preferences/MyProg Prefs/Prefs5
  */
-static structMelderFile prefsFile { 0 };
+static structMelderFile prefsFile { };
 /*
  * buttonsFile: buttons file.
  *    Unix:   /u/miep/.myProg-dir/buttons
@@ -88,12 +88,12 @@ static structMelderFile prefsFile { 0 };
  *                    or:   C:\Users\Miep\MyProg\Buttons5.ini
  *    Mac X:   /Users/Miep/Library/Preferences/MyProg Prefs/Buttons5
  */
-static structMelderFile buttonsFile { 0 };
+static structMelderFile buttonsFile { };
 #if defined (UNIX)
-	static structMelderFile pidFile { 0 };   // like /u/miep/.myProg-dir/pid
-	static structMelderFile messageFile { 0 };   // like /u/miep/.myProg-dir/message
+	static structMelderFile pidFile { };   // like /u/miep/.myProg-dir/pid
+	static structMelderFile messageFile { };   // like /u/miep/.myProg-dir/message
 #elif defined (_WIN32)
-	static structMelderFile messageFile { 0 };   // like C:\Users\Miep\myProg\Message.txt
+	static structMelderFile messageFile { };   // like C:\Users\Miep\myProg\Message.txt
 #endif
 /*
  * tracingFile: tracing file.
@@ -102,7 +102,7 @@ static structMelderFile buttonsFile { 0 };
  *                    or:   C:\Users\Miep\MyProg\Tracing.txt
  *    Mac X:   /Users/Miep/Library/Preferences/MyProg Prefs/Tracing.txt
  */
-static structMelderFile tracingFile { 0 };
+static structMelderFile tracingFile { };
 
 static GuiList praatList_objects;
 
@@ -217,7 +217,7 @@ char32 *praat_name (int IOBJECT) { return str32chr (FULL_NAME, U' ') + 1; }
 void praat_write_do (UiForm dia, const char32 *extension) {
 	int IOBJECT, found = 0;
 	Daata data = nullptr;
-	static MelderString defaultFileName { 0 };
+	static MelderString defaultFileName { };
 	WHERE (SELECTED) { if (! data) data = (Daata) OBJECT; found += 1; }
 	if (found == 1) {
 		MelderString_copy (& defaultFileName, data -> name);
@@ -357,7 +357,7 @@ void praat_newWithFile (autoDaata me, MelderFile file, const char32 *myName) {
 	theCurrentPraatObjects -> totalBeingCreated ++;
 }
 
-static MelderString thePraatNewName { 0 };
+static MelderString thePraatNewName { };
 void praat_new (autoDaata me) {
 	praat_newWithFile (me.move(), nullptr, U"");
 }
@@ -1180,7 +1180,7 @@ void praat_init (const char32 *title, int argc, char **argv)
 	 * Also create names for message and tracing files.
 	 */
 	if (MelderDir_isNull (& praatDir)) {   // not yet set by the --prefdir option?
-		structMelderDir prefParentDir { { 0 } };   // directory under which to store our preferences directory
+		structMelderDir prefParentDir { };   // directory under which to store our preferences directory
 		Melder_getPrefDir (& prefParentDir);
 
 		/*
@@ -1390,7 +1390,7 @@ static void executeStartUpFile (MelderDir startUpDirectory, const char32 *fileNa
 	char32 name [256];
 	Melder_sprint (name,256, fileNameHead, programName, fileNameTail);
 	if (! MelderDir_isNull (startUpDirectory)) {   // should not occur on modern systems
-		structMelderFile startUp = { 0 };
+		structMelderFile startUp { };
 		MelderDir_getFile (startUpDirectory, name, & startUp);
 		if (! MelderFile_readable (& startUp))
 			return;   // it's OK if the file doesn't exist
@@ -1472,7 +1472,7 @@ void praat_run () {
 	 * On Unix and the Mac, we try no less than three start-up file names.
 	 */
 	#if defined (UNIX) || defined (macintosh)
-		structMelderDir usrLocal = { { 0 } };
+		structMelderDir usrLocal { };
 		Melder_pathToDir (U"/usr/local", & usrLocal);
 		executeStartUpFile (& usrLocal, U"", U"-startUp");
 	#endif
@@ -1489,14 +1489,14 @@ void praat_run () {
 		/* The Praat phase should remain praat_STARTING_UP,
 		 * because any added commands must not be included in the buttons file.
 		 */
-		structMelderFile searchPattern { 0 };
+		structMelderFile searchPattern { };
 		MelderDir_getFile (& praatDir, U"plugin_*", & searchPattern);
 		try {
 			autoStrings directoryNames = Strings_createAsDirectoryList (Melder_fileToPath (& searchPattern));
 			if (directoryNames -> numberOfStrings > 0) {
 				for (long i = 1; i <= directoryNames -> numberOfStrings; i ++) {
-					structMelderDir pluginDir { { 0 } };
-					structMelderFile plugin { 0 };
+					structMelderDir pluginDir { };
+					structMelderFile plugin { };
 					MelderDir_getSubdir (& praatDir, directoryNames -> strings [i], & pluginDir);
 					MelderDir_getFile (& pluginDir, U"setup.praat", & plugin);
 					if (MelderFile_readable (& plugin)) {
@@ -1516,15 +1516,18 @@ void praat_run () {
 	}
 
 	Melder_assert (str32equ (Melder_double (1.5), U"1.5"));   // check locale settings; because of the required file portability Praat cannot stand "1,5"
+	{ unsigned char dummy = 200;
+		Melder_assert ((int) dummy == 200);
+	}
 	{ int dummy = 200;
-		Melder_assert ((int) (signed char) dummy == -56);   // bingeti1 relies on this
+		Melder_assert ((int) (signed char) dummy == -56);   // bingeti8 relies on this
 		Melder_assert ((int) (unsigned char) dummy == 200);
 		Melder_assert ((double) dummy == 200.0);
 		Melder_assert ((double) (signed char) dummy == -56.0);
 		Melder_assert ((double) (unsigned char) dummy == 200.0);
 	}
 	{ uint16 dummy = 40000;
-		Melder_assert ((int) (int16_t) dummy == -25536);   // bingeti2 relies on this
+		Melder_assert ((int) (int16_t) dummy == -25536);   // bingeti16 relies on this
 		Melder_assert ((short) (int16_t) dummy == -25536);   // bingete2 relies on this
 		Melder_assert ((double) dummy == 40000.0);
 		Melder_assert ((double) (int16_t) dummy == -25536.0);
@@ -1555,6 +1558,38 @@ void praat_run () {
 		Melder_assert (str32str (U"hellogoodbye", U"ogo"));
 		Melder_assert (! str32str (U"hellogoodbye", U"oygo"));
 	}
+	Melder_assert (isundef (undefined));
+	Melder_assert (isinf (1.0 / 0.0));
+	Melder_assert (isnan (0.0 / 0.0));
+	{
+		double x = sqrt (-10.0);
+		//if (! isnan (x)) printf ("sqrt (-10.0) = %g\n", x);   // -10.0 on Windows
+		x = sqrt_scalar (-10.0);
+		Melder_assert (isundef (x));
+	}
+	Melder_assert (isdefined (0.0));
+	Melder_assert (isdefined (1e300));
+	Melder_assert (isundef ((real) 1e320L));
+	Melder_assert (isundef (pow (10.0, 330)));
+	Melder_assert (isundef (0.0 / 0.0));
+	Melder_assert (isundef (1.0 / 0.0));
+	{
+		numvec x { };
+		Melder_assert (! x.at);
+		Melder_assert (x.size == 0);
+		nummat y { };
+		Melder_assert (! y.at);
+		Melder_assert (y.nrow == 0);
+		Melder_assert (y.ncol == 0);
+		autonummat z {y.at,y.nrow,y.ncol};   // OK
+		autonummat a;
+		a = z.move();
+		autonumvec b { x };
+		//autonumvec c = x;   // implicit construction not OK
+	}
+	Melder_assert (sizeof (real32) == 4);
+	Melder_assert (sizeof (real64) == 8);
+	Melder_assert (sizeof (real80) >= 12);
 
 	if (sizeof (off_t) < 8)
 		Melder_fatal (U"sizeof(off_t) is less than 8. Compile Praat with -D_FILE_OFFSET_BITS=64.");
diff --git a/sys/praat.h b/sys/praat.h
index 7bb7946..47fb4c9 100644
--- a/sys/praat.h
+++ b/sys/praat.h
@@ -2,7 +2,7 @@
 #define _praat_h_
 /* praat.h
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -434,7 +434,7 @@ void praat_name2 (char32 *name, ClassInfo klas1, ClassInfo klas2);
 			try { \
 				MelderFile file; \
 				int IOBJECT = 0; \
-				structMelderFile file2 { 0 }; \
+				structMelderFile file2 { }; \
 				(void) IOBJECT; \
 				if (! args && ! sendingString) { \
 					file = UiFile_getFile (dia); \
@@ -455,7 +455,7 @@ void praat_name2 (char32 *name, ClassInfo klas1, ClassInfo klas2);
 			try { \
 				MelderFile file; \
 				int IOBJECT = 0; \
-				structMelderFile file2 { 0 }; \
+				structMelderFile file2 { }; \
 				(void) IOBJECT; \
 				if (! args && ! sendingString) { \
 					file = UiFile_getFile (dia); \
diff --git a/sys/praat_actions.cpp b/sys/praat_actions.cpp
index 30d5fcd..9f58e26 100644
--- a/sys/praat_actions.cpp
+++ b/sys/praat_actions.cpp
@@ -281,7 +281,7 @@ void praat_addActionScript (const char32 *className1, int n1, const char32 *clas
 		if (str32len (script) == 0) {
 			action -> script = nullptr;
 		} else {
-			structMelderFile file = { 0 };
+			structMelderFile file { };
 			Melder_relativePathToFile (script, & file);
 			action -> script = Melder_dup_f (Melder_fileToPath (& file));
 		}
diff --git a/sys/praat_menuCommands.cpp b/sys/praat_menuCommands.cpp
index 82ecea3..4b94da9 100644
--- a/sys/praat_menuCommands.cpp
+++ b/sys/praat_menuCommands.cpp
@@ -1,6 +1,6 @@
 /* praat_menuCommands.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -268,7 +268,7 @@ void praat_addMenuCommandScript (const char32 *window, const char32 *menu, const
 		if (str32len (script) == 0) {
 			command -> script = Melder_dup_f (U"");   // empty string, which will be needed to signal origin
 		} else {
-			structMelderFile file = { 0 };
+			structMelderFile file { };
 			Melder_relativePathToFile (script, & file);
 			command -> script = Melder_dup_f (Melder_fileToPath (& file));
 		}
diff --git a/sys/praat_objectMenus.cpp b/sys/praat_objectMenus.cpp
index 584b841..6e423ad 100644
--- a/sys/praat_objectMenus.cpp
+++ b/sys/praat_objectMenus.cpp
@@ -1,6 +1,6 @@
 /* praat_objectMenus.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -53,7 +53,7 @@ DO
 	static MelderString string;
 	MelderString_copy (& string, newName);
 	praat_cleanUpName (string.string);
-	static MelderString fullName { 0 };
+	static MelderString fullName { };
 	MelderString_copy (& fullName, Thing_className (OBJECT), U" ", string.string);
 	if (! str32equ (fullName.string, FULL_NAME)) {
 		Melder_free (FULL_NAME), FULL_NAME = Melder_dup_f (fullName.string);
@@ -266,7 +266,7 @@ FORM (STRING_praat_calculator, U"Calculator", U"Calculator") {
 	LABEL (U"", U"For details, click Help.")
 	OK
 DO
-	struct Formula_Result result;
+	Formula_Result result;
 	if (! interpreter) {
 		autoInterpreter tempInterpreter = Interpreter_create (nullptr, nullptr);
 		Interpreter_anyExpression (tempInterpreter.get(), expression, & result);
@@ -282,8 +282,12 @@ DO
 			Melder_free (result. result.stringResult);
 		} break;
 		case kFormula_EXPRESSION_TYPE_NUMERIC_VECTOR: {
+			Melder_information (result. result.numericVectorResult);
+			result. result.numericVectorResult. reset();
 		} break;
 		case kFormula_EXPRESSION_TYPE_NUMERIC_MATRIX: {
+			Melder_information (result. result.numericMatrixResult);
+			result. result.numericMatrixResult. reset();
 		}
 	}
 END }
@@ -481,7 +485,7 @@ FORM (PRAAT_ManPages_saveToHtmlDirectory, U"Save all pages as HTML files", nullp
 	LABEL (U"", U"Type a directory name:")
 	TEXTFIELD4 (directory, U"directory", U"")
 OK
-	structMelderDir currentDirectory { { 0 } };
+	structMelderDir currentDirectory { };
 	Melder_getDefaultDir (& currentDirectory);
 	SET_STRING (U"directory", Melder_dirToPath (& currentDirectory))
 DO
@@ -535,7 +539,7 @@ FORM (HELP_WriteManualToHtmlDirectory, U"Save all pages as HTML files", nullptr)
 	LABEL (U"", U"Type a directory name:")
 	TEXTFIELD4 (directory, U"directory", U"")
 OK
-	structMelderDir currentDirectory { { 0 } };
+	structMelderDir currentDirectory { };
 	Melder_getDefaultDir (& currentDirectory);
 	SET_STRING (U"directory", Melder_dirToPath (& currentDirectory))
 DO
@@ -572,7 +576,7 @@ static void searchProc () {
 	HELP_SearchManual (nullptr, 0, nullptr, nullptr, nullptr, nullptr, false, nullptr);
 }
 
-static MelderString itemTitle_about { 0 };
+static MelderString itemTitle_about { };
 
 static autoDaata scriptRecognizer (int nread, const char *header, MelderFile file) {
 	const char32 *name = MelderFile_name (file);
diff --git a/sys/praat_picture.cpp b/sys/praat_picture.cpp
index ba026ff..1a160e7 100644
--- a/sys/praat_picture.cpp
+++ b/sys/praat_picture.cpp
@@ -439,7 +439,7 @@ static void GRAPHICS_Picture_writeToEpsFile (UiForm sendingForm, int narg, Stack
 		GRAPHICS_Picture_writeToEpsFile, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.eps");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		Picture_writeToEpsFile (praat_picture.get(), file, true, false);
@@ -457,7 +457,7 @@ static void GRAPHICS_Picture_writeToFontlessEpsFile_xipa (UiForm sendingForm, in
 		GRAPHICS_Picture_writeToFontlessEpsFile_xipa, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.eps");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		Picture_writeToEpsFile (praat_picture.get(), file, false, false);
@@ -472,7 +472,7 @@ static void GRAPHICS_Picture_writeToFontlessEpsFile_silipa (UiForm sendingForm,
 		GRAPHICS_Picture_writeToFontlessEpsFile_silipa, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.eps");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		Picture_writeToEpsFile (praat_picture.get(), file, false, true);
@@ -487,7 +487,7 @@ static void GRAPHICS_Picture_writeToPdfFile (UiForm sendingForm, int narg, Stack
 		GRAPHICS_Picture_writeToPdfFile, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.pdf");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		if (theCurrentPraatPicture == & theForegroundPraatPicture) {
@@ -495,7 +495,7 @@ static void GRAPHICS_Picture_writeToPdfFile (UiForm sendingForm, int narg, Stack
 		} else {
 			try {
 				//autoPraatPicture picture;
-				autoGraphics graphics = Graphics_create_pdffile (file, 300, NUMundefined, 10.24, NUMundefined, 7.68);
+				autoGraphics graphics = Graphics_create_pdffile (file, 300, undefined, 10.24, undefined, 7.68);
 				Graphics_play (GRAPHICS, graphics.get());
 			} catch (MelderError) {
 				Melder_throw (U"Picture not written to PDF file ", file, U".");
@@ -512,7 +512,7 @@ static void GRAPHICS_Picture_writeToPngFile_300 (UiForm sendingForm, int narg, S
 		GRAPHICS_Picture_writeToPngFile_300, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.png");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		if (theCurrentPraatPicture == & theForegroundPraatPicture) {
@@ -536,7 +536,7 @@ static void GRAPHICS_Picture_writeToPngFile_600 (UiForm sendingForm, int narg, S
 		GRAPHICS_Picture_writeToPngFile_600, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.png");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		if (theCurrentPraatPicture == & theForegroundPraatPicture) {
@@ -560,7 +560,7 @@ static void GRAPHICS_Picture_writeToPraatPictureFile (UiForm sendingForm, int na
 		GRAPHICS_Picture_writeToPraatPictureFile, nullptr, invokingButtonTitle, nullptr);
 	if (narg < 0) UiForm_info (dia, narg); else if (! sendingForm && ! args && ! sendingString) {
 		UiOutfile_do (dia, U"praat.prapic");
-	} else { MelderFile file; structMelderFile file2 { 0 };
+	} else { MelderFile file; structMelderFile file2 { };
 		if (! args && ! sendingString) file = UiFile_getFile (dia);
 		else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 		Picture_writeToPraatPictureFile (praat_picture.get(), file);
@@ -590,7 +590,7 @@ END }
 			GRAPHICS_Picture_writeToWindowsMetafile, nullptr, invokingButtonTitle, nullptr);
 		if (! sendingForm && ! args && ! sendingString) {
 			UiOutfile_do (dia, U"praat.emf");
-		} else { MelderFile file; structMelderFile file2 { 0 };
+		} else { MelderFile file; structMelderFile file2 { };
 			if (! args && ! sendingString) file = UiFile_getFile (dia);
 			else { Melder_relativePathToFile (args ? args [1]. string : sendingString, & file2); file = & file2; }
 			Picture_writeToWindowsMetafile (praat_picture.get(), file);
@@ -777,7 +777,7 @@ DO
 	function -> dx = (toX - fromX) / (numberOfHorizontalSteps - 1);
 	Formula_compile (interpreter, function.get(), formula, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 	for (long i = 1; i <= numberOfHorizontalSteps; i ++) {
-		struct Formula_Result result;
+		Formula_Result result;
 		Formula_run (1, i, & result);
 		y [i] = result. result.numericResult;
 	}
diff --git a/sys/praat_script.cpp b/sys/praat_script.cpp
index f716f28..8576d47 100644
--- a/sys/praat_script.cpp
+++ b/sys/praat_script.cpp
@@ -32,7 +32,7 @@ static int praat_findObjectFromString (Interpreter interpreter, const char32 *st
 			/*
 			 * Find the object by its name.
 			 */
-			static MelderString buffer { 0 };
+			static MelderString buffer { };
 			MelderString_copy (& buffer, string);
 			char32 *space = str32chr (buffer.string, U' ');
 			if (! space)
@@ -119,7 +119,7 @@ static int parseCommaSeparatedArguments (Interpreter interpreter, char32 *argume
 			if (narg == MAXIMUM_NUMBER_OF_FIELDS)
 				Melder_throw (U"Cannot have more than ", MAXIMUM_NUMBER_OF_FIELDS, U" arguments");
 			*p = U'\0';
-			struct Formula_Result result;
+			Formula_Result result;
 			Interpreter_anyExpression (interpreter, arguments, & result);
 			narg ++;
 			/*
@@ -213,7 +213,7 @@ int praat_executeCommand (Interpreter interpreter, char32 *command) {
 		} else if (str32nequ (command, U"fappendinfo ", 12)) {
 			if (theCurrentPraatObjects != & theForegroundPraatObjects)
 				Melder_throw (U"The script command \"fappendinfo\" is not available inside pictures.");
-			structMelderFile file = { 0 };
+			structMelderFile file { };
 			Melder_relativePathToFile (command + 12, & file);
 			MelderFile_appendText (& file, Melder_getInfo ());
 		} else if (str32nequ (command, U"unix ", 5)) {
@@ -339,7 +339,7 @@ int praat_executeCommand (Interpreter interpreter, char32 *command) {
 			if (theCurrentPraatObjects != & theForegroundPraatObjects)
 				Melder_throw (U"The script command \"filedelete\" is not available inside manuals.");
 			const char32 *p = command + 11;
-			structMelderFile file = { 0 };
+			structMelderFile file { };
 			while (*p == U' ' || *p == U'\t') p ++;
 			if (*p == U'\0')
 				Melder_throw (U"Missing file name after `filedelete'.");
@@ -370,7 +370,7 @@ int praat_executeCommand (Interpreter interpreter, char32 *command) {
 			}
 			*q = U'\0';
 			if (*p == U' ' || *p == U'\t') {
-				structMelderFile file = { 0 };
+				structMelderFile file { };
 				Melder_relativePathToFile (path, & file);
 				MelderFile_appendText (& file, p + 1);
 			}
@@ -543,7 +543,7 @@ void praat_executeScriptFromFileName (const char32 *fileName, int narg, Stackel
 	/*
 	 * The argument 'fileName' is unsafe. Duplicate its contents.
 	 */
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	Melder_relativePathToFile (fileName, & file);
 	try {
 		autostring32 text = MelderFile_readText (& file);
@@ -561,7 +561,7 @@ void praat_executeScriptFromFileName (const char32 *fileName, int narg, Stackel
 void praat_executeScriptFromFileNameWithArguments (const char32 *nameAndArguments) {
 	char32 path [256];
 	const char32 *p, *arguments;
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	/*
 	 * Split into file name and arguments.
 	 */
@@ -608,7 +608,7 @@ void praat_executeScriptFromText (const char32 *text) {
 
 void praat_executeScriptFromDialog (UiForm dia) {
 	char32 *path = UiForm_getString (dia, U"$file");
-	structMelderFile file { 0 };
+	structMelderFile file { };
 	Melder_pathToFile (path, & file);
 	autostring32 text = MelderFile_readText (& file);
 	autoMelderFileSetDefaultDir dir (& file);
@@ -661,7 +661,7 @@ void DO_RunTheScriptFromAnyAddedMenuCommand (UiForm /* sendingForm_dummy */, int
 	const char32 *scriptPath, Interpreter /* interpreter */,
 	const char32 * /* invokingButtonTitle */, bool /* modified */, void *)
 {
-	structMelderFile file = { 0 };
+	structMelderFile file { };
 	Melder_relativePathToFile (scriptPath, & file);
 	firstPassThroughScript (& file);
 }
diff --git a/sys/praat_statistics.cpp b/sys/praat_statistics.cpp
index 814b696..35171af 100644
--- a/sys/praat_statistics.cpp
+++ b/sys/praat_statistics.cpp
@@ -1,6 +1,6 @@
 /* praat_statistics.cpp
  *
- * Copyright (C) 1992-2012,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma
  *
  * This code is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@ void praat_statistics_exit () {
 void praat_reportIntegerProperties () {
 	MelderInfo_open ();
 	MelderInfo_writeLine (U"Integer properties of this edition of Praat on this computer:\n");
+	MelderInfo_writeLine (U"A boolean is ",                sizeof (bool)        * 8, U" bits.");
 	MelderInfo_writeLine (U"A \"short integer\" is ",      sizeof (short)       * 8, U" bits.");
 	MelderInfo_writeLine (U"An \"integer\" is ",           sizeof (int)         * 8, U" bits.");
 	MelderInfo_writeLine (U"A \"long integer\" is ",       sizeof (long)        * 8, U" bits.");
@@ -141,7 +142,7 @@ void praat_reportMemoryUse () {
 	MelderInfo_writeLine (U"   Arrays: ", NUM_getTotalNumberOfArrays ());
 	MelderInfo_writeLine (U"   Things: ", theTotalNumberOfThings,
 		U" (objects in list: ", theCurrentPraatObjects -> n, U")");
-	long numberOfMotifWidgets =
+	integer numberOfMotifWidgets =
 	#if motif
 		Gui_getNumberOfMotifWidgets ();
 		MelderInfo_writeLine (U"   Motif widgets: ", numberOfMotifWidgets);
diff --git a/sys/praat_version.h b/sys/praat_version.h
index d056e99..294cdc3 100644
--- a/sys/praat_version.h
+++ b/sys/praat_version.h
@@ -1,5 +1,5 @@
-#define PRAAT_VERSION_STR 6.0.30
-#define PRAAT_VERSION_NUM 6030
+#define PRAAT_VERSION_STR 6.0.31
+#define PRAAT_VERSION_NUM 6031
 #define PRAAT_YEAR 2017
-#define PRAAT_MONTH July
-#define PRAAT_DAY 22
+#define PRAAT_MONTH August
+#define PRAAT_DAY 21
diff --git a/sys/sendpraat.c b/sys/sendpraat.c
index 3cd7540..163fa23 100644
--- a/sys/sendpraat.c
+++ b/sys/sendpraat.c
@@ -1,6 +1,6 @@
 /* sendpraat.c */
 /* by Paul Boersma */
-/* 20 July 2017 */
+/* 21 August 2017 */
 
 /*
  * The sendpraat subroutine (Unix with GTK; Windows; Macintosh) sends a message
@@ -386,7 +386,7 @@ wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, co
 			return errorMessageW;
 		}
 		if (timeOut)
-			fwprintf (messageFile, L"#%ld\n", getpid ());   /* Write own process ID for callback. */
+			fwprintf (messageFile, L"#%ld\n", (long) getpid ());   /* Write own process ID for callback. */
 		fwprintf (messageFile, L"\ufeff%ls", text);
 		fclose (messageFile);
 	#elif win
@@ -479,7 +479,7 @@ wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, co
 				if (! displaySupplied) gdk_display_close (display);
 				swprintf (errorMessageW, 1000, L"Cannot send message to %ls (window %ld). "
 					"The program %ls may have been started by a different user, "
-					"or may have crashed.", programName, wid, programName);
+					"or may have crashed.", programName, (long) wid, programName);
 				return errorMessageW;
 			}
 			if (! displaySupplied) gdk_display_close (display);
diff --git a/sys/tensor.cpp b/sys/tensor.cpp
new file mode 100644
index 0000000..27ea28a
--- /dev/null
+++ b/sys/tensor.cpp
@@ -0,0 +1,1251 @@
+/* tensor.cpp
+ *
+ * Copyright (C) 2017 Paul Boersma
+ *
+ * This code 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.
+ *
+ * This code is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this work. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tensor.h"
+#include "NUM2.h"
+
+void numvec :: _initAt (integer givenSize, bool zero) {
+	Melder_assert (givenSize >= 0);
+	try {
+		our at = ( givenSize == 0 ? nullptr : NUMvector <double> (1, givenSize, zero) );
+	} catch (MelderError) {
+		Melder_throw (U"Numeric vector not created.");
+	}
+}
+
+void numvec :: _freeAt () noexcept {
+	if (our at) NUMvector_free (our at, 1);
+}
+
+void nummat :: _initAt (integer givenNrow, integer givenNcol, bool zero) {
+	Melder_assert (givenNrow >= 0);
+	Melder_assert (givenNcol >= 0);
+	try {
+		our at = ( givenNrow > 0 && givenNcol > 0 ? NUMmatrix <double> (1, givenNrow, 1, givenNcol, zero) : nullptr );
+	} catch (MelderError) {
+		Melder_throw (U"Numeric matrix not created.");
+	}
+}
+
+void nummat :: _freeAt () noexcept {
+	if (our at) NUMmatrix_free (our at, 1, 1);
+}
+
+/*
+	Recursive ("pairwise") addition preserves precision.
+	Therefore, don't delete the parentheses!
+*/
+#define tensor_ADD_1(offset)  tensor_TERM ((1+offset))
+#define tensor_ADD_2(offset)  tensor_TERM ((1+offset)) + tensor_TERM ((2+offset))
+#define tensor_ADD_3(offset)  tensor_TERM ((1+offset)) + tensor_TERM ((2+offset)) + tensor_TERM ((3+offset))
+#define tensor_ADD_4(offset)  (tensor_ADD_2 (offset)) + (tensor_ADD_2 (2+offset))
+#define tensor_ADD_5(offset)  (tensor_ADD_3 (offset)) + (tensor_ADD_2 (3+offset))
+#define tensor_ADD_6(offset)  (tensor_ADD_3 (offset)) + (tensor_ADD_3 (3+offset))
+#define tensor_ADD_7(offset)  (tensor_ADD_4 (offset)) + (tensor_ADD_3 (4+offset))
+#define tensor_ADD_8(offset)  (tensor_ADD_4 (offset)) + (tensor_ADD_4 (4+offset))
+#define tensor_ADD_9(offset)  (tensor_ADD_5 (offset)) + (tensor_ADD_4 (5+offset))
+#define tensor_ADD_10(offset)  (tensor_ADD_5 (offset)) + (tensor_ADD_5 (5+offset))
+#define tensor_ADD_11(offset)  (tensor_ADD_6 (offset)) + (tensor_ADD_5 (6+offset))
+#define tensor_ADD_12(offset)  (tensor_ADD_6 (offset)) + (tensor_ADD_6 (6+offset))
+#define tensor_ADD_13(offset)  (tensor_ADD_7 (offset)) + (tensor_ADD_6 (7+offset))
+#define tensor_ADD_14(offset)  (tensor_ADD_7 (offset)) + (tensor_ADD_7 (7+offset))
+#define tensor_ADD_15(offset)  (tensor_ADD_8 (offset)) + (tensor_ADD_7 (8+offset))
+#define tensor_ADD_16(offset)  (tensor_ADD_8 (offset)) + (tensor_ADD_8 (8+offset))
+#define tensor_ADD_17(offset)  (tensor_ADD_9 (offset)) + (tensor_ADD_8 (9+offset))
+#define tensor_ADD_18(offset)  (tensor_ADD_9 (offset)) + (tensor_ADD_9 (9+offset))
+#define tensor_ADD_19(offset)  (tensor_ADD_10 (offset)) + (tensor_ADD_9 (10+offset))
+#define tensor_ADD_20(offset)  (tensor_ADD_10 (offset)) + (tensor_ADD_10 (10+offset))
+#define tensor_ADD_21(offset)  (tensor_ADD_11 (offset)) + (tensor_ADD_10 (11+offset))
+#define tensor_ADD_22(offset)  (tensor_ADD_11 (offset)) + (tensor_ADD_11 (11+offset))
+#define tensor_ADD_23(offset)  (tensor_ADD_12 (offset)) + (tensor_ADD_11 (12+offset))
+#define tensor_ADD_24(offset)  (tensor_ADD_12 (offset)) + (tensor_ADD_12 (12+offset))
+#define tensor_ADD_25(offset)  (tensor_ADD_13 (offset)) + (tensor_ADD_12 (13+offset))
+#define tensor_ADD_26(offset)  (tensor_ADD_13 (offset)) + (tensor_ADD_13 (13+offset))
+#define tensor_ADD_27(offset)  (tensor_ADD_14 (offset)) + (tensor_ADD_13 (14+offset))
+#define tensor_ADD_28(offset)  (tensor_ADD_14 (offset)) + (tensor_ADD_14 (14+offset))
+#define tensor_ADD_29(offset)  (tensor_ADD_15 (offset)) + (tensor_ADD_14 (15+offset))
+#define tensor_ADD_30(offset)  (tensor_ADD_15 (offset)) + (tensor_ADD_15 (15+offset))
+#define tensor_ADD_31(offset)  (tensor_ADD_16 (offset)) + (tensor_ADD_15 (16+offset))
+#define tensor_ADD_32(offset)  (tensor_ADD_16 (offset)) + (tensor_ADD_16 (16+offset))
+#define tensor_ADD_33(offset)  (tensor_ADD_17 (offset)) + (tensor_ADD_16 (17+offset))
+#define tensor_ADD_34(offset)  (tensor_ADD_17 (offset)) + (tensor_ADD_17 (17+offset))
+#define tensor_ADD_35(offset)  (tensor_ADD_18 (offset)) + (tensor_ADD_17 (18+offset))
+#define tensor_ADD_36(offset)  (tensor_ADD_18 (offset)) + (tensor_ADD_18 (18+offset))
+#define tensor_ADD_37(offset)  (tensor_ADD_19 (offset)) + (tensor_ADD_18 (19+offset))
+#define tensor_ADD_38(offset)  (tensor_ADD_19 (offset)) + (tensor_ADD_19 (19+offset))
+#define tensor_ADD_39(offset)  (tensor_ADD_20 (offset)) + (tensor_ADD_19 (20+offset))
+#define tensor_ADD_40(offset)  (tensor_ADD_20 (offset)) + (tensor_ADD_20 (20+offset))
+#define tensor_ADD_41(offset)  (tensor_ADD_21 (offset)) + (tensor_ADD_20 (21+offset))
+#define tensor_ADD_42(offset)  (tensor_ADD_21 (offset)) + (tensor_ADD_21 (21+offset))
+#define tensor_ADD_43(offset)  (tensor_ADD_22 (offset)) + (tensor_ADD_21 (22+offset))
+#define tensor_ADD_44(offset)  (tensor_ADD_22 (offset)) + (tensor_ADD_22 (22+offset))
+#define tensor_ADD_45(offset)  (tensor_ADD_23 (offset)) + (tensor_ADD_22 (23+offset))
+#define tensor_ADD_46(offset)  (tensor_ADD_23 (offset)) + (tensor_ADD_23 (23+offset))
+#define tensor_ADD_47(offset)  (tensor_ADD_24 (offset)) + (tensor_ADD_23 (24+offset))
+#define tensor_ADD_48(offset)  (tensor_ADD_24 (offset)) + (tensor_ADD_24 (24+offset))
+#define tensor_ADD_49(offset)  (tensor_ADD_25 (offset)) + (tensor_ADD_24 (25+offset))
+#define tensor_ADD_50(offset)  (tensor_ADD_25 (offset)) + (tensor_ADD_25 (25+offset))
+#define tensor_ADD_51(offset)  (tensor_ADD_26 (offset)) + (tensor_ADD_25 (26+offset))
+#define tensor_ADD_52(offset)  (tensor_ADD_26 (offset)) + (tensor_ADD_26 (26+offset))
+#define tensor_ADD_53(offset)  (tensor_ADD_27 (offset)) + (tensor_ADD_26 (27+offset))
+#define tensor_ADD_54(offset)  (tensor_ADD_27 (offset)) + (tensor_ADD_27 (27+offset))
+#define tensor_ADD_55(offset)  (tensor_ADD_28 (offset)) + (tensor_ADD_27 (28+offset))
+#define tensor_ADD_56(offset)  (tensor_ADD_28 (offset)) + (tensor_ADD_28 (28+offset))
+#define tensor_ADD_57(offset)  (tensor_ADD_29 (offset)) + (tensor_ADD_28 (29+offset))
+#define tensor_ADD_58(offset)  (tensor_ADD_29 (offset)) + (tensor_ADD_29 (29+offset))
+#define tensor_ADD_59(offset)  (tensor_ADD_30 (offset)) + (tensor_ADD_29 (30+offset))
+#define tensor_ADD_60(offset)  (tensor_ADD_30 (offset)) + (tensor_ADD_30 (30+offset))
+#define tensor_ADD_61(offset)  (tensor_ADD_31 (offset)) + (tensor_ADD_30 (31+offset))
+#define tensor_ADD_62(offset)  (tensor_ADD_31 (offset)) + (tensor_ADD_31 (31+offset))
+#define tensor_ADD_63(offset)  (tensor_ADD_32 (offset)) + (tensor_ADD_31 (32+offset))
+#define tensor_ADD_64(offset)  (tensor_ADD_32 (offset)) + (tensor_ADD_32 (32+offset))
+
+#define tensor_ADD_casesUpTo7(remainder,sum)  \
+	switch (remainder) {  \
+		case 0: sum = 0.0; break;  \
+		case 1: sum = tensor_ADD_1 (0); break;  \
+		case 2: sum = tensor_ADD_2 (0); break;  \
+		case 3: sum = tensor_ADD_3 (0); break;  \
+		case 4: sum = tensor_ADD_4 (0); break;  \
+		case 5: sum = tensor_ADD_5 (0); break;  \
+		case 6: sum = tensor_ADD_6 (0); break;  \
+		case 7: sum = tensor_ADD_7 (0); break;  \
+		default: sum = undefined;  \
+	}
+
+#define tensor_ADD_casesUpTo15(remainder,sum)  \
+	switch (remainder) {  \
+		case 0: sum = 0.0; break;  \
+		case 1: sum = tensor_ADD_1 (0); break;  \
+		case 2: sum = tensor_ADD_2 (0); break;  \
+		case 3: sum = tensor_ADD_3 (0); break;  \
+		case 4: sum = tensor_ADD_4 (0); break;  \
+		case 5: sum = tensor_ADD_5 (0); break;  \
+		case 6: sum = tensor_ADD_6 (0); break;  \
+		case 7: sum = tensor_ADD_7 (0); break;  \
+		case 8: sum = tensor_ADD_8 (0); break;  \
+		case 9: sum = tensor_ADD_9 (0); break;  \
+		case 10: sum = tensor_ADD_10 (0); break;  \
+		case 11: sum = tensor_ADD_11 (0); break;  \
+		case 12: sum = tensor_ADD_12 (0); break;  \
+		case 13: sum = tensor_ADD_13 (0); break;  \
+		case 14: sum = tensor_ADD_14 (0); break;  \
+		case 15: sum = tensor_ADD_15 (0); break;  \
+		default: sum = undefined;  \
+	}
+
+#define tensor_ADD_casesUpTo31(remainder,sum)  \
+	switch (remainder) {  \
+		case 0: sum = 0.0; break;  \
+		case 1: sum = tensor_ADD_1 (0); break;  \
+		case 2: sum = tensor_ADD_2 (0); break;  \
+		case 3: sum = tensor_ADD_3 (0); break;  \
+		case 4: sum = tensor_ADD_4 (0); break;  \
+		case 5: sum = tensor_ADD_5 (0); break;  \
+		case 6: sum = tensor_ADD_6 (0); break;  \
+		case 7: sum = tensor_ADD_7 (0); break;  \
+		case 8: sum = tensor_ADD_8 (0); break;  \
+		case 9: sum = tensor_ADD_9 (0); break;  \
+		case 10: sum = tensor_ADD_10 (0); break;  \
+		case 11: sum = tensor_ADD_11 (0); break;  \
+		case 12: sum = tensor_ADD_12 (0); break;  \
+		case 13: sum = tensor_ADD_13 (0); break;  \
+		case 14: sum = tensor_ADD_14 (0); break;  \
+		case 15: sum = tensor_ADD_15 (0); break;  \
+		case 16: sum = tensor_ADD_16 (0); break;  \
+		case 17: sum = tensor_ADD_17 (0); break;  \
+		case 18: sum = tensor_ADD_18 (0); break;  \
+		case 19: sum = tensor_ADD_19 (0); break;  \
+		case 20: sum = tensor_ADD_20 (0); break;  \
+		case 21: sum = tensor_ADD_21 (0); break;  \
+		case 22: sum = tensor_ADD_22 (0); break;  \
+		case 23: sum = tensor_ADD_23 (0); break;  \
+		case 24: sum = tensor_ADD_24 (0); break;  \
+		case 25: sum = tensor_ADD_25 (0); break;  \
+		case 26: sum = tensor_ADD_26 (0); break;  \
+		case 27: sum = tensor_ADD_27 (0); break;  \
+		case 28: sum = tensor_ADD_28 (0); break;  \
+		case 29: sum = tensor_ADD_29 (0); break;  \
+		case 30: sum = tensor_ADD_30 (0); break;  \
+		case 31: sum = tensor_ADD_31 (0); break;  \
+		default: sum = undefined;  \
+	}
+
+#define tensor_ADD_casesUpTo63(remainder,sum)  \
+	switch (remainder) {  \
+		case 0: sum = 0.0; break;  \
+		case 1: sum = tensor_ADD_1 (0); break;  \
+		case 2: sum = tensor_ADD_2 (0); break;  \
+		case 3: sum = tensor_ADD_3 (0); break;  \
+		case 4: sum = tensor_ADD_4 (0); break;  \
+		case 5: sum = tensor_ADD_5 (0); break;  \
+		case 6: sum = tensor_ADD_6 (0); break;  \
+		case 7: sum = tensor_ADD_7 (0); break;  \
+		case 8: sum = tensor_ADD_8 (0); break;  \
+		case 9: sum = tensor_ADD_9 (0); break;  \
+		case 10: sum = tensor_ADD_10 (0); break;  \
+		case 11: sum = tensor_ADD_11 (0); break;  \
+		case 12: sum = tensor_ADD_12 (0); break;  \
+		case 13: sum = tensor_ADD_13 (0); break;  \
+		case 14: sum = tensor_ADD_14 (0); break;  \
+		case 15: sum = tensor_ADD_15 (0); break;  \
+		case 16: sum = tensor_ADD_16 (0); break;  \
+		case 17: sum = tensor_ADD_17 (0); break;  \
+		case 18: sum = tensor_ADD_18 (0); break;  \
+		case 19: sum = tensor_ADD_19 (0); break;  \
+		case 20: sum = tensor_ADD_20 (0); break;  \
+		case 21: sum = tensor_ADD_21 (0); break;  \
+		case 22: sum = tensor_ADD_22 (0); break;  \
+		case 23: sum = tensor_ADD_23 (0); break;  \
+		case 24: sum = tensor_ADD_24 (0); break;  \
+		case 25: sum = tensor_ADD_25 (0); break;  \
+		case 26: sum = tensor_ADD_26 (0); break;  \
+		case 27: sum = tensor_ADD_27 (0); break;  \
+		case 28: sum = tensor_ADD_28 (0); break;  \
+		case 29: sum = tensor_ADD_29 (0); break;  \
+		case 30: sum = tensor_ADD_30 (0); break;  \
+		case 31: sum = tensor_ADD_31 (0); break;  \
+		case 32: sum = tensor_ADD_32 (0); break;  \
+		case 33: sum = tensor_ADD_33 (0); break;  \
+		case 34: sum = tensor_ADD_34 (0); break;  \
+		case 35: sum = tensor_ADD_35 (0); break;  \
+		case 36: sum = tensor_ADD_36 (0); break;  \
+		case 37: sum = tensor_ADD_37 (0); break;  \
+		case 38: sum = tensor_ADD_38 (0); break;  \
+		case 39: sum = tensor_ADD_39 (0); break;  \
+		case 40: sum = tensor_ADD_40 (0); break;  \
+		case 41: sum = tensor_ADD_41 (0); break;  \
+		case 42: sum = tensor_ADD_42 (0); break;  \
+		case 43: sum = tensor_ADD_43 (0); break;  \
+		case 44: sum = tensor_ADD_44 (0); break;  \
+		case 45: sum = tensor_ADD_45 (0); break;  \
+		case 46: sum = tensor_ADD_46 (0); break;  \
+		case 47: sum = tensor_ADD_47 (0); break;  \
+		case 48: sum = tensor_ADD_48 (0); break;  \
+		case 49: sum = tensor_ADD_49 (0); break;  \
+		case 50: sum = tensor_ADD_50 (0); break;  \
+		case 51: sum = tensor_ADD_51 (0); break;  \
+		case 52: sum = tensor_ADD_52 (0); break;  \
+		case 53: sum = tensor_ADD_53 (0); break;  \
+		case 54: sum = tensor_ADD_54 (0); break;  \
+		case 55: sum = tensor_ADD_55 (0); break;  \
+		case 56: sum = tensor_ADD_56 (0); break;  \
+		case 57: sum = tensor_ADD_57 (0); break;  \
+		case 58: sum = tensor_ADD_58 (0); break;  \
+		case 59: sum = tensor_ADD_59 (0); break;  \
+		case 60: sum = tensor_ADD_60 (0); break;  \
+		case 61: sum = tensor_ADD_61 (0); break;  \
+		case 62: sum = tensor_ADD_62 (0); break;  \
+		case 63: sum = tensor_ADD_63 (0); break;  \
+		default: sum = undefined;  \
+	}
+/*
+	For instance:
+		tensor_ADD_4 (0) =
+			(tensor_ADD_2 (0)) + (tensor_ADD_2 (2)) =
+			(tensor_TERM ((1+0)) + tensor_TERM ((2+0))) + (tensor_TERM ((1+2)) + tensor_TERM ((2+2)))
+*/
+
+void sum_mean_scalar (numvec x, real *p_sum, real *p_mean) noexcept {
+	if (x.size <= 4) {
+		switch (x.size) {
+			case 0: {
+				if (p_sum) *p_sum = 0.0;
+				if (p_mean) *p_mean = undefined;
+			} break; case 1: {
+				if (p_sum) *p_sum = x [1];
+				if (p_mean) *p_mean = x [1];
+			} break; case 2: {
+				real80 sum = (real80) x [1] + (real80) x [2];
+				if (p_sum) *p_sum = (real) sum;
+				if (p_mean) *p_mean = real (0.5 * sum);
+			} break; case 3: {
+				real80 sum = (real80) x [1] + (real80) x [2] + (real80) x [3];
+				if (p_sum) *p_sum = (real) sum;
+				if (p_mean) *p_mean = real (sum / 3.0);
+			} break; case 4: {
+				real80 sum = ((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4]);
+				if (p_sum) *p_sum = (real) sum;
+				if (p_mean) *p_mean = real (0.25 * sum);
+			} break; default: {
+				if (p_sum) *p_sum = undefined;
+				if (p_mean) *p_mean = undefined;
+			}
+		}
+		return;
+	}
+	if (Melder_debug != 0) {
+		if (Melder_debug == 48) {
+			/*
+				Naive implementation in real64.
+			*/
+			real sum = 0.0;   // -> sum in R (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				sum += x [i];   // sum before in R, x [i] in R -> sum after in R
+			}
+			if (p_sum) *p_sum = sum;
+			real mean = sum / x.size;   // sum in R, x.size != 0 -> mean in R
+			if (p_mean) *p_mean = mean;
+			return;
+		}
+		if (Melder_debug == 49) {
+			/*
+				Naive implementation in real80.
+			*/
+			real80 sum = 0.0;   // -> sum in R (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				sum += (real80) x [i];   // sum before in R, x [i] in R -> sum after in R
+			}
+			if (p_sum) *p_sum = (real) sum;
+			real80 mean = sum / x.size;   // sum in R, x.size != 0 -> mean in R
+			if (p_mean) *p_mean = (real) mean;
+			return;
+		}
+		if (Melder_debug == 50) {
+			/*
+				First-element offset corrects for large DC components.
+			*/
+			real80 offset = (real80) x [1];   // x.size != 0 -> offset in R
+			real80 sumOfDifferences = 0.0;   // sumOfDifferences in R (invariant)
+			for (integer i = 2; i <= x.size; i ++) {
+				sumOfDifferences += (real80) x [i] - offset;   // sumOfDifferences before in R, x [i] in R, offset in R -> sumOfDifferences after in R
+			}
+			if (p_sum) {
+				real80 sum = sumOfDifferences + offset * x.size;
+				*p_sum = (real) sum;
+			}
+			real80 mean = offset + sumOfDifferences / x.size;   // offset in R, sumOfDifferences in R, x.size != 0 -> mean in R
+			if (p_mean) *p_mean = (real) mean;
+			return;
+		}
+		if (Melder_debug == 51) {
+			/*
+				Chan, Golub & LeVeque's pairwise algorithm.
+			*/
+			#define REAL  real80
+			//real offset = x [1];
+			const real offset = 0.0;
+			long terms [65];
+			REAL suma [65];
+			terms [1] = 0;
+			int top = 2;
+			long n2 = x.size / 2;
+			for (long i = 1; i <= n2; i ++) {
+				/*
+					Compute the sum of the next two data points.
+					Put this sum on top of the stack.
+				*/
+				long start = 2 * i - 1;
+				suma [top] = (REAL) (x [start] - offset) + REAL (x [start + 1] - offset);
+				terms [top] = 2;
+				while (terms [top] == terms [top - 1]) {
+					top --;
+					terms [top] *= 2;
+					suma [top] += suma [top + 1];
+				}
+				top ++;
+			}
+			top --;
+			if (x.size & 1) {
+				/*
+					x.size is odd. Put the last point on the stack.
+				*/
+				top ++;
+				suma [top] = (REAL) (x [x.size] - offset);
+			}
+			REAL sum = suma [top];
+			/*
+				If the remaining stack contains more than one element, x.size is not a power of 2.
+				Add all the elements.
+			*/
+			for (long i = top - 1; i >= 2; i --) {
+				sum += suma [i];
+			}
+			REAL mean = offset + sum / x.size;
+			if (p_sum) {
+				sum += offset * x.size;
+				*p_sum = (real) sum;
+			}
+			if (p_mean) *p_mean = (real) mean;
+			#undef REAL
+			return;
+		}
+		if (Melder_debug == 52) {
+			/*
+				Pairwise algorithm with base case 8.
+				
+				For an explanation see the base case 32 case.
+			*/
+			constexpr integer baseCasePower = 3;
+			constexpr integer baseCaseSize = 1 << baseCasePower;
+			integer remainder = x.size % baseCaseSize;
+			real80 sum;
+			real *y = x.at;
+			#define tensor_TERM(i)  (real80) y [i]
+			tensor_ADD_casesUpTo7 (remainder, sum)
+			integer numberOfBaseCases = x.size / baseCaseSize;
+			if (numberOfBaseCases != 0) {
+				constexpr integer highestIndex = 63 - baseCasePower;
+				integer numbersOfTerms [1 + highestIndex];
+				real80 partialSums [1 + highestIndex];
+				numbersOfTerms [0] = 0;
+				integer stackPointer = 0;
+				y += remainder;
+				for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+					partialSums [++ stackPointer] = tensor_ADD_8 (0);
+					numbersOfTerms [stackPointer] = baseCaseSize;
+					while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+						numbersOfTerms [-- stackPointer] *= 2;
+						partialSums [stackPointer] += partialSums [stackPointer + 1];
+					}
+					y += baseCaseSize;
+				}
+				for (integer i = stackPointer; i > 0; i --) {
+					sum += partialSums [i];
+				}
+			}
+			#undef tensor_TERM
+			if (p_sum) *p_sum = (real) sum;
+			if (p_mean) {
+				real80 mean = sum / x.size;
+				*p_mean = (real) mean;
+			}
+			return;
+		}
+		if (Melder_debug == 53) {
+			/*
+				Pairwise algorithm with base case 16.
+				
+				For an explanation see the base case 32 case.
+			*/
+			constexpr integer baseCasePower = 4;
+			constexpr integer baseCaseSize = 1 << baseCasePower;
+			integer remainder = x.size % baseCaseSize;
+			real80 sum;
+			real *y = x.at;
+			#define tensor_TERM(i)  (real80) y [i]
+			tensor_ADD_casesUpTo15 (remainder, sum)
+			integer numberOfBaseCases = x.size / baseCaseSize;
+			if (numberOfBaseCases != 0) {
+				constexpr integer highestIndex = 63 - baseCasePower;
+				integer numbersOfTerms [1 + highestIndex];
+				real80 partialSums [1 + highestIndex];
+				numbersOfTerms [0] = 0;
+				integer stackPointer = 0;
+				y += remainder;
+				for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+					partialSums [++ stackPointer] = tensor_ADD_16 (0);
+					numbersOfTerms [stackPointer] = baseCaseSize;
+					while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+						numbersOfTerms [-- stackPointer] *= 2;
+						partialSums [stackPointer] += partialSums [stackPointer + 1];
+					}
+					y += baseCaseSize;
+				}
+				for (integer i = stackPointer; i > 0; i --) {
+					sum += partialSums [i];
+				}
+			}
+			#undef tensor_TERM
+			if (p_sum) *p_sum = (real) sum;
+			if (p_mean) {
+				real80 mean = sum / x.size;
+				*p_mean = (real) mean;
+			}
+			return;
+		}
+		if (Melder_debug == 54) {
+			real80 sum = 0.0;   // -> sum in R (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				sum += x [i];   // sum before in R, x [i] in R -> sum after in R
+			}
+			if (p_sum) *p_sum = (real) sum;
+			real80 mean = sum / x.size;   // sum in R, x.size != 0 -> mean in R
+			if (p_mean) {
+				real80 sum2 = 0.0;
+				for (integer i = 1; i <= x.size; i ++) {
+					sum2 += (real80) x [i] - mean;
+				}
+				*p_mean = real (mean + sum2 / x.size);
+			}
+			return;
+		}
+		if (Melder_debug == 55) {
+			/*
+				Pairwise algorithm with base case 32.
+				
+				For an explanation see the base case 64 case.
+			*/
+			constexpr integer baseCasePower = 5;
+			constexpr integer baseCaseSize = 1 << baseCasePower;
+			integer remainder = x.size % baseCaseSize;
+			real80 sum;
+			real *y = x.at;
+			#define tensor_TERM(i)  (real80) y [i]
+			tensor_ADD_casesUpTo31 (remainder, sum)
+			integer numberOfBaseCases = x.size / baseCaseSize;
+			if (numberOfBaseCases != 0) {
+				constexpr integer highestIndex = 63 - baseCasePower;
+				integer numbersOfTerms [1 + highestIndex];
+				real80 partialSums [1 + highestIndex];
+				numbersOfTerms [0] = 0;
+				integer stackPointer = 0;
+				y += remainder;
+				for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+					partialSums [++ stackPointer] = tensor_ADD_32 (0);
+					numbersOfTerms [stackPointer] = baseCaseSize;
+					while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+						numbersOfTerms [-- stackPointer] *= 2;
+						partialSums [stackPointer] += partialSums [stackPointer + 1];
+					}
+					y += baseCaseSize;
+				}
+				for (integer i = stackPointer; i > 0; i --) {
+					sum += partialSums [i];
+				}
+			}
+			#undef tensor_TERM
+			if (p_sum) *p_sum = (real) sum;
+			if (p_mean) {
+				real80 mean = sum / x.size;
+				*p_mean = (real) mean;
+			}
+			return;
+		}
+	}
+	/*
+		Our standard: pairwise algorithm with base case size 64 (if baseCasePower is 6).
+
+		If you want to change the base case size, do the following three things:
+		1. Change the `constexpr integer baseCasePower = 6` assignment (e.g. to 7).
+		2. Change the number of cases in the switch statement (e.g. up to case 127).
+		3. Change the `partialSums [++ stackPointer] = tensor_ADD_64` assignment (e.g. to tensor_ADD_128).
+	*/
+	constexpr integer baseCasePower = 6;
+	constexpr integer baseCaseSize = 1 << baseCasePower;
+	integer numberOfBaseCases = x.size / baseCaseSize, remainder = x.size % baseCaseSize;
+	real80 sum;
+	real *y = x.at;
+	#define tensor_TERM(i)  (real80) y [i]
+	tensor_ADD_casesUpTo63 (remainder, sum)
+	if (numberOfBaseCases != 0) {
+		/*
+			The value of numbersOfTerms [0] stays at 0, to denote the bottom of the stack.
+			The maximum value of numbersOfTerms [1] should be 2^62, because x.size can be at most 2^63-1 (if sizeof integer is 64).
+			The maximum value of numbersOfTerms [2] should then be 2^61.
+			The maximum value of numbersOfTerms [3] should be 2^60.
+			...
+			The maximum value of numbersOfTerms [58] should be 2^5, which is the granularity with which base case sums are put on the stack.
+			The maximum value of numbersOfTerms [59] should also be 2^5, because this can be the situation just before collapsing the top of the stack.
+			However, if the whole stack is filled up like this, the actual number of terms is already 2^63. Therefore, we need one element less.
+			So the highest index of numbersOfTerms [] should be 58.
+		*/
+		constexpr integer highestIndex = 63 - baseCasePower;
+		integer numbersOfTerms [1 + highestIndex];
+		real80 partialSums [1 + highestIndex];
+		numbersOfTerms [0] = 0;   // the constant zero at the bottom of the stack
+		integer stackPointer = 0;
+		y += remainder;
+		for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+			/*
+				Compute the sum of the next 32 data points.
+				Put this sum on top of the stack.
+			*/
+			partialSums [++ stackPointer] = tensor_ADD_64 (0);
+			numbersOfTerms [stackPointer] = baseCaseSize;
+			while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+				numbersOfTerms [-- stackPointer] *= 2;
+				partialSums [stackPointer] += partialSums [stackPointer + 1];
+			}
+			y += baseCaseSize;
+		}
+		/*
+			Add all the elements of the stack, starting at the top (small sums to big sums).
+		*/
+		for (integer i = stackPointer; i > 0; i --) {
+			sum += partialSums [i];
+		}
+	}
+	#undef tensor_TERM
+	if (p_sum) *p_sum = (real) sum;
+	if (p_mean) {
+		real80 mean = sum / x.size;   // it helps a bit to perform this division while still in real80
+		*p_mean = (real) mean;
+	}
+}
+
+void sum_mean_sumsq_variance_stdev_scalar (numvec x, real *p_sum, real *p_mean, real *p_sumsq, real *p_variance, real *p_stdev) noexcept {
+	if (x.size < 2) {
+		if (x.size <= 0) {
+			if (p_sum) *p_sum = 0.0;
+			if (p_mean) *p_mean = undefined;
+			if (p_sumsq) *p_sumsq = undefined;
+		} else {
+			if (p_sum) *p_sum = x [1];
+			if (p_mean) *p_mean = x [1];
+			if (p_sumsq) *p_sumsq = 0.0;
+		}
+		if (p_variance) *p_variance = undefined;
+		if (p_stdev) *p_stdev = undefined;
+		return;
+	}
+	if (Melder_debug != 0) {
+		if (Melder_debug == 48) {
+			/*
+				Naive implementation in real64.
+			*/
+			real sum = 0.0;   // -> sum in R (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				sum += x [i];   // sum before in R, x [i] in R -> sum after in R
+			}
+			if (p_sum) *p_sum = sum;
+			real mean = sum / x.size;   // sum in R, x.size != 0 -> mean in R
+			if (p_mean) *p_mean = mean;
+			if (! p_sumsq && ! p_variance && ! p_stdev) return;
+			real sumOfSquaredResiduals = 0.0;   // -> sumOfSquares >= 0.0 (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				real residual = x [i] - mean;   // x [i] in R, mean in R -> residual in R
+				real squaredResidual = residual * residual;   // residual in R -> squaredResidual >= 0.0
+				sumOfSquaredResiduals += squaredResidual;   // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
+			}
+			if (p_sumsq) *p_sumsq = sumOfSquaredResiduals;
+			integer degreesOfFreedom = x.size - 1;   // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
+			real meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom;   // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
+			if (p_variance) *p_variance = (real) meanSquaredResidual;
+			if (p_stdev) {
+				real rootMeanSquaredResidual = sqrt (meanSquaredResidual);   // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
+				*p_stdev = rootMeanSquaredResidual;
+			}
+			return;
+		}
+		if (Melder_debug == 49) {
+			/*
+				Naive implementation in real80.
+			*/
+			real80 sum = 0.0;   // -> sum in R (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				sum += (real80) x [i];   // sum before in R, x [i] in R -> sum after in R
+			}
+			if (p_sum) *p_sum = (real) sum;
+			real80 mean = sum / x.size;   // sum in R, x.size != 0 -> mean in R
+			if (p_mean) *p_mean = (real) mean;
+			if (! p_sumsq && ! p_variance && ! p_stdev) return;
+			real80 sumOfSquaredResiduals = 0.0;   // -> sumOfSquares >= 0.0 (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				real80 residual = (real80) x [i] - mean;   // x [i] in R, mean in R -> residual in R
+				real80 squaredResidual = residual * residual;   // residual in R -> squaredResidual >= 0.0
+				sumOfSquaredResiduals += squaredResidual;   // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
+			}
+			if (p_sumsq) *p_sumsq = (real) sumOfSquaredResiduals;
+			integer degreesOfFreedom = x.size - 1;   // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
+			real80 meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom;   // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
+			if (p_variance) *p_variance = (real) meanSquaredResidual;
+			if (p_stdev) {
+				real80 rootMeanSquaredResidual = sqrtl (meanSquaredResidual);   // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
+				*p_stdev = (real) rootMeanSquaredResidual;
+			}
+			return;
+		}
+		if (Melder_debug == 50) {
+			/*
+				First-element offset corrects for large DC components.
+			*/
+			real80 offset = (real80) x [1];   // x.size != 0 -> offset in R
+			real80 sumOfDifferences = 0.0;   // sumOfDifferences in R (invariant)
+			for (integer i = 2; i <= x.size; i ++) {
+				sumOfDifferences += (real80) x [i] - offset;   // sumOfDifferences before in R, x [i] in R, offset in R -> sumOfDifferences after in R
+			}
+			if (p_sum) {
+				real80 sum = sumOfDifferences + offset * x.size;
+				*p_sum = (real) sum;
+			}
+			real80 mean = offset + sumOfDifferences / x.size;   // offset in R, sumOfDifferences in R, x.size != 0 -> mean in R
+			if (p_mean) *p_mean = (real) mean;
+			if (! p_sumsq && ! p_variance && ! p_stdev) return;
+			real80 sumOfSquaredResiduals = 0.0;   // -> sumOfSquares >= 0.0 (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				real80 residual = (real80) x [i] - mean;   // x [i] in R, mean in R -> residual in R
+				real80 squaredResidual = residual * residual;   // residual in R -> squaredResidual >= 0.0
+				sumOfSquaredResiduals += squaredResidual;   // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
+			}
+			if (p_sumsq) *p_sumsq = (real) sumOfSquaredResiduals;
+			integer degreesOfFreedom = x.size - 1;   // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
+			real80 meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom;   // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
+			if (p_variance) *p_variance = (real) meanSquaredResidual;
+			if (p_stdev) {
+				real80 rootMeanSquaredResidual = sqrtl (meanSquaredResidual);   // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
+				*p_stdev = (real) rootMeanSquaredResidual;
+			}
+			return;
+		}
+		if (Melder_debug == 51) {
+			/*
+				Chan, Golub & LeVeque's pairwise algorithm.
+			*/
+			#define REAL  real80
+			if (! p_sumsq && ! p_variance && ! p_stdev) {
+				//real offset = x [1];
+				const real offset = 0.0;
+				long terms [65];
+				REAL suma [65];
+				terms [1] = 0;
+				int top = 2;
+				long n2 = x.size / 2;
+				for (long i = 1; i <= n2; i ++) {
+					/*
+						Compute the sum of the next two data points.
+						Put this sum on top of the stack.
+					*/
+					long start = 2 * i - 1;
+					suma [top] = (REAL) (x [start] - offset) + REAL (x [start + 1] - offset);
+					terms [top] = 2;
+					while (terms [top] == terms [top - 1]) {
+						top --;
+						terms [top] *= 2;
+						suma [top] += suma [top + 1];
+					}
+					top ++;
+				}
+				top --;
+				if (x.size & 1) {
+					/*
+						x.size is odd. Put the last point on the stack.
+					*/
+					top ++;
+					suma [top] = (REAL) (x [x.size] - offset);
+				}
+				REAL sum = suma [top];
+				/*
+					If the remaining stack contains more than one element, x.size is not a power of 2.
+					Add all the elements.
+				*/
+				for (long i = top - 1; i >= 2; i --) {
+					sum += suma [i];
+				}
+				REAL mean = offset + sum / x.size;
+				if (p_sum) {
+					sum += offset * x.size;
+					*p_sum = (real) sum;
+				}
+				if (p_mean) *p_mean = (real) mean;
+				return;
+			}
+			int64 terms [65];
+			REAL suma [65], sa [65];
+			terms [1] = 0;
+			int top = 2;
+			long n2 = x.size / 2;
+			for (long i = 1; i <= n2; i ++) {
+				suma [top] = x [2*i-1] + x [2*i];
+				REAL diff = x [2*i] - x [2*i-1];
+				sa [top] = diff * diff / 2.0;
+				terms [top] = 2;
+				while (terms [top] == terms [top - 1]) {
+					top --;
+					terms [top] *= 2;
+					diff = suma [top] - suma [top + 1];
+					sa [top] += sa [top + 1] + diff * diff / terms [top];
+					suma [top] += suma [top + 1];
+				}
+				top ++;
+			}
+			top --;
+			if (x.size & 1) {
+				top ++;
+				terms [top] = 1;
+				suma [top] = x [x.size];
+				sa [top] = 0.0;
+			}
+			long t = terms [top];
+			REAL sum = suma [top];
+			REAL sumOfSquaredResiduals = sa [top];
+			for (long i = top - 1; i >= 2; i --) {
+				REAL diff = terms [i] * sum / t - suma [i];
+				sumOfSquaredResiduals += sa [i] + t * diff * diff / terms [i] / (terms [i] + t);
+				sum += suma [i];
+				t += terms [i];
+			}
+			REAL mean = sum / x.size;
+			REAL variance = sumOfSquaredResiduals / (x.size - 1);
+			if (p_sum) *p_sum = (real) sum;
+			if (p_mean) *p_mean = (real) mean;
+			if (p_sumsq) *p_sumsq = (real) sumOfSquaredResiduals;
+			if (p_variance) *p_variance = (real) variance;
+			if (p_stdev) *p_stdev = (real) sqrtl (variance);
+			#undef REAL
+			return;
+		}
+		if (Melder_debug == 52) {
+			/*
+				Pairwise algorithm with base case 8.
+			*/
+			#define REAL  real80
+			//real offset = x [1];
+			const real offset = 0.0;
+			integer numbersOfTerms [1+60];
+			REAL partialSums [1+60];
+			numbersOfTerms [0] = 0;
+			integer stackPointer = 0;
+			integer n8 = x.size / 8, remainder = x.size % 8;
+			#define tensor_TERM(i)  REAL (y [i] - offset)
+			for (integer ipart = 1; ipart <= n8; ipart ++) {
+				/*
+					Compute the sum of the next eight data points.
+					Put this sum on top of the stack.
+				*/
+				real *y = & x [8 * (ipart - 1)];
+				partialSums [++ stackPointer] = tensor_ADD_8 (0);
+				numbersOfTerms [stackPointer] = 8;
+				while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+					numbersOfTerms [-- stackPointer] *= 2;
+					partialSums [stackPointer] += partialSums [stackPointer + 1];
+				}
+			}
+			REAL sum = 0.0;
+			if (remainder != 0) {
+				real *y = & x [x.size - remainder];
+				tensor_ADD_casesUpTo7 (remainder, sum)
+			}
+			#undef tensor_TERM
+			/*
+				Add all the elements of the stack.
+			*/
+			for (integer i = stackPointer; i > 0; i --) {
+				sum += partialSums [i];
+			}
+			REAL mean = offset + sum / x.size;
+			if (p_sum) {
+				sum += offset * x.size;
+				*p_sum = (real) sum;
+			}
+			real mean64 = (real) mean;
+			if (p_mean) *p_mean = mean64;
+			if (! p_sumsq && ! p_variance && ! p_stdev) {
+				return;
+			}
+			stackPointer = 0;
+			#define tensor_TERM(i)  REAL (y [i] - mean64) * REAL (y [i] - mean64)
+			for (integer ipart = 1; ipart <= n8; ipart ++) {
+				real *y = & x [8 * (ipart - 1)];
+				partialSums [++ stackPointer] = tensor_ADD_8 (0);
+				numbersOfTerms [stackPointer] = 16;
+				while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+					numbersOfTerms [-- stackPointer] *= 2;
+					partialSums [stackPointer] += partialSums [stackPointer + 1];
+				}
+			}
+			REAL sumsq = 0.0;
+			if (remainder != 0) {
+				real *y = & x [x.size - remainder];
+				tensor_ADD_casesUpTo7 (remainder, sumsq)
+			}
+			#undef tensor_TERM
+			for (integer i = stackPointer; i > 0; i --) {
+				sumsq += partialSums [i];
+			}
+			real variance = (real) sumsq / (x.size - 1);
+			if (p_sumsq) *p_sumsq = (real) sumsq;
+			if (p_variance) *p_variance = variance;
+			if (p_stdev) *p_stdev = sqrt (variance);
+			#undef REAL
+			return;
+		}
+		if (Melder_debug == 53) {
+			real mean;
+			sum_mean_scalar (x, p_sum, & mean);   // compute the sum only if the user asks for it, but the mean always, because we need it here
+			if (p_mean) *p_mean = mean;
+			if (! p_sumsq && ! p_variance && ! p_stdev) {
+				return;
+			}
+			constexpr integer baseCasePower = 4;
+			constexpr integer baseCaseSize = 1 << baseCasePower;
+			integer remainder = x.size % baseCaseSize;
+			real80 sumsq;
+			real *y = x.at;
+			#define tensor_TERM(i)  real80 (y [i] - mean) * real80 (y [i] - mean)
+			tensor_ADD_casesUpTo15 (remainder, sumsq)
+			integer numberOfBaseCases = x.size / baseCaseSize;
+			if (numberOfBaseCases != 0) {
+				constexpr integer highestIndex = 63 - baseCasePower;
+				integer numbersOfTerms [1 + highestIndex];
+				real80 partialSums [1 + highestIndex];
+				numbersOfTerms [0] = 0;
+				integer stackPointer = 0;
+				y += remainder;
+				for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+					partialSums [++ stackPointer] = tensor_ADD_16 (0);
+					numbersOfTerms [stackPointer] = baseCaseSize;
+					while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+						numbersOfTerms [-- stackPointer] *= 2;
+						partialSums [stackPointer] += partialSums [stackPointer + 1];
+					}
+					y += baseCaseSize;
+				}
+				for (integer i = stackPointer; i > 0; i --) {
+					sumsq += partialSums [i];
+				}
+			}
+			#undef tensor_TERM
+			real variance = (real) sumsq / (x.size - 1);
+			if (p_sumsq) *p_sumsq = (real) sumsq;
+			if (p_variance) *p_variance = variance;
+			if (p_stdev) *p_stdev = sqrt (variance);
+			return;
+		}
+		if (Melder_debug == 54) {
+			real sum, mean;
+			sum_mean_scalar (x, & sum, & mean);
+			if (p_sum) *p_sum = sum;
+			if (p_mean) *p_mean = mean;
+			if (! p_sumsq && ! p_variance && ! p_stdev) return;
+			real sumOfSquaredResiduals = 0.0;   // -> sumOfSquares >= 0.0 (invariant)
+			for (integer i = 1; i <= x.size; i ++) {
+				real residual = x [i] - mean;   // x [i] in R, mean in R -> residual in R
+				real squaredResidual = residual * residual;   // residual in R -> squaredResidual >= 0.0
+				sumOfSquaredResiduals += squaredResidual;   // sumOfSquaredResiduals before >= 0.0, squaredResidual >= 0.0 -> sumOfSquaredResiduals after >= 0.0
+			}
+			if (p_sumsq) *p_sumsq = sumOfSquaredResiduals;
+			integer degreesOfFreedom = x.size - 1;   // x.size >= 2 -> degreesOfFreedom >= 1 -> degreesOfFreedom > 0
+			real meanSquaredResidual = sumOfSquaredResiduals / degreesOfFreedom;   // sumOfSquaredResiduals >= 0.0, degreesOfFreedom > 0 -> meanSquaredResidual >= 0.0
+			if (p_variance) *p_variance = (real) meanSquaredResidual;
+			if (p_stdev) {
+				real rootMeanSquaredResidual = sqrt (meanSquaredResidual);   // meanSquaredResidual >= 0.0 -> rootMeanSquaredResidual >= 0.0 (in particular, not NaN)
+				*p_stdev = rootMeanSquaredResidual;
+			}
+			return;
+		}
+		if (Melder_debug == 55) {
+			real mean;
+			sum_mean_scalar (x, p_sum, & mean);   // compute the sum only if the user asks for it, but the mean always, because we need it here
+			if (p_mean) *p_mean = mean;
+			if (! p_sumsq && ! p_variance && ! p_stdev) {
+				return;
+			}
+			constexpr integer baseCasePower = 5;
+			constexpr integer baseCaseSize = 1 << baseCasePower;
+			integer remainder = x.size % baseCaseSize;
+			real80 sumsq;
+			real *y = x.at;
+			#define tensor_TERM(i)  real80 (y [i] - mean) * real80 (y [i] - mean)
+			tensor_ADD_casesUpTo31 (remainder, sumsq)
+			integer numberOfBaseCases = x.size / baseCaseSize;
+			if (numberOfBaseCases != 0) {
+				constexpr integer highestIndex = 63 - baseCasePower;
+				integer numbersOfTerms [1 + highestIndex];
+				real80 partialSums [1 + highestIndex];
+				numbersOfTerms [0] = 0;
+				integer stackPointer = 0;
+				y += remainder;
+				for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+					partialSums [++ stackPointer] = tensor_ADD_32 (0);
+					numbersOfTerms [stackPointer] = baseCaseSize;
+					while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+						numbersOfTerms [-- stackPointer] *= 2;
+						partialSums [stackPointer] += partialSums [stackPointer + 1];
+					}
+					y += baseCaseSize;
+				}
+				for (integer i = stackPointer; i > 0; i --) {
+					sumsq += partialSums [i];
+				}
+			}
+			#undef tensor_TERM
+			real variance = (real) sumsq / (x.size - 1);
+			if (p_sumsq) *p_sumsq = (real) sumsq;
+			if (p_variance) *p_variance = variance;
+			if (p_stdev) *p_stdev = sqrt (variance);
+			return;
+		}
+	} else {
+		/*
+			Our standard: pairwise algorithm with base case 64.
+		*/
+		real mean;
+		sum_mean_scalar (x, p_sum, & mean);   // compute the sum only if the user asks for it, but the mean always, because we need it here
+		if (p_mean) *p_mean = mean;
+		if (! p_sumsq && ! p_variance && ! p_stdev) {
+			return;
+		}
+		constexpr integer baseCasePower = 6;
+		constexpr integer baseCaseSize = 1 << baseCasePower;
+		integer numberOfBaseCases = x.size / baseCaseSize, remainder = x.size % baseCaseSize;
+		real80 sumsq;
+		real *y = x.at;
+		#define tensor_TERM(i)  real80 (y [i] - mean) * real80 (y [i] - mean)
+		tensor_ADD_casesUpTo63 (remainder, sumsq)
+		if (numberOfBaseCases != 0) {
+			constexpr integer highestIndex = 63 - baseCasePower;
+			integer numbersOfTerms [1 + highestIndex];
+			real80 partialSums [1 + highestIndex];
+			numbersOfTerms [0] = 0;
+			integer stackPointer = 0;
+			y += remainder;
+			for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+				partialSums [++ stackPointer] = tensor_ADD_64 (0);
+				numbersOfTerms [stackPointer] = baseCaseSize;
+				while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+					numbersOfTerms [-- stackPointer] *= 2;
+					partialSums [stackPointer] += partialSums [stackPointer + 1];
+				}
+				y += baseCaseSize;
+			}
+			for (integer i = stackPointer; i > 0; i --) {
+				sumsq += partialSums [i];
+			}
+		}
+		#undef tensor_TERM
+		real variance = (real) sumsq / (x.size - 1);
+		if (p_sumsq) *p_sumsq = (real) sumsq;
+		if (p_variance) *p_variance = variance;
+		if (p_stdev) *p_stdev = sqrt (variance);
+	}
+}
+
+real sumsq_scalar (numvec x) noexcept {
+	real sumsq;
+	sum_mean_sumsq_variance_stdev_scalar (x, nullptr, nullptr, & sumsq, nullptr, nullptr);
+	return sumsq;
+}
+
+real variance_scalar (numvec x) noexcept {
+	real variance;
+	sum_mean_sumsq_variance_stdev_scalar (x, nullptr, nullptr, nullptr, & variance, nullptr);
+	return variance;
+}
+
+real stdev_scalar (numvec x) noexcept {
+	real stdev;
+	sum_mean_sumsq_variance_stdev_scalar (x, nullptr, nullptr, nullptr, nullptr, & stdev);
+	return stdev;
+}
+
+double center_scalar (numvec x) noexcept {
+	double weightedSumOfIndexes = 0.0, sumOfWeights = 0.0;
+	for (integer i = 1; i <= x.size; i ++) {
+		weightedSumOfIndexes += i * x [i];
+		sumOfWeights += x [i];
+	}
+	return weightedSumOfIndexes / sumOfWeights;
+}
+
+real _inner_scalar (numvec x, numvec y) {
+	if (x.size != y.size) return undefined;
+	constexpr integer baseCasePower = 6;
+	constexpr integer baseCaseSize = 1 << baseCasePower;
+	integer numberOfBaseCases = x.size / baseCaseSize, remainder = x.size % baseCaseSize;
+	real80 sum;
+	real *xx = x.at, *yy = y.at;
+	#define tensor_TERM(i)  ((real80) xx [i] * (real80) yy [i])
+	//#define tensor_TERM(i)  xx [i] * yy [i]
+	tensor_ADD_casesUpTo63 (remainder, sum)
+	if (numberOfBaseCases != 0) {
+		constexpr integer highestIndex = 63 - baseCasePower;
+		integer numbersOfTerms [1 + highestIndex];
+		real80 partialSums [1 + highestIndex];
+		numbersOfTerms [0] = 0;
+		integer stackPointer = 0;
+		xx += remainder;
+		yy += remainder;
+		for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+			partialSums [++ stackPointer] = tensor_ADD_64 (0);
+			numbersOfTerms [stackPointer] = baseCaseSize;
+			while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+				numbersOfTerms [-- stackPointer] *= 2;
+				partialSums [stackPointer] += partialSums [stackPointer + 1];
+			}
+			xx += baseCaseSize;
+			yy += baseCaseSize;
+		}
+		for (integer i = stackPointer; i > 0; i --) {
+			sum += partialSums [i];
+		}
+	}
+	#undef tensor_TERM
+	return (real) sum;
+}
+
+real norm_scalar (numvec x, real power) noexcept {
+	if (power < 0.0) return undefined;
+	constexpr integer baseCasePower = 5;
+	constexpr integer baseCaseSize = 1 << baseCasePower;
+	integer numberOfBaseCases = x.size / baseCaseSize, remainder = x.size % baseCaseSize;
+	real80 sum;
+	real *y = x.at;
+	if (power == 2.0) {
+		#define tensor_TERM(i)  ((real80) y [i] * (real80) y [i])
+		tensor_ADD_casesUpTo31 (remainder, sum)
+		if (numberOfBaseCases != 0) {
+			constexpr integer highestIndex = 63 - baseCasePower;
+			integer numbersOfTerms [1 + highestIndex];
+			real80 partialSums [1 + highestIndex];
+			numbersOfTerms [0] = 0;
+			integer stackPointer = 0;
+			y += remainder;
+			for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+				partialSums [++ stackPointer] = tensor_ADD_32 (0);
+				numbersOfTerms [stackPointer] = baseCaseSize;
+				while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+					numbersOfTerms [-- stackPointer] *= 2;
+					partialSums [stackPointer] += partialSums [stackPointer + 1];
+				}
+				y += baseCaseSize;
+			}
+			for (integer i = stackPointer; i > 0; i --) {
+				sum += partialSums [i];
+			}
+		}
+		#undef tensor_TERM
+		return sqrt ((real) sum);
+	} else if (power == 1.0) {
+		#define tensor_TERM(i)  (real80) fabs (y [i])
+		tensor_ADD_casesUpTo31 (remainder, sum)
+		if (numberOfBaseCases != 0) {
+			constexpr integer highestIndex = 63 - baseCasePower;
+			integer numbersOfTerms [1 + highestIndex];
+			real80 partialSums [1 + highestIndex];
+			numbersOfTerms [0] = 0;
+			integer stackPointer = 0;
+			y += remainder;
+			for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+				partialSums [++ stackPointer] = tensor_ADD_32 (0);
+				numbersOfTerms [stackPointer] = baseCaseSize;
+				while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+					numbersOfTerms [-- stackPointer] *= 2;
+					partialSums [stackPointer] += partialSums [stackPointer + 1];
+				}
+				y += baseCaseSize;
+			}
+			for (integer i = stackPointer; i > 0; i --) {
+				sum += partialSums [i];
+			}
+		}
+		#undef tensor_TERM
+		return (real) sum;
+	} else {
+		#define tensor_TERM(i)  powl ((real80) fabs (y [i]), power)
+		tensor_ADD_casesUpTo31 (remainder, sum)
+		if (numberOfBaseCases != 0) {
+			constexpr integer highestIndex = 63 - baseCasePower;
+			integer numbersOfTerms [1 + highestIndex];
+			real80 partialSums [1 + highestIndex];
+			numbersOfTerms [0] = 0;
+			integer stackPointer = 0;
+			y += remainder;
+			for (integer ipart = 1; ipart <= numberOfBaseCases; ipart ++) {
+				partialSums [++ stackPointer] = tensor_ADD_32 (0);
+				numbersOfTerms [stackPointer] = baseCaseSize;
+				while (numbersOfTerms [stackPointer] == numbersOfTerms [stackPointer - 1]) {
+					numbersOfTerms [-- stackPointer] *= 2;
+					partialSums [stackPointer] += partialSums [stackPointer + 1];
+				}
+				y += baseCaseSize;
+			}
+			for (integer i = stackPointer; i > 0; i --) {
+				sum += partialSums [i];
+			}
+		}
+		#undef tensor_TERM
+		return (real) powl (sum, (real80) 1.0 / power);
+	}
+}
+
+autonumvec copy_numvec (numvec x) {
+	autonumvec result (x.size, false);
+	for (integer i = 1; i <= x.size; i ++) {
+		result [i] = x [i];
+	}
+	return result;
+}
+
+autonummat copy_nummat (nummat x) {
+	autonummat result (x.nrow, x.ncol, false);
+	for (integer irow = 1; irow <= x.nrow; irow ++) {
+		for (integer icol = 1; icol <= x.ncol; icol ++) {
+			result [irow] [icol] = x [irow] [icol];
+		}
+	}
+	return result;
+}
+
+autonummat outer_nummat (numvec x, numvec y) {
+	autonummat result (x.size, y.size, false);
+	for (integer irow = 1; irow <= x.size; irow ++) {
+		for (integer icol = 1; icol <= y.size; icol ++) {
+			result [irow] [icol] = x [irow] * y [icol];
+		}
+	}
+	return result;
+}
+
+autonummat peaks_nummat (numvec x, bool includeEdges, int interpolate, bool sortByHeight) {
+	if (x.size < 2) {
+		includeEdges = false;
+	}
+	integer numberOfPeaks = 0;
+	for (integer i = 2; i < x.size; i ++) {
+		if (x [i] > x [i - 1] && x [i] >= x [i + 1]) {
+			numberOfPeaks ++;
+		}
+	}
+	if (includeEdges) {
+		if (x [1] > x [2]) numberOfPeaks ++;
+		if (x [x.size] > x [x.size - 1]) numberOfPeaks ++;
+	}
+	autonummat result (2, numberOfPeaks, false);
+	integer peakNumber = 0;
+	if (includeEdges && x [1] > x [2]) {
+		result [1] [++ peakNumber] = 1;
+		result [2] [peakNumber] = x [1];
+	}
+	for (integer i = 2; i < x.size; i ++) {
+		if (x [i] > x [i - 1] && x [i] >= x [i + 1]) {
+			++ peakNumber;
+			if (interpolate != 0) {   // this is not a boolean; there could follow more options
+				/*
+					Parabolic interpolation.
+				*/
+				real dy = 0.5 * (x [i + 1] - x [i - 1]);
+				real d2y = (x [i] - x [i - 1]) + (x [i] - x [i + 1]);
+				Melder_assert (d2y > 0.0);
+				result [1] [peakNumber] = (real) i + dy / d2y;
+				result [2] [peakNumber] = x [i] + 0.5 * dy * (dy / d2y);
+			} else {
+				/*
+					Don't interpolate: choose the nearest index.
+				*/
+				result [1] [peakNumber] = i;
+				result [2] [peakNumber] = x [i];
+			}
+		}
+	}
+	if (includeEdges && x [x.size] > x [x.size - 1]) {
+		result [1] [++ peakNumber] = x.size;
+		result [2] [peakNumber] = x [x.size];
+	}
+	Melder_assert (peakNumber == numberOfPeaks);
+	if (sortByHeight) {
+		for (integer i = 1; i <= numberOfPeaks; i ++)
+			result [2] [i] *= -1.0;
+		NUMsort2 (result.ncol, result [2], result [1]);
+		for (integer i = 1; i <= numberOfPeaks; i ++)
+			result [2] [i] *= -1.0;
+	}
+	return result;
+}
+
+/* End of file tensor.cpp */
diff --git a/sys/tensor.h b/sys/tensor.h
new file mode 100644
index 0000000..d94aabb
--- /dev/null
+++ b/sys/tensor.h
@@ -0,0 +1,142 @@
+#ifndef _tensor_h_
+#define _tensor_h_
+/* tensor.h
+ *
+ * Copyright (C) 2017 Paul Boersma
+ *
+ * This code 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.
+ *
+ * This code is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this work. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "melder.h"
+#include <math.h>
+
+inline static double sqrt_scalar (double x) {
+	#if defined (_WIN32)
+		if (x < 0.0) return undefined;
+	#endif
+	return sqrt (x);
+}
+
+void sum_mean_scalar (numvec x, real *p_sum, real *p_mean) noexcept;
+void sum_mean_sumsq_variance_stdev_scalar (numvec x, real *p_sum, real *p_mean, real *p_sumsq, real *p_variance, real *p_stdev) noexcept;
+
+inline static real sum_scalar (numvec x) noexcept {
+	integer n = x.size;
+	if (n <= 8) {
+		if (n <= 2) return n <= 0 ? 0.0 : n == 1 ? x [1] : x [1] + x [2];
+		if (n <= 4) return n == 3 ?
+			(real) ((real80) x [1] + (real80) x [2] + (real80) x [3]) :
+			(real) (((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4]));
+		if (n <= 6) return n == 5 ?
+			(real) (((real80) x [1] + (real80) x [2] + (real80) x [3]) + ((real80) x [4] + (real80) x [5])) :
+			(real) (((real80) x [1] + (real80) x [2] + (real80) x [3]) + ((real80) x [4] + (real80) x [5] + (real80) x [6]));
+		return n == 7 ?
+			(real) ((((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4])) + ((real80) x [5] + (real80) x [6] + (real80) x [7])) :
+			(real) ((((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4])) + (((real80) x [5] + (real80) x [6]) + ((real80) x [7] + (real80) x [8])));
+	}
+	real sum;
+	sum_mean_scalar (x, & sum, nullptr);
+	return sum;
+}
+
+inline static real mean_scalar (numvec x) noexcept {
+	integer n = x.size;
+	if (n <= 8) {
+		if (n <= 2) return n <= 0 ? undefined : n == 1 ? x [1] : (real) (0.5 * ((real80) x [1] + (real80) x [2]));
+		if (n <= 4) return n == 3 ?
+			(real) ((1.0 / (real80) 3.0) * ((real80) x [1] + (real80) x [2] + (real80) x [3])) :
+			(real) (0.25 * (((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4])));
+		if (n <= 6) return n == 5 ?
+			(real) ((1.0 / (real80) 5.0) * (((real80) x [1] + (real80) x [2] + (real80) x [3]) + ((real80) x [4] + (real80) x [5]))) :
+			(real) ((1.0 / (real80) 6.0) * (((real80) x [1] + (real80) x [2] + (real80) x [3]) + ((real80) x [4] + (real80) x [5] + (real80) x [6])));
+		return n == 7 ?
+			(real) ((1.0 / (real80) 7.0) * ((((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4])) + ((real80) x [5] + (real80) x [6] + (real80) x [7]))) :
+			(real) (0.125 * ((((real80) x [1] + (real80) x [2]) + ((real80) x [3] + (real80) x [4])) + (((real80) x [5] + (real80) x [6]) + ((real80) x [7] + (real80) x [8]))));
+	}
+	real mean;
+	sum_mean_scalar (x, nullptr, & mean);
+	return mean;
+}
+
+real sumsq_scalar (numvec x) noexcept;
+real variance_scalar (numvec x) noexcept;
+real stdev_scalar (numvec x) noexcept;
+real norm_scalar (numvec x, real power) noexcept;
+real center_scalar (numvec x) noexcept;
+
+real _inner_scalar (numvec x, numvec y);
+inline static real inner_scalar (numvec x, numvec y) {
+	integer n = x.size;
+	if (y.size != n) return undefined;
+	if (n <= 8) {
+		if (n <= 2) return n <= 0 ? 0.0 : n == 1 ? x [1] * y [1] : (real) ((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2]);
+		if (n <= 4) return n == 3 ?
+			(real) ((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2] + (real80) x [3] * (real80) y [3]) :
+			(real) (((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2]) + ((real80) x [3] * (real80) y [3] + (real80) x [4] * (real80) y [4]));
+		if (n <= 6) return n == 5 ?
+			(real) (((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2] + (real80) x [3] * (real80) y [3]) + ((real80) x [4] * (real80) y [4] + (real80) x [5] * (real80) y [5])) :
+			(real) (((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2] + (real80) x [3] * (real80) y [3]) + ((real80) x [4] * (real80) y [4] + (real80) x [5] * (real80) y [5] + (real80) x [6] * (real80) y [6]));
+		return n == 7 ?
+			(real) ((((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2]) + ((real80) x [3] * (real80) y [3] + (real80) x [4] * (real80) y [4])) + ((real80) x [5] * (real80) y [5] + (real80) x [6] * (real80) y [6] + (real80) x [7] * (real80) y [7])) :
+			(real) ((((real80) x [1] * (real80) y [1] + (real80) x [2] * (real80) y [2]) + ((real80) x [3] * (real80) y [3] + (real80) x [4] * (real80) y [4])) + (((real80) x [5] * (real80) y [5] + (real80) x [6] * (real80) y [6]) + ((real80) x [7] * (real80) y [7] + (real80) x [8] * (real80) y [8])));
+	}
+	return _inner_scalar (x, y);
+}
+
+autonumvec copy_numvec (numvec x);
+
+inline static bool equal_numvec (numvec x, numvec y) {
+	integer n = x.size;
+	if (y.size != n) return false;
+	for (integer i = 1; i <= x.size; i ++) {
+		if (x [i] != y [i]) {
+			return false;
+		}
+	}
+	return true;
+}
+
+inline static autonumvec add_numvec (numvec x, numvec y) {
+	if (x.size != y.size) return autonumvec { nullptr, 0 };
+	autonumvec result (x.size, false);
+	for (integer i = 1; i <= x.size; i ++) {
+		result [i] = x [i] + y [i];
+	}
+	return result;
+}
+inline static autonumvec sub_numvec (numvec x, numvec y) {
+	if (x.size != y.size) return autonumvec { nullptr, 0 };
+	autonumvec result (x.size, false);
+	for (integer i = 1; i <= x.size; i ++) {
+		result [i] = x [i] - y [i];
+	}
+	return result;
+}
+
+autonummat copy_nummat (nummat x);
+
+inline static numvec as_numvec (nummat x) {
+	return numvec (x.nrow * x.ncol, x [1]);
+}
+
+inline static real norm_scalar (nummat x, real power) noexcept {
+	return norm_scalar (as_numvec (x), power);
+}
+
+autonummat outer_nummat (numvec x, numvec y);
+
+autonummat peaks_nummat (numvec x, bool includeEdges, int interpolate, bool sortByHeight);
+
+/* End of file tensor.h */
+#endif
diff --git a/test/num/fisherQ.praat b/test/num/fisherQ.praat
index ec596bf..8d02e34 100644
--- a/test/num/fisherQ.praat
+++ b/test/num/fisherQ.praat
@@ -88,9 +88,9 @@ assert fisherQ (1, 1e19, 1e19) = undefined
 #
 Debug... no 29   ; set invFisherQ to GSL
 f = invFisherQ (0.01, 1, 10000)   ; not such an unusual case
-assert "'f'" = "nan" or "'f'" = "NaN" or index ("'f'", "NAN") or "'f:5'" = "6.63743"
-Debug... no 0   ; use our corrected NUMridders again
-f = invFisherQ (0.01, 1, 10000)   ; same case
+Debug... no 0   ; quickly (i.e. before the assert!) undo the debug-29 option
+assert "'f'" = "--undefined--" or "'f:5'" = "6.63743"
+f = invFisherQ (0.01, 1, 10000)   ; same case, but using our corrected NUMridders again
 assert "'f:5'" = "6.63743"
 #
 printline OK
diff --git a/test/num/inner.praat b/test/num/inner.praat
new file mode 100644
index 0000000..3860e4f
--- /dev/null
+++ b/test/num/inner.praat
@@ -0,0 +1,22 @@
+writeInfoLine: "inner..."
+
+assert inner(linear#(1,100,100,0),linear#(1,100,100,0)) = 338350
+assert inner(linear#(1,100,100,0),1000000+linear#(1,100,100,0)) = 5050338350
+
+for size from 1 to 100
+	x# = linear# (1, size, size, 0)
+	y# = 1000000 + x#
+	assert inner (x#, y#) = sumOver (i to size, x# [i] * y# [i])   ; 'i'
+endfor
+
+durations# = zero# (100)
+for n from 1 to 100
+	result$ = Praat test: "TimeInner", string$ (10^8 / n), string$ (n), "", ""
+	durations# [n] = extractNumber (result$, newline$)
+	appendInfoLine (n, " ", durations# [n])
+endfor
+
+appendInfoLine: "mean ", mean (durations#), " nanoseconds"
+
+;for n to 1000
+appendInfoLine: "OK"
diff --git a/test/num/mean.R b/test/num/mean.R
new file mode 100644
index 0000000..b636490
--- /dev/null
+++ b/test/num/mean.R
@@ -0,0 +1,44 @@
+n = 1e5+1
+n7 = 7 * n
+d = 0
+d = 0.23456
+#d = 0.000547462463
+big0 = 1 + d
+sequenceA = seq (1, 7)
+meanA = mean (sequenceA)
+stdevA = sd (sequenceA) * sqrt (6 / 7) / sqrt (1 - 1 / 7 / n)
+sequenceB = seq (1, n)
+meanB = mean (sequenceB)
+stdevB = sd (sequenceB)
+big = big0
+for (power in seq (1, 25)) {
+	big = big * 10
+	a = rep (big + sequenceA, n)
+	b = big + sequenceB
+	cat (power, mean (a) - big - meanA, sd (a) - stdevA, mean (b) - big - meanB, sd (b) - stdevB, '\n')
+}
+
+numberOfTrials = 100
+t = system.time (for (i in 1:numberOfTrials) mean (a))
+cat ('mean:', t[1] / numberOfTrials / n * 1e9 / 7, 'ns per element\n')
+t = system.time (for (i in 1:numberOfTrials) sd (a))
+cat ('stdev:', t[1] / numberOfTrials / n * 1e9 / 7, 'ns per element\n')
+
+a = rnorm (7 * n, 0, 1)
+t = system.time (for (i in 1:numberOfTrials) mean (a))
+cat ('mean:', t[1] / numberOfTrials / n * 1e9 / 7, 'ns per element\n')
+t = system.time (for (i in 1:numberOfTrials) sd (a))
+cat ('stdev:', t[1] / numberOfTrials / n * 1e9 / 7, 'ns per element\n')
+
+#d = 1.23456
+do_single_peak = function (peakLocation, zeroLocation) {
+	a = d + rep (1e13+1e5, 1e6 + 2)
+	a [peakLocation] = d + (-1e19-1e11)
+	a [zeroLocation] = d
+	cat (mean (a) - d, mean (a) + mean (- mean (a) + a) - d, '\n')
+}
+do_single_peak (1, 2)
+do_single_peak (2, 1)
+do_single_peak (2, 3)
+do_single_peak (1e6+1, 1e6+2)
+do_single_peak (1e6+2, 1e6+1)
diff --git a/test/num/mean.praat b/test/num/mean.praat
new file mode 100644
index 0000000..6460324
--- /dev/null
+++ b/test/num/mean.praat
@@ -0,0 +1,157 @@
+writeInfoLine: "Mean..."
+
+durations# = zero# (100)
+for n from 1 to 100
+	result$ = Praat test: "TimeMean", string$ (10^8 / n), string$ (n), "", ""
+	durations# [n] = extractNumber (result$, newline$)
+	appendInfoLine (n, " ", durations# [n])
+endfor
+
+appendInfoLine: "mean ", mean (durations#), " nanoseconds"
+
+n = 1e5+1
+n7 = 7 * n
+d = 0
+d = 0.23456
+;d = 0.000547462463
+big0 = 1 + d 
+sequenceA# = { 1, 2, 3, 4, 5, 6, 7 }
+meanA = mean (sequenceA#)
+stdevA = stdev (sequenceA#) * sqrt (6 / 7) / sqrt (1 - 1 / n7)
+sequenceB# = linear# (1, n, n, 0)
+meanB = mean (sequenceB#)
+stdevB = stdev (sequenceB#)
+sequenceC# = { 0 }
+meanC = 0.0
+stdevC = 0.0
+Debug: "no", 48   ; naive mean
+big = big0
+for power from 1 to 25
+	big *= 10
+	a# = repeat# (big + sequenceA#, n)
+	mean1 = mean (a#)
+	dmean1 = mean1 - big - meanA
+	mean2 = a# [1] + mean (- a# [1] + a#)
+	dmean2 = mean2 - big - meanA
+	assert big <> round (big) or dmean2 = 0 or power > 18 - log10 (n)
+	mean3 = mean (a#) + mean (- mean1 + a#)
+	dmean3 = mean3 - big - meanA
+	assert big <> round (big) or dmean3 = 0 or power > 18 - log10 (n)
+	diffSquare1# = (a# - mean1) * (a# - mean1)
+	meanSquare1 = mean (diffSquare1#)
+	diffSquare2# = (a# - mean2) * (a# - mean2)
+	meanSquare2 = mean (diffSquare2#)
+	diffSquare3# = (a# - mean3) * (a# - mean3)
+	meanSquare3 = mean (diffSquare3#)
+	;mean2q = mean2 + mean (- mean2 + diff2#)
+	stdev1 = sqrt (meanSquare1 * n7 / (n7 - 1))
+	stdev2 = sqrt (meanSquare2 * n7 / (n7 - 1))
+	stdev3 = sqrt (meanSquare3 * n7 / (n7 - 1))
+	appendInfoLine: power, " mean: ", dmean1, " ", dmean2, " ", dmean3, " ; stdev: ", stdev1 - stdevA, " ", stdev2 - stdevA, " ", stdev3 - stdevA
+endfor
+Debug: "no", 0
+
+debug# = { 48, 49, 50, 51, 52, 53, 54, 55, 0 }
+debug$ [1] = "Naive 64-bits"
+debug$ [2] = "Naive 80-bits"
+debug$ [3] = "First-element offset"
+debug$ [4] = "Chan pairwise"
+debug$ [5] = "Pairwise base case 8"
+debug$ [6] = "Pairwise base case 16"
+debug$ [7] = "Two-loop"
+debug$ [8] = "Pairwise base case 32"
+debug$ [9] = "Pairwise base case 64"
+
+appendInfoLine: newline$, "OFFSET"
+for idebug from 1 to size (debug#)
+	appendInfoLine: newline$, debug$ [idebug]
+	Debug: "no", debug# [idebug]
+	big = big0
+	for power from 1 to 25
+		big *= 10
+		a# = repeat# (big + sequenceA#, n)
+		b# = big + sequenceB#
+		c# = repeat# (big + sequenceC#, n7)
+		appendInfoLine: "Power ", power, ". Sawtooth: mean ", mean (a#) - big - meanA, ", stdev ", stdev (a#) - stdevA,
+		... ". Line: mean ", mean (b#) - big - meanB, ", stdev ", stdev (b#) - stdevB,
+		... ". Constant: mean ", mean (c#) - big - meanC, ", stdev ", stdev (c#) - stdevC
+	endfor
+	Debug: "no", 0
+endfor
+
+assert mean ({ -1e18, 3, 1e18 }) = 1
+assert mean ({ -1e19, 3, 1e19 }) = 1
+;assert mean ({ -1e20, 3, 1e20 }) = 1
+
+for power from 1 to 16
+	assert (mean (repeat# (10^power + sequenceA#, n)) - 10^power = mean (sequenceA#))
+endfor
+
+appendInfoLine: newline$, "TIMING"
+numberOfTrials = 100
+stopwatch
+for i to numberOfTrials
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+	b# = a#
+endfor
+appendInfoLine: "Baseline: ", stopwatch / numberOfTrials / n7 * 1e9 / 10, " ns"
+for idebug from 1 to size (debug#)
+	Debug: "no", debug# [idebug]
+	stopwatch
+	for i to numberOfTrials
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+		mean: a#
+	endfor
+	appendInfoLine: debug$ [idebug], " mean: ", stopwatch / numberOfTrials / n7 * 1e9 / 10, " ns"
+endfor
+for idebug from 1 to size (debug#)
+	Debug: "no", debug# [idebug]
+	stopwatch
+	for i to numberOfTrials
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+		stdev: a#
+	endfor
+	appendInfoLine: debug$ [idebug], " stdev: ", stopwatch / numberOfTrials / n7 * 1e9 / 10, " ns"
+endfor
+
+appendInfoLine: newline$, "ONE PEAK"
+procedure do_single_peak: peakLocation, zeroLocation
+	a# = d + repeat# ({ 1e13+1e5 }, 1e6 + 2)
+	a# [peakLocation] = d + (-1e19-1e11)
+	a# [zeroLocation] = d
+	appendInfoLine: debug$ [idebug], ": ", mean (a#) - d, " ", mean (a#) + mean (a# - mean (a#)) - d
+endproc
+for idebug from 1 to size (debug#)
+	Debug: "no", debug# [idebug]
+	@do_single_peak: 1, 2
+	@do_single_peak: 2, 1
+	@do_single_peak: 2, 3
+	@do_single_peak: 1e6+2, 1e6+1
+	@do_single_peak: 1e6+1, 1e6+2
+endfor
+
+appendInfoLine: newline$, "OK"
\ No newline at end of file
diff --git a/test/num/stdev.praat b/test/num/stdev.praat
new file mode 100644
index 0000000..ddfe1e9
--- /dev/null
+++ b/test/num/stdev.praat
@@ -0,0 +1,20 @@
+a# = zero# (1000000)
+writeInfoLine: stdev (randomGauss# (a#, 0, 1))
+
+for power from 1 to 18
+	a# = 10 ^ power - randomUniform (0, 1) +
+	... { 14.34629189464373, 7.23754354546, 13.645326754, 16.45342671345 }
+	appendInfoLine: power, " ", stdev (a#)
+endfor
+
+for power from 1 to 18
+	a# = randomGauss# (a#, 1, 10 ^ - power)
+	stdev1 = stdev (a#)
+	Debug: "no", 48
+	stdev2 = stdev (a#)
+	Debug: "no", 49
+	stdev3 = stdev (a#)
+	Debug: "no", 0
+	appendInfoLine: stdev1, " ", stdev2, " ", stdev3
+	appendInfoLine: "... ", abs (stdev2 - stdev1), " ", abs (stdev3 - stdev1)
+endfor
diff --git a/test/num/sum.praat b/test/num/sum.praat
new file mode 100644
index 0000000..d0c3011
--- /dev/null
+++ b/test/num/sum.praat
@@ -0,0 +1,22 @@
+writeInfoLine: "sum..."
+
+for i from 2 to 100
+	assert sum (linear# (1, i, i, 0)) = sum (linear# (1, i - 1, i - 1, 0)) + i   ; 'i'
+endfor
+
+for i from 1 to 10
+	appendInfoLine: sum (linear# (1, i, i, 0)), " ", mean (linear# (1, i, i, 0))
+	assert sum (linear# (1, i, i, 0)) = i * mean (linear# (1, i, i, 0))   ; 'i'
+endfor
+
+durations# = zero# (100)
+for n from 1 to 100
+	result$ = Praat test: "TimeSum", string$ (10^8 / n), string$ (n), "", ""
+	durations# [n] = extractNumber (result$, newline$)
+	appendInfoLine (n, " ", durations# [n])
+endfor
+
+appendInfoLine: "mean ", mean (durations#), " nanoseconds"
+
+;for n to 1000
+appendInfoLine: "OK"
diff --git a/test/script/arrays.praat b/test/script/arrays.praat
deleted file mode 100644
index 35c4fd1..0000000
--- a/test/script/arrays.praat
+++ /dev/null
@@ -1,67 +0,0 @@
-writeInfoLine: "vectors and matrices..."
-
-a# = zero#(16)
-a#[3] = 4
-assert a#[3] = 4
-
-asserterror Vector b# does not exist.
-b# [5] = 3
-
-asserterror A vector index cannot be less than 1 (the index you supplied is 0).
-a# [0] = 932875289
-
-asserterror A vector index cannot be greater than the number of elements (here 16). The index you supplied is 20.
-a# [20] = 45786457
-
-assert numberOfRows (zero## (5, 6)) = 5
-assert numberOfColumns (zero## (5, 6)) = 6
-a## = zero## (5, 6)
-assert numberOfRows (a##) = 5
-assert a## [3, 4] = 0
-
-a## [5, 6] = 567
-assert a##[5,6] = 567
-
-c# = linear# (0, 100, 101)
-assert c# [98] = 97
-c# = linear# (0, 100, 101, 0)
-assert c# [98] = 97
-c# = linear# (0, 100, 100, 1)
-assert c# [98] = 97.5
-
-d# = randomGauss# (c#, 20, 1)
-a = d# [98]
-b = d# [99]
-c = d# [100]
-printline 'a' 'b' 'c'
-
-d# = randomUniform# (c#, 7, 10)
-a = d# [98]
-b = d# [99]
-c = d# [100]
-printline 'a' 'b' 'c'
-
-d# = randomInteger# (c#, 7, 10)
-a = d# [98]
-b = d# [99]
-c = d# [100]
-printline 'a' 'b' 'c'
-
-e# = a# + a#
-assert e# [3] = 8
-
-asserterror numbers of elements should be equal
-e# = a# + d#
-
-; q### =
-; data####
-;e# = d# + c#
-
-;speaker$# = empty$# [2]
-;speaker$# [1] = "JM"
-;speaker$# [2] = "PB"
-
-;speaker$ [1] = "JM"
-;speaker$ [2] = "PB"
-
-printline OK
diff --git a/test/script/tensor.praat b/test/script/tensor.praat
new file mode 100644
index 0000000..2124ce7
--- /dev/null
+++ b/test/script/tensor.praat
@@ -0,0 +1,160 @@
+writeInfoLine: "vectors and matrices..."
+
+a# = zero#(16)
+a#[3] = 4
+assert a#[3] = 4
+
+asserterror Vector b# does not exist.
+b# [5] = 3
+
+asserterror A vector index cannot be less than 1 (the index you supplied is 0).
+a# [0] = 932875289
+
+asserterror A vector index cannot be greater than the number of elements (here 16). The index you supplied is 20.
+a# [20] = 45786457
+
+assert numberOfRows (zero## (5, 6)) = 5
+assert numberOfColumns (zero## (5, 6)) = 6
+a## = zero## (5, 6)
+assert numberOfRows (a##) = 5
+assert a## [3, 4] = 0
+
+a## [5, 6] = 567
+assert a##[5,6] = 567
+
+c# = linear# (0, 100, 101)
+assert c# [98] = 97
+c# = linear# (0, 100, 101, 0)
+assert c# [98] = 97
+c# = linear# (0, 100, 100, 1)
+assert c# [98] = 97.5
+
+d# = randomGauss# (c#, 20, 1)
+a = d# [98]
+b = d# [99]
+c = d# [100]
+appendInfoLine: a, " ", b, " ", c
+
+d# = randomUniform# (c#, 7, 10)
+a = d# [98]
+b = d# [99]
+c = d# [100]
+appendInfoLine: a, " ", b, " ", c
+
+d# = randomInteger# (c#, 7, 10)
+a = d# [98]
+b = d# [99]
+c = d# [100]
+appendInfoLine: a, " ", b, " ", c
+
+e# = a# + a#
+assert e# [3] = 8
+
+asserterror numbers of elements should be equal
+e# = a# + d#
+
+; q### =
+; data####
+;e# = d# + c#
+
+;speaker$# = empty$# [2]
+;speaker$# [1] = "JM"
+;speaker$# [2] = "PB"
+
+;speaker$ [1] = "JM"
+;speaker$ [2] = "PB"
+
+#
+# outer##
+#
+n# = zero# (100)
+x# = randomInteger# (n#, 1, 1e7)
+y# = randomInteger# (n#, 1, 1e7)
+mat## = outer## (x#, y#)
+for row to 100
+	for col to 100
+		assert mat## [row, col] = x# [row] * y# [col]
+	endfor
+endfor
+
+squares# = { 1, 4, 9, 16, 25 }
+assert sum (squares#) = 55
+assert mean (squares#) = 11
+assert abs (mean (squares#) - sum (squares#) / 5) < 1e-14
+assert abs (stdev (squares#) - 9.669539802906858) < 1e-14
+assert abs (stdev (squares#) - sqrt (sumOver (i to 5, (squares# [i] - mean (squares#)) ^ 2) / 4)) < 1e-14
+assert abs (center (squares#) - 4.090909090909091) < 1e-14
+assert abs (center (squares#) - sumOver (i to 5, i * squares# [i]) / sum (squares#)) < 1e-14
+other# = { 2, 1.5, 1, 0.5, 0 }
+assert inner (squares#, other#) = 25
+assert sumOver (i to 5, squares# [i] * other# [i]) = 25
+
+a# = squares# + 5
+assert a# = { 6, 9, 14, 21, 30 }
+b# = a# + { 3.14, 2.72, 3.16, -1, 7.5 }
+assert b# = { 9.14, 11.72, 17.16, 20, 37.5 }
+c# = b# / 2
+appendInfoLine: c#
+assert c# = { 4.57, 5.86, 8.58, 10, 18.75 }
+d# = b# * c#
+norm = norm (d# - { 41.7698, 68.6792, 147.2328, 200, 703.125 })
+assert norm < 1e-13   ; 'norm'
+
+stopwatch
+iterations = 1e5
+for i to iterations
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+	a = 10+5
+endfor
+t = stopwatch / 10 * 1e9 / iterations
+appendInfoLine: t, " ns"
+
+stopwatch
+a# = { 4, 9, 16 }
+b# = { 25, 36, 49 }
+iterations = 1e5
+for i to iterations
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+	c# = a# - b#
+endfor
+t = stopwatch / 10 * 1e9 / iterations / 3
+appendInfoLine: t, " ns"
+
+stopwatch
+n = 100
+z# = zero# (n)
+a# = randomGauss# (z#, 0, 1)
+b# = randomGauss# (z#, 0, 1)
+iterations = 1e4
+for i to iterations
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+	m## = outer## (a#, b#)
+endfor
+t = stopwatch / 10 * 1e9 / iterations / n^2
+appendInfoLine: t, " ns"
+
+appendInfoLine: "OK"
diff --git a/test/script/undefined.praat b/test/script/undefined.praat
new file mode 100644
index 0000000..3433c66
--- /dev/null
+++ b/test/script/undefined.praat
@@ -0,0 +1,61 @@
+#
+# Some normal numbers.
+#
+assert 1 / 2 <> undefined
+assert 0 / 2 <> undefined
+assert sqrt (10) <> undefined
+
+#
+# Some infinities.
+#
+assert 1 / 0 = undefined
+assert 1 div 0 = undefined
+assert 1 mod 0 = undefined
+assert 10 ^ 500 = undefined
+assert exp (1000) = undefined
+
+#
+# Some infinitesimals.
+#
+assert 10 ^ -500 = 0
+assert exp (-1000) = 0
+
+#
+# Some not-a-numbers.
+#
+assert sqrt (-10) = undefined
+assert 0 / 0 = undefined
+assert 0 div 0 = undefined
+assert 0 mod 0 = undefined
+
+#
+# Propagation.
+#
+assert - undefined = undefined
+assert undefined - undefined = undefined
+assert sqrt (undefined) = undefined
+assert sqrt (- undefined) = undefined
+assert undefined * 0 = undefined
+assert 0 * undefined = undefined
+assert 1 / undefined = undefined
+assert 0 ^ undefined = undefined
+assert undefined ^ undefined = undefined
+
+#
+# Propagation within larger expressions.
+#
+assert 1 / (1 / 0) = undefined
+assert 1 / (0 / 0) = undefined
+assert 1 / exp (1000) = undefined   ; not the same as exp (-1000)!
+assert 0 ^ (1 / 0) = undefined
+assert 0 * (0 / 0) = undefined
+assert 0 * (1 / 0) = undefined
+
+#
+# Exception to propagation: anything to the power 0 always gives 1 (as in R).
+#
+assert 0 ^ 0 = 1
+;assert undefined ^ 0 = 1
+assert undefined ^ 0 = undefined
+;assert sqrt (-1) ^ 0 = 1
+assert sqrt (-1) ^ 0 = undefined
\ No newline at end of file
diff --git a/test/script/vectors.praat b/test/script/vectors.praat
deleted file mode 100644
index 7ce56f4..0000000
--- a/test/script/vectors.praat
+++ /dev/null
@@ -1,8 +0,0 @@
-a# = { 1, 4, 9, 16, 25 }
-assert sum (a#) = 55
-assert mean (a#) = 11
-assert abs (mean (a#) - sum (a#) / 5) < 1e-14
-assert abs (stdev (a#) - 9.669539802906858) < 1e-14
-assert abs (stdev (a#) - sqrt (sumOver (i to 5, (a# [i] - mean (a#)) ^ 2) / 4)) < 1e-14
-assert abs (center (a#) - 4.090909090909091) < 1e-14
-assert abs (center (a#) - sumOver (i to 5, i * a# [i]) / sum (a#)) < 1e-14

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/praat.git



More information about the debian-med-commit mailing list