[med-svn] [praat] 01/05: New upstream version 6.0.35

Rafael Laboissiere rafael at debian.org
Sat Oct 21 13:49:28 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 49d4a6c83ff09d0316193bd13f5d2a78b6e1825a
Author: Rafael Laboissiere <rafael at debian.org>
Date:   Fri Oct 20 19:11:39 2017 -0200

    New upstream version 6.0.35
---
 EEG/ERPTier.cpp                                    |   2 +-
 FFNet/FFNet.h                                      |   4 +-
 FFNet/praat_FFNet_init.cpp                         |   4 +-
 LPC/Cepstrogram.cpp                                |   4 +-
 LPC/Cepstrum.cpp                                   |   2 +-
 LPC/Cepstrumc.cpp                                  |   2 +-
 LPC/Sound_and_LPC.cpp                              |   4 +-
 LPC/Sound_and_LPC_robust.cpp                       |   4 +-
 LPC/VocalTractTier.cpp                             |   2 +-
 LPC/praat_LPC_init.cpp                             |  13 +-
 contrib/ola/praat_contrib_Ola_KNN.cpp              |  12 +-
 dwsys/Eigen.cpp                                    |   4 +-
 dwsys/NUM2.cpp                                     |   2 +-
 dwsys/NUMstring.cpp                                |   2 +-
 dwtools/CCs_to_DTW.cpp                             |   2 +-
 dwtools/ComplexSpectrogram.cpp                     |   6 +-
 dwtools/Confusion.cpp                              |   6 +-
 dwtools/DTW.cpp                                    |  14 +-
 dwtools/Discriminant.cpp                           |  10 +-
 dwtools/ICA.cpp                                    |   4 +-
 dwtools/Intensity_extensions.cpp                   |   2 +-
 dwtools/KlattGrid.cpp                              |  10 +-
 dwtools/KlattTable.cpp                             |  20 +-
 dwtools/LongSound_extensions.cpp                   |   8 +-
 dwtools/MFCC.cpp                                   |   2 +-
 dwtools/Matrix_extensions.cpp                      |   9 +-
 dwtools/Pitch_extensions.cpp                       |   2 +-
 dwtools/Polynomial.cpp                             |   2 +-
 dwtools/SPINET_to_Pitch.cpp                        |   6 +-
 dwtools/SSCP.cpp                                   |  20 +-
 dwtools/Sound_and_MixingMatrix.cpp                 | 280 +++++-----
 dwtools/Sound_extensions.cpp                       |  37 +-
 dwtools/Sound_to_Pitch2.cpp                        |   4 +-
 dwtools/Spectrum_extensions.cpp                    |  14 +-
 dwtools/SpeechSynthesizer_and_TextGrid.cpp         |   2 +-
 dwtools/TableOfReal_extensions.cpp                 |   8 +-
 dwtools/VowelEditor.cpp                            |   6 +-
 dwtools/praat_BSS_init.cpp                         |   2 +-
 dwtools/praat_DataModeler_init.cpp                 |   6 +-
 dwtools/praat_David_init.cpp                       | 111 ++--
 dwtools/praat_HMM_init.cpp                         |  30 +-
 dwtools/praat_KlattGrid_init.cpp                   |  16 +-
 fon/AmplitudeTier.cpp                              |   2 +-
 fon/FormantGrid.cpp                                |   2 +-
 fon/FunctionEditor.cpp                             |   2 +-
 fon/LongSound.cpp                                  |   4 +-
 fon/Ltas.cpp                                       |  57 +-
 fon/Ltas.h                                         |   2 +-
 fon/Manipulation.cpp                               |  58 +-
 fon/Matrix.cpp                                     |  18 +-
 fon/Matrix_and_Polygon.cpp                         |   4 +-
 fon/Movie.cpp                                      |   4 +-
 fon/Movie.h                                        |   6 +-
 fon/ParamCurve.cpp                                 |  10 +-
 fon/Photo.cpp                                      |  68 +--
 fon/Photo.h                                        |  10 +-
 fon/Pitch.cpp                                      | 106 ++--
 fon/Pitch.h                                        |  16 +-
 fon/PitchEditor.cpp                                |   2 +-
 fon/PitchTier.cpp                                  |  12 +-
 fon/PitchTier_to_PointProcess.cpp                  |  16 +-
 fon/PitchTier_to_Sound.cpp                         |   8 +-
 fon/PitchTier_to_Sound.h                           |   4 +-
 fon/Pitch_AnyTier_to_PitchTier.cpp                 |   4 +-
 fon/Pitch_Intensity.cpp                            |  14 +-
 fon/Pitch_to_PitchTier.cpp                         |  14 +-
 fon/Pitch_to_PointProcess.cpp                      |  22 +-
 fon/Pitch_to_Sound.cpp                             |   4 +-
 fon/PointProcess.cpp                               |   2 +-
 fon/PointProcess_and_Sound.cpp                     |  30 +-
 fon/PointProcess_and_Sound.h                       |   2 +-
 fon/Polygon.cpp                                    |  54 +-
 fon/Polygon.h                                      |   6 +-
 fon/Praat_tests.cpp                                |  16 +-
 fon/RealTier.cpp                                   |  62 +--
 fon/RealTier.h                                     |  12 +-
 fon/Sampled.cpp                                    |  64 +--
 fon/Sampled.h                                      |  40 +-
 fon/SampledXY.cpp                                  |   2 +-
 fon/SampledXY.h                                    |   2 +-
 fon/Sound.cpp                                      | 256 +++++----
 fon/Sound.h                                        |  16 +-
 fon/SoundRecorder.cpp                              |   6 +-
 fon/Sound_PointProcess.cpp                         |   2 +-
 fon/Sound_and_Spectrogram.cpp                      |  18 +-
 fon/Sound_audio.cpp                                |   2 +-
 fon/Sound_to_Cochleagram.cpp                       |   6 +-
 fon/Sound_to_Formant.cpp                           |   4 +-
 fon/Sound_to_Harmonicity_GNE.cpp                   |   2 +-
 fon/Sound_to_Intensity.cpp                         |   2 +-
 fon/Sound_to_Pitch.cpp                             |  14 +-
 fon/Spectrum_to_Excitation.cpp                     |   2 +-
 fon/TextGridEditor.cpp                             |   2 +-
 fon/TextGrid_Sound.cpp                             |  16 +-
 fon/TimeSoundEditor.cpp                            |   2 +-
 fon/Vector.cpp                                     |   2 +-
 fon/manual_Fon.cpp                                 |   2 +-
 fon/manual_Manual.cpp                              |   2 +-
 fon/manual_Picture.cpp                             |   2 +-
 fon/manual_Sampling.cpp                            |   2 +-
 fon/manual_Script.cpp                              |   2 +-
 fon/manual_annotation.cpp                          |   2 +-
 fon/manual_exampleSound.cpp                        |   2 +-
 fon/manual_exampleSound.h                          |   2 +-
 fon/manual_formant.cpp                             |   2 +-
 fon/manual_glossary.cpp                            |   2 +-
 fon/manual_pitch.cpp                               |   2 +-
 fon/manual_programming.cpp                         |   2 +-
 fon/manual_references.cpp                          |   2 +-
 fon/manual_sound.cpp                               |   2 +-
 fon/manual_soundFiles.cpp                          |   2 +-
 fon/manual_spectrum.cpp                            |   2 +-
 fon/manual_tutorials.cpp                           |   8 +-
 fon/manual_voice.cpp                               |   2 +-
 fon/praat_TextGrid_init.cpp                        |   4 +-
 gram/DeepBeliefNetwork.cpp                         | 208 +++++++
 gram/DeepBeliefNetwork.h                           |  59 ++
 .../DeepBeliefNetwork_def.h                        |  21 +-
 .../DeepBeliefNetwork_enums.h                      |  18 +-
 gram/Makefile                                      |  54 +-
 gram/Network.cpp                                   | 100 ++--
 gram/Network.h                                     |  34 +-
 gram/Network_def.h                                 |   2 +-
 gram/Network_enums.h                               |   2 +-
 gram/OTGrammar.cpp                                 | 596 ++++++++++-----------
 gram/OTGrammar.h                                   |  60 +--
 gram/OTGrammarEditor.cpp                           |   6 +-
 gram/OTGrammarEditor.h                             |   4 +-
 gram/OTGrammar_def.h                               |   2 +-
 gram/OTGrammar_ex_NPA.cpp                          |   2 +-
 gram/OTGrammar_ex_NoCoda.cpp                       |   2 +-
 gram/OTGrammar_ex_metrics.cpp                      |  46 +-
 gram/OTGrammar_ex_tongueRoot.cpp                   |  10 +-
 gram/OTMulti.cpp                                   | 266 ++++-----
 gram/OTMulti.h                                     |  22 +-
 gram/OTMultiEditor.cpp                             |   6 +-
 gram/OTMultiEditor.h                               |   4 +-
 gram/OTMulti_def.h                                 |   2 +-
 gram/OTMulti_ex_metrics.cpp                        |  43 +-
 gram/RBM.cpp                                       | 106 ++--
 gram/RBM.h                                         |  10 +-
 gram/manual_gram.cpp                               |   2 +-
 gram/praat_gram.cpp                                | 239 ++++++++-
 num/NUM.cpp                                        |   2 +-
 stat/Distributions.cpp                             |  38 +-
 stat/Distributions.h                               |  12 +-
 stat/Distributions_and_Strings.cpp                 |  30 +-
 stat/Distributions_and_Strings.h                   |   6 +-
 stat/PairDistribution.cpp                          |  44 +-
 stat/PairDistribution.h                            |  12 +-
 stat/Regression.cpp                                |  22 +-
 stat/Regression.h                                  |   4 +-
 stat/praat_Stat.cpp                                | 122 ++---
 stat/praat_TableOfReal.cpp                         |  16 +-
 sys/Formula.cpp                                    |  54 +-
 sys/Graphics_image.cpp                             |   4 +-
 sys/Gui.cpp                                        |   2 +-
 sys/Gui.h                                          |   2 +-
 sys/GuiP.h                                         |   2 +-
 sys/GuiText.cpp                                    |  44 +-
 sys/MelderGui.cpp                                  |   2 +-
 sys/MelderThread.h                                 |   2 +-
 sys/melder.cpp                                     |   2 +-
 sys/melder.h                                       | 148 +++--
 sys/melder_alloc.cpp                               |   2 +-
 sys/melder_atof.cpp                                |   2 +-
 sys/melder_audio.cpp                               |   2 +-
 sys/melder_audiofiles.cpp                          |   2 +-
 sys/melder_console.cpp                             |   2 +-
 sys/melder_debug.cpp                               |   2 +-
 sys/melder_files.cpp                               |   2 +-
 sys/melder_ftoa.cpp                                |   2 +-
 sys/melder_info.cpp                                |   2 +-
 sys/melder_readtext.cpp                            |   2 +-
 sys/melder_strings.cpp                             |   2 +-
 sys/melder_sysenv.cpp                              |   2 +-
 sys/melder_textencoding.cpp                        |   2 +-
 sys/melder_time.cpp                                |   2 +-
 sys/melder_token.cpp                               |   2 +-
 sys/melder_writetext.cpp                           |   2 +-
 sys/motifEmulator.cpp                              |  17 +-
 sys/oo_READ_BINARY.h                               |   8 +-
 sys/oo_READ_TEXT.h                                 |   4 +-
 sys/oo_WRITE_BINARY.h                              |   4 +-
 sys/oo_WRITE_TEXT.h                                |   4 +-
 sys/praat.h                                        |   3 +-
 sys/praat_version.h                                |   6 +-
 sys/tensor.cpp                                     |  20 +-
 sys/tensor.h                                       |   8 +-
 test/gram/DBN.praat                                |  59 ++
 test/gram/DBNtry.txt                               |  54 ++
 test/script/RBM.praat                              |   4 +-
 test/script/{RBM.praat => RBMparallel.praat}       |  61 +--
 193 files changed, 2631 insertions(+), 2008 deletions(-)

diff --git a/EEG/ERPTier.cpp b/EEG/ERPTier.cpp
index af1dc1a..b007cc2 100644
--- a/EEG/ERPTier.cpp
+++ b/EEG/ERPTier.cpp
@@ -78,7 +78,7 @@ static autoERPTier EEG_PointProcess_to_ERPTier (EEG me, PointProcess events, dou
 		integer numberOfEvents = events -> nt;
 		double soundDuration = toTime - fromTime;
 		double samplingPeriod = my sound -> dx;
-		integer numberOfSamples = (integer) floor (soundDuration / samplingPeriod) + 1;
+		integer numberOfSamples = Melder_iroundDown (soundDuration / samplingPeriod) + 1;
 		if (numberOfSamples < 1)
 			Melder_throw (U"Time window too short.");
 		double midTime = 0.5 * (fromTime + toTime);
diff --git a/FFNet/FFNet.h b/FFNet/FFNet.h
index 7be484c..608cda7 100644
--- a/FFNet/FFNet.h
+++ b/FFNet/FFNet.h
@@ -59,8 +59,8 @@
  *    *error		    : array[1..nNodes] the error at node
  *    *dw		    	: array[1..nWeights] total derivative for weights
  *    *dwi		   		: array[1..nWeights] derivative per pattern
- * long dimension		: dimension of minimizer space (<= my nWeights)
- * long nPatterns	    : the #patterns to be learned
+ *  long dimension		: dimension of minimizer space (<= my nWeights)
+ *  long nPatterns	    : the #patterns to be learned
  * double **inputPattern: matrix[1..nPatterns][1..nInputs]
  * double **targetActivation: matrix[1..nPatterns][1..nOutputs]
  * double accumulatedCost : accumulated costs of testing/training with patterns
diff --git a/FFNet/praat_FFNet_init.cpp b/FFNet/praat_FFNet_init.cpp
index 8f54a96..1cde333 100644
--- a/FFNet/praat_FFNet_init.cpp
+++ b/FFNet/praat_FFNet_init.cpp
@@ -106,7 +106,7 @@ DO
 		autoPatternList result = PatternList_create (numberOfPatterns, patternDimension);
 	CREATE_ONE_END (name);
 }
-	
+
 /**************** New Categories ***************************/
 	
 FORM (NEW1_Categories_create, U"Create Categories", nullptr) {
@@ -564,7 +564,7 @@ DIRECT (NEW1_RBM_PatternList_to_ActivationList) {
 }
 
 void praat_uvafon_FFNet_init () {
-	Thing_recognizeClassesByName (classFFNet, NULL);
+	Thing_recognizeClassesByName (classFFNet, nullptr);
 
 	praat_addMenuCommand (U"Objects", U"New", U"Feedforward neural networks", nullptr, 0, nullptr);
 	praat_addMenuCommand (U"Objects", U"New", U"Create FFNet...", nullptr, 1, NEW1_FFNet_create);
diff --git a/LPC/Cepstrogram.cpp b/LPC/Cepstrogram.cpp
index 9713c43..72f9c85 100644
--- a/LPC/Cepstrogram.cpp
+++ b/LPC/Cepstrogram.cpp
@@ -194,7 +194,7 @@ autoPowerCepstrogram PowerCepstrogram_smooth (PowerCepstrogram me, double timeAv
 	try {
 		autoPowerCepstrogram thee = Data_copy (me);
 		// 1. average across time
-		long numberOfFrames = (long) floor (timeAveragingWindow / my dx);
+		integer numberOfFrames = Melder_iroundDown (timeAveragingWindow / my dx);
 		if (numberOfFrames > 1) {
 			autoNUMvector<double> qin (1, my nx);
 			autoNUMvector<double> qout (1, my nx);
@@ -211,7 +211,7 @@ autoPowerCepstrogram PowerCepstrogram_smooth (PowerCepstrogram me, double timeAv
 			}
 		}
 		// 2. average across quefrencies
-		long numberOfQuefrencyBins = (long) floor (quefrencyAveragingWindow / my dy);
+		integer numberOfQuefrencyBins = Melder_iroundDown (quefrencyAveragingWindow / my dy);
 		if (numberOfQuefrencyBins > 1) {
 			autoNUMvector<double> qin (1, thy ny);
 			autoNUMvector<double> qout (1, thy ny);
diff --git a/LPC/Cepstrum.cpp b/LPC/Cepstrum.cpp
index 487143b..4a40fff 100644
--- a/LPC/Cepstrum.cpp
+++ b/LPC/Cepstrum.cpp
@@ -317,7 +317,7 @@ autoPowerCepstrum PowerCepstrum_subtractTilt (PowerCepstrum me, double qstartFit
 
 void PowerCepstrum_smooth_inline (PowerCepstrum me, double quefrencyAveragingWindow, long numberOfIterations) {
 	try {
-		long numberOfQuefrencyBins = (long) floor (quefrencyAveragingWindow / my dx);
+		integer numberOfQuefrencyBins = Melder_iroundDown (quefrencyAveragingWindow / my dx);
 		if (numberOfQuefrencyBins > 1) {
 			autoNUMvector<double> qin (1, my nx);
 			autoNUMvector<double> qout (1, my nx);
diff --git a/LPC/Cepstrumc.cpp b/LPC/Cepstrumc.cpp
index 291e26d..f973da3 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 {
-		integer nr = (integer) floor (dtr / my dx);
+		integer nr = Melder_iroundDown (dtr / my dx);
 
 		if (my maxnCoefficients != thy maxnCoefficients) {
 			Melder_throw (U"Cepstrumc orders must be equal.");
diff --git a/LPC/Sound_and_LPC.cpp b/LPC/Sound_and_LPC.cpp
index 2ebb133..a2873eb 100644
--- a/LPC/Sound_and_LPC.cpp
+++ b/LPC/Sound_and_LPC.cpp
@@ -373,7 +373,7 @@ static autoLPC _Sound_to_LPC (Sound me, int predictionOrder, double analysisWidt
 	double windowDuration = 2 * analysisWidth; /* gaussian window */
 	integer numberOfFrames, frameErrorCount = 0;
 
-	if (floor (windowDuration / my dx) < predictionOrder + 1) {
+	if (Melder_roundDown (windowDuration / my dx) < predictionOrder + 1) {
 		Melder_throw (U"Analysis window duration too short.\n For a prediction order of ", predictionOrder,
 			U" the analysis window duration has to be greater than ", my dx * (predictionOrder + 1), U"Please increase the analysis window duration or lower the prediction order.");
 	}
@@ -544,7 +544,7 @@ autoSound LPC_and_Sound_filter (LPC me, Sound thee, int useGain) {
 			for (long i = ifirst; i <= ilast; i++) {
 				double t = his x1 + (i - 1) * his dx; /* Sampled_indexToX (him, i) */
 				double riFrame = (t - my x1) / my dx + 1; /* Sampled_xToIndex (me, t); */
-				long iFrame = (long) floor (riFrame);
+				integer iFrame = Melder_iroundDown (riFrame);
 				double phase = riFrame - iFrame;
 				if (iFrame < 0 || iFrame > my nx) {
 					x[i] = 0.0;
diff --git a/LPC/Sound_and_LPC_robust.cpp b/LPC/Sound_and_LPC_robust.cpp
index c61a471..7955f54 100644
--- a/LPC/Sound_and_LPC_robust.cpp
+++ b/LPC/Sound_and_LPC_robust.cpp
@@ -197,7 +197,7 @@ autoLPC LPC_and_Sound_to_LPC_robust (LPC thee, Sound me, double analysisWidth, d
 		if (my dx != thy samplingPeriod) {
 			Melder_throw (U"Sampling intervals differ.");
 		}
-		if (floor (windowDuration / my dx) < p + 1) {
+		if (Melder_roundDown (windowDuration / my dx) < p + 1) {
 			Melder_throw (U"Analysis window too short.");
 		}
 		Sampled_shortTermAnalysis (me, windowDuration, thy dx, & numberOfFrames, & t1);
@@ -259,7 +259,7 @@ autoFormant Sound_to_Formant_robust (Sound me, double dt_in, double numberOfForm
 {
 	double dt = dt_in > 0.0 ? dt_in : halfdt_window / 4.0;
 	double nyquist = 0.5 / my dx;
-	int predictionOrder = (long) floor (2 * numberOfFormants);
+	integer predictionOrder = Melder_iroundDown (2 * numberOfFormants);
 	try {
 		autoSound sound;
 		if (maximumFrequency <= 0.0 || fabs (maximumFrequency / nyquist - 1.0) < 1.0e-12) {
diff --git a/LPC/VocalTractTier.cpp b/LPC/VocalTractTier.cpp
index de9d114..02195cc 100644
--- a/LPC/VocalTractTier.cpp
+++ b/LPC/VocalTractTier.cpp
@@ -141,7 +141,7 @@ autoLPC VocalTractTier_to_LPC (VocalTractTier me, double timeStep) {
 		if (my d_vocalTracts.size == 0) {
 			Melder_throw (U"Empty VocalTractTier");
 		}
-		long numberOfFrames = (long) floor ((my xmax - my xmin) / timeStep);
+		integer numberOfFrames = Melder_iroundDown ((my xmax - my xmin) / timeStep);
 		VocalTractPoint vtp = my d_vocalTracts.at [1];
 		long numberOfSections = vtp -> d_vocalTract -> nx;
 		double samplingPeriod = 1.0 / (1000.0 * numberOfSections);
diff --git a/LPC/praat_LPC_init.cpp b/LPC/praat_LPC_init.cpp
index c808860..c0e8ff8 100644
--- a/LPC/praat_LPC_init.cpp
+++ b/LPC/praat_LPC_init.cpp
@@ -598,7 +598,7 @@ FORM (NEW_LFCC_to_LPC, U"LFCC: To LPC", U"LFCC: To LPC...") {
 	INTEGER (numberOfCoefficients, U"Number of coefficients", U"0")
 	OK
 DO
-	REQUIRE (numberOfCoefficients >= 0, U"Number of coefficients must be greater or equal zero.")
+	Melder_require (numberOfCoefficients >= 0, U"Number of coefficients must be greater or equal zero.");
 	CONVERT_EACH (LFCC)
 		autoLPC result = LFCC_to_LPC (me, numberOfCoefficients);
 	CONVERT_EACH_END (my name);
@@ -657,7 +657,8 @@ FORM (INTEGER_LPC_getNumberOfCoefficients, U"LPC: Get number of coefficients", U
 	OK
 DO
 	INTEGER_ONE (LPC)
-		REQUIRE (frameNumber <= my nx, Melder_cat (U"Frame number is too large.\n\nPlease choose a number between 1 and ", my nx))
+		Melder_require (frameNumber <= my nx,
+			U"Your frame number (", frameNumber, U") is too large. It should be between 1 and ", my nx, U".");
 		long result = my d_frames[frameNumber].nCoefficients;
 	INTEGER_ONE_END (U" coefficients")
 }
@@ -688,7 +689,7 @@ FORM (NEW_LPC_to_LFCC, U"LPC: To LFCC", U"LPC: To LFCC...") {
 	INTEGER (numberOfCoefficients, U"Number of coefficients", U"0")
 	OK
 DO
-	REQUIRE (numberOfCoefficients >= 0, U"The number of coefficients should be greater than or equal to zero.")
+	Melder_require (numberOfCoefficients >= 0, U"The number of coefficients should be greater than or equal to zero.");
 	CONVERT_EACH (LPC)
 		autoLFCC result = LPC_to_LFCC (me, numberOfCoefficients);
 	CONVERT_EACH_END (my name)
@@ -891,7 +892,7 @@ FORM (NEW_Sound_to_MFCC, U"Sound: To MFCC", U"Sound: To MFCC...") {
 	REAL (maximumFrequency, U"Maximum frequency (mel)", U"0.0");
 	OK
 DO
-	REQUIRE (numberOfCoefficients < 25, U"The number of coefficients should be less than 25.")
+	Melder_require (numberOfCoefficients < 25, U"The number of coefficients should be less than 25.");
 	CONVERT_EACH (Sound)
 		autoMFCC result = Sound_to_MFCC (me, numberOfCoefficients, windowLength, timeStep, firstFilterFrequency, maximumFrequency, distancBetweenFilters);
 	CONVERT_EACH_END (my name)
@@ -929,8 +930,8 @@ FORM (NEW_VocalTract_to_VocalTractTier, U"VocalTract: To VocalTractTier", nullpt
 	REAL (time, U"Insert at time (s)", U"0.5")
 	OK
 DO
-	REQUIRE (fromTime < toTime, U"The start time must be before the end time.")
-	REQUIRE (time >= fromTime && time <= toTime, U"The insert time must be between start and end time.")
+	Melder_require (fromTime < toTime, U"Your start time should be before your end time.");
+	Melder_require (time >= fromTime && time <= toTime, U"Your insert time should be between your start and end times.");
 	CONVERT_EACH (VocalTract)
 		autoVocalTractTier result = VocalTract_to_VocalTractTier (me, fromTime, toTime, time);
 	CONVERT_EACH_END (my name)
diff --git a/contrib/ola/praat_contrib_Ola_KNN.cpp b/contrib/ola/praat_contrib_Ola_KNN.cpp
index 5467788..d9f6520 100644
--- a/contrib/ola/praat_contrib_Ola_KNN.cpp
+++ b/contrib/ola/praat_contrib_Ola_KNN.cpp
@@ -525,8 +525,8 @@ DO
 			Melder_throw (U"Please select a value of k such that 0 < k <= ", my ny, U".");
 		if (maximumNumberOfReseeds < 0)
 			Melder_throw (U"The maximum number of reseeds should not be negative.");
-		REQUIRE (clusterSizeRatioConstraint > 0.0 && clusterSizeRatioConstraint <= 1.0,
-			U"The cluster size ratio constraint should be between 0.0 (exclusive) and 1.0 (inclusive).")
+		Melder_require (clusterSizeRatioConstraint > 0.0 && clusterSizeRatioConstraint <= 1.0,
+			U"The cluster size ratio constraint should be between 0.0 (exclusive) and 1.0 (inclusive).");
 		autoFeatureWeights fws = FeatureWeights_create (my nx);
 		autoCategories result = PatternList_to_Categories_cluster (me, fws.get(), kClusters, clusterSizeRatioConstraint, maximumNumberOfReseeds);
 	CONVERT_EACH_END (U"Output")
@@ -545,10 +545,10 @@ DO
 			Melder_throw (U"The number of features and the number of feature weights should be equal.");
 		if (kClusters < 1 || kClusters > my ny)
 			Melder_throw (U"Please select a value of k such that 0 < k <= ", my ny, U".");
-		REQUIRE (maximumNumberOfReseeds >= 0,
-			U"The maximum number of reseeds should be 0 or positive.")
-		REQUIRE (clusterSizeRatioConstraint > 0.0 && clusterSizeRatioConstraint <= 1.0,
-			U"The cluster size ratio constraint should be between 0.0 (exclusive) and 1.0 (inclusive).")
+		Melder_require (maximumNumberOfReseeds >= 0,
+			U"The maximum number of reseeds should be 0 or positive.");
+		Melder_require (clusterSizeRatioConstraint > 0.0 && clusterSizeRatioConstraint <= 1.0,
+			U"The cluster size ratio constraint should be between 0.0 (exclusive) and 1.0 (inclusive).");
 		autoCategories result = PatternList_to_Categories_cluster (me, you, kClusters, clusterSizeRatioConstraint, maximumNumberOfReseeds);
 	CONVERT_TWO_END (U"Output")
 }
diff --git a/dwsys/Eigen.cpp b/dwsys/Eigen.cpp
index ec0028e..2c58f6d 100644
--- a/dwsys/Eigen.cpp
+++ b/dwsys/Eigen.cpp
@@ -89,7 +89,7 @@ static void Graphics_ticks (Graphics g, double min, double max, bool hasNumber,
 		dtick = 0.5;
 	}
 	dtick *= scale;
-	tick = dtick * floor (min / dtick);
+	tick = dtick * Melder_roundDown (min / dtick);
 	if (tick < min) {
 		tick += dtick;
 	}
@@ -239,7 +239,7 @@ void Eigen_initFromSymmetricMatrix (Eigen me, double **a, integer n) {
 		Melder_throw (U"dsyev initialization fails");
 	}
 
-	lwork = (integer) floor (wt[0]);
+	lwork = Melder_iroundDown (wt [0]);
 	autoNUMvector <double> work ((integer) 0, lwork);
 
 	(void) NUMlapack_dsyev (&jobz, &uplo, &n, &my eigenvectors[1][1], &n, &my eigenvalues[1], work.peek(), & lwork, & info);
diff --git a/dwsys/NUM2.cpp b/dwsys/NUM2.cpp
index 8e542d4..2d0f9ba 100644
--- a/dwsys/NUM2.cpp
+++ b/dwsys/NUM2.cpp
@@ -2965,7 +2965,7 @@ integer NUMrandomBinomial (double p, integer n) {
 		/* Note: magic numbers 2.195, 4.6, 0.134, 20.5, 15.3 */
 		/* These magic numbers are not adjustable...at least not easily! */
 
-		double p1 = floor (2.195 * sqrt (npq) - 4.6 * q) + 0.5;
+		double p1 = Melder_roundDown (2.195 * sqrt (npq) - 4.6 * q) + 0.5;
 
 		/* xl, xr: left and right edges of triangle */
 		double xl = xm - p1;
diff --git a/dwsys/NUMstring.cpp b/dwsys/NUMstring.cpp
index 4f8b224..7908416 100644
--- a/dwsys/NUMstring.cpp
+++ b/dwsys/NUMstring.cpp
@@ -515,7 +515,7 @@ integer *NUMstring_getElementsOfRanges (const char32 *ranges, integer maximumEle
 
 char32 * NUMstring_timeNoDot (double time) {
 	static char32 string[100];
-	long seconds = (long) floor (time);
+	integer seconds = Melder_iroundDown (time);
 	long ms = lround ((time - seconds) * 1000.0);
 	Melder_sprint (string,100, U"_", seconds, U"_", ms);
 	return string;
diff --git a/dwtools/CCs_to_DTW.cpp b/dwtools/CCs_to_DTW.cpp
index aae3fdb..d96ad44 100644
--- a/dwtools/CCs_to_DTW.cpp
+++ b/dwtools/CCs_to_DTW.cpp
@@ -59,7 +59,7 @@ autoDTW CCs_to_DTW (CC me, CC thee, double wc, double wle, double wr, double wer
 		if (my maximumNumberOfCoefficients != thy maximumNumberOfCoefficients) {
 			Melder_throw (U"CC orders must be equal.");
 		}
-		long nr = (long) floor (dtr / my dx);
+		integer nr = Melder_iroundDown (dtr / my dx);
 		if (wr != 0.0 && nr < 2) {
 			Melder_throw (U"Time window for regression is too small.");
 		}
diff --git a/dwtools/ComplexSpectrogram.cpp b/dwtools/ComplexSpectrogram.cpp
index 23fb410..7945c4c 100644
--- a/dwtools/ComplexSpectrogram.cpp
+++ b/dwtools/ComplexSpectrogram.cpp
@@ -60,7 +60,7 @@ autoComplexSpectrogram Sound_to_ComplexSpectrogram (Sound me, double windowLengt
 			Melder_throw (U"Your sound is too short:\nit should be at least as long as one window length.");
 		}
 		
-		long nsamp_window = (long) floor (windowLength / my dx);
+		integer nsamp_window = Melder_iroundDown (windowLength / my dx);
 		long halfnsamp_window = nsamp_window / 2 - 1;
 		nsamp_window = halfnsamp_window * 2;
 		
@@ -165,9 +165,9 @@ autoSound ComplexSpectrogram_to_Sound (ComplexSpectrogram me, double stretchFact
 
 			// Where should the sound be placed?
 
-			long thyEndSampleP = (long) floor (fmin (thyStartSample + synthesis -> nx - 1, thyStartSample + stretchedStepSizeSamples - 1)); // guard against extreme stretches
+			integer thyEndSampleP = Melder_iroundDown (fmin (thyStartSample + synthesis -> nx - 1, thyStartSample + stretchedStepSizeSamples - 1)); // guard against extreme stretches
 			if (iframe == my nx) {
-				thyEndSampleP = (long) floor (fmin (thy nx, thyStartSample + synthesis -> nx - 1));   // ppgb: waarom naar beneden afgerond?
+				thyEndSampleP = Melder_iroundDown (fmin (thy nx, thyStartSample + synthesis -> nx - 1));   // ppgb: waarom naar beneden afgerond?
 			}
 			for (long j = thyStartSample; j <= thyEndSampleP; j++) {
 				thy z[1][j] = synthesis -> z[1][j - thyStartSample + 1];
diff --git a/dwtools/Confusion.cpp b/dwtools/Confusion.cpp
index c8e53dc..769f94a 100644
--- a/dwtools/Confusion.cpp
+++ b/dwtools/Confusion.cpp
@@ -235,7 +235,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 = undefined;
-	long numberOfCorrect = -1;
+	integer numberOfCorrect = -1;
 
 	double c = 0.0, ct = 0.0;
 	for (long i = 1; i <= my numberOfRows; i++) {
@@ -256,7 +256,7 @@ void Confusion_getFractionCorrect (Confusion me, double *p_fraction, long *p_num
 	if (p_fraction) {
 		*p_fraction = fraction;
 	}
-	numberOfCorrect = (long) floor (c);
+	numberOfCorrect = Melder_iroundDown (c);
 	if (p_numberOfCorrect) {
 		*p_numberOfCorrect = numberOfCorrect;
 	}
@@ -408,7 +408,7 @@ long Confusion_getNumberOfEntries (Confusion me) {
 			total += my data[i][j];
 		}
 	}
-	return (long) floor (total);
+	return Melder_iroundDown (total);
 }
 
 static void create_index (char32 **s, long sb, long se, char32 **ref, long rb, long re, long *index) {
diff --git a/dwtools/DTW.cpp b/dwtools/DTW.cpp
index c056e97..ba0e465 100644
--- a/dwtools/DTW.cpp
+++ b/dwtools/DTW.cpp
@@ -477,7 +477,7 @@ double DTW_getPathY (DTW me, double tx) {
 
 	// Find column in DTW matrix
 
-	long ix = (long) floor ((tx - my x1) / my dx) + 1;
+	integer ix = Melder_iroundDown ((tx - my x1) / my dx) + 1;
 	if (ix < 1) {
 		ix = 1;
 	}
@@ -1209,7 +1209,7 @@ static void DTW_and_Polygon_setUnreachableParts (DTW me, Polygon thee, long **ps
         // find border "above" polygon
         for (long ix = 1; ix <= my nx; ix ++) {
             double x = my x1 + (ix - 1) * my dx;
-            long iystart = (long) floor (dtw_slope * ix * (my dx / my dy)) + 1;
+            integer iystart = Melder_iroundDown (dtw_slope * ix * (my dx / my dy)) + 1;
             for (long iy = iystart + 1; iy <= my ny; iy ++) {
                 double y = my y1 + (iy - 1) * my dy;
                 if (Polygon_getLocationOfPoint (thee, x, y, eps) == Polygon_OUTSIDE) {
@@ -1223,7 +1223,7 @@ static void DTW_and_Polygon_setUnreachableParts (DTW me, Polygon thee, long **ps
         // find border "below" polygon
         for (long ix = 2; ix <= my nx; ix ++) {
             double x = my x1 + (ix - 1) * my dx;
-            long iystart = (long) floor (dtw_slope * ix * (my dx / my dy));   // start 1 lower
+            integer iystart = Melder_iroundDown (dtw_slope * ix * (my dx / my dy));   // start 1 lower
             if (iystart > my ny) iystart = my ny;
             for (long iy = iystart - 1; iy >= 1; iy --) {
                 double y = my y1 + (iy - 1) * my dy;
@@ -1407,9 +1407,9 @@ void DTW_and_Polygon_findPathInside (DTW me, Polygon thee, int localSlope, autoM
         }
 
         // Make begin part of first column reachable
-        long rowto = delta_xy;
+        integer rowto = delta_xy;
         if (localSlope != 1) {
-			rowto = (long) floor (slopes[localSlope]) + 1;
+			rowto = Melder_iroundDown (slopes [localSlope]) + 1;
 		}
         for (long iy = 2; iy <= rowto; iy ++) {
             if (localSlope != 1) {
@@ -1420,9 +1420,9 @@ void DTW_and_Polygon_findPathInside (DTW me, Polygon thee, int localSlope, autoM
             }
         }
         // Make begin part of first row reachable
-        long colto = delta_xy;
+        integer colto = delta_xy;
         if (localSlope != 1) {
-			colto = (long) floor (slopes[localSlope]) + 1;
+			colto = Melder_iroundDown (slopes [localSlope]) + 1;
 		}
         for (long ix = 2; ix <= colto; ix ++) {
             if (localSlope != 1) {
diff --git a/dwtools/Discriminant.cpp b/dwtools/Discriminant.cpp
index afa295d..5f9d59e 100644
--- a/dwtools/Discriminant.cpp
+++ b/dwtools/Discriminant.cpp
@@ -110,10 +110,10 @@ long Discriminant_getNumberOfGroups (Discriminant me) {
 
 long Discriminant_getNumberOfObservations (Discriminant me, long group) {
 	if (group == 0) {
-		return (long) floor (my total -> numberOfObservations);
+		return Melder_iroundDown (my total -> numberOfObservations);
 	} else if (group >= 1 && group <= my numberOfGroups) {
 		SSCP sscp = my groups->at [group];
-		return (long) floor (sscp -> numberOfObservations);
+		return Melder_iroundDown (sscp -> numberOfObservations);
 	} else {
 		return -1;
 	}
@@ -190,7 +190,7 @@ autoTableOfReal Discriminant_extractGroupStandardDeviations (Discriminant me) {
 		for (long i = 1; i <= m; i ++) {
 			SSCP sscp = my groups->at [i];
 			TableOfReal_setRowLabel (thee.get(), i, Thing_getName (sscp));
-			long numberOfObservationsm1 = (long) floor (sscp -> numberOfObservations) - 1;
+			integer numberOfObservationsm1 = Melder_iroundDown (sscp -> numberOfObservations) - 1;
 			for (long j = 1; j <= n; j ++) {
 				thy data [i] [j] = ( numberOfObservationsm1 > 0 ? sqrt (sscp -> data [j] [j] / numberOfObservationsm1) : undefined );
 			}
@@ -592,7 +592,7 @@ autoClassificationTable Discriminant_and_TableOfReal_to_ClassificationTable (Dis
 			long npool = 0;
 			for (long j = 1; j <= g; j ++) {
 				SSCP t = groups->at [j];
-				long no = (long) floor (SSCP_getNumberOfObservations (t));
+				integer no = Melder_iroundDown (SSCP_getNumberOfObservations (t));
 				for (long i = 1; i <= p; i ++) {
 					for (long k = i; k <= p; k ++) {
 						t -> data [k] [i] = t -> data [i] [k] /= no - 1;
@@ -717,7 +717,7 @@ autoClassificationTable Discriminant_and_TableOfReal_to_ClassificationTable_dw (
 			long npool = 0;
 			for (long j = 1; j <= g; j ++) {
 				SSCP t = groups->at [j];
-				long no = (long) floor (SSCP_getNumberOfObservations (t));
+				integer no = Melder_iroundDown (SSCP_getNumberOfObservations (t));
 				for (long i = 1; i <= p; i ++) {
 					for (long k = i; k <= p; k ++) {
 						t -> data [k] [i] = t -> data [i] [k] /= no - 1;
diff --git a/dwtools/ICA.cpp b/dwtools/ICA.cpp
index 12a1fc8..4b3512f 100644
--- a/dwtools/ICA.cpp
+++ b/dwtools/ICA.cpp
@@ -474,7 +474,7 @@ autoCrossCorrelationTable Sound_to_CrossCorrelationTable (Sound me, double start
 			startTime = my xmin;
 			endTime = my xmax;
 		}
-		long lag = (long) floor (lagStep / my dx);   // ppgb: voor al dit soort dingen geldt: waarom afronden naar beneden?
+		integer lag = Melder_iroundDown (lagStep / my dx);   // ppgb: voor al dit soort dingen geldt: waarom afronden naar beneden?
 		long i1 = Sampled_xToNearestIndex (me, startTime);
 		if (i1 < 1) {
 			i1 = 1;
@@ -513,7 +513,7 @@ autoCrossCorrelationTable Sounds_to_CrossCorrelationTable_combined (Sound me, So
 			relativeStartTime = my xmin;
 			relativeEndTime = my xmax;
 		}
-		long ndelta = (long) floor (lagStep / my dx), nchannels = my ny + thy ny;
+		integer ndelta = Melder_iroundDown (lagStep / my dx), nchannels = my ny + thy ny;
 		long i1 = Sampled_xToNearestIndex (me, relativeStartTime);
 		if (i1 < 1) {
 			i1 = 1;
diff --git a/dwtools/Intensity_extensions.cpp b/dwtools/Intensity_extensions.cpp
index fd9be84..93d0b4c 100644
--- a/dwtools/Intensity_extensions.cpp
+++ b/dwtools/Intensity_extensions.cpp
@@ -131,7 +131,7 @@ autoTextGrid Intensity_to_TextGrid_detectSilences (Intensity me, double silenceT
 
 autoIntensity IntensityTier_to_Intensity (IntensityTier me, double dt) {
 	try {
-		long nt = (long) floor ((my xmax - my xmin) / dt);
+		integer nt = Melder_iroundDown ((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 ++) {
diff --git a/dwtools/KlattGrid.cpp b/dwtools/KlattGrid.cpp
index 49fa8d1..03ec6a3 100644
--- a/dwtools/KlattGrid.cpp
+++ b/dwtools/KlattGrid.cpp
@@ -1106,7 +1106,7 @@ static autoSound PhonationGrid_PhonationTier_to_Sound_voiced (PhonationGrid me,
 			// Fill in the samples to the left of the current point.
 
 			long midSample = Sampled_xToLowIndex (him.get(), t), beginSample;
-			beginSample = midSample - (long) floor (te / his dx);
+			beginSample = midSample - Melder_iroundDown (te / his dx);
 			if (beginSample < 1) {
 				beginSample = 0;
 			}
@@ -1147,7 +1147,7 @@ static autoSound PhonationGrid_PhonationTier_to_Sound_voiced (PhonationGrid me,
 				double ta = collisionPhase * (period * openPhase);
 				double factorPerSample = exp (- his dx / ta);
 				double value = flow * exp (- (his x1 + midSample * his dx - t) / ta);
-				long endSample = midSample + (long) floor (20.0 * ta / his dx);
+				integer endSample = midSample + Melder_iroundDown (20.0 * ta / his dx);
 				if (endSample > his nx) {
 					endSample = his nx;
 				}
@@ -2884,8 +2884,8 @@ autoKlattGrid KlattTable_to_KlattGrid (KlattTable me, double frameDuration) {
 	try {
 		Table kt = (Table) me;
 
-		long nrows = my rows.size;
-		double tmin = 0, tmax = nrows * frameDuration;
+		long numberOfRows = my rows.size;
+		double tmin = 0, tmax = numberOfRows * frameDuration;
 		double dBNul = -300;
 		double dB_offset = -20.0 * log10 (2.0e-5) - 87.0; // in KlattTable maximum in DB_to_LIN is at 87 dB : 32767
 		double dB_offset_voicing = 20.0 * log10 (320000 / 32767); // V'[n] in range (-320000,32000)
@@ -2903,7 +2903,7 @@ autoKlattGrid KlattTable_to_KlattGrid (KlattTable me, double frameDuration) {
 		autoKlattGrid thee = KlattGrid_create (tmin, tmax, numberOfFormants, numberOfNasalFormants,
 		                                       numberOfNasalAntiFormants, numberOfTrachealFormants, numberOfTrachealAntiFormants,
 		                                       numberOfFricationFormants, numberOfDeltaFormants);
-		for (long irow = 1; irow <= nrows; irow++) {
+		for (long irow = 1; irow <= numberOfRows; irow++) {
 			double t = (irow - 1) * frameDuration;
 
 			long icol = 1;
diff --git a/dwtools/KlattTable.cpp b/dwtools/KlattTable.cpp
index 2bee17b..ce0036e 100644
--- a/dwtools/KlattTable.cpp
+++ b/dwtools/KlattTable.cpp
@@ -501,7 +501,7 @@ static KlattGlobal KlattGlobal_create (double samplingFrequency) {
 	try {
 		me = (KlattGlobal) _Melder_calloc_f (1, sizeof (struct structKlattGlobal));
 
-		my samrate = (long) floor (samplingFrequency);
+		my samrate = Melder_iroundDown (samplingFrequency);
 		double dT = 1.0 / my samrate;
 
 		for (long i = 1; i <= 8; i++) {
@@ -535,7 +535,7 @@ static void KlattGlobal_init (KlattGlobal me, int synthesisModel, int numberOfFo
 		-1891, -1045, -1600, -1462, -1384, -1261, -949, -730
 	};
 
-	my nspfr = (long) floor (my samrate * frameDuration); /* average number of samples per frame */
+	my nspfr = Melder_iroundDown (my samrate * frameDuration); /* average number of samples per frame */
 	my synthesis_model = synthesisModel;
 	my nfcascade = numberOfFormants;
 	my glsource = glottalSource;
@@ -545,8 +545,8 @@ static void KlattGlobal_init (KlattGlobal me, int synthesisModel, int numberOfFo
 	my outsl = outputType;
 	my f0_flutter = flutter;
 
-	my FLPhz = (long) floor (0.0950 * my samrate); // depends on samplingFrequency ????
-	my BLPhz = (long) floor (0.0630 * my samrate);
+	my FLPhz = Melder_iroundDown (0.0950 * my samrate); // depends on samplingFrequency ????
+	my BLPhz = Melder_iroundDown (0.0630 * my samrate);
 	Filter_setFB (my rlp.get(), my FLPhz, my BLPhz);
 }
 
@@ -561,7 +561,7 @@ static void KlattFrame_free (KlattFrame me) {
 autoKlattTable KlattTable_create (double frameDuration, double totalDuration) {
 	try {
 		autoKlattTable me = Thing_new (KlattTable);
-		long nrows = (long) floor (totalDuration / frameDuration) + 1;
+		integer nrows = Melder_iroundDown (totalDuration / frameDuration) + 1;
 		Table_initWithColumnNames (me.get(), nrows, columnNames);
 		return me;
 	} catch (MelderError) {
@@ -702,7 +702,7 @@ static double KlattGlobal_sampled_source (KlattGlobal me) {   // ppgb: dit was e
 	if (my T0 != 0) {
 		double ftemp = my nper;
 		ftemp *= my num_samples / my T0;
-		long itemp = (long) floor (ftemp);
+		integer itemp = Melder_iroundDown (ftemp);
 
 		double temp_diff = ftemp - itemp;
 
@@ -795,7 +795,7 @@ static void KlattGlobal_pitch_synch_par_reset (KlattGlobal me) {
 		my T0 = (40 * my samrate) / my F0hz10;
 
 
-		my amp_voice = DBtoLIN ((long) floor (my AVdb));
+		my amp_voice = DBtoLIN (Melder_iroundDown (my AVdb));
 
 		/* Duration of period before amplitude modulation */
 
@@ -806,7 +806,7 @@ static void KlattGlobal_pitch_synch_par_reset (KlattGlobal me) {
 
 		/* Breathiness of voicing waveform */
 
-		my amp_breth = DBtoLIN ((long) floor (my Aturb)) * 0.1;
+		my amp_breth = DBtoLIN (Melder_iroundDown (my Aturb)) * 0.1;
 
 		/* Set open phase of glottal period where  40 <= open phase <= 263 */
 
@@ -1142,9 +1142,9 @@ autoSound KlattTable_to_Sound (KlattTable me, double samplingFrequency, int synt
 		thee = KlattGlobal_create (samplingFrequency);
 		frame = KlattFrame_create ();
 		autoNUMvector <short> iwave ((integer) 0, MAX_SAM);
-		thy samrate = (long) floor (samplingFrequency);
+		thy samrate = Melder_iroundDown (samplingFrequency);
 
-		KlattGlobal_init (thee, synthesisModel, numberOfFormants, glottalSource, frameDuration, (long) floor (flutter), outputType);
+		KlattGlobal_init (thee, synthesisModel, numberOfFormants, glottalSource, frameDuration, Melder_iroundDown (flutter), outputType);
 
 		autoSound him = Sound_createSimple (1, frameDuration * my rows.size, samplingFrequency);
 
diff --git a/dwtools/LongSound_extensions.cpp b/dwtools/LongSound_extensions.cpp
index 2b8813c..4ec551f 100644
--- a/dwtools/LongSound_extensions.cpp
+++ b/dwtools/LongSound_extensions.cpp
@@ -93,7 +93,7 @@ void LongSounds_writeToStereoAudioFile16 (LongSound me, LongSound thee, int audi
 		autoNUMvector<short> buffer (1, nchannels * nbuf);
 
 		autoMelderFile f  = MelderFile_create (file);
-		MelderFile_writeAudioFileHeader (file, audioFileType, (long) floor (my sampleRate), nx, nchannels, numberOfBitsPerSamplePoint);
+		MelderFile_writeAudioFileHeader (file, audioFileType, Melder_iroundDown (my sampleRate), nx, nchannels, numberOfBitsPerSamplePoint);
 
 		for (long i = 1; i <= numberOfReads; i++) {
 			long n_to_write = i == numberOfReads ? (nx - 1) % nbuf + 1 : nbuf;
@@ -102,7 +102,7 @@ void LongSounds_writeToStereoAudioFile16 (LongSound me, LongSound thee, int audi
 			MelderFile_writeShortToAudio (file, nchannels, Melder_defaultAudioFileEncoding (audioFileType,
                 numberOfBitsPerSamplePoint), buffer.peek(), n_to_write);
 		}
-		MelderFile_writeAudioFileTrailer (file, audioFileType, (long) floor (my sampleRate), nx, nchannels, numberOfBitsPerSamplePoint);
+		MelderFile_writeAudioFileTrailer (file, audioFileType, Melder_iroundDown (my sampleRate), nx, nchannels, numberOfBitsPerSamplePoint);
 		f.close ();
 	} catch (MelderError) {
 		Melder_throw (me, U": no stereo audio file created.");
@@ -207,13 +207,13 @@ void LongSounds_appendToExistingSoundFile (OrderedOf<structSampled>* me, MelderF
 
 		// Check whether all the sampling frequencies and channels match.
 
-		long sampleRate = (long) floor (sampleRate_d);
+		integer sampleRate = Melder_iroundDown (sampleRate_d);
 		for (long i = 1; i <= my size; i ++) {
 			bool sampleRatesMatch, numbersOfChannelsMatch;
 			Sampled data = my at [i];
 			if (data -> classInfo == classSound) {
 				Sound sound = (Sound) data;
-				sampleRatesMatch = floor (1.0 / sound -> dx + 0.5) == sampleRate;
+				sampleRatesMatch = Melder_iround_tieUp (1.0 / sound -> dx) == sampleRate;
 				numbersOfChannelsMatch = sound -> ny == numberOfChannels;
 				numberOfSamples += sound -> nx;
 			} else {
diff --git a/dwtools/MFCC.cpp b/dwtools/MFCC.cpp
index c80d4e2..fb5cde9 100644
--- a/dwtools/MFCC.cpp
+++ b/dwtools/MFCC.cpp
@@ -158,7 +158,7 @@ static double CC_Frames_distance (CC_Frame me, CC_Frame thee, bool includeEnergy
  */
 autoMatrix MFCC_to_Matrix_features (MFCC me, double windowLength, bool includeEnergy) {
 	try {
-		long nw = (long) floor (windowLength / my dx / 2);
+		integer nw = Melder_iroundDown (windowLength / my dx / 2.0);
 		autoMelSpectrogram him = MFCC_to_MelSpectrogram (me, 0, 0, 1);
 		autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, 1, 4, 4, 1, 1);
 		thy z[1][1] = thy z[1][my nx] = 0;  // first & last frame
diff --git a/dwtools/Matrix_extensions.cpp b/dwtools/Matrix_extensions.cpp
index c042c01..eff56df 100644
--- a/dwtools/Matrix_extensions.cpp
+++ b/dwtools/Matrix_extensions.cpp
@@ -225,11 +225,12 @@ void Matrix_drawDistribution (Matrix me, Graphics g, double xmin, double xmax, d
 	autoNUMvector<long> freq (1, nBins);
 	double binWidth = (maximum - minimum) / nBins;
 	long nxy = 0;
-	for (long i = iymin; i <= iymax; i++) {
-		for (long j = ixmin; j <= ixmax; j++) {
-			long bin = 1 + (long) floor ( (my z[i][j] - minimum) / binWidth);
+	for (long i = iymin; i <= iymax; i ++) {
+		for (long j = ixmin; j <= ixmax; j ++) {
+			integer bin = 1 + Melder_iroundDown ((my z [i] [j] - minimum) / binWidth);
 			if (bin <= nBins && bin > 0) {
-				freq[bin]++; nxy ++;
+				freq [bin] ++;
+				nxy ++;
 			}
 		}
 	}
diff --git a/dwtools/Pitch_extensions.cpp b/dwtools/Pitch_extensions.cpp
index 041fa39..600d7ec 100644
--- a/dwtools/Pitch_extensions.cpp
+++ b/dwtools/Pitch_extensions.cpp
@@ -187,7 +187,7 @@ autoPitch PitchTier_to_Pitch (PitchTier me, double dt, double pitchFloor, double
 			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.0;
-		long nt = (long) floor ((tmax - tmin - t1) / dt);
+		integer nt = Melder_iroundDown ((tmax - tmin - t1) / dt);
 		if (t1 + nt * dt < tmax) {
 			nt ++;
 		}
diff --git a/dwtools/Polynomial.cpp b/dwtools/Polynomial.cpp
index 15faf5d..f0813d8 100644
--- a/dwtools/Polynomial.cpp
+++ b/dwtools/Polynomial.cpp
@@ -1223,7 +1223,7 @@ autoRoots Polynomial_to_Roots (Polynomial me) {
 				Melder_throw (U"Programming error. Argument ", info, U" in NUMlapack_dhseqr has illegal value.");
 			}
 		}
-		lwork = (integer) floor (wt[0]);
+		lwork = Melder_iroundDown (wt[0]);
 		autoNUMvector <double> work (1, lwork);
 
 		// Find eigenvalues.
diff --git a/dwtools/SPINET_to_Pitch.cpp b/dwtools/SPINET_to_Pitch.cpp
index 459d43b..3cb5fce 100644
--- a/dwtools/SPINET_to_Pitch.cpp
+++ b/dwtools/SPINET_to_Pitch.cpp
@@ -38,8 +38,8 @@ autoPitch SPINET_to_Pitch (SPINET me, double harmonicFallOffSlope, double ceilin
 		double fminl2 = NUMlog2 (fmin), fmaxl2 = NUMlog2 (fmax);
 		double points = (fmaxl2 - fminl2) * nPointsPerOctave;
 		double dfl2 = (fmaxl2 - fminl2) / (points - 1);
-		long nFrequencyPoints = (long) floor (points);
-		long maxHarmonic = (long) floor (fmax / fmin);
+		integer nFrequencyPoints = Melder_iroundDown (points);
+		integer maxHarmonic = Melder_iroundDown (fmax / fmin);
 		double maxStrength = 0.0, unvoicedCriterium = 0.45, maxPower = 0.0;
 
 		if (nFrequencyPoints < 2) {
@@ -98,7 +98,7 @@ autoPitch SPINET_to_Pitch (SPINET me, double harmonicFallOffSlope, double ceilin
 
 			for (long m = 1; m <= maxHarmonic; m++) {
 				double hm = 1 - harmonicFallOffSlope * NUMlog2 (m);
-				long kb = 1 + (long) floor (nPointsPerOctave * NUMlog2 (m));
+				integer kb = 1 + Melder_iroundDown (nPointsPerOctave * NUMlog2 (m));
 				for (long k = kb; k <= nFrequencyPoints; k++) {
 					if (pitch[k] > 0.0) {
 						sumspec[k - kb + 1] += pitch[k] * hm;
diff --git a/dwtools/SSCP.cpp b/dwtools/SSCP.cpp
index e81f83e..b4113dc 100644
--- a/dwtools/SSCP.cpp
+++ b/dwtools/SSCP.cpp
@@ -108,7 +108,7 @@ void structSSCP :: v_info () {
 	be multiplied to obtain the length of an ellipse axis.
 */
 double SSCP_getEllipseScalefactor (SSCP me, double scale, bool confidence) {
-	long n = (long) floor (SSCP_getNumberOfObservations (me));
+	integer n = Melder_iroundDown (SSCP_getNumberOfObservations (me));
 
 	if (confidence) {
 		long p = my numberOfColumns;
@@ -496,7 +496,7 @@ void Covariance_and_PCA_generateOneVector (Covariance me, PCA thee, double *vec,
 autoTableOfReal Covariance_to_TableOfReal_randomSampling (Covariance me, long numberOfData) {
 	try {
 		if (numberOfData <= 0) {
-			numberOfData = (long) floor (my numberOfObservations);
+			numberOfData = Melder_iroundDown (my numberOfObservations);
 		}
 		autoPCA pca = SSCP_to_PCA (me);
 		autoTableOfReal thee = TableOfReal_create (numberOfData, my numberOfColumns);
@@ -765,7 +765,7 @@ autoPCA SSCP_to_PCA (SSCP me) {
 		NUMstrings_copyElements (my columnLabels, thy labels, 1, my numberOfColumns);
 		Eigen_initFromSymmetricMatrix (thee.get(), data, my numberOfColumns);
 		NUMvector_copyElements (my centroid, thy centroid, 1, my numberOfColumns);
-		PCA_setNumberOfObservations (thee.get(), (long) floor (my numberOfObservations));
+		PCA_setNumberOfObservations (thee.get(), Melder_iroundDown (my numberOfObservations));
 		return thee;
 	} catch (MelderError) {
 		Melder_throw (me, U": PCA not created.");
@@ -929,7 +929,7 @@ autoCCA SSCP_to_CCA (SSCP me, integer ny) {
 		NUMnormalizeRows (thy y -> eigenvectors, thy y -> numberOfEigenvalues, thy y -> numberOfEigenvalues, 1);
 
 		thy numberOfCoefficients = thy y -> numberOfEigenvalues;
-		thy numberOfObservations = (long) floor (my numberOfObservations);
+		thy numberOfObservations = Melder_iroundDown (my numberOfObservations);
 
 		// x = Sxx**-1 * Syx' * y
 
@@ -1469,9 +1469,9 @@ void Covariance_getMarginalDensityParameters (Covariance me, double v[], double
 }
 
 double Covariances_getMultivariateCentroidDifference (Covariance me, Covariance thee, int equalCovariances, double *p_prob, double *p_fisher, double *p_df1, double *p_df2) {
-	long p = my numberOfRows, N = (long) floor (my numberOfObservations + thy numberOfObservations);
-	long N1 = (long) floor (my numberOfObservations), n1 = N1 - 1;
-	long N2 = (long) floor (thy numberOfObservations), n2 = N2 - 1;
+	integer p = my numberOfRows, N = Melder_iroundDown (my numberOfObservations + thy numberOfObservations);
+	integer N1 = Melder_iroundDown (my numberOfObservations), n1 = N1 - 1;
+	integer N2 = Melder_iroundDown (thy numberOfObservations), n2 = N2 - 1;
 
 	double dif = undefined, fisher = undefined;
 	double df1 = p, df2 = N - p - 1;
@@ -1652,7 +1652,7 @@ void Covariances_equality (CovarianceList me, int method, double *p_prob, double
 
 void Covariance_difference (Covariance me, Covariance thee, double *p_prob, double *p_chisq, double *p_df) {
 	long p = my numberOfRows;
-	long numberOfObservations = (long) floor (my numberOfObservations);
+	integer numberOfObservations = Melder_iroundDown (my numberOfObservations);
 	double  ln_me, ln_thee;
 	double chisq = undefined, df = undefined;
 	
@@ -1660,7 +1660,7 @@ void Covariance_difference (Covariance me, Covariance thee, double *p_prob, doub
 		Melder_throw (U"Matrices must have equal dimensions.");
 	}
 	if (my numberOfObservations != thy numberOfObservations) {
-		numberOfObservations = (long) floor (my numberOfObservations > thy numberOfObservations ?
+		numberOfObservations = Melder_iroundDown (my numberOfObservations > thy numberOfObservations ?
 		                        thy numberOfObservations : my numberOfObservations) - 1;
 		Melder_warning (U"Covariance_difference: number of observations of matrices do not agree.\n"
 		                U" The minimum  size (", numberOfObservations, U") of the two is used.");
@@ -1745,7 +1745,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);
+	integer n = Melder_iroundDown (my numberOfObservations);
 
 	double prob = undefined, t = undefined;
 	double df = 2.0 * (n - 1);
diff --git a/dwtools/Sound_and_MixingMatrix.cpp b/dwtools/Sound_and_MixingMatrix.cpp
index 51f1fd7..f43f5b4 100644
--- a/dwtools/Sound_and_MixingMatrix.cpp
+++ b/dwtools/Sound_and_MixingMatrix.cpp
@@ -1,140 +1,140 @@
-/* Sound_and_MixingMatrix.cpp
- *
- * Copyright (C) 2010-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 "Sound_and_MixingMatrix.h"
-
-void Sound_and_MixingMatrix_playPart (Sound me, MixingMatrix thee, double fromTime, double toTime, Sound_PlayCallback callback, Thing boss) {
-	try {
-		autoSound mix = Sound_and_MixingMatrix_mixPart (me, thee, fromTime, toTime);
-		Sound_playPart (mix.get(), fromTime, toTime, callback, boss);
-	} catch (MelderError) {
-		Melder_throw (me, U": not played.");
-	}
-}
-
-void Sound_and_MixingMatrix_play (Sound me, MixingMatrix thee, Sound_PlayCallback callback, Thing boss) {
-	Sound_and_MixingMatrix_playPart (me, thee, my xmin, my xmax, callback, boss);
-}
-
-autoSound Sound_and_MixingMatrix_mix (Sound me, MixingMatrix thee) {
-	return Sound_and_MixingMatrix_mixPart (me, thee, my xmin, my xmax);
-}
-
-autoSound Sound_and_MixingMatrix_mixPart (Sound me, MixingMatrix thee, double fromTime, double toTime) {
-	try {
-		if (my ny != thy numberOfColumns) {
-			Melder_throw (U"The number of inputs in the MixingMatrix and the number of channels in the Sound must be equal.");
-		}
-		if (fromTime == toTime) { 
-			fromTime = my xmin; toTime = my xmax; 
-		}
-	
-		// Determine index range. We use all the real or virtual samples that fit within [fromTime..toTime].
-
-		long ix1 = 1 + (long) ceil ((fromTime - my x1) / my dx);
-		long ix2 = 1 + (long) floor ((toTime - my x1) / my dx);
-		if (ix2 < ix1) {
-			Melder_throw (U"Mixed Sound would contain no samples.");
-		}
-
-		autoSound him = Sound_create (thy numberOfRows, fromTime, toTime, ix2 - ix1 + 1, my dx, my x1 + (ix1 - 1) * my dx);
-		/*
-		*      1          nx                             1          nx
-		*      |..........|                              |..........|                 (me)
-		*  |-----------|---|                                |-----|----------|        (index in me)
-		* ix1         ix2  ix2                              ix1   ix2        ix2
-		* 1           'nx' 'nx'
-		* Example:   (1)     (2)                                  (3)        (4)
-		* New sound: him_nx = ix2 - ix1 + 1
-		* Example: nx = 12
-		* (1) copy from [1,  ix2] to [2-ix1, 1 - ix1 + ix2]
-		*		ix1=-3, ix2=8 [1,8] -> [5,12] 
-		* (2) copy from [1,   nx] to [2-ix1, 1 - ix1 +  nx]
-		* 		ix1=-3, ix2=13 [1,12] -> [5,16] 
-		* (3) copy from [ix1,ix2] to [1    , ix2  -ix1 + 1]
-		* 		ix1=4, ix2=10 [4,10] -> [1,7]
-		* (4) copy from [ix1, nx] to [1    , nx -ix1 + 1]
-		* 		ix1=4, ix2=21 [4,12] -> [1,9]
-		*/
-		if (! (toTime < my xmin || fromTime > my xmax)) {
-			for (long i = 1; i <= thy numberOfRows; i++) {
-				for (long ichan = 1; ichan <= my ny; ichan ++) {
-					double mixingCoeffient = thy data [i][ichan];
-					if (mixingCoeffient != 0.0) {
-						double *from = my z [ichan], *to = his z[i];
-						long to_i1 = 1, to_i2 = his nx;
-						if (ix1 < 1) { // (1) + (2)
-							to = his z[i] + 1 - ix1;
-							to_i1 = 1 - ix1; to_i2 = to_i1 + my nx; // (2)
-							if (ix2 < my nx) { // (1)
-								to_i2 = 1 - ix1 + ix2;
-							}
-						} else { // (3) + (4)
-							from = my z [ichan] + ix1 - 1; 
-							to_i2 = to_i1 + ix2 - ix1; // (3)
-							if (ix2 > my nx) { // (4)
-								to_i2 = his nx;
-							}
-						}
-						for (long j = 1; j <= to_i2 - to_i1 + 1; j++) {
-							to [j] += mixingCoeffient * from [j];
-						}
-					}
-				}
-			}
-		}
-		return him;
-	} catch (MelderError) {
-		Melder_throw (me, U": not mixed.");
-	}
-}
-
-autoSound Sound_and_MixingMatrix_unmix (Sound me, MixingMatrix thee) {
-	try {
-		if (my ny != thy numberOfRows) {
-			Melder_throw (U"The MixingMatrix and the Sound must have the same number of channels.");
-		}
-
-		autoNUMmatrix<double> minv (1, thy numberOfColumns, 1, thy numberOfRows);
-		NUMpseudoInverse (thy data, thy numberOfRows, thy numberOfColumns, minv.peek(), 0);
-		autoSound him = Sound_create (thy numberOfColumns, my xmin, my xmax, my nx, my dx, my x1);
-		for (long i = 1; i <= thy numberOfColumns; i++) {
-			for (long j = 1; j <= my nx; j++) {
-				double s = 0;
-				for (long k = 1; k <= my ny; k++) {
-					s += minv[i][k] * my z[k][j];
-				}
-				his z[i][j] = s;
-			}
-		}
-		return him;
-	} catch (MelderError) {
-		Melder_throw (me, U": not unmixed.");
-	}
-}
-
-#if 0
-// TODO
-void LongSound_and_MixingMatrix_playPart (LongSound me, MixingMatrix thee, double fromTime, double toTime, Sound_PlayCallback callback, Thing boss) {
-	
-}
-#endif
-
-/* End of file Sound_and_MixingMatrix.cpp */
+/* Sound_and_MixingMatrix.cpp
+ *
+ * Copyright (C) 2010-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 "Sound_and_MixingMatrix.h"
+
+void Sound_and_MixingMatrix_playPart (Sound me, MixingMatrix thee, double fromTime, double toTime, Sound_PlayCallback callback, Thing boss) {
+	try {
+		autoSound mix = Sound_and_MixingMatrix_mixPart (me, thee, fromTime, toTime);
+		Sound_playPart (mix.get(), fromTime, toTime, callback, boss);
+	} catch (MelderError) {
+		Melder_throw (me, U": not played.");
+	}
+}
+
+void Sound_and_MixingMatrix_play (Sound me, MixingMatrix thee, Sound_PlayCallback callback, Thing boss) {
+	Sound_and_MixingMatrix_playPart (me, thee, my xmin, my xmax, callback, boss);
+}
+
+autoSound Sound_and_MixingMatrix_mix (Sound me, MixingMatrix thee) {
+	return Sound_and_MixingMatrix_mixPart (me, thee, my xmin, my xmax);
+}
+
+autoSound Sound_and_MixingMatrix_mixPart (Sound me, MixingMatrix thee, double fromTime, double toTime) {
+	try {
+		if (my ny != thy numberOfColumns) {
+			Melder_throw (U"The number of inputs in the MixingMatrix and the number of channels in the Sound must be equal.");
+		}
+		if (fromTime == toTime) { 
+			fromTime = my xmin; toTime = my xmax; 
+		}
+	
+		// Determine index range. We use all the real or virtual samples that fit within [fromTime..toTime].
+
+		long ix1 = 1 + (long) ceil ((fromTime - my x1) / my dx);
+		integer ix2 = 1 + Melder_iroundDown ((toTime - my x1) / my dx);
+		if (ix2 < ix1) {
+			Melder_throw (U"Mixed Sound would contain no samples.");
+		}
+
+		autoSound him = Sound_create (thy numberOfRows, fromTime, toTime, ix2 - ix1 + 1, my dx, my x1 + (ix1 - 1) * my dx);
+		/*
+		*      1          nx                             1          nx
+		*      |..........|                              |..........|                 (me)
+		*  |-----------|---|                                |-----|----------|        (index in me)
+		* ix1         ix2  ix2                              ix1   ix2        ix2
+		* 1           'nx' 'nx'
+		* Example:   (1)     (2)                                  (3)        (4)
+		* New sound: him_nx = ix2 - ix1 + 1
+		* Example: nx = 12
+		* (1) copy from [1,  ix2] to [2-ix1, 1 - ix1 + ix2]
+		*		ix1=-3, ix2=8 [1,8] -> [5,12] 
+		* (2) copy from [1,   nx] to [2-ix1, 1 - ix1 +  nx]
+		* 		ix1=-3, ix2=13 [1,12] -> [5,16] 
+		* (3) copy from [ix1,ix2] to [1    , ix2  -ix1 + 1]
+		* 		ix1=4, ix2=10 [4,10] -> [1,7]
+		* (4) copy from [ix1, nx] to [1    , nx -ix1 + 1]
+		* 		ix1=4, ix2=21 [4,12] -> [1,9]
+		*/
+		if (! (toTime < my xmin || fromTime > my xmax)) {
+			for (long i = 1; i <= thy numberOfRows; i++) {
+				for (long ichan = 1; ichan <= my ny; ichan ++) {
+					double mixingCoeffient = thy data [i][ichan];
+					if (mixingCoeffient != 0.0) {
+						double *from = my z [ichan], *to = his z[i];
+						long to_i1 = 1, to_i2 = his nx;
+						if (ix1 < 1) { // (1) + (2)
+							to = his z[i] + 1 - ix1;
+							to_i1 = 1 - ix1; to_i2 = to_i1 + my nx; // (2)
+							if (ix2 < my nx) { // (1)
+								to_i2 = 1 - ix1 + ix2;
+							}
+						} else { // (3) + (4)
+							from = my z [ichan] + ix1 - 1; 
+							to_i2 = to_i1 + ix2 - ix1; // (3)
+							if (ix2 > my nx) { // (4)
+								to_i2 = his nx;
+							}
+						}
+						for (long j = 1; j <= to_i2 - to_i1 + 1; j++) {
+							to [j] += mixingCoeffient * from [j];
+						}
+					}
+				}
+			}
+		}
+		return him;
+	} catch (MelderError) {
+		Melder_throw (me, U": not mixed.");
+	}
+}
+
+autoSound Sound_and_MixingMatrix_unmix (Sound me, MixingMatrix thee) {
+	try {
+		if (my ny != thy numberOfRows) {
+			Melder_throw (U"The MixingMatrix and the Sound must have the same number of channels.");
+		}
+
+		autoNUMmatrix<double> minv (1, thy numberOfColumns, 1, thy numberOfRows);
+		NUMpseudoInverse (thy data, thy numberOfRows, thy numberOfColumns, minv.peek(), 0);
+		autoSound him = Sound_create (thy numberOfColumns, my xmin, my xmax, my nx, my dx, my x1);
+		for (long i = 1; i <= thy numberOfColumns; i++) {
+			for (long j = 1; j <= my nx; j++) {
+				double s = 0;
+				for (long k = 1; k <= my ny; k++) {
+					s += minv[i][k] * my z[k][j];
+				}
+				his z[i][j] = s;
+			}
+		}
+		return him;
+	} catch (MelderError) {
+		Melder_throw (me, U": not unmixed.");
+	}
+}
+
+#if 0
+// TODO
+void LongSound_and_MixingMatrix_playPart (LongSound me, MixingMatrix thee, double fromTime, double toTime, Sound_PlayCallback callback, Thing boss) {
+	
+}
+#endif
+
+/* End of file Sound_and_MixingMatrix.cpp */
diff --git a/dwtools/Sound_extensions.cpp b/dwtools/Sound_extensions.cpp
index c03d01c..276d8d6 100644
--- a/dwtools/Sound_extensions.cpp
+++ b/dwtools/Sound_extensions.cpp
@@ -237,7 +237,7 @@ static void u4write (Sound me, FILE *f, int littleEndian, long *nClip) {
 	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);
+		double sample = Melder_round_tieUp (s[i] * 4294967295.0);
 		if (sample > max) {
 			sample = max;
 			(*nClip) ++;
@@ -614,7 +614,7 @@ static autoSound Sound_createToneComplex (double minimumTime, double maximumTime
 autoSound Sound_createSimpleToneComplex (double minimumTime, double maximumTime, double samplingFrequency, double firstFrequency, long numberOfComponents, double frequencyDistance, int scaleAmplitudes) {
 	if (firstFrequency + (numberOfComponents - 1) * frequencyDistance > samplingFrequency / 2) {
 		Melder_warning (U"Sound_createSimpleToneComplex: frequency of (some) components too high.");
-		numberOfComponents = (long) floor (1.0 + (samplingFrequency / 2 - firstFrequency) / frequencyDistance);
+		numberOfComponents = Melder_iroundDown (1.0 + (0.5 * samplingFrequency - firstFrequency) / frequencyDistance);
 	}
 	return Sound_createToneComplex (minimumTime, maximumTime, samplingFrequency,
 	                                firstFrequency, numberOfComponents, frequencyDistance, 0, 0, scaleAmplitudes);
@@ -623,7 +623,7 @@ autoSound Sound_createSimpleToneComplex (double minimumTime, double maximumTime,
 autoSound Sound_createMistunedHarmonicComplex (double minimumTime, double maximumTime, double samplingFrequency, double firstFrequency, long numberOfComponents, long mistunedComponent, double mistuningFraction, int scaleAmplitudes) {
 	if (firstFrequency + (numberOfComponents - 1) * firstFrequency > samplingFrequency / 2) {
 		Melder_warning (U"Sound_createMistunedHarmonicComplex: frequency of (some) components too high.");
-		numberOfComponents = (long) floor (1.0 + (samplingFrequency / 2 - firstFrequency) / firstFrequency);
+		numberOfComponents = Melder_iroundDown (1.0 + (0.5 * samplingFrequency - firstFrequency) / firstFrequency);
 	}
 	if (mistunedComponent > numberOfComponents) {
 		Melder_warning (U"Sound_createMistunedHarmonicComplex: mistuned component too high.");
@@ -1075,7 +1075,7 @@ double Sound_correlateParts (Sound me, double tx, double ty, double duration) {
 	long nby = Sampled_xToNearestIndex (me, ty);
 	long ney = Sampled_xToNearestIndex (me, ty + duration);
 
-	long increment = 0, decrement = 0;
+	integer increment = 0, decrement = 0;
 	if (nbx < 1) {
 		increment = 1 - nbx;
 	}
@@ -1083,25 +1083,28 @@ double Sound_correlateParts (Sound me, double tx, double ty, double duration) {
 		decrement = ney - my nx;
 	}
 
-	long ns = (long) floor (duration / my dx) - increment - decrement;
+	integer ns = Melder_iroundDown (duration / my dx) - increment - decrement;
 	if (ns < 1) {
-		return 0;
+		return 0.0;
 	}
 
-	double *x = & my z[1][nbx + increment - 1];
-	double *y = & my z[1][nby + increment - 1];
-	double xm = 0, ym = 0, sxx = 0, syy = 0, sxy = 0;
-	for (long i = 1; i <= ns; i++) {
-		xm += x[i];
-		ym += y[i];
+	double *x = & my z [1] [nbx + increment - 1];
+	double *y = & my z [1] [nby + increment - 1];
+	double xm = 0.0, ym = 0.0, sxx = 0.0, syy = 0.0, sxy = 0.0;
+	for (long i = 1; i <= ns; i ++) {
+		xm += x [i];
+		ym += y [i];
 	}
-	xm /= ns; ym /= ns;
+	xm /= ns;
+	ym /= ns;
 	for (long i = 1; i <= ns; i++) {
 		double xt = x[i] - xm, yt = y[i] - ym;
-		sxx += xt * xt; syy += yt * yt; sxy += xt * yt;
+		sxx += xt * xt;
+		syy += yt * yt;
+		sxy += xt * yt;
 	}
 	double denum = sxx * syy;
-	double rxy = denum > 0 ? sxy / sqrt (denum) : 0;
+	double rxy = denum > 0.0 ? sxy / sqrt (denum) : 0.0;
 	return rxy;
 }
 
@@ -1250,7 +1253,7 @@ void Sound_filter_part_formula (Sound me, double t1, double t2, const char32 *fo
 autoPointProcess Sound_to_PointProcess_getJumps (Sound me, double minimumJump, double dt) {
 	try {
 		autoPointProcess thee = PointProcess_create (my xmin, my xmax, 10);
-		long i = 1, dtn = (long) floor (dt / my dx);
+		integer i = 1, dtn = Melder_iroundDown (dt / my dx);
 		if (dtn < 1) {
 			dtn = 1;
 		}
@@ -1661,7 +1664,7 @@ void Sound_draw_btlr (Sound me, Graphics g, double tmin, double tmax, double ami
 }
 
 void Sound_fade (Sound me, int channel, double t, double fadeTime, int inout, int fadeGlobal) {
-	long numberOfSamples = (long) floor (fabs (fadeTime) / my dx);
+	integer numberOfSamples = Melder_iroundDown (fabs (fadeTime) / my dx);
 	double t1 = t, t2 = t1 + fadeTime;
 	const char32 *fade_inout = inout > 0 ? U"out" : U"in";
 	if (channel < 0 || channel > my ny) {
diff --git a/dwtools/Sound_to_Pitch2.cpp b/dwtools/Sound_to_Pitch2.cpp
index 5a75e4c..2f6451b 100644
--- a/dwtools/Sound_to_Pitch2.cpp
+++ b/dwtools/Sound_to_Pitch2.cpp
@@ -97,7 +97,7 @@ autoPitch Sound_to_Pitch_shs (Sound me, double timeStep, double minimumPitch,
 			The number of points on the octave scale.
 		*/
 		double fminl2 = NUMlog2 (minimumPitch), fmaxl2 = NUMlog2 (maximumFrequency);
-		long nFrequencyPoints = (long) floor ((fmaxl2 - fminl2) * nPointsPerOctave);
+		integer nFrequencyPoints = Melder_iroundDown ((fmaxl2 - fminl2) * nPointsPerOctave);
 		double dfl2 = (fmaxl2 - fminl2) / (nFrequencyPoints - 1);
 
 		autoSound sound = Sound_resample (me, newSamplingFrequency, 50);
@@ -200,7 +200,7 @@ autoPitch Sound_to_Pitch_shs (Sound me, double timeStep, double minimumPitch,
 			pitchFrame -> nCandidates = 0; /* !!!!! */
 
 			for (long m = 1; m <= maxnSubharmonics + 1; m++) {
-				long kb = 1 + (long) floor (nPointsPerOctave * NUMlog2 (m));
+				integer kb = 1 + Melder_iroundDown (nPointsPerOctave * NUMlog2 (m));
 				for (long k = kb; k <= nFrequencyPoints; k++) {
 					sumspec[k - kb + 1] += al2[k] * hm;
 				}
diff --git a/dwtools/Spectrum_extensions.cpp b/dwtools/Spectrum_extensions.cpp
index f74d662..8d683b4 100644
--- a/dwtools/Spectrum_extensions.cpp
+++ b/dwtools/Spectrum_extensions.cpp
@@ -96,7 +96,7 @@ static void getSpectralValues (struct tribolet_struct *tbs, double freq_rad, dou
 
 static int phase_check (double pv, double *phase, double thlcon) {
 	double a0 = (*phase - pv) / NUM2pi;
-	long k = (long) floor (a0);   // ppgb: instead of truncation toward zero
+	integer k = Melder_iroundDown (a0);   // ppgb: instead of truncation toward zero
 	double a1 = pv + k * NUM2pi;
 	double a2 = a1 + SIGN (NUM2pi, a0);
 	double a3 = fabs (a1 - *phase);
@@ -214,7 +214,7 @@ autoMatrix Spectrum_unwrap (Spectrum me) {
 		tbs.thlcon = THLCON;
 		tbs.x = x -> z[1];
 		tbs.nx = x -> nx;
-		tbs.l = (long) floor (pow (2, EXP2) + 0.1);
+		tbs.l = Melder_iroundDown (pow (2, EXP2) + 0.1);
 		tbs.ddf = NUM2pi / ( (tbs.l) * nfft);
 		tbs.reverse_sign = my z[1][1] < 0;
 		tbs.count = 0;
@@ -250,7 +250,7 @@ autoMatrix Spectrum_unwrap (Spectrum me) {
 			                   U" unwrapped phases from ", my nx, U".");
 		}
 
-		long iphase = (long) floor (phase / NUMpi + 0.1);   // ppgb: better than truncation toward zero
+		integer iphase = Melder_iroundDown (phase / NUMpi + 0.1);   // ppgb: better than truncation toward zero
 
 		if (remove_linear_part) {
 			phase /= my nx - 1;
@@ -351,9 +351,9 @@ static autoSpectrum Spectrum_shiftFrequencies2 (Spectrum me, double shiftBy, boo
 autoSpectrum Spectrum_shiftFrequencies (Spectrum me, double shiftBy, double newMaximumFrequency, long interpolationDepth) {
 	try {
 		double xmax = my xmax;
-		long numberOfFrequencies = my nx;
-		if (newMaximumFrequency != 0) {
-			numberOfFrequencies = (long) floor (newMaximumFrequency / my dx) + 1;
+		integer numberOfFrequencies = my nx;
+		if (newMaximumFrequency != 0.0) {
+			numberOfFrequencies = Melder_iroundDown (newMaximumFrequency / my dx) + 1;
 			xmax = newMaximumFrequency;
 		}
 		autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies);
@@ -384,7 +384,7 @@ autoSpectrum Spectrum_compressFrequencyDomain (Spectrum me, double fmax, long in
 		double fdomain = my xmax - my xmin, factor = fdomain / fmax ;
 		//long numberOfFrequencies = 1.0 + fmax / my dx; // keep dx the same, otherwise the "duration" changes
 		double xmax = my xmax / factor;
-		long numberOfFrequencies = (long) floor (my nx / factor); // keep dx the same, otherwise the "duration" changes
+		integer numberOfFrequencies = Melder_iroundDown (my nx / factor); // keep dx the same, otherwise the "duration" changes
 		autoSpectrum thee = Spectrum_create (xmax, numberOfFrequencies);
 		thy z[1][1] = my z[1][1]; thy z[2][1] = my z[2][1];
 		double df = freqscale == 1 ? factor * my dx : log10 (fdomain) / (numberOfFrequencies - 1);
diff --git a/dwtools/SpeechSynthesizer_and_TextGrid.cpp b/dwtools/SpeechSynthesizer_and_TextGrid.cpp
index cd74035..6aa2711 100644
--- a/dwtools/SpeechSynthesizer_and_TextGrid.cpp
+++ b/dwtools/SpeechSynthesizer_and_TextGrid.cpp
@@ -488,7 +488,7 @@ autoTextGrid SpeechSynthesizer_and_Sound_and_TextInterval_align (SpeechSynthesiz
 			double wordsPerMinute_rawTokens = 60.0 * numberOfTokens / s_thee_duration;
 			// compensation for long words: 5 characters / word
 			double wordsPerMinute_rawText = 60.0 * (str32len (his text) / 5.0) / s_thee_duration;
-			my d_wordsPerMinute =  (long) floor (0.5 * (wordsPerMinute_rawTokens + wordsPerMinute_rawText));
+			my d_wordsPerMinute = Melder_iroundDown (0.5 * (wordsPerMinute_rawTokens + wordsPerMinute_rawText));
 		}
 		autoTextGrid tg2;
 		autoSound synth = SpeechSynthesizer_and_TextInterval_to_Sound (me, him, & tg2);
diff --git a/dwtools/TableOfReal_extensions.cpp b/dwtools/TableOfReal_extensions.cpp
index 934569e..62642f1 100644
--- a/dwtools/TableOfReal_extensions.cpp
+++ b/dwtools/TableOfReal_extensions.cpp
@@ -327,7 +327,7 @@ void TableOfReal_drawRowsAsHistogram (TableOfReal me, Graphics g, const char32 *
 	integer nrows;
 	autoNUMvector <real> irows (NUMstring_to_numbers (rows, & nrows), 1);
 	for (integer i = 1; i <= nrows; i ++) {
-		integer irow = (long) floor (irows [i]);
+		integer irow = Melder_iroundDown (irows [i]);
 		if (irow < 0 || irow > my numberOfRows) {
 			Melder_throw (U"Invalid row (", irow, U").");
 		}
@@ -358,7 +358,7 @@ void TableOfReal_drawRowsAsHistogram (TableOfReal me, Graphics g, const char32 *
 	double dx = (interbarsFraction + nrows + (nrows - 1) * interbarFraction) * bar_width;
 
 	for (long i = 1; i <= nrows; i++) {
-		long irow = (long) floor (irows[i]);
+		integer irow = Melder_iroundDown (irows[i]);
 		double xb = xoffsetFraction * bar_width + (i - 1) * (1.0 + interbarFraction) * bar_width;
 
 		double x1 = xb;
@@ -867,10 +867,10 @@ void TableOfReal_drawScatterPlot (TableOfReal me, Graphics g, long icx, long icy
 		rowb = 1;
 	}
 	if (rowe > m) {
-		rowe = (long) floor (m);
+		rowe = Melder_iroundDown (m);
 	}
 	if (rowe <= rowb) {
-		rowb = 1; rowe = (long) floor (m);
+		rowb = 1; rowe = Melder_iroundDown (m);
 	}
 
 	if (xmax == xmin) {
diff --git a/dwtools/VowelEditor.cpp b/dwtools/VowelEditor.cpp
index 6301845..ea74d64 100644
--- a/dwtools/VowelEditor.cpp
+++ b/dwtools/VowelEditor.cpp
@@ -351,7 +351,7 @@ static double VowelEditor_updateDurationInfo (VowelEditor me) {
 }
 
 static void Sound_fadeIn (Sound me, double duration, bool fromFirstNonZeroSample) {
-	long istart = 1, numberOfSamples = (long) floor (duration / my dx);   // ppgb: waarom afronden naar beneden?
+	integer istart = 1, numberOfSamples = Melder_iroundDown (duration / my dx);   // ppgb: waarom afronden naar beneden?
 
 	if (numberOfSamples < 2) {
 		return;
@@ -381,7 +381,7 @@ static void Sound_fadeIn (Sound me, double duration, bool fromFirstNonZeroSample
 }
 
 static void Sound_fadeOut (Sound me, double duration) {
-	long istart, numberOfSamples = (long) floor (duration / my dx);
+	integer istart, numberOfSamples = Melder_iroundDown (duration / my dx);
 
 	if (numberOfSamples < 2) {
 		return;
@@ -780,7 +780,7 @@ static void VowelEditor_drawBackground (VowelEditor me, Graphics g) {
 				VowelEditor_getXYFromF1F2 (me, f1, f2, &x1, &y1);
 				int size = prefs.marksFontSize;
 				if (col_fs != 0) {
-					size = (int) floor (Table_getNumericValue_Assert (my marks.get(), i, col_fs));
+					size = Melder_iroundDown (Table_getNumericValue_Assert (my marks.get(), i, col_fs));
 				}
 				Graphics_setFontSize (g, size);
 				Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
diff --git a/dwtools/praat_BSS_init.cpp b/dwtools/praat_BSS_init.cpp
index 6cc00e3..90fe286 100644
--- a/dwtools/praat_BSS_init.cpp
+++ b/dwtools/praat_BSS_init.cpp
@@ -435,7 +435,7 @@ FORM (NEW_Sound_to_Sound_whiteChannels, U"Sound: To Sound (white channels)", U"S
     OK
 DO
     if (varianceFraction > 1.0) varianceFraction = 1.0;
-    long permille = (long) floor (varianceFraction * 1000.0);
+    integer permille = Melder_iroundDown (varianceFraction * 1000.0);
     CONVERT_EACH (Sound)
 		autoSound result = Sound_whitenChannels (me, varianceFraction);
     CONVERT_EACH_END (my name, U"_", permille);
diff --git a/dwtools/praat_DataModeler_init.cpp b/dwtools/praat_DataModeler_init.cpp
index 0f96209..c3b115e 100644
--- a/dwtools/praat_DataModeler_init.cpp
+++ b/dwtools/praat_DataModeler_init.cpp
@@ -75,7 +75,7 @@ FORM (GRAPHICS_DataModeler_drawEstimatedTrack, U"DataModeler: Draw estimated tra
 	BOOLEAN (garnish, U"Garnish", true)
 	OK
 DO
-	REQUIRE (order >= 0, U"The order must be greater than or equal to zero.")
+	Melder_require (order >= 0, U"The order should be at least zero.");
 	GRAPHICS_EACH (DataModeler)
 		DataModeler_drawTrack (me, GRAPHICS, xmin, xmax, ymin, ymax, 1, order + 1, xOffset, garnish);
 	GRAPHICS_EACH_END
@@ -377,7 +377,7 @@ FORM (NEW_Formant_to_FormantModeler, U"Formant: To FormantModeler", nullptr) {
 		OPTION (U"Sqrt bandwidth")
 	OK
 DO
-	REQUIRE (order >= 0, U"The order must be greater than or equal to zero.")
+	Melder_require (order >= 0, U"The order should be at least zero.");
 	CONVERT_EACH (Formant)
 		autoFormantModeler result = Formant_to_FormantModeler (me, fromTime, toTime, numberOfFormants, order + 1, weighDataType);
 	CONVERT_EACH_END (my name, U"_o", order);
@@ -474,7 +474,7 @@ FORM (GRAPHICS_FormantModeler_drawEstimatedTracks, U"FormantModeler: Draw estima
 	BOOLEAN (garnish, U"Garnish", true)
 	OK
 DO
-	REQUIRE (order >= 0, U"The order must be greater than or equal to zero.")
+	Melder_require (order >= 0, U"The order should be at least zero.");
 	GRAPHICS_EACH (FormantModeler)
 		FormantModeler_drawTracks (me, GRAPHICS, fromTime, toTime, maximumFrequency, fromFormant, toFormant, 1, order + 1, xOffset_mm, garnish);
 	GRAPHICS_EACH_END
diff --git a/dwtools/praat_David_init.cpp b/dwtools/praat_David_init.cpp
index 5e447b8..e916aef 100644
--- a/dwtools/praat_David_init.cpp
+++ b/dwtools/praat_David_init.cpp
@@ -633,7 +633,7 @@ FORM (NEW1_ChebyshevSeries_create, U"Create ChebyshevSeries", U"Create Chebyshev
 	SENTENCE (coefficients_string, U"Coefficients (c[k])", U"0 0 1.0")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be smaller than Xmax.");
 	CREATE_ONE
 		autoChebyshevSeries result = ChebyshevSeries_createFromString (xmin, xmax, coefficients_string);
 	CREATE_ONE_END (name)
@@ -850,7 +850,7 @@ FORM (GRAPHICS_Confusion_Matrix_draw, U"Confusion & Matrix: Draw confusions with
 	BOOLEAN (garnish, U"Garnish", true)
 	OK
 DO
-	REQUIRE (categoryPosition >= 0, U"Category position must be >= 0")
+	Melder_require (categoryPosition >= 0, U"Your category position should be at least 0.");
 	GRAPHICS_TWO (Confusion, Matrix)
 		Confusion_Matrix_draw (me, you, GRAPHICS, categoryPosition, lowerLevel, xmin, xmax, ymin, ymax, garnish);
 	GRAPHICS_TWO_END
@@ -1137,7 +1137,7 @@ FORM (NEW1_Discriminant_and_TableOfReal_to_Configuration, U"Discriminant & Table
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"0")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	CONVERT_TWO (Discriminant, TableOfReal)
 		autoConfiguration result = Discriminant_and_TableOfReal_to_Configuration (me, you, numberOfDimensions);
 	CONVERT_TWO_END (my name, U"_", your name)
@@ -1164,7 +1164,7 @@ FORM (NEW1_Discriminant_and_TableOfReal_mahalanobis, U"Discriminant & TableOfRea
 DO
 	CONVERT_TWO (Discriminant, TableOfReal)
 		long group = Discriminant_groupLabelToIndex (me, groupLabel);
-		REQUIRE (group > 0, U"Group label does not exist.")
+		Melder_require (group > 0, U"Your group label \"", groupLabel, U"\" does not exist.");
 		autoTableOfReal result = Discriminant_and_TableOfReal_mahalanobis (me, you, group, poolCovariances);
 	CONVERT_TWO_END (U"mahalanobis")
 }
@@ -1215,10 +1215,9 @@ DO
 
 FORM (REAL_Discriminant_getWilksLambda, U"Discriminant: Get Wilks' lambda", U"Discriminant: Get Wilks' lambda...") {
 	LABEL (U"Product (i=from..numberOfEigenvalues, 1 / (1 + eigenvalue[i]))")
-	INTEGER (from, U"From", U"1") //TODO better name
+	NATURAL (from, U"From", U"1") //TODO better name
 	OK
 DO
-	REQUIRE (from >= 1, U"Number must be greater than or equal to one.")
 	NUMBER_ONE (Discriminant)
 		double result = Discriminant_getWilksLambda (me, from);
 	NUMBER_ONE_END (U" (wilks lambda)")
@@ -1239,7 +1238,7 @@ FORM (REAL_Discriminant_getPartialDiscriminationProbability, U"Discriminant: Get
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"1")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater than or equal to zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	NUMBER_ONE (Discriminant)
 		double result, chisq, df;
 		Discriminant_getPartialDiscriminationProbability (me, numberOfDimensions, & result, & chisq, & df);
@@ -1284,7 +1283,7 @@ FORM (REAL_Discriminant_getConcentrationEllipseArea, U"Discriminant: Get concent
 DO
 	NUMBER_ONE (Discriminant)
 		long group = Discriminant_groupLabelToIndex (me, groupLabel);
-		REQUIRE (group > 0, U"Group label does not exist.")
+		Melder_require (group > 0, U"The group label \"", groupLabel, U"\" does not exist.");
 		double result = Discriminant_getConcentrationEllipseArea (me, group, numberOfSigmas, false, discriminatPlane, xDimension, yDimension);
 	NUMBER_ONE_END (U" (concentration ellipse area)")
 }
@@ -1299,7 +1298,7 @@ FORM (REAL_Discriminant_getConfidenceEllipseArea, U"Discriminant: Get confidence
 DO
 	NUMBER_ONE (Discriminant)
 		long group = Discriminant_groupLabelToIndex (me, groupLabel);
-		REQUIRE (group > 0, U"Group label does not exist.")
+		Melder_require (group > 0, U"The group label \"", groupLabel, U"\" does not exist.");
 		double result = Discriminant_getConcentrationEllipseArea (me, group, confidenceLevel, true, discriminatPlane, xDimension, yDimension);
 	NUMBER_ONE_END (U" (confidence ellipse area)")
 }
@@ -1310,7 +1309,7 @@ FORM (REAL_Discriminant_getLnDeterminant_group, U"Discriminant: Get determinant
 DO
 	NUMBER_ONE (Discriminant)
 		long group = Discriminant_groupLabelToIndex (me, groupLabel);
-		REQUIRE (group > 0, U"Group label does not exist.")
+		Melder_require (group > 0, U"The group label \"", groupLabel, U"\" does not exist.");
 		double result = Discriminant_getLnDeterminant_group (me, group);
 	NUMBER_ONE_END (U" (ln(determinant) group")
 }
@@ -3298,7 +3297,7 @@ FORM (NEW1_LegendreSeries_create, U"Create LegendreSeries", U"Create LegendreSer
 	SENTENCE (coefficients_string, U"Coefficients", U"0 0 1.0")
 	OK
 DO
-	REQUIRE  (xmin < xmax, U"Xmin must be smaller than Xmax.") 
+	Melder_require (xmin < xmax, U"Xmin should be smaller than Xmax.");
 	CREATE_ONE
 		autoLegendreSeries result = LegendreSeries_createFromString (xmin, xmax, coefficients_string);
 	CREATE_ONE_END (name)
@@ -3913,7 +3912,7 @@ FORM (NEW_MSpline_create, U"Create MSpline", U"Create MSpline...") {
 	SENTENCE (knots_string, U"Interior knots" , U"0.3 0.5 0.6")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be smaller than Xmax.");
 	CREATE_ONE
 		autoMSpline result = MSpline_createFromStrings (xmin, xmax, degree, coefficients_string, knots_string);
 	CREATE_ONE_END (name)
@@ -3968,14 +3967,17 @@ DO
 }
 
 FORM (MODIFY_PatternList_formula, U"PatternList: Formula", nullptr) {
-	LABEL (U"        y := 1; for row := 1 to nrow do { x := 1; "
-		"for col := 1 to ncol do { self [row, col] := `formula' ; x := x + 1 } "
-		"y := y + 1 }}")
-	TEXTFIELD (formula, U"Formula:", U"self")
+	LABEL (U"# `col` is the node number, `row` is the pattern number")
+	LABEL (U"for row from 1 to nrow   ; for all patterns")
+	LABEL (U"   for col from 1 to ncol   ; for all nodes")
+	LABEL (U"      self [row, col] =")
+	TEXTFIELD (formula, nullptr, U"5 * exp (-0.5 * ((col - 10 - row/100) / 1.5) ^ 2) - 0.5   ; sliding peak")
+	LABEL (U"   endfor")
+	LABEL (U"endfor")
 	OK
 DO
 	MODIFY_EACH (PatternList)
-		Matrix_formula (reinterpret_cast <Matrix> (me), formula, interpreter, nullptr);
+		Matrix_formula (me, formula, interpreter, nullptr);
 	MODIFY_EACH_END
 }
 
@@ -3986,8 +3988,8 @@ FORM (MODIFY_PatternList_setValue, U"PatternList: Set value", U"PatternList: Set
 	OK
 DO
 	MODIFY_EACH (PatternList)
-		REQUIRE (rowNumber <= my ny, U"Row number must not be greater than number of rows.")
-		REQUIRE (columnNumber <= my nx, U"Column number must not be greater than number of columns.")
+		Melder_require (rowNumber <= my ny, U"The row number should not be greater than the number of rows.");
+		Melder_require (columnNumber <= my nx, U"The column number should not be greater than the number of columns.");
 		my z [rowNumber] [columnNumber] = newValue;
 	MODIFY_EACH_END
 }
@@ -4008,9 +4010,7 @@ DIRECT (HELP_PCA_help) {
 DIRECT (HINT_hint_PCA_and_TableOfReal_to_Configuration) {
 	Melder_information (U"You can get principal components by selecting a PCA and a TableOfReal\n"
 		"together and choosing \"To Configuration...\".");
-	END 
-
-}
+END }
 
 DIRECT (HINT_hint_PCA_and_Covariance_Project) {
 	Melder_information (U"You can get a new Covariance object rotated to the directions of the direction vectors\n"
@@ -4039,12 +4039,12 @@ DIRECT (NEW_PCA_and_Configuration_to_TableOfReal_reconstruct) {
 }
 
 FORM (NEW1_PCA_and_TableOfReal_to_TableOfReal_projectRows, U"PCA & TableOfReal: To TableOfReal (project rows)", U"PCA & TableOfReal: To Configuration...") {
-	INTEGER (numberOfDimensions, U"Number of dimensions to keep", U"0 (= all)")
+	INTEGER (numberOfDimensionsToKeep, U"Number of dimensions to keep", U"0 (= all)")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater equal zero.")
+	Melder_require (numberOfDimensionsToKeep >= 0, U"The number of dimensions to keep should be at least zero.");
 	CONVERT_ONE_AND_GENERIC (PCA, TableOfReal)
-		autoTableOfReal result = PCA_and_TableOfReal_to_TableOfReal_projectRows (me, you, numberOfDimensions);
+		autoTableOfReal result = PCA_and_TableOfReal_to_TableOfReal_projectRows (me, you, numberOfDimensionsToKeep);
 	CONVERT_ONE_AND_GENERIC_END (my name, U"_", your name)
 }
 
@@ -4052,7 +4052,7 @@ FORM (NEW1_PCA_and_TableOfReal_to_Configuration, U"PCA & TableOfReal: To Configu
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"0 (= all)")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater equal zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	CONVERT_ONE_AND_GENERIC (PCA, TableOfReal)
 		autoConfiguration result = PCA_and_TableOfReal_to_Configuration (me, you, numberOfDimensions);
 	CONVERT_ONE_AND_GENERIC_END (my name, U"_", your name)
@@ -4062,7 +4062,7 @@ FORM (NEW1_PCA_and_TableOfReal_to_TableOfReal_zscores, U"PCA & TableOfReal: To T
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"0 (= all)")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater equal zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	CONVERT_ONE_AND_GENERIC (PCA, TableOfReal)
 		autoTableOfReal result = PCA_and_TableOfReal_to_TableOfReal_zscores (me, you, numberOfDimensions);
 	CONVERT_ONE_AND_GENERIC_END (my name, U"_", your name, U"_zscores")
@@ -4072,7 +4072,7 @@ FORM (NEW1_PCA_and_Matrix_to_Matrix_projectRows, U"PCA & Matrix: To Matrix (proj
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"0 (= all)")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater equal zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	CONVERT_TWO (PCA, Matrix)
 		autoMatrix result = Eigen_and_Matrix_to_Matrix_projectRows (me, you, numberOfDimensions);
 	CONVERT_TWO_END (my name, U"_", your name)
@@ -4082,7 +4082,7 @@ FORM (NEW1_PCA_and_Matrix_to_Matrix_projectColumns, U"PCA & Matrix: To Matrix (p
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"0 (= all)")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater equal zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	CONVERT_ONE_AND_GENERIC (PCA, Matrix)
 		autoMatrix result = Eigen_and_Matrix_to_Matrix_projectColumns (me, you, numberOfDimensions);
 	CONVERT_ONE_AND_GENERIC_END (my name, U"_", your name)
@@ -4093,7 +4093,7 @@ FORM (REAL_PCA_getCentroidElement, U"PCA: Get centroid element...", nullptr) {
 	OK
 DO
 	NUMBER_ONE (PCA)
-		REQUIRE (number <= my dimension, Melder_cat (U"Number may not be larger than ", my dimension, U"."))
+		Melder_require (number <= my dimension, U"Number should not be greater than ", my dimension, U".");
 		double result = my centroid [number];
 	NUMBER_ONE_END (U" (element ", number, U")")
 }
@@ -4115,7 +4115,7 @@ FORM (INTEGER_PCA_getNumberOfComponentsVAF, U"PCA: Get number of components (VAF
 	POSITIVE (varianceFraction, U"Variance fraction (0-1)", U"0.95")
 	OK
 DO
-	REQUIRE (varianceFraction >= 0.0 && varianceFraction <= 1.0, U"The variance fraction must be in interval (0-1).")
+	Melder_require (varianceFraction >= 0.0 && varianceFraction <= 1.0, U"The variance fraction must be in interval [0-1].");
 	NUMBER_ONE (PCA)
 		double result = Eigen_getDimensionOfFraction (me, varianceFraction);
 	NUMBER_ONE_END (U" (variance fraction)")
@@ -4126,7 +4126,7 @@ FORM (REAL_PCA_getFractionVAF, U"PCA: Get fraction variance accounted for", U"PC
 	NATURAL (toPrincipalComponent, U"right Principal component range", U"1")
 	OK
 DO
-	REQUIRE (fromPrincipalComponent <= toPrincipalComponent, U"The second component must be greater than or equal to the first component.")
+	Melder_require (fromPrincipalComponent <= toPrincipalComponent, U"The second component should be greater than or equal to the first component.");
 	NUMBER_ONE (PCA)
 		double result = Eigen_getCumulativeContributionOfComponents (me, fromPrincipalComponent, toPrincipalComponent);
 	NUMBER_ONE_END (U"")
@@ -4148,8 +4148,8 @@ FORM (NEW_PCA_extractEigenvector, U"PCA: Extract eigenvector", U"Eigen: Extract
 	INTEGER (numberOfColumns, U"Number of columns", U"0")
 	OK
 DO
-	REQUIRE (numberOfRows >= 0, U"Number of rows must be >= 0.")
-	REQUIRE (numberOfColumns >= 0, U"Number of columns must be >= 0.")
+	Melder_require (numberOfRows >= 0, U"The number of rows should beat least 0.");
+	Melder_require (numberOfColumns >= 0, U"The number of columns should be at least 0.");
 	CONVERT_EACH (PCA);
 		autoMatrix result = Eigen_extractEigenvector (me, eigenvectorNumber, numberOfRows, numberOfColumns);
 	CONVERT_EACH_END (my name, U"_ev", eigenvectorNumber)
@@ -4507,7 +4507,7 @@ FORM (INFO_Polygon_getLocationOfPoint, U"Get location of point", U"Polygon: Get
 	REAL (eps, U"Precision", U"1.64e-15")
 	OK
 DO
-	REQUIRE (eps >= 0, U"The precision cannot be negative.")
+	Melder_require (eps >= 0.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" :
@@ -4616,7 +4616,7 @@ FORM (NEW1_Polynomial_create, U"Create Polynomial from coefficients", U"Create P
 	SENTENCE (coefficients_string, U"Coefficients", U"2.0 -1.0 -2.0 1.0")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be less than Xmax.");
 	CREATE_ONE
 		autoPolynomial result = Polynomial_createFromString (xmin, xmax, coefficients_string);
 	CREATE_ONE_END (name)
@@ -4631,7 +4631,7 @@ FORM (NEW1_Polynomial_createFromProducts, U"Create Polynomial from second order
 	SENTENCE (coefficients_string, U"The a's", U"1.0 2.0")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be less than Xmax.");
 	CREATE_ONE
 		autoPolynomial result = Polynomial_createFromProductOfSecondOrderTermsString (xmin, xmax, coefficients_string);
 	CREATE_ONE_END (name)
@@ -4646,7 +4646,7 @@ FORM (NEW1_Polynomial_createFromZeros, U"Create Polynomial from first order prod
 	SENTENCE (zeros_string, U"The zero's", U"1.0 2.0")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be less than Xmax.");
 	CREATE_ONE
 		autoPolynomial result = Polynomial_createFromRealRootsString (xmin, xmax, zeros_string);
 	CREATE_ONE_END (name)
@@ -4733,7 +4733,7 @@ FORM (NEW_Polynomial_scaleX, U"Polynomial: Scale x", U"Polynomial: Scale x...")
 	REAL (xmax, U"Xmax", U"1.0")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be less than Xmax.");
 	CONVERT_EACH (Polynomial)
 		autoPolynomial result = Polynomial_scaleX (me, xmin, xmax);
 	CONVERT_EACH_END (my name, U"_scaleX")
@@ -4791,7 +4791,7 @@ DO
 		Polynomial p1 = nullptr, p2 = nullptr, pq, pr;
 	*/
 
-	REQUIRE (wantQuotient || wantRemainder, U"Either \'Want quotient\' or \'Want remainder\' should be chosen")
+	Melder_require (wantQuotient || wantRemainder, U"You should select \"Want quotient\", \"Want remainder\", or both.");
 	FIND_COUPLE (Polynomial)
 		autoPolynomial aq, ar;
 		Polynomials_divide (me, you, wantQuotient ? & aq : nullptr, wantRemainder ? & ar : nullptr);
@@ -4931,7 +4931,7 @@ FORM (REAL_Praat_getInvTukeyQ, U"Get invTukeyQ", nullptr) {
 	NATURAL (numberOfRows, U"Number of rows", U"1")
 	OK
 DO
-	REQUIRE (probability >= 0.0 && probability <= 1.0, U"The probability should be in the interval [0, 1].")
+	Melder_require (probability >= 0.0 && probability <= 1.0, U"The probability should be in the interval [0, 1].");
 	double result = NUMinvTukeyQ (probability, numberOfMeans, degreesOfFreedon, numberOfRows);
 	Melder_information (result, U" (inv tukeyQ)");
 END }
@@ -5064,8 +5064,9 @@ FORM (NEW1_Sound_createAsGammaTone, U"Create a gammatone", U"Create Sound as gam
 DO
 	CREATE_ONE
 		Sound_create_checkCommonFields (startTime, endTime, samplingFrequency);
-		REQUIRE (frequency < samplingFrequency / 2, Melder_cat (U"Frequency cannot be larger than half the sampling frequency.\nPlease use a frequency smaller than ", 	samplingFrequency / 2, U"."))
-		REQUIRE (gamma >= 0, U"Gamma cannot be negative.\nPlease use a positive or zero gamma.")
+		Melder_require (frequency < 0.5 * samplingFrequency,
+			U"Your frequency should not be greater than half the sampling frequency. Use a frequency less than ", 0.5 * samplingFrequency, U".");
+		Melder_require (gamma >= 0, U"Gamma should not be negative. Use a positive or zero gamma.");
 		autoSound result = Sound_createGammaTone (startTime, endTime, samplingFrequency, gamma, frequency, bandwidth, initialPhase, additionFactor, scaleAmplitudes);
 	CREATE_ONE_END (name)
 }
@@ -5318,8 +5319,8 @@ FORM (NEW_Sound_to_Pitch_shs, U"Sound: To Pitch (shs)", U"Sound: To Pitch (shs).
 	NATURAL (numberOfPointsPerOctave, U"Number of points per octave", U"48");
 	OK
 DO
-	REQUIRE (pitchFloor < pitchCeiling, U"Minimum pitch should be smaller than ceiling.")
-	REQUIRE (pitchCeiling < maximumFrequency, U"Maximum frequency must be greater than or equal to ceiling.")
+	Melder_require (pitchFloor < pitchCeiling, U"The minimum pitch should be less than the ceiling.");
+	Melder_require (pitchCeiling < maximumFrequency, U"The maximum frequency should be greater than or equal to the ceiling.");
 	CONVERT_EACH (Sound)
 		autoPitch result = Sound_to_Pitch_shs (me, timeStep, pitchFloor, maximumFrequency, pitchCeiling, maximumNumberOfSubharmonics, maximumNumberOfCandidates, compressionFactor, numberOfPointsPerOctave);
 	CONVERT_EACH_END (my name)
@@ -5380,7 +5381,7 @@ FORM (NEW_Sound_to_Pitch_SPINET, U"Sound: To SPINET", U"Sound: To SPINET...") {
 	NATURAL (maximumNumberOfCandidates, U"Max. number of candidates", U"15")
 	OK
 DO
-	REQUIRE (minimumFrequency < maximumFrequency, U"Maximum frequency must be larger than minimum frequency.")
+	Melder_require (minimumFrequency < maximumFrequency, U"The maximum frequency should be greater than the minimum frequency.");
 	CONVERT_EACH (Sound)
 		autoPitch result = Sound_to_Pitch_SPINET (me, timeStep, windowLength, minimumFrequency, maximumFrequency, numberOfFilters, pitchCeiling, maximumNumberOfCandidates);
 	CONVERT_EACH_END (my name)
@@ -5450,7 +5451,7 @@ FORM (NEW_Sound_changeSpeaker, U"Sound: Change speaker", U"Sound: Change speaker
 	POSITIVE (durationMultiplicationFactor, U"Multiply duration by", U"1.0")
 	OK
 DO
-	REQUIRE (pitchFloor < pitchCeiling, U"Maximum pitch should be greater than minimum pitch.")
+	Melder_require (pitchFloor < pitchCeiling, U"The maximum pitch should be greater than the minimum pitch.");
 	CONVERT_EACH (Sound)
 		autoSound result = Sound_changeSpeaker (me, pitchFloor, pitchCeiling, formantMultiplicationFactor, pitchMultiplicationFactor, pitchRangeMultiplicationFactor, durationMultiplicationFactor);
 	CONVERT_EACH_END (my name, U"_changeSpeaker")
@@ -5467,7 +5468,7 @@ FORM (NEW_Sound_changeGender, U"Sound: Change gender", U"Sound: Change gender...
 	POSITIVE (durationMultiplicationFactor, U"Duration factor", U"1.0")
 	OK
 DO
-	REQUIRE (pitchFloor < pitchCeiling, U"Maximum pitch should be greater than minimum pitch.")
+	Melder_require (pitchFloor < pitchCeiling, U"The maximum pitch should be greater than the minimum pitch.");
 	CONVERT_EACH (Sound)
 		autoSound result = Sound_changeGender_old (me, pitchFloor, pitchCeiling, formantShiftRatio, pitchMedian, pitchRangeMultiplicationFactor, durationMultiplicationFactor);
 	CONVERT_EACH_END (my name, U"_changeGender");
@@ -5552,7 +5553,7 @@ FORM (MODIFY_Spectrum_setRealValueInBin, U"Spectrum: Set real value in bin", nul
 	OK
 DO
 	MODIFY_EACH (Spectrum)
-		REQUIRE (binNumber <= my nx, U"Bin number must not exceed number of bins.")
+		Melder_require (binNumber <= my nx, U"Your bin number should not exceed the number of bins (", my nx, U").");
 		my z[1][binNumber]= value;
 	MODIFY_EACH_END
 }
@@ -5563,7 +5564,7 @@ FORM (MODIFY_Spectrum_setImaginaryValueInBin, U"Spectrum: Set imaginary value in
 	OK
 DO
 	MODIFY_EACH (Spectrum)
-		REQUIRE (binNumber <= my nx, U"Bin number must not exceed number of bins.")
+		Melder_require (binNumber <= my nx, U"Your bin number should not exceed the number of bins (", my nx, U").");
 		my z[2][binNumber]= value;
 	MODIFY_EACH_END
 }
@@ -5582,7 +5583,7 @@ FORM (NEW_Spectrum_shiftFrequencies, U"Spectrum: Shift frequencies", U"Spectrum:
 DO
 	CONVERT_EACH (Spectrum)
 		autoSpectrum result = Spectrum_shiftFrequencies (me, frequencyShift, maximumFrequency, interpolationDepth);
-	CONVERT_EACH_END (my name, (frequencyShift < 0 ? U"_m" : U"_"), (long) floor (frequencyShift))
+	CONVERT_EACH_END (my name, (frequencyShift < 0 ? U"_m" : U"_"), Melder_iroundDown (frequencyShift))
 }
 
 DIRECT (NEW_Spectra_multiply) {
@@ -5610,7 +5611,7 @@ FORM (NEW_Spectrum_compressFrequencyDomain, U"Spectrum: Compress frequency domai
 DO
 	CONVERT_EACH (Spectrum)
 		autoSpectrum result = Spectrum_compressFrequencyDomain (me, maximumFrequency, interpolationDepth, scale, 1);
-	CONVERT_EACH_END (my name, U"_", (long) floor (maximumFrequency))
+	CONVERT_EACH_END (my name, U"_", Melder_iroundDown (maximumFrequency))
 }
 
 DIRECT (NEW_Spectrum_unwrap) {
@@ -5809,7 +5810,7 @@ FORM (NEW_Spline_scaleX, U"Spline: Scale x", U"Spline: Scale x...") {
 	REAL (xmax, U"Xmax", U"1.0")
 	OK
 DO
-	REQUIRE (xmin < xmax, U"Xmin must be smaller than Xmax.")
+	Melder_require (xmin < xmax, U"Xmin should be less than Xmax.");
 	CONVERT_EACH (Spline)
 		autoSpline result = Spline_scaleX (me, xmin, xmax);
 	CONVERT_EACH_END (my name, U"_scaleX")
@@ -5900,7 +5901,7 @@ DIRECT (INTEGER_SSCP_getDegreesOfFreedom) {
 
 DIRECT (INTEGER_SSCP_getNumberOfObservations) {
 	INTEGER_ONE (SSCP)
-		long result = (long) floor (my numberOfObservations);   // ppgb: blijf ik raar vinden
+		integer result = Melder_iroundDown (my numberOfObservations);   // ppgb: blijf ik raar vinden
 	INTEGER_ONE_END (U" (number of observations)")
 }
 
@@ -6790,7 +6791,7 @@ FORM (NEW_TableOfReal_to_Configuration_lda, U"TableOfReal: To Configuration (lda
 	INTEGER (numberOfDimensions, U"Number of dimensions", U"0 (= all)")
 	OK
 DO
-	REQUIRE (numberOfDimensions >= 0, U"Number of dimensions must be greater equal zero.")
+	Melder_require (numberOfDimensions >= 0, U"The number of dimensions should be at least zero.");
 	CONVERT_EACH (TableOfReal)
 		autoConfiguration result = TableOfReal_to_Configuration_lda (me, numberOfDimensions);
 	CONVERT_EACH_END (my name, U"_lda")
diff --git a/dwtools/praat_HMM_init.cpp b/dwtools/praat_HMM_init.cpp
index 6ad976c..1559d1c 100644
--- a/dwtools/praat_HMM_init.cpp
+++ b/dwtools/praat_HMM_init.cpp
@@ -255,7 +255,7 @@ FORM (NEW1_HMM_createContinuousModel, U"HMM: Create continuous model", nullptr)
 		OPTION (U"Diagonal")
 	OK
 DO
-	REQUIRE (matricesType >= 0 && matricesType <= componentDimension, U"Not a valid covariance matrix type")
+	Melder_require (matricesType >= 0 && matricesType <= componentDimension, U"Not a valid covariance matrix type");
 	CREATE_ONE
 		autoHMM result = HMM_createContinuousModel (leftToRightModel, numberOfStates, numberOfSymbols, numberOfComponents, componentDimension, matricesType - 1);
 	CREATE_ONE_END (name)
@@ -312,7 +312,7 @@ FORM (REAL_HMM_getTransitionProbability, U"HMM: Get transition probability", U"H
 	OK
 DO
 	NUMBER_ONE (HMM)
-		REQUIRE (fromState <= my numberOfStates && toState <= my numberOfStates, U"State number(s) too high.")
+		Melder_require (fromState <= my numberOfStates && toState <= my numberOfStates, U"State number(s) too high.");
 		double result = my transitionProbs [fromState] [toState];
 	NUMBER_ONE_END (U" : [ ", fromState, U", ", toState, U" ]")
 }
@@ -323,8 +323,8 @@ FORM (REAL_HMM_getEmissionProbability, U"HMM: Get emission probability", U"HMM:
 	OK
 DO
 	NUMBER_ONE (HMM)
-		REQUIRE (fromState <= my numberOfStates, U"State number too high.")
-		REQUIRE (toState <= my numberOfObservationSymbols, U"Symbol number too high.")
+		Melder_require (fromState <= my numberOfStates, U"State number too high.");
+		Melder_require (toState <= my numberOfObservationSymbols, U"Symbol number too high.");
 		double result = my emissionProbs[fromState][toState];
 	NUMBER_ONE_END (U" : [ ", fromState, U", ", toState, U" ]")
 }
@@ -334,7 +334,7 @@ FORM (REAL_HMM_getStartProbability, U"HMM: Get start probability", U"HMM: Get st
 	OK
 DO
 	NUMBER_ONE (HMM)
-		REQUIRE (stateNumber <= my numberOfStates, U"State number too high.")
+		Melder_require (stateNumber <= my numberOfStates, U"State number too high.");
 		double result = my transitionProbs[0][stateNumber];
 	NUMBER_ONE_END (U" : [ ", stateNumber, U" ]")
 }
@@ -386,7 +386,7 @@ FORM (INFO_HMM_getSymbolLabel, U"HMM: Get symbol label", nullptr) {
 	OK
 DO
 	STRING_ONE (HMM)
-		REQUIRE (symbolNumber <= my numberOfObservationSymbols, U"Symbol number too high.")
+		Melder_require (symbolNumber <= my numberOfObservationSymbols, U"Symbol number too high.");
 		HMMObservation s = my observationSymbols->at [symbolNumber];
 		const char32 *result = s -> label;
 	STRING_ONE_END
@@ -397,7 +397,7 @@ FORM (INFO_HMM_getStateLabel, U"HMM: Get state label", nullptr) {
 	OK
 DO
 	STRING_ONE (HMM)
-		REQUIRE (stateNumber <= my numberOfStates, U"State number too high.")
+		Melder_require (stateNumber <= my numberOfStates, U"State number too high.");
 		HMMState state = my states->at [stateNumber];
 		const char32 *result = state -> label;
 	STRING_ONE_END
@@ -465,7 +465,7 @@ FORM (MODIFY_HMM_and_HMMObservationSequence_learn, U"HMM & HMMObservationSequenc
 	BOOLEAN (showProgress, U"Learning history in Info window", false)
 	OK
 DO
-	REQUIRE (minimumProbability >= 0 && minimumProbability < 1, U"A probabilty must be >= 0 and < 1!")
+	Melder_require (minimumProbability >= 0.0 && minimumProbability < 1.0, U"The minimum probabilty should be in [0, 1).");
 	MODIFY_FIRST_OF_ONE_AND_LIST(HMM, HMMObservationSequence)
 		HMM_and_HMMObservationSequenceBag_learn (me, (HMMObservationSequenceBag) &list, relativePrecision_log, minimumProbability, showProgress);
 	MODIFY_FIRST_OF_ONE_AND_LIST_END
@@ -588,7 +588,7 @@ FORM (NEW_TableOfReal_to_GaussianMixture, U"TableOfReal: To GaussianMixture (no
 	GaussianMixture_OPTION_MENU_CRITERIA
 	OK
 DO
-	REQUIRE (lambda >= 0.0 && lambda < 1.0, U"Lambda must be in interval [0,1).")
+	Melder_require (lambda >= 0.0 && lambda < 1.0, U"Lambda should be in the interval [0, 1).");
 	CONVERT_EACH (TableOfReal)
 		autoGaussianMixture result = TableOfReal_to_GaussianMixture (me, numberOfComponents, tolerance, maximumNumberOfIterations, lambda, matricesType - 1, criterion - 1);
 	CONVERT_EACH_END (my name)
@@ -601,10 +601,10 @@ FORM (MODIFY_GaussianMixture_and_TableOfReal_improveLikelihood, U"GaussianMixtur
 	GaussianMixture_OPTION_MENU_CRITERIA
 	OK
 DO
-	REQUIRE (lambda >= 0.0 && lambda < 1.0, U"Lambda must be in interval [0,1).")
+	Melder_require (lambda >= 0.0 && lambda < 1.0, U"Lambda should be in the interval [0, 1).");
 	MODIFY_FIRST_OF_TWO (GaussianMixture, TableOfReal)
-		REQUIRE (your numberOfColumns == my dimension, U"The number of columns and the dimension of the model do not agree.");
-		REQUIRE (my numberOfComponents < you -> numberOfRows / 2, U"Not enough data points.")
+		Melder_require (your numberOfColumns == my dimension, U"The number of columns and the dimension of the model do not agree.");
+		Melder_require (my numberOfComponents < your numberOfRows / 2, U"Not enough data points.");
 		GaussianMixture_and_TableOfReal_improveLikelihood (me, you, tolerance, maximumNumberOfIterations, lambda, criterion - 1);
 	MODIFY_FIRST_OF_TWO_END
 }
@@ -617,10 +617,10 @@ FORM (NEW1_GaussianMixture_and_TableOfReal_to_GaussianMixture_CEMM, U"GaussianMi
 	GaussianMixture_OPTION_MENU_CRITERIA
 	OK
 DO
-	REQUIRE (lambda >= 0.0 && lambda < 1.0, U"Lambda must be in interval [0,1).")
+	Melder_require (lambda >= 0.0 && lambda < 1.0, U"Lambda should be in the interval [0, 1).");
 	CONVERT_TWO (GaussianMixture, TableOfReal)
-		REQUIRE (your numberOfColumns == my dimension, U"The number of columns and the dimension of the model do not agree.");
-		REQUIRE (my numberOfComponents < you -> numberOfRows / 2, U"Not enough data points.")
+		Melder_require (your numberOfColumns == my dimension, U"The number of columns and the dimension of the model do not agree.");
+		Melder_require (my numberOfComponents < your numberOfRows / 2, U"Not enough data points.");
 		autoGaussianMixture result = GaussianMixture_and_TableOfReal_to_GaussianMixture_CEMM (me, you, minimumNumberOfComponents, tolerance, maximumNumberOfIterations, lambda, criterion - 1);
 	CONVERT_TWO_END (my name)
 }
diff --git a/dwtools/praat_KlattGrid_init.cpp b/dwtools/praat_KlattGrid_init.cpp
index 0e37d75..4d5c7f7 100644
--- a/dwtools/praat_KlattGrid_init.cpp
+++ b/dwtools/praat_KlattGrid_init.cpp
@@ -164,11 +164,11 @@ FORM (NEW1_KlattGrid_create, U"Create KlattGrid", U"Create KlattGrid...") {
 	INTEGER (numberOfDeltaFormants, U"Number of delta formants", U"1")
 	OK
 DO
-	REQUIRE (fromTime < toTime, U"The start time must lie before the end time.")
-	REQUIRE (numberOfOralFormants >= 0 && numberOfNasalFormants >= 0 && numberOfNasalAntiFormants >= 0
+	Melder_require (fromTime < toTime, U"The start time must lie before the end time.");
+	Melder_require (numberOfOralFormants >= 0 && numberOfNasalFormants >= 0 && numberOfNasalAntiFormants >= 0
 		&& numberOfTrachealFormants >= 0 && numberOfTrachealAntiFormants >= 0
 		&& numberOfFricationFormants >= 0 && numberOfDeltaFormants >= 0,
-		U"The number of (..) formants cannot be negative!")
+		U"No number of formants should be negative.");
 	CREATE_ONE
 		autoKlattGrid result = KlattGrid_create (fromTime, toTime, numberOfOralFormants, numberOfNasalFormants, numberOfNasalAntiFormants, numberOfTrachealFormants, numberOfTrachealAntiFormants, numberOfFricationFormants, numberOfDeltaFormants);
 	CREATE_ONE_END (name)
@@ -262,7 +262,7 @@ FORM (MODIFY_KlattGrid_add##Name##Point, U"KlattGrid: Add " #name " point", null
 	REAL (value, U"Value" unit, default) \
 	OK \
 DO \
-	REQUIRE (require, requiremessage) \
+	Melder_require (require, requiremessage); \
 	MODIFY_EACH (KlattGrid); \
 		KlattGrid_add##Name##Point (me, time, value); \
 	MODIFY_EACH_END \
@@ -336,7 +336,7 @@ FORM (MODIFY_KlattGrid_add##Name##Formant##FBA##Point, U"KlattGrid: Add " #namef
 	REAL (value, U"Value " #unit, default) \
 	OK \
 DO \
-	REQUIRE (require, requiremessage) \
+	Melder_require (require, requiremessage); \
 	MODIFY_EACH (KlattGrid); \
 		KlattGrid_add##Form##Point (me, formantType, formantNumber, time, value); \
 	MODIFY_EACH_END \
@@ -630,7 +630,7 @@ FORM (MODIFY_KlattGrid_add##Name##Point, U"KlattGrid: Add " #name " point", null
 	REAL (value, U"Value" unit, default) \
 	OK \
 DO \
-	REQUIRE (require, requiremessage) \
+	Melder_require (require, requiremessage); \
 	LOOP { iam (KlattGrid); \
 		KlattGrid_add##Name##Point (me, formantType, formantNumber, time, value); \
 		praat_dataChanged (me); \
@@ -642,7 +642,7 @@ FORM (MODIFY_KlattGrid_addDelta##Name##Point, U"KlattGrid: Add delta " #name " p
 	REAL (value, U"Value" unit, default) \
 	OK \
 DO \
-	REQUIRE (require, requiremessage) \
+	Melder_require (require, requiremessage); \
 	LOOP { iam (KlattGrid); \
 		KlattGrid_addDelta##Name##Point (me, formantNumber, time, value); \
 		praat_dataChanged (me); \
@@ -880,7 +880,7 @@ FORM (NEW_KlattGrid_to_oralFormantGrid_openPhases, U"KlattGrid: Extract oral for
 	REAL (fadeFraction, U"Fade fraction (0..0.5)", U"0.1")
 	OK
 DO
-	REQUIRE (fadeFraction < 0.5, U"Fade fraction has to be smaller than 0.5.")
+	Melder_require (fadeFraction < 0.5, U"The fade fraction has to be less than 0.5.");
 	CONVERT_EACH (KlattGrid)
 		autoFormantGrid result = KlattGrid_to_oralFormantGrid_openPhases (me, fadeFraction);
 	CONVERT_EACH_END (U"corrected")
diff --git a/fon/AmplitudeTier.cpp b/fon/AmplitudeTier.cpp
index c8bd2b6..fd4e3a2 100644
--- a/fon/AmplitudeTier.cpp
+++ b/fon/AmplitudeTier.cpp
@@ -344,7 +344,7 @@ double AmplitudeTier_getShimmer_dda (AmplitudeTier me, double pmin, double pmax,
 
 autoSound AmplitudeTier_to_Sound (AmplitudeTier me, double samplingFrequency, integer interpolationDepth) {
 	try {
-		integer sound_nt = 1 + (integer) floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
+		integer sound_nt = 1 + Melder_iroundDown ((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;
diff --git a/fon/FormantGrid.cpp b/fon/FormantGrid.cpp
index 7150515..fd5cf00 100644
--- a/fon/FormantGrid.cpp
+++ b/fon/FormantGrid.cpp
@@ -309,7 +309,7 @@ autoFormant FormantGrid_to_Formant (FormantGrid me, double dt, double intensity)
 	try {
 		Melder_assert (dt > 0.0);
 		Melder_assert (intensity >= 0.0);
-		long nt = (long) floor ((my xmax - my xmin) / dt) + 1;
+		integer nt = Melder_iroundDown ((my xmax - my xmin) / dt) + 1;
 		double t1 = 0.5 * (my xmin + my xmax - (nt - 1) * dt);
 		autoFormant thee = Formant_create (my xmin, my xmax, nt, dt, t1, my formants.size);
 		for (long iframe = 1; iframe <= nt; iframe ++) {
diff --git a/fon/FunctionEditor.cpp b/fon/FunctionEditor.cpp
index 094b8f2..4cca26a 100644
--- a/fon/FunctionEditor.cpp
+++ b/fon/FunctionEditor.cpp
@@ -387,7 +387,7 @@ static void gui_drawingarea_cb_resize (FunctionEditor me, GuiDrawingArea_ResizeE
 	 * Put the function viewer at the left and the selection viewer at the right.
 	 */
 	my functionViewerLeft = 0;
-	my functionViewerRight = my p_showSelectionViewer ? (short) floor (width * (2.0/3.0)) : width;
+	my functionViewerRight = my p_showSelectionViewer ? Melder_iroundDown (width * (2.0/3.0)) : width;
 	my selectionViewerLeft = my functionViewerRight;
 	my selectionViewerRight = width;
 	my height = event -> height + 111;
diff --git a/fon/LongSound.cpp b/fon/LongSound.cpp
index fc426d1..37b0796 100644
--- a/fon/LongSound.cpp
+++ b/fon/LongSound.cpp
@@ -419,9 +419,9 @@ static void _LongSound_haveSamples (LongSound me, long imin, long imax) {
 	 */
 	imin -= MARGIN * n;
 	if (imin < 1) imin = 1;
-	imax = imin + (long) floor ((1.0 + 2.0 * MARGIN) * n);
+	imax = imin + Melder_iroundDown ((1.0 + 2.0 * MARGIN) * n);
 	if (imax > my nx) imax = my nx;
-	imin = imax - (long) floor ((1.0 + 2.0 * MARGIN) * n);
+	imin = imax - Melder_iroundDown ((1.0 + 2.0 * MARGIN) * n);
 	if (imin < 1) imin = 1;
 	Melder_assert (imax - imin + 1 <= my nmax);
 	/*
diff --git a/fon/Ltas.cpp b/fon/Ltas.cpp
index 7e1d346..fee31b6 100644
--- a/fon/Ltas.cpp
+++ b/fon/Ltas.cpp
@@ -126,10 +126,10 @@ autoLtas Ltases_merge (LtasBag ltases) {
 		/*
 		 * Convert to energy.
 		 */
-		for (long iband = 1; iband <= thy nx; iband ++) {
+		for (integer iband = 1; iband <= thy nx; iband ++) {
 			thy z [1] [iband] = pow (10.0, thy z [1] [iband] / 10.0);
 		}
-		for (long ispec = 2; ispec <= ltases->size; ispec ++) {
+		for (integer ispec = 2; ispec <= ltases->size; ispec ++) {
 			Ltas him = ltases->at [ispec];
 			if (his xmin != thy xmin || his xmax != thy xmax)
 				Melder_throw (U"Frequency domains do not match.");
@@ -140,14 +140,14 @@ autoLtas Ltases_merge (LtasBag ltases) {
 			/*
 			 * Add band energies.
 			 */
-			for (long iband = 1; iband <= thy nx; iband ++) {
+			for (integer iband = 1; iband <= thy nx; iband ++) {
 				thy z [1] [iband] += pow (10.0, his z [1] [iband] / 10.0);
 			}
 		}
 		/*
 		 * Convert back to dB.
 		 */
-		for (long iband = 1; iband <= thy nx; iband ++) {
+		for (integer iband = 1; iband <= thy nx; iband ++) {
 			thy z [1] [iband] = 10.0 * log10 (thy z [1] [iband]);
 		}
 		return thee;
@@ -162,7 +162,7 @@ autoLtas Ltases_average (LtasBag ltases) {
 	try {
 		double factor = -10.0 * log10 (ltases->size);
 		autoLtas thee = Ltases_merge (ltases);
-		for (long iband = 1; iband <= thy nx; iband ++) {
+		for (integer iband = 1; iband <= thy nx; iband ++) {
 			thy z [1] [iband] += factor;
 		}	
 		return thee;
@@ -223,32 +223,33 @@ autoLtas Ltas_subtractTrendLine (Ltas me, double fmin, double fmax) {
 		/*
 		 * 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;
+		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.
 		 */
+		real80 numerator = 0.0, denominator = 0.0;
 		for (long 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 < imin; i ++) {
+		for (integer i = 1; i < imin; i ++) {
 			thy z [1] [i] = 0.0;
 		}
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double df = thy x1 + (i - 1) * thy dx - fmean;
 			thy z [1] [i] -= amean + slope * df;
 		}
-		for (long i = imax + 1; i <= thy nx; i ++) {
+		for (integer i = imax + 1; i <= thy nx; i ++) {
 			thy z [1] [i] = 0.0;
 		}
 		return thee;
@@ -264,7 +265,7 @@ autoLtas Spectrum_to_Ltas (Spectrum me, double bandWidth) {
 			Melder_throw (U"Bandwidth must be greater than ", my dx, U".");
 		autoLtas thee = Thing_new (Ltas);
 		Matrix_init (thee.get(), my xmin, my xmax, numberOfBands, bandWidth, my xmin + 0.5 * bandWidth, 1.0, 1.0, 1, 1.0, 1.0);
-		for (long iband = 1; iband <= numberOfBands; iband ++) {
+		for (integer iband = 1; iband <= numberOfBands; iband ++) {
 			double fmin = thy xmin + (iband - 1) * bandWidth;
 			double meanEnergyDensity = Sampled_getMean (me, fmin, fmin + bandWidth, 0, 1, false);
 			double meanPowerDensity = meanEnergyDensity * my dx;   // as an approximation for a division by the original duration
@@ -280,7 +281,7 @@ autoLtas Spectrum_to_Ltas_1to1 (Spectrum me) {
 	try {
 		autoLtas thee = Thing_new (Ltas);
 		Matrix_init (thee.get(), my xmin, my xmax, my nx, my dx, my x1, 1.0, 1.0, 1, 1.0, 1.0);
-		for (long iband = 1; iband <= my nx; iband ++) {
+		for (integer iband = 1; iband <= my nx; iband ++) {
 			thy z [1] [iband] = Sampled_getValueAtSample (me, iband, 0, 2);
 		}
 		return thee;
@@ -294,7 +295,7 @@ autoLtas Sound_to_Ltas (Sound me, double bandwidth) {
 		autoSpectrum thee = Sound_to_Spectrum (me, true);
 		autoLtas him = Spectrum_to_Ltas (thee.get(), bandwidth);
 		double correction = -10.0 * log10 (thy dx * my nx * my dx);
-		for (long iband = 1; iband <= his nx; iband ++) {
+		for (integer iband = 1; iband <= his nx; iband ++) {
 			his z [1] [iband] += correction;
 		}
 		return him;
@@ -308,14 +309,14 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 	double shortestPeriod, double longestPeriod, double maximumPeriodFactor)
 {
 	try {
-		long numberOfPeriods = pulses -> nt - 2, totalNumberOfEnergies = 0;
-		autoLtas ltas = Ltas_create ((integer) floor (maximumFrequency / bandWidth), bandWidth);
+		integer numberOfPeriods = pulses -> nt - 2, totalNumberOfEnergies = 0;
+		autoLtas ltas = Ltas_create (Melder_iroundDown (maximumFrequency / bandWidth), bandWidth);
 		ltas -> xmax = maximumFrequency;
 		autoLtas numbers = Data_copy (ltas.get());
 		if (numberOfPeriods < 1)
 			Melder_throw (U"Cannot compute an Ltas if there are no periods in the point process.");
 		autoMelderProgress progress (U"Ltas analysis...");
-		for (long ipulse = 2; ipulse < pulses -> nt; ipulse ++) {
+		for (integer ipulse = 2; ipulse < pulses -> nt; ipulse ++) {
 			double leftInterval = pulses -> t [ipulse] - pulses -> t [ipulse - 1];
 			double rightInterval = pulses -> t [ipulse + 1] - pulses -> t [ipulse];
 			double intervalFactor = leftInterval > rightInterval ? leftInterval / rightInterval : rightInterval / leftInterval;
@@ -331,7 +332,7 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 					pulses -> t [ipulse] - 0.5 * leftInterval, pulses -> t [ipulse] + 0.5 * rightInterval,
 					kSound_windowShape::RECTANGULAR, 1.0, false);
 				autoSpectrum spectrum = Sound_to_Spectrum (period.get(), false);
-				for (long ifreq = 1; ifreq <= spectrum -> nx; ifreq ++) {
+				for (integer ifreq = 1; ifreq <= spectrum -> nx; ifreq ++) {
 					double frequency = spectrum -> xmin + (ifreq - 1) * spectrum -> dx;
 					double realPart = spectrum -> z [1] [ifreq];
 					double imaginaryPart = spectrum -> z [2] [ifreq];
@@ -376,9 +377,9 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 				}
 			}
 		}
-		for (long iband = 1; iband <= ltas -> nx; iband ++) {
+		for (integer iband = 1; iband <= ltas -> nx; iband ++) {
 			if (isundef (ltas -> z [1] [iband])) {
-				long ibandleft = iband - 1, ibandright = iband + 1;
+				integer ibandleft = iband - 1, ibandright = iband + 1;
 				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)
@@ -417,17 +418,17 @@ autoLtas Sound_to_Ltas_pitchCorrected (Sound sound, double minimumPitch, double
 }
 
 autoLtas PointProcess_Sound_to_Ltas_harmonics (PointProcess pulses, Sound sound,
-	long maximumHarmonic,
+	integer maximumHarmonic,
 	double shortestPeriod, double longestPeriod, double maximumPeriodFactor)
 {
 	try {
-		long numberOfPeriods = pulses -> nt - 2;
+		integer numberOfPeriods = pulses -> nt - 2;
 		autoLtas ltas = Ltas_create (maximumHarmonic, 1.0);
 		ltas -> xmax = maximumHarmonic;
 		if (numberOfPeriods < 1)
 			Melder_throw (U"There are no periods in the point process.");
 		autoMelderProgress progress (U"LTAS (harmonics) analysis...");
-		for (long ipulse = 2; ipulse < pulses -> nt; ipulse ++) {
+		for (integer ipulse = 2; ipulse < pulses -> nt; ipulse ++) {
 			double leftInterval = pulses -> t [ipulse] - pulses -> t [ipulse - 1];
 			double rightInterval = pulses -> t [ipulse + 1] - pulses -> t [ipulse];
 			double intervalFactor = leftInterval > rightInterval ? leftInterval / rightInterval : rightInterval / leftInterval;
@@ -439,13 +440,13 @@ autoLtas PointProcess_Sound_to_Ltas_harmonics (PointProcess pulses, Sound sound,
 				/*
 				 * We have a period! Compute the spectrum.
 				 */
-				long localMaximumHarmonic;
+				integer localMaximumHarmonic;
 				autoSound period = Sound_extractPart (sound,
 					pulses -> t [ipulse] - 0.5 * leftInterval, pulses -> t [ipulse] + 0.5 * rightInterval,
 					kSound_windowShape::RECTANGULAR, 1.0, false);
 				autoSpectrum spectrum = Sound_to_Spectrum (period.get(), false);
 				localMaximumHarmonic = maximumHarmonic < spectrum -> nx ? maximumHarmonic : spectrum -> nx;
-				for (long iharm = 1; iharm <= localMaximumHarmonic; iharm ++) {
+				for (integer iharm = 1; iharm <= localMaximumHarmonic; iharm ++) {
 					double realPart = spectrum -> z [1] [iharm];
 					double imaginaryPart = spectrum -> z [2] [iharm];
 					double energy = (realPart * realPart + imaginaryPart * imaginaryPart) * 2.0 * spectrum -> dx;
@@ -457,7 +458,7 @@ autoLtas PointProcess_Sound_to_Ltas_harmonics (PointProcess pulses, Sound sound,
 		}
 		if (numberOfPeriods < 1)
 			Melder_throw (U"There are no periods in the point process.");
-		for (long iharm = 1; iharm <= ltas -> nx; iharm ++) {
+		for (integer iharm = 1; iharm <= ltas -> nx; iharm ++) {
 			if (ltas -> z [1] [iharm] == 0.0) {
 				ltas -> z [1] [iharm] = -300.0;
 			} else {
diff --git a/fon/Ltas.h b/fon/Ltas.h
index ad5fea5..ccaab83 100644
--- a/fon/Ltas.h
+++ b/fon/Ltas.h
@@ -85,7 +85,7 @@ autoLtas PointProcess_Sound_to_Ltas (PointProcess pulses, Sound sound,
 	double maximumFrequency, double bandWidth,
 	double shortestPeriod, double longestPeriod, double maximumPeriodFactor);
 autoLtas PointProcess_Sound_to_Ltas_harmonics (PointProcess pulses, Sound sound,
-	long maximumHarmonic,
+	integer maximumHarmonic,
 	double shortestPeriod, double longestPeriod, double maximumPeriodFactor);
 
 /* Shortcuts. */
diff --git a/fon/Manipulation.cpp b/fon/Manipulation.cpp
index 1faa268..93f0efb 100644
--- a/fon/Manipulation.cpp
+++ b/fon/Manipulation.cpp
@@ -1,6 +1,6 @@
 /* Manipulation.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
@@ -158,10 +158,10 @@ int Manipulation_playPart (Manipulation me, double tmin, double tmax, int method
 			if (! my sound)
 				Melder_throw (U"Cannot synthesize overlap-add without a sound.");
 			autoSound part = Data_copy (my sound.get());
-			long imin = Sampled_xToLowIndex (part.get(), tmin), imax = Sampled_xToHighIndex (part.get(), tmax);
+			integer imin = Sampled_xToLowIndex (part.get(), tmin), imax = Sampled_xToHighIndex (part.get(), tmax);
 			double *amp = part -> z [1];
-			for (long i = 1; i <= imin; i ++) amp [i] = 0.0;
-			for (long i = imax; i <= part -> nx; i ++) amp [i] = 0.0;
+			for (integer i = 1; i <= imin; i ++) amp [i] = 0.0;
+			for (integer i = imax; i <= part -> nx; i ++) amp [i] = 0.0;
 			autoSound saved = my sound.move();
 			my sound = part.move();
 			try {
@@ -197,38 +197,38 @@ int Manipulation_play (Manipulation me, int method) {
 	}
 }
 
-static long PointProcess_getFirstVoicedPoint (PointProcess me, double maxT) {
-	for (long i = 1; i < my nt; i ++) if (my t [i + 1] - my t [i] <= maxT) return i;
+static integer PointProcess_getFirstVoicedPoint (PointProcess me, double maxT) {
+	for (integer i = 1; i < my nt; i ++) if (my t [i + 1] - my t [i] <= maxT) return i;
 	return 0;
 }
 
 static void copyRise (Sound me, double tmin, double tmax, Sound thee, double tmaxTarget) {
-	long imin = Sampled_xToHighIndex (me, tmin);
+	integer imin = Sampled_xToHighIndex (me, tmin);
 	if (imin < 1) imin = 1;
-	long imax = Sampled_xToHighIndex (me, tmax) - 1;   // not xToLowIndex: ensure separation of subsequent calls
+	integer imax = Sampled_xToHighIndex (me, tmax) - 1;   // not xToLowIndex: ensure separation of subsequent calls
 	if (imax > my nx) imax = my nx;
 	if (imax < imin) return;
-	long imaxTarget = Sampled_xToHighIndex (thee, tmaxTarget) - 1;
-	long distance = imaxTarget - imax;
+	integer imaxTarget = Sampled_xToHighIndex (thee, tmaxTarget) - 1;
+	integer distance = imaxTarget - imax;
 	double dphase = NUMpi / (imax - imin + 1);
-	for (long i = imin; i <= imax; i ++) {
-		long iTarget = i + distance;
+	for (integer i = imin; i <= imax; i ++) {
+		integer iTarget = i + distance;
 		if (iTarget >= 1 && iTarget <= thy nx)
 			thy z [1] [iTarget] += my z [1] [i] * 0.5 * (1.0 - cos (dphase * (i - imin + 0.5)));
 	}
 }
 
 static void copyFall (Sound me, double tmin, double tmax, Sound thee, double tminTarget) {
-	long imin = Sampled_xToHighIndex (me, tmin);
+	integer imin = Sampled_xToHighIndex (me, tmin);
 	if (imin < 1) imin = 1;
-	long imax = Sampled_xToHighIndex (me, tmax) - 1;   // not xToLowIndex: ensure separation of subsequent calls
+	integer imax = Sampled_xToHighIndex (me, tmax) - 1;   // not xToLowIndex: ensure separation of subsequent calls
 	if (imax > my nx) imax = my nx;
 	if (imax < imin) return;
-	long iminTarget = Sampled_xToHighIndex (thee, tminTarget);
-	long distance = iminTarget - imin;
+	integer iminTarget = Sampled_xToHighIndex (thee, tminTarget);
+	integer distance = iminTarget - imin;
 	double dphase = NUMpi / (imax - imin + 1);
-	for (long i = imin; i <= imax; i ++) {
-		long iTarget = i + distance;
+	for (integer i = imin; i <= imax; i ++) {
+		integer iTarget = i + distance;
 		if (iTarget >= 1 && iTarget <= thy nx)
 			thy z [1] [iTarget] += my z [1] [i] * 0.5 * (1.0 + cos (dphase * (i - imin + 0.5)));
 	}
@@ -239,7 +239,7 @@ static void copyBell (Sound me, double tmid, double leftWidth, double rightWidth
 	copyFall (me, tmid, tmid + rightWidth, thee, tmidTarget);
 }
 
-static void copyBell2 (Sound me, PointProcess source, long isource, double leftWidth, double rightWidth,
+static void copyBell2 (Sound me, PointProcess source, integer isource, double leftWidth, double rightWidth,
 	Sound thee, double tmidTarget, double maxT)
 {
 	/*
@@ -259,12 +259,12 @@ static void copyBell2 (Sound me, PointProcess source, long isource, double leftW
 }
 
 static void copyFlat (Sound me, double tmin, double tmax, Sound thee, double tminTarget) {
-	long imin = Sampled_xToHighIndex (me, tmin);
+	integer imin = Sampled_xToHighIndex (me, tmin);
 	if (imin < 1) imin = 1;
-	long imax = Sampled_xToHighIndex (me, tmax) - 1;   // not xToLowIndex: ensure separation of subsequent calls
+	integer imax = Sampled_xToHighIndex (me, tmax) - 1;   // not xToLowIndex: ensure separation of subsequent calls
 	if (imax > my nx) imax = my nx;
 	if (imax < imin) return;
-	long iminTarget = Sampled_xToHighIndex (thee, tminTarget);
+	integer iminTarget = Sampled_xToHighIndex (thee, tminTarget);
 	if (iminTarget < 1) iminTarget = 1;
 	trace (tmin, U" ", tmax, U" ", tminTarget, U" ", imin, U" ", imax, U" ", iminTarget);
 	Melder_assert (iminTarget + imax - imin <= thy nx);
@@ -278,14 +278,14 @@ autoSound Sound_Point_Point_to_Sound (Sound me, PointProcess source, PointProces
 			NUMvector_copyElements (my z [1], thy z [1], 1, my nx);
 			return thee;
 		}
-		for (long i = 1; i <= target -> nt; i ++) {
+		for (integer i = 1; i <= target -> nt; i ++) {
 			double tmid = target -> t [i];
 			double tleft = i > 1 ? target -> t [i - 1] : my xmin;
 			double tright = i < target -> nt ? target -> t [i + 1] : my xmax;
 			double leftWidth = tmid - tleft, rightWidth = tright - tmid;
 			int leftVoiced = i > 1 && leftWidth <= maxT;
 			int rightVoiced = i < target -> nt && rightWidth <= maxT;
-			long isource = PointProcess_getNearestIndex (source, tmid);
+			integer isource = PointProcess_getNearestIndex (source, tmid);
 			if (! leftVoiced) leftWidth = rightWidth;   // symmetric bell
 			if (! rightVoiced) rightWidth = leftWidth;   // symmetric bell
 			if (leftVoiced || rightVoiced) {
@@ -317,7 +317,7 @@ autoSound Sound_Point_Pitch_Duration_to_Sound (Sound me, PointProcess pulses,
 	PitchTier pitch, DurationTier duration, double maxT)
 {
 	try {
-		long ipointleft, ipointright;
+		integer ipointleft, ipointright;
 		double deltat = 0, handledTime = my xmin;
 		double startOfSourceNoise, endOfSourceNoise, startOfTargetNoise, endOfTargetNoise;
 		double durationOfSourceNoise, durationOfTargetNoise;
@@ -404,7 +404,7 @@ autoSound Sound_Point_Pitch_Duration_to_Sound (Sound me, PointProcess pulses,
 			ttarget = startOfTargetVoice + 0.5 * startingPeriod;
 			while (ttarget < endOfTargetVoice) {
 				double tsource, period;
-				long isourcepulse;
+				integer isourcepulse;
 				double tleft = startOfSourceVoice, tright = endOfSourceVoice;
 				int i;
 				for (i = 1; i <= 15; i ++) {
@@ -569,10 +569,10 @@ static Sound synthesize_pulses_formant (Manipulation me, int useIntensity) {
 */
 
 static void Sound_PointProcess_fillVoiceless (Sound me, PointProcess pulses) {
-	long ipointleft, ipointright;
+	integer ipointleft, ipointright;
 	double beginVoiceless = my xmin, endVoiceless;
 	for (ipointleft = 1; ipointleft <= pulses -> nt; ipointleft = ipointright + 1) {
-		long i1, i2, i;
+		integer i1, i2, i;
 		endVoiceless = pulses -> t [ipointleft] - 0.005;
 		i1 = Sampled_xToHighIndex (me, beginVoiceless);
 		if (i1 < 1) i1 = 1; if (i1 > my nx) i1 = my nx;
@@ -588,7 +588,7 @@ static void Sound_PointProcess_fillVoiceless (Sound me, PointProcess pulses) {
 	}
 	endVoiceless = my xmax;
 	{
-		long i1, i2, i;
+		integer i1, i2, i;
 		i1 = Sampled_xToHighIndex (me, beginVoiceless);
 		if (i1 < 1) i1 = 1; if (i1 > my nx) i1 = my nx;
 		i2 = Sampled_xToLowIndex (me, endVoiceless);
diff --git a/fon/Matrix.cpp b/fon/Matrix.cpp
index 7630ef6..fc667c7 100644
--- a/fon/Matrix.cpp
+++ b/fon/Matrix.cpp
@@ -102,7 +102,7 @@ double structMatrix :: v_getMatrix (integer irow, integer 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;
-	integer irow = (integer) floor (rrow), icol = (integer) floor (rcol);
+	integer irow = Melder_iroundDown (rrow), icol = Melder_iroundDown (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];
@@ -154,23 +154,23 @@ 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; }
 
-integer Matrix_xToLowColumn (Matrix me, double x) { return (integer) floor (Matrix_xToColumn (me, x)); }
+integer Matrix_xToLowColumn (Matrix me, double x) { return Melder_iroundDown (Matrix_xToColumn (me, x)); }
 
 integer Matrix_xToHighColumn (Matrix me, double x) { return (integer) ceil (Matrix_xToColumn (me, x)); }
 
-integer Matrix_xToNearestColumn (Matrix me, double x) { return (integer) floor (Matrix_xToColumn (me, x) + 0.5); }
+integer Matrix_xToNearestColumn (Matrix me, double x) { return Melder_iround_tieUp (Matrix_xToColumn (me, x)); }
 
 double Matrix_yToRow (Matrix me, double y) { return (y - my y1) / my dy + 1.0; }
 
-integer Matrix_yToLowRow (Matrix me, double y) { return (integer) floor (Matrix_yToRow (me, y)); }
+integer Matrix_yToLowRow (Matrix me, double y) { return Melder_iroundDown (Matrix_yToRow (me, y)); }
 
 integer Matrix_yToHighRow (Matrix me, double y) { return (integer) ceil (Matrix_yToRow (me, y)); }
 
-integer Matrix_yToNearestRow (Matrix me, double y) { return (integer) floor (Matrix_yToRow (me, y) + 0.5); }
+integer Matrix_yToNearestRow (Matrix me, double y) { return Melder_iround_tieUp (Matrix_yToRow (me, y)); }
 
 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);
+	*ixmax = 1 + Melder_iroundDown ((xmax - my x1) / my dx);
 	if (*ixmin < 1) *ixmin = 1;
 	if (*ixmax > my nx) *ixmax = my nx;
 	if (*ixmin > *ixmax) return 0;
@@ -179,7 +179,7 @@ integer Matrix_getWindowSamplesX (Matrix me, double xmin, double xmax, integer *
 
 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);
+	*iymax = 1 + Melder_iroundDown ((ymax - my y1) / my dy);
 	if (*iymin < 1) *iymin = 1;
 	if (*iymax > my ny) *iymax = my ny;
 	if (*iymin > *iymax) return 0;
@@ -216,9 +216,9 @@ double Matrix_getValueAtXY (Matrix me, double x, double y) {
 	/*
 	 * Determine the four nearest (xi, yi) points.
 	 */
-	integer bottomRow = (integer) floor (row_real);   // 0 <= bottomRow <= my ny
+	integer bottomRow = Melder_iroundDown (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 leftCol = Melder_iroundDown (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
diff --git a/fon/Matrix_and_Polygon.cpp b/fon/Matrix_and_Polygon.cpp
index b762c34..b6b71f0 100644
--- a/fon/Matrix_and_Polygon.cpp
+++ b/fon/Matrix_and_Polygon.cpp
@@ -1,6 +1,6 @@
 /* Matrix_and_Polygon.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
@@ -36,7 +36,7 @@ autoPolygon Matrix_to_Polygon (Matrix me) {
 			NUMvector_copyElements (my z [2], thy y, 1, my nx);
 		} else {
 			thee = Polygon_create (my ny);
-			for (long i = 1; i <= my ny; i ++) {
+			for (integer i = 1; i <= my ny; i ++) {
 				thy x [i] = my z [i] [1];
 				thy y [i] = my z [i] [2];
 			}
diff --git a/fon/Movie.cpp b/fon/Movie.cpp
index dae4aa9..33f81e7 100644
--- a/fon/Movie.cpp
+++ b/fon/Movie.cpp
@@ -82,7 +82,7 @@ autoMovie Movie_openFromSoundFile (MelderFile file)
 	}
 }
 
-void Movie_paintOneImageInside (Movie me, Graphics graphics, long frameNumber, double xmin, double xmax, double ymin, double ymax)
+void Movie_paintOneImageInside (Movie me, Graphics graphics, integer frameNumber, double xmin, double xmax, double ymin, double ymax)
 {
 	try {
 		if (frameNumber < 1) Melder_throw (U"Specified frame number is ", frameNumber, U" but should be at least 1.");
@@ -99,7 +99,7 @@ void Movie_paintOneImageInside (Movie me, Graphics graphics, long frameNumber, d
 	}
 }
 
-void Movie_paintOneImage (Movie me, Graphics graphics, long frameNumber, double xmin, double xmax, double ymin, double ymax) {
+void Movie_paintOneImage (Movie me, Graphics graphics, integer frameNumber, double xmin, double xmax, double ymin, double ymax) {
 	try {
 		Graphics_setInner (graphics);
 		Graphics_setWindow (graphics, 0.0, 1.0, 0.0, 1.0);
diff --git a/fon/Movie.h b/fon/Movie.h
index 4e16886..cb7f5d4 100644
--- a/fon/Movie.h
+++ b/fon/Movie.h
@@ -2,7 +2,7 @@
 #define _Movie_h_
 /* Movie.h
  *
- * Copyright (C) 2011,2014,2015 Paul Boersma
+ * Copyright (C) 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
@@ -29,9 +29,9 @@ autoMovie Movie_openFromSoundFile (MelderFile file);
 
 void Movie_init (Movie me, autoSound sound, const char32 *folderName, autoStrings fileNames);
 
-void Movie_paintOneImageInside (Movie me, Graphics graphics, long frameNumber, double xmin, double xmax, double ymin, double ymax);
+void Movie_paintOneImageInside (Movie me, Graphics graphics, integer frameNumber, double xmin, double xmax, double ymin, double ymax);
 
-void Movie_paintOneImage (Movie me, Graphics graphics, long frameNumber, double xmin, double xmax, double ymin, double ymax);
+void Movie_paintOneImage (Movie me, Graphics graphics, integer frameNumber, double xmin, double xmax, double ymin, double ymax);
 
 void Movie_play (Movie me, Graphics graphics, double tmin, double tmax, Sound_PlayCallback callback, Thing boss);
 
diff --git a/fon/ParamCurve.cpp b/fon/ParamCurve.cpp
index 299c0f6..91879d0 100644
--- a/fon/ParamCurve.cpp
+++ b/fon/ParamCurve.cpp
@@ -1,6 +1,6 @@
 /* ParamCurve.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
@@ -33,12 +33,12 @@ Thing_implement (ParamCurve, Function, 2);
 
 void structParamCurve :: v_info () {
 	double xvalmin = 1e308, xvalmax = -1e308, yvalmin = 1e308, yvalmax = -1e308;
-	for (long i = 1; i <= our x -> nx; i ++) {
+	for (integer i = 1; i <= our x -> nx; i ++) {
 		double value = our x -> z [1] [i];
 		if (value < xvalmin) xvalmin = value;
 		if (value > xvalmax) xvalmax = value;
 	}
-	for (long i = 1; i <= y -> nx; i ++) {
+	for (integer i = 1; i <= y -> nx; i ++) {
 		double value = our y -> z [1] [i];
 		if (value < yvalmin) yvalmin = value;
 		if (value > yvalmax) yvalmax = value;
@@ -127,11 +127,11 @@ void ParamCurve_draw (ParamCurve me, Graphics g, double t1, double t2, double dt
 	if (y1 == y2) { y1 -= 1.0; y2 += 1.0; }
 	if (dt <= 0.0)
 		dt = my x -> dx < my y -> dx ? my x -> dx : my y -> dx;
-	long numberOfPoints = (long) ceil ((t2 - t1) / dt) + 1;
+	integer numberOfPoints = (integer) ceil ((t2 - t1) / dt) + 1;
 	if (numberOfPoints > 0) {
 		autoNUMvector <double> x (1, numberOfPoints);
 		autoNUMvector <double> y (1, numberOfPoints);
-		for (long i = 1; i <= numberOfPoints; i ++) {
+		for (integer i = 1; i <= numberOfPoints; i ++) {
 			double t = i == numberOfPoints ? t2 : t1 + (i - 1) * dt;
 			double index = Sampled_xToIndex (my x.get(), t);
 			x [i] = NUM_interpolate_sinc (my x -> z [1], my x -> nx, index, 50);
diff --git a/fon/Photo.cpp b/fon/Photo.cpp
index f05103f..93cb475 100644
--- a/fon/Photo.cpp
+++ b/fon/Photo.cpp
@@ -1,6 +1,6 @@
 /* Photo.cpp
  *
- * Copyright (C) 2013,2014,2015,2016 Paul Boersma
+ * Copyright (C) 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
@@ -65,8 +65,8 @@ void structPhoto :: v_info () {
 }
 
 void Photo_init (Photo 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)
 {
 	SampledXY_init (me, xmin, xmax, nx, dx, x1, ymin, ymax, ny, dy, y1);
 	my d_red =          Matrix_create (xmin, xmax, nx, dx, x1, ymin, ymax, ny, dy, y1);
@@ -76,8 +76,8 @@ void Photo_init (Photo me,
 }
 
 autoPhoto Photo_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 {
 		autoPhoto me = Thing_new (Photo);
@@ -88,7 +88,7 @@ autoPhoto Photo_create
 	}
 }
 
-autoPhoto Photo_createSimple (long numberOfRows, long numberOfColumns) {
+autoPhoto Photo_createSimple (integer numberOfRows, integer numberOfColumns) {
 	try {
 		autoPhoto me = Thing_new (Photo);
 		Photo_init (me.get(), 0.5, numberOfColumns + 0.5, numberOfColumns, 1, 1,
@@ -105,20 +105,20 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 			cairo_surface_t *surface = cairo_image_surface_create_from_png (Melder_peek32to8 (file -> path));
 			//if (cairo_surface_status)
 			//	Melder_throw (U"Error opening PNG file.");
-			long width = cairo_image_surface_get_width (surface);
-			long height = cairo_image_surface_get_height (surface);
+			integer width = cairo_image_surface_get_width (surface);
+			integer height = cairo_image_surface_get_height (surface);
 			if (width == 0 || height == 0) {
 				cairo_surface_destroy (surface);
 				Melder_throw (U"Error reading PNG file.");
 			}
 			unsigned char *imageData = cairo_image_surface_get_data (surface);
-			long bytesPerRow = cairo_image_surface_get_stride (surface);
+			integer bytesPerRow = cairo_image_surface_get_stride (surface);
 			cairo_format_t format = cairo_image_surface_get_format (surface);
 			autoPhoto me = Photo_createSimple (height, width);
 			if (format == CAIRO_FORMAT_ARGB32) {
-				for (long irow = 1; irow <= height; irow ++) {
+				for (integer irow = 1; irow <= height; irow ++) {
 					uint8_t *rowAddress = imageData + bytesPerRow * (height - irow);
-					for (long icol = 1; icol <= width; icol ++) {
+					for (integer icol = 1; icol <= width; icol ++) {
 						my d_blue  -> z [irow] [icol] = (* rowAddress ++) / 255.0;
 						my d_green -> z [irow] [icol] = (* rowAddress ++) / 255.0;
 						my d_red   -> z [irow] [icol] = (* rowAddress ++) / 255.0;
@@ -126,9 +126,9 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 					}
 				}
 			} else if (format == CAIRO_FORMAT_RGB24) {
-				for (long irow = 1; irow <= height; irow ++) {
+				for (integer irow = 1; irow <= height; irow ++) {
 					uint8_t *rowAddress = imageData + bytesPerRow * (height - irow);
-					for (long icol = 1; icol <= width; icol ++) {
+					for (integer icol = 1; icol <= width; icol ++) {
 						my d_blue  -> z [irow] [icol] = (* rowAddress ++) / 255.0;
 						my d_green -> z [irow] [icol] = (* rowAddress ++) / 255.0;
 						my d_red   -> z [irow] [icol] = (* rowAddress ++) / 255.0;
@@ -143,13 +143,13 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 			return me;
 		#elif defined (_WIN32)
 			Gdiplus::Bitmap gdiplusBitmap (Melder_peek32toW (file -> path));
-			long width = gdiplusBitmap. GetWidth ();
-			long height = gdiplusBitmap. GetHeight ();
+			integer width = gdiplusBitmap. GetWidth ();
+			integer height = gdiplusBitmap. GetHeight ();
 			if (width == 0 || height == 0)
 				Melder_throw (U"Error reading PNG file.");
 			autoPhoto me = Photo_createSimple (height, width);
-			for (long irow = 1; irow <= height; irow ++) {
-				for (long icol = 1; icol <= width; icol ++) {
+			for (integer irow = 1; irow <= height; irow ++) {
+				for (integer icol = 1; icol <= width; icol ++) {
 					Gdiplus::Color gdiplusColour;
 					gdiplusBitmap. GetPixel (icol - 1, height - irow, & gdiplusColour);
 					my d_red -> z [irow] [icol] = (gdiplusColour. GetRed ()) / 255.0;
@@ -173,12 +173,12 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 			CGImageRef image = CGImageSourceCreateImageAtIndex (imageSource, 0, nullptr);
 			CFRelease (imageSource);
 			if (image) {
-				long width = CGImageGetWidth (image);
-				long height = CGImageGetHeight (image);
+				integer width = CGImageGetWidth (image);
+				integer height = CGImageGetHeight (image);
 				me = Photo_createSimple (height, width);
-				long bitsPerPixel = CGImageGetBitsPerPixel (image);
-				long bitsPerComponent = CGImageGetBitsPerComponent (image);
-				long bytesPerRow = CGImageGetBytesPerRow (image);
+				integer bitsPerPixel = CGImageGetBitsPerPixel (image);
+				integer bitsPerComponent = CGImageGetBitsPerComponent (image);
+				integer bytesPerRow = CGImageGetBytesPerRow (image);
 				trace (
 					bitsPerPixel, U" bits per pixel, ",
 					bitsPerComponent, U" bits per component, ",
@@ -192,9 +192,9 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 				CGDataProviderRef dataProvider = CGImageGetDataProvider (image);   // not retained, so don't release
 				CFDataRef data = CGDataProviderCopyData (dataProvider);
 				uint8_t *pixelData = (uint8_t *) CFDataGetBytePtr (data);
-				for (long irow = 1; irow <= height; irow ++) {
+				for (integer irow = 1; irow <= height; irow ++) {
 					uint8_t *rowAddress = pixelData + bytesPerRow * (height - irow);
-					for (long icol = 1; icol <= width; icol ++) {
+					for (integer icol = 1; icol <= width; icol ++) {
 						my d_red   -> z [irow] [icol] = (*rowAddress ++) / 255.0;
 						my d_green -> z [irow] [icol] = (*rowAddress ++) / 255.0;
 						my d_blue  -> z [irow] [icol] = (*rowAddress ++) / 255.0;
@@ -224,12 +224,12 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 #if defined (linux) && ! defined (NO_GRAPHICS)
 	static void _lin_saveAsImageFile (Photo me, MelderFile file, const char32 *which) {
 		cairo_format_t format = CAIRO_FORMAT_ARGB32;
-		long bytesPerRow = cairo_format_stride_for_width (format, my nx);   // likely to be my nx * 4
-		long numberOfRows = my ny;
+		integer bytesPerRow = cairo_format_stride_for_width (format, my nx);   // likely to be my nx * 4
+		integer numberOfRows = my ny;
 		uint8 *imageData = Melder_malloc_f (uint8, bytesPerRow * numberOfRows);
-		for (long irow = 1; irow <= my ny; irow ++) {
+		for (integer irow = 1; irow <= my ny; irow ++) {
 			uint8 *rowAddress = imageData + bytesPerRow * (my ny - irow);
-			for (long icol = 1; icol <= my nx; icol ++) {
+			for (integer icol = 1; icol <= my nx; icol ++) {
 				* rowAddress ++ = round (my d_blue         -> z [irow] [icol] * 255.0);
 				* rowAddress ++ = round (my d_green        -> z [irow] [icol] * 255.0);
 				* rowAddress ++ = round (my d_red          -> z [irow] [icol] * 255.0);
@@ -246,8 +246,8 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 #ifdef _WIN32
 	static void _win_saveAsImageFile (Photo me, MelderFile file, const char32 *mimeType) {
 		Gdiplus::Bitmap gdiplusBitmap (my nx, my ny, PixelFormat32bppARGB);
-		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 ++) {
 				Gdiplus::Color gdiplusColour (
 					255 - round (my d_transparency -> z [irow] [icol] * 255.0),
 					round (my d_red   -> z [irow] [icol] * 255.0),
@@ -291,12 +291,12 @@ autoPhoto Photo_readFromImageFile (MelderFile file) {
 
 #ifdef macintosh
 	static void _mac_saveAsImageFile (Photo me, MelderFile file, const void *which) {
-		long bytesPerRow = my nx * 4;
-		long numberOfRows = my ny;
+		integer bytesPerRow = my nx * 4;
+		integer numberOfRows = my ny;
 		unsigned char *imageData = Melder_malloc_f (unsigned char, bytesPerRow * numberOfRows);
-		for (long irow = 1; irow <= my ny; irow ++) {
+		for (integer irow = 1; irow <= my ny; irow ++) {
 			uint8_t *rowAddress = imageData + bytesPerRow * (my ny - irow);
-			for (long icol = 1; icol <= my nx; icol ++) {
+			for (integer icol = 1; icol <= my nx; icol ++) {
 				* rowAddress ++ = (uint8) lround (my d_red          -> z [irow] [icol] * 255.0);   // BUG: should be tested for speed
 				* rowAddress ++ = (uint8) lround (my d_green        -> z [irow] [icol] * 255.0);
 				* rowAddress ++ = (uint8) lround (my d_blue         -> z [irow] [icol] * 255.0);
diff --git a/fon/Photo.h b/fon/Photo.h
index 351dd8b..fb5b200 100644
--- a/fon/Photo.h
+++ b/fon/Photo.h
@@ -23,12 +23,12 @@
 #include "Photo_def.h"
 
 void Photo_init (Photo 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);
 
 autoPhoto Photo_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 opaque black Photo.
@@ -53,7 +53,7 @@ autoPhoto Photo_create
 		result -> d_transparency -> z [1..ny] [1..nx] == 0.0;
 */
 
-autoPhoto Photo_createSimple (long numberOfRows, long numberOfColumns);
+autoPhoto Photo_createSimple (integer numberOfRows, integer numberOfColumns);
 /*
 	Function:
 		return a new opaque black Photo.
diff --git a/fon/Pitch.cpp b/fon/Pitch.cpp
index 08063ba..21e03f1 100644
--- a/fon/Pitch.cpp
+++ b/fon/Pitch.cpp
@@ -147,7 +147,7 @@ double structPitch :: v_getValueAtSample (integer iframe, integer ilevel, int un
 	return v_convertStandardToSpecialUnit (ilevel == Pitch_LEVEL_FREQUENCY ? f : frame [iframe]. candidate [1]. strength, ilevel, unit);
 }
 
-bool Pitch_isVoiced_i (Pitch me, long iframe) {
+bool Pitch_isVoiced_i (Pitch me, integer iframe) {
 	return isdefined (Sampled_getValueAtSample (me, iframe, Pitch_LEVEL_FREQUENCY, (int) kPitch_unit::HERTZ));
 }
 
@@ -163,7 +163,7 @@ double Pitch_getStrengthAtTime (Pitch me, double time, kPitch_unit unit, bool in
 	return Sampled_getValueAtX (me, time, Pitch_LEVEL_STRENGTH, (int) unit, interpolate);
 }
 
-long Pitch_countVoicedFrames (Pitch me) {
+integer Pitch_countVoicedFrames (Pitch me) {
 	return Sampled_countDefinedSamples (me, Pitch_LEVEL_FREQUENCY, (int) kPitch_unit::HERTZ);
 }
 
@@ -235,25 +235,25 @@ double Pitch_getTimeOfMinimum (Pitch me, double tmin, double tmax, kPitch_unit u
 	return time;
 }
 
-static long Pitch_getMeanAbsoluteSlope (Pitch me,
+static integer Pitch_getMeanAbsoluteSlope (Pitch me,
 	double *out_hertz, double *out_mel, double *out_semitones, double *out_erb, double *out_withoutOctaveJumps)
 {
-	long firstVoicedFrame = 0, lastVoicedFrame = 0, nVoiced = 0;
+	integer firstVoicedFrame = 0, lastVoicedFrame = 0, nVoiced = 0;
 	autoNUMvector <double> frequencies (1, my nx);
-	for (long i = 1; i <= my nx; i ++) {
+	for (integer 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 );
 		if (frequencies [i] != 0.0) nVoiced ++;
 	}
-	for (long i = 1; i <= my nx; i ++)   // look for first voiced frame
+	for (integer i = 1; i <= my nx; i ++)   // look for first voiced frame
 		if (frequencies [i] != 0.0) { firstVoicedFrame = i; break; }
-	for (long i = my nx; i >= 1; i --)   // look for last voiced frame
+	for (integer i = my nx; i >= 1; i --)   // look for last voiced frame
 		if (frequencies [i] != 0.0) { lastVoicedFrame = i; break; }
 	if (nVoiced > 1) {
 		int ilast = firstVoicedFrame;
 		double span = (lastVoicedFrame - firstVoicedFrame) * my dx, flast = frequencies [ilast];
 		double slopeHz = 0.0, slopeMel = 0.0, slopeSemitones = 0.0, slopeErb = 0.0, slopeRobust = 0.0;
-		for (long i = firstVoicedFrame + 1; i <= lastVoicedFrame; i ++) if (frequencies [i] != 0.0) {
+		for (integer i = firstVoicedFrame + 1; i <= lastVoicedFrame; i ++) if (frequencies [i] != 0.0) {
 			double localStepSemitones = fabs (SEMITONES (frequencies [i]) - SEMITONES (flast));
 			slopeHz += fabs (frequencies [i] - flast);
 			slopeMel += fabs (MEL (frequencies [i]) - MEL (flast));
@@ -280,28 +280,28 @@ static long Pitch_getMeanAbsoluteSlope (Pitch me,
 	return nVoiced;
 }
 
-long Pitch_getMeanAbsSlope_hertz (Pitch me, double *slope) {
+integer Pitch_getMeanAbsSlope_hertz (Pitch me, double *slope) {
 	return Pitch_getMeanAbsoluteSlope (me, slope, nullptr, nullptr, nullptr, nullptr);
 }
 
-long Pitch_getMeanAbsSlope_mel (Pitch me, double *slope) {
+integer Pitch_getMeanAbsSlope_mel (Pitch me, double *slope) {
 	return Pitch_getMeanAbsoluteSlope (me, nullptr, slope, nullptr, nullptr, nullptr);
 }
 
-long Pitch_getMeanAbsSlope_semitones (Pitch me, double *slope) {
+integer Pitch_getMeanAbsSlope_semitones (Pitch me, double *slope) {
 	return Pitch_getMeanAbsoluteSlope (me, nullptr, nullptr, slope, nullptr, nullptr);
 }
 
-long Pitch_getMeanAbsSlope_erb (Pitch me, double *slope) {
+integer Pitch_getMeanAbsSlope_erb (Pitch me, double *slope) {
 	return Pitch_getMeanAbsoluteSlope (me, nullptr, nullptr, nullptr, slope, nullptr);
 }
 
-long Pitch_getMeanAbsSlope_noOctave (Pitch me, double *slope) {
+integer Pitch_getMeanAbsSlope_noOctave (Pitch me, double *slope) {
 	return Pitch_getMeanAbsoluteSlope (me, nullptr, nullptr, nullptr, nullptr, slope);
 }
 
 void structPitch :: v_info () {
-	long nVoiced;
+	integer nVoiced;
 	autoNUMvector <double> frequencies (Sampled_getSortedValues (this, Pitch_LEVEL_FREQUENCY, (int) kPitch_unit::HERTZ, & nVoiced), 1);
 	structDaata :: v_info ();
 	MelderInfo_writeLine (U"Time domain:");
@@ -390,7 +390,7 @@ void Pitch_Frame_init (Pitch_Frame me, int nCandidates) {
 	my nCandidates = nCandidates;
 }
 
-autoPitch Pitch_create (double tmin, double tmax, long nt, double dt, double t1,
+autoPitch Pitch_create (double tmin, double tmax, integer nt, double dt, double t1,
 	double ceiling, int maxnCandidates)
 {
 	try {
@@ -401,7 +401,7 @@ autoPitch Pitch_create (double tmin, double tmax, long nt, double dt, double t1,
 		my frame = NUMvector <structPitch_Frame> (1, nt);
 
 		/* Put one candidate in every frame (unvoiced, silent). */
-		for (long it = 1; it <= nt; it ++) {
+		for (integer it = 1; it <= nt; it ++) {
 			Pitch_Frame_init (& my frame [it], 1);
 		}
 
@@ -417,7 +417,7 @@ void Pitch_setCeiling (Pitch me, double ceiling) {
 
 int Pitch_getMaxnCandidates (Pitch me) {
 	int result = 0;
-	for (long i = 1; i <= my nx; i ++) {
+	for (integer i = 1; i <= my nx; i ++) {
 		int nCandidates = my frame [i]. nCandidates;
 		if (nCandidates > result) result = nCandidates;
 	}
@@ -438,8 +438,8 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 			U"\nCeiling = ", ceiling,
 			U"\nPull formants = ", pullFormants);
 	try {
-		long maxnCandidates = Pitch_getMaxnCandidates (me);
-		long place;
+		integer maxnCandidates = Pitch_getMaxnCandidates (me);
+		integer place;
 		volatile double maximum, value;
 		double ceiling2 = pullFormants ? 2 * ceiling : ceiling;
 		/* Next three lines 20011015 */
@@ -449,14 +449,14 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 
 		my ceiling = ceiling;
 		autoNUMmatrix <double> delta (1, my nx, 1, maxnCandidates);
-		autoNUMmatrix <long> psi (1, my nx, 1, maxnCandidates);
+		autoNUMmatrix <integer> psi (1, my nx, 1, maxnCandidates);
 
-		for (long iframe = 1; iframe <= my nx; iframe ++) {
+		for (integer iframe = 1; iframe <= my nx; iframe ++) {
 			Pitch_Frame frame = & my frame [iframe];
 			double unvoicedStrength = silenceThreshold <= 0 ? 0 :
 				2 - frame->intensity / (silenceThreshold / (1 + voicingThreshold));
 			unvoicedStrength = voicingThreshold + (unvoicedStrength > 0 ? unvoicedStrength : 0);
-			for (long icand = 1; icand <= frame->nCandidates; icand ++) {
+			for (integer icand = 1; icand <= frame->nCandidates; icand ++) {
 				Pitch_Candidate candidate = & frame->candidate [icand];
 				bool voiceless = ! (candidate->frequency > 0.0 && candidate->frequency < ceiling2);
 				delta [iframe] [icand] = voiceless ? unvoicedStrength :
@@ -468,15 +468,15 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 		/* There is a cost for the voiced/unvoiced transition, */
 		/* and a cost for a frequency jump. */
 
-		for (long iframe = 2; iframe <= my nx; iframe ++) {
+		for (integer iframe = 2; iframe <= my nx; iframe ++) {
 			Pitch_Frame prevFrame = & my frame [iframe - 1], curFrame = & my frame [iframe];
 			double *prevDelta = delta [iframe - 1], *curDelta = delta [iframe];
-			long *curPsi = psi [iframe];
-			for (long icand2 = 1; icand2 <= curFrame -> nCandidates; icand2 ++) {
+			integer *curPsi = psi [iframe];
+			for (integer icand2 = 1; icand2 <= curFrame -> nCandidates; icand2 ++) {
 				double f2 = curFrame -> candidate [icand2]. frequency;
 				maximum = -1e30;
 				place = 0;
-				for (long icand1 = 1; icand1 <= prevFrame -> nCandidates; icand1 ++) {
+				for (integer icand1 = 1; icand1 <= prevFrame -> nCandidates; icand1 ++) {
 					double f1 = prevFrame -> candidate [icand1]. frequency;
 					double transitionCost;
 					bool previousVoiceless = ! (f1 > 0.0 && f1 < ceiling2);
@@ -494,8 +494,8 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 								/*
 								 * Try to take into account a frequency jump across a voiceless stretch.
 								 */
-								long place1 = icand1;
-								for (long jframe = iframe - 2; jframe >= 1; jframe --) {
+								integer place1 = icand1;
+								for (integer jframe = iframe - 2; jframe >= 1; jframe --) {
 									place1 = psi [jframe + 1] [place1];
 									f1 = my frame [jframe]. candidate [place1]. frequency;
 									if (f1 > 0.0 && f1 < ceiling) {
@@ -532,7 +532,7 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 
 		place = 1;
 		maximum = delta [my nx] [place];
-		for (long icand = 2; icand <= my frame [my nx]. nCandidates; icand ++) {
+		for (integer icand = 2; icand <= my frame [my nx]. nCandidates; icand ++) {
 			if (delta [my nx] [icand] > maximum) {
 				place = icand;
 				maximum = delta [my nx] [place];
@@ -541,7 +541,7 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 
 		/* Backtracking: follow the path backwards. */
 
-		for (long iframe = my nx; iframe >= 1; iframe --) {
+		for (integer iframe = my nx; iframe >= 1; iframe --) {
 			if (Melder_debug == 33)
 				Melder_casual (
 					U"Frame ", iframe, U":",
@@ -559,12 +559,12 @@ void Pitch_pathFinder (Pitch me, double silenceThreshold, double voicingThreshol
 		if (ceiling2 > ceiling) {
 			if (Melder_debug == 33)
 				Melder_casual (U"Pulling formants...");
-			for (long iframe = my nx; iframe >= 1; iframe --) {
+			for (integer iframe = my nx; iframe >= 1; iframe --) {
 				Pitch_Frame frame = & my frame [iframe];
 				Pitch_Candidate winner = & frame -> candidate [1];
 				double f = winner -> frequency;
 				if (f > ceiling && f < ceiling2) {
-					for (long icand = 2; icand <= frame -> nCandidates; icand ++) {
+					for (integer icand = 2; icand <= frame -> nCandidates; icand ++) {
 						Pitch_Candidate loser = & frame -> candidate [icand];
 						if (loser -> frequency == 0.0) {
 							structPitch_Candidate help = * winner;
@@ -603,12 +603,12 @@ void Pitch_draw (Pitch me, Graphics g, double tmin, double tmax, double fmin, do
 }
 
 void Pitch_difference (Pitch me, Pitch thee) {
-	long nuvtov = 0, nvtouv = 0, ndfdown = 0, ndfup = 0;
+	integer nuvtov = 0, nvtouv = 0, ndfdown = 0, ndfup = 0;
 	if (my nx != thy nx || my dx != thy dx || my x1 != thy x1) {
 		Melder_flushError (U"Pitch_difference: these Pitches are not aligned.");
 		return;
 	}
-	for (long i = 1; i <= my nx; i ++) {
+	for (integer 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.0 && myf < my ceiling);
 		int thyUnvoiced = ! (thyf > 0.0 && thyf < thy ceiling);
@@ -649,9 +649,9 @@ void Pitch_difference (Pitch me, Pitch thee) {
 autoPitch Pitch_killOctaveJumps (Pitch me) {
 	try {
 		autoPitch thee = Pitch_create (my xmin, my xmax, my nx, my dx, my x1, my ceiling, 2);
-		long nVoiced = 0, nUp = 0;
+		integer nVoiced = 0, nUp = 0;
 		double lastFrequency = 0.0;
-		for (long i = 1; i <= my nx; i ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			double f = my frame [i]. candidate [1]. frequency;
 			thy frame [i]. candidate [1]. strength = my frame [i]. candidate [1]. strength;
 			if (f > 0.0 && f < my ceiling) {
@@ -666,12 +666,12 @@ autoPitch Pitch_killOctaveJumps (Pitch me) {
 		}
 		thy ceiling *= 2.0;   // make room for some octave jumps
 		while (nUp > nVoiced / 2) {
-			for (long i = 1; i <= thy nx; i ++)
+			for (integer i = 1; i <= thy nx; i ++)
 				thy frame [i]. candidate [1]. frequency *= 0.5;
 			nUp -= nVoiced;
 		}
 		while (nUp < - nVoiced / 2) {
-			for (long i = 1; i <= thy nx; i ++)
+			for (integer i = 1; i <= thy nx; i ++)
 				thy frame [i]. candidate [1]. frequency *= 2.0;
 			nUp += nVoiced;
 		}
@@ -684,13 +684,13 @@ autoPitch Pitch_killOctaveJumps (Pitch me) {
 autoPitch Pitch_interpolate (Pitch me) {
 	try {
 		autoPitch thee = Pitch_create (my xmin, my xmax, my nx, my dx, my x1, my ceiling, 2);
-		for (long i = 1; i <= my nx; i ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			double f = my frame [i]. candidate [1]. frequency;
 			thy frame [i]. candidate [1]. strength = 0.9;
 			if (f > 0.0 && f < my ceiling) {
 				thy frame [i]. candidate [1]. frequency = f;
 			} else {
-				long left, right;
+				integer left, right;
 				double fleft = 0.0, fright = 0.0;
 				for (left = i - 1; left >= 1 && fleft == 0.0; left --) {
 					fleft = my frame [left]. candidate [1]. frequency;
@@ -717,18 +717,18 @@ autoPitch Pitch_subtractLinearFit (Pitch me, kPitch_unit unit) {
 		/*
 		 * Find the first and last voiced frame.
 		 */
-		long imin = thy nx + 1, imax = 0;
-		for (long i = 1; i <= my nx; i ++)
+		integer imin = thy nx + 1, imax = 0;
+		for (integer i = 1; i <= my nx; i ++)
 			if (Pitch_isVoiced_i (thee.get(), i)) { imin = i; break; }
-		for (long i = imin + 1; i <= my nx; i ++)
+		for (integer i = imin + 1; i <= my nx; i ++)
 			if (! Pitch_isVoiced_i (thee.get(), i)) { imax = i - 1; break; }
-		long n = imax - imin + 1;
+		integer n = imax - imin + 1;
 		if (n < 3) return thee;
 		/*
 		 * Compute average pitch and time.
 		 */
 		double sum = 0.0;
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			sum += Sampled_getValueAtSample (thee.get(), i, Pitch_LEVEL_FREQUENCY, (int) unit);
 		}
 		double fmean = sum / n;
@@ -737,7 +737,7 @@ autoPitch Pitch_subtractLinearFit (Pitch me, kPitch_unit unit) {
 		 * Compute slope.
 		 */
 		double numerator = 0.0, denominator = 0.0;
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double t = thy x1 + (i - 1) * thy dx - tmean;
 			double f = Sampled_getValueAtSample (thee.get(), i, Pitch_LEVEL_FREQUENCY, (int) unit) - fmean;
 			numerator += f * t;
@@ -747,7 +747,7 @@ autoPitch Pitch_subtractLinearFit (Pitch me, kPitch_unit unit) {
 		/*
 		 * Modify frequencies.
 		 */
-		for (long i = imin; i <= imax; i ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			Pitch_Frame myFrame = & my frame [i], thyFrame = & thy frame [i];
 			double t = thy x1 + (i - 1) * thy dx - tmean, myFreq = FREQUENCY (myFrame);
 			double f = Sampled_getValueAtSample (thee.get(), i, Pitch_LEVEL_FREQUENCY, (int) unit);
@@ -770,8 +770,8 @@ autoPitch Pitch_smooth (Pitch me, double bandWidth) {
 		autoSound sound1 = Sound_create (1, 2 * matrix1->xmin - matrix1->xmax, 2 * matrix1->xmax - matrix1->xmin,
 			3 * matrix1->nx, matrix1->dx, matrix1->x1 - 2 * matrix1->nx * matrix1->dx);
 
-		long firstVoiced = 0, lastVoiced = 0;
-		for (long i = 1; i <= matrix1 -> nx; i ++) {
+		integer firstVoiced = 0, lastVoiced = 0;
+		for (integer i = 1; i <= matrix1 -> nx; i ++) {
 			double f = matrix1 -> z [1] [i];
 			if (f != 0.0) {
 				if (! firstVoiced) firstVoiced = i;
@@ -783,16 +783,16 @@ autoPitch Pitch_smooth (Pitch me, double bandWidth) {
 		/* Extrapolate. */
 		double fextrap = matrix1 -> z [1] [firstVoiced];
 		firstVoiced += matrix1 -> nx;
-		for (long i = 1; i < firstVoiced; i ++)
+		for (integer i = 1; i < firstVoiced; i ++)
 			sound1 -> z [1] [i] = fextrap;
 		fextrap = matrix1 -> z [1] [lastVoiced];
 		lastVoiced += matrix1 -> nx;
-		for (long i = lastVoiced + 1; i <= sound1 -> nx; i ++)
+		for (integer i = lastVoiced + 1; i <= sound1 -> nx; i ++)
 			sound1 -> z [1] [i] = fextrap;
 
 		/* Smooth. */
 		autoSpectrum spectrum = Sound_to_Spectrum (sound1.get(), true);
-		for (long i = 1; i <= spectrum -> nx; i ++) {
+		for (integer i = 1; i <= spectrum -> nx; i ++) {
 			double f = (i - 1) * spectrum -> dx, fT = f / bandWidth, factor = exp (- fT * fT);
 			spectrum -> z [1] [i] *= factor;
 			spectrum -> z [2] [i] *= factor;
@@ -800,7 +800,7 @@ autoPitch Pitch_smooth (Pitch me, double bandWidth) {
 		autoSound sound2 = Spectrum_to_Sound (spectrum.get());
 
 		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 ++) {
+		for (integer 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 );
diff --git a/fon/Pitch.h b/fon/Pitch.h
index 06a8b04..6531ebf 100644
--- a/fon/Pitch.h
+++ b/fon/Pitch.h
@@ -25,7 +25,7 @@ Thing_declare (Interpreter);
 #include "Pitch_enums.h"
 #include "Pitch_def.h"
 
-autoPitch Pitch_create (double tmin, double tmax, long nt, double dt, double t1,
+autoPitch Pitch_create (double tmin, double tmax, integer nt, double dt, double t1,
 	double ceiling, int maxnCandidates);
 /*
 	Function:
@@ -62,7 +62,7 @@ void Pitch_Frame_init (Pitch_Frame me, int nCandidates);
 		my intensity == 0.0; // silent
 */
 
-bool Pitch_isVoiced_i (Pitch me, long index);
+bool Pitch_isVoiced_i (Pitch me, integer index);
 /*
 	Is the frame 'index' voiced?
 	A frame is considered voiced if the frequency of its first candidate
@@ -92,7 +92,7 @@ bool Pitch_isVoiced_t (Pitch me, double t);
 double Pitch_getValueAtTime (Pitch me, double time, kPitch_unit unit, bool interpolate);
 double Pitch_getStrengthAtTime (Pitch me, double time, kPitch_unit unit, bool interpolate);
 
-long Pitch_countVoicedFrames (Pitch me);
+integer Pitch_countVoicedFrames (Pitch me);
 
 double Pitch_getMean (Pitch me, double tmin, double tmax, kPitch_unit unit);
 double Pitch_getMeanStrength (Pitch me, double tmin, double tmax, int strengthUnit);
@@ -137,11 +137,11 @@ void Pitch_draw (Pitch me, Graphics g, double tmin, double tmax, double fmin, do
 void Pitch_difference (Pitch me, Pitch thee);
 /* give information about frames that are different in me and thee. */
 
-long Pitch_getMeanAbsSlope_hertz (Pitch me, double *slope);
-long Pitch_getMeanAbsSlope_mel (Pitch me, double *slope);
-long Pitch_getMeanAbsSlope_semitones (Pitch me, double *slope);
-long Pitch_getMeanAbsSlope_erb (Pitch me, double *slope);
-long Pitch_getMeanAbsSlope_noOctave (Pitch me, double *slope);
+integer Pitch_getMeanAbsSlope_hertz (Pitch me, double *slope);
+integer Pitch_getMeanAbsSlope_mel (Pitch me, double *slope);
+integer Pitch_getMeanAbsSlope_semitones (Pitch me, double *slope);
+integer Pitch_getMeanAbsSlope_erb (Pitch me, double *slope);
+integer Pitch_getMeanAbsSlope_noOctave (Pitch me, double *slope);
 /*
    The value returned is the number of voiced frames (nVoiced);
    this signals if the values are valid:
diff --git a/fon/PitchEditor.cpp b/fon/PitchEditor.cpp
index 50c0d0e..a559305 100644
--- a/fon/PitchEditor.cpp
+++ b/fon/PitchEditor.cpp
@@ -223,7 +223,7 @@ void structPitchEditor :: v_draw () {
 			Graphics_setColour (our graphics.get(), Graphics_BLACK);
 			Graphics_setTextAlignment (our graphics.get(), Graphics_CENTRE, Graphics_HALF);
 			for (int icand = 1; icand <= frame -> nCandidates; icand ++) {
-				int strength = (int) floor (10 * frame -> candidate [icand]. strength + 0.5);
+				int strength = Melder_iround_tieUp (10 * frame -> candidate [icand]. strength);
 				f = frame -> candidate [icand]. frequency;
 				if (strength > 9) strength = 9;
 				if (f > 0 && f <= pitch -> ceiling) Graphics_text (our graphics.get(), t, f, strength);
diff --git a/fon/PitchTier.cpp b/fon/PitchTier.cpp
index 4d2f3a2..64d874a 100644
--- a/fon/PitchTier.cpp
+++ b/fon/PitchTier.cpp
@@ -58,9 +58,9 @@ autoPitchTier PointProcess_upto_PitchTier (PointProcess me, double frequency) {
 
 void PitchTier_stylize (PitchTier me, double frequencyResolution, bool useSemitones) {
 	for (;;) {
-		long imin = 0;
+		integer imin = 0;
 		double dfmin = 1e308;
-		for (long i = 2; i <= my points.size - 1; i ++) {
+		for (integer i = 2; i <= my points.size - 1; i ++) {
 			RealPoint pm = my points.at [i];
 			RealPoint pl = my points.at [i - 1];
 			RealPoint pr = my points.at [i + 1];
@@ -82,8 +82,8 @@ void PitchTier_stylize (PitchTier me, double frequencyResolution, bool useSemito
 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, (long) my points.size);
-	for (long i = 1; i <= my points.size; i ++) {
+		fprintf (f, "\"ooTextFile\"\n\"PitchTier\"\n%.17g %.17g %ld\n", my xmin, my xmax, (long_not_integer) my points.size);
+	for (integer i = 1; i <= my points.size; i ++) {
 		RealPoint point = my points.at [i];
 		fprintf (f, "%.17g\t%.17g\n", point -> number, point -> value);
 	}
@@ -108,7 +108,7 @@ void PitchTier_writeToHeaderlessSpreadsheetFile (PitchTier me, MelderFile file)
 
 void PitchTier_shiftFrequencies (PitchTier me, double tmin, double tmax, double shift, kPitch_unit unit) {
 	try {
-		for (long i = 1; i <= my points.size; i ++) {
+		for (integer i = 1; i <= my points.size; i ++) {
 			RealPoint point = my points.at [i];
 			double frequency = point -> value;
 			if (point -> number < tmin || point -> number > tmax) continue;
@@ -142,7 +142,7 @@ void PitchTier_shiftFrequencies (PitchTier me, double tmin, double tmax, double
 
 void PitchTier_multiplyFrequencies (PitchTier me, double tmin, double tmax, double factor) {
 	Melder_assert (factor > 0.0);
-	for (long i = 1; i <= my points.size; i ++) {
+	for (integer i = 1; i <= my points.size; i ++) {
 		RealPoint point = my points.at [i];
 		if (point -> number < tmin || point -> number > tmax) continue;
 		point -> value *= factor;
diff --git a/fon/PitchTier_to_PointProcess.cpp b/fon/PitchTier_to_PointProcess.cpp
index 46745b6..1227d2e 100644
--- a/fon/PitchTier_to_PointProcess.cpp
+++ b/fon/PitchTier_to_PointProcess.cpp
@@ -23,9 +23,9 @@ autoPointProcess PitchTier_to_PointProcess (PitchTier me) {
 	try {
 		autoPointProcess thee = PointProcess_create (my xmin, my xmax, 1000);
 		double area = 0.5;   // imagine an event half a period before the beginning
-		long size = my points.size;
+		integer size = my points.size;
 		if (size == 0) return thee;
-		for (long interval = 0; interval <= size; interval ++) {
+		for (integer interval = 0; interval <= size; interval ++) {
 			double t1 = ( interval == 0 ? my xmin : my points.at [interval] -> number );
 			Melder_assert (isdefined (t1));
 			double t2 = ( interval == size ? my xmax : my points.at [interval + 1] -> number );
@@ -56,7 +56,7 @@ autoPointProcess PitchTier_Pitch_to_PointProcess (PitchTier me, Pitch vuv) {
 		/*
 		 * Copy only voiced parts to result.
 		 */
-		for (long i = 1; i <= fullPoint -> nt; i ++) {
+		for (integer i = 1; i <= fullPoint -> nt; i ++) {
 			double t = fullPoint -> t [i];
 			if (Pitch_isVoiced_t (vuv, t)) {
 				PointProcess_addPoint (thee.get(), t);
@@ -69,7 +69,7 @@ autoPointProcess PitchTier_Pitch_to_PointProcess (PitchTier me, Pitch vuv) {
 }
 
 static int PointProcess_isVoiced_t (PointProcess me, double t, double maxT) {
-	long imid = PointProcess_getNearestIndex (me, t);
+	integer imid = PointProcess_getNearestIndex (me, t);
 	if (imid == 0) return 0;
 	double tmid = my t [imid];
 	int leftVoiced = imid > 1 && tmid - my t [imid - 1] <= maxT;
@@ -87,7 +87,7 @@ autoPointProcess PitchTier_Point_to_PointProcess (PitchTier me, PointProcess vuv
 		/*
 		 * Copy only voiced parts to result.
 		 */
-		for (long i = 1; i <= fullPoint -> nt; i ++) {
+		for (integer i = 1; i <= fullPoint -> nt; i ++) {
 			double t = fullPoint -> t [i];
 			if (PointProcess_isVoiced_t (vuv, t, maxT)) {
 				PointProcess_addPoint (thee.get(), t);
@@ -102,7 +102,7 @@ autoPointProcess PitchTier_Point_to_PointProcess (PitchTier me, PointProcess vuv
 autoPitchTier PointProcess_to_PitchTier (PointProcess me, double maximumInterval) {
 	try {
 		autoPitchTier thee = PitchTier_create (my xmin, my xmax);
-		for (long i = 1; i < my nt; i ++) {
+		for (integer i = 1; i < my nt; i ++) {
 			double interval = my t [i + 1] - my t [i];
 			if (interval <= maximumInterval) {
 				RealTier_addPoint (thee.get(), my t [i] + 0.5 * interval, 1.0 / interval);
@@ -128,7 +128,7 @@ autoPitchTier PitchTier_PointProcess_to_PitchTier (PitchTier me, PointProcess pp
 	try {
 		if (my points.size == 0) Melder_throw (U"No pitch points.");
 		autoPitchTier thee = PitchTier_create (pp -> xmin, pp -> xmax);
-		for (long i = 1; i <= pp -> nt; i ++) {
+		for (integer i = 1; i <= pp -> nt; i ++) {
 			double time = pp -> t [i];
 			double value = RealTier_getValueAtTime (me, time);
 			RealTier_addPoint (thee.get(), time, value);
@@ -143,7 +143,7 @@ autoTableOfReal PitchTier_downto_TableOfReal (PitchTier me, int useSemitones) {
 	try {
 		autoTableOfReal thee = RealTier_downto_TableOfReal (me, U"Time", U"F0");
 		if (useSemitones)
-			for (long i = 1; i <= thy numberOfRows; i ++)
+			for (integer i = 1; i <= thy numberOfRows; i ++)
 				thy data [i] [2] = NUMhertzToSemitones (thy data [i] [2]);
 		return thee;
 	} catch (MelderError) {
diff --git a/fon/PitchTier_to_Sound.cpp b/fon/PitchTier_to_Sound.cpp
index e7f4d43..7768d30 100644
--- a/fon/PitchTier_to_Sound.cpp
+++ b/fon/PitchTier_to_Sound.cpp
@@ -1,6 +1,6 @@
 /* PitchTier_to_Sound.cpp
  *
- * Copyright (C) 1992-2011,2016 Paul Boersma
+ * Copyright (C) 1992-2011,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 @@
 #include "PointProcess_and_Sound.h"
 
 autoSound PitchTier_to_Sound_pulseTrain (PitchTier me, double samplingFrequency,
-	 double adaptFactor, double adaptTime, long interpolationDepth, bool hum)
+	 double adaptFactor, double adaptTime, integer interpolationDepth, bool hum)
 {
 	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 };
@@ -75,13 +75,13 @@ void PitchTier_hum (PitchTier me) {
 autoSound PitchTier_to_Sound_sine (PitchTier me, double tmin, double tmax, double samplingFrequency) {
 	try {
 		if (tmax <= tmin) tmin = my xmin, tmax = my xmax;
-		long numberOfSamples = 1 + (long) floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
+		integer numberOfSamples = 1 + Melder_iroundDown ((my xmax - my xmin) * samplingFrequency);   // >= 1
 		double samplingPeriod = 1.0 / samplingFrequency;
 		double tmid = (tmin + tmax) / 2.0;
 		double t1 = tmid - 0.5 * (numberOfSamples - 1) * samplingPeriod;
 		autoSound thee = Sound_create (1, tmin, tmax, numberOfSamples, samplingPeriod, t1);
 		double phase = 0.0;
-		for (long isamp = 2; isamp <= numberOfSamples; isamp ++) {
+		for (integer isamp = 2; isamp <= numberOfSamples; isamp ++) {
 			double tleft = t1 + (isamp - 1.5) * samplingPeriod;
 			double fleft = RealTier_getValueAtTime (me, tleft);
 			phase += fleft * thy dx;
diff --git a/fon/PitchTier_to_Sound.h b/fon/PitchTier_to_Sound.h
index 56e665f..789ad3c 100644
--- a/fon/PitchTier_to_Sound.h
+++ b/fon/PitchTier_to_Sound.h
@@ -1,6 +1,6 @@
 /* PitchTier_to_Sound.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,7 +20,7 @@
 #include "Sound.h"
 
 autoSound PitchTier_to_Sound_pulseTrain (PitchTier me, double samplingFrequency,
-	 double adaptFactor, double adaptTime, long interpolationDepth,
+	 double adaptFactor, double adaptTime, integer interpolationDepth,
 	 bool hum);
 autoSound PitchTier_to_Sound_phonation (PitchTier me, double samplingFrequency,
 	 double adaptFactor, double maximumPeriod,
diff --git a/fon/Pitch_AnyTier_to_PitchTier.cpp b/fon/Pitch_AnyTier_to_PitchTier.cpp
index 56ef3e6..903a324 100644
--- a/fon/Pitch_AnyTier_to_PitchTier.cpp
+++ b/fon/Pitch_AnyTier_to_PitchTier.cpp
@@ -33,7 +33,7 @@ autoPitchTier PitchTier_AnyTier_to_PitchTier (PitchTier pitch, AnyTier tier) {
 		/*
 		 * Copy pitch's frequencies at tier's points to the resulting PitchTier.
 		 */
-		for (long ipoint = 1; ipoint <= tier -> points.size; ipoint ++) {
+		for (integer ipoint = 1; ipoint <= tier -> points.size; ipoint ++) {
 			AnyPoint point = tier -> points.at [ipoint];
 			double time = point -> number;
 			double frequency = RealTier_getValueAtTime (pitch, time);
@@ -63,7 +63,7 @@ autoPitchTier Pitch_AnyTier_to_PitchTier (Pitch pitch, AnyTier tier, int checkMe
 		/*
 		 * Copy pitch's frequencies at tier's points to the resulting PitchTier.
 		 */
-		for (long ipoint = 1; ipoint <= tier -> points.size; ipoint ++) {
+		for (integer ipoint = 1; ipoint <= tier -> points.size; ipoint ++) {
 			AnyPoint point = tier -> points.at [ipoint];
 			double time = point -> number;
 			double frequency = Pitch_getValueAtTime (pitch, time, kPitch_unit::HERTZ, Pitch_LINEAR);
diff --git a/fon/Pitch_Intensity.cpp b/fon/Pitch_Intensity.cpp
index f10528e..81c08f0 100644
--- a/fon/Pitch_Intensity.cpp
+++ b/fon/Pitch_Intensity.cpp
@@ -20,7 +20,7 @@
 
 static void Pitch_getExtrema (Pitch me, double *minimum, double *maximum) {
 	*minimum = 1e308, *maximum = -1e308;
-	for (long i = 1; i <= my nx; i ++) {
+	for (integer i = 1; i <= my nx; i ++) {
 		double frequency = my frame [i]. candidate [1]. frequency;
 		if (frequency == 0.0) continue;   // voiceless
 		if (frequency < *minimum) *minimum = frequency;
@@ -42,8 +42,8 @@ void Pitch_Intensity_draw (Pitch pitch, Intensity intensity, Graphics g,
 	Graphics_setInner (g);
 	double previousX = undefined;
 	double previousY = undefined;
-	long previousI = 0;
-	for (long i = 1; i <= pitch -> nx; i ++) {
+	integer previousI = 0;
+	for (integer i = 1; i <= pitch -> nx; i ++) {
 		double t = Sampled_indexToX (pitch, i);
 		double x = pitch -> frame [i]. candidate [1]. frequency;
 		double y = Sampled_getValueAtX (intensity, t, Pitch_LEVEL_FREQUENCY, (int) kPitch_unit::HERTZ, true);
@@ -73,9 +73,9 @@ void Pitch_Intensity_draw (Pitch pitch, Intensity intensity, Graphics g,
 }
 
 double Pitch_Intensity_getMean (Pitch thee, Intensity me) {
-	long numberOfValidLocalMeasurements = 0;
+	integer numberOfValidLocalMeasurements = 0;
 	double sumOfLocalValues = 0.0;
-	for (long iframe = 1; iframe <= my nx; iframe ++) {
+	for (integer iframe = 1; iframe <= my nx; iframe ++) {
 		double t = Sampled_indexToX (me, iframe);
 		bool localMeasurentIsValid = Pitch_isVoiced_t (thee, t);
 		if (localMeasurentIsValid) {
@@ -88,9 +88,9 @@ double Pitch_Intensity_getMean (Pitch thee, Intensity me) {
 }
 
 double Pitch_Intensity_getMeanAbsoluteSlope (Pitch thee, Intensity me) {
-	long numberOfValidLocalMeasurements = 0;
+	integer numberOfValidLocalMeasurements = 0;
 	double sumOfLocalAbsoluteSlopes = 0.0;
-	for (long iframe = 1; iframe < my nx; iframe ++) {
+	for (integer iframe = 1; iframe < my nx; iframe ++) {
 		double t1 = Sampled_indexToX (me, iframe);
 		double t2 = t1 + my dx;
 		bool localMeasurentIsValid = ( Pitch_isVoiced_t (thee, t1) && Pitch_isVoiced_t (thee, t2) );
diff --git a/fon/Pitch_to_PitchTier.cpp b/fon/Pitch_to_PitchTier.cpp
index ebb9b0e..e7f9f47 100644
--- a/fon/Pitch_to_PitchTier.cpp
+++ b/fon/Pitch_to_PitchTier.cpp
@@ -1,6 +1,6 @@
 /* Pitch_to_PitchTier.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
@@ -21,7 +21,7 @@
 autoPitchTier Pitch_to_PitchTier (Pitch me) {
 	try {
 		autoPitchTier thee = PitchTier_create (my xmin, my xmax);
-		for (long i = 1; i <= my nx; i ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			double frequency = my frame [i]. candidate [1]. frequency;
 
 			/*
@@ -47,11 +47,11 @@ static void Pitch_line (Pitch me, Graphics g, double tmin, double fleft, double
 	int lineType = Graphics_inqLineType (g);
 	double lineWidth = Graphics_inqLineWidth (g);
 	double slope = (fright - fleft) / (tmax - tmin);
-	long imin = Sampled_xToNearestIndex (me, tmin);
+	integer imin = Sampled_xToNearestIndex (me, tmin);
 	if (imin < 1) imin = 1;
-	long imax = Sampled_xToNearestIndex (me, tmax);
+	integer imax = Sampled_xToNearestIndex (me, tmax);
 	if (imax > my nx) imax = my nx;
-	for (long i = imin; i <= imax; i ++) {
+	for (integer i = imin; i <= imax; i ++) {
 		double tleft, tright;
 		if (! Pitch_isVoiced_i (me, i)) {
 			if (nonPeriodicLineType == 2) continue;
@@ -73,7 +73,7 @@ static void Pitch_line (Pitch me, Graphics g, double tmin, double fleft, double
 void PitchTier_Pitch_draw (PitchTier me, Pitch uv, Graphics g,
 	double tmin, double tmax, double fmin, double fmax, int nonPeriodicLineType, int garnish, const char32 *method)
 {
-	long n = my points.size, imin, imax, i;
+	integer n = my points.size, imin, imax, i;
 	if (nonPeriodicLineType == 0) {
 		PitchTier_draw (me, g, tmin, tmax, fmin, fmax, garnish, method);
 		return;
@@ -119,7 +119,7 @@ autoPitch Pitch_PitchTier_to_Pitch (Pitch me, PitchTier tier) {
 	try {
 		if (tier -> points.size == 0) Melder_throw (U"No pitch points.");
 		autoPitch thee = Data_copy (me);
-		for (long iframe = 1; iframe <= my nx; iframe ++) {
+		for (integer iframe = 1; iframe <= my nx; iframe ++) {
 			Pitch_Frame frame = & thy frame [iframe];
 			Pitch_Candidate cand = & frame -> candidate [1];
 			if (cand -> frequency > 0.0 && cand -> frequency <= my ceiling)
diff --git a/fon/Pitch_to_PointProcess.cpp b/fon/Pitch_to_PointProcess.cpp
index 8b8345d..258b70e 100644
--- a/fon/Pitch_to_PointProcess.cpp
+++ b/fon/Pitch_to_PointProcess.cpp
@@ -48,7 +48,7 @@ autoPointProcess Pitch_to_PointProcess (Pitch pitch) {
 }
 
 static int Pitch_getVoicedIntervalAfter (Pitch me, double after, double *tleft, double *tright) {
-	long ileft = Sampled_xToHighIndex (me, after), iright;
+	integer ileft = Sampled_xToHighIndex (me, after), iright;
 	if (ileft > my nx) return 0;   // offright
 	if (ileft < 1) ileft = 1;   // offleft
 
@@ -71,10 +71,10 @@ static int Pitch_getVoicedIntervalAfter (Pitch me, double after, double *tleft,
 	return 1;
 }
 
-static double findExtremum_3 (double *channel1_base, double *channel2_base, long d, long n, int includeMaxima, int includeMinima) {
+static double findExtremum_3 (double *channel1_base, double *channel2_base, integer d, integer n, int includeMaxima, int includeMinima) {
 	double *channel1 = channel1_base + d, *channel2 = channel2_base ? channel2_base + d : nullptr;
 	int includeAll = includeMaxima == includeMinima;
-	long imin = 1, imax = 1, i, iextr;
+	integer imin = 1, imax = 1, i, iextr;
 	double minimum, maximum;
 	if (n < 3) {
 		if (n <= 0) return 0.0;   // outside
@@ -110,7 +110,7 @@ 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);
+	integer imin = Sampled_xToLowIndex (me, tmin), imax = Sampled_xToHighIndex (me, tmax);
 	Melder_assert (isdefined (tmin));
 	Melder_assert (isdefined (tmax));
 	if (imin < 1) imin = 1;
@@ -127,16 +127,16 @@ static double Sound_findMaximumCorrelation (Sound me, double t1, double windowLe
 	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);
-	long iright1 = Sampled_xToNearestIndex ((Sampled) me, t1 + halfWindowLength);
-	long ileft2min = Sampled_xToLowIndex ((Sampled) me, tmin2 - halfWindowLength);
-	long ileft2max = Sampled_xToHighIndex ((Sampled) me, tmax2 - halfWindowLength);
+	integer ileft1 = Sampled_xToNearestIndex ((Sampled) me, t1 - halfWindowLength);
+	integer iright1 = Sampled_xToNearestIndex ((Sampled) me, t1 + halfWindowLength);
+	integer ileft2min = Sampled_xToLowIndex ((Sampled) me, tmin2 - halfWindowLength);
+	integer ileft2max = Sampled_xToHighIndex ((Sampled) me, tmax2 - halfWindowLength);
 	*peak = 0.0;   // default
 	Melder_assert (ileft2max >= ileft2min);   // if the loop is never executed, the result will be garbage
-	for (long ileft2 = ileft2min; ileft2 <= ileft2max; ileft2 ++) {
+	for (integer ileft2 = ileft2min; ileft2 <= ileft2max; ileft2 ++) {
 		double norm1 = 0.0, norm2 = 0.0, product = 0.0, localPeak = 0.0;
-		for (long ichan = 1; ichan <= my ny; ichan ++) {
-			for (long i1 = ileft1, i2 = ileft2; i1 <= iright1; i1 ++, i2 ++) {
+		for (integer ichan = 1; ichan <= my ny; ichan ++) {
+			for (integer i1 = ileft1, i2 = ileft2; i1 <= iright1; i1 ++, i2 ++) {
 				if (i1 < 1 || i1 > my nx || i2 < 1 || i2 > my nx) continue;
 				double amp1 = my z [ichan] [i1], amp2 = my z [ichan] [i2];
 				norm1 += amp1 * amp1;
diff --git a/fon/Pitch_to_Sound.cpp b/fon/Pitch_to_Sound.cpp
index 98e4b5d..fddda7b 100644
--- a/fon/Pitch_to_Sound.cpp
+++ b/fon/Pitch_to_Sound.cpp
@@ -1,6 +1,6 @@
 /* Pitch_to_Sound.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
@@ -69,7 +69,7 @@ autoSound Pitch_to_Sound_sine (Pitch me, double tmin, double tmax, double sampli
 	try {
 		autoPitchTier tier = Pitch_to_PitchTier (me);
 		autoSound sound = PitchTier_to_Sound_sine (tier.get(), tmin, tmax, samplingFrequency);
-		long iframe = 1;
+		integer iframe = 1;
 		double unvoicedMin = my xmin;
 		double unvoicedMax = my x1 + (iframe - 1.5) * my dx;
 		for (;;) {
diff --git a/fon/PointProcess.cpp b/fon/PointProcess.cpp
index 7b0b707..a950109 100644
--- a/fon/PointProcess.cpp
+++ b/fon/PointProcess.cpp
@@ -343,7 +343,7 @@ 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
-		integer n = (integer) floor ((tmax - tmin) / period);
+		integer n = Melder_iroundDown ((tmax - tmin) / period);
 		double t = 0.5 * (tmin + tmax - n * period);
 		for (integer i = 1; i <= n; i ++, t += period) {
 			PointProcess_addPoint (me, t);
diff --git a/fon/PointProcess_and_Sound.cpp b/fon/PointProcess_and_Sound.cpp
index 61b0ae5..78b0496 100644
--- a/fon/PointProcess_and_Sound.cpp
+++ b/fon/PointProcess_and_Sound.cpp
@@ -20,29 +20,29 @@
 
 autoSound PointProcess_to_Sound_pulseTrain
 	(PointProcess me, double samplingFrequency,
-	 double adaptFactor, double adaptTime, long interpolationDepth)
+	 double adaptFactor, double adaptTime, integer interpolationDepth)
 {
 	try {
-		long sound_nt = 1 + (long) floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
+		integer sound_nt = 1 + Melder_iroundDown ((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;
 		autoSound thee = Sound_create (1, my xmin, my xmax, sound_nt, dt, t1);
 		double *sound = thy z [1];
-		for (long it = 1; it <= my nt; it ++) {
+		for (integer it = 1; it <= my nt; it ++) {
 			double t = my t [it], amplitude = 0.9, angle, halfampsinangle;
-			long mid = Sampled_xToNearestIndex (thee.get(), t);
+			integer mid = Sampled_xToNearestIndex (thee.get(), t);
 			if (it <= 2 || my t [it - 2] < my t [it] - adaptTime) {
 				amplitude *= adaptFactor;
 				if (it == 1 || my t [it - 1] < my t [it] - adaptTime)
 					amplitude *= adaptFactor;
 			}
-			long begin = mid - interpolationDepth, end = mid + interpolationDepth;
+			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;
 			halfampsinangle = 0.5 * amplitude * sin (angle);
-			for (long j = begin; j <= end; j ++) {
+			for (integer j = begin; j <= end; j ++) {
 				if (fabs (angle) < 1e-6)
 					sound [j] += amplitude;
 				else if (angle < 0.0)
@@ -66,7 +66,7 @@ autoSound PointProcess_to_Sound_phonation
 	 double openPhase, double collisionPhase, double power1, double power2)
 {
 	try {
-		long sound_nt = 1 + (long) floor ((my xmax - my xmin) * samplingFrequency);   // >= 1
+		integer sound_nt = 1 + Melder_iroundDown ((my xmax - my xmin) * samplingFrequency);   // >= 1
 		double dt = 1.0 / samplingFrequency;
 		double tmid = (my xmin + my xmax) / 2.0;
 		double t1 = tmid - 0.5 * (sound_nt - 1) * dt;
@@ -99,10 +99,10 @@ autoSound PointProcess_to_Sound_phonation
 		 * Cycle through the points. Each will become a period.
 		 */
 		double *sound = thy z [1];
-		for (long it = 1; it <= my nt; it ++) {
+		for (integer it = 1; it <= my nt; it ++) {
 			double t = my t [it], amplitude = a;
 			double period = undefined, te, phase, flow;
-			long midSample = Sampled_xToNearestIndex (thee.get(), t);
+			integer midSample = Sampled_xToNearestIndex (thee.get(), t);
 			/*
 			 * Determine the period: first look left (because that's where the open phase is),
 			 * then right.
@@ -138,11 +138,11 @@ autoSound PointProcess_to_Sound_phonation
 			 * Fill in the samples to the left of the current point.
 			 */
 			{// scope
-				long beginSample = midSample - (long) floor (te / thy dx);
+				integer beginSample = midSample - Melder_iroundDown (te / thy dx);
 				if (beginSample < 1) beginSample = 1;
-				long endSample = midSample;
+				integer endSample = midSample;
 				if (endSample > thy nx) endSample = thy nx;
-				for (long isamp = beginSample; isamp <= endSample; isamp ++) {
+				for (integer isamp = beginSample; isamp <= endSample; isamp ++) {
 					double tsamp = thy x1 + (isamp - 1) * thy dx;
 					phase = (tsamp - (t - te)) / (period * openPhase);
 					if (phase > 0.0)
@@ -162,11 +162,11 @@ autoSound PointProcess_to_Sound_phonation
 				double ta = - flow / flowDerivative;
 				double factorPerSample = exp (- thy dx / ta);
 				double value = flowDerivative * factorPerSample;
-				long beginSample = midSample + 1;
+				integer beginSample = midSample + 1;
 				if (beginSample < 1) beginSample = 1;
-				long endSample = midSample + (long) floor (20.0 * ta / thy dx);
+				integer endSample = midSample + Melder_iroundDown (20.0 * ta / thy dx);
 				if (endSample > thy nx) endSample = thy nx;
-				for (long isamp = beginSample; isamp <= endSample; isamp ++) {
+				for (integer isamp = beginSample; isamp <= endSample; isamp ++) {
 					sound [isamp] += value;
 					value *= factorPerSample;
 				}
diff --git a/fon/PointProcess_and_Sound.h b/fon/PointProcess_and_Sound.h
index 1b1e190..309c351 100644
--- a/fon/PointProcess_and_Sound.h
+++ b/fon/PointProcess_and_Sound.h
@@ -20,7 +20,7 @@
 #include "Sound.h"
 
 autoSound PointProcess_to_Sound_pulseTrain (PointProcess me, double samplingFrequency,
-	double adaptFactor, double adaptTime, long interpolationDepth);
+	double adaptFactor, double adaptTime, integer interpolationDepth);
 /*
 	Function:
 		create a time signal out of a point process.
diff --git a/fon/Polygon.cpp b/fon/Polygon.cpp
index 256bd5e..f33bbc3 100644
--- a/fon/Polygon.cpp
+++ b/fon/Polygon.cpp
@@ -43,7 +43,7 @@ void structPolygon :: v_info () {
   
 void structPolygon :: v_writeText (MelderFile file) {
 	texputi32 (file, our numberOfPoints, U"numberOfPoints", 0,0,0,0,0);
-	for (long i = 1; i <= our numberOfPoints; i ++) {
+	for (integer i = 1; i <= our numberOfPoints; i ++) {
 		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);
 	}
@@ -55,13 +55,13 @@ void structPolygon :: v_readText (MelderReadText text, int /*formatVersion*/) {
 		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 ++) {
+	for (integer i = 1; i <= our numberOfPoints; i ++) {
 		our x [i] = texgetr64 (text);
 		our y [i] = texgetr64 (text);
 	}
 }
 
-autoPolygon Polygon_create (long numberOfPoints) {
+autoPolygon Polygon_create (integer numberOfPoints) {
 	try {
 		autoPolygon me = Thing_new (Polygon);
 		my numberOfPoints = numberOfPoints;
@@ -74,8 +74,8 @@ autoPolygon Polygon_create (long numberOfPoints) {
 }
 
 void Polygon_randomize (Polygon me) {
-	for (long i = 1; i <= my numberOfPoints; i ++) {
-		long j = NUMrandomInteger (i, my numberOfPoints);
+	for (integer i = 1; i <= my numberOfPoints; i ++) {
+		integer j = NUMrandomInteger (i, my numberOfPoints);
 		double xdum = my x [i];
 		double ydum = my y [i];
 		my x [i] = my x [j];
@@ -89,7 +89,7 @@ double Polygon_perimeter (Polygon me) {
 	if (my numberOfPoints < 1) return 0.0;
 	double dx = my x [1] - my x [my numberOfPoints], dy = my y [1] - my y [my numberOfPoints];
 	double result = sqrt (dx * dx + dy * dy);
-	for (long i = 1; i <= my numberOfPoints - 1; i ++) {
+	for (integer i = 1; i <= my numberOfPoints - 1; i ++) {
 		dx = my x [i] - my x [i + 1];
 		dy = my y [i] - my y [i + 1];
 		result += sqrt (dx * dx + dy * dy);
@@ -98,24 +98,24 @@ double Polygon_perimeter (Polygon me) {
 }
 
 static void computeDistanceTable (Polygon me, int **table) {
-	for (long i = 1; i <= my numberOfPoints - 1; i ++)
-		for (long j = i + 1; j <= my numberOfPoints; j ++) {
+	for (integer i = 1; i <= my numberOfPoints - 1; i ++)
+		for (integer j = i + 1; j <= my numberOfPoints; j ++) {
 			double dx = my x [i] - my x [j], dy = my y [i] - my y [j];
 			table [i] [j] = table [j] [i] =
-				(int) floor (sqrt (dx * dx + dy * dy));   // round to zero
+				Melder_iroundDown (sqrt (dx * dx + dy * dy));   // round to zero
 		}
 }
 
-static long computeTotalDistance (int **distance, int path [], int numberOfCities) {
-	long result = 0;
-	for (long i = 1; i <= numberOfCities; i ++)
+static integer computeTotalDistance (int **distance, int path [], int numberOfCities) {
+	integer result = 0;
+	for (integer i = 1; i <= numberOfCities; i ++)
 		result += distance [path [i - 1]] [path [i]];
 	return result;
 }
 
 static void shuffle (int path [], int numberOfCities) {
-	for (long i = 1; i <= numberOfCities; i ++) {
-		int j = NUMrandomInteger (i, numberOfCities);
+	for (integer i = 1; i <= numberOfCities; i ++) {
+		integer j = NUMrandomInteger (i, numberOfCities);
 		int help = path [i];
 		path [i] = path [j];
 		path [j] = help;
@@ -123,7 +123,7 @@ static void shuffle (int path [], int numberOfCities) {
 	path [0] = path [numberOfCities];
 }
   
-static int tryExchange (int **distance, int *path, int numberOfCities, long *totalDistance) {
+static int tryExchange (int **distance, int *path, int numberOfCities, integer *totalDistance) {
 	int result = 0;
 	int b1 = path [0];
 	int b2nr = 1;
@@ -154,7 +154,7 @@ static int tryExchange (int **distance, int *path, int numberOfCities, long *tot
 	return result;
 }
 
-static int tryAdoption (int **distance, int *path, int numberOfCities, long *totalDistance)
+static int tryAdoption (int **distance, int *path, int numberOfCities, integer *totalDistance)
 {
 	int *help = NUMvector <int> (0, numberOfCities);
 	int i, maximumGainLeft, result = 0;
@@ -212,9 +212,9 @@ static int tryAdoption (int **distance, int *path, int numberOfCities, long *tot
 	return result;
 }
 
-void Polygon_salesperson (Polygon me, long numberOfIterations) {
+void Polygon_salesperson (Polygon me, integer numberOfIterations) {
 	try {
-		long numberOfShortest = 1, totalDistance, shortestDistance = 0;
+		integer numberOfShortest = 1, totalDistance, shortestDistance = 0;
 
 		int numberOfCities = my numberOfPoints;
 		if (numberOfCities < 1)
@@ -222,11 +222,11 @@ void Polygon_salesperson (Polygon me, long numberOfIterations) {
 		autoNUMmatrix <int> distance (1, numberOfCities, 1, numberOfCities);
 		computeDistanceTable (me, distance.peek());
 		autoNUMvector <int> path ((integer) 0, numberOfCities);
-		for (int i = 1; i <= numberOfCities; i ++)
+		for (integer i = 1; i <= numberOfCities; i ++)
 			path [i] = i;
 		path [0] = numberOfCities;   // close path
 		autoNUMvector <int> shortestPath (NUMvector_copy (path.peek(), 0, numberOfCities), 0);
-		for (long iteration = 1; iteration <= numberOfIterations; iteration ++) {
+		for (integer iteration = 1; iteration <= numberOfIterations; iteration ++) {
 			if (iteration > 1) shuffle (path.peek(), numberOfCities);
 			totalDistance = computeTotalDistance (distance.peek(), path.peek(), numberOfCities);
 			if (iteration == 1) shortestDistance = totalDistance;
@@ -250,7 +250,7 @@ void Polygon_salesperson (Polygon me, long numberOfIterations) {
 		/* Change me: I will follow the shortest path found. */
 
 		autoPolygon help = Data_copy (me);
-		for (long i = 1; i <= numberOfCities; i ++) {
+		for (integer i = 1; i <= numberOfCities; i ++) {
 			my x [i] = help -> x [shortestPath [i]];
 			my y [i] = help -> y [shortestPath [i]];
 		}
@@ -265,7 +265,7 @@ static void setWindow (Polygon me, Graphics graphics,
 	Melder_assert (me);
 	if (xmax == xmin) {   // autoscaling along x axis
 		xmax = xmin = my x [1];
-		for (long i = 2; i <= my numberOfPoints; i ++) {
+		for (integer i = 2; i <= my numberOfPoints; i ++) {
 			if (my x [i] < xmin)
 				xmin = my x [i];
 			if (my x [i] > xmax)
@@ -278,7 +278,7 @@ static void setWindow (Polygon me, Graphics graphics,
 	}
 	if (ymax == ymin) {   // autoscaling along y axis
 		ymax = ymin = my y [1];
-		for (long i = 2; i <= my numberOfPoints; i ++) {
+		for (integer i = 2; i <= my numberOfPoints; i ++) {
 			if (my y [i] < ymin)
 				ymin = my y [i];
 			if (my y [i] > ymax)
@@ -319,7 +319,7 @@ void Polygon_drawCircles (Polygon me, Graphics g,
 {
 	Graphics_setInner (g);
 	setWindow (me, g, xmin, xmax, ymin, ymax);
-	for (long i = 1; i <= my numberOfPoints; i ++)
+	for (integer i = 1; i <= my numberOfPoints; i ++)
 		Graphics_circle_mm (g, my x [i], my y [i], diameter_mm);
 	Graphics_unsetInner (g);
 }
@@ -329,7 +329,7 @@ void Polygon_paintCircles (Polygon me, Graphics g,
 {
 	Graphics_setInner (g);
 	setWindow (me, g, xmin, xmax, ymin, ymax);
-	for (long i = 1; i <= my numberOfPoints; i ++)
+	for (integer i = 1; i <= my numberOfPoints; i ++)
 		Graphics_fillCircle_mm (g, my x [i], my y [i], diameter);
 	Graphics_unsetInner (g);
 }
@@ -338,11 +338,11 @@ void Polygons_drawConnection (Polygon me, Polygon thee, Graphics g,
 	double xmin, double xmax, double ymin, double ymax, int hasArrow, double relativeLength)
 {
 	double w2 = 0.5 * (1 - relativeLength), w1 = 1 - w2;
-	long n = my numberOfPoints;
+	integer n = my numberOfPoints;
 	if (thy numberOfPoints < n) n = thy numberOfPoints;
 	Graphics_setInner (g);
 	setWindow (me, g, xmin, xmax, ymin, ymax);
-	for (long i = 1; i <= n; i ++) {
+	for (integer i = 1; i <= n; i ++) {
 		double x1 = my x [i], x2 = thy x [i], y1 = my y [i], y2 = thy y [i];
 		double dummy = w1 * x1 + w2 * x2;
 		x2 = w1 * x2 + w2 * x1;
diff --git a/fon/Polygon.h b/fon/Polygon.h
index 6faabbc..9332def 100644
--- a/fon/Polygon.h
+++ b/fon/Polygon.h
@@ -2,7 +2,7 @@
 #define _Polygon_h_
 /* Polygon.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
@@ -23,7 +23,7 @@
 
 #include "Polygon_def.h"
 
-autoPolygon Polygon_create (long numberOfPoints);
+autoPolygon Polygon_create (integer numberOfPoints);
 /*
 	Function:
 		create a new instance of Polygon.
@@ -43,7 +43,7 @@ void Polygon_randomize (Polygon me);   /* Randomize the order of the points. */
 
 double Polygon_perimeter (Polygon me);   /* Return the length of the closed path through all points. */
 
-void Polygon_salesperson (Polygon me, long numberOfIterations);
+void Polygon_salesperson (Polygon me, integer numberOfIterations);
 /*
 	Function:
 		change the order of the points in such a way that it defines the shortest closed path.
diff --git a/fon/Praat_tests.cpp b/fon/Praat_tests.cpp
index b73c5ec..97cc83a 100644
--- a/fon/Praat_tests.cpp
+++ b/fon/Praat_tests.cpp
@@ -296,7 +296,7 @@ int Praat_tests (kPraatTests itest, char32 *arg1, char32 *arg2, char32 *arg3, ch
 		} break;
 		case kPraatTests::TIME_INNER: {
 			int size = Melder_atoi (arg2);
-			autonumvec x { size, false }, y { size, false };
+			autonumvec x { size, kTensorInitializationType::RAW }, y { size, kTensorInitializationType::RAW };
 			for (int64 i = 1; i <= size; i ++) {
 				x [i] = NUMrandomGauss (0.0, 1.0);
 				y [i] = NUMrandomGauss (0.0, 1.0);
@@ -349,7 +349,7 @@ int Praat_tests (kPraatTests itest, char32 *arg1, char32 *arg2, char32 *arg3, ch
 		} break;
 		case kPraatTests::TIME_SUM: {
 			integer size = Melder_atoi (arg2);
-			autonumvec x { size, false };
+			autonumvec x { size, kTensorInitializationType::RAW };
 			for (integer i = 1; i <= size; i ++)
 				x [i] = NUMrandomGauss (0.0, 1.0);
 			double z = 0.0;
@@ -362,7 +362,7 @@ int Praat_tests (kPraatTests itest, char32 *arg1, char32 *arg2, char32 *arg3, ch
 		} break;
 		case kPraatTests::TIME_MEAN: {
 			integer size = Melder_atoi (arg2);
-			autonumvec x { size, false };
+			autonumvec x { size, kTensorInitializationType::RAW };
 			for (integer i = 1; i <= size; i ++)
 				x [i] = NUMrandomGauss (0.0, 1.0);
 			double z = 0.0;
@@ -375,7 +375,7 @@ int Praat_tests (kPraatTests itest, char32 *arg1, char32 *arg2, char32 *arg3, ch
 		} break;
 		case kPraatTests::TIME_STDEV: {
 			integer size = 10000;
-			autonumvec x { size, false };
+			autonumvec x { size, kTensorInitializationType::RAW };
 			for (integer i = 1; i <= size; i ++)
 				x [i] = NUMrandomGauss (0.0, 1.0);
 			double z = 0.0;
@@ -389,20 +389,20 @@ int Praat_tests (kPraatTests itest, char32 *arg1, char32 *arg2, char32 *arg3, ch
 		case kPraatTests::TIME_ALLOC: {
 			integer size = Melder_atoi (arg2);
 			for (int64 iteration = 1; iteration <= n; iteration ++) {
-				autonumvec result (size, false);
+				autonumvec result (size, kTensorInitializationType::RAW);
 			}
 			t = Melder_stopwatch () / size;
 		} break;
 		case kPraatTests::TIME_ALLOC0: {
 			integer size = Melder_atoi (arg2);
 			for (int64 iteration = 1; iteration <= n; iteration ++) {
-				autonumvec result (size, true);
+				autonumvec result (size, kTensorInitializationType::RAW);
 			}
 			t = Melder_stopwatch () / size;
 		} break;
 		case kPraatTests::TIME_ZERO: {
 			integer size = Melder_atoi (arg2);
-			autonumvec result { size, false };
+			autonumvec result { size, kTensorInitializationType::RAW };
 			double z = 0.0;
 			for (int64 iteration = 1; iteration <= n; iteration ++) {
 				for (long i = 1; i <= size; i ++) {
@@ -526,7 +526,7 @@ int Praat_tests (kPraatTests itest, char32 *arg1, char32 *arg2, char32 *arg3, ch
 				const autonumvec d { };
 				double *e;
 				const autonumvec f { e, 10 };
-				const autonumvec g { 100, true };
+				const autonumvec g { 100, kTensorInitializationType::ZERO };
 				//return f;   // call to deleted constructor
 				numvec h;
 				autonumvec j;
diff --git a/fon/RealTier.cpp b/fon/RealTier.cpp
index cd609f1..5f40946 100644
--- a/fon/RealTier.cpp
+++ b/fon/RealTier.cpp
@@ -104,20 +104,20 @@ void RealTier_addPoint (RealTier me, double t, double value) {
 	}
 }
 
-double RealTier_getValueAtIndex (RealTier me, long i) {
+double RealTier_getValueAtIndex (RealTier me, integer i) {
 	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;
+	integer n = my points.size;
 	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];
 	if (t >= pointLeft -> number) return pointLeft -> value;   // constant extrapolation
 	Melder_assert (n >= 2);
-	long ileft = AnyTier_timeToLowIndex (me->asAnyTier(), t), iright = ileft + 1;
+	integer ileft = AnyTier_timeToLowIndex (me->asAnyTier(), t), iright = ileft + 1;
 	Melder_assert (ileft >= 1 && iright <= n);
 	pointLeft = my points.at [ileft];
 	pointRight = my points.at [iright];
@@ -130,8 +130,8 @@ double RealTier_getValueAtTime (RealTier me, double t) {
 
 double RealTier_getMaximumValue (RealTier me) {
 	double result = undefined;
-	long n = my points.size;
-	for (long i = 1; i <= n; i ++) {
+	integer n = my points.size;
+	for (integer i = 1; i <= n; i ++) {
 		RealPoint point = my points.at [i];
 		if (isundef (result) || point -> value > result)
 			result = point -> value;
@@ -141,8 +141,8 @@ double RealTier_getMaximumValue (RealTier me) {
 
 double RealTier_getMinimumValue (RealTier me) {
 	double result = undefined;
-	long n = my points.size;
-	for (long i = 1; i <= n; i ++) {
+	integer n = my points.size;
+	for (integer i = 1; i <= n; i ++) {
 		RealPoint point = my points.at [i];
 		if (isundef (result) || point -> value < result)
 			result = point -> value;
@@ -151,7 +151,7 @@ double RealTier_getMinimumValue (RealTier me) {
 }
 
 double RealTier_getArea (RealTier me, double tmin, double tmax) {
-	long n = my points.size, imin, imax;
+	integer n = my points.size, imin, imax;
 	if (n == 0) return undefined;
 	if (n == 1) return (tmax - tmin) * my points.at [1] -> value;
 	imin = AnyTier_timeToLowIndex (me->asAnyTier(), tmin);
@@ -164,8 +164,8 @@ double RealTier_getArea (RealTier me, double tmin, double tmax) {
 	 * Sum the areas between the points.
 	 * This works even if imin is 0 (offleft) and/or imax is n + 1 (offright).
 	 */
-	double area = 0.0;
-	for (long i = imin; i < imax; i ++) {
+	real80 area = 0.0;
+	for (integer i = imin; i < imax; i ++) {
 		double tleft, fleft, tright, fright;
 		if (i == imin) {
 			tleft = tmin;
@@ -183,7 +183,7 @@ double RealTier_getArea (RealTier me, double tmin, double tmax) {
 		}
 		area += 0.5 * (fleft + fright) * (tright - tleft);
 	}
-	return area;
+	return (real) area;
 }
 
 double RealTier_getMean_curve (RealTier me, double tmin, double tmax) {
@@ -194,7 +194,7 @@ double RealTier_getMean_curve (RealTier me, double tmin, double tmax) {
 }
 
 double RealTier_getStandardDeviation_curve (RealTier me, double tmin, double tmax) {
-	long n = my points.size, imin, imax;
+	integer n = my points.size, imin, imax;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindow
 	if (n == 0) return undefined;
 	if (n == 1) return 0.0;
@@ -210,7 +210,7 @@ double RealTier_getStandardDeviation_curve (RealTier me, double tmin, double tma
 	 */
 	real mean = RealTier_getMean_curve (me, tmin, tmax);
 	real80 integral = 0.0;
-	for (long i = imin; i < imax; i ++) {
+	for (integer i = imin; i < imax; i ++) {
 		double tleft, fleft, tright, fright;
 		if (i == imin) {
 			tleft = tmin;
@@ -261,7 +261,7 @@ real RealTier_getStandardDeviation_points (RealTier me, real tmin, real tmax) {
 	if (n < 2) return undefined;
 	real mean = RealTier_getMean_points (me, tmin, tmax);
 	real80 sum = 0.0;
-	for (long i = imin; i <= imax; i ++) {
+	for (integer i = imin; i <= imax; i ++) {
 		real diff = my points.at [i] -> value - mean;
 		sum += diff * diff;
 	}
@@ -283,7 +283,7 @@ void RealTier_draw (RealTier me, Graphics g, double tmin, double tmax, double fm
 {
 	bool drawLines = str32str (method, U"lines") || str32str (method, U"Lines");
 	bool drawSpeckles = str32str (method, U"speckles") || str32str (method, U"Speckles");
-	long n = my points.size, imin, imax, i;
+	integer n = my points.size, imin, imax, i;
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
 	Graphics_setWindow (g, tmin, tmax, fmin, fmax);
 	Graphics_setInner (g);
@@ -328,7 +328,7 @@ autoTableOfReal RealTier_downto_TableOfReal (RealTier me, const char32 *timeLabe
 		autoTableOfReal thee = TableOfReal_create (my points.size, 2);
 		TableOfReal_setColumnLabel (thee.get(), 1, timeLabel);
 		TableOfReal_setColumnLabel (thee.get(), 2, valueLabel);
-		for (long i = 1; i <= my points.size; i ++) {
+		for (integer i = 1; i <= my points.size; i ++) {
 			RealPoint point = my points.at [i];
 			thy data [i] [1] = point -> number;
 			thy data [i] [2] = point -> value;
@@ -339,10 +339,10 @@ autoTableOfReal RealTier_downto_TableOfReal (RealTier me, const char32 *timeLabe
 	}
 }
 
-void RealTier_interpolateQuadratically (RealTier me, long numberOfPointsPerParabola, int logarithmically) {
+void RealTier_interpolateQuadratically (RealTier me, integer numberOfPointsPerParabola, int logarithmically) {
 	try {
 		autoRealTier thee = Data_copy (me);
-		for (long ipoint = 1; ipoint < my points.size; ipoint ++) {
+		for (integer ipoint = 1; ipoint < my points.size; ipoint ++) {
 			RealPoint point1 = my points.at [ipoint], point2 = my points.at [ipoint + 1];
 			double time1 = point1 -> number, time2 = point2 -> number, tmid = 0.5 * (time1 + time2);
 			double value1 = point1 -> value, value2 = point2 -> value, valuemid;
@@ -352,7 +352,7 @@ void RealTier_interpolateQuadratically (RealTier me, long numberOfPointsPerParab
 			/*
 			 * Left from the midpoint.
 			 */
-			for (long inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
+			for (integer inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
 				double newTime = time1 + inewpoint * timeStep;
 				double phase = (newTime - time1) / (tmid - time1);
 				double newValue = value1 + (valuemid - value1) * phase * phase;
@@ -366,7 +366,7 @@ void RealTier_interpolateQuadratically (RealTier me, long numberOfPointsPerParab
 			/*
 			 * Right from the midpoint.
 			 */
-			for (long inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
+			for (integer inewpoint = 1; inewpoint <= numberOfPointsPerParabola; inewpoint ++) {
 				double newTime = tmid + inewpoint * timeStep;
 				double phase = (time2 - newTime) / (time2 - tmid);
 				double newValue = value2 + (valuemid - value2) * phase * phase;
@@ -384,11 +384,11 @@ autoTable RealTier_downto_Table (RealTier me, const char32 *indexText, const cha
 	try {
 		autoTable thee = Table_createWithoutColumnNames (my points.size,
 			(!! indexText) + (!! timeText) + (!! valueText));
-		long icol = 0;
+		integer icol = 0;
 		if (indexText) Table_setColumnLabel (thee.get(), ++ icol, indexText);
 		if (timeText ) Table_setColumnLabel (thee.get(), ++ icol, timeText);
 		if (valueText) Table_setColumnLabel (thee.get(), ++ icol, valueText);
-		for (long ipoint = 1; ipoint <= my points.size; ipoint ++) {
+		for (integer ipoint = 1; ipoint <= my points.size; ipoint ++) {
 			RealPoint point = my points.at [ipoint];
 			icol = 0;
 			if (indexText) Table_setNumericValue (thee.get(), ipoint, ++ icol, ipoint);
@@ -401,10 +401,10 @@ autoTable RealTier_downto_Table (RealTier me, const char32 *indexText, const cha
 	}
 }
 
-autoRealTier Vector_to_RealTier (Vector me, long channel, ClassInfo klas) {
+autoRealTier Vector_to_RealTier (Vector me, integer channel, ClassInfo klas) {
 	try {
 		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
-		for (long i = 1; i <= my nx; i ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			RealTier_addPoint (thee.get(), Sampled_indexToX (me, i), my z [channel] [i]);
 		}
 		return thee;
@@ -413,10 +413,10 @@ autoRealTier Vector_to_RealTier (Vector me, long channel, ClassInfo klas) {
 	}
 }
 
-autoRealTier Vector_to_RealTier_peaks (Vector me, long channel, ClassInfo klas) {
+autoRealTier Vector_to_RealTier_peaks (Vector me, integer channel, ClassInfo klas) {
 	try {
 		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
-		for (long i = 2; i < my nx; i ++) {
+		for (integer i = 2; i < my nx; i ++) {
 			double left = my z [channel] [i - 1], centre = my z [channel] [i], right = my z [channel] [i + 1];
 			if (left <= centre && right < centre) {
 				double x, maximum;
@@ -431,10 +431,10 @@ autoRealTier Vector_to_RealTier_peaks (Vector me, long channel, ClassInfo klas)
 	}
 }
 
-autoRealTier Vector_to_RealTier_valleys (Vector me, long channel, ClassInfo klas) {
+autoRealTier Vector_to_RealTier_valleys (Vector me, integer channel, ClassInfo klas) {
 	try {
 		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
-		for (long i = 2; i < my nx; i ++) {
+		for (integer i = 2; i < my nx; i ++) {
 			double left = my z [channel] [i - 1], centre = my z [channel] [i], right = my z [channel] [i + 1];
 			if (left >= centre && right > centre) {
 				double x, minimum;
@@ -452,7 +452,7 @@ autoRealTier Vector_to_RealTier_valleys (Vector me, long channel, ClassInfo klas
 autoRealTier PointProcess_upto_RealTier (PointProcess me, double value, ClassInfo klas) {
 	try {
 		autoRealTier thee = RealTier_createWithClass (my xmin, my xmax, klas);
-		for (long i = 1; i <= my nt; i ++) {
+		for (integer i = 1; i <= my nt; i ++) {
 			RealTier_addPoint (thee.get(), my t [i], value);
 		}
 		return thee;
@@ -465,7 +465,7 @@ void RealTier_formula (RealTier me, const char32 *expression, Interpreter interp
 	try {
 		Formula_compile (interpreter, me, expression, kFormula_EXPRESSION_TYPE_NUMERIC, true);
 		if (! thee) thee = me;
-		for (long icol = 1; icol <= my points.size; icol ++) {
+		for (integer icol = 1; icol <= my points.size; icol ++) {
 			Formula_Result result;
 			Formula_run (0, icol, & result);
 			if (isundef (result. numericResult))
@@ -478,7 +478,7 @@ void RealTier_formula (RealTier me, const char32 *expression, Interpreter interp
 }
 
 void RealTier_removePointsBelow (RealTier me, double level) {
-	for (long ipoint = my points.size; ipoint > 0; ipoint --) {
+	for (integer ipoint = my points.size; ipoint > 0; ipoint --) {
 		RealPoint point = my points.at [ipoint];
 		if (point -> value < level) {
 			AnyTier_removePoint (me->asAnyTier(), ipoint);
diff --git a/fon/RealTier.h b/fon/RealTier.h
index d46e507..8e463e7 100644
--- a/fon/RealTier.h
+++ b/fon/RealTier.h
@@ -2,7 +2,7 @@
 #define _RealTier_h_
 /* RealTier.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
@@ -47,7 +47,7 @@ autoRealTier RealTier_createWithClass (double tmin, double tmax, ClassInfo klas)
 		result -> points.size == 0;
 */
 
-double RealTier_getValueAtIndex (RealTier me, long point);
+double RealTier_getValueAtIndex (RealTier me, integer point);
 /* No points or 'point' out of range: undefined. */
 
 double RealTier_getValueAtTime (RealTier me, double t);
@@ -68,12 +68,12 @@ void RealTier_draw (RealTier me, Graphics g, double tmin, double tmax,
 	double ymin, double ymax, int garnish, const char32 *method, const char32 *quantity);
 autoTableOfReal RealTier_downto_TableOfReal (RealTier me, const char32 *timeLabel, const char32 *valueLabel);
 
-void RealTier_interpolateQuadratically (RealTier me, long numberOfPointsPerParabola, int logarithmically);
+void RealTier_interpolateQuadratically (RealTier me, integer numberOfPointsPerParabola, int logarithmically);
 
 autoTable RealTier_downto_Table (RealTier me, const char32 *indexText, const char32 *timeText, const char32 *valueText);
-autoRealTier Vector_to_RealTier (Vector me, long channel, ClassInfo klas);
-autoRealTier Vector_to_RealTier_peaks (Vector me, long channel, ClassInfo klas);
-autoRealTier Vector_to_RealTier_valleys (Vector me, long channel, ClassInfo klas);
+autoRealTier Vector_to_RealTier (Vector me, integer channel, ClassInfo klas);
+autoRealTier Vector_to_RealTier_peaks (Vector me, integer channel, ClassInfo klas);
+autoRealTier Vector_to_RealTier_valleys (Vector me, integer channel, ClassInfo klas);
 autoRealTier PointProcess_upto_RealTier (PointProcess me, double value, ClassInfo klas);
 
 void RealTier_formula (RealTier me, const char32 *expression, Interpreter interpreter, RealTier thee);
diff --git a/fon/Sampled.cpp b/fon/Sampled.cpp
index f17c567..dde2e3f 100644
--- a/fon/Sampled.cpp
+++ b/fon/Sampled.cpp
@@ -53,9 +53,9 @@ void structSampled :: v_scaleX (double xminfrom, double xmaxfrom, double xminto,
 
 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;
-	*ixmax = rixmax > (double) my nx ? my nx : (long) rixmax;
+	double rixmax = 1.0 + Melder_roundDown ((xmax - my x1) / my dx);   // could be above 32-bit LONG_MAX
+	*ixmin = rixmin < 1.0 ? 1 : (integer) rixmin;
+	*ixmax = rixmax > (double) my nx ? my nx : (integer) rixmax;
 	if (*ixmin > *ixmax) return 0;
 	return *ixmax - *ixmin + 1;
 }
@@ -81,16 +81,16 @@ void Sampled_shortTermAnalysis (Sampled me, double windowDuration, double timeSt
 	*firstTime = ourMidTime - 0.5 * thyDuration + 0.5 * timeStep;
 }
 
-double Sampled_getValueAtSample (Sampled me, long isamp, long ilevel, int unit) {
+double Sampled_getValueAtSample (Sampled me, integer isamp, integer ilevel, int unit) {
 	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) {
+double Sampled_getValueAtX (Sampled me, double x, integer ilevel, int unit, bool interpolate) {
 	if (x < my xmin || x > my xmax) return undefined;
 	if (interpolate) {
 		double ireal = Sampled_xToIndex (me, x);
-		long ileft = (long) floor (ireal), inear, ifar;
+		integer ileft = Melder_iroundDown (ireal), inear, ifar;
 		double phase = ireal - ileft;
 		if (phase < 0.5) {
 			inear = ileft, ifar = ileft + 1;
@@ -109,9 +109,9 @@ double Sampled_getValueAtX (Sampled me, double x, long ilevel, int unit, bool in
 	return Sampled_getValueAtSample (me, Sampled_xToNearestIndex (me, x), ilevel, unit);
 }
 
-long Sampled_countDefinedSamples (Sampled me, long ilevel, int unit) {
-	long numberOfDefinedSamples = 0;
-	for (long isamp = 1; isamp <= my nx; isamp ++) {
+integer Sampled_countDefinedSamples (Sampled me, integer ilevel, int unit) {
+	integer numberOfDefinedSamples = 0;
+	for (integer isamp = 1; isamp <= my nx; isamp ++) {
 		double value = my v_getValueAtSample (isamp, ilevel, unit);
 		if (isundef (value)) continue;
 		numberOfDefinedSamples += 1;
@@ -119,8 +119,8 @@ long Sampled_countDefinedSamples (Sampled me, long ilevel, int unit) {
 	return numberOfDefinedSamples;
 }
 
-double * Sampled_getSortedValues (Sampled me, long ilevel, int unit, long *return_numberOfValues) {
-	long isamp, numberOfDefinedSamples = 0;
+double * Sampled_getSortedValues (Sampled me, integer ilevel, int unit, integer *return_numberOfValues) {
+	integer isamp, numberOfDefinedSamples = 0;
 	autoNUMvector <double> values (1, my nx);
 	for (isamp = 1; isamp <= my nx; isamp ++) {
 		double value = my v_getValueAtSample (isamp, ilevel, unit);
@@ -132,7 +132,7 @@ double * Sampled_getSortedValues (Sampled me, long ilevel, int unit, long *retur
 	return values.transfer();
 }
 
-double Sampled_getQuantile (Sampled me, double xmin, double xmax, double quantile, long ilevel, int unit) {
+double Sampled_getQuantile (Sampled me, double xmin, double xmax, double quantile, integer ilevel, int unit) {
 	try {
 		autoNUMvector <double> values (1, my nx);
 		Function_unidirectionalAutowindow (me, & xmin, & xmax);
@@ -157,7 +157,7 @@ double Sampled_getQuantile (Sampled me, double xmin, double xmax, double quantil
 }
 
 static void Sampled_getSumAndDefinitionRange
-	(Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate, double *return_sum, double *return_definitionRange)
+	(Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate, double *return_sum, double *return_definitionRange)
 {
 	/*
 		This function computes the area under the linearly interpolated curve between xmin and xmax.
@@ -250,8 +250,8 @@ 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) {
-				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);
+				integer imin = rimin < 0.5 ? 0 : Melder_iround_tieUp (rimin);
+				integer imax = rimax >= my nx + 0.5 ? my nx + 1 : Melder_iround_tieUp (rimax);
 				for (integer isamp = imin + 1; isamp < imax; isamp ++) {
 					double value = my v_getValueAtSample (isamp, ilevel, unit);
 					if (isdefined (value)) {
@@ -291,28 +291,28 @@ static void Sampled_getSumAndDefinitionRange
 	if (return_definitionRange) *return_definitionRange = (real) definitionRange;
 }
 
-double Sampled_getMean (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getMean (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double sum, definitionRange;
 	Sampled_getSumAndDefinitionRange (me, xmin, xmax, ilevel, unit, interpolate, & 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) {
+double Sampled_getMean_standardUnit (Sampled me, double xmin, double xmax, integer ilevel, int averagingUnit, bool interpolate) {
 	return Function_convertSpecialToStandardUnit (me, Sampled_getMean (me, xmin, xmax, ilevel, averagingUnit, interpolate), ilevel, averagingUnit);
 }
 
-double Sampled_getIntegral (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getIntegral (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double sum, definitionRange;
 	Sampled_getSumAndDefinitionRange (me, xmin, xmax, ilevel, unit, interpolate, & sum, & definitionRange);
 	return sum * my dx;
 }
 
-double Sampled_getIntegral_standardUnit (Sampled me, double xmin, double xmax, long ilevel, int averagingUnit, bool interpolate) {
+double Sampled_getIntegral_standardUnit (Sampled me, double xmin, double xmax, integer ilevel, int averagingUnit, bool interpolate) {
 	return Function_convertSpecialToStandardUnit (me, Sampled_getIntegral (me, xmin, xmax, ilevel, averagingUnit, interpolate), ilevel, averagingUnit);
 }
 
 static void Sampled_getSum2AndDefinitionRange
-	(Sampled me, double xmin, double xmax, long ilevel, int unit, double mean, bool interpolate, double *return_sum2, double *return_definitionRange)
+	(Sampled me, double xmin, double xmax, integer ilevel, int unit, double mean, bool interpolate, double *return_sum2, double *return_definitionRange)
 {
 	/*
 		This function computes the area under the linearly interpolated squared difference curve between xmin and xmax.
@@ -326,7 +326,7 @@ static void Sampled_getSum2AndDefinitionRange
 			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 ++) {
+				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 (isdefined (value)) {
 						value -= mean;
@@ -474,7 +474,7 @@ static void Sampled_getSum2AndDefinitionRange
 	if (return_definitionRange) *return_definitionRange = (real) definitionRange;
 }
 
-double Sampled_getStandardDeviation (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getStandardDeviation (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double sum, sum2, definitionRange;
 	Sampled_getSumAndDefinitionRange (me, xmin, xmax, ilevel, unit, interpolate, & sum, & definitionRange);
 	if (definitionRange < 2.0) return undefined;
@@ -482,11 +482,11 @@ double Sampled_getStandardDeviation (Sampled me, double xmin, double xmax, long
 	return sqrt (sum2 / (definitionRange - 1.0));
 }
 
-double Sampled_getStandardDeviation_standardUnit (Sampled me, double xmin, double xmax, long ilevel, int averagingUnit, bool interpolate) {
+double Sampled_getStandardDeviation_standardUnit (Sampled me, double xmin, double xmax, integer ilevel, int averagingUnit, bool interpolate) {
 	return Function_convertSpecialToStandardUnit (me, Sampled_getStandardDeviation (me, xmin, xmax, ilevel, averagingUnit, interpolate), ilevel, averagingUnit);
 }
 
-void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate,
+void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate,
 	double *return_minimum, double *return_xOfMinimum)
 {
 	double minimum = 1e301, xOfMinimum = 0.0;
@@ -510,7 +510,7 @@ void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, long ilevel,
 		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 ++) {
+		for (integer i = imin; i <= imax; i ++) {
 			double fmid = my v_getValueAtSample (i, ilevel, unit);
 			if (isundef (fmid)) continue;
 			if (! interpolate) {
@@ -549,19 +549,19 @@ end:
 	if (return_xOfMinimum) *return_xOfMinimum = xOfMinimum;
 }
 
-double Sampled_getMinimum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getMinimum (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double minimum;
 	Sampled_getMinimumAndX (me, xmin, xmax, ilevel, unit, interpolate, & minimum, nullptr);
 	return minimum;
 }
 
-double Sampled_getXOfMinimum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getXOfMinimum (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double time;
 	Sampled_getMinimumAndX (me, xmin, xmax, ilevel, unit, interpolate, nullptr, & time);
 	return time;
 }
 
-void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate,
+void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate,
 	double *return_maximum, double *return_xOfMaximum)
 {
 	double maximum = -1e301, xOfMaximum = 0.0;
@@ -626,20 +626,20 @@ end:
 	if (return_xOfMaximum) *return_xOfMaximum = xOfMaximum;
 }
 
-double Sampled_getMaximum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getMaximum (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double maximum;
 	Sampled_getMaximumAndX (me, xmin, xmax, ilevel, unit, interpolate, & maximum, nullptr);
 	return maximum;
 }
 
-double Sampled_getXOfMaximum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate) {
+double Sampled_getXOfMaximum (Sampled me, double xmin, double xmax, integer ilevel, int unit, bool interpolate) {
 	double time;
 	Sampled_getMaximumAndX (me, xmin, xmax, ilevel, unit, interpolate, nullptr, & time);
 	return time;
 }
 
 static void Sampled_speckleInside (Sampled me, Graphics g, double xmin, double xmax, double ymin, double ymax,
-	long ilevel, int unit)
+	integer ilevel, int unit)
 {
 	Function_unidirectionalAutowindow (me, & xmin, & xmax);
 	integer ixmin, ixmax;
@@ -662,7 +662,7 @@ static void Sampled_speckleInside (Sampled me, Graphics g, double xmin, double x
 }
 
 void Sampled_drawInside (Sampled me, Graphics g, double xmin, double xmax, double ymin, double ymax,
-	bool speckle, long ilevel, int unit)
+	bool speckle, integer ilevel, int unit)
 {
 	try {
 		if (speckle) {
diff --git a/fon/Sampled.h b/fon/Sampled.h
index 01fd38b..bb0c554 100644
--- a/fon/Sampled.h
+++ b/fon/Sampled.h
@@ -31,12 +31,12 @@
 
 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_xToLowIndex     (Sampled me, double x) { return Melder_iroundDown ((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); }
 
 static inline autonumvec Sampled_getX_numvec (Sampled me) {
-	autonumvec result (my nx, false);
+	autonumvec result (my nx, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= my nx; i ++)
 		result [i] = my x1 + (i - 1) * my dx;
 	return result;
@@ -78,37 +78,37 @@ void Sampled_shortTermAnalysis (Sampled me, double windowDuration, double timeSt
 			result -> x1 == firstTime;
 */
 
-double Sampled_getValueAtSample (Sampled me, long isamp, long ilevel, int unit);
-double Sampled_getValueAtX (Sampled me, double x, long ilevel, int unit, bool interpolate);
-long Sampled_countDefinedSamples (Sampled me, long ilevel, int unit);
-double * Sampled_getSortedValues (Sampled me, long ilevel, int unit, long *numberOfValues);
+double Sampled_getValueAtSample (Sampled me, integer sampleNumber, integer level, int unit);
+double Sampled_getValueAtX (Sampled me, double x, integer level, int unit, bool interpolate);
+integer Sampled_countDefinedSamples (Sampled me, integer level, int unit);
+double * Sampled_getSortedValues (Sampled me, integer level, int unit, integer *numberOfValues);
 
 double Sampled_getQuantile
-	(Sampled me, double xmin, double xmax, double quantile, long ilevel, int unit);
+	(Sampled me, double xmin, double xmax, double quantile, integer level, int unit);
 double Sampled_getMean
-	(Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
+	(Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
 double Sampled_getMean_standardUnit
-	(Sampled me, double xmin, double xmax, long ilevel, int averagingUnit, bool interpolate);
+	(Sampled me, double xmin, double xmax, integer level, int averagingUnit, bool interpolate);
 double Sampled_getIntegral
-	(Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
+	(Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
 double Sampled_getIntegral_standardUnit
-	(Sampled me, double xmin, double xmax, long ilevel, int averagingUnit, bool interpolate);
+	(Sampled me, double xmin, double xmax, integer level, int averagingUnit, bool interpolate);
 double Sampled_getStandardDeviation
-	(Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
+	(Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
 double Sampled_getStandardDeviation_standardUnit
-	(Sampled me, double xmin, double xmax, long ilevel, int averagingUnit, bool interpolate);
+	(Sampled me, double xmin, double xmax, integer level, int averagingUnit, bool interpolate);
 
-void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate,
+void Sampled_getMinimumAndX (Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate,
 	double *return_minimum, double *return_xOfMinimum);
-double Sampled_getMinimum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
-double Sampled_getXOfMinimum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
-void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate,
+double Sampled_getMinimum (Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
+double Sampled_getXOfMinimum (Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
+void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate,
 	double *return_maximum, double *return_xOfMaximum);
-double Sampled_getMaximum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
-double Sampled_getXOfMaximum (Sampled me, double xmin, double xmax, long ilevel, int unit, bool interpolate);
+double Sampled_getMaximum (Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
+double Sampled_getXOfMaximum (Sampled me, double xmin, double xmax, integer level, int unit, bool interpolate);
 
 void Sampled_drawInside
-	(Sampled me, Graphics g, double xmin, double xmax, double ymin, double ymax, bool speckle, long ilevel, int unit);
+	(Sampled me, Graphics g, double xmin, double xmax, double ymin, double ymax, bool speckle, integer level, int unit);
 
 /* End of file Sampled.h */
 #endif
diff --git a/fon/SampledXY.cpp b/fon/SampledXY.cpp
index ae59c5c..0076c8b 100644
--- a/fon/SampledXY.cpp
+++ b/fon/SampledXY.cpp
@@ -67,7 +67,7 @@ void SampledXY_init (SampledXY me,
 
 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
+	double riymax = 1.0 + Melder_roundDown ((toY - my y1) / my dy);   // could be above 32-bit LONG_MAX
 	*iymin = riymin < 1.0 ? 1 : (integer) riymin;
 	*iymax = riymax > (double) my ny ? my ny : (integer) riymax;
 	if (*iymin > *iymax) return 0;
diff --git a/fon/SampledXY.h b/fon/SampledXY.h
index cc604ff..870ce24 100644
--- a/fon/SampledXY.h
+++ b/fon/SampledXY.h
@@ -27,7 +27,7 @@ void SampledXY_init (SampledXY me, double xmin, double xmax, integer nx, double
 
 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 integer SampledXY_yToLowIndex     (SampledXY me, double y) { return (integer) floor ((y - my y1) / my dy + 1.0); }
+static inline integer SampledXY_yToLowIndex     (SampledXY me, double y) { return Melder_iroundDown ((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); }
 
diff --git a/fon/Sound.cpp b/fon/Sound.cpp
index b246b40..efc142c 100644
--- a/fon/Sound.cpp
+++ b/fon/Sound.cpp
@@ -25,6 +25,7 @@
 #include "Sound.h"
 #include "Sound_extensions.h"
 #include "NUM2.h"
+#include "tensor.h"
 
 #include "enums_getText.h"
 #include "Sound_enums.h"
@@ -50,10 +51,10 @@ void structSound :: v_info () {
 	MelderInfo_writeLine (U"   Sampling frequency: ", Melder_single (1.0 / dx), U" Hz");
 	MelderInfo_writeLine (U"   First sample centred at: ", x1, U" seconds");
 	{// scope
-		double sum = 0.0, sumOfSquares = 0.0;
-		for (long channel = 1; channel <= ny; channel ++) {
+		real80 sum = 0.0, sumOfSquares = 0.0;
+		for (integer channel = 1; channel <= ny; channel ++) {
 			double *amplitude = z [channel];
-			for (long i = 1; i <= nx; i ++) {
+			for (integer i = 1; i <= nx; i ++) {
 				double value = amplitude [i];
 				sum += value;
 				sumOfSquares += value * value;
@@ -64,10 +65,10 @@ void structSound :: v_info () {
 		MelderInfo_writeLine (U"Amplitude:");
 		MelderInfo_writeLine (U"   Minimum: ", Melder_single (minimum), U" Pascal");
 		MelderInfo_writeLine (U"   Maximum: ", Melder_single (maximum), U" Pascal");
-		double mean = sum / (nx * ny);
+		double mean = (real) sum / (nx * ny);
 		MelderInfo_writeLine (U"   Mean: ", Melder_single (mean), U" Pascal");
-		MelderInfo_writeLine (U"   Root-mean-square: ", Melder_single (sqrt (sumOfSquares / (nx * ny))), U" Pascal");
-		double penergy = sumOfSquares * dx / ny;   /* Pa2 s = kg2 m-2 s-3 */
+		MelderInfo_writeLine (U"   Root-mean-square: ", Melder_single (sqrt ((real) sumOfSquares / (nx * ny))), U" Pascal");
+		double penergy = (real) sumOfSquares * dx / ny;   /* Pa2 s = kg2 m-2 s-3 */
 		MelderInfo_write (U"Total energy: ", Melder_single (penergy), U" Pascal\u00B2 sec");
 		double energy = penergy / rho_c;   /* kg s-2 = Joule m-2 */
 		MelderInfo_writeLine (U" (energy in air: ", Melder_single (energy), U" Joule/m\u00B2)");
@@ -80,19 +81,8 @@ void structSound :: v_info () {
 		}
 	}
 	if (nx > 1) {
-		for (long channel = 1; channel <= ny; channel ++) {
-			double *amplitude = z [channel];
-			double sum = 0.0;
-			for (long i = 1; i <= nx; i ++) {
-				double value = amplitude [i];
-				sum += value;
-			}
-			double mean = sum / nx, stdev = 0.0;
-			for (long i = 1; i <= nx; i ++) {
-				double value = amplitude [i] - mean;
-				stdev += value * value;
-			}
-			stdev = sqrt (stdev / (nx - 1));
+		for (integer channel = 1; channel <= ny; channel ++) {
+			double stdev = stdev_scalar ({ z [channel], our nx });
 			MelderInfo_writeLine (U"Standard deviation in channel ", channel, U": ", Melder_single (stdev), U" Pascal");
 		}
 	}
@@ -117,12 +107,12 @@ double structSound :: v_getMatrix (integer irow, integer icol) {
 }
 
 double structSound :: v_getFunction2 (double x, double y) {
-	long channel = (long) floor (y);
+	integer channel = Melder_iroundDown (y);
 	if (channel < 0 || channel > ny || y != (double) channel) return 0.0;
 	return v_getFunction1 (channel, x);
 }
 
-autoSound Sound_create (long numberOfChannels, double xmin, double xmax, long nx, double dx, double x1) {
+autoSound Sound_create (integer numberOfChannels, double xmin, double xmax, integer nx, double dx, double x1) {
 	try {
 		autoSound me = Thing_new (Sound);
 		Matrix_init (me.get(), xmin, xmax, nx, dx, x1, 1, numberOfChannels, numberOfChannels, 1, 1);
@@ -132,13 +122,13 @@ autoSound Sound_create (long numberOfChannels, double xmin, double xmax, long nx
 	}
 }
 
-autoSound Sound_createSimple (long numberOfChannels, double duration, double samplingFrequency) {
+autoSound Sound_createSimple (integer numberOfChannels, double duration, double samplingFrequency) {
 	Melder_assert (duration >= 0.0);
 	Melder_assert (samplingFrequency > 0.0);
 	double numberOfSamples_f = round (duration * samplingFrequency);
 	if (numberOfSamples_f > (double) INT32_MAX)
 		Melder_throw (U"Cannot create sounds with more than ", Melder_bigInteger (INT32_MAX), U" samples, because they cannot be saved to disk.");
-	return Sound_create (numberOfChannels, 0.0, duration, (long) (int32_t) numberOfSamples_f,
+	return Sound_create (numberOfChannels, 0.0, duration, (integer) (int32_t) numberOfSamples_f,
 		1.0 / samplingFrequency, 0.5 / samplingFrequency);
 }
 
@@ -147,13 +137,13 @@ autoSound Sound_convertToMono (Sound me) {
 	try {
 		autoSound thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1);
 		if (my ny == 2) {   // Optimization.
-			for (long i = 1; i <= my nx; i ++) {
+			for (integer i = 1; i <= my nx; i ++) {
 				thy z [1] [i] = 0.5 * (my z [1] [i] + my z [2] [i]);
 			}
 		} else {
-			for (long i = 1; i <= my nx; i ++) {
+			for (integer i = 1; i <= my nx; i ++) {
 				double sum = my z [1] [i] + my z [2] [i] + my z [3] [i];
-				for (long channel = 4; channel <= my ny; channel ++) {
+				for (integer channel = 4; channel <= my ny; channel ++) {
 					sum += my z [channel] [i];
 				}
 				thy z [1] [i] = sum / my ny;
@@ -173,7 +163,7 @@ autoSound Sound_convertToStereo (Sound me) {
 		}
 		Melder_assert (my ny == 1);
 		autoSound thee = Sound_create (2, my xmin, my xmax, my nx, my dx, my x1);
-		for (long i = 1; i <= my nx; i ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			thy z [1] [i] = thy z [2] [i] = my z [1] [i];
 		}
 		return thee;
@@ -184,9 +174,9 @@ autoSound Sound_convertToStereo (Sound me) {
 
 autoSound Sounds_combineToStereo (OrderedOf<structSound>* me) {
 	try {
-		long totalNumberOfChannels = 0;
+		integer totalNumberOfChannels = 0;
 		double sharedSamplingPeriod = 0.0;
-		for (long isound = 1; isound <= my size; isound ++) {
+		for (integer isound = 1; isound <= my size; isound ++) {
 			Sound sound = my at [isound];
 			totalNumberOfChannels += sound -> ny;
 			if (sharedSamplingPeriod == 0.0) {
@@ -199,32 +189,32 @@ autoSound Sounds_combineToStereo (OrderedOf<structSound>* me) {
 		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 ++) {
+		for (integer isound = 2; isound <= my size; isound ++) {
 			Sound sound = my at [isound];
 			if (sound -> xmin < sharedMinimumTime) sharedMinimumTime = sound -> xmin;
 			if (sound -> xmax > sharedMaximumTime) sharedMaximumTime = sound -> xmax;
 		}
 		autoNUMvector <double> numberOfInitialZeroes (1, my size);
-		long sharedNumberOfSamples = 0;
+		integer sharedNumberOfSamples = 0;
 		double sumOfFirstTimes = 0.0;
-		for (long isound = 1; isound <= my size; isound ++) {
+		for (integer isound = 1; isound <= my size; isound ++) {
 			Sound sound = my at [isound];
-			numberOfInitialZeroes [isound] = floor ((sound -> xmin - sharedMinimumTime) / sharedSamplingPeriod);
+			numberOfInitialZeroes [isound] = Melder_roundDown ((sound -> xmin - sharedMinimumTime) / sharedSamplingPeriod);
 			double newFirstTime = sound -> x1 - sound -> dx * numberOfInitialZeroes [isound];
 			sumOfFirstTimes += newFirstTime;
-			long newNumberOfSamplesThroughLastNonzero = sound -> nx + (long) floor (numberOfInitialZeroes [isound]);
+			integer newNumberOfSamplesThroughLastNonzero = sound -> nx + Melder_iroundDown (numberOfInitialZeroes [isound]);
 			if (newNumberOfSamplesThroughLastNonzero > sharedNumberOfSamples) sharedNumberOfSamples = newNumberOfSamplesThroughLastNonzero;
 		}
 		double sharedTimeOfFirstSample = sumOfFirstTimes / my size;   // this is an approximation
 		autoSound thee = Sound_create (totalNumberOfChannels, sharedMinimumTime, sharedMaximumTime,
 			sharedNumberOfSamples, sharedSamplingPeriod, sharedTimeOfFirstSample);
-		long channelNumber = 0;
-		for (long isound = 1; isound <= my size; isound ++) {
+		integer channelNumber = 0;
+		for (integer isound = 1; isound <= my size; isound ++) {
 			Sound sound = my at [isound];
-			long offset = (long) floor (numberOfInitialZeroes [isound]);
-			for (long ichan = 1; ichan <= sound -> ny; ichan ++) {
+			integer offset = Melder_iroundDown (numberOfInitialZeroes [isound]);
+			for (integer ichan = 1; ichan <= sound -> ny; ichan ++) {
 				channelNumber ++;
-				for (long isamp = 1; isamp <= sound -> nx; isamp ++) {
+				for (integer isamp = 1; isamp <= sound -> nx; isamp ++) {
 					thy z [channelNumber] [isamp + offset] = sound -> z [ichan] [isamp];
 				}
 			}
@@ -235,12 +225,12 @@ autoSound Sounds_combineToStereo (OrderedOf<structSound>* me) {
 	}
 }
 
-autoSound Sound_extractChannel (Sound me, long ichan) {
+autoSound Sound_extractChannel (Sound me, integer ichan) {
 	try {
 		if (ichan <= 0 || ichan > my ny)
 			Melder_throw (U"There is no channel ", ichan, U".");
 		autoSound thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1);
-		for (long isamp = 1; isamp <= my nx; isamp ++) {
+		for (integer isamp = 1; isamp <= my nx; isamp ++) {
 			thy z [1] [isamp] = my z [ichan] [isamp];
 		}
 		return thee;
@@ -301,7 +291,7 @@ double Sound_getPowerInAir (Sound me) {
 	return ( isdefined (sum2) ? sum2 / (n * my ny) / 400 : undefined );
 }
 
-autoSound Matrix_to_Sound_mono (Matrix me, long row) {
+autoSound Matrix_to_Sound_mono (Matrix me, integer row) {
 	try {
 		autoSound thee = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1);
 		if (row < 0) row = my ny + 1 + row;
@@ -336,21 +326,21 @@ autoMatrix Sound_to_Matrix (Sound me) {
 
 autoSound Sound_upsample (Sound me) {
 	try {
-		long nfft = 1;
+		integer nfft = 1;
 		while (nfft < my nx + 2000) nfft *= 2;
 		autoSound thee = Sound_create (my ny, my xmin, my xmax, my nx * 2, my dx / 2, my x1 - my dx / 4);
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			autoNUMvector<double> data (1, 2 * nfft);   // zeroing is important...
 			NUMvector_copyElements (my z [channel], & data [1000], 1, my nx);   // ...because this fills only part of the sound
 			NUMrealft (data.peek(), nfft, 1);
-			long imin = (long) (nfft * 0.95);
-			for (long i = imin + 1; i <= nfft; i ++) {
+			integer imin = (integer) (nfft * 0.95);
+			for (integer i = imin + 1; i <= nfft; i ++) {
 				data [i] *= ((double) (nfft - i)) / (nfft - imin);
 			}
 			data [2] = 0.0;
 			NUMrealft (data.peek(), 2 * nfft, -1);
 			double factor = 1.0 / nfft;
-			for (long i = 1; i <= thy nx; i ++) {
+			for (integer i = 1; i <= thy nx; i ++) {
 				thy z [channel] [i] = data [i + 2000] * factor;
 			}
 		}
@@ -360,34 +350,34 @@ autoSound Sound_upsample (Sound me) {
 	}
 }
 
-autoSound Sound_resample (Sound me, double samplingFrequency, long precision) {
+autoSound Sound_resample (Sound me, double samplingFrequency, integer precision) {
 	double upfactor = samplingFrequency * my dx;
 	if (fabs (upfactor - 2) < 1e-6) return Sound_upsample (me);
 	if (fabs (upfactor - 1) < 1e-6) return Data_copy (me);
 	try {
-		long numberOfSamples = lround ((my xmax - my xmin) * samplingFrequency);
+		integer numberOfSamples = lround ((my xmax - my xmin) * samplingFrequency);
 		if (numberOfSamples < 1)
 			Melder_throw (U"The resampled Sound would have no samples.");
 		autoSound filtered;
 		if (upfactor < 1.0) {   // need anti-aliasing filter?
-			long nfft = 1, antiTurnAround = 1000;
+			integer nfft = 1, antiTurnAround = 1000;
 			while (nfft < my nx + antiTurnAround * 2) nfft *= 2;
 			autoNUMvector<double> data (1, nfft);
 			filtered = Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1);
-			for (long channel = 1; channel <= my ny; channel ++) {
-				for (long i = 1; i <= nfft; i ++) {
+			for (integer channel = 1; channel <= my ny; channel ++) {
+				for (integer i = 1; i <= nfft; i ++) {
 					data [i] = 0.0;
 				}
 				NUMvector_copyElements (my z [channel], & data [antiTurnAround], 1, my nx);
 				NUMrealft (data.peek(), nfft, 1);   // go to the frequency domain
-				for (long i = (long) floor (upfactor * nfft); i <= nfft; i ++) {
+				for (integer i = Melder_iroundDown (upfactor * nfft); i <= nfft; i ++) {
 					data [i] = 0.0;   // filter away high frequencies
 				}
 				data [2] = 0.0;
 				NUMrealft (data.peek(), nfft, -1);   // return to the time domain
 				double factor = 1.0 / nfft;
 				double *to = filtered -> z [channel];
-				for (long i = 1; i <= my nx; i ++) {
+				for (integer i = 1; i <= my nx; i ++) {
 					to [i] = data [i + antiTurnAround] * factor;
 				}
 			}
@@ -395,20 +385,20 @@ autoSound Sound_resample (Sound me, double samplingFrequency, long precision) {
 		}
 		autoSound thee = Sound_create (my ny, my xmin, my xmax, numberOfSamples, 1.0 / samplingFrequency,
 			0.5 * (my xmin + my xmax - (numberOfSamples - 1) / samplingFrequency));
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			double *from = my z [channel];
 			double *to = thy z [channel];
 			if (precision <= 1) {
-				for (long i = 1; i <= numberOfSamples; i ++) {
+				for (integer i = 1; i <= numberOfSamples; i ++) {
 					double x = Sampled_indexToX (thee.get(), i);
 					double index = Sampled_xToIndex (me, x);
-					long leftSample = (long) floor (index);
+					integer leftSample = Melder_iroundDown (index);
 					double fraction = index - leftSample;
 					to [i] = leftSample < 1 || leftSample >= my nx ? 0.0 :
 						(1 - fraction) * from [leftSample] + fraction * from [leftSample + 1];
 				}
 			} else {
-				for (long i = 1; i <= numberOfSamples; i ++) {
+				for (integer i = 1; i <= numberOfSamples; i ++) {
 					double x = Sampled_indexToX (thee.get(), i);
 					double index = Sampled_xToIndex (me, x);
 					to [i] = NUM_interpolate_sinc (my z [channel], my nx, index, precision);
@@ -423,13 +413,13 @@ autoSound Sound_resample (Sound me, double samplingFrequency, long precision) {
 
 autoSound Sounds_append (Sound me, double silenceDuration, Sound thee) {
 	try {
-		long nx_silence = lround (silenceDuration / my dx), nx = my nx + nx_silence + thy nx;
+		integer nx_silence = lround (silenceDuration / my dx), nx = my nx + nx_silence + thy nx;
 		if (my ny != thy ny)
 			Melder_throw (U"The numbers of channels are not equal (e.g. one is mono, the other stereo).");
 		if (my dx != thy dx)
 			Melder_throw (U"The sampling frequencies are not equal.");
 		autoSound him = Sound_create (my ny, 0.0, nx * my dx, nx, my dx, 0.5 * my dx);
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			NUMvector_copyElements (my z [channel], his z [channel], 1, my nx);
 			NUMvector_copyElements (thy z [channel], his z [channel] + my nx + nx_silence, 1, thy nx);
 		}
@@ -441,9 +431,9 @@ autoSound Sounds_append (Sound me, double silenceDuration, Sound thee) {
 
 autoSound Sounds_concatenate (OrderedOf<structSound>& list, double overlapTime) {
 	try {
-		long numberOfChannels = 0, nx = 0, numberOfSmoothingSamples;
+		integer numberOfChannels = 0, nx = 0, numberOfSmoothingSamples;
 		double dx = 0.0;
-		for (long i = 1; i <= list.size; i ++) {
+		for (integer i = 1; i <= list.size; i ++) {
 			Sound sound = list.at [i];
 			if (numberOfChannels == 0) {
 				numberOfChannels = sound -> ny;
@@ -464,12 +454,12 @@ autoSound Sounds_concatenate (OrderedOf<structSound>& list, double overlapTime)
 		if (numberOfSmoothingSamples > 0) {
 			smoother.reset (1, numberOfSmoothingSamples);
 			double factor = NUMpi / numberOfSmoothingSamples;
-			for (long i = 1; i <= numberOfSmoothingSamples; i ++) {
+			for (integer i = 1; i <= numberOfSmoothingSamples; i ++) {
 				smoother [i] = 0.5 - 0.5 * cos (factor * (i - 0.5));
 			}
 		}
 		nx = 0;
-		for (long i = 1; i <= list.size; i ++) {
+		for (integer i = 1; i <= list.size; i ++) {
 			Sound sound = list.at [i];
 			if (numberOfSmoothingSamples > 2 * sound -> nx)
 				Melder_throw (U"At least one of the sounds is shorter than twice the overlap time.\nChoose a shorter overlap time.");
@@ -477,10 +467,10 @@ autoSound Sounds_concatenate (OrderedOf<structSound>& list, double overlapTime)
 			bool thisIsTheLastSound = ( i == list.size );
 			bool weNeedSmoothingAtTheStartOfThisSound = ! thisIsTheFirstSound;
 			bool weNeedSmoothingAtTheEndOfThisSound = ! thisIsTheLastSound;
-			long numberOfSmoothingSamplesAtTheStartOfThisSound = weNeedSmoothingAtTheStartOfThisSound ? numberOfSmoothingSamples : 0;
-			long numberOfSmoothingSamplesAtTheEndOfThisSound = weNeedSmoothingAtTheEndOfThisSound ? numberOfSmoothingSamples : 0;
-			for (long channel = 1; channel <= numberOfChannels; channel ++) {
-				for (long j = 1, mySample = 1, thySample = mySample + nx;
+			integer numberOfSmoothingSamplesAtTheStartOfThisSound = weNeedSmoothingAtTheStartOfThisSound ? numberOfSmoothingSamples : 0;
+			integer numberOfSmoothingSamplesAtTheEndOfThisSound = weNeedSmoothingAtTheEndOfThisSound ? numberOfSmoothingSamples : 0;
+			for (integer channel = 1; channel <= numberOfChannels; channel ++) {
+				for (integer j = 1, mySample = 1, thySample = mySample + nx;
 					 j <= numberOfSmoothingSamplesAtTheStartOfThisSound;
 					 j ++, mySample ++, thySample ++)
 				{
@@ -488,7 +478,7 @@ autoSound Sounds_concatenate (OrderedOf<structSound>& list, double overlapTime)
 				}
 				NUMvector_copyElements (sound -> z [channel], thy z [channel] + nx,
 					1 + numberOfSmoothingSamplesAtTheStartOfThisSound, sound -> nx - numberOfSmoothingSamplesAtTheEndOfThisSound);
-				for (long j = 1, mySample = sound -> nx - numberOfSmoothingSamplesAtTheEndOfThisSound + 1, thySample = mySample + nx;
+				for (integer j = 1, mySample = sound -> nx - numberOfSmoothingSamplesAtTheEndOfThisSound + 1, thySample = mySample + nx;
 					 j <= numberOfSmoothingSamplesAtTheEndOfThisSound;
 					 j ++, mySample ++, thySample ++)
 				{
@@ -512,32 +502,32 @@ autoSound Sounds_convolve (Sound me, Sound thee, kSounds_convolve_scaling scalin
 			Melder_throw (U"The numbers of channels of the two sounds have to be equal or 1.");
 		if (my dx != thy dx)
 			Melder_throw (U"The sampling frequencies of the two sounds have to be equal.");
-		long n1 = my nx, n2 = thy nx;
-		long n3 = n1 + n2 - 1, nfft = 1;
+		integer n1 = my nx, n2 = thy nx;
+		integer n3 = n1 + n2 - 1, nfft = 1;
 		while (nfft < n3) nfft *= 2;
 		autoNUMvector <double> data1 (1, nfft);
 		autoNUMvector <double> data2 (1, nfft);
-		long numberOfChannels = my ny > thy ny ? my ny : thy ny;
+		integer numberOfChannels = my ny > thy ny ? my ny : thy ny;
 		autoSound him = Sound_create (numberOfChannels, my xmin + thy xmin, my xmax + thy xmax, n3, my dx, my x1 + thy x1);
-		for (long channel = 1; channel <= numberOfChannels; channel ++) {
+		for (integer channel = 1; channel <= numberOfChannels; channel ++) {
 			double *a = my z [my ny == 1 ? 1 : channel];
-			for (long i = n1; i > 0; i --) data1 [i] = a [i];
-			for (long i = n1 + 1; i <= nfft; i ++) data1 [i] = 0.0;
+			for (integer i = n1; i > 0; i --) data1 [i] = a [i];
+			for (integer i = n1 + 1; i <= nfft; i ++) data1 [i] = 0.0;
 			a = thy z [thy ny == 1 ? 1 : channel];
-			for (long i = n2; i > 0; i --) data2 [i] = a [i];
-			for (long i = n2 + 1; i <= nfft; i ++) data2 [i] = 0.0;
+			for (integer i = n2; i > 0; i --) data2 [i] = a [i];
+			for (integer i = n2 + 1; i <= nfft; i ++) data2 [i] = 0.0;
 			NUMrealft (data1.peek(), nfft, 1);
 			NUMrealft (data2.peek(), nfft, 1);
 			data2 [1] *= data1 [1];
 			data2 [2] *= data1 [2];
-			for (long i = 3; i <= nfft; i += 2) {
+			for (integer i = 3; i <= nfft; i += 2) {
 				double temp = data1 [i] * data2 [i] - data1 [i + 1] * data2 [i + 1];
 				data2 [i + 1] = data1 [i] * data2 [i + 1] + data1 [i + 1] * data2 [i];
 				data2 [i] = temp;
 			}
 			NUMrealft (data2.peek(), nfft, -1);
 			a = him -> z [channel];
-			for (long i = 1; i <= n3; i ++) {
+			for (integer i = 1; i <= n3; i ++) {
 				a [i] = data2 [i];
 			}
 		}
@@ -546,10 +536,10 @@ autoSound Sounds_convolve (Sound me, Sound thee, kSounds_convolve_scaling scalin
 				// do nothing
 			} break;
 			case kSounds_convolve_signalOutsideTimeDomain::SIMILAR: {
-				for (long channel = 1; channel <= numberOfChannels; channel ++) {
+				for (integer channel = 1; channel <= numberOfChannels; channel ++) {
 					double *a = his z [channel];
 					double edge = n1 < n2 ? n1 : n2;
-					for (long i = 1; i < edge; i ++) {
+					for (integer i = 1; i < edge; i ++) {
 						double factor = edge / i;
 						a [i] *= factor;
 						a [n3 + 1 - i] *= factor;
@@ -591,36 +581,36 @@ autoSound Sounds_crossCorrelate (Sound me, Sound thee, kSounds_convolve_scaling
 			Melder_throw (U"The numbers of channels of the two sounds have to be equal or 1.");
 		if (my dx != thy dx)
 			Melder_throw (U"The sampling frequencies of the two sounds have to be equal.");
-		long numberOfChannels = my ny > thy ny ? my ny : thy ny;
-		long n1 = my nx, n2 = thy nx;
-		long n3 = n1 + n2 - 1, nfft = 1;
+		integer numberOfChannels = my ny > thy ny ? my ny : thy ny;
+		integer n1 = my nx, n2 = thy nx;
+		integer n3 = n1 + n2 - 1, nfft = 1;
 		while (nfft < n3) nfft *= 2;
 		autoNUMvector <double> data1 (1, nfft);
 		autoNUMvector <double> data2 (1, nfft);
 		double my_xlast = my x1 + (n1 - 1) * my dx;
 		autoSound him = Sound_create (numberOfChannels, thy xmin - my xmax, thy xmax - my xmin, n3, my dx, thy x1 - my_xlast);
-		for (long channel = 1; channel <= numberOfChannels; channel ++) {
+		for (integer channel = 1; channel <= numberOfChannels; channel ++) {
 			double *a = my z [my ny == 1 ? 1 : channel];
-			for (long i = n1; i > 0; i --) data1 [i] = a [i];
-			for (long i = n1 + 1; i <= nfft; i ++) data1 [i] = 0.0;
+			for (integer i = n1; i > 0; i --) data1 [i] = a [i];
+			for (integer i = n1 + 1; i <= nfft; i ++) data1 [i] = 0.0;
 			a = thy z [thy ny == 1 ? 1 : channel];
-			for (long i = n2; i > 0; i --) data2 [i] = a [i];
-			for (long i = n2 + 1; i <= nfft; i ++) data2 [i] = 0.0;
+			for (integer i = n2; i > 0; i --) data2 [i] = a [i];
+			for (integer i = n2 + 1; i <= nfft; i ++) data2 [i] = 0.0;
 			NUMrealft (data1.peek(), nfft, 1);
 			NUMrealft (data2.peek(), nfft, 1);
 			data2 [1] *= data1 [1];
 			data2 [2] *= data1 [2];
-			for (long i = 3; i <= nfft; i += 2) {
+			for (integer i = 3; i <= nfft; i += 2) {
 				double temp = data1 [i] * data2 [i] + data1 [i + 1] * data2 [i + 1];   // reverse me by taking the conjugate of data1
 				data2 [i + 1] = data1 [i] * data2 [i + 1] - data1 [i + 1] * data2 [i];   // reverse me by taking the conjugate of data1
 				data2 [i] = temp;
 			}
 			NUMrealft (data2.peek(), nfft, -1);
 			a = him -> z [channel];
-			for (long i = 1; i < n1; i ++) {
+			for (integer i = 1; i < n1; i ++) {
 				a [i] = data2 [i + (nfft - (n1 - 1))];   // data for the first part ("negative lags") is at the end of data2
 			}
-			for (long i = 1; i <= n2; i ++) {
+			for (integer i = 1; i <= n2; i ++) {
 				a [i + (n1 - 1)] = data2 [i];   // data for the second part ("positive lags") is at the beginning of data2
 			}
 		}
@@ -629,10 +619,10 @@ autoSound Sounds_crossCorrelate (Sound me, Sound thee, kSounds_convolve_scaling
 				// do nothing
 			} break;
 			case kSounds_convolve_signalOutsideTimeDomain::SIMILAR: {
-				for (long channel = 1; channel <= numberOfChannels; channel ++) {
+				for (integer channel = 1; channel <= numberOfChannels; channel ++) {
 					double *a = his z [channel];
 					double edge = n1 < n2 ? n1 : n2;
-					for (long i = 1; i < edge; i ++) {
+					for (integer i = 1; i < edge; i ++) {
 						double factor = edge / i;
 						a [i] *= factor;
 						a [n3 + 1 - i] *= factor;
@@ -670,28 +660,28 @@ autoSound Sounds_crossCorrelate (Sound me, Sound thee, kSounds_convolve_scaling
 
 autoSound Sound_autoCorrelate (Sound me, kSounds_convolve_scaling scaling, kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) {
 	try {
-		long numberOfChannels = my ny, n1 = my nx, n2 = n1 + n1 - 1, nfft = 1;
+		integer numberOfChannels = my ny, n1 = my nx, n2 = n1 + n1 - 1, nfft = 1;
 		while (nfft < n2) nfft *= 2;
 		autoNUMvector <double> data (1, nfft);
 		double my_xlast = my x1 + (n1 - 1) * my dx;
 		autoSound thee = Sound_create (numberOfChannels, my xmin - my xmax, my xmax - my xmin, n2, my dx, my x1 - my_xlast);
-		for (long channel = 1; channel <= numberOfChannels; channel ++) {
+		for (integer channel = 1; channel <= numberOfChannels; channel ++) {
 			double *a = my z [channel];
-			for (long i = n1; i > 0; i --) data [i] = a [i];
-			for (long i = n1 + 1; i <= nfft; i ++) data [i] = 0.0;
+			for (integer i = n1; i > 0; i --) data [i] = a [i];
+			for (integer i = n1 + 1; i <= nfft; i ++) data [i] = 0.0;
 			NUMrealft (data.peek(), nfft, 1);
 			data [1] *= data [1];
 			data [2] *= data [2];
-			for (long i = 3; i <= nfft; i += 2) {
+			for (integer i = 3; i <= nfft; i += 2) {
 				data [i] = data [i] * data [i] + data [i + 1] * data [i + 1];
 				data [i + 1] = 0.0;   // reverse me by taking the conjugate of data1
 			}
 			NUMrealft (data.peek(), nfft, -1);
 			a = thy z [channel];
-			for (long i = 1; i < n1; i ++) {
+			for (integer i = 1; i < n1; i ++) {
 				a [i] = data [i + (nfft - (n1 - 1))];   // data for the first part ("negative lags") is at the end of data
 			}
-			for (long i = 1; i <= n1; i ++) {
+			for (integer i = 1; i <= n1; i ++) {
 				a [i + (n1 - 1)] = data [i];   // data for the second part ("positive lags") is at the beginning of data
 			}
 		}
@@ -700,10 +690,10 @@ autoSound Sound_autoCorrelate (Sound me, kSounds_convolve_scaling scaling, kSoun
 				// do nothing
 			} break;
 			case kSounds_convolve_signalOutsideTimeDomain::SIMILAR: {
-				for (long channel = 1; channel <= numberOfChannels; channel ++) {
+				for (integer channel = 1; channel <= numberOfChannels; channel ++) {
 					double *a = thy z [channel];
 					double edge = n1;
-					for (long i = 1; i < edge; i ++) {
+					for (integer i = 1; i < edge; i ++) {
 						double factor = edge / i;
 						a [i] *= factor;
 						a [n2 + 1 - i] *= factor;
@@ -770,12 +760,12 @@ void Sound_draw (Sound me, Graphics g,
 		Set coordinates for drawing.
 	*/
 	Graphics_setInner (g);
-	for (long channel = 1; channel <= my ny; channel ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		Graphics_setWindow (g, treversed ? tmax : tmin, treversed ? tmin : tmax,
 			minimum - (my ny - channel) * (maximum - minimum),
 			maximum + (channel - 1) * (maximum - minimum));
 		if (str32str (method, U"bars") || str32str (method, U"Bars")) {
-			for (long ix = ixmin; ix <= ixmax; ix ++) {
+			for (integer ix = ixmin; ix <= ixmax; ix ++) {
 				double x = Sampled_indexToX (me, ix);
 				double y = my z [channel] [ix];
 				double left = x - 0.5 * my dx, right = x + 0.5 * my dx;
@@ -787,12 +777,12 @@ void Sound_draw (Sound me, Graphics g,
 				Graphics_line (g, right, y, right, minimum);
 			}
 		} else if (str32str (method, U"poles") || str32str (method, U"Poles")) {
-			for (long 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 [channel] [ix]);
 			}
 		} else if (str32str (method, U"speckles") || str32str (method, U"Speckles")) {
-			for (long ix = ixmin; ix <= ixmax; ix ++) {
+			for (integer ix = ixmin; ix <= ixmax; ix ++) {
 				double x = Sampled_indexToX (me, ix);
 				Graphics_speckle (g, x, my z [channel] [ix]);
 			}
@@ -828,18 +818,18 @@ void Sound_draw (Sound me, Graphics g,
 	}
 }
 
-static double interpolate (Sound me, long i1, long channel)
+static double interpolate (Sound me, integer i1, integer channel)
 /* Precondition: my z [1] [i1] != my z [1] [i1 + 1]; */
 {
-	long i2 = i1 + 1;
+	integer i2 = i1 + 1;
 	double x1 = Sampled_indexToX (me, i1), x2 = Sampled_indexToX (me, i2);
 	double y1 = my z [channel] [i1], y2 = my z [channel] [i2];
 	return x1 + (x2 - x1) * y1 / (y1 - y2);   // linear
 }
-double Sound_getNearestZeroCrossing (Sound me, double position, long channel) {
+double Sound_getNearestZeroCrossing (Sound me, double position, integer channel) {
 	double *amplitude = my z [channel];
-	long leftSample = Sampled_xToLowIndex (me, position);
-	long rightSample = leftSample + 1, ileft, iright;
+	integer leftSample = Sampled_xToLowIndex (me, position);
+	integer rightSample = leftSample + 1, ileft, iright;
 	double leftZero, rightZero;
 	/* Are we already at a zero crossing? */
 	if (leftSample >= 1 && rightSample <= my nx &&
@@ -872,7 +862,7 @@ double Sound_getNearestZeroCrossing (Sound me, double position, long channel) {
 void Sound_setZero (Sound me, double tmin_in, double tmax_in, bool roundTimesToNearestZeroCrossing) {
 	Function_unidirectionalAutowindow (me, & tmin_in, & tmax_in);
 	Function_intersectRangeWithDomain (me, & tmin_in, & tmax_in);
-	for (long channel = 1; channel <= my ny; channel ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		double tmin = tmin_in, tmax = tmax_in;
 		if (roundTimesToNearestZeroCrossing) {
 			if (tmin > my xmin) tmin = Sound_getNearestZeroCrossing (me, tmin_in, channel);
@@ -888,14 +878,14 @@ void Sound_setZero (Sound me, double tmin_in, double tmax_in, bool roundTimesToN
 	}
 }
 
-autoSound Sound_createAsPureTone (long numberOfChannels, double startingTime, double endTime,
+autoSound Sound_createAsPureTone (integer numberOfChannels, double startingTime, double endTime,
 	double sampleRate, double frequency, double amplitude, double fadeInDuration, double fadeOutDuration)
 {
 	try {
 		double numberOfSamples_f = round ((endTime - startingTime) * sampleRate);
 		if (numberOfSamples_f > (double) INT32_MAX)
 			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,
+		autoSound me = Sound_create (numberOfChannels, startingTime, endTime, (integer) numberOfSamples_f,
 			1.0 / sampleRate, startingTime + 0.5 / sampleRate);
 		for (integer isamp = 1; isamp <= my nx; isamp ++) {
 			double time = my x1 + (isamp - 1) * my dx;
@@ -906,7 +896,7 @@ autoSound Sound_createAsPureTone (long numberOfChannels, double startingTime, do
 			double timeFromEnd = endTime - time;
 			if (timeFromEnd < fadeOutDuration)
 				value *= 0.5 - 0.5 * cos (NUMpi * timeFromEnd / fadeOutDuration);
-			for (long ichan = 1; ichan <= my ny; ichan ++) {
+			for (integer ichan = 1; ichan <= my ny; ichan ++) {
 				my z [ichan] [isamp] = value;
 			}
 		}
@@ -917,7 +907,7 @@ autoSound Sound_createAsPureTone (long numberOfChannels, double startingTime, do
 }
 
 autoSound Sound_createAsToneComplex (double startTime, double endTime, double samplingFrequency,
-	int phase, double frequencyStep, double firstFrequency, double ceiling, long numberOfComponents)
+	int phase, double frequencyStep, double firstFrequency, double ceiling, integer numberOfComponents)
 {
 	try {
 		if (frequencyStep == 0.0)
@@ -935,7 +925,7 @@ autoSound Sound_createAsToneComplex (double startTime, double endTime, double sa
 		/*
 		 * Translate number of components.
 		 */
-		long maximumNumberOfComponents = (long) floor ((ceiling - firstFrequency) / frequencyStep) + 1;
+		integer maximumNumberOfComponents = Melder_iroundDown ((ceiling - firstFrequency) / frequencyStep) + 1;
 		if (numberOfComponents <= 0 || numberOfComponents > maximumNumberOfComponents)
 			numberOfComponents = maximumNumberOfComponents;
 		if (numberOfComponents < 1)
@@ -966,7 +956,7 @@ autoSound Sound_createAsToneComplex (double startTime, double endTime, double sa
 }
 
 void Sound_multiplyByWindow (Sound me, kSound_windowShape windowShape) {
-	for (long channel = 1; channel <= my ny; channel ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		integer n = my nx;
 		double *amp = my z [channel];
 		switch (windowShape) {
@@ -1026,8 +1016,8 @@ void Sound_scaleIntensity (Sound me, double newAverageIntensity) {
 	double currentIntensity = Sound_getIntensity_dB (me), factor;
 	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 ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
+		for (integer i = 1; i <= my nx; i ++) {
 			my z [channel] [i] *= factor;
 		}
 	}
@@ -1061,8 +1051,8 @@ autoSound Sound_extractPart (Sound me, double t1, double t2, kSound_windowShape
 		/*
 		 * Determine index range. We use all the real or virtual samples that fit within [t1..t2].
 		 */
-		long ix1 = 1 + (long) ceil ((t1 - my x1) / my dx);
-		long ix2 = 1 + (long) floor ((t2 - my x1) / my dx);
+		integer ix1 = 1 + (integer) ceil ((t1 - my x1) / my dx);
+		integer ix2 = 1 + Melder_iroundDown ((t2 - my x1) / my dx);
 		if (ix2 < ix1) Melder_throw (U"Extracted Sound would contain no samples.");
 		/*
 		 * Create sound, optionally shifted to [0..t2-t1].
@@ -1073,7 +1063,7 @@ autoSound Sound_extractPart (Sound me, double t1, double t2, kSound_windowShape
 		 * Copy only *real* samples into the new sound.
 		 * The *virtual* samples will remain at zero.
 		 */
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			NUMvector_copyElements (my z [channel], thy z [channel] + 1 - ix1,
 					( ix1 < 1 ? 1 : ix1 ), ( ix2 > my nx ? my nx : ix2 ));
 		}
@@ -1100,8 +1090,8 @@ autoSound Sound_extractPartForOverlap (Sound me, double t1, double t2, double ov
 		/*
 		 * Determine index range. We use all the real or virtual samples that fit within [t1..t2].
 		 */
-		long ix1 = 1 + (long) ceil ((t1 - my x1) / my dx);
-		long ix2 = 1 + (long) floor ((t2 - my x1) / my dx);
+		integer ix1 = 1 + (integer) ceil ((t1 - my x1) / my dx);
+		integer ix2 = 1 + Melder_iroundDown ((t2 - my x1) / my dx);
 		if (ix2 < ix1) Melder_throw (U"Extracted Sound would contain no samples.");
 		/*
 		 * Create sound.
@@ -1114,7 +1104,7 @@ autoSound Sound_extractPartForOverlap (Sound me, double t1, double t2, double ov
 		 * Copy only *real* samples into the new sound.
 		 * The *virtual* samples will remain at zero.
 		 */
-		for (long channel = 1; channel <= my ny; channel ++) {
+		for (integer channel = 1; channel <= my ny; channel ++) {
 			NUMvector_copyElements (my z [channel], thy z [channel] + 1 - ix1,
 					( ix1 < 1 ? 1 : ix1 ), ( ix2 > my nx ? my nx : ix2 ));
 		}
@@ -1157,7 +1147,7 @@ autoSound Sound_filter_oneFormant (Sound me, double frequency, double bandwidth)
 }
 
 void Sound_filterWithOneFormantInline (Sound me, double frequency, double bandwidth) {
-	for (long channel = 1; channel <= my ny; channel ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		NUMfilterSecondOrderSection_fb (my z [channel], my nx, my dx, frequency, bandwidth);
 	}
 	Matrix_scaleAbsoluteExtremum (me, 0.99);
@@ -1189,7 +1179,7 @@ void Sound_reverse (Sound me, double tmin, double tmax) {
 	if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }   // autowindowing
 	integer itmin, itmax;
 	integer n = Sampled_getWindowSamples (me, tmin, tmax, & itmin, & itmax) / 2;
-	for (long channel = 1; channel <= my ny; channel ++) {
+	for (integer channel = 1; channel <= my ny; channel ++) {
 		double *amp = my z [channel];
 		for (integer i = 0; i < n; i ++) {
 			double dummy = amp [itmin + i];
@@ -1207,9 +1197,9 @@ autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double
 			Melder_throw (U"Numbers of channels are not equal.");
 		double dt = my dx;
 		double dphase = (thy x1 - my x1) / dt;
-		dphase -= floor (dphase);   // a number between 0 and 1
+		dphase -= Melder_roundDown (dphase);   // a number between 0 and 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 i2 = Melder_iroundDown (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.");
@@ -1217,10 +1207,10 @@ autoSound Sounds_crossCorrelate_short (Sound me, Sound thee, double tmin, double
 		autoSound him = Sound_create (1, tmin, tmax, nt, dt, t1);
 		for (integer i = 1; i <= nt; i ++) {
 			integer di = i - 1 + i1;
-			for (long ime = 1; ime <= my nx; ime ++) {
+			for (integer ime = 1; ime <= my nx; ime ++) {
 				if (ime + di < 1) continue;
 				if (ime + di > thy nx) break;
-				for (long channel = 1; channel <= my ny; channel ++) {
+				for (integer channel = 1; channel <= my ny; channel ++) {
 					his z [1] [i] += my z [channel] [ime] * thy z [channel] [ime + di];
 				}
 			}
diff --git a/fon/Sound.h b/fon/Sound.h
index 3b5aac7..a4ebe4a 100644
--- a/fon/Sound.h
+++ b/fon/Sound.h
@@ -54,7 +54,7 @@ Thing_define (Sound, Vector) {
 	z may be replaced (e.g., in pasting).
 */
 
-autoSound Sound_create (long numberOfChannels, double xmin, double xmax, long nx, double dx, double x1);
+autoSound Sound_create (integer numberOfChannels, double xmin, double xmax, integer nx, double dx, double x1);
 /*
 	Function:
 		return a new silent Sound.
@@ -76,7 +76,7 @@ autoSound Sound_create (long numberOfChannels, double xmin, double xmax, long nx
 		thy z [i] [1..nx] == 0.0;
 */
 
-autoSound Sound_createSimple (long numberOfChannels, double duration, double samplingFrequency);
+autoSound Sound_createSimple (integer numberOfChannels, double duration, double samplingFrequency);
 /*
 	Function:
 		return a new silent Sound.
@@ -99,7 +99,7 @@ autoSound Sound_createSimple (long numberOfChannels, double duration, double sam
 
 autoSound Sound_convertToMono (Sound me);
 autoSound Sound_convertToStereo (Sound me);
-autoSound Sound_extractChannel (Sound me, long ichannel);
+autoSound Sound_extractChannel (Sound me, integer ichannel);
 autoSound Sounds_combineToStereo (OrderedOf<structSound>* me);
 
 /* Levels for Sampled_getValueAtSample (me, index, level, unit) */
@@ -109,7 +109,7 @@ autoSound Sounds_combineToStereo (OrderedOf<structSound>* me);
 
 autoSound Sound_upsample (Sound me);   /* By a factor 2. */
 
-autoSound Sound_resample (Sound me, double samplingFrequency, long precision);
+autoSound Sound_resample (Sound me, double samplingFrequency, integer precision);
 /*
 	Method:
 		precision <= 1: linear interpolation.
@@ -161,14 +161,14 @@ double Sound_getEnergyInAir (Sound me);
 double Sound_getPowerInAir (Sound me);
 double Sound_getIntensity_dB (Sound me);
 
-double Sound_getNearestZeroCrossing (Sound me, double position, long ichannel);
+double Sound_getNearestZeroCrossing (Sound me, double position, integer ichannel);
 void Sound_setZero (Sound me, double tmin, double tmax, bool roundTimesToNearestZeroCrossing);
 
-autoSound Sound_createAsPureTone (long numberOfChannels, double startingTime, double endTime,
+autoSound Sound_createAsPureTone (integer numberOfChannels, double startingTime, double endTime,
 	double sampleRate, double frequency, double amplitude, double fadeInDuration, double fadeOutDuration);
 autoSound Sound_createAsToneComplex (double startingTime, double endTime,
 	double sampleRate, int phase, double frequencyStep,
-	double firstFrequency, double ceiling, long numberOfComponents);
+	double firstFrequency, double ceiling, integer numberOfComponents);
 /* Values for `phase' parameter: */
 #define Sound_TONE_COMPLEX_SINE  0
 #define Sound_TONE_COMPLEX_COSINE  1
@@ -200,7 +200,7 @@ autoMatrix Sound_to_Matrix (Sound me);
 
 autoSound Matrix_to_Sound (Matrix me);
 
-autoSound Matrix_to_Sound_mono (Matrix me, long row);
+autoSound Matrix_to_Sound_mono (Matrix me, integer row);
 /*
 	Function:
 		create a Sound from one row of a Matrix.
diff --git a/fon/SoundRecorder.cpp b/fon/SoundRecorder.cpp
index 0135abd..e7944d5 100644
--- a/fon/SoundRecorder.cpp
+++ b/fon/SoundRecorder.cpp
@@ -306,14 +306,14 @@ static void showMeter (SoundRecorder me, short *buffer, integer nsamp) {
 			}
 		}
 		if (my lastLeftMaximum > 30000) {
-			int leak = my lastLeftMaximum - (int) floor (2000000 / theControlPanel. sampleRate);
+			int leak = my lastLeftMaximum - Melder_iroundDown (2000000.0 / theControlPanel. sampleRate);
 			if (leftMaximum < leak) leftMaximum = leak;
 		}
 		showMaximum (me, 1, leftMaximum);
 		my lastLeftMaximum = leftMaximum;
 		if (my numberOfChannels == 2) {
 			if (my lastRightMaximum > 30000) {
-				int leak = my lastRightMaximum - (int) floor (2000000 / theControlPanel. sampleRate);
+				int leak = my lastRightMaximum - Melder_iroundDown (2000000.0 / theControlPanel. sampleRate);
 				if (rightMaximum < leak) rightMaximum = leak;
 			}
 			showMaximum (me, 2, rightMaximum);
@@ -847,7 +847,7 @@ void structSoundRecorder :: v_createChildren ()
 			y += Gui_RADIOBUTTON_HEIGHT + Gui_RADIOBUTTON_SPACING;
 			our fsamps [i]. button = GuiRadioButton_createShown (our windowForm,
 				-150, -10, y, y + Gui_RADIOBUTTON_HEIGHT,
-				Melder_cat (fsamp == floor (fsamp) ? Melder_integer ((integer) fsamp) : Melder_fixed (fsamp, 5), U" Hz"),
+				Melder_cat (fsamp == Melder_roundDown (fsamp) ? Melder_integer ((integer) fsamp) : Melder_fixed (fsamp, 5), U" Hz"),
 				gui_radiobutton_cb_fsamp, this, fsamp == theControlPanel. sampleRate ? GuiRadioButton_SET : 0);
 		}
 	}
diff --git a/fon/Sound_PointProcess.cpp b/fon/Sound_PointProcess.cpp
index 0afe589..3f710f3 100644
--- a/fon/Sound_PointProcess.cpp
+++ b/fon/Sound_PointProcess.cpp
@@ -29,7 +29,7 @@ autoSound Sound_PointProcess_to_SoundEnsemble_correlate (Sound me, PointProcess
 			Melder_throw (U"Sound has to be mono.");
 		long numberOfPoints = thy nt;
 		double hisDuration = toLag - fromLag;
-		long numberOfSamples = (long) floor (hisDuration / my dx) + 1;
+		integer numberOfSamples = Melder_iroundDown (hisDuration / my dx) + 1;
 		if (numberOfSamples < 1)
 			Melder_throw (U"Time window too short.");
 		double midTime = 0.5 * (fromLag + toLag);
diff --git a/fon/Sound_and_Spectrogram.cpp b/fon/Sound_and_Spectrogram.cpp
index b2edceb..cfbbec7 100644
--- a/fon/Sound_and_Spectrogram.cpp
+++ b/fon/Sound_and_Spectrogram.cpp
@@ -59,7 +59,7 @@ autoSpectrogram Sound_to_Spectrogram (Sound me, double effectiveAnalysisWidth, d
 		/*
 		 * Compute the time sampling.
 		 */
-		long nsamp_window = (long) floor (physicalAnalysisWidth / my dx);
+		integer nsamp_window = Melder_iroundDown (physicalAnalysisWidth / my dx);
 		long halfnsamp_window = nsamp_window / 2 - 1;
 		nsamp_window = halfnsamp_window * 2;
 		if (nsamp_window < 1)
@@ -68,7 +68,7 @@ autoSpectrogram Sound_to_Spectrogram (Sound me, double effectiveAnalysisWidth, d
 			Melder_throw (U"Your sound is too short:\n"
 				U"it should be at least as long as ",
 				windowType == kSound_to_Spectrogram_windowShape::GAUSSIAN ? U"two window lengths." : U"one window length.");
-		long numberOfTimes = 1 + (long) floor ((duration - physicalAnalysisWidth) / timeStep);   // >= 1
+		integer numberOfTimes = 1 + Melder_iroundDown ((duration - physicalAnalysisWidth) / timeStep);   // >= 1
 		double t1 = my x1 + 0.5 * ((double) (my nx - 1) * my dx - (double) (numberOfTimes - 1) * timeStep);
 			/* Centre of first frame. */
 
@@ -76,7 +76,7 @@ autoSpectrogram Sound_to_Spectrogram (Sound me, double effectiveAnalysisWidth, d
 		 * Compute the frequency sampling of the FFT spectrum.
 		 */
 		if (fmax <= 0.0 || fmax > nyquist) fmax = nyquist;
-		long numberOfFreqs = (long) floor (fmax / freqStep);
+		integer numberOfFreqs = Melder_iroundDown (fmax / freqStep);
 		if (numberOfFreqs < 1) return autoSpectrogram ();
 		long nsampFFT = 1;
 		while (nsampFFT < nsamp_window || nsampFFT < 2 * numberOfFreqs * (nyquist / fmax))
@@ -86,11 +86,11 @@ autoSpectrogram Sound_to_Spectrogram (Sound me, double effectiveAnalysisWidth, d
 		/*
 		 * Compute the frequency sampling of the spectrogram.
 		 */
-		long binWidth_samples = (long) floor (freqStep * my dx * nsampFFT);
+		integer binWidth_samples = Melder_iroundDown (freqStep * my dx * nsampFFT);
 		if (binWidth_samples < 1) binWidth_samples = 1;
 		double binWidth_hertz = 1.0 / (my dx * nsampFFT);
 		freqStep = binWidth_samples * binWidth_hertz;
-		numberOfFreqs = (long) floor (fmax / freqStep);
+		numberOfFreqs = Melder_iroundDown (fmax / freqStep);
 		if (numberOfFreqs < 1) return autoSpectrogram ();
 
 		autoSpectrogram thee = Spectrogram_create (my xmin, my xmax, numberOfTimes, timeStep, t1,
@@ -183,16 +183,16 @@ autoSpectrogram Sound_to_Spectrogram (Sound me, double effectiveAnalysisWidth, d
 
 autoSound Spectrogram_to_Sound (Spectrogram me, double fsamp) {
 	try {
-		double dt = 1 / fsamp;
-		long n = (long) floor ((my xmax - my xmin) / dt);
+		double dt = 1.0 / fsamp;
+		integer n = Melder_iroundDown ((my xmax - my xmin) / dt);
 		if (n < 0) return autoSound ();
 		autoSound thee = Sound_create (1, my xmin, my xmax, n, dt, 0.5 * dt);
 		for (long i = 1; i <= n; i ++) {
 			double t = Sampled_indexToX (thee.get(), i);
 			double rframe = Sampled_xToIndex (me, t), phase, value = 0.0;
-			long leftFrame, rightFrame;
+			integer leftFrame, rightFrame;
 			if (rframe < 1 || rframe >= my nx) continue;
-			leftFrame = (long) floor (rframe), rightFrame = leftFrame + 1, phase = rframe - leftFrame;
+			leftFrame = Melder_iroundDown (rframe), rightFrame = leftFrame + 1, phase = rframe - leftFrame;
 			for (long j = 1; j <= my ny; j ++) {
 				double f = Matrix_rowToY (me, j);
 				double power = my z [j] [leftFrame] * (1 - phase) + my z [j] [rightFrame] * phase;
diff --git a/fon/Sound_audio.cpp b/fon/Sound_audio.cpp
index 3141f16..fb52524 100644
--- a/fon/Sound_audio.cpp
+++ b/fon/Sound_audio.cpp
@@ -261,7 +261,7 @@ autoSound Sound_record_fixedTime (int inputSource, double gain, double balance,
 			#if defined (macintosh) || defined (_WIN32)
 				/* Taken from Audio Control Panel. */
 			#elif defined (linux) && ! defined (NO_AUDIO)
-				val = (gain <= 0.0 ? 0 : gain >= 1.0 ? 100 : floor (gain * 100 + 0.5));  
+				val = (gain <= 0.0 ? 0 : gain >= 1.0 ? 100 : Melder_iround_tieUp (gain * 100));  
 				balance = balance <= 0 ? 0 : balance >= 1 ? 1 : balance;
 				if (balance >= 0.5) {
 					val = (int)(((int)(val*balance/(1-balance)) << 8) | val);
diff --git a/fon/Sound_to_Cochleagram.cpp b/fon/Sound_to_Cochleagram.cpp
index 32177c4..543e418 100644
--- a/fon/Sound_to_Cochleagram.cpp
+++ b/fon/Sound_to_Cochleagram.cpp
@@ -35,8 +35,8 @@
 autoCochleagram Sound_to_Cochleagram (Sound me, double dt, double df, double dt_window, double forwardMaskingTime) {
 	try {
 		double duration = my nx * my dx;
-		long nFrames = 1 + (long) floor ((duration - dt_window) / dt);
-		long nsamp_window = (long) floor (dt_window / my dx), halfnsamp_window = nsamp_window / 2 - 1;
+		integer nFrames = 1 + Melder_iroundDown ((duration - dt_window) / dt);
+		integer nsamp_window = Melder_iroundDown (dt_window / my dx), halfnsamp_window = nsamp_window / 2 - 1;
 		long nf = lround (25.6 / df);
 		double dampingFactor = forwardMaskingTime > 0.0 ? exp (- dt / forwardMaskingTime) : 0.0;   // default 30 ms
 		double integrationCorrection = 1.0 - dampingFactor;
@@ -186,7 +186,7 @@ autoCochleagram Sound_to_Cochleagram_edb
 							mean += basil -> z [1] [isamp];
 						mean /= n;
 					} else {
-						double mu = floor ((i1 + i2) / 2.0);
+						double mu = Melder_roundDown ((i1 + i2) / 2.0);
 						integer muint = (long) mu, dint = (long) d;
 						for (integer isamp = muint - dint; isamp <= muint + dint; isamp ++) {
 							double y = 0;
diff --git a/fon/Sound_to_Formant.cpp b/fon/Sound_to_Formant.cpp
index 558d4d7..52a7d5b 100644
--- a/fon/Sound_to_Formant.cpp
+++ b/fon/Sound_to_Formant.cpp
@@ -270,8 +270,8 @@ static autoFormant Sound_to_Formant_any_inline (Sound me, double dt_in, int numb
 	double dt = dt_in > 0.0 ? dt_in : halfdt_window / 4.0;
 	double duration = my nx * my dx, t1;
 	double dt_window = 2.0 * halfdt_window;
-	long nFrames = 1 + (long) floor ((duration - dt_window) / dt);
-	long nsamp_window = (long) floor (dt_window / my dx), halfnsamp_window = nsamp_window / 2;
+	integer nFrames = 1 + Melder_iroundDown ((duration - dt_window) / dt);
+	integer nsamp_window = Melder_iroundDown (dt_window / my dx), halfnsamp_window = nsamp_window / 2;
 
 	if (nsamp_window < numberOfPoles + 1)
 		Melder_throw (U"Window too short.");
diff --git a/fon/Sound_to_Harmonicity_GNE.cpp b/fon/Sound_to_Harmonicity_GNE.cpp
index 87c58a3..1374313 100644
--- a/fon/Sound_to_Harmonicity_GNE.cpp
+++ b/fon/Sound_to_Harmonicity_GNE.cpp
@@ -53,7 +53,7 @@ autoMatrix Sound_to_Harmonicity_GNE (Sound me,
 {
 	try {
 		autoSound envelope [1+100];
-		long nenvelopes = (long) floor ((fmax - fmin) / step);
+		integer nenvelopes = Melder_iroundDown ((fmax - fmin) / step);
 		for (long ienvelope = 1; ienvelope <= 100; ienvelope ++)
 			Melder_assert (! envelope [ienvelope].get());
 
diff --git a/fon/Sound_to_Intensity.cpp b/fon/Sound_to_Intensity.cpp
index 65d623a..957bc3b 100644
--- a/fon/Sound_to_Intensity.cpp
+++ b/fon/Sound_to_Intensity.cpp
@@ -51,7 +51,7 @@ static autoIntensity Sound_to_Intensity_ (Sound me, double minimumPitch, double
 		const double windowDuration = 6.4 / minimumPitch;
 		Melder_assert (windowDuration > 0.0);
 		const double halfWindowDuration = 0.5 * windowDuration;
-		const long halfWindowSamples = (long) floor (halfWindowDuration / my dx);
+		const integer halfWindowSamples = Melder_iroundDown (halfWindowDuration / my dx);
 		autoNUMvector <double> amplitude (- halfWindowSamples, halfWindowSamples);
 		autoNUMvector <double> window (- halfWindowSamples, halfWindowSamples);
 
diff --git a/fon/Sound_to_Pitch.cpp b/fon/Sound_to_Pitch.cpp
index 8f0a249..fdf4c31 100644
--- a/fon/Sound_to_Pitch.cpp
+++ b/fon/Sound_to_Pitch.cpp
@@ -361,7 +361,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		Melder_assert (maxnCandidates >= 2);
 		Melder_assert (method >= AC_HANNING && method <= FCC_ACCURATE);
 
-		if (maxnCandidates < ceiling / minimumPitch) maxnCandidates = (long) floor (ceiling / minimumPitch);
+		if (maxnCandidates < ceiling / minimumPitch) maxnCandidates = Melder_iroundDown (ceiling / minimumPitch);
 
 		if (dt <= 0.0) dt = periodsPerWindow / minimumPitch / 4.0;   // e.g. 3 periods, 75 Hz: 10 milliseconds
 
@@ -393,7 +393,7 @@ 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).
 		 */
-		integer nsamp_period = (long) floor (1 / my dx / minimumPitch);
+		integer nsamp_period = Melder_iroundDown (1.0 / my dx / minimumPitch);
 		integer halfnsamp_period = nsamp_period / 2 + 1;
 
 		if (ceiling > 0.5 / my dx) ceiling = 0.5 / my dx;
@@ -402,7 +402,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		 * Determine window length in seconds and in samples.
 		 */
 		real dt_window = periodsPerWindow / minimumPitch;
-		integer nsamp_window = (long) floor (dt_window / my dx);
+		integer nsamp_window = Melder_iroundDown (dt_window / my dx);
 		integer halfnsamp_window = nsamp_window / 2 - 1;
 		if (halfnsamp_window < 2)
 			Melder_throw (U"Analysis window too short.");
@@ -411,9 +411,9 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		/*
 		 * Determine the minimum and maximum lags.
 		 */
-		minimumLag = (long) floor (1.0 / my dx / ceiling);
+		minimumLag = Melder_iroundDown (1.0 / my dx / ceiling);
 		if (minimumLag < 2) minimumLag = 2;
-		maximumLag = (long) floor (nsamp_window / periodsPerWindow) + 2;
+		maximumLag = Melder_iroundDown (nsamp_window / periodsPerWindow) + 2;
 		if (maximumLag > nsamp_window) maximumLag = nsamp_window;
 
 		/*
@@ -465,7 +465,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 		if (method >= FCC_NORMAL) {   /* For cross-correlation analysis. */
 
 			nsampFFT = 0;
-			brent_ixmax = (long) floor (nsamp_window * interpolation_depth);
+			brent_ixmax = Melder_iroundDown (nsamp_window * interpolation_depth);
 
 		} else {   /* For autocorrelation analysis. */
 
@@ -523,7 +523,7 @@ autoPitch Sound_to_Pitch_any (Sound me,
 			}
 			windowR [1] = 1.0;   // normalize
 
-			brent_ixmax = (long) floor (nsamp_window * interpolation_depth);
+			brent_ixmax = Melder_iroundDown (nsamp_window * interpolation_depth);
 		}
 
 		autoMelderProgress progress (U"Sound to Pitch...");
diff --git a/fon/Spectrum_to_Excitation.cpp b/fon/Spectrum_to_Excitation.cpp
index 5e6c8b4..3081d44 100644
--- a/fon/Spectrum_to_Excitation.cpp
+++ b/fon/Spectrum_to_Excitation.cpp
@@ -20,7 +20,7 @@
 
 autoExcitation Spectrum_to_Excitation (Spectrum me, double dbark) {
 	try {
-		long nbark = (int) floor (25.6 / dbark + 0.5);
+		integer nbark = Melder_iround_tieUp (25.6 / dbark);
 		double *re = my z [1], *im = my z [2]; 
 
 		autoNUMvector <double> auditoryFilter (1, nbark);
diff --git a/fon/TextGridEditor.cpp b/fon/TextGridEditor.cpp
index 8d87e96..a4af1c6 100644
--- a/fon/TextGridEditor.cpp
+++ b/fon/TextGridEditor.cpp
@@ -72,7 +72,7 @@ static int _TextGridEditor_yWCtoTier (TextGridEditor me, double yWC) {
 	TextGrid grid = (TextGrid) my data;
 	int ntier = grid -> tiers->size;
 	double soundY = _TextGridEditor_computeSoundY (me);
-	int itier = ntier - (int) floor (yWC / soundY * (double) ntier);
+	int itier = ntier - Melder_iroundDown (yWC / soundY * (double) ntier);
 	if (itier < 1) itier = 1; if (itier > ntier) itier = ntier;
 	return itier;
 }
diff --git a/fon/TextGrid_Sound.cpp b/fon/TextGrid_Sound.cpp
index d416090..89996b6 100644
--- a/fon/TextGrid_Sound.cpp
+++ b/fon/TextGrid_Sound.cpp
@@ -499,19 +499,19 @@ autoSoundList TextGrid_Sound_extractIntervalsWhere (TextGrid me, Sound sound, lo
 static void autoMarks (Graphics g, double ymin, double ymax, bool haveDottedLines) {
 	double dy = ymax - ymin;
 	if (dy < 26.0) {
-		long imin = (long) ceil ((ymin + 2.0) / 5.0), imax = (long) floor ((ymax - 2.0) / 5.0);
+		integer imin = (long) ceil ((ymin + 2.0) / 5.0), imax = Melder_iroundDown ((ymax - 2.0) / 5.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 5.0, true, true, haveDottedLines, nullptr);
 	} else if (dy < 110.0) {
-		long imin = (long) ceil ((ymin + 8.0) / 20.0), imax = (long) floor ((ymax - 8.0) / 20.0);
+		integer imin = (long) ceil ((ymin + 8.0) / 20.0), imax = Melder_iroundDown ((ymax - 8.0) / 20.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 20.0, true, true, haveDottedLines, nullptr);
 	} else if (dy < 260.0) {
-		long imin = (long) ceil ((ymin + 20.0) / 50.0), imax = (long) floor ((ymax - 20.0) / 50.0);
+		integer imin = (long) ceil ((ymin + 20.0) / 50.0), imax = Melder_iroundDown ((ymax - 20.0) / 50.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 50.0, true, true, haveDottedLines, nullptr);
 	} else if (dy < 510.0) {
-		long imin = (long) ceil ((ymin + 40.0) / 100.0), imax = (long) floor ((ymax - 40.0) / 100.0);
+		integer imin = (long) ceil ((ymin + 40.0) / 100.0), imax = Melder_iroundDown ((ymax - 40.0) / 100.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 100.0, true, true, haveDottedLines, nullptr);
 	}
@@ -559,19 +559,19 @@ static void autoMarks_logarithmic (Graphics g, double ymin, double ymax, bool ha
 static void autoMarks_semitones (Graphics g, double ymin, double ymax, bool haveDottedLines) {
 	double dy = ymax - ymin;
 	if (dy < 16) {
-		long imin = (long) ceil ((ymin + 1.2) / 3.0), imax = (long) floor ((ymax - 1.2) / 3.0);
+		long imin = (long) ceil ((ymin + 1.2) / 3.0), imax = Melder_iroundDown ((ymax - 1.2) / 3.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 3.0, true, true, haveDottedLines, nullptr);
 	} else if (dy < 32) {
-		long imin = (long) ceil ((ymin + 2.4) / 6.0), imax = (long) floor ((ymax - 2.4) / 6.0);
+		long imin = (long) ceil ((ymin + 2.4) / 6.0), imax = Melder_iroundDown ((ymax - 2.4) / 6.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 6.0, true, true, haveDottedLines, nullptr);
 	} else if (dy < 64) {
-		long imin = (long) ceil ((ymin + 4.8) / 12.0), imax = (long) floor ((ymax - 4.8) / 12.0);
+		long imin = (long) ceil ((ymin + 4.8) / 12.0), imax = Melder_iroundDown ((ymax - 4.8) / 12.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 12.0, true, true, haveDottedLines, nullptr);
 	} else if (dy < 128) {
-		long imin = (long) ceil ((ymin + 9.6) / 24.0), imax = (long) floor ((ymax - 9.6) / 24.0);
+		long imin = (long) ceil ((ymin + 9.6) / 24.0), imax = Melder_iroundDown ((ymax - 9.6) / 24.0);
 		for (long i = imin; i <= imax; i ++)
 			Graphics_markLeft (g, i * 24.0, true, true, haveDottedLines, nullptr);
 	}
diff --git a/fon/TimeSoundEditor.cpp b/fon/TimeSoundEditor.cpp
index bc1d0d8..c29cc4d 100644
--- a/fon/TimeSoundEditor.cpp
+++ b/fon/TimeSoundEditor.cpp
@@ -194,7 +194,7 @@ 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;
-		integer nmargin = (integer) floor (margin / sound -> dx);
+		integer nmargin = Melder_iroundDown (margin / sound -> dx);
 		integer first, last, numberOfSamples = Sampled_getWindowSamples (sound,
 			my startSelection, my endSelection, & first, & last) + nmargin * 2;
 		first -= nmargin;
diff --git a/fon/Vector.cpp b/fon/Vector.cpp
index 95e5b20..d3791c4 100644
--- a/fon/Vector.cpp
+++ b/fon/Vector.cpp
@@ -41,7 +41,7 @@ double structVector :: v_getVector (integer irow, integer icol) {
 //
 double structVector :: v_getFunction1 (integer irow, double x) {
 	double rcol = (x - x1) / dx + 1.0;
-	integer icol = (integer) floor (rcol);
+	integer icol = Melder_iroundDown (rcol);
 	double dcol = rcol - icol;
 	double z1;
 	if (icol < 1 || icol > nx) {
diff --git a/fon/manual_Fon.cpp b/fon/manual_Fon.cpp
index eef55ad..d7ae889 100644
--- a/fon/manual_Fon.cpp
+++ b/fon/manual_Fon.cpp
@@ -1,6 +1,6 @@
 /* manual_Fon.cpp
  *
- * Copyright (C) 1992-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2008,2010,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
diff --git a/fon/manual_Manual.cpp b/fon/manual_Manual.cpp
index 0bb7394..2b72708 100644
--- a/fon/manual_Manual.cpp
+++ b/fon/manual_Manual.cpp
@@ -1,6 +1,6 @@
 /* manual_Manual.cpp
  *
- * Copyright (C) 1992-2011,2013,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2007,2010,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
diff --git a/fon/manual_Picture.cpp b/fon/manual_Picture.cpp
index b9ebcbe..e56b1b7 100644
--- a/fon/manual_Picture.cpp
+++ b/fon/manual_Picture.cpp
@@ -1,6 +1,6 @@
 /* manual_Picture.cpp
  *
- * Copyright (C) 1992-2011,2012,2013,2014,2015,2017 Paul Boersma
+ * Copyright (C) 1992-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
diff --git a/fon/manual_Sampling.cpp b/fon/manual_Sampling.cpp
index 32aa471..48aa423 100644
--- a/fon/manual_Sampling.cpp
+++ b/fon/manual_Sampling.cpp
@@ -1,6 +1,6 @@
 /* manual_Sampling.cpp
  *
- * Copyright (C) 1992-2010,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2005,2007,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
diff --git a/fon/manual_Script.cpp b/fon/manual_Script.cpp
index dc4cfee..289ad46 100644
--- a/fon/manual_Script.cpp
+++ b/fon/manual_Script.cpp
@@ -1,6 +1,6 @@
 /* manual_Script.cpp
  *
- * Copyright (C) 1992-2011,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1992-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
diff --git a/fon/manual_annotation.cpp b/fon/manual_annotation.cpp
index 019906f..49082ef 100644
--- a/fon/manual_annotation.cpp
+++ b/fon/manual_annotation.cpp
@@ -1,6 +1,6 @@
 /* manual_annotation.cpp
  *
- * Copyright (C) 1992-2011,2014,2015 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
diff --git a/fon/manual_exampleSound.cpp b/fon/manual_exampleSound.cpp
index dcff7f3..6bdf512 100644
--- a/fon/manual_exampleSound.cpp
+++ b/fon/manual_exampleSound.cpp
@@ -1,6 +1,6 @@
 /* manual_exampleSound.cpp
  *
- * Copyright (C) 2004-2011 Paul Boersma
+ * Copyright (C) 2004,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
diff --git a/fon/manual_exampleSound.h b/fon/manual_exampleSound.h
index edb82b9..55229e4 100644
--- a/fon/manual_exampleSound.h
+++ b/fon/manual_exampleSound.h
@@ -2,7 +2,7 @@
 #define _manual_exampleSound_h_
 /* manual_exampleSound.h
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-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
diff --git a/fon/manual_formant.cpp b/fon/manual_formant.cpp
index 5686e2e..d644cee 100644
--- a/fon/manual_formant.cpp
+++ b/fon/manual_formant.cpp
@@ -1,6 +1,6 @@
 /* manual_formant.cpp
  *
- * Copyright (C) 1992-2010,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2008,2010,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
diff --git a/fon/manual_glossary.cpp b/fon/manual_glossary.cpp
index 65cb0c7..431335e 100644
--- a/fon/manual_glossary.cpp
+++ b/fon/manual_glossary.cpp
@@ -1,6 +1,6 @@
 /* manual_glossary.cpp
  *
- * Copyright (C) 1992-2008,2014,2015,2017 Paul Boersma
+ * Copyright (C) 1992-2008,2010,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
diff --git a/fon/manual_pitch.cpp b/fon/manual_pitch.cpp
index f904ff2..8ffccf7 100644
--- a/fon/manual_pitch.cpp
+++ b/fon/manual_pitch.cpp
@@ -1,6 +1,6 @@
 /* manual_pitch.cpp
  *
- * Copyright (C) 1992-2010,2015,2017 Paul Boersma
+ * Copyright (C) 1992-2007,2010,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
diff --git a/fon/manual_programming.cpp b/fon/manual_programming.cpp
index 9a2b348..4250569 100644
--- a/fon/manual_programming.cpp
+++ b/fon/manual_programming.cpp
@@ -1,6 +1,6 @@
 /* manual_programming.cpp
  *
- * Copyright (C) 1992-2010,2015,2017 Paul Boersma
+ * Copyright (C) 1992-2010,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
diff --git a/fon/manual_references.cpp b/fon/manual_references.cpp
index 6678178..452cd0c 100644
--- a/fon/manual_references.cpp
+++ b/fon/manual_references.cpp
@@ -1,6 +1,6 @@
 /* manual_references.cpp
  *
- * Copyright (C) 1992-2010,2015 Paul Boersma
+ * Copyright (C) 1992-2008,2010,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
diff --git a/fon/manual_sound.cpp b/fon/manual_sound.cpp
index 40d4cbf..af87d1e 100644
--- a/fon/manual_sound.cpp
+++ b/fon/manual_sound.cpp
@@ -1,6 +1,6 @@
 /* manual_sound.cpp
  *
- * Copyright (C) 1992-2010,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2008,2010-2012,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
diff --git a/fon/manual_soundFiles.cpp b/fon/manual_soundFiles.cpp
index 2e405b1..ea056cb 100644
--- a/fon/manual_soundFiles.cpp
+++ b/fon/manual_soundFiles.cpp
@@ -1,6 +1,6 @@
 /* manual_soundFiles.cpp
  *
- * Copyright (C) 1992-2008,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2005,2007,2008,2010,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
diff --git a/fon/manual_spectrum.cpp b/fon/manual_spectrum.cpp
index f8b1b59..77beb45 100644
--- a/fon/manual_spectrum.cpp
+++ b/fon/manual_spectrum.cpp
@@ -1,6 +1,6 @@
 /* manual_spectrum.cpp
  *
- * Copyright (C) 1992-2010,2014,2015,2017 Paul Boersma
+ * Copyright (C) 1992-2008,2010,2012,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
diff --git a/fon/manual_tutorials.cpp b/fon/manual_tutorials.cpp
index ef63776..74e7025 100644
--- a/fon/manual_tutorials.cpp
+++ b/fon/manual_tutorials.cpp
@@ -1,6 +1,6 @@
 /* manual_tutorials.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1992-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,12 @@
 void manual_tutorials_init (ManPages me);
 void manual_tutorials_init (ManPages me) {
 
-MAN_BEGIN (U"What's new?", U"ppgb", 20171010)
+MAN_BEGIN (U"What's new?", U"ppgb", 20171016)
 INTRO (U"Latest changes in Praat.")
 //LIST_ITEM (U"• Manual page about @@drawing a vowel triangle at .")
 
+NORMAL (U"##6.0.35# (16 October 2017)")
+LIST_ITEM (U"• Fixed a bug introduced in 6.0.23 by which ##Remove right boundary# would sometimes incorrectly refuse.")
 NORMAL (U"##6.0.34# (10 October 2017)")
 LIST_ITEM (U"• Scripting: arrays in menu commands in scripts.")
 LIST_ITEM (U"• #Inspect: made a button visible that had disappeared in 6.0.33.")
@@ -64,7 +66,7 @@ NORMAL (U"##6.0.25# (11 February 2017)")
 LIST_ITEM (U"• Mac: made $$demoShow()$ and $$blankWhilePlaying$ compatible with MacOS 10.12 Sierra.")
 LIST_ITEM (U"• Mac SoundRecorder: more sampling frequencies, on behalf of external USB microphones.")
 NORMAL (U"##6.0.24# (23 January 2017)")
-LIST_ITEM (U"• Fixed a bug by which ##Remove right boundary# would choose the wrong tier.")
+LIST_ITEM (U"• Fixed a bug introduced in 6.0.23 by which ##Remove right boundary# would choose the wrong tier.")
 LIST_ITEM (U"• TextGrid window: click to insert a phonetic symbol from an IPA chart.")
 NORMAL (U"##6.0.23# (12 December 2016)")
 LIST_ITEM (U"• Linux: fixed a bug that caused Praat to crash when playing a sound of more than 7 channels.")
diff --git a/fon/manual_voice.cpp b/fon/manual_voice.cpp
index 9faf9b2..472ebb9 100644
--- a/fon/manual_voice.cpp
+++ b/fon/manual_voice.cpp
@@ -1,6 +1,6 @@
 /* manual_voice.cpp
  *
- * Copyright (C) 1992-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1992-2007,2010,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
diff --git a/fon/praat_TextGrid_init.cpp b/fon/praat_TextGrid_init.cpp
index 506d60e..ad226cd 100644
--- a/fon/praat_TextGrid_init.cpp
+++ b/fon/praat_TextGrid_init.cpp
@@ -1216,10 +1216,10 @@ DO
 		if (intervalTier -> classInfo != classIntervalTier)
 			Melder_throw (U"You cannot remove a boundary from tier ", tierNumber, U" of ", me,
 				U", because that tier is a point tier instead of an interval tier.");
-		if (tierNumber > intervalTier -> intervals.size)
+		if (intervalNumber > intervalTier -> intervals.size)
 			Melder_throw (U"You cannot remove a boundary from interval ", intervalNumber, U" of tier ", tierNumber, U" of ", me,
 				U", because that tier has only ", intervalTier -> intervals.size, U" intervals.");
-		if (tierNumber == intervalTier -> intervals.size)
+		if (intervalNumber == intervalTier -> intervals.size)
 			Melder_throw (U"You cannot remove the right boundary from interval ", intervalNumber, U" of tier ", tierNumber, U" of ", me,
 				U", because this is at the right edge of the tier.");
 		IntervalTier_removeLeftBoundary (intervalTier, intervalNumber + 1);
diff --git a/gram/DeepBeliefNetwork.cpp b/gram/DeepBeliefNetwork.cpp
new file mode 100644
index 0000000..20c8e4d
--- /dev/null
+++ b/gram/DeepBeliefNetwork.cpp
@@ -0,0 +1,208 @@
+/* DeepBeliefNetwork.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 <OpenCL/OpenCL.h>
+#include "DeepBeliefNetwork.h"
+#include "tensor.h"
+
+#include "oo_DESTROY.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_COPY.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_EQUAL.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_CAN_WRITE_AS_ENCODING.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_WRITE_TEXT.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_READ_TEXT.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_WRITE_BINARY.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_READ_BINARY.h"
+#include "DeepBeliefNetwork_def.h"
+#include "oo_DESCRIPTION.h"
+#include "DeepBeliefNetwork_def.h"
+
+#include "enums_getText.h"
+#include "DeepBeliefNetwork_enums.h"
+#include "enums_getValue.h"
+#include "DeepBeliefNetwork_enums.h"
+
+Thing_implement (DeepBeliefNetwork, Daata, 0);
+
+void DeepBeliefNetwork_init (DeepBeliefNetwork me, numvec numbersOfNodes, bool inputsAreBinary) {
+	if (numbersOfNodes.size < 2)
+		Melder_throw (U"A DeepBeliefNetwork should have at least two levels of nodes.");
+	integer numberOfLayers = numbersOfNodes.size - 1;
+	for (integer ilayer = 1; ilayer <= numberOfLayers; ilayer ++) {
+		autoRBM layer = RBM_create (
+			Melder_iround_tieUp (numbersOfNodes [ilayer]),
+			Melder_iround_tieUp (numbersOfNodes [ilayer + 1]),
+			ilayer == 1 ? inputsAreBinary : true
+		);
+		my layers. addItem_move (layer.move());
+	}
+}
+
+autoDeepBeliefNetwork DeepBeliefNetwork_create (numvec numbersOfNodes, bool inputsAreBinary) {
+	try {
+		autoDeepBeliefNetwork me = Thing_new (DeepBeliefNetwork);
+		DeepBeliefNetwork_init (me.get(), numbersOfNodes, inputsAreBinary);
+		return me;
+	} catch (MelderError) {
+		Melder_throw (U"DeepBeliefNetwork not created.");
+	}
+}
+
+static void copyOutputsToInputs (RBM me, RBM you) {
+	Melder_assert (my numberOfOutputNodes == your numberOfInputNodes);
+	for (integer inode = 1; inode <= my numberOfOutputNodes; inode ++) {
+		your inputActivities [inode] = my outputActivities [inode];
+	}
+}
+
+void DeepBeliefNetwork_spreadUp (DeepBeliefNetwork me, kDeepBeliefNetwork_activationType activationType) {
+	for (integer ilayer = 1; ilayer <= my layers.size; ilayer ++) {
+		RBM layer = my layers.at [ilayer];
+		if (ilayer > 1)
+			copyOutputsToInputs (my layers.at [ilayer - 1], layer);
+		RBM_spreadUp (layer);
+		if (activationType == kDeepBeliefNetwork_activationType::STOCHASTIC)
+			RBM_sampleOutput (layer);
+	}
+}
+
+void DeepBeliefNetwork_sampleInput (DeepBeliefNetwork me) {
+	RBM_sampleInput (my layers.at [1]);
+}
+
+void DeepBeliefNetwork_sampleOutput (DeepBeliefNetwork me) {
+	RBM_sampleOutput (my layers.at [my layers.size]);
+}
+
+static void copyInputsToOutputs (RBM me, RBM you) {
+	Melder_assert (my numberOfInputNodes == your numberOfOutputNodes);
+	for (integer inode = 1; inode <= my numberOfInputNodes; inode ++) {
+		your outputActivities [inode] = my inputActivities [inode];
+	}
+}
+
+void DeepBeliefNetwork_spreadDown (DeepBeliefNetwork me, kDeepBeliefNetwork_activationType activationType) {
+	for (integer ilayer = my layers.size; ilayer > 0; ilayer --) {
+		RBM layer = my layers.at [ilayer];
+		if (ilayer < my layers.size)
+			copyInputsToOutputs (my layers.at [ilayer + 1], layer);
+		RBM_spreadDown (layer);
+		if (activationType == kDeepBeliefNetwork_activationType::STOCHASTIC)
+			RBM_sampleInput (layer);
+	}
+}
+
+void DeepBeliefNetwork_spreadDown_reconstruction (DeepBeliefNetwork me) {
+	for (integer ilayer = my layers.size; ilayer > 0; ilayer --) {
+		RBM_spreadDown_reconstruction (my layers.at [ilayer]);
+	}
+}
+
+void DeepBeliefNetwork_spreadUp_reconstruction (DeepBeliefNetwork me) {
+	for (integer ilayer = 1; ilayer <= my layers.size; ilayer ++) {
+		RBM_spreadUp_reconstruction (my layers.at [ilayer]);
+	}
+}
+
+void DeepBeliefNetwork_update (DeepBeliefNetwork me, double learningRate) {
+	for (integer ilayer = 1; ilayer <= my layers.size; ilayer ++) {
+		RBM_update (my layers.at [ilayer], learningRate);
+	}
+}
+
+void DeepBeliefNetwork_PatternList_applyToInput (DeepBeliefNetwork me, PatternList thee, integer rowNumber) {
+	RBM_PatternList_applyToInput (my layers.at [1], thee, rowNumber);
+}
+
+void DeepBeliefNetwork_PatternList_applyToOutput (DeepBeliefNetwork me, PatternList thee, integer rowNumber) {
+	RBM_PatternList_applyToOutput (my layers.at [my layers.size], thee, rowNumber);
+}
+
+void DeepBeliefNetwork_PatternList_learn (DeepBeliefNetwork me, PatternList thee, double learningRate) {
+	for (integer ipattern = 1; ipattern <= thy ny; ipattern ++) {
+		DeepBeliefNetwork_PatternList_applyToInput (me, thee, ipattern);
+		DeepBeliefNetwork_spreadUp (me, kDeepBeliefNetwork_activationType::STOCHASTIC);
+		for (integer ilayer = 1; ilayer <= my layers.size; ilayer ++) {
+			RBM layer = my layers.at [ilayer];
+			RBM_spreadDown_reconstruction (layer);
+			RBM_spreadUp_reconstruction (layer);
+			RBM_update (layer, learningRate);
+		}
+	}
+}
+
+void DeepBeliefNetwork_PatternList_learnByLayer (DeepBeliefNetwork me, PatternList thee, double learningRate) {
+	for (integer ilayer = 1; ilayer <= my layers.size; ilayer ++) {
+		RBM layer = my layers.at [ilayer];
+		for (integer ipattern = 1; ipattern <= thy ny; ipattern ++) {
+			RBM_PatternList_applyToInput (my layers.at [1], thee, ipattern);
+			RBM_spreadUp (my layers.at [1]);
+			RBM_sampleOutput (my layers.at [1]);
+			for (integer jlayer = 2; jlayer <= ilayer; jlayer ++) {
+				copyOutputsToInputs (my layers.at [jlayer - 1], my layers.at [jlayer]);
+				RBM_spreadUp (my layers.at [jlayer]);
+				RBM_sampleOutput (my layers.at [jlayer]);
+			}
+			RBM_spreadDown_reconstruction (layer);
+			RBM_spreadUp_reconstruction (layer);
+			RBM_update (layer, learningRate);
+		}
+	}
+}
+
+autoMatrix DeepBeliefNetwork_extractInputActivities (DeepBeliefNetwork me) {
+	return RBM_extractInputActivities (my layers.at [1]);
+}
+
+autoMatrix DeepBeliefNetwork_extractOutputActivities (DeepBeliefNetwork me) {
+	return RBM_extractOutputActivities (my layers.at [my layers.size]);
+}
+
+autoMatrix DeepBeliefNetwork_extractInputReconstruction (DeepBeliefNetwork me) {
+	return RBM_extractInputReconstruction (my layers.at [1]);
+}
+
+autoMatrix DeepBeliefNetwork_extractOutputReconstruction (DeepBeliefNetwork me) {
+	return RBM_extractOutputReconstruction (my layers.at [my layers.size]);
+}
+
+autoMatrix DeepBeliefNetwork_extractInputBiases (DeepBeliefNetwork me, integer layerNumber) {
+	return RBM_extractInputBiases (my layers.at [layerNumber]);
+}
+
+autoMatrix DeepBeliefNetwork_extractOutputBiases (DeepBeliefNetwork me, integer layerNumber) {
+	return RBM_extractOutputBiases (my layers.at [layerNumber]);
+}
+
+autoMatrix DeepBeliefNetwork_extractWeights (DeepBeliefNetwork me, integer layerNumber) {
+	return RBM_extractWeights (my layers.at [layerNumber]);
+}
+
+autonummat DeepBeliefNetwork_getWeights_nummat (DeepBeliefNetwork me, integer layerNumber) {
+	RBM layer = my layers.at [layerNumber];
+	return copy_nummat ({ layer -> weights, layer -> numberOfInputNodes, layer -> numberOfOutputNodes });
+}
+
+/* End of file DeepBeliefNetwork.cpp */
diff --git a/gram/DeepBeliefNetwork.h b/gram/DeepBeliefNetwork.h
new file mode 100644
index 0000000..efe7541
--- /dev/null
+++ b/gram/DeepBeliefNetwork.h
@@ -0,0 +1,59 @@
+#ifndef _DeepBeliefNetwork_h_
+#define _DeepBeliefNetwork_h_
+/* DeepBeliefNetwork.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 "RBM.h"
+#include "Table.h"
+#include "PatternList.h"
+
+#include "DeepBeliefNetwork_enums.h"
+#include "DeepBeliefNetwork_def.h"
+
+void DeepBeliefNetwork_init (DeepBeliefNetwork me, numvec numbersOfNodes, bool inputsAreBinary);
+
+autoDeepBeliefNetwork DeepBeliefNetwork_create (numvec numbersOfNodes, bool inputsAreBinary);
+
+void DeepBeliefNetwork_addLayer (DeepBeliefNetwork me, integer numberOfOutputNodes);
+
+void DeepBeliefNetwork_spreadUp (DeepBeliefNetwork me, kDeepBeliefNetwork_activationType activationType);
+void DeepBeliefNetwork_spreadDown (DeepBeliefNetwork me, kDeepBeliefNetwork_activationType activationType);
+void DeepBeliefNetwork_spreadDown_reconstruction (DeepBeliefNetwork me);
+void DeepBeliefNetwork_spreadUp_reconstruction (DeepBeliefNetwork me);
+void DeepBeliefNetwork_sampleInput (DeepBeliefNetwork me);
+void DeepBeliefNetwork_sampleOutput (DeepBeliefNetwork me);
+void DeepBeliefNetwork_update (DeepBeliefNetwork me, double learningRate);
+
+void DeepBeliefNetwork_PatternList_applyToInput (DeepBeliefNetwork me, PatternList thee, integer rowNumber);
+void DeepBeliefNetwork_PatternList_applyToOutput (DeepBeliefNetwork me, PatternList thee, integer rowNumber);
+void DeepBeliefNetwork_PatternList_learn (DeepBeliefNetwork me, PatternList thee, double learningRate);
+void DeepBeliefNetwork_PatternList_learnByLayer (DeepBeliefNetwork me, PatternList thee, double learningRate);
+
+autoMatrix DeepBeliefNetwork_extractInputActivities (DeepBeliefNetwork me);
+autoMatrix DeepBeliefNetwork_extractOutputActivities (DeepBeliefNetwork me);
+autoMatrix DeepBeliefNetwork_extractInputReconstruction (DeepBeliefNetwork me);
+autoMatrix DeepBeliefNetwork_extractOutputReconstruction (DeepBeliefNetwork me);
+
+autoMatrix DeepBeliefNetwork_extractInputBiases (DeepBeliefNetwork me, integer layerNumber);
+autoMatrix DeepBeliefNetwork_extractOutputBiases (DeepBeliefNetwork me, integer layerNumber);
+autoMatrix DeepBeliefNetwork_extractWeights (DeepBeliefNetwork me, integer layerNumber);
+
+autonummat DeepBeliefNetwork_getWeights_nummat (DeepBeliefNetwork me, integer layerNumber);
+
+/* End of file DeepBeliefNetwork.h */
+#endif
diff --git a/fon/manual_exampleSound.h b/gram/DeepBeliefNetwork_def.h
similarity index 69%
copy from fon/manual_exampleSound.h
copy to gram/DeepBeliefNetwork_def.h
index edb82b9..8c4371a 100644
--- a/fon/manual_exampleSound.h
+++ b/gram/DeepBeliefNetwork_def.h
@@ -1,8 +1,6 @@
-#ifndef _manual_exampleSound_h_
-#define _manual_exampleSound_h_
-/* manual_exampleSound.h
+/* DeepBeliefNetwork_def.h
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * 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
@@ -18,11 +16,14 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Sound.h"
-#include "Pitch.h"
 
-Sound manual_exampleSound ();
-Pitch manual_examplePitch ();
+#define ooSTRUCT DeepBeliefNetwork
+oo_DEFINE_CLASS (DeepBeliefNetwork, Daata)
 
-/* End of file manual_exampleSound.h */
-#endif
+	oo_COLLECTION_OF (OrderedOf, layers, RBM, 0)
+
+oo_END_CLASS (DeepBeliefNetwork)
+#undef ooSTRUCT
+
+
+/* End of file DeepBeliefNetwork_def.h */
diff --git a/fon/manual_exampleSound.h b/gram/DeepBeliefNetwork_enums.h
similarity index 62%
copy from fon/manual_exampleSound.h
copy to gram/DeepBeliefNetwork_enums.h
index edb82b9..f6dfeb8 100644
--- a/fon/manual_exampleSound.h
+++ b/gram/DeepBeliefNetwork_enums.h
@@ -1,8 +1,6 @@
-#ifndef _manual_exampleSound_h_
-#define _manual_exampleSound_h_
-/* manual_exampleSound.h
+/* DeepBeliefNetwork_enums.h
  *
- * Copyright (C) 1992-2011 Paul Boersma
+ * 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
@@ -18,11 +16,9 @@
  * along with this work. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "Sound.h"
-#include "Pitch.h"
+enums_begin (kDeepBeliefNetwork_activationType, 0)
+	enums_add (kDeepBeliefNetwork_activationType, 0, DETERMINISTIC, U"deterministic")
+	enums_add (kDeepBeliefNetwork_activationType, 1, STOCHASTIC, U"stochastic")
+enums_end (kDeepBeliefNetwork_activationType, 1, DETERMINISTIC)
 
-Sound manual_exampleSound ();
-Pitch manual_examplePitch ();
-
-/* End of file manual_exampleSound.h */
-#endif
+/* End of file DeepBeliefNetwork_enums.h */
diff --git a/gram/Makefile b/gram/Makefile
index 58e45ec..7671d70 100644
--- a/gram/Makefile
+++ b/gram/Makefile
@@ -1,27 +1,27 @@
-# Makefile of the library "gram"
-# Paul Boersma, 8 August 2017
-
-include ../makefile.defs
-
-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 \
-   OTGrammar_ex_metrics.o OTGrammar_ex_NoCoda.o OTGrammar_ex_NPA.o OTGrammar_ex_tongueRoot.o \
-   OTMulti_ex_metrics.o RBM.o
-
-.PHONY: all clean
-
-all: libgram.a
-
-clean:
-	$(RM) $(OBJECTS)
-	$(RM) libgram.a
-
-libgram.a: $(OBJECTS)
-	touch libgram.a
-	rm libgram.a
-	$(AR) cq libgram.a $(OBJECTS)
-	$(RANLIB) libgram.a
-
-$(OBJECTS): *.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
+# Makefile of the library "gram"
+# Paul Boersma 2017-10-16
+
+include ../makefile.defs
+
+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 \
+   OTGrammar_ex_metrics.o OTGrammar_ex_NoCoda.o OTGrammar_ex_NPA.o OTGrammar_ex_tongueRoot.o \
+   OTMulti_ex_metrics.o RBM.o DeepBeliefNetwork.o
+
+.PHONY: all clean
+
+all: libgram.a
+
+clean:
+	$(RM) $(OBJECTS)
+	$(RM) libgram.a
+
+libgram.a: $(OBJECTS)
+	touch libgram.a
+	rm libgram.a
+	$(AR) cq libgram.a $(OBJECTS)
+	$(RANLIB) libgram.a
+
+$(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 53a6a9f..82f7f3f 100644
--- a/gram/Network.cpp
+++ b/gram/Network.cpp
@@ -1,6 +1,6 @@
 /* Network.cpp
  *
- * Copyright (C) 2009-2012,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 2009,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
@@ -74,7 +74,7 @@ Thing_implement (Network, Daata, 6);
 void Network_init (Network me, double spreadingRate, kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	double xmin, double xmax, double ymin, double ymax, long numberOfNodes, long numberOfConnections)
+	double xmin, double xmax, double ymin, double ymax, integer numberOfNodes, integer numberOfConnections)
 {
 	my spreadingRate = spreadingRate;
 	my activityClippingRule = activityClippingRule;
@@ -100,7 +100,7 @@ void Network_init (Network me, double spreadingRate, kNetwork_activityClippingRu
 autoNetwork Network_create (double spreadingRate, kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	double xmin, double xmax, double ymin, double ymax, long numberOfNodes, long numberOfConnections)
+	double xmin, double xmax, double ymin, double ymax, integer numberOfNodes, integer numberOfConnections)
 {
 	try {
 		autoNetwork me = Thing_new (Network);
@@ -113,7 +113,7 @@ autoNetwork Network_create (double spreadingRate, kNetwork_activityClippingRule
 	}
 }
 
-double Network_getActivity (Network me, long nodeNumber) {
+double Network_getActivity (Network me, integer nodeNumber) {
 	try {
 		if (nodeNumber <= 0 || nodeNumber > my numberOfNodes)
 			Melder_throw (me, U": node number (", nodeNumber, U") out of the range 1..", my numberOfNodes, U".");
@@ -123,7 +123,7 @@ double Network_getActivity (Network me, long nodeNumber) {
 	}
 }
 
-void Network_setActivity (Network me, long nodeNumber, double activity) {
+void Network_setActivity (Network me, integer nodeNumber, double activity) {
 	try {
 		if (nodeNumber <= 0 || nodeNumber > my numberOfNodes)
 			Melder_throw (me, U": node number (", nodeNumber, U") out of the range 1..", my numberOfNodes, U".");
@@ -133,7 +133,7 @@ void Network_setActivity (Network me, long nodeNumber, double activity) {
 	}
 }
 
-double Network_getWeight (Network me, long connectionNumber) {
+double Network_getWeight (Network me, integer connectionNumber) {
 	try {
 		if (connectionNumber <= 0 || connectionNumber > my numberOfConnections)
 			Melder_throw (me, U": connection number (", connectionNumber, U") out of the range 1..", my numberOfConnections, U".");
@@ -143,7 +143,7 @@ double Network_getWeight (Network me, long connectionNumber) {
 	}
 }
 
-void Network_setWeight (Network me, long connectionNumber, double weight) {
+void Network_setWeight (Network me, integer connectionNumber, double weight) {
 	try {
 		if (connectionNumber <= 0 || connectionNumber > my numberOfConnections)
 			Melder_throw (me, U": connection number (", connectionNumber, U") out of the range 1..", my numberOfConnections, U".");
@@ -153,7 +153,7 @@ void Network_setWeight (Network me, long connectionNumber, double weight) {
 	}
 }
 
-void Network_setClamping (Network me, long nodeNumber, bool clamped) {
+void Network_setClamping (Network me, integer nodeNumber, bool clamped) {
 	try {
 		if (nodeNumber <= 0 || nodeNumber > my numberOfNodes)
 			Melder_throw (me, U": node number (", nodeNumber, U") out of the range 1..", my numberOfNodes, U".");
@@ -163,14 +163,14 @@ void Network_setClamping (Network me, long nodeNumber, bool clamped) {
 	}
 }
 
-void Network_spreadActivities (Network me, long numberOfSteps) {
-	for (long istep = 1; istep <= numberOfSteps; istep ++) {
-		for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+void Network_spreadActivities (Network me, integer numberOfSteps) {
+	for (integer istep = 1; istep <= numberOfSteps; istep ++) {
+		for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 			NetworkNode node = & my nodes [inode];
 			if (! node -> clamped)
 				node -> excitation -= my spreadingRate * my activityLeak * node -> excitation;
 		}
-		for (long iconn = 1; iconn <= my numberOfConnections; iconn ++) {
+		for (integer iconn = 1; iconn <= my numberOfConnections; iconn ++) {
 			NetworkConnection connection = & my connections [iconn];
 			NetworkNode nodeFrom = & my nodes [connection -> nodeFrom];
 			NetworkNode nodeTo = & my nodes [connection -> nodeTo];
@@ -180,7 +180,7 @@ void Network_spreadActivities (Network me, long numberOfSteps) {
 			if (! nodeTo -> clamped)
 				nodeTo -> excitation += my spreadingRate * nodeFrom -> activity * (my connections [iconn]. weight - shunting * nodeTo -> excitation);
 		}
-		for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+		for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 			NetworkNode node = & my nodes [inode];
 			if (! node -> clamped) {
 				switch (my activityClippingRule) {
@@ -212,34 +212,34 @@ void Network_spreadActivities (Network me, long numberOfSteps) {
 	}
 }
 
-void Network_zeroActivities (Network me, long nodeMin, long nodeMax) {
+void Network_zeroActivities (Network me, integer nodeMin, integer nodeMax) {
 	if (my numberOfNodes < 1) return;
 	if (nodeMax == 0) { nodeMin = 1; nodeMax = my numberOfNodes; }
 	if (nodeMin < 1) nodeMin = 1;
 	if (nodeMax > my numberOfNodes) nodeMax = my numberOfNodes;
-	for (long inode = nodeMin; inode <= nodeMax; inode ++) {
+	for (integer inode = nodeMin; inode <= nodeMax; inode ++) {
 		my nodes [inode]. activity = my nodes [inode]. excitation = 0.0;
 	}
 }
 
-void Network_normalizeActivities (Network me, long nodeMin, long nodeMax) {
+void Network_normalizeActivities (Network me, integer nodeMin, integer nodeMax) {
 	if (my numberOfNodes < 1) return;
 	if (nodeMax == 0) { nodeMin = 1; nodeMax = my numberOfNodes; }
 	if (nodeMin < 1) nodeMin = 1;
 	if (nodeMax > my numberOfNodes) nodeMax = my numberOfNodes;
 	if (nodeMax < nodeMin) return;
-	double sum = 0.0;
-	for (long inode = nodeMin; inode <= nodeMax; inode ++) {
+	real80 sum = 0.0;
+	for (integer inode = nodeMin; inode <= nodeMax; inode ++) {
 		sum += my nodes [inode]. activity;
 	}
-	double average = sum / (nodeMax - nodeMin + 1);
-	for (long inode = nodeMin; inode <= nodeMax; inode ++) {
+	double average = (real) sum / (nodeMax - nodeMin + 1);
+	for (integer inode = nodeMin; inode <= nodeMax; inode ++) {
 		my nodes [inode]. activity -= average;
 	}	
 }
 
 void Network_updateWeights (Network me) {
-	for (long iconn = 1; iconn <= my numberOfConnections; iconn ++) {
+	for (integer iconn = 1; iconn <= my numberOfConnections; iconn ++) {
 		NetworkConnection connection = & my connections [iconn];
 		NetworkNode nodeFrom = & my nodes [connection -> nodeFrom];
 		NetworkNode nodeTo = & my nodes [connection -> nodeTo];
@@ -250,23 +250,23 @@ void Network_updateWeights (Network me) {
 	}
 }
 
-void Network_normalizeWeights (Network me, long nodeMin, long nodeMax, long nodeFromMin, long nodeFromMax, double newSum) {
+void Network_normalizeWeights (Network me, integer nodeMin, integer nodeMax, integer nodeFromMin, integer nodeFromMax, double newSum) {
 	if (my numberOfNodes < 1) return;
 	if (nodeMax == 0) { nodeMin = 1; nodeMax = my numberOfNodes; }
 	if (nodeMin < 1) nodeMin = 1;
 	if (nodeMax > my numberOfNodes) nodeMax = my numberOfNodes;
 	if (nodeMax < nodeMin) return;
-	for (long inode = nodeMin; inode <= nodeMax; inode ++) {
-		double sum = 0.0;
-		for (long iconn = 1; iconn <= my numberOfConnections; iconn ++) {
+	for (integer inode = nodeMin; inode <= nodeMax; inode ++) {
+		real80 sum = 0.0;
+		for (integer iconn = 1; iconn <= my numberOfConnections; iconn ++) {
 			NetworkConnection connection = & my connections [iconn];
 			if (connection -> nodeTo == inode && connection -> nodeFrom >= nodeFromMin && connection -> nodeFrom <= nodeFromMax) {
 				sum += connection -> weight;
 			}
 		}
 		if (sum != 0.0) {
-			double factor = newSum / sum;
-			for (long iconn = 1; iconn <= my numberOfConnections; iconn ++) {
+			double factor = newSum / (real) sum;
+			for (integer iconn = 1; iconn <= my numberOfConnections; iconn ++) {
 				NetworkConnection connection = & my connections [iconn];
 				if (connection -> nodeTo == inode && connection -> nodeFrom >= nodeFromMin && connection -> nodeFrom <= nodeFromMax) {
 					connection -> weight *= factor;
@@ -279,7 +279,7 @@ void Network_normalizeWeights (Network me, long nodeMin, long nodeMax, long node
 autoNetwork Network_create_rectangle (double spreadingRate, enum kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	long numberOfRows, long numberOfColumns, bool bottomRowClamped,
+	integer numberOfRows, integer numberOfColumns, bool bottomRowClamped,
 	double initialMinimumWeight, double initialMaximumWeight)
 {
 	try {
@@ -290,7 +290,7 @@ autoNetwork Network_create_rectangle (double spreadingRate, enum kNetwork_activi
 		/*
 		 * Define nodes.
 		 */
-		for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+		for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 			NetworkNode node = & my nodes [inode];
 			node -> x = (inode - 1) % numberOfColumns + 0.5;
 			node -> y = (inode - 1) / numberOfColumns + 0.5;
@@ -300,9 +300,9 @@ autoNetwork Network_create_rectangle (double spreadingRate, enum kNetwork_activi
 		/*
 		 * Define connections.
 		 */
-		long iconn = 0;
-		for (long irow = 1; irow <= numberOfRows; irow ++) {
-			for (long icol = 1; icol <= numberOfColumns - 1; icol ++) {
+		integer iconn = 0;
+		for (integer irow = 1; irow <= numberOfRows; irow ++) {
+			for (integer icol = 1; icol <= numberOfColumns - 1; icol ++) {
 				NetworkConnection conn = & my connections [++ iconn];
 				conn -> nodeFrom = (irow - 1) * numberOfColumns + icol;
 				conn -> nodeTo = conn -> nodeFrom + 1;
@@ -310,8 +310,8 @@ autoNetwork Network_create_rectangle (double spreadingRate, enum kNetwork_activi
 				conn -> plasticity = 1.0;
 			}
 		}
-		for (long irow = 1; irow <= numberOfRows - 1; irow ++) {
-			for (long icol = 1; icol <= numberOfColumns; icol ++) {
+		for (integer irow = 1; irow <= numberOfRows - 1; irow ++) {
+			for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 				NetworkConnection conn = & my connections [++ iconn];
 				conn -> nodeFrom = (irow - 1) * numberOfColumns + icol;
 				conn -> nodeTo = conn -> nodeFrom + numberOfColumns;
@@ -329,7 +329,7 @@ autoNetwork Network_create_rectangle (double spreadingRate, enum kNetwork_activi
 autoNetwork Network_create_rectangle_vertical (double spreadingRate, enum kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	long numberOfRows, long numberOfColumns, bool bottomRowClamped,
+	integer numberOfRows, integer numberOfColumns, bool bottomRowClamped,
 	double initialMinimumWeight, double initialMaximumWeight)
 {
 	try {
@@ -340,7 +340,7 @@ autoNetwork Network_create_rectangle_vertical (double spreadingRate, enum kNetwo
 		/*
 		 * Define nodes.
 		 */
-		for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+		for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 			NetworkNode node = & my nodes [inode];
 			node -> x = (inode - 1) % numberOfColumns + 0.5;
 			node -> y = (inode - 1) / numberOfColumns + 0.5;
@@ -350,10 +350,10 @@ autoNetwork Network_create_rectangle_vertical (double spreadingRate, enum kNetwo
 		/*
 		 * Define connections.
 		 */
-		long iconn = 0;
-		for (long icol = 1; icol <= numberOfColumns; icol ++) {
-			for (long jcol = 1; jcol <= numberOfColumns; jcol ++) {
-				for (long irow = 1; irow <= numberOfRows - 1; irow ++) {
+		integer iconn = 0;
+		for (integer icol = 1; icol <= numberOfColumns; icol ++) {
+			for (integer jcol = 1; jcol <= numberOfColumns; jcol ++) {
+				for (integer irow = 1; irow <= numberOfRows - 1; irow ++) {
 					NetworkConnection conn = & my connections [++ iconn];
 					conn -> nodeFrom = (irow - 1) * numberOfColumns + icol;
 					conn -> nodeTo = irow * numberOfColumns + jcol;
@@ -380,7 +380,7 @@ void Network_draw (Network me, Graphics graphics, bool useColour) {
 	/*
 	 * Draw connections.
 	 */
-	for (long iconn = 1; iconn <= my numberOfConnections; iconn ++) {
+	for (integer iconn = 1; iconn <= my numberOfConnections; iconn ++) {
 		NetworkConnection conn = & my connections [iconn];
 		if (fabs (conn -> weight) >= 0.01) {
 			NetworkNode nodeFrom = & my nodes [conn -> nodeFrom];
@@ -394,7 +394,7 @@ void Network_draw (Network me, Graphics graphics, bool useColour) {
 	/*
 	 * Draw the backgrounds of the nodes.
 	 */
-	for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+	for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 		NetworkNode node = & my nodes [inode];
 		Graphics_setColour (graphics, useColour ? Graphics_SILVER : Graphics_WHITE);
 		Graphics_fillCircle_mm (graphics, node -> x, node -> y, 5.0);
@@ -404,7 +404,7 @@ void Network_draw (Network me, Graphics graphics, bool useColour) {
 	 */
 	Graphics_setColour (graphics, Graphics_BLACK);
 	Graphics_setLineWidth (graphics, 2.0);
-	for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+	for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 		NetworkNode node = & my nodes [inode];
 		Graphics_setLineType (graphics, node -> clamped ? Graphics_DRAWN : Graphics_DOTTED);
 		Graphics_circle_mm (graphics, node -> x, node -> y, 5.2);
@@ -412,7 +412,7 @@ void Network_draw (Network me, Graphics graphics, bool useColour) {
 	/*
 	 * Draw the activities of the nodes.
 	 */
-	for (long inode = 1; inode <= my numberOfNodes; inode ++) {
+	for (integer inode = 1; inode <= my numberOfNodes; inode ++) {
 		NetworkNode node = & my nodes [inode];
 		double activity = fabs (node -> activity);
 		if (activity >= 1.0) activity = sqrt (activity);
@@ -444,7 +444,7 @@ 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) {
+void Network_addConnection (Network me, integer nodeFrom, integer nodeTo, double weight, double plasticity) {
 	try {
 		integer numberOfConnections = my numberOfConnections;
 		NUMvector_append (& my connections, 1, & numberOfConnections);
@@ -485,7 +485,7 @@ void Network_setActivityClippingRule (Network me, enum kNetwork_activityClipping
 	Network_zeroActivities (me, 0, 0);
 }
 
-autoTable Network_nodes_downto_Table (Network me, long fromNodeNumber, long toNodeNumber,
+autoTable Network_nodes_downto_Table (Network me, integer fromNodeNumber, integer toNodeNumber,
 	bool includeNodeNumbers,
 	bool includeX, bool includeY, int positionDecimals,
 	bool includeClamped,
@@ -496,18 +496,18 @@ autoTable Network_nodes_downto_Table (Network me, long fromNodeNumber, long toNo
 		if (toNodeNumber > my numberOfNodes) toNodeNumber = my numberOfNodes;
 		if (fromNodeNumber > toNodeNumber)
 			fromNodeNumber = 1, toNodeNumber = my numberOfNodes;
-		long numberOfNodes = toNodeNumber - fromNodeNumber + 1;
+		integer numberOfNodes = toNodeNumber - fromNodeNumber + 1;
 		Melder_assert (numberOfNodes >= 1);
 		autoTable thee = Table_createWithoutColumnNames (numberOfNodes,
 			includeNodeNumbers + includeX + includeY + includeClamped + includeActivity + includeExcitation);
-		long icol = 0;
+		integer icol = 0;
 		if (includeNodeNumbers) Table_setColumnLabel (thee.get(), ++ icol, U"node");
 		if (includeX)           Table_setColumnLabel (thee.get(), ++ icol, U"x");
 		if (includeY)           Table_setColumnLabel (thee.get(), ++ icol, U"y");
 		if (includeClamped)     Table_setColumnLabel (thee.get(), ++ icol, U"clamped");
 		if (includeActivity)    Table_setColumnLabel (thee.get(), ++ icol, U"activity");
 		if (includeExcitation)  Table_setColumnLabel (thee.get(), ++ icol, U"excitation");
-		for (long inode = fromNodeNumber; inode <= toNodeNumber; inode ++) {
+		for (integer inode = fromNodeNumber; inode <= toNodeNumber; inode ++) {
 			NetworkNode node = & my nodes [inode];
 			icol = 0;
 			if (includeNodeNumbers) Table_setNumericValue (thee.get(), inode, ++ icol, inode);
@@ -523,7 +523,7 @@ autoTable Network_nodes_downto_Table (Network me, long fromNodeNumber, long toNo
 	}
 }
 
-void Network_listNodes (Network me, long fromNodeNumber, long toNodeNumber,
+void Network_listNodes (Network me, integer fromNodeNumber, integer toNodeNumber,
 	bool includeNodeNumbers,
 	bool includeX, bool includeY, int positionDecimals,
 	bool includeClamped,
diff --git a/gram/Network.h b/gram/Network.h
index c999e61..f4e4281 100644
--- a/gram/Network.h
+++ b/gram/Network.h
@@ -2,7 +2,7 @@
 #define _Network_h_
 /* Network.h
  *
- * Copyright (C) 2009-2012,2013,2014,2017 Paul Boersma
+ * Copyright (C) 2009,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
@@ -28,50 +28,50 @@ void Network_init (Network me,
 	double spreadingRate, kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	double xmin, double xmax, double ymin, double ymax, long numberOfNodes, long numberOfConnections);
+	double xmin, double xmax, double ymin, double ymax, integer numberOfNodes, integer numberOfConnections);
 
 autoNetwork Network_create (double spreadingRate, enum kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	double xmin, double xmax, double ymin, double ymax, long numberOfNodes, long numberOfConnections);
+	double xmin, double xmax, double ymin, double ymax, integer numberOfNodes, integer numberOfConnections);
 
 autoNetwork Network_create_rectangle (double spreadingRate, enum kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	long numberOfRows, long numberOfColumns, bool bottomRowClamped,
+	integer numberOfRows, integer numberOfColumns, bool bottomRowClamped,
 	double initialMinimumWeight, double initialMaximumWeight);
 
 autoNetwork Network_create_rectangle_vertical (double spreadingRate, enum kNetwork_activityClippingRule activityClippingRule,
 	double minimumActivity, double maximumActivity, double activityLeak,
 	double learningRate, double minimumWeight, double maximumWeight, double weightLeak,
-	long numberOfRows, long numberOfColumns, bool bottomRowClamped,
+	integer numberOfRows, integer numberOfColumns, bool bottomRowClamped,
 	double initialMinimumWeight, double initialMaximumWeight);
 
 void Network_addNode (Network me, double x, double y, double activity, bool clamped);
-void Network_addConnection (Network me, long fromNodeNumber, long toNodeNumber, double weight, double plasticity);
+void Network_addConnection (Network me, integer fromNodeNumber, integer toNodeNumber, double weight, double plasticity);
 void Network_draw (Network me, Graphics graphics, bool colour);
-double Network_getActivity (Network me, long nodeNumber);
-void Network_setActivity (Network me, long nodeNumber, double activity);
-double Network_getWeight (Network me, long connectionNumber);
-void Network_setWeight (Network me, long connectionNumber, double weight);
-void Network_setClamping (Network me, long nodeNumber, bool clamped);
-void Network_zeroActivities (Network me, long fromNodeNumber, long toNodeNumber);
-void Network_normalizeActivities (Network me, long fromNodeNumber, long toNodeNumber);
-void Network_spreadActivities (Network me, long numberOfSteps);
+double Network_getActivity (Network me, integer nodeNumber);
+void Network_setActivity (Network me, integer nodeNumber, double activity);
+double Network_getWeight (Network me, integer connectionNumber);
+void Network_setWeight (Network me, integer connectionNumber, double weight);
+void Network_setClamping (Network me, integer nodeNumber, bool clamped);
+void Network_zeroActivities (Network me, integer fromNodeNumber, integer toNodeNumber);
+void Network_normalizeActivities (Network me, integer fromNodeNumber, integer toNodeNumber);
+void Network_spreadActivities (Network me, integer numberOfSteps);
 void Network_updateWeights (Network me);
-void Network_normalizeWeights (Network me, long nodeMin, long nodeMax, long nodeFromMin, long nodeFromMax, double newSum);
+void Network_normalizeWeights (Network me, integer nodeMin, integer nodeMax, integer nodeFromMin, integer nodeFromMax, double newSum);
 void Network_setInstar (Network me, double instar);
 void Network_setOutstar (Network me, double outstar);
 void Network_setWeightLeak (Network me, double weightLeak);
 void Network_setActivityLeak (Network me, double activityLeak);
 void Network_setShunting (Network me, double shunting);
 void Network_setActivityClippingRule (Network me, enum kNetwork_activityClippingRule activityClippingRule);
-autoTable Network_nodes_downto_Table (Network me, long fromNodeNumber, long toNodeNumber,
+autoTable Network_nodes_downto_Table (Network me, integer fromNodeNumber, integer toNodeNumber,
 	bool includeNodeNumbers,
 	bool includeX, bool includeY, int positionDecimals,
 	bool includeClamped,
 	bool includeActivity, bool includeExcitation, int activityDecimals);
-void Network_listNodes (Network me, long fromNodeNumber, long toNodeNumber,
+void Network_listNodes (Network me, integer fromNodeNumber, integer toNodeNumber,
 	bool includeNodeNumbers,
 	bool includeX, bool includeY, int positionDecimals,
 	bool includeClamped,
diff --git a/gram/Network_def.h b/gram/Network_def.h
index 5365ed0..518b9c7 100644
--- a/gram/Network_def.h
+++ b/gram/Network_def.h
@@ -1,6 +1,6 @@
 /* Network_def.h
  *
- * Copyright (C) 2009-2011,2012,2013,2014,2015 Paul Boersma
+ * Copyright (C) 2009-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
diff --git a/gram/Network_enums.h b/gram/Network_enums.h
index 05cf03f..b0b1cff 100644
--- a/gram/Network_enums.h
+++ b/gram/Network_enums.h
@@ -1,6 +1,6 @@
 /* Network_enums.h
  *
- * Copyright (C) 2012,2015,2017 Paul Boersma
+ * Copyright (C) 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
diff --git a/gram/OTGrammar.cpp b/gram/OTGrammar.cpp
index aa2825f..4c26577 100644
--- a/gram/OTGrammar.cpp
+++ b/gram/OTGrammar.cpp
@@ -1,6 +1,6 @@
 /* OTGrammar.cpp
  *
- * Copyright (C) 1997-2012,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1997-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
@@ -97,11 +97,11 @@
 void structOTGrammar :: v_info ()
 {
 	structDaata :: v_info ();
-	long numberOfCandidates = 0, numberOfViolations = 0;
-	for (long itab = 1; itab <= numberOfTableaus; itab ++) {
+	integer numberOfCandidates = 0, numberOfViolations = 0;
+	for (integer itab = 1; itab <= numberOfTableaus; itab ++) {
 		numberOfCandidates += tableaus [itab]. numberOfCandidates;
-		for (long icand = 1; icand <= tableaus [itab]. numberOfCandidates; icand ++)
-			for (long icons = 1; icons <= numberOfConstraints; icons ++)
+		for (integer icand = 1; icand <= tableaus [itab]. numberOfCandidates; icand ++)
+			for (integer icons = 1; icons <= numberOfConstraints; icons ++)
 				numberOfViolations += tableaus [itab]. candidates [icand]. marks [icons];
 	}
 	MelderInfo_writeLine (U"Decision strategy: ", kOTGrammar_decisionStrategy_getText (decisionStrategy));
@@ -114,7 +114,7 @@ void structOTGrammar :: v_info ()
 void structOTGrammar :: v_writeText (MelderFile file) {
 	MelderFile_write (file, U"\n<", kOTGrammar_decisionStrategy_getText (decisionStrategy),
 		U">\n", leak, U" ! leak\n", numberOfConstraints, U" constraints");
-	for (long icons = 1; icons <= numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & constraints [icons];
 		MelderFile_write (file, U"\nconstraint [", icons, U"]: \"");
 		for (const char32 *p = & constraint -> name [0]; *p; p ++) {
@@ -131,12 +131,12 @@ void structOTGrammar :: v_writeText (MelderFile file) {
 		}
 	}
 	MelderFile_write (file, U"\n\n", numberOfFixedRankings, U" fixed rankings");
-	for (long irank = 1; irank <= numberOfFixedRankings; irank ++) {
+	for (integer irank = 1; irank <= numberOfFixedRankings; irank ++) {
 		OTGrammarFixedRanking fixedRanking = & fixedRankings [irank];
 		MelderFile_write (file, U"\n   ", fixedRanking -> higher, U" ", fixedRanking -> lower);
 	}
 	MelderFile_write (file, U"\n\n", numberOfTableaus, U" tableaus");
-	for (long itab = 1; itab <= numberOfTableaus; itab ++) {
+	for (integer itab = 1; itab <= numberOfTableaus; itab ++) {
 		OTGrammarTableau tableau = & tableaus [itab];
 		MelderFile_write (file, U"\ninput [", itab, U"]: \"");
 		for (const char32 *p = & tableau -> input [0]; *p; p ++) {
@@ -144,7 +144,7 @@ void structOTGrammar :: v_writeText (MelderFile file) {
 			MelderFile_writeCharacter (file, *p);
 		}
 		MelderFile_write (file, U"\" ", tableau -> numberOfCandidates);
-		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 			OTGrammarCandidate candidate = & tableau -> candidates [icand];
 			MelderFile_write (file, U"\n   candidate [", icand, U"]: \"");
 			for (const char32 *p = & candidate -> output [0]; *p; p ++) {
@@ -152,7 +152,7 @@ void structOTGrammar :: v_writeText (MelderFile file) {
 				MelderFile_writeCharacter (file, *p);
 			}
 			MelderFile_writeCharacter (file, U'\"');
-			for (long icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
 				MelderFile_write (file, U" ", candidate -> marks [icons]);
 			}
 		}
@@ -189,7 +189,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 	}
 	if (numberOfConstraints < 1) Melder_throw (U"No constraints.");
 	constraints = NUMvector <structOTGrammarConstraint> (1, numberOfConstraints);
-	for (long icons = 1; icons <= numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & constraints [icons];
 		try {
 			constraint -> name = texgetw16 (text);
@@ -223,7 +223,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 	}
 	if (numberOfFixedRankings >= 1) {
 		fixedRankings = NUMvector <structOTGrammarFixedRanking> (1, numberOfFixedRankings);
-		for (long irank = 1; irank <= numberOfFixedRankings; irank ++) {
+		for (integer irank = 1; irank <= numberOfFixedRankings; irank ++) {
 			OTGrammarFixedRanking fixedRanking = & fixedRankings [irank];
 			try {
 				fixedRanking -> higher = texgeti32 (text);
@@ -244,7 +244,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 	}
 	if (numberOfTableaus < 1) Melder_throw (U"No tableaus.");
 	tableaus = NUMvector <structOTGrammarTableau> (1, numberOfTableaus);
-	for (long itab = 1; itab <= numberOfTableaus; itab ++) {
+	for (integer itab = 1; itab <= numberOfTableaus; itab ++) {
 		OTGrammarTableau tableau = & tableaus [itab];
 		try {
 			tableau -> input = texgetw16 (text);
@@ -264,7 +264,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 			 itab == 1 ? nullptr : tableaus [itab - 1]. input,
 			 itab == 1 ? nullptr : U_RIGHT_GUILLEMET U".");
 		tableau -> candidates = NUMvector <structOTGrammarCandidate> (1, tableau -> numberOfCandidates);
-		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 			OTGrammarCandidate candidate = & tableau -> candidates [icand];
 			try {
 				candidate -> output = texgetw16 (text);
@@ -274,7 +274,7 @@ void structOTGrammar :: v_readText (MelderReadText text, int formatVersion) {
 			}
 			candidate -> numberOfConstraints = numberOfConstraints;   // redundancy, needed for writing binary
 			candidate -> marks = NUMvector <int> (1, candidate -> numberOfConstraints);
-			for (long icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
 				try {
 					candidate -> marks [icons] = texgeti16 (text);
 				} catch (MelderError) {
@@ -317,7 +317,7 @@ static int constraintCompare (const void *first, const void *second) {
 void OTGrammar_sort (OTGrammar me) {
 	constraintCompare_grammar = me;
 	qsort (& my index [1], my numberOfConstraints, sizeof (integer), constraintCompare);
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [my index [icons]];
 		constraint -> tiedToTheLeft = icons > 1 &&
 			my constraints [my index [icons - 1]]. disharmony == constraint -> disharmony;
@@ -327,7 +327,7 @@ void OTGrammar_sort (OTGrammar me) {
 }
 
 void OTGrammar_newDisharmonies (OTGrammar me, double spreading) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [icons];
 		constraint -> disharmony = constraint -> ranking + NUMrandomGauss (0, spreading)
 			/*NUMrandomUniform (-spreading, spreading)*/;
@@ -335,41 +335,41 @@ void OTGrammar_newDisharmonies (OTGrammar me, double spreading) {
 	OTGrammar_sort (me);
 }
 
-long OTGrammar_getTableau (OTGrammar me, const char32 *input) {
-	long n = my numberOfTableaus;
-	for (long i = 1; i <= n; i ++)
+integer OTGrammar_getTableau (OTGrammar me, const char32 *input) {
+	integer n = my numberOfTableaus;
+	for (integer i = 1; i <= n; i ++)
 		if (str32equ (my tableaus [i]. input, input))
 			return i;
 	Melder_throw (U"Input \"", input, U"\" not in list of tableaus.");
 }
 
-static void _OTGrammar_fillInHarmonies (OTGrammar me, long itab) noexcept {
+static void _OTGrammar_fillInHarmonies (OTGrammar me, integer itab) noexcept {
 	if (my decisionStrategy == kOTGrammar_decisionStrategy::OPTIMALITY_THEORY) return;
 	OTGrammarTableau tableau = & my tableaus [itab];
-	for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 		OTGrammarCandidate candidate = & tableau -> candidates [icand];
 		int *marks = candidate -> marks;
 		double disharmony = 0.0;
 		if (my decisionStrategy == kOTGrammar_decisionStrategy::HARMONIC_GRAMMAR ||
 			my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY)
 		{
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				disharmony += my constraints [icons]. disharmony * marks [icons];
 			}
 		} else if (my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG ||
 			my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
 		{
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				disharmony += exp (my constraints [icons]. disharmony) * marks [icons];
 			}
 		} else if (my decisionStrategy == kOTGrammar_decisionStrategy::LINEAR_OT) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				if (my constraints [icons]. disharmony > 0.0) {
 					disharmony += my constraints [icons]. disharmony * marks [icons];
 				}
 			}
 		} else if (my decisionStrategy == kOTGrammar_decisionStrategy::POSITIVE_HG) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				double constraintDisharmony = my constraints [icons]. disharmony > 1.0 ? my constraints [icons]. disharmony : 1.0;
 				disharmony += constraintDisharmony * marks [icons];
 			}
@@ -380,11 +380,11 @@ static void _OTGrammar_fillInHarmonies (OTGrammar me, long itab) noexcept {
 	}
 }
 
-int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long itab2, long icand2) noexcept {
+int OTGrammar_compareCandidates (OTGrammar me, integer itab1, integer icand1, integer itab2, integer icand2) noexcept {
 	int *marks1 = my tableaus [itab1]. candidates [icand1]. marks;
 	int *marks2 = my tableaus [itab2]. candidates [icand2]. marks;
 	if (my decisionStrategy == kOTGrammar_decisionStrategy::OPTIMALITY_THEORY) {
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int numberOfMarks1 = marks1 [my index [icons]];
 			int numberOfMarks2 = marks2 [my index [icons]];
 			/*
@@ -404,7 +404,7 @@ int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long ita
 		my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY)
 	{
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			disharmony1 += my constraints [icons]. disharmony * marks1 [icons];
 			disharmony2 += my constraints [icons]. disharmony * marks2 [icons];
 		}
@@ -412,7 +412,7 @@ int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long ita
 		if (disharmony1 > disharmony2) return +1;   // candidate 2 is better than candidate 1
 	} else if (my decisionStrategy == kOTGrammar_decisionStrategy::LINEAR_OT) {
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			if (my constraints [icons]. disharmony > 0.0) {
 				disharmony1 += my constraints [icons]. disharmony * marks1 [icons];
 				disharmony2 += my constraints [icons]. disharmony * marks2 [icons];
@@ -424,7 +424,7 @@ int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long ita
 		my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
 	{
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			disharmony1 += exp (my constraints [icons]. disharmony) * marks1 [icons];
 			disharmony2 += exp (my constraints [icons]. disharmony) * marks2 [icons];
 		}
@@ -432,7 +432,7 @@ int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long ita
 		if (disharmony1 > disharmony2) return +1;   // candidate 2 is better than candidate 1
 	} else if (my decisionStrategy == kOTGrammar_decisionStrategy::POSITIVE_HG) {
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			double constraintDisharmony = my constraints [icons]. disharmony > 1.0 ? my constraints [icons]. disharmony : 1.0;
 			disharmony1 += constraintDisharmony * marks1 [icons];
 			disharmony2 += constraintDisharmony * marks2 [icons];
@@ -443,34 +443,34 @@ int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long ita
 	return 0;   // the two total disharmonies are equal
 }
 
-static void _OTGrammar_fillInProbabilities (OTGrammar me, long itab) noexcept {
+static void _OTGrammar_fillInProbabilities (OTGrammar me, integer itab) noexcept {
 	OTGrammarTableau tableau = & my tableaus [itab];
 	double maximumHarmony = tableau -> candidates [1]. harmony;
-	for (long icand = 2; icand <= tableau -> numberOfCandidates; icand ++) {
+	for (integer icand = 2; icand <= tableau -> numberOfCandidates; icand ++) {
 		OTGrammarCandidate candidate = & tableau -> candidates [icand];
 		if (candidate -> harmony > maximumHarmony) {
 			maximumHarmony = candidate -> harmony;
 		}
 	}
-	for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 		OTGrammarCandidate candidate = & tableau -> candidates [icand];
 		candidate -> probability = exp (candidate -> harmony - maximumHarmony);
 		Melder_assert (candidate -> probability >= 0.0 && candidate -> probability <= 1.0);
 	}
 	double sumOfProbabilities = 0.0;
-	for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 		OTGrammarCandidate candidate = & tableau -> candidates [icand];
 		sumOfProbabilities += candidate -> probability;
 	}
 	Melder_assert (sumOfProbabilities > 0.0);   // because at least one of them is 1.0
-	for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 		OTGrammarCandidate candidate = & tableau -> candidates [icand];
 		candidate -> probability /= sumOfProbabilities;
 	}
 }
 
-long OTGrammar_getWinner (OTGrammar me, long itab) noexcept {
-	long icand_best = 1;
+integer OTGrammar_getWinner (OTGrammar me, integer itab) noexcept {
+	integer icand_best = 1;
 	if (my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY ||
 		my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
 	{
@@ -478,7 +478,7 @@ long OTGrammar_getWinner (OTGrammar me, long itab) noexcept {
 		_OTGrammar_fillInProbabilities (me, itab);
 		double cutOff = NUMrandomUniform (0.0, 1.0);
 		double sumOfProbabilities = 0.0;
-		for (long icand = 1; icand <= my tableaus [itab]. numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= my tableaus [itab]. numberOfCandidates; icand ++) {
 			sumOfProbabilities += my tableaus [itab]. candidates [icand]. probability;
 			if (sumOfProbabilities > cutOff) {
 				icand_best = icand;
@@ -486,8 +486,8 @@ long OTGrammar_getWinner (OTGrammar me, long itab) noexcept {
 			}
 		}
 	} else {
-		long numberOfBestCandidates = 1;
-		for (long icand = 2; icand <= my tableaus [itab]. numberOfCandidates; icand ++) {
+		integer numberOfBestCandidates = 1;
+		for (integer icand = 2; icand <= my tableaus [itab]. numberOfCandidates; icand ++) {
 			int comparison = OTGrammar_compareCandidates (me, itab, icand, itab, icand_best);
 			if (comparison == -1) {
 				icand_best = icand;   // the current candidate is the unique best candidate found so far
@@ -510,10 +510,10 @@ long OTGrammar_getWinner (OTGrammar me, long itab) noexcept {
 	return icand_best;
 }
 
-long OTGrammar_getNumberOfOptimalCandidates (OTGrammar me, long itab) {
+integer OTGrammar_getNumberOfOptimalCandidates (OTGrammar me, integer itab) {
 	if (my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY ||
 		my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY) return 1;
-	long icand_best = 1, icand, numberOfBestCandidates = 1;
+	integer icand_best = 1, icand, numberOfBestCandidates = 1;
 	for (icand = 2; icand <= my tableaus [itab]. numberOfCandidates; icand ++) {
 		int comparison = OTGrammar_compareCandidates (me, itab, icand, itab, icand_best);
 		if (comparison == -1) {
@@ -526,28 +526,28 @@ long OTGrammar_getNumberOfOptimalCandidates (OTGrammar me, long itab) {
 	return numberOfBestCandidates;
 }
 
-bool OTGrammar_isCandidateGrammatical (OTGrammar me, long itab, long icand) {
-	for (long jcand = 1; jcand <= my tableaus [itab]. numberOfCandidates; jcand ++) {
+bool OTGrammar_isCandidateGrammatical (OTGrammar me, integer itab, integer icand) {
+	for (integer jcand = 1; jcand <= my tableaus [itab]. numberOfCandidates; jcand ++) {
 		if (jcand != icand && OTGrammar_compareCandidates (me, itab, jcand, itab, icand) < 0)
 			return false;
 	}
 	return true;
 }
 
-bool OTGrammar_isCandidateSinglyGrammatical (OTGrammar me, long itab, long icand) {
-	for (long jcand = 1; jcand <= my tableaus [itab]. numberOfCandidates; jcand ++) {
+bool OTGrammar_isCandidateSinglyGrammatical (OTGrammar me, integer itab, integer icand) {
+	for (integer jcand = 1; jcand <= my tableaus [itab]. numberOfCandidates; jcand ++) {
 		if (jcand != icand && OTGrammar_compareCandidates (me, itab, jcand, itab, icand) <= 0)
 			return false;
 	}
 	return true;
 }
 
-void OTGrammar_getInterpretiveParse (OTGrammar me, const char32 *partialOutput, long *bestTableau, long *bestCandidate) {
+void OTGrammar_getInterpretiveParse (OTGrammar me, const char32 *partialOutput, integer *bestTableau, integer *bestCandidate) {
 	try {
-		long itab_best = 0, icand_best = 0, numberOfBestCandidates = 0;
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		integer itab_best = 0, icand_best = 0, numberOfBestCandidates = 0;
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				OTGrammarCandidate cand = & tableau -> candidates [icand];
 				if (str32str (cand -> output, partialOutput)) {   // T&S' idea of surface->overt mapping
 					if (itab_best == 0) {
@@ -588,12 +588,12 @@ void OTGrammar_getInterpretiveParse (OTGrammar me, const char32 *partialOutput,
 	}
 }
 
-static void OTGrammar_getInterpretiveParse_opt (OTGrammar me, long ipartialOutput, long *bestTableau, long *bestCandidate) {
+static void OTGrammar_getInterpretiveParse_opt (OTGrammar me, integer ipartialOutput, integer *bestTableau, integer *bestCandidate) {
 	try {
-		long itab_best = 0, icand_best = 0, numberOfBestCandidates = 0;
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		integer itab_best = 0, icand_best = 0, numberOfBestCandidates = 0;
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				OTGrammarCandidate cand = & tableau -> candidates [icand];
 				Melder_assert (cand -> partialOutputMatches);
 				if (cand -> partialOutputMatches [ipartialOutput]) {   // T&S' idea of surface->overt mapping
@@ -636,9 +636,9 @@ static void OTGrammar_getInterpretiveParse_opt (OTGrammar me, long ipartialOutpu
 }
 
 bool OTGrammar_isPartialOutputGrammatical (OTGrammar me, const char32 *partialOutput) {
-	for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+	for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 		OTGrammarTableau tableau = & my tableaus [itab];
-		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 			if (str32str (tableau -> candidates [icand]. output, partialOutput)) {
 				if (OTGrammar_isCandidateGrammatical (me, itab, icand)) {
 					return true;
@@ -650,7 +650,7 @@ bool OTGrammar_isPartialOutputGrammatical (OTGrammar me, const char32 *partialOu
 }
 
 bool OTGrammar_areAllPartialOutputsGrammatical (OTGrammar me, Strings thee) {
-	for (long ioutput = 1; ioutput <= thy numberOfStrings; ioutput ++) {
+	for (integer ioutput = 1; ioutput <= thy numberOfStrings; ioutput ++) {
 		const char32 *partialOutput = thy strings [ioutput];
 		if (! OTGrammar_isPartialOutputGrammatical (me, partialOutput)) {
 			return false;
@@ -661,16 +661,16 @@ bool OTGrammar_areAllPartialOutputsGrammatical (OTGrammar me, Strings thee) {
 
 bool OTGrammar_isPartialOutputSinglyGrammatical (OTGrammar me, const char32 *partialOutput) {
 	bool found = false;
-	for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+	for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 		OTGrammarTableau tableau = & my tableaus [itab];
-		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 			if (str32str (tableau -> candidates [icand]. output, partialOutput)) {
 				if (OTGrammar_isCandidateGrammatical (me, itab, icand)) {
 					found = true;
 					/*
 					 * All other grammatical candidates should match.
 					 */
-					for (long jcand = 1; jcand <= tableau -> numberOfCandidates; jcand ++) {
+					for (integer jcand = 1; jcand <= tableau -> numberOfCandidates; jcand ++) {
 						if (OTGrammar_compareCandidates (me, itab, jcand, itab, icand) == 0) {
 							if (! str32str (tableau -> candidates [jcand]. output, partialOutput)) {
 								return false;   // partial output is multiply optimal
@@ -685,7 +685,7 @@ bool OTGrammar_isPartialOutputSinglyGrammatical (OTGrammar me, const char32 *par
 }
 
 bool OTGrammar_areAllPartialOutputsSinglyGrammatical (OTGrammar me, Strings thee) {
-	for (long ioutput = 1; ioutput <= thy numberOfStrings; ioutput ++) {
+	for (integer ioutput = 1; ioutput <= thy numberOfStrings; ioutput ++) {
 		const char32 *partialOutput = thy strings [ioutput];
 		if (! OTGrammar_isPartialOutputSinglyGrammatical (me, partialOutput)) {
 			return false;
@@ -694,7 +694,7 @@ bool OTGrammar_areAllPartialOutputsSinglyGrammatical (OTGrammar me, Strings thee
 	return true;
 }
 
-static int OTGrammar_crucialCell (OTGrammar me, long itab, long icand, long iwinner, long numberOfOptimalCandidates) {
+static int OTGrammar_crucialCell (OTGrammar me, integer itab, integer icand, integer iwinner, integer numberOfOptimalCandidates) {
 	int icons;
 	OTGrammarTableau tableau = & my tableaus [itab];
 	if (tableau -> numberOfCandidates < 2) return 0;   // if there is only one candidate, all cells can be greyed
@@ -703,7 +703,7 @@ static int OTGrammar_crucialCell (OTGrammar me, long itab, long icand, long iwin
 		if (numberOfOptimalCandidates > 1) {
 			/* All cells are important. */
 		} else {
-			long jcand, secondBest = 0;
+			integer jcand, secondBest = 0;
 			for (jcand = 1; jcand <= tableau -> numberOfCandidates; jcand ++) {
 				if (OTGrammar_compareCandidates (me, itab, jcand, itab, iwinner) != 0) {   // a non-optimal candidate?
 					if (secondBest == 0) {
@@ -753,9 +753,9 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 	try {
 		double x, y, fontSize = Graphics_inqFontSize (g);
 		Graphics_Colour colour = Graphics_inqColour (g);
-		const long itab = OTGrammar_getTableau (me, input);
+		const integer itab = OTGrammar_getTableau (me, input);
 		_OTGrammar_fillInHarmonies (me, itab);
-		const long winner = OTGrammar_getWinner (me, itab);
+		const integer winner = OTGrammar_getWinner (me, itab);
 		
 		Graphics_setWindow (g, 0.0, 1.0, 0.0, 1.0);
 		const double margin = Graphics_dxMMtoWC (g, 1.0);
@@ -771,7 +771,7 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 		double headerHeight;
 		if (vertical) {
 			headerHeight = 0.0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				double constraintTextWidth = Graphics_textWidth (g, constraint -> name);
 				if (constraintTextWidth > headerHeight)
@@ -781,7 +781,7 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 			headerHeight *= worldAspectRatio;
 		} else {
 			headerHeight = rowHeight;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				if (str32chr (constraint -> name, U'\n')) {
 					headerHeight *= 1.6;
@@ -795,8 +795,8 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 		 */
 		double candWidth = Graphics_textWidth (g, input);
 		OTGrammarTableau tableau = & my tableaus [itab];
-		long numberOfOptimalCandidates = 0;
-		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+		integer numberOfOptimalCandidates = 0;
+		for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 			double width = Graphics_textWidth (g, tableau -> candidates [icand]. output);
 			if (OTGrammar_compareCandidates (me, itab, icand, itab, winner) == 0) {
 				width += fingerWidth;
@@ -812,7 +812,7 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 		if (vertical) {
 			tableauWidth += rowHeight * my numberOfConstraints / worldAspectRatio;
 		} else {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				tableauWidth += OTGrammar_constraintWidth (g, constraint -> name);
 			}
@@ -837,7 +837,7 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 		 */
 		x += candWidth + doubleLineDx;
 		if (vertical) Graphics_setTextRotation (g, 90.0);
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTGrammarConstraint constraint = & my constraints [my index [icons]];
 			double width = vertical ? rowHeight / worldAspectRatio : OTGrammar_constraintWidth (g, constraint -> name) + margin * 2;
 			if (str32chr (constraint -> name, U'\n') && ! vertical) {
@@ -868,8 +868,8 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 		 * Draw candidates.
 		 */
 		y -= doubleLineDy;
-		for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
-			long crucialCell = OTGrammar_crucialCell (me, itab, icand, winner, numberOfOptimalCandidates);
+		for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			integer crucialCell = OTGrammar_crucialCell (me, itab, icand, winner, numberOfOptimalCandidates);
 			bool candidateIsOptimal = OTGrammar_compareCandidates (me, itab, icand, itab, winner) == 0;
 			/*
 			 * Draw candidate transcription.
@@ -892,7 +892,7 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 			 */
 			x = candWidth + 2 * doubleLineDx;
 			Graphics_setGrey (g, 0.9);
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int index = my index [icons];
 				OTGrammarConstraint constraint = & my constraints [index];
 				double width = vertical ? rowHeight / worldAspectRatio : OTGrammar_constraintWidth (g, constraint -> name) + margin * 2;
@@ -906,7 +906,7 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 			 */
 			x = candWidth + 2 * doubleLineDx;
 			Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int index = my index [icons];
 				OTGrammarConstraint constraint = & my constraints [index];
 				double width = vertical ? rowHeight / worldAspectRatio : OTGrammar_constraintWidth (g, constraint -> name) + margin * 2;
@@ -921,12 +921,12 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 					 */
 					if (icons == crucialCell && ! candidateIsOptimal && ! constraint -> tiedToTheLeft && ! constraint -> tiedToTheRight) {
 						int winnerMarks = tableau -> candidates [winner]. marks [index];
-						for (long imark = 1; imark <= winnerMarks + 1; imark ++)
+						for (integer imark = 1; imark <= winnerMarks + 1; imark ++)
 							MelderString_appendCharacter (& markString, U'*');
-						for (long imark = tableau -> candidates [icand]. marks [index]; imark < 0; imark ++)
+						for (integer imark = tableau -> candidates [icand]. marks [index]; imark < 0; imark ++)
 							MelderString_appendCharacter (& markString, U'+');
 						MelderString_appendCharacter (& markString, U'!');
-						for (long imark = winnerMarks + 2; imark <= tableau -> candidates [icand]. marks [index]; imark ++)
+						for (integer imark = winnerMarks + 2; imark <= tableau -> candidates [icand]. marks [index]; imark ++)
 							MelderString_appendCharacter (& markString, U'*');
 					} else {
 						if (! candidateIsOptimal && (constraint -> tiedToTheLeft || constraint -> tiedToTheRight) &&
@@ -934,15 +934,15 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 						{
 							Graphics_setColour (g, Graphics_RED);
 						}
-						for (long imark = 1; imark <= tableau -> candidates [icand]. marks [index]; imark ++)
+						for (integer imark = 1; imark <= tableau -> candidates [icand]. marks [index]; imark ++)
 							MelderString_appendCharacter (& markString, U'*');
-						for (long imark = tableau -> candidates [icand]. marks [index]; imark < 0; imark ++)
+						for (integer imark = tableau -> candidates [icand]. marks [index]; imark < 0; imark ++)
 							MelderString_appendCharacter (& markString, U'+');
 					}
 				} else {
-					for (long imark = 1; imark <= tableau -> candidates [icand]. marks [index]; imark ++)
+					for (integer imark = 1; imark <= tableau -> candidates [icand]. marks [index]; imark ++)
 						MelderString_appendCharacter (& markString, U'*');
-					for (long imark = tableau -> candidates [icand]. marks [index]; imark < 0; imark ++)
+					for (integer imark = tableau -> candidates [icand]. marks [index]; imark < 0; imark ++)
 						MelderString_appendCharacter (& markString, U'+');
 				}
 				Graphics_text (g, x + 0.5 * width, y + descent, markString.string);
@@ -982,12 +982,12 @@ void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char3
 	}
 }
 
-autoStrings OTGrammar_generateInputs (OTGrammar me, long numberOfTrials) {
+autoStrings OTGrammar_generateInputs (OTGrammar me, integer numberOfTrials) {
 	try {
 		autoStrings thee = Thing_new (Strings);
 		thy strings = NUMvector <char32 *> (1, thy numberOfStrings = numberOfTrials);
-		for (long i = 1; i <= numberOfTrials; i ++) {
-			long itab = NUMrandomInteger (1, my numberOfTableaus);
+		for (integer i = 1; i <= numberOfTrials; i ++) {
+			integer itab = NUMrandomInteger (1, my numberOfTableaus);
 			thy strings [i] = Melder_dup (my tableaus [itab]. input);
 		}
 		return thee;
@@ -1000,7 +1000,7 @@ autoStrings OTGrammar_getInputs (OTGrammar me) {
 	try {
 		autoStrings thee = Thing_new (Strings);
 		thy strings = NUMvector <char32 *> (1, thy numberOfStrings = my numberOfTableaus);
-		for (long i = 1; i <= my numberOfTableaus; i ++) {
+		for (integer i = 1; i <= my numberOfTableaus; i ++) {
 			thy strings [i] = Melder_dup (my tableaus [i]. input);
 		}
 		return thee;
@@ -1012,8 +1012,8 @@ autoStrings OTGrammar_getInputs (OTGrammar me) {
 void OTGrammar_inputToOutput (OTGrammar me, const char32 *input, char32 *output, double evaluationNoise) {
 	try {
 		OTGrammar_newDisharmonies (me, evaluationNoise);
-		long itab = OTGrammar_getTableau (me, input);
-		long winner = OTGrammar_getWinner (me, itab);
+		integer itab = OTGrammar_getTableau (me, input);
+		integer winner = OTGrammar_getWinner (me, itab);
 		if (winner == 0)
 			Melder_throw (U"No winner");
 		str32cpy (output, my tableaus [itab]. candidates [winner]. output);
@@ -1025,10 +1025,10 @@ void OTGrammar_inputToOutput (OTGrammar me, const char32 *input, char32 *output,
 autoStrings OTGrammar_inputsToOutputs (OTGrammar me, Strings inputs, double evaluationNoise) {
 	try {
 		autoStrings him = Thing_new (Strings);
-		long n = inputs -> numberOfStrings;
+		integer n = inputs -> numberOfStrings;
 		his numberOfStrings = n;
 		his strings = NUMvector <char32 *> (1, n);
-		for (long i = 1; i <= n; i ++) {
+		for (integer i = 1; i <= n; i ++) {
 			char32 output [100];
 			OTGrammar_inputToOutput (me, inputs -> strings [i], output, evaluationNoise);
 			his strings [i] = Melder_dup (output);
@@ -1039,12 +1039,12 @@ autoStrings OTGrammar_inputsToOutputs (OTGrammar me, Strings inputs, double eval
 	}
 }
 
-autoStrings OTGrammar_inputToOutputs (OTGrammar me, const char32 *input, long n, double evaluationNoise) {
+autoStrings OTGrammar_inputToOutputs (OTGrammar me, const char32 *input, integer n, double evaluationNoise) {
 	try {
 		autoStrings thee = Thing_new (Strings);
 		thy numberOfStrings = n;
 		thy strings = NUMvector <char32 *> (1, n);
-		for (long i = 1; i <= n; i ++) {
+		for (integer i = 1; i <= n; i ++) {
 			char32 output [100];
 			OTGrammar_inputToOutput (me, input, output, evaluationNoise);
 			thy strings [i] = Melder_dup (output);
@@ -1055,13 +1055,13 @@ autoStrings OTGrammar_inputToOutputs (OTGrammar me, const char32 *input, long n,
 	}
 }
 
-autoDistributions OTGrammar_to_Distribution (OTGrammar me, long trialsPerInput, double noise) {
+autoDistributions OTGrammar_to_Distribution (OTGrammar me, integer trialsPerInput, double noise) {
 	try {
-		long totalNumberOfOutputs = 0, nout = 0;
+		integer totalNumberOfOutputs = 0, nout = 0;
 		/*
 		 * Count the total number of outputs.
 		 */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++)
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++)
 			totalNumberOfOutputs += my tableaus [itab]. numberOfCandidates;
 		/*
 		 * Create the distribution. One row for every output form.
@@ -1071,21 +1071,21 @@ autoDistributions OTGrammar_to_Distribution (OTGrammar me, long trialsPerInput,
 		 * Measure every input form.
 		 */
 		autoMelderProgress progress (U"OTGrammar: compute output distribution.");
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
 			Melder_progress ((itab - 0.5) / my numberOfTableaus, U"Measuring input \"", tableau -> input, U"\"");
 			/*
 			 * Set the row labels to the output strings.
 			 */
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				thy rowLabels [nout + icand] = Melder_dup (Melder_cat (tableau -> input, U" \\-> ", tableau -> candidates [icand]. output));
 			}
 			/*
 			 * Compute a number of outputs and store the results.
 			 */
-			for (long itrial = 1; itrial <= trialsPerInput; itrial ++) {
+			for (integer itrial = 1; itrial <= trialsPerInput; itrial ++) {
 				OTGrammar_newDisharmonies (me, noise);
-				long iwinner = OTGrammar_getWinner (me, itab);
+				integer iwinner = OTGrammar_getWinner (me, itab);
 				thy data [nout + iwinner] [1] += 1;
 			}
 			/*
@@ -1099,13 +1099,13 @@ autoDistributions OTGrammar_to_Distribution (OTGrammar me, long trialsPerInput,
 	}
 }
 
-autoPairDistribution OTGrammar_to_PairDistribution (OTGrammar me, long trialsPerInput, double noise) {
+autoPairDistribution OTGrammar_to_PairDistribution (OTGrammar me, integer trialsPerInput, double noise) {
 	try {
-		long totalNumberOfOutputs = 0, nout = 0;
+		integer totalNumberOfOutputs = 0, nout = 0;
 		/*
 		 * Count the total number of outputs.
 		 */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++)
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++)
 			totalNumberOfOutputs += my tableaus [itab]. numberOfCandidates;
 		/*
 		 * Create the distribution. One row for every output form.
@@ -1115,21 +1115,21 @@ autoPairDistribution OTGrammar_to_PairDistribution (OTGrammar me, long trialsPer
 		 * Measure every input form.
 		 */
 		autoMelderProgress progress (U"OTGrammar: compute output distribution.");
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
 			Melder_progress ((itab - 0.5) / my numberOfTableaus, U"Measuring input \"", tableau -> input, U"\"");
 			/*
 			 * Copy the input and output strings to the target object.
 			 */
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				PairDistribution_add (thee.get(), tableau -> input, tableau -> candidates [icand]. output, 0.0);
 			}
 			/*
 			 * Compute a number of outputs and store the results.
 			 */
-			for (long itrial = 1; itrial <= trialsPerInput; itrial ++) {
+			for (integer itrial = 1; itrial <= trialsPerInput; itrial ++) {
 				OTGrammar_newDisharmonies (me, noise);
-				long iwinner = OTGrammar_getWinner (me, itab);
+				integer iwinner = OTGrammar_getWinner (me, itab);
 				thy pairs.at [nout + iwinner] -> weight += 1.0;
 			}
 			/*
@@ -1144,9 +1144,9 @@ autoPairDistribution OTGrammar_to_PairDistribution (OTGrammar me, long trialsPer
 }
 
 static bool honoursFixedRankings (OTGrammar me) {
-	for (long i = 1; i <= my numberOfFixedRankings; i ++) {
-		long higher = my fixedRankings [i]. higher, lower = my fixedRankings [i]. lower;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer i = 1; i <= my numberOfFixedRankings; i ++) {
+		integer higher = my fixedRankings [i]. higher, lower = my fixedRankings [i]. lower;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			if (my index [icons] == higher) break;   // detected higher before lower: OK
 			if (my index [icons] == lower) return false;
 		}
@@ -1156,18 +1156,18 @@ static bool honoursFixedRankings (OTGrammar me) {
 
 autoDistributions OTGrammar_measureTypology_WEAK (OTGrammar me) {
 	try {
-		long totalNumberOfOutputs = 0, nout = 0, ncons = my numberOfConstraints, nperm, factorial [1+12];
+		integer totalNumberOfOutputs = 0, nout = 0, ncons = my numberOfConstraints, nperm, factorial [1+12];
 		if (ncons > 12)
 			Melder_throw (U"Cannot handle more than 12 constraints.");
 		factorial [0] = 1;
-		for (long icons = 1; icons <= ncons; icons ++) {
+		for (integer icons = 1; icons <= ncons; icons ++) {
 			factorial [icons] = factorial [icons - 1] * icons;
 		}
 		nperm = factorial [ncons];
 		/*
 		 * Count the total number of outputs.
 		 */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++)
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++)
 			totalNumberOfOutputs += my tableaus [itab]. numberOfCandidates;
 		/*
 		 * Create the distribution. One row for every output form.
@@ -1177,26 +1177,26 @@ autoDistributions OTGrammar_measureTypology_WEAK (OTGrammar me) {
 		 * Measure every input form.
 		 */
 		autoMelderProgress progress (U"Measuring typology...");
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
 			Melder_progress ((itab - 0.5) / my numberOfTableaus, U"Measuring input \"", tableau -> input, U"\"");
 			/*
 			 * Set the row labels to the output strings.
 			 */
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				thy rowLabels [nout + icand] = Melder_dup (Melder_cat (tableau -> input, U" \\-> ", tableau -> candidates [icand]. output));
 			}
 			/*
 			 * Compute a number of outputs and store the results.
 			 */
-			for (long iperm = 0; iperm < nperm; iperm ++) {
-				long permleft = iperm, iwinner;
+			for (integer iperm = 0; iperm < nperm; iperm ++) {
+				integer permleft = iperm, iwinner;
 				/* Initialize to 12345 before permuting. */
-				for (long icons = 1; icons <= ncons; icons ++) {
+				for (integer icons = 1; icons <= ncons; icons ++) {
 					my index [icons] = icons;
 				}
-				for (long icons = 1; icons < ncons; icons ++) {
-					long fac = factorial [ncons - icons], shift = permleft / fac, dummy;
+				for (integer icons = 1; icons < ncons; icons ++) {
+					integer fac = factorial [ncons - icons], shift = permleft / fac, dummy;
 					/*
 					 * Swap constraint with the one at a distance 'shift'.
 					 */
@@ -1229,7 +1229,7 @@ static void OTGrammar_honourLocalRankings (OTGrammar me, double plasticity, doub
 	bool improved;
 	do {
 		improved = false;
-		for (long irank = 1; irank <= my numberOfFixedRankings; irank ++) {
+		for (integer irank = 1; irank <= my numberOfFixedRankings; irank ++) {
 			OTGrammarFixedRanking fixedRanking = & my fixedRankings [irank];
 			OTGrammarConstraint higher = & my constraints [fixedRanking -> higher], lower = & my constraints [fixedRanking -> lower];
 			while (higher -> ranking <= lower -> ranking) {
@@ -1241,7 +1241,7 @@ static void OTGrammar_honourLocalRankings (OTGrammar me, double plasticity, doub
 	} while (improved);
 }
 
-static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, long iadult,
+static void OTGrammar_modifyRankings (OTGrammar me, integer itab, integer iwinner, integer iadult,
 	kOTGrammar_rerankingStrategy updateRule, int honourLocalRankings,
 	double plasticity, double relativePlasticityNoise, int warnIfStalled, bool *grammarHasChanged)
 {
@@ -1264,7 +1264,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			else if (Melder_debug == 27) multiplyStepByNumberOfViolations = true;   // HG-GLA
 		}
 		if (updateRule == kOTGrammar_rerankingStrategy::SYMMETRIC_ONE) {
-			long icons = NUMrandomInteger (1, my numberOfConstraints);
+			integer icons = NUMrandomInteger (1, my numberOfConstraints);
 			OTGrammarConstraint constraint = & my constraints [icons];
 			double constraintStep = step * constraint -> plasticity;
 			int winnerMarks = winner -> marks [icons];
@@ -1281,7 +1281,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			}
 		} else if (updateRule == kOTGrammar_rerankingStrategy::SYMMETRIC_ALL) {
 			bool changed = false;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -1300,11 +1300,11 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			if (changed && my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG)
 			{
 				double sumOfWeights = 0.0;
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					sumOfWeights += my constraints [icons]. ranking;
 				}
 				double averageWeight = sumOfWeights / my numberOfConstraints;
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					my constraints [icons]. ranking -= averageWeight;
 				}
 			}
@@ -1312,13 +1312,13 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 		} else if (updateRule == kOTGrammar_rerankingStrategy::SYMMETRIC_ALL_SKIPPABLE) {
 			bool changed = false;
 			int winningConstraints = 0, adultConstraints = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [icons];
 				int adultMarks = adult -> marks [icons];
 				if (adultMarks > winnerMarks) adultConstraints ++;
 				if (winnerMarks > adultMarks) winningConstraints ++;
 			}
-			if (winningConstraints != 0) for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			if (winningConstraints != 0) for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -1337,24 +1337,24 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			if (changed && my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG)
 			{
 				double sumOfWeights = 0.0;
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					sumOfWeights += my constraints [icons]. ranking;
 				}
 				double averageWeight = sumOfWeights / my numberOfConstraints;
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					my constraints [icons]. ranking -= averageWeight;
 				}
 			}
 			if (grammarHasChanged) *grammarHasChanged = changed;
 		} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_UNCANCELLED) {
 			int winningConstraints = 0, adultConstraints = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [icons];
 				int adultMarks = adult -> marks [icons];
 				if (adultMarks > winnerMarks) adultConstraints ++;
 				if (winnerMarks > adultMarks) winningConstraints ++;
 			}
-			if (winningConstraints != 0) for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			if (winningConstraints != 0) for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -1374,13 +1374,13 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			}
 		} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL) {
 			int winningConstraints = 0, adultConstraints = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [icons];
 				int adultMarks = adult -> marks [icons];
 				if (adultMarks > 0) adultConstraints ++;
 				if (winnerMarks > 0) winningConstraints ++;
 			}
-			if (winningConstraints != 0) for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			if (winningConstraints != 0) for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTGrammarConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -1402,7 +1402,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			 */
 			double pivotRanking;
 			bool equivalent = true;
-			long icons = 1;
+			integer icons = 1;
 			for (; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 				int adultMarks = adult -> marks [my index [icons]];
@@ -1420,7 +1420,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			 */
 			pivotRanking = my constraints [my index [icons]]. ranking;
 			if (updateRule == kOTGrammar_rerankingStrategy::EDCD_WITH_VACATION) {
-				long numberOfConstraintsToDemote = 0;
+				integer numberOfConstraintsToDemote = 0;
 				for (icons = 1; icons <= my numberOfConstraints; icons ++) {
 					int winnerMarks = winner -> marks [icons];
 					int adultMarks = adult -> marks [icons];
@@ -1446,7 +1446,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			 * that have rankings not lower than the pivot.
 			 */
 			for (icons = 1; icons <= my numberOfConstraints; icons ++) {
-				long numberOfConstraintsDemoted = 0;
+				integer numberOfConstraintsDemoted = 0;
 				int winnerMarks = winner -> marks [my index [icons]];   // for the vacation version, the order is important, therefore indirect
 				int adultMarks = adult -> marks [my index [icons]];
 				if (adultMarks > winnerMarks) {
@@ -1463,9 +1463,9 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			/*
 			 * Determine the crucial adult mark.
 			 */
-			long crucialAdultMark;
+			integer crucialAdultMark;
 			OTGrammarConstraint offendingConstraint;
-			long icons = 1;
+			integer icons = 1;
 			for (; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [my index [icons]];   // the order is important, so we indirect
 				int adultMarks = adult -> marks [my index [icons]];
@@ -1486,8 +1486,8 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 			offendingConstraint -> ranking -= constraintStep;
 			if (grammarHasChanged) *grammarHasChanged = true;
 		} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGHEST_DOWN) {
-			long numberOfUp = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			integer numberOfUp = 0;
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [icons];
 				int adultMarks = adult -> marks [icons];
 				if (winnerMarks > adultMarks) {
@@ -1495,7 +1495,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				}
 			}
 			if (numberOfUp > 0) {
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					OTGrammarConstraint constraint = & my constraints [icons];
 					double constraintStep = step * constraint -> plasticity;
 					int winnerMarks = winner -> marks [icons];
@@ -1506,9 +1506,9 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 						if (grammarHasChanged) *grammarHasChanged = true;
 					}
 				}
-				long crucialAdultMark, winnerMarks = 0, adultMarks = 0;
+				integer crucialAdultMark, winnerMarks = 0, adultMarks = 0;
 				OTGrammarConstraint offendingConstraint;
-				long icons = 1;
+				integer icons = 1;
 				for (; icons <= my numberOfConstraints; icons ++) {
 					winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 					adultMarks = adult -> marks [my index [icons]];
@@ -1531,8 +1531,8 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				if (grammarHasChanged) *grammarHasChanged = true;
 			}
 		} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGHEST_DOWN_2012) {
-			long numberOfUp = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			integer numberOfUp = 0;
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [icons];
 				int adultMarks = adult -> marks [icons];
 				if (winnerMarks > adultMarks) {
@@ -1540,7 +1540,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				}
 			}
 			if (numberOfUp > 0) {
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					OTGrammarConstraint constraint = & my constraints [icons];
 					double constraintStep = step * constraint -> plasticity;
 					int winnerMarks = winner -> marks [icons];
@@ -1551,9 +1551,9 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 						if (grammarHasChanged) *grammarHasChanged = true;
 					}
 				}
-				long crucialAdultMark, winnerMarks = 0, adultMarks = 0;
+				integer crucialAdultMark, winnerMarks = 0, adultMarks = 0;
 				OTGrammarConstraint offendingConstraint;
-				long icons = 1;
+				integer icons = 1;
 				for (; icons <= my numberOfConstraints; icons ++) {
 					winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 					adultMarks = adult -> marks [my index [icons]];
@@ -1576,8 +1576,8 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				if (grammarHasChanged) *grammarHasChanged = true;
 			}
 		} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGH_DOWN) {
-			long numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			integer numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 				int adultMarks = adult -> marks [my index [icons]];
 				if (adultMarks < winnerMarks) {
@@ -1595,8 +1595,8 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				return;
 			}
 			if (numberOfUp > 0) {
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
-					long constraintIndex = my index [icons];
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
+					integer constraintIndex = my index [icons];
 					OTGrammarConstraint constraint = & my constraints [constraintIndex];
 					double constraintStep = step * constraint -> plasticity;
 					int winnerMarks = winner -> marks [constraintIndex];   // the order is important, therefore indirect
@@ -1616,8 +1616,8 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				if (grammarHasChanged) *grammarHasChanged = true;
 			}
 		} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGH_DOWN_2012) {
-			long numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			integer numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 				int adultMarks = adult -> marks [my index [icons]];
 				if (adultMarks < winnerMarks) {
@@ -1635,8 +1635,8 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
 				return;
 			}
 			if (numberOfUp > 0) {
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
-					long constraintIndex = my index [icons];
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
+					integer constraintIndex = my index [icons];
 					OTGrammarConstraint constraint = & my constraints [constraintIndex];
 					double constraintStep = step * constraint -> plasticity;
 					int winnerMarks = winner -> marks [constraintIndex];   // the order is important, therefore indirect
@@ -1675,14 +1675,14 @@ void OTGrammar_learnOne (OTGrammar me, const char32 *input, const char32 *adultO
 		/*
 		 * Evaluate the input in the learner's hypothesis.
 		 */
-		long itab = OTGrammar_getTableau (me, input);
+		integer itab = OTGrammar_getTableau (me, input);
 		OTGrammarTableau tableau = & my tableaus [itab];
 
 		/*
 		 * Determine the "winner", i.e. the candidate that wins in the learner's grammar
 		 * (Tesar & Smolensky call this the "loser").
 		 */
-		long iwinner = OTGrammar_getWinner (me, itab);
+		integer iwinner = OTGrammar_getWinner (me, itab);
 		OTGrammarCandidate winner = & tableau -> candidates [iwinner];
 
 		/*
@@ -1694,7 +1694,7 @@ void OTGrammar_learnOne (OTGrammar me, const char32 *input, const char32 *adultO
 		 * Find (perhaps the learner's interpretation of) the adult output in the learner's own tableau
 		 * (Tesar & Smolensky call this the "winner").
 		 */
-		long iadult = 1;
+		integer iadult = 1;
 		for (; iadult <= tableau -> numberOfCandidates; iadult ++) {
 			OTGrammarCandidate cand = & tableau -> candidates [iadult];
 			if (str32equ (cand -> output, adultOutput)) break;
@@ -1715,15 +1715,15 @@ void OTGrammar_learnOne (OTGrammar me, const char32 *input, const char32 *adultO
 
 void OTGrammar_learn (OTGrammar me, Strings inputs, Strings outputs,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double plasticity, double relativePlasticityNoise, long numberOfChews)
+	double plasticity, double relativePlasticityNoise, integer numberOfChews)
 {
 	if (! inputs) inputs = outputs;
 	try {
-		long n = inputs -> numberOfStrings;
+		integer n = inputs -> numberOfStrings;
 		if (outputs -> numberOfStrings != n)
 			Melder_throw (U"Numbers of strings in input and output are not equal.");
-		for (long i = 1; i <= n; i ++) {
-			for (long ichew = 1; ichew <= numberOfChews; ichew ++) {
+		for (integer i = 1; i <= n; i ++) {
+			for (integer ichew = 1; ichew <= numberOfChews; ichew ++) {
 				OTGrammar_learnOne (me, inputs -> strings [i], outputs -> strings [i],
 					evaluationNoise, updateRule, honourLocalRankings,
 					plasticity, relativePlasticityNoise, true, true, nullptr);
@@ -1736,25 +1736,25 @@ void OTGrammar_learn (OTGrammar me, Strings inputs, Strings outputs,
 
 void OTGrammar_PairDistribution_learn (OTGrammar me, PairDistribution thee,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double initialPlasticity, long replicationsPerPlasticity, double plasticityDecrement,
-	long numberOfPlasticities, double relativePlasticityNoise, long numberOfChews)
+	double initialPlasticity, integer replicationsPerPlasticity, double plasticityDecrement,
+	integer numberOfPlasticities, double relativePlasticityNoise, integer numberOfChews)
 {
-	long idatum = 0, numberOfData = numberOfPlasticities * replicationsPerPlasticity;
+	integer idatum = 0, numberOfData = numberOfPlasticities * replicationsPerPlasticity;
 	try {
 		double plasticity = initialPlasticity;
 		autoMelderMonitor monitor (U"Learning with full knowledge...");
 		if (monitor.graphics()) {
 			Graphics_clearWs (monitor.graphics());
 		}
-		for (long iplasticity = 1; iplasticity <= numberOfPlasticities; iplasticity ++) {
-			for (long ireplication = 1; ireplication <= replicationsPerPlasticity; ireplication ++) {
+		for (integer iplasticity = 1; iplasticity <= numberOfPlasticities; iplasticity ++) {
+			for (integer ireplication = 1; ireplication <= replicationsPerPlasticity; ireplication ++) {
 				char32 *input, *output;
 				PairDistribution_peekPair (thee, & input, & output);
 				++ idatum;
 				if (monitor.graphics() && idatum % (numberOfData / 400 + 1) == 0) {
 					Graphics_beginMovieFrame (monitor.graphics(), nullptr);
 					Graphics_setWindow (monitor.graphics(), 0, numberOfData, 50, 150);
-					for (long icons = 1; icons <= 14 && icons <= my numberOfConstraints; icons ++) {
+					for (integer icons = 1; icons <= 14 && icons <= my numberOfConstraints; icons ++) {
 						Graphics_setGrey (monitor.graphics(), (double) icons / 14);
 						Graphics_line (monitor.graphics(), idatum, my constraints [icons]. ranking,
 							idatum, my constraints [icons]. ranking+1);
@@ -1764,7 +1764,7 @@ void OTGrammar_PairDistribution_learn (OTGrammar me, PairDistribution thee,
 				Melder_monitor ((double) idatum / numberOfData,
 					U"Processing input-output pair ", idatum,
 					U" out of ", numberOfData, U": ", input, U" -> ", output);
-				for (long ichew = 1; ichew <= numberOfChews; ichew ++) {
+				for (integer ichew = 1; ichew <= numberOfChews; ichew ++) {
 					OTGrammar_learnOne (me, input, output,
 						evaluationNoise, updateRule, honourLocalRankings,
 						plasticity, relativePlasticityNoise, true, true, nullptr);
@@ -1779,9 +1779,9 @@ void OTGrammar_PairDistribution_learn (OTGrammar me, PairDistribution thee,
 	}
 }
 
-static long PairDistribution_getNumberOfAttestedOutputs (PairDistribution me, const char32 *input, char32 **attestedOutput) {
-	long result = 0;
-	for (long ipair = 1; ipair <= my pairs.size; ipair ++) {
+static integer PairDistribution_getNumberOfAttestedOutputs (PairDistribution me, const char32 *input, char32 **attestedOutput) {
+	integer result = 0;
+	for (integer ipair = 1; ipair <= my pairs.size; ipair ++) {
 		PairProbability pair = my pairs.at [ipair];
 		if (str32equ (pair -> string1, input) && pair -> weight > 0.0) {
 			if (attestedOutput) *attestedOutput = pair -> string2;
@@ -1802,21 +1802,21 @@ bool OTGrammar_PairDistribution_findPositiveWeights_e (OTGrammar me, PairDistrib
 		{
 			Melder_throw (U"To find positive weights, the decision strategy has to be HarmonicGrammar, LinearOT, PositiveHG, or ExponentialHG.");
 		}
-		autoNUMvector <long> optimalCandidates (1, my numberOfTableaus);
+		autoNUMvector <integer> optimalCandidates (1, my numberOfTableaus);
 		/*
 		 * Check that there is exactly one optimal output for each input.
 		 */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tab = & my tableaus [itab];
 			char32 *attestedOutput = nullptr;
-			long numberOfAttestedOutputs = PairDistribution_getNumberOfAttestedOutputs (thee, tab -> input, & attestedOutput);
+			integer numberOfAttestedOutputs = PairDistribution_getNumberOfAttestedOutputs (thee, tab -> input, & attestedOutput);
 			if (numberOfAttestedOutputs == 0) {
 				Melder_throw (U"Input \"", my tableaus [itab]. input, U"\" has no attested output.");
 			} else if (numberOfAttestedOutputs > 1) {
 				Melder_throw (U"Input \"", my tableaus [itab]. input, U"\" has more than one attested output.");
 			} else {
 				Melder_assert (attestedOutput);
-				for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
+				for (integer icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
 					OTGrammarCandidate cand = & tab -> candidates [icand];
 					if (str32equ (attestedOutput, cand -> output)) {
 						optimalCandidates [itab] = icand;
@@ -1829,25 +1829,25 @@ bool OTGrammar_PairDistribution_findPositiveWeights_e (OTGrammar me, PairDistrib
 		 * Create linear programming problem.
 		 */
 		linprog = NUMlinprog_new (false);
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			NUMlinprog_addVariable (linprog, weightFloor, undefined, 1.0);
 		}
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tab = & my tableaus [itab];
-			long ioptimalCandidate = optimalCandidates [itab];
+			integer ioptimalCandidate = optimalCandidates [itab];
 			Melder_assert (ioptimalCandidate >= 1);
 			Melder_assert (ioptimalCandidate <= tab -> numberOfCandidates);
 			OTGrammarCandidate optimalCandidate = & tab -> candidates [ioptimalCandidate];
-			for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) if (icand != ioptimalCandidate) {
+			for (integer icand = 1; icand <= tab -> numberOfCandidates; icand ++) if (icand != ioptimalCandidate) {
 				OTGrammarCandidate cand = & tab -> candidates [icand];
 				NUMlinprog_addConstraint (linprog, marginOfSeparation, undefined);
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					NUMlinprog_addConstraintCoefficient (linprog, cand -> marks [icons] - optimalCandidate -> marks [icons]);
 				}
 			}
 		}
 		NUMlinprog_run (linprog);
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			double weighting = NUMlinprog_getPrimalValue (linprog, icons);
 			Melder_assert (weighting >= weightFloor);
 			my constraints [icons]. ranking = my constraints [icons]. disharmony =
@@ -1862,7 +1862,7 @@ bool OTGrammar_PairDistribution_findPositiveWeights_e (OTGrammar me, PairDistrib
 }
 
 void OTGrammar_reset (OTGrammar me, double ranking) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [icons];
 		constraint -> disharmony = constraint -> ranking = ranking;
 	}
@@ -1870,7 +1870,7 @@ void OTGrammar_reset (OTGrammar me, double ranking) {
 }
 
 void OTGrammar_resetToRandomRanking (OTGrammar me, double mean, double standardDeviation) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [my index [icons]];
 		constraint -> disharmony = constraint -> ranking = NUMrandomGauss (mean, standardDeviation);
 	}
@@ -1881,7 +1881,7 @@ void OTGrammar_resetToRandomTotalRanking (OTGrammar me, double maximumRanking, d
 	/*
 	 * First put the constraints in a random order and build a random index.
 	 */
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [icons];
 		constraint -> ranking = 0.0;
 	}
@@ -1889,14 +1889,14 @@ void OTGrammar_resetToRandomTotalRanking (OTGrammar me, double maximumRanking, d
 	/*
 	 * Then use the random index to yield a cascade of rankings.
 	 */
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [my index [icons]];
 		constraint -> disharmony = constraint -> ranking = maximumRanking - (icons - 1) * rankingDistance;
 	}
 	OTGrammar_sort (me);
 }
 
-void OTGrammar_setRanking (OTGrammar me, long constraint, double ranking, double disharmony) {
+void OTGrammar_setRanking (OTGrammar me, integer constraint, double ranking, double disharmony) {
 	try {
 		if (constraint < 1 || constraint > my numberOfConstraints)
 			Melder_throw (U"There is no constraint with number ", constraint, U".");
@@ -1908,7 +1908,7 @@ void OTGrammar_setRanking (OTGrammar me, long constraint, double ranking, double
 	}
 }
 
-void OTGrammar_setConstraintPlasticity (OTGrammar me, long constraint, double plasticity) {
+void OTGrammar_setConstraintPlasticity (OTGrammar me, integer constraint, double plasticity) {
 	try {
 		if (constraint < 1 || constraint > my numberOfConstraints)
 			Melder_throw (U"There is no constraint with number ", constraint, U".");
@@ -1918,7 +1918,7 @@ void OTGrammar_setConstraintPlasticity (OTGrammar me, long constraint, double pl
 	}
 }
 
-long theSaveNumberOfConstraints, *theSaveIndex;
+integer theSaveNumberOfConstraints, *theSaveIndex;
 double *theSaveRankings, *theSaveDisharmonies;
 int *theSaveTiedToTheLeft, *theSaveTiedToTheRight;
 static void OTGrammar_save (OTGrammar me) {
@@ -1930,12 +1930,12 @@ static void OTGrammar_save (OTGrammar me) {
 		NUMvector_free (theSaveTiedToTheRight, 1); theSaveTiedToTheRight = nullptr;
 		theSaveNumberOfConstraints = my numberOfConstraints;
 	}
-	if (! theSaveIndex) theSaveIndex = NUMvector <long> (1, my numberOfConstraints);
+	if (! theSaveIndex) theSaveIndex = NUMvector <integer> (1, my numberOfConstraints);
 	if (! theSaveRankings) theSaveRankings = NUMvector <double> (1, my numberOfConstraints);
 	if (! theSaveDisharmonies) theSaveDisharmonies = NUMvector <double> (1, my numberOfConstraints);
 	if (! theSaveTiedToTheLeft) theSaveTiedToTheLeft = NUMvector <int> (1, my numberOfConstraints);
 	if (! theSaveTiedToTheRight) theSaveTiedToTheRight = NUMvector <int> (1, my numberOfConstraints);
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		theSaveIndex [icons] = my index [icons];
 		theSaveRankings [icons] = my constraints [icons]. ranking;
 		theSaveDisharmonies [icons] = my constraints [icons]. disharmony;
@@ -1944,7 +1944,7 @@ static void OTGrammar_save (OTGrammar me) {
 	}
 }
 static void OTGrammar_restore (OTGrammar me) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		my index [icons] = theSaveIndex [icons];
 		my constraints [icons]. ranking = theSaveRankings [icons];
 		my constraints [icons]. disharmony = theSaveDisharmonies [icons];
@@ -1955,16 +1955,16 @@ static void OTGrammar_restore (OTGrammar me) {
 
 void OTGrammar_learnOneFromPartialOutput (OTGrammar me, const char32 *partialAdultOutput,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double plasticity, double relativePlasticityNoise, long numberOfChews, bool warnIfStalled)
+	double plasticity, double relativePlasticityNoise, integer numberOfChews, bool warnIfStalled)
 {
 	try {
 		OTGrammar_newDisharmonies (me, evaluationNoise);
 		if (numberOfChews > 1 && updateRule == kOTGrammar_rerankingStrategy::EDCD) {
 			OTGrammar_save (me);
 		}
-		long ichew = 1;
+		integer ichew = 1;
 		for (; ichew <= numberOfChews; ichew ++) {
-			long assumedAdultInputTableau, assumedAdultCandidate;
+			integer assumedAdultInputTableau, assumedAdultCandidate;
 			OTGrammar_getInterpretiveParse (me, partialAdultOutput, & assumedAdultInputTableau, & assumedAdultCandidate);
 			bool grammarHasChanged = false;
 			OTGrammar_learnOne (me,
@@ -1978,7 +1978,7 @@ void OTGrammar_learnOneFromPartialOutput (OTGrammar me, const char32 *partialAdu
 			/*
 			 * Is the partial output form grammatical by now?
 			 */
-			long assumedAdultInputTableau, assumedAdultCandidate;
+			integer assumedAdultInputTableau, assumedAdultCandidate;
 			OTGrammar_getInterpretiveParse (me, partialAdultOutput, & assumedAdultInputTableau, & assumedAdultCandidate);
 			OTGrammarCandidate learnerCandidate = & my tableaus [assumedAdultInputTableau]. candidates [OTGrammar_getWinner (me, assumedAdultInputTableau)];
 			if (! str32equ (learnerCandidate -> output,
@@ -1995,19 +1995,19 @@ void OTGrammar_learnOneFromPartialOutput (OTGrammar me, const char32 *partialAdu
 	}
 }
 
-static void OTGrammar_learnOneFromPartialOutput_opt (OTGrammar me, const char32 *partialAdultOutput, long ipartialAdultOutput,
+static void OTGrammar_learnOneFromPartialOutput_opt (OTGrammar me, const char32 *partialAdultOutput, integer ipartialAdultOutput,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double plasticity, double relativePlasticityNoise, long numberOfChews, bool warnIfStalled,
-	bool resampleForVirtualProduction, bool compareOnlyPartialOutput, long resampleForCorrectForm)
+	double plasticity, double relativePlasticityNoise, integer numberOfChews, bool warnIfStalled,
+	bool resampleForVirtualProduction, bool compareOnlyPartialOutput, integer resampleForCorrectForm)
 {
 	try {
 		OTGrammar_newDisharmonies (me, evaluationNoise);
 		if (numberOfChews > 1 && updateRule == kOTGrammar_rerankingStrategy::EDCD) {
 			OTGrammar_save (me);
 		}
-		long ichew = 1;
+		integer ichew = 1;
 		for (; ichew <= numberOfChews; ichew ++) {
-			long assumedAdultInputTableau, assumedAdultCandidate;
+			integer assumedAdultInputTableau, assumedAdultCandidate;
 			OTGrammar_getInterpretiveParse_opt (me, ipartialAdultOutput, & assumedAdultInputTableau, & assumedAdultCandidate);
 			OTGrammarTableau tableau = & my tableaus [assumedAdultInputTableau];
 			OTGrammarCandidate assumedCorrect = & tableau -> candidates [assumedAdultCandidate];
@@ -2017,7 +2017,7 @@ static void OTGrammar_learnOneFromPartialOutput_opt (OTGrammar me, const char32
 			 * (Tesar & Smolensky call this the "loser").
 			 */
 			if (resampleForVirtualProduction) OTGrammar_newDisharmonies (me, evaluationNoise);
-			long iwinner = OTGrammar_getWinner (me, assumedAdultInputTableau);
+			integer iwinner = OTGrammar_getWinner (me, assumedAdultInputTableau);
 			OTGrammarCandidate winner = & tableau -> candidates [iwinner];
 
 			/*
@@ -2029,10 +2029,10 @@ static void OTGrammar_learnOneFromPartialOutput_opt (OTGrammar me, const char32
 				if (str32equ (winner -> output, assumedCorrect -> output)) return;   // as far as we know, the grammar is already correct: don't update rankings
 			}
 			if (resampleForCorrectForm) {
-				long itry = 1;
+				integer itry = 1;
 				for (; itry <= resampleForCorrectForm; itry ++) {
 					OTGrammar_newDisharmonies (me, evaluationNoise);
-					long iwinner2 = OTGrammar_getWinner (me, assumedAdultInputTableau);
+					integer iwinner2 = OTGrammar_getWinner (me, assumedAdultInputTableau);
 					OTGrammarCandidate winner2 = & tableau -> candidates [iwinner2];
 					if (compareOnlyPartialOutput) {
 						if (str32str (winner2 -> output, partialAdultOutput)) { assumedAdultCandidate = iwinner2; break; }
@@ -2056,7 +2056,7 @@ static void OTGrammar_learnOneFromPartialOutput_opt (OTGrammar me, const char32
 			/*
 			 * Is the partial output form grammatical by now?
 			 */
-			long assumedAdultInputTableau, assumedAdultCandidate;
+			integer assumedAdultInputTableau, assumedAdultCandidate;
 			OTGrammar_getInterpretiveParse_opt (me, ipartialAdultOutput, & assumedAdultInputTableau, & assumedAdultCandidate);
 			OTGrammarCandidate learnerCandidate = & my tableaus [assumedAdultInputTableau]. candidates [OTGrammar_getWinner (me, assumedAdultInputTableau)];
 			if (! str32equ (learnerCandidate -> output,
@@ -2073,9 +2073,9 @@ static void OTGrammar_learnOneFromPartialOutput_opt (OTGrammar me, const char32
 	}
 }
 
-static autoOTHistory OTGrammar_createHistory (OTGrammar me, long storeHistoryEvery, long numberOfData) {
+static autoOTHistory OTGrammar_createHistory (OTGrammar me, integer storeHistoryEvery, integer numberOfData) {
 	try {
-		long numberOfSamplingPoints = numberOfData / storeHistoryEvery, icons;   // e.g. 0, 20, 40, ...
+		integer numberOfSamplingPoints = numberOfData / storeHistoryEvery, icons;   // e.g. 0, 20, 40, ...
 		autoOTHistory thee = Thing_new (OTHistory);
 		TableOfReal_init (thee.get(), 2 + numberOfSamplingPoints * 2, 1 + my numberOfConstraints);
 		TableOfReal_setColumnLabel (thee.get(), 1, U"Datum");
@@ -2093,14 +2093,14 @@ static autoOTHistory OTGrammar_createHistory (OTGrammar me, long storeHistoryEve
 	}
 }
 
-static void OTGrammar_updateHistory (OTGrammar me, OTHistory thee, long storeHistoryEvery, long idatum, const char32 *input) {
+static void OTGrammar_updateHistory (OTGrammar me, OTHistory thee, integer storeHistoryEvery, integer idatum, const char32 *input) {
 	try {
 		if (idatum % storeHistoryEvery == 0) {
-			long irow = 2 * idatum / storeHistoryEvery;
+			integer irow = 2 * idatum / storeHistoryEvery;
 			TableOfReal_setRowLabel (thee, irow, input);
 			thy data [irow] [1] = idatum;
 			thy data [irow + 1] [1] = idatum;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				thy data [irow] [icons + 1] = my constraints [icons]. disharmony;
 				thy data [irow + 1] [icons + 1] = my constraints [icons]. ranking;
 			}
@@ -2110,11 +2110,11 @@ static void OTGrammar_updateHistory (OTGrammar me, OTHistory thee, long storeHis
 	}
 }
 
-static void OTGrammar_finalizeHistory (OTGrammar me, OTHistory thee, long idatum) {
+static void OTGrammar_finalizeHistory (OTGrammar me, OTHistory thee, integer idatum) {
 	try {
 		TableOfReal_setRowLabel (thee, thy numberOfRows, U"Final state");
 		thy data [thy numberOfRows] [1] = idatum;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			thy data [thy numberOfRows] [icons + 1] = my constraints [icons]. ranking;
 		}
 	} catch (MelderError) {
@@ -2124,8 +2124,8 @@ static void OTGrammar_finalizeHistory (OTGrammar me, OTHistory thee, long idatum
 
 void OTGrammar_learnFromPartialOutputs (OTGrammar me, Strings partialOutputs,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double plasticity, double relativePlasticityNoise, long numberOfChews,
-	long storeHistoryEvery, autoOTHistory *history_out)
+	double plasticity, double relativePlasticityNoise, integer numberOfChews,
+	integer storeHistoryEvery, autoOTHistory *history_out)
 {
 	try {
 		autoOTHistory history;
@@ -2133,7 +2133,7 @@ void OTGrammar_learnFromPartialOutputs (OTGrammar me, Strings partialOutputs,
 			history = OTGrammar_createHistory (me, storeHistoryEvery, partialOutputs -> numberOfStrings);
 		}
 		try {
-			for (long idatum = 1; idatum <= partialOutputs -> numberOfStrings; idatum ++) {
+			for (integer idatum = 1; idatum <= partialOutputs -> numberOfStrings; idatum ++) {
 				try {
 					OTGrammar_learnOneFromPartialOutput (me, partialOutputs -> strings [idatum],
 						evaluationNoise, updateRule, honourLocalRankings,
@@ -2162,9 +2162,9 @@ void OTGrammar_learnFromPartialOutputs (OTGrammar me, Strings partialOutputs,
 }
 
 static void OTGrammar_opt_deleteOutputMatching (OTGrammar me) {
-	for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+	for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 		OTGrammarTableau tab = & my tableaus [itab];
-		for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
 			OTGrammarCandidate cand = & tab -> candidates [icand];
 			cand -> numberOfPotentialPartialOutputsMatching = 0;
 			NUMvector_free (cand -> partialOutputMatches, 1);
@@ -2173,27 +2173,27 @@ static void OTGrammar_opt_deleteOutputMatching (OTGrammar me) {
 	}
 }
 
-static void OTGrammar_Distributions_opt_createOutputMatching (OTGrammar me, Distributions thee, long columnNumber) {
+static void OTGrammar_Distributions_opt_createOutputMatching (OTGrammar me, Distributions thee, integer columnNumber) {
 	try {
 		if (columnNumber > thy numberOfColumns)
 			Melder_throw (U"No column ", columnNumber, U" in Distributions.");
 		if (thy numberOfRows < 1)
 			Melder_throw (U"No candidates in Distributions.");
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tab = & my tableaus [itab];
-			for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
 				OTGrammarCandidate cand = & tab -> candidates [icand];
 				cand -> numberOfPotentialPartialOutputsMatching = thy numberOfRows;
 				cand -> partialOutputMatches = NUMvector <bool> (1, thy numberOfRows);
 			}
 		}
-		for (long ipartialOutput = 1; ipartialOutput <= thy numberOfRows; ipartialOutput ++) {
+		for (integer ipartialOutput = 1; ipartialOutput <= thy numberOfRows; ipartialOutput ++) {
 			if (thy data [ipartialOutput] [columnNumber] > 0.0) {
 				char32 *partialOutput = thy rowLabels [ipartialOutput];
 				bool foundPartialOutput = false;
-				for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+				for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 					OTGrammarTableau tab = & my tableaus [itab];
-					for (long icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
+					for (integer icand = 1; icand <= tab -> numberOfCandidates; icand ++) {
 						OTGrammarCandidate cand = & tab -> candidates [icand];
 						if (str32str (cand -> output, partialOutput)) {
 							foundPartialOutput = true;
@@ -2211,15 +2211,15 @@ static void OTGrammar_Distributions_opt_createOutputMatching (OTGrammar me, Dist
 	}
 }
 
-void OTGrammar_Distributions_learnFromPartialOutputs (OTGrammar me, Distributions thee, long columnNumber,
+void OTGrammar_Distributions_learnFromPartialOutputs (OTGrammar me, Distributions thee, integer columnNumber,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double initialPlasticity, long replicationsPerPlasticity, double plasticityDecrement,
-	long numberOfPlasticities, double relativePlasticityNoise, long numberOfChews,
-	long storeHistoryEvery, autoOTHistory *history_out,
-	bool resampleForVirtualProduction, bool compareOnlyPartialOutput, long resampleForCorrectForm)
+	double initialPlasticity, integer replicationsPerPlasticity, double plasticityDecrement,
+	integer numberOfPlasticities, double relativePlasticityNoise, integer numberOfChews,
+	integer storeHistoryEvery, autoOTHistory *history_out,
+	bool resampleForVirtualProduction, bool compareOnlyPartialOutput, integer resampleForCorrectForm)
 {
-	long idatum = 0;
-	const long numberOfData = numberOfPlasticities * replicationsPerPlasticity;
+	integer idatum = 0;
+	const integer numberOfData = numberOfPlasticities * replicationsPerPlasticity;
 	try {
 		autoOTHistory history;
 		OTGrammar_Distributions_opt_createOutputMatching (me, thee, columnNumber);
@@ -2232,16 +2232,16 @@ void OTGrammar_Distributions_learnFromPartialOutputs (OTGrammar me, Distribution
 		}
 		try {
 			double plasticity = initialPlasticity;
-			for (long iplasticity = 1; iplasticity <= numberOfPlasticities; iplasticity ++) {
-				for (long ireplication = 1; ireplication <= replicationsPerPlasticity; ireplication ++) {
+			for (integer iplasticity = 1; iplasticity <= numberOfPlasticities; iplasticity ++) {
+				for (integer ireplication = 1; ireplication <= replicationsPerPlasticity; ireplication ++) {
 					char32 *partialOutput;
-					long ipartialOutput;
+					integer ipartialOutput;
 					Distributions_peek (thee, columnNumber, & partialOutput, & ipartialOutput);
 					++ idatum;
 					if (monitor.graphics() && idatum % (numberOfData / 400 + 1) == 0) {
 						Graphics_beginMovieFrame (monitor.graphics(), nullptr);
 						Graphics_setWindow (monitor.graphics(), 0, numberOfData, 50, 150);
-						for (long icons = 1; icons <= 14 && icons <= my numberOfConstraints; icons ++) {
+						for (integer icons = 1; icons <= 14 && icons <= my numberOfConstraints; icons ++) {
 							Graphics_setGrey (monitor.graphics(), (double) icons / 14);
 							Graphics_line (monitor.graphics(), idatum, my constraints [icons]. ranking,
 								idatum, my constraints [icons]. ranking+1);
@@ -2288,15 +2288,15 @@ void OTGrammar_Distributions_learnFromPartialOutputs (OTGrammar me, Distribution
 }
 
 double OTGrammar_PairDistribution_getFractionCorrect (OTGrammar me, PairDistribution thee,
-	double evaluationNoise, long numberOfInputs)
+	double evaluationNoise, integer numberOfInputs)
 {
 	try {
-		long numberOfCorrect = 0;
-		for (long ireplication = 1; ireplication <= numberOfInputs; ireplication ++) {
+		integer numberOfCorrect = 0;
+		for (integer ireplication = 1; ireplication <= numberOfInputs; ireplication ++) {
 			char32 *input, *adultOutput;
 			PairDistribution_peekPair (thee, & input, & adultOutput);
 			OTGrammar_newDisharmonies (me, evaluationNoise);
-			long inputTableau = OTGrammar_getTableau (me, input);
+			integer inputTableau = OTGrammar_getTableau (me, input);
 			OTGrammarCandidate learnerCandidate = & my tableaus [inputTableau]. candidates [OTGrammar_getWinner (me, inputTableau)];
 			if (str32equ (learnerCandidate -> output, adultOutput))
 				numberOfCorrect ++;
@@ -2307,18 +2307,18 @@ double OTGrammar_PairDistribution_getFractionCorrect (OTGrammar me, PairDistribu
 	}
 }
 
-long OTGrammar_PairDistribution_getMinimumNumberCorrect (OTGrammar me, PairDistribution thee,
-	double evaluationNoise, long numberOfReplications)
+integer OTGrammar_PairDistribution_getMinimumNumberCorrect (OTGrammar me, PairDistribution thee,
+	double evaluationNoise, integer numberOfReplications)
 {
 	try {
-		long minimumNumberCorrect = numberOfReplications;
-		for (long ipair = 1; ipair <= thy pairs.size; ipair ++) {
+		integer minimumNumberCorrect = numberOfReplications;
+		for (integer ipair = 1; ipair <= thy pairs.size; ipair ++) {
 			PairProbability prob = thy pairs.at [ipair];
 			if (prob -> weight > 0.0) {
-				long numberOfCorrect = 0;
+				integer numberOfCorrect = 0;
 				char32 *input = prob -> string1, *adultOutput = prob -> string2;
-				long inputTableau = OTGrammar_getTableau (me, input);
-				for (long ireplication = 1; ireplication <= numberOfReplications; ireplication ++) {
+				integer inputTableau = OTGrammar_getTableau (me, input);
+				for (integer ireplication = 1; ireplication <= numberOfReplications; ireplication ++) {
 					OTGrammar_newDisharmonies (me, evaluationNoise);
 					OTGrammarCandidate learnerCandidate = & my tableaus [inputTableau]. candidates [OTGrammar_getWinner (me, inputTableau)];
 					if (str32equ (learnerCandidate -> output, adultOutput))
@@ -2334,17 +2334,17 @@ long OTGrammar_PairDistribution_getMinimumNumberCorrect (OTGrammar me, PairDistr
 	}
 }
 
-double OTGrammar_Distributions_getFractionCorrect (OTGrammar me, Distributions thee, long columnNumber,
-	double evaluationNoise, long numberOfInputs)
+double OTGrammar_Distributions_getFractionCorrect (OTGrammar me, Distributions thee, integer columnNumber,
+	double evaluationNoise, integer numberOfInputs)
 {
 	try {
-		long numberOfCorrect = 0;
+		integer numberOfCorrect = 0;
 		OTGrammar_Distributions_opt_createOutputMatching (me, thee, columnNumber);
-		for (long ireplication = 1; ireplication <= numberOfInputs; ireplication ++) {
-			long ipartialOutput;
+		for (integer ireplication = 1; ireplication <= numberOfInputs; ireplication ++) {
+			integer ipartialOutput;
 			Distributions_peek (thee, columnNumber, nullptr, & ipartialOutput);
 			OTGrammar_newDisharmonies (me, evaluationNoise);
-			long assumedAdultInputTableau, assumedAdultCandidate;
+			integer assumedAdultInputTableau, assumedAdultCandidate;
 			OTGrammar_getInterpretiveParse_opt (me, ipartialOutput, & assumedAdultInputTableau, & assumedAdultCandidate);
 			OTGrammarCandidate learnerCandidate = & my tableaus [assumedAdultInputTableau]. candidates [OTGrammar_getWinner (me, assumedAdultInputTableau)];
 			if (str32equ (learnerCandidate -> output, my tableaus [assumedAdultInputTableau]. candidates [assumedAdultCandidate]. output))
@@ -2359,7 +2359,7 @@ double OTGrammar_Distributions_getFractionCorrect (OTGrammar me, Distributions t
 
 void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName) {
 	try {
-		long removed = 0;
+		integer removed = 0;
 
 		if (my numberOfConstraints <= 1)
 			Melder_throw (U"Cannot remove last remaining constraint.");
@@ -2367,7 +2367,7 @@ void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName) {
 		/*
 		 * Look for the constraint to be removed.
 		 */
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTGrammarConstraint constraint = & my constraints [icons];
 			if (str32equ (constraint -> name, constraintName)) {
 				removed = icons;
@@ -2384,13 +2384,13 @@ void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName) {
 		 * Shift constraints.
 		 */
 		Melder_free (my constraints [removed]. name);
-		for (long icons = removed; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = removed; icons <= my numberOfConstraints; icons ++) {
 			my constraints [icons] = my constraints [icons + 1];
 		}
 		/*
 		 * Remove or shift fixed rankings.
 		 */
-		for (long ifixed = my numberOfFixedRankings; ifixed > 0; ifixed --) {
+		for (integer ifixed = my numberOfFixedRankings; ifixed > 0; ifixed --) {
 			OTGrammarFixedRanking fixed = & my fixedRankings [ifixed];
 			if (fixed -> higher == removed || fixed -> lower == removed) {
 				/*
@@ -2401,7 +2401,7 @@ void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName) {
 					NUMvector_free <structOTGrammarFixedRanking> (my fixedRankings, 1);
 					my fixedRankings = nullptr;
 				}
-				for (long jfixed = ifixed; jfixed <= my numberOfFixedRankings; jfixed ++) {
+				for (integer jfixed = ifixed; jfixed <= my numberOfFixedRankings; jfixed ++) {
 					my fixedRankings [jfixed] = my fixedRankings [jfixed + 1];
 				}
 			} else {
@@ -2415,12 +2415,12 @@ void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName) {
 		/*
 		 * Shift tableau rows.
 		 */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				OTGrammarCandidate candidate = & tableau -> candidates [icand];
 				candidate -> numberOfConstraints -= 1;
-				for (long icons = removed; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = removed; icons <= my numberOfConstraints; icons ++) {
 					candidate -> marks [icons] = candidate -> marks [icons + 1];
 				}
 			}
@@ -2428,14 +2428,14 @@ void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName) {
 		/*
 		 * Rebuild index.
 		 */
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) my index [icons] = icons;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) my index [icons] = icons;
 		OTGrammar_sort (me);
 	} catch (MelderError) {
 		Melder_throw (me, U": constraint \"", constraintName, U"\" not removed.");
 	}
 }
 
-static void OTGrammarTableau_removeCandidate_unstripped (OTGrammarTableau me, long candidateNumber) {
+static void OTGrammarTableau_removeCandidate_unstripped (OTGrammarTableau me, integer candidateNumber) {
 	Melder_assert (candidateNumber >= 1);
 	if (candidateNumber > my numberOfCandidates) Melder_fatal (U"icand ", candidateNumber, U", ncand ", my numberOfCandidates);
 	/*
@@ -2450,7 +2450,7 @@ static void OTGrammarTableau_removeCandidate_unstripped (OTGrammarTableau me, lo
 	/*
 	 * Shift.
 	 */
-	for (long jcand = candidateNumber; jcand <= my numberOfCandidates; jcand ++) {
+	for (integer jcand = candidateNumber; jcand <= my numberOfCandidates; jcand ++) {
 		OTGrammarCandidate candj = & my candidates [jcand];
 		OTGrammarCandidate candj1 = & my candidates [jcand + 1];
 		candj -> output = candj1 -> output;
@@ -2458,18 +2458,18 @@ static void OTGrammarTableau_removeCandidate_unstripped (OTGrammarTableau me, lo
 	}
 }
 
-static bool OTGrammarTableau_isHarmonicallyBounded (OTGrammarTableau me, long icand, long jcand) {
+static bool OTGrammarTableau_isHarmonicallyBounded (OTGrammarTableau me, integer icand, integer jcand) {
 	OTGrammarCandidate candi = & my candidates [icand], candj = & my candidates [jcand];
 	bool equal = true;
 	if (icand == jcand) return false;
-	for (long icons = 1; icons <= candi -> numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= candi -> numberOfConstraints; icons ++) {
 		if (candi -> marks [icons] < candj -> marks [icons]) return false;
 		if (candi -> marks [icons] > candj -> marks [icons]) equal = false;
 	}
 	return ! equal;
 }
 
-static bool OTGrammarTableau_candidateIsPossibleWinner (OTGrammar me, long itab, long icand) {
+static bool OTGrammarTableau_candidateIsPossibleWinner (OTGrammar me, integer itab, integer icand) {
 	OTGrammar_save (me);
 	OTGrammar_reset (me, 100.0);
 	for (;;) {
@@ -2482,7 +2482,7 @@ static bool OTGrammarTableau_candidateIsPossibleWinner (OTGrammar me, long itab,
 		}
 		double previousStratum = 101.0;
 		OTGrammar_newDisharmonies (me, 0.0);
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			double stratum = my constraints [my index [icons]]. ranking;
 			#if 0
 			if (stratum < 50.0 - my numberOfConstraints) {
@@ -2509,10 +2509,10 @@ void OTGrammar_removeHarmonicallyBoundedCandidates (OTGrammar me, bool singly) {
 		 * First, the candidates that are harmonically bounded by one or more single other candidates have to be removed;
 		 * otherwise, EDCD will stall.
 		 */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tab = & my tableaus [itab];
-			for (long icand = tab -> numberOfCandidates; icand >= 1; icand --) {
-				for (long jcand = 1; jcand <= tab -> numberOfCandidates; jcand ++) {
+			for (integer icand = tab -> numberOfCandidates; icand >= 1; icand --) {
+				for (integer jcand = 1; jcand <= tab -> numberOfCandidates; jcand ++) {
 					if (OTGrammarTableau_isHarmonicallyBounded (tab, icand, jcand)) {
 						OTGrammarTableau_removeCandidate_unstripped (tab, icand);
 						break;
@@ -2522,9 +2522,9 @@ void OTGrammar_removeHarmonicallyBoundedCandidates (OTGrammar me, bool singly) {
 			tab -> candidates = (OTGrammarCandidate) realloc (& tab -> candidates [1], sizeof (struct structOTGrammarCandidate) * tab -> numberOfCandidates) - 1;
 		}
 		if (! singly) {
-			for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+			for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 				OTGrammarTableau tab = & my tableaus [itab];
-				for (long icand = tab -> numberOfCandidates; icand >= 1; icand --) {
+				for (integer icand = tab -> numberOfCandidates; icand >= 1; icand --) {
 					if (! OTGrammarTableau_candidateIsPossibleWinner (me, itab, icand)) {
 						OTGrammarTableau_removeCandidate_unstripped (tab, icand);
 					}
@@ -2540,7 +2540,7 @@ void OTGrammar_removeHarmonicallyBoundedCandidates (OTGrammar me, bool singly) {
 Thing_define (OTGrammar_List4, Daata) {
 	// new data:
 	public:
-		long hi1, lo1, hi2, lo2;
+		integer hi1, lo1, hi2, lo2;
 };
 
 Thing_implement (OTGrammar_List4, Daata, 0);
@@ -2551,11 +2551,11 @@ void OTGrammar_PairDistribution_listObligatoryRankings (OTGrammar me, PairDistri
 	 */
 	OTGrammarFixedRanking savedFixedRankings = my fixedRankings;   // dangle...
 	my fixedRankings = nullptr;   // ...undangle
-	long savedNumberOfFixedRankings = my numberOfFixedRankings;
+	integer savedNumberOfFixedRankings = my numberOfFixedRankings;
 	OTGrammar_save (me);
 	try {
-		long ifixedRanking, icons, jcons, kcons, lcons, ipair = 0, npair = my numberOfConstraints * (my numberOfConstraints - 1);
-		long ilist, jlist, itrial, iform;
+		integer ifixedRanking, icons, jcons, kcons, lcons, ipair = 0, npair = my numberOfConstraints * (my numberOfConstraints - 1);
+		integer ilist, jlist, itrial, iform;
 		bool improved;
 		double evaluationNoise = 1e-9;
 		/*
@@ -2696,8 +2696,8 @@ void OTGrammar_PairDistribution_listObligatoryRankings (OTGrammar me, PairDistri
 				for (jlist = 1; jlist <= list.size; jlist ++) if (ilist != jlist) {
 					OTGrammar_List4 elA = list.at [ilist];
 					OTGrammar_List4 elB = list.at [jlist];
-					long ahi1 = elA -> hi1, alo1 = elA -> lo1, ahi2 = elA -> hi2, alo2 = elA -> lo2;
-					long bhi1 = elB -> hi1, blo1 = elB -> lo1, bhi2 = elB -> hi2, blo2 = elB -> lo2;
+					integer ahi1 = elA -> hi1, alo1 = elA -> lo1, ahi2 = elA -> hi2, alo2 = elA -> lo2;
+					integer bhi1 = elB -> hi1, blo1 = elB -> lo1, bhi2 = elB -> hi2, blo2 = elB -> lo2;
 					improved |= (ahi1 == bhi1 || obligatory [bhi1] [ahi1]) && (ahi2 == bhi2 || obligatory [bhi2] [ahi2]) &&
 						(alo1 == blo1 || obligatory [alo1] [blo1]) && (alo2 == blo2 || obligatory [alo2] [blo2]);
 					improved |= (ahi1 == bhi2 || obligatory [bhi2] [ahi1]) && (ahi2 == bhi1 || obligatory [bhi1] [ahi2]) &&
@@ -2717,8 +2717,8 @@ void OTGrammar_PairDistribution_listObligatoryRankings (OTGrammar me, PairDistri
 				for (jlist = 1; jlist <= list.size; jlist ++) if (ilist != jlist) {
 					OTGrammar_List4 elA = list.at [ilist];
 					OTGrammar_List4 elB = list.at [jlist];
-					long ahi1 = elA -> hi1, alo1 = elA -> lo1, ahi2 = elA -> hi2, alo2 = elA -> lo2;
-					long bhi1 = elB -> hi1, blo1 = elB -> lo1, bhi2 = elB -> hi2, blo2 = elB -> lo2;
+					integer ahi1 = elA -> hi1, alo1 = elA -> lo1, ahi2 = elA -> hi2, alo2 = elA -> lo2;
+					integer bhi1 = elB -> hi1, blo1 = elB -> lo1, bhi2 = elB -> hi2, blo2 = elB -> lo2;
 					improved |= ahi1 == bhi1 && alo1 == blo1 && ahi2 == bhi2 && blo2 == bhi1 && alo2 == alo1;
 					improved |= ahi1 == bhi2 && alo1 == blo2 && ahi2 == bhi1 && blo1 == bhi2 && alo2 == alo1;
 					improved |= ahi2 == bhi1 && alo2 == blo1 && ahi1 == bhi2 && blo2 == bhi1 && alo1 == alo2;
@@ -2764,7 +2764,7 @@ void OTGrammar_PairDistribution_listObligatoryRankings (OTGrammar me, PairDistri
 	}
 }
 
-void OTGrammar_Distributions_listObligatoryRankings (OTGrammar me, Distributions thee, long columnNumber) {
+void OTGrammar_Distributions_listObligatoryRankings (OTGrammar me, Distributions thee, integer columnNumber) {
 	/*
 	 * Save.
 	 */
@@ -2772,7 +2772,7 @@ void OTGrammar_Distributions_listObligatoryRankings (OTGrammar me, Distributions
 	my fixedRankings = nullptr;
 	OTGrammar_save (me);
 	try {
-		long ifixedRanking, icons, jcons, kcons, ipair = 0, npair = my numberOfConstraints * (my numberOfConstraints - 1);
+		integer ifixedRanking, icons, jcons, kcons, ipair = 0, npair = my numberOfConstraints * (my numberOfConstraints - 1);
 		/*
 		 * Add room for one more fixed ranking.
 		 */
@@ -2838,7 +2838,7 @@ void OTGrammar_Distributions_listObligatoryRankings (OTGrammar me, Distributions
 static void printConstraintNames (OTGrammar me, MelderString *buffer) {
 	char32 text [200];
 	bool secondLine = false;
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & my constraints [my index [icons]];
 		if (str32chr (constraint -> name, U'\n')) {
 			char32 *newLine;
@@ -2854,7 +2854,7 @@ static void printConstraintNames (OTGrammar me, MelderString *buffer) {
 	MelderString_appendCharacter (buffer, U'\n');
 	if (secondLine) {
 		MelderString_appendCharacter (buffer, U'\t');
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTGrammarConstraint constraint = & my constraints [my index [icons]];
 			char32 *newLine = str32chr (constraint -> name, U'\n');
 			MelderString_append (buffer, U"\t", newLine ? newLine + 1 : U"");
@@ -2869,38 +2869,38 @@ void OTGrammar_writeToHeaderlessSpreadsheetFile (OTGrammar me, MelderFile file)
 		MelderString_copy (& buffer, U"CONSTRAINTS\t");
 		printConstraintNames (me, & buffer);
 		MelderString_append (& buffer, U"rankings\t");
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTGrammarConstraint constraint = & my constraints [my index [icons]];
 			MelderString_append (& buffer, U"\t", constraint -> ranking);
 		}
 		MelderString_append (& buffer, U"\ndisharmonies\t");
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTGrammarConstraint constraint = & my constraints [my index [icons]];
 			MelderString_append (& buffer, U"\t", constraint -> disharmony);
 		}
 		MelderString_appendCharacter (& buffer, U'\n');
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
-			long winner = OTGrammar_getWinner (me, itab), numberOfOptimalCandidates = 0;
-			for (long icons = 1; icons <= my numberOfConstraints + 1; icons ++) {
+			integer winner = OTGrammar_getWinner (me, itab), numberOfOptimalCandidates = 0;
+			for (integer icons = 1; icons <= my numberOfConstraints + 1; icons ++) {
 				MelderString_appendCharacter (& buffer, U'\t');
 			}
 			MelderString_append (& buffer, U"\nINPUT\t", tableau -> input);
 			printConstraintNames (me, & buffer);
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				if (OTGrammar_compareCandidates (me, itab, icand, itab, winner) == 0) {
 					numberOfOptimalCandidates ++;
 				}
 			}
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				OTGrammarCandidate candidate = & tableau -> candidates [icand];
 				bool candidateIsOptimal = OTGrammar_compareCandidates (me, itab, icand, itab, winner) == 0;
-				long crucialCell = OTGrammar_crucialCell (me, itab, icand, winner, numberOfOptimalCandidates);
+				integer crucialCell = OTGrammar_crucialCell (me, itab, icand, winner, numberOfOptimalCandidates);
 				MelderString_append (& buffer,
 					candidateIsOptimal == false ? U"loser" : numberOfOptimalCandidates > 1 ? U"co-winner" : U"winner",
 					U"\t",
 					candidate -> output);
-				for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+				for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 					int index = my index [icons];
 					OTGrammarConstraint constraint = & my constraints [index];
 					static MelderString markString;
@@ -2913,10 +2913,10 @@ void OTGrammar_writeToHeaderlessSpreadsheetFile (OTGrammar me, MelderFile file)
 					 */
 					if (icons == crucialCell && ! candidateIsOptimal && ! constraint -> tiedToTheLeft && ! constraint -> tiedToTheRight) {
 						int winnerMarks = tableau -> candidates [winner]. marks [index];
-						for (long imark = 1; imark <= winnerMarks + 1; imark ++)
+						for (integer imark = 1; imark <= winnerMarks + 1; imark ++)
 							MelderString_appendCharacter (& markString, U'*');
 						MelderString_appendCharacter (& markString, U'!');
-						for (long imark = winnerMarks + 2; imark <= candidate -> marks [index]; imark ++)
+						for (integer imark = winnerMarks + 2; imark <= candidate -> marks [index]; imark ++)
 							MelderString_appendCharacter (& markString, U'*');
 					} else {
 						if (! candidateIsOptimal && (constraint -> tiedToTheLeft || constraint -> tiedToTheRight) &&
@@ -2924,7 +2924,7 @@ void OTGrammar_writeToHeaderlessSpreadsheetFile (OTGrammar me, MelderFile file)
 						{
 							MelderString_appendCharacter (& markString, U'=');
 						}
-						for (long imark = 1; imark <= candidate -> marks [index]; imark ++)
+						for (integer imark = 1; imark <= candidate -> marks [index]; imark ++)
 							MelderString_appendCharacter (& markString, U'*');
 					}
 					MelderString_append (& buffer, U"\t", markString.string);
diff --git a/gram/OTGrammar.h b/gram/OTGrammar.h
index 4b86847..7c180ac 100644
--- a/gram/OTGrammar.h
+++ b/gram/OTGrammar.h
@@ -2,7 +2,7 @@
 #define _OTGrammar_h_
 /* OTGrammar.h
  *
- * Copyright (C) 1997-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1997-2012,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
@@ -40,8 +40,8 @@ void OTGrammar_sort (OTGrammar me);
 
 void OTGrammar_newDisharmonies (OTGrammar me, double spreading);
 
-long OTGrammar_getTableau (OTGrammar me, const char32 *input);
-int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long itab2, long icand2) noexcept;
+integer OTGrammar_getTableau (OTGrammar me, const char32 *input);
+int OTGrammar_compareCandidates (OTGrammar me, integer itab1, integer icand1, integer itab2, integer icand2) noexcept;
 	/*
 	 * Function:
 	 *    to compare the optimality of candidates icand1 in tableau itab1
@@ -61,15 +61,15 @@ int OTGrammar_compareCandidates (OTGrammar me, long itab1, long icand1, long ita
 	 */
 
 /* Productive parsing. */
-long OTGrammar_getWinner (OTGrammar me, long itab) noexcept;
+integer OTGrammar_getWinner (OTGrammar me, integer itab) noexcept;
 	/* Gives randomized results in case of tied candidates. */
-long OTGrammar_getNumberOfOptimalCandidates (OTGrammar me, long itab);
-bool OTGrammar_isCandidateGrammatical (OTGrammar me, long itab, long icand);
-bool OTGrammar_isCandidateSinglyGrammatical (OTGrammar me, long itab, long icand);
+integer OTGrammar_getNumberOfOptimalCandidates (OTGrammar me, integer itab);
+bool OTGrammar_isCandidateGrammatical (OTGrammar me, integer itab, integer icand);
+bool OTGrammar_isCandidateSinglyGrammatical (OTGrammar me, integer itab, integer icand);
 
 /* Interpretive parsing. */
 void OTGrammar_getInterpretiveParse
-	(OTGrammar me, const char32 *partialOutput, long *bestTableau, long *bestCandidate);
+	(OTGrammar me, const char32 *partialOutput, integer *bestTableau, integer *bestCandidate);
 	/* Gives randomized results in case of tied candidates. */
 bool OTGrammar_isPartialOutputGrammatical (OTGrammar me, const char32 *partialOutput);
 	/* Is there an input for which this partial output is contained in any of the optimal outputs? */
@@ -80,13 +80,13 @@ bool OTGrammar_areAllPartialOutputsSinglyGrammatical (OTGrammar me, Strings thee
 
 void OTGrammar_drawTableau (OTGrammar me, Graphics g, bool vertical, const char32 *input);
 
-autoStrings OTGrammar_generateInputs (OTGrammar me, long numberOfTrials);
+autoStrings OTGrammar_generateInputs (OTGrammar me, integer numberOfTrials);
 autoStrings OTGrammar_getInputs (OTGrammar me);
 void OTGrammar_inputToOutput (OTGrammar me, const char32 *input, char32 *output, double evaluationNoise);
 autoStrings OTGrammar_inputsToOutputs (OTGrammar me, Strings inputs, double evaluationNoise);
-autoStrings OTGrammar_inputToOutputs (OTGrammar me, const char32 *input, long n, double evaluationNoise);
-autoDistributions OTGrammar_to_Distribution (OTGrammar me, long trialsPerInput, double evaluationNoise);
-autoPairDistribution OTGrammar_to_PairDistribution (OTGrammar me, long trialsPerInput, double evaluationNoise);
+autoStrings OTGrammar_inputToOutputs (OTGrammar me, const char32 *input, integer n, double evaluationNoise);
+autoDistributions OTGrammar_to_Distribution (OTGrammar me, integer trialsPerInput, double evaluationNoise);
+autoPairDistribution OTGrammar_to_PairDistribution (OTGrammar me, integer trialsPerInput, double evaluationNoise);
 autoDistributions OTGrammar_measureTypology_WEAK (OTGrammar me);   // WEAK because it has a progress bar
 
 void OTGrammar_learnOne (OTGrammar me, const char32 *input, const char32 *adultOutput,
@@ -95,30 +95,30 @@ void OTGrammar_learnOne (OTGrammar me, const char32 *input, const char32 *adultO
 	bool warnIfStalled, bool *grammarHasChanged);
 void OTGrammar_learn (OTGrammar me, Strings inputs, Strings outputs,
 	double rankingSpreading, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double demotionMean, double relativeDemotionSpreading, long numberOfChews);
+	double demotionMean, double relativeDemotionSpreading, integer numberOfChews);
 void OTGrammar_PairDistribution_learn (OTGrammar me, PairDistribution thee,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double initialPlasticity, long replicationsPerPlasticity, double plasticityDecrement,
-	long numberOfPlasticities, double relativePlasticityNoise, long numberOfChews);
+	double initialPlasticity, integer replicationsPerPlasticity, double plasticityDecrement,
+	integer numberOfPlasticities, double relativePlasticityNoise, integer numberOfChews);
 bool OTGrammar_PairDistribution_findPositiveWeights_e (OTGrammar me, PairDistribution thee, double weightFloor, double marginOfSeparation);
 void OTGrammar_learnOneFromPartialOutput (OTGrammar me, const char32 *partialAdultOutput,
 	double rankingSpreading, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double demotionMean, double relativeDemotionSpreading, long numberOfChews, bool warnIfStalled);
+	double demotionMean, double relativeDemotionSpreading, integer numberOfChews, bool warnIfStalled);
 void OTGrammar_learnFromPartialOutputs (OTGrammar me, Strings partialOutputs,
 	double rankingSpreading, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double demotionMean, double relativeDemotionSpreading, long numberOfChews, long storeHistoryEvery, autoOTHistory *history);
-void OTGrammar_Distributions_learnFromPartialOutputs (OTGrammar me, Distributions thee, long columnNumber,
+	double demotionMean, double relativeDemotionSpreading, integer numberOfChews, integer storeHistoryEvery, autoOTHistory *history);
+void OTGrammar_Distributions_learnFromPartialOutputs (OTGrammar me, Distributions thee, integer columnNumber,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, bool honourLocalRankings,
-	double initialPlasticity, long replicationsPerPlasticity, double plasticityDecrement,
-	long numberOfPlasticities, double relativePlasticityNoise, long numberOfChews,
-	long storeHistoryEvery, autoOTHistory *history_out,
-	bool resampleForVirtualProduction, bool compareOnlyPartialOutput, long resampleForCorrectForm);
+	double initialPlasticity, integer replicationsPerPlasticity, double plasticityDecrement,
+	integer numberOfPlasticities, double relativePlasticityNoise, integer numberOfChews,
+	integer storeHistoryEvery, autoOTHistory *history_out,
+	bool resampleForVirtualProduction, bool compareOnlyPartialOutput, integer resampleForCorrectForm);
 double OTGrammar_PairDistribution_getFractionCorrect (OTGrammar me, PairDistribution thee,
-	double evaluationNoise, long numberOfInputs);
-long OTGrammar_PairDistribution_getMinimumNumberCorrect (OTGrammar me, PairDistribution thee,
-	double evaluationNoise, long numberOfReplications);
-double OTGrammar_Distributions_getFractionCorrect (OTGrammar me, Distributions thee, long columnNumber,
-	double evaluationNoise, long numberOfInputs);
+	double evaluationNoise, integer numberOfInputs);
+integer OTGrammar_PairDistribution_getMinimumNumberCorrect (OTGrammar me, PairDistribution thee,
+	double evaluationNoise, integer numberOfReplications);
+double OTGrammar_Distributions_getFractionCorrect (OTGrammar me, Distributions thee, integer columnNumber,
+	double evaluationNoise, integer numberOfInputs);
 
 void OTGrammar_checkIndex (OTGrammar me);
 
@@ -138,13 +138,13 @@ autoOTGrammar OTGrammar_create_metrics (
 void OTGrammar_reset (OTGrammar me, double ranking);
 void OTGrammar_resetToRandomRanking (OTGrammar me, double mean, double standardDeviation);
 void OTGrammar_resetToRandomTotalRanking (OTGrammar me, double maximumRanking, double rankingDistance);
-void OTGrammar_setRanking (OTGrammar me, long constraint, double ranking, double disharmony);
-void OTGrammar_setConstraintPlasticity (OTGrammar me, long constraint, double plasticity);
+void OTGrammar_setRanking (OTGrammar me, integer constraint, double ranking, double disharmony);
+void OTGrammar_setConstraintPlasticity (OTGrammar me, integer constraint, double plasticity);
 
 void OTGrammar_removeConstraint (OTGrammar me, const char32 *constraintName);
 void OTGrammar_removeHarmonicallyBoundedCandidates (OTGrammar me, bool singly);
 void OTGrammar_PairDistribution_listObligatoryRankings (OTGrammar me, PairDistribution thee);
-void OTGrammar_Distributions_listObligatoryRankings (OTGrammar me, Distributions thee, long columnNumber);
+void OTGrammar_Distributions_listObligatoryRankings (OTGrammar me, Distributions thee, integer columnNumber);
 
 void OTGrammar_writeToHeaderlessSpreadsheetFile (OTGrammar me, MelderFile file);
 
diff --git a/gram/OTGrammarEditor.cpp b/gram/OTGrammarEditor.cpp
index ba3055d..d103821 100644
--- a/gram/OTGrammarEditor.cpp
+++ b/gram/OTGrammarEditor.cpp
@@ -1,6 +1,6 @@
 /* OTGrammarEditor.cpp
  *
- * Copyright (C) 1997-2011,2012,2013,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1997-2005,2007-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
@@ -202,7 +202,7 @@ void structOTGrammarEditor :: v_draw () {
 	} else {
 		HyperPage_listItem (this, U"\t\t      %%ranking value\t      %disharmony\t      %plasticity");
 	}
-	for (long icons = 1; icons <= ot -> numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= ot -> numberOfConstraints; icons ++) {
 		OTGrammarConstraint constraint = & ot -> constraints [ot -> index [icons]];
 		if (ot -> decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG ||
 			ot -> decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
@@ -227,7 +227,7 @@ void structOTGrammarEditor :: v_draw () {
 		HyperPage_listItem (this, text);
 	}
 	Graphics_setAtSignIsLink (graphics.get(), false);
-	for (long itab = 1; itab <= ot -> numberOfTableaus; itab ++) {
+	for (integer itab = 1; itab <= ot -> numberOfTableaus; itab ++) {
 		OTGrammarTableau tableau = & ot -> tableaus [itab];
 		double rowHeight = 0.25;
 		double tableauHeight = rowHeight * (tableau -> numberOfCandidates + 2);
diff --git a/gram/OTGrammarEditor.h b/gram/OTGrammarEditor.h
index 84290be..e1af610 100644
--- a/gram/OTGrammarEditor.h
+++ b/gram/OTGrammarEditor.h
@@ -2,7 +2,7 @@
 #define _OTGrammarEditor_h_
 /* OTGrammar.h
  *
- * Copyright (C) 1997-2011,2012,2015 Paul Boersma
+ * Copyright (C) 1997-2005,2007,2009-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
@@ -22,7 +22,7 @@
 #include "OTGrammar.h"
 
 Thing_define (OTGrammarEditor, HyperPage) {
-	long selected;
+	integer selected;
 	bool d_constraintsAreDrawnVertically;
 
 	bool v_editable ()
diff --git a/gram/OTGrammar_def.h b/gram/OTGrammar_def.h
index 766d564..7052e0b 100644
--- a/gram/OTGrammar_def.h
+++ b/gram/OTGrammar_def.h
@@ -1,6 +1,6 @@
 /* OTGrammar_def.h
  *
- * Copyright (C) 1997-2011,2015,2017 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
diff --git a/gram/OTGrammar_ex_NPA.cpp b/gram/OTGrammar_ex_NPA.cpp
index 00317da..1f95d5c 100644
--- a/gram/OTGrammar_ex_NPA.cpp
+++ b/gram/OTGrammar_ex_NPA.cpp
@@ -1,6 +1,6 @@
 /* OTGrammar_ex_NPA.cpp
  *
- * Copyright (C) 1992-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1992-2005,2007,2009,2011,2012,2015,2016 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
diff --git a/gram/OTGrammar_ex_NoCoda.cpp b/gram/OTGrammar_ex_NoCoda.cpp
index 3187690..192b921 100644
--- a/gram/OTGrammar_ex_NoCoda.cpp
+++ b/gram/OTGrammar_ex_NoCoda.cpp
@@ -1,6 +1,6 @@
 /* OTGrammar_ex_NoCoda.cpp
  *
- * Copyright (C) 1997-2011,2015,2016 Paul Boersma
+ * Copyright (C) 1997-2005,2007,2009,2011,2012,2015,2016 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
diff --git a/gram/OTGrammar_ex_metrics.cpp b/gram/OTGrammar_ex_metrics.cpp
index 2457b22..ab48186 100644
--- a/gram/OTGrammar_ex_metrics.cpp
+++ b/gram/OTGrammar_ex_metrics.cpp
@@ -1,6 +1,6 @@
 /* OTGrammar_ex_metrics.cpp
  *
- * Copyright (C) 2001-2011,2014,2015 Paul Boersma
+ * Copyright (C) 2001-2007,2009,2011,2012,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
@@ -65,7 +65,7 @@ static const char32 *constraintNames [1+NUMBER_OF_CONSTRAINTS] = { 0,
 	U"WSP", U"FtNonfinal", U"Iambic", U"Parse", U"FootBin", U"WFL", U"WFR", U"Main-L", U"Main-R", U"AFL", U"AFR", U"Nonfinal",
 	U"Trochaic", U"FtBimor", U"FtBisyl", U"Peripheral", U"MainNonfinal", U"HeadNonfinal", U"*Clash", U"*Lapse", U"WeightByPosition", U"*C\\mu" };
 
-static void addCandidate (OTGrammarTableau me, long numberOfSyllables, int stress [],
+static void addCandidate (OTGrammarTableau me, integer numberOfSyllables, int stress [],
 	bool footedToTheLeft [], bool footedToTheRight [], int surfaceWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
@@ -73,13 +73,13 @@ static void addCandidate (OTGrammarTableau me, long numberOfSyllables, int stres
 	static const char32 *syllableWithoutSecondaryStress [] = { U"L", U"L1", U"L", U"H", U"H1", U"H", U"K", U"K1", U"K", U"J", U"J1", U"J" };
 	char32 output [100];
 	str32cpy (output, U"[");
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		if (isyll > 1) str32cpy (output + str32len (output), U" ");
 		str32cpy (output + str32len (output), ( overtFormsHaveSecondaryStress ? syllable : syllableWithoutSecondaryStress )
 				[stress [isyll] + 3 * (surfaceWeightPattern [isyll] - 1)]);
 	}
 	str32cpy (output + str32len (output), U"] \\-> /");
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		if (isyll > 1) str32cpy (output + str32len (output), U" ");
 		if (footedToTheRight [isyll] || (! footedToTheLeft [isyll] && stress [isyll] != 0)) str32cpy (output + str32len (output), U"(");
 		str32cpy (output + str32len (output), syllable [stress [isyll] + 3 * (surfaceWeightPattern [isyll] - 1)]);
@@ -89,13 +89,13 @@ static void addCandidate (OTGrammarTableau me, long numberOfSyllables, int stres
 	my candidates [++ my numberOfCandidates]. output = Melder_dup (output);
 }
 
-static void fillSurfaceWeightPattern (OTGrammarTableau me, long numberOfSyllables, int stress [],
+static void fillSurfaceWeightPattern (OTGrammarTableau me, integer numberOfSyllables, int stress [],
 	bool footedToTheLeft [], bool footedToTheRight [], int underlyingWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
 	int surfaceWeightPattern [1+7], minSurfaceWeight [1+7], maxSurfaceWeight [1+7];
 	int weight1, weight2, weight3, weight4, weight5;
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		if (underlyingWeightPattern [isyll] < 3) {
 			minSurfaceWeight [isyll] = maxSurfaceWeight [isyll] = underlyingWeightPattern [isyll];   // L -> L; H -> H
 		} else {
@@ -127,17 +127,17 @@ static void fillSurfaceWeightPattern (OTGrammarTableau me, long numberOfSyllable
 	}
 }
 
-static void path (OTGrammarTableau me, long numberOfSyllables, int stress [],
+static void path (OTGrammarTableau me, integer numberOfSyllables, int stress [],
 	int startingSyllable, bool footedToTheLeft_in [], bool footedToTheRight_in [], int underlyingWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
 	bool footedToTheLeft [10], footedToTheRight [10];
 	/* Localize all arguments. */
-	for (long isyll = 1; isyll <= startingSyllable; isyll ++) {
+	for (integer isyll = 1; isyll <= startingSyllable; isyll ++) {
 		footedToTheLeft [isyll] = footedToTheLeft_in [isyll];
 		footedToTheRight [isyll] = footedToTheRight_in [isyll];
 	}
-	for (long isyll = startingSyllable + 1; isyll <= numberOfSyllables; isyll ++)
+	for (integer isyll = startingSyllable + 1; isyll <= numberOfSyllables; isyll ++)
 		footedToTheLeft [isyll] = footedToTheRight [isyll] = 0;
 	if (startingSyllable > numberOfSyllables) {
 		fillSurfaceWeightPattern (me, numberOfSyllables, stress, footedToTheLeft, footedToTheRight, underlyingWeightPattern, overtFormsHaveSecondaryStress);
@@ -163,7 +163,7 @@ static void path (OTGrammarTableau me, long numberOfSyllables, int stress [],
 	}
 }
 
-static void fillOvertStressPattern (OTGrammarTableau me, long numberOfSyllables, int stress [], int underlyingWeightPattern [],
+static void fillOvertStressPattern (OTGrammarTableau me, integer numberOfSyllables, int stress [], int underlyingWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
 	bool footedToTheLeft [10], footedToTheRight [10];
@@ -172,12 +172,12 @@ static void fillOvertStressPattern (OTGrammarTableau me, long numberOfSyllables,
 	path (me, numberOfSyllables, stress, 1, footedToTheLeft, footedToTheRight, underlyingWeightPattern, overtFormsHaveSecondaryStress);
 }
 
-static void fillTableau (OTGrammarTableau me, long numberOfSyllables, int underlyingWeightPattern [], int overtFormsHaveSecondaryStress, int includeCodas) {
+static void fillTableau (OTGrammarTableau me, integer numberOfSyllables, int underlyingWeightPattern [], int overtFormsHaveSecondaryStress, int includeCodas) {
 	char32 input [100];
 	static int numberOfCandidates_noCodas [1+7] = { 0, 1, 6, 24, 88, 300, 984, 3136 };
 	static int numberOfCandidates_codas [1+7] = { 0, 1, 24, 192, 1408, 9600, 984, 3136 };
 	str32cpy (input, U"|");
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		static const char32 *syllable_noCodas [] = { U"", U"L", U"H" };
 		static const char32 *syllable_codas [] = { U"", U"cv", U"cv:", U"cvc" };
 		if (isyll > 1) str32cpy (input + str32len (input), includeCodas ? U"." : U" ");
@@ -186,7 +186,7 @@ static void fillTableau (OTGrammarTableau me, long numberOfSyllables, int underl
 	str32cpy (input + str32len (input), U"|");
 	my input = Melder_dup (input);
 	my candidates = NUMvector <structOTGrammarCandidate> (1, ( includeCodas ? numberOfCandidates_codas : numberOfCandidates_noCodas ) [numberOfSyllables]);
-	for (long mainStressed = 1; mainStressed <= numberOfSyllables; mainStressed ++) {
+	for (integer mainStressed = 1; mainStressed <= numberOfSyllables; mainStressed ++) {
 		int stress [10];
 		stress [mainStressed] = 1;
 		for (int secondary1 = false; secondary1 <= true; secondary1 ++) {
@@ -442,10 +442,10 @@ autoOTGrammar OTGrammar_create_metrics (
 {
 	try {
 		int underlyingWeightPattern [1+7], maximumUnderlyingWeight = includeCodas ? 3 : 2;
-		long numberOfTableaus = includeCodas ? 9 + 27 + 81 + 243 + 2 : 62;
+		integer numberOfTableaus = includeCodas ? 9 + 27 + 81 + 243 + 2 : 62;
 		autoOTGrammar me = Thing_new (OTGrammar);
 		my constraints = NUMvector <structOTGrammarConstraint> (1, my numberOfConstraints = NUMBER_OF_CONSTRAINTS);
-		for (long icons = 1; icons <= NUMBER_OF_CONSTRAINTS; icons ++) {
+		for (integer icons = 1; icons <= NUMBER_OF_CONSTRAINTS; icons ++) {
 			OTGrammarConstraint constraint = & my constraints [icons];
 			constraint -> name = Melder_dup (constraintNames [icons]);
 			constraint -> ranking = 100.0;
@@ -463,17 +463,17 @@ autoOTGrammar OTGrammar_create_metrics (
 		}
 		my tableaus = NUMvector <structOTGrammarTableau> (1, numberOfTableaus);
 		for (int numberOfSyllables = 2; numberOfSyllables <= 7; numberOfSyllables ++) {
-			long numberOfUnderlyingWeightPatterns = numberOfSyllables > 5 ? 1 : lround (pow (maximumUnderlyingWeight, numberOfSyllables));
-			for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+			integer numberOfUnderlyingWeightPatterns = numberOfSyllables > 5 ? 1 : lround (pow (maximumUnderlyingWeight, numberOfSyllables));
+			for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 				underlyingWeightPattern [isyll] = 1;   /* L or cv */
 			}
-			for (long iweightPattern = 1; iweightPattern <= numberOfUnderlyingWeightPatterns; iweightPattern ++) {
+			for (integer iweightPattern = 1; iweightPattern <= numberOfUnderlyingWeightPatterns; iweightPattern ++) {
 				fillTableau (& my tableaus [++ my numberOfTableaus], numberOfSyllables, underlyingWeightPattern, overtFormsHaveSecondaryStress, includeCodas);
 				/*
 				 * Cycle to next underlying weight pattern.
 				 */
 				underlyingWeightPattern [numberOfSyllables] += 1;
-				for (long isyll = numberOfSyllables; isyll >= 2; isyll --) {
+				for (integer isyll = numberOfSyllables; isyll >= 2; isyll --) {
 					if (underlyingWeightPattern [isyll] > maximumUnderlyingWeight) {
 						underlyingWeightPattern [isyll] = 1;
 						underlyingWeightPattern [isyll - 1] += 1;
@@ -482,9 +482,9 @@ autoOTGrammar OTGrammar_create_metrics (
 			}
 		}
 		/* Compute violation marks. */
-		for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+		for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 			OTGrammarTableau tableau = & my tableaus [itab];
-			for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 				computeViolationMarks (& tableau -> candidates [icand]);
 			}
 		}
@@ -517,9 +517,9 @@ autoOTGrammar OTGrammar_create_metrics (
 			OTGrammar_removeConstraint (me.get(), U"*C\\mu");
 		}
 		if (includeCodas) {
-			for (long itab = 1; itab <= my numberOfTableaus; itab ++) {
+			for (integer itab = 1; itab <= my numberOfTableaus; itab ++) {
 				OTGrammarTableau tableau = & my tableaus [itab];
-				for (long icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
+				for (integer icand = 1; icand <= tableau -> numberOfCandidates; icand ++) {
 					replaceOutput (& tableau -> candidates [icand]);
 				}
 			}
diff --git a/gram/OTGrammar_ex_tongueRoot.cpp b/gram/OTGrammar_ex_tongueRoot.cpp
index 93921c4..96bd811 100644
--- a/gram/OTGrammar_ex_tongueRoot.cpp
+++ b/gram/OTGrammar_ex_tongueRoot.cpp
@@ -1,6 +1,6 @@
 /* OTGrammar_ex_tongueRoot.cpp
  *
- * Copyright (C) 1997-2011,2013,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1997-2005,2007,2009,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
@@ -75,13 +75,13 @@ autoOTGrammar OTGrammar_create_tongueRoot_grammar (
 			my constraints [9]. name = Melder_dup (U"*[atr / hi]");
 		}
 		if (equal_random_infant_Wolof == kOTGrammar_createTongueRootGrammar_ranking::EQUAL) {
-			for (long icons = 1; icons <= ncons; icons ++)
+			for (integer icons = 1; icons <= ncons; icons ++)
 				my constraints [icons]. ranking = 100.0;
 		} else if (equal_random_infant_Wolof == kOTGrammar_createTongueRootGrammar_ranking::RANDOM) {
-			for (long icons = 1; icons <= ncons; icons ++)
+			for (integer icons = 1; icons <= ncons; icons ++)
 				my constraints [icons]. ranking = NUMrandomGauss (100.0, 10.0);
 		} else if (equal_random_infant_Wolof == kOTGrammar_createTongueRootGrammar_ranking::INFANT) {
-			for (long icons = 1; icons <= ncons; icons ++)
+			for (integer icons = 1; icons <= ncons; icons ++)
 				my constraints [icons]. ranking = 100.0;   // structural constraints
 			my constraints [3]. ranking = 50.0;   // faithfulness constraints
 			my constraints [4]. ranking = 50.0;
@@ -144,7 +144,7 @@ autoOTGrammar OTGrammar_create_tongueRoot_grammar (
 		}
 		OTGrammar_checkIndex (me.get());
 		OTGrammar_newDisharmonies (me.get(), 0.0);
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++)
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++)
 			my constraints [icons]. plasticity = 1.0;
 		return me;
 	} catch (MelderError) {
diff --git a/gram/OTMulti.cpp b/gram/OTMulti.cpp
index 3672e53..37614d8 100644
--- a/gram/OTMulti.cpp
+++ b/gram/OTMulti.cpp
@@ -1,6 +1,6 @@
 /* OTMulti.cpp
  *
- * Copyright (C) 2005-2012,2013,2015,2016,2017 Paul Boersma
+ * Copyright (C) 2005-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,9 +54,9 @@
 void structOTMulti :: v_info ()
 {
 	structDaata :: v_info ();
-	long numberOfViolations = 0;
-	for (long icand = 1; icand <= numberOfCandidates; icand ++) {
-		for (long icons = 1; icons <= numberOfConstraints; icons ++) {
+	integer numberOfViolations = 0;
+	for (integer icand = 1; icand <= numberOfCandidates; icand ++) {
+		for (integer icons = 1; icons <= numberOfConstraints; icons ++) {
 			numberOfViolations += candidates [icand]. marks [icons];
 		}
 	}
@@ -69,7 +69,7 @@ void structOTMulti :: v_info ()
 void structOTMulti :: v_writeText (MelderFile file) {
 	MelderFile_write (file, U"\n<", kOTGrammar_decisionStrategy_getText (decisionStrategy),
 		U">\n", leak, U" ! leak\n", numberOfConstraints, U" constraints");
-	for (long icons = 1; icons <= numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= numberOfConstraints; icons ++) {
 		OTConstraint constraint = & constraints [icons];
 		MelderFile_write (file, U"\n\t\"");
 		for (const char32 *p = & constraint -> name [0]; *p != U'\0'; p ++) {
@@ -80,7 +80,7 @@ void structOTMulti :: v_writeText (MelderFile file) {
 			U" ", constraint -> disharmony, U" ", constraint -> plasticity);
 	}
 	MelderFile_write (file, U"\n\n", numberOfCandidates, U" candidates");
-	for (long icand = 1; icand <= numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= numberOfCandidates; icand ++) {
 		OTCandidate candidate = & candidates [icand];
 		MelderFile_write (file, U"\n\t\"");
 		for (const char32 *p = & candidate -> string [0]; *p != U'\0'; p ++) {
@@ -88,7 +88,7 @@ void structOTMulti :: v_writeText (MelderFile file) {
 			MelderFile_writeCharacter (file, *p);
 		}
 		MelderFile_write (file, U"\"  ");
-		for (long icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
 			MelderFile_write (file, U" ", candidate -> marks [icons]);
 		}
 	}
@@ -119,7 +119,7 @@ void structOTMulti :: v_readText (MelderReadText text, int formatVersion) {
 	}
 	if ((numberOfConstraints = texgeti32 (text)) < 1) Melder_throw (U"No constraints.");
 	constraints = NUMvector <structOTConstraint> (1, numberOfConstraints);
-	for (long icons = 1; icons <= numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= numberOfConstraints; icons ++) {
 		OTConstraint constraint = & constraints [icons];
 		constraint -> name = texgetw16 (text);
 		constraint -> ranking = texgetr64 (text);
@@ -136,12 +136,12 @@ void structOTMulti :: v_readText (MelderReadText text, int formatVersion) {
 	}
 	if ((numberOfCandidates = texgeti32 (text)) < 1) Melder_throw (U"No candidates.");
 	candidates = NUMvector <structOTCandidate> (1, numberOfCandidates);
-	for (long icand = 1; icand <= numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= numberOfCandidates; icand ++) {
 		OTCandidate candidate = & candidates [icand];
 		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 ++) {
+		for (integer icons = 1; icons <= candidate -> numberOfConstraints; icons ++) {
 			candidate -> marks [icons] = texgeti16 (text);
 		}
 	}
@@ -150,8 +150,8 @@ void structOTMulti :: v_readText (MelderReadText text, int formatVersion) {
 
 Thing_implement (OTMulti, Daata, 2);
 
-long OTMulti_getConstraintIndexFromName (OTMulti me, const char32 *name) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+integer OTMulti_getConstraintIndexFromName (OTMulti me, const char32 *name) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		if (Melder_equ (my constraints [icons]. name, name)) {
 			return icons;
 		}
@@ -179,7 +179,7 @@ static int constraintCompare (const void *first, const void *second) {
 void OTMulti_sort (OTMulti me) {
 	constraintCompare_grammar = me;
 	qsort (& my index [1], my numberOfConstraints, sizeof (integer), constraintCompare);
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTConstraint constraint = & my constraints [my index [icons]];
 		constraint -> tiedToTheLeft = icons > 1 &&
 			my constraints [my index [icons - 1]]. disharmony == constraint -> disharmony;
@@ -189,18 +189,18 @@ void OTMulti_sort (OTMulti me) {
 }
 
 void OTMulti_newDisharmonies (OTMulti me, double evaluationNoise) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTConstraint constraint = & my constraints [icons];
 		constraint -> disharmony = constraint -> ranking + NUMrandomGauss (0, evaluationNoise);
 	}
 	OTMulti_sort (me);
 }
 
-int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2) {
+int OTMulti_compareCandidates (OTMulti me, integer icand1, integer icand2) {
 	int *marks1 = my candidates [icand1]. marks;
 	int *marks2 = my candidates [icand2]. marks;
 	if (my decisionStrategy == kOTGrammar_decisionStrategy::OPTIMALITY_THEORY) {
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int numberOfMarks1 = marks1 [my index [icons]];
 			int numberOfMarks2 = marks2 [my index [icons]];
 			/*
@@ -218,7 +218,7 @@ int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2) {
 		my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY)
 	{
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			disharmony1 += my constraints [icons]. disharmony * marks1 [icons];
 			disharmony2 += my constraints [icons]. disharmony * marks2 [icons];
 		}
@@ -226,7 +226,7 @@ int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2) {
 		if (disharmony1 > disharmony2) return +1;   /* Candidate 2 is better than candidate 1. */
 	} else if (my decisionStrategy == kOTGrammar_decisionStrategy::LINEAR_OT) {
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			if (my constraints [icons]. disharmony > 0.0) {
 				disharmony1 += my constraints [icons]. disharmony * marks1 [icons];
 				disharmony2 += my constraints [icons]. disharmony * marks2 [icons];
@@ -238,7 +238,7 @@ int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2) {
 		my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
 	{
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			disharmony1 += exp (my constraints [icons]. disharmony) * marks1 [icons];
 			disharmony2 += exp (my constraints [icons]. disharmony) * marks2 [icons];
 		}
@@ -246,7 +246,7 @@ int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2) {
 		if (disharmony1 > disharmony2) return +1;   /* Candidate 2 is better than candidate 1. */
 	} else if (my decisionStrategy == kOTGrammar_decisionStrategy::POSITIVE_HG) {
 		double disharmony1 = 0.0, disharmony2 = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			double constraintDisharmony = my constraints [icons]. disharmony > 1.0 ? my constraints [icons]. disharmony : 1.0;
 			disharmony1 += constraintDisharmony * marks1 [icons];
 			disharmony2 += constraintDisharmony * marks2 [icons];
@@ -259,37 +259,37 @@ int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2) {
 	return 0;   /* None of the comparisons found a difference between the two candidates. Hence, they are equally good. */
 }
 
-int OTMulti_candidateMatches (OTMulti me, long icand, const char32 *form1, const char32 *form2) {
+int OTMulti_candidateMatches (OTMulti me, integer icand, const char32 *form1, const char32 *form2) {
 	const char32 *string = my candidates [icand]. string;
 	return (form1 [0] == '\0' || str32str (string, form1)) && (form2 [0] == '\0' || str32str (string, form2));
 }
 
 static void _OTMulti_fillInHarmonies (OTMulti me, const char32 *form1, const char32 *form2) {
 	if (my decisionStrategy == kOTGrammar_decisionStrategy::OPTIMALITY_THEORY) return;
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 		OTCandidate candidate = & my candidates [icand];
 		int *marks = candidate -> marks;
 		double disharmony = 0.0;
 		if (my decisionStrategy == kOTGrammar_decisionStrategy::HARMONIC_GRAMMAR ||
 			my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY)
 		{
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				disharmony += my constraints [icons]. disharmony * marks [icons];
 			}
 		} else if (my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG ||
 			my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
 		{
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				disharmony += exp (my constraints [icons]. disharmony) * marks [icons];
 			}
 		} else if (my decisionStrategy == kOTGrammar_decisionStrategy::LINEAR_OT) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				if (my constraints [icons]. disharmony > 0.0) {
 					disharmony += my constraints [icons]. disharmony * marks [icons];
 				}
 			}
 		} else if (my decisionStrategy == kOTGrammar_decisionStrategy::POSITIVE_HG) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				double constraintDisharmony = my constraints [icons]. disharmony > 1.0 ? my constraints [icons]. disharmony : 1.0;
 				disharmony += constraintDisharmony * marks [icons];
 			}
@@ -302,24 +302,24 @@ static void _OTMulti_fillInHarmonies (OTMulti me, const char32 *form1, const cha
 
 static void _OTMulti_fillInProbabilities (OTMulti me, const char32 *form1, const char32 *form2) {
 	double maximumHarmony = -1e308;
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 		OTCandidate candidate = & my candidates [icand];
 		if (candidate -> harmony > maximumHarmony) {
 			maximumHarmony = candidate -> harmony;
 		}
 	}
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 		OTCandidate candidate = & my candidates [icand];
 		candidate -> probability = exp (candidate -> harmony - maximumHarmony);
 		Melder_assert (candidate -> probability >= 0.0 && candidate -> probability <= 1.0);
 	}
 	double sumOfProbabilities = 0.0;
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 		OTCandidate candidate = & my candidates [icand];
 		sumOfProbabilities += candidate -> probability;
 	}
 	Melder_assert (sumOfProbabilities > 0.0);   // Because at least one of them is 1.0.
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 		OTCandidate candidate = & my candidates [icand];
 		candidate -> probability /= sumOfProbabilities;
 	}
@@ -327,9 +327,9 @@ static void _OTMulti_fillInProbabilities (OTMulti me, const char32 *form1, const
 
 class MelderError_OTMulti_NoMatchingCandidate: public MelderError {};
 
-long OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2) {
+integer OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2) {
 	try {
-		long icand_best = 0;
+		integer icand_best = 0;
 		if (my decisionStrategy == kOTGrammar_decisionStrategy::MAXIMUM_ENTROPY ||
 			my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_MAXIMUM_ENTROPY)
 		{
@@ -337,7 +337,7 @@ long OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2) {
 			_OTMulti_fillInProbabilities (me, form1, form2);
 			double cutOff = NUMrandomUniform (0.0, 1.0);
 			double sumOfProbabilities = 0.0;
-			for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+			for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 				sumOfProbabilities += my candidates [icand]. probability;
 				if (sumOfProbabilities > cutOff) {
 					icand_best = icand;
@@ -345,8 +345,8 @@ long OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2) {
 				}
 			}
 		} else {
-			long numberOfBestCandidates = 0;
-			for (long icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
+			integer numberOfBestCandidates = 0;
+			for (integer icand = 1; icand <= my numberOfCandidates; icand ++) if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 				if (icand_best == 0) {
 					icand_best = icand;
 					numberOfBestCandidates = 1;
@@ -381,7 +381,7 @@ long OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2) {
 	}
 }
 
-static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
+static void OTMulti_modifyRankings (OTMulti me, integer iwinner, integer iloser,
 	kOTGrammar_rerankingStrategy updateRule,
 	double plasticity, double relativePlasticityNoise)
 {
@@ -405,7 +405,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		else if (Melder_debug == 27) multiplyStepByNumberOfViolations = true;   // HG-GLA
 	}
 	if (updateRule == kOTGrammar_rerankingStrategy::SYMMETRIC_ONE) {
-		long icons = NUMrandomInteger (1, my numberOfConstraints);
+		integer icons = NUMrandomInteger (1, my numberOfConstraints);
 		OTConstraint constraint = & my constraints [icons];
 		double constraintStep = step * constraint -> plasticity;
 		int winnerMarks = winner -> marks [icons];
@@ -422,7 +422,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		}
 	} else if (updateRule == kOTGrammar_rerankingStrategy::SYMMETRIC_ALL) {
 		bool changed = false;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			double constraintStep = step * constraint -> plasticity;
 			int winnerMarks = winner -> marks [icons];
@@ -440,11 +440,11 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		}
 		if (changed && my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG) {
 			double sumOfWeights = 0.0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				sumOfWeights += my constraints [icons]. ranking;
 			}
 			double averageWeight = sumOfWeights / my numberOfConstraints;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				my constraints [icons]. ranking -= averageWeight;
 			}
 		}
@@ -452,13 +452,13 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 	} else if (updateRule == kOTGrammar_rerankingStrategy::SYMMETRIC_ALL_SKIPPABLE) {
 		bool changed = false;
 		int winningConstraints = 0, losingConstraints = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [icons];
 			int loserMarks = loser -> marks [icons];
 			if (loserMarks > winnerMarks) losingConstraints ++;
 			if (winnerMarks > loserMarks) winningConstraints ++;
 		}
-		if (winningConstraints != 0) for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		if (winningConstraints != 0) for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			double constraintStep = step * constraint -> plasticity;
 			int winnerMarks = winner -> marks [icons];
@@ -476,25 +476,25 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		}
 		if (changed && my decisionStrategy == kOTGrammar_decisionStrategy::EXPONENTIAL_HG) {
 			double sumOfWeights = 0.0;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				sumOfWeights += my constraints [icons]. ranking;
 			}
 			double averageWeight = sumOfWeights / my numberOfConstraints;
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				my constraints [icons]. ranking -= averageWeight;
 			}
 		}
 		if (grammarHasChanged) *grammarHasChanged = changed;
 	} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_UNCANCELLED) {
 		int winningConstraints = 0, losingConstraints = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [icons];
 			int loserMarks = loser -> marks [icons];
 			if (loserMarks > winnerMarks) losingConstraints ++;
 			if (winnerMarks > loserMarks) winningConstraints ++;
 		}
 		if (winningConstraints != 0) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -515,13 +515,13 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		}
 	} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL) {
 		int winningConstraints = 0, losingConstraints = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [icons];
 			int loserMarks = loser -> marks [icons];
 			if (loserMarks > 0) losingConstraints ++;
 			if (winnerMarks > 0) winningConstraints ++;
 		}
-		if (winningConstraints != 0) for (long icons = 1; icons <= my numberOfConstraints; icons ++)  {
+		if (winningConstraints != 0) for (integer icons = 1; icons <= my numberOfConstraints; icons ++)  {
 			OTConstraint constraint = & my constraints [icons];
 			double constraintStep = step * constraint -> plasticity;
 			int winnerMarks = winner -> marks [icons];
@@ -543,7 +543,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		 */
 		double pivotRanking;
 		bool equivalent = true;
-		long icons = 1;
+		integer icons = 1;
 		for (; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [my index [icons]];   // order is important, so indirect
 			int loserMarks = loser -> marks [my index [icons]];
@@ -561,7 +561,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		 */
 		pivotRanking = my constraints [my index [icons]]. ranking;
 		if (updateRule == kOTGrammar_rerankingStrategy::EDCD_WITH_VACATION) {
-			long numberOfConstraintsToDemote = 0;
+			integer numberOfConstraintsToDemote = 0;
 			for (icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int winnerMarks = winner -> marks [icons];
 				int loserMarks = loser -> marks [icons];
@@ -587,7 +587,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		 * that have rankings not lower than the pivot.
 		 */
 		for (icons = 1; icons <= my numberOfConstraints; icons ++) {
-			long numberOfConstraintsDemoted = 0;
+			integer numberOfConstraintsDemoted = 0;
 			int winnerMarks = winner -> marks [my index [icons]];   // For the vacation version, the order is important, so indirect.
 			int loserMarks = loser -> marks [my index [icons]];
 			if (loserMarks > winnerMarks) {
@@ -604,9 +604,9 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		/*
 		 * Determine the crucial loser mark.
 		 */
-		long crucialLoserMark;
+		integer crucialLoserMark;
 		OTConstraint offendingConstraint;
-		long icons = 1;
+		integer icons = 1;
 		for (; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [my index [icons]];   /* Order is important, so indirect. */
 			int loserMarks = loser -> marks [my index [icons]];
@@ -639,8 +639,8 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		}
 	} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGHEST_DOWN) {
 		bool changed = false;
-		long numberOfUp = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		integer numberOfUp = 0;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [icons];
 			int loserMarks = loser -> marks [icons];
 			if (winnerMarks > loserMarks) {
@@ -648,7 +648,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 			}
 		}
 		if (numberOfUp > 0) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -658,9 +658,9 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 					constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) / numberOfUp;
 				}
 			}
-			long crucialLoserMark, winnerMarks = 0, loserMarks = 0;
+			integer crucialLoserMark, winnerMarks = 0, loserMarks = 0;
 			OTConstraint offendingConstraint;
-			long icons = 1;
+			integer icons = 1;
 			for (; icons <= my numberOfConstraints; icons ++) {
 				winnerMarks = winner -> marks [my index [icons]];   // order is important, so indirect
 				loserMarks = loser -> marks [my index [icons]];
@@ -695,8 +695,8 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		if (grammarHasChanged) *grammarHasChanged = changed;
 	} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGHEST_DOWN_2012) {
 		bool changed = false;
-		long numberOfUp = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		integer numberOfUp = 0;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [icons];
 			int loserMarks = loser -> marks [icons];
 			if (winnerMarks > loserMarks) {
@@ -704,7 +704,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 			}
 		}
 		if (/*true ||*/ numberOfUp > 0) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				OTConstraint constraint = & my constraints [icons];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [icons];
@@ -714,9 +714,9 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 					constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) / (numberOfUp + 1);
 				}
 			}
-			long crucialLoserMark, winnerMarks = 0, loserMarks = 0;
+			integer crucialLoserMark, winnerMarks = 0, loserMarks = 0;
 			OTConstraint offendingConstraint;
-			long icons = 1;
+			integer icons = 1;
 			for (; icons <= my numberOfConstraints; icons ++) {
 				winnerMarks = winner -> marks [my index [icons]];   /* Order is important, so indirect. */
 				loserMarks = loser -> marks [my index [icons]];
@@ -750,8 +750,8 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 		}
 		if (grammarHasChanged) *grammarHasChanged = changed;
 	} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGH_DOWN) {
-		long numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		integer numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 			int loserMarks = loser -> marks [my index [icons]];
 			if (loserMarks < winnerMarks) {
@@ -764,8 +764,8 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 			}
 		}
 		if (numberOfUp > 0) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
-				long constraintIndex = my index [icons];
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
+				integer constraintIndex = my index [icons];
 				OTConstraint constraint = & my constraints [constraintIndex];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [constraintIndex];   // the order is important, therefore indirect
@@ -785,8 +785,8 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 			if (grammarHasChanged) *grammarHasChanged = true;
 		}
 	} else if (updateRule == kOTGrammar_rerankingStrategy::WEIGHTED_ALL_UP_HIGH_DOWN_2012) {
-		long numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		integer numberOfDown = 0, numberOfUp = 0, lowestDemotableConstraint = 0;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int winnerMarks = winner -> marks [my index [icons]];   // the order is important, therefore indirect
 			int loserMarks = loser -> marks [my index [icons]];
 			if (loserMarks < winnerMarks) {
@@ -799,8 +799,8 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 			}
 		}
 		if (numberOfUp > 0) {
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
-				long constraintIndex = my index [icons];
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
+				integer constraintIndex = my index [icons];
 				OTConstraint constraint = & my constraints [constraintIndex];
 				double constraintStep = step * constraint -> plasticity;
 				int winnerMarks = winner -> marks [constraintIndex];   // the order is important, therefore indirect
@@ -825,37 +825,37 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
 int OTMulti_learnOne (OTMulti me, const char32 *form1, const char32 *form2,
 	enum kOTGrammar_rerankingStrategy updateRule, int direction, double plasticity, double relativePlasticityNoise)
 {
-	long iloser = OTMulti_getWinner (me, form1, form2);
+	integer iloser = OTMulti_getWinner (me, form1, form2);
 	if (direction & OTMulti_LEARN_FORWARD) {
 		if (Melder_debug == 47) OTMulti_newDisharmonies (me, 2.0);
-		long iwinner = OTMulti_getWinner (me, form1, U"");
+		integer iwinner = OTMulti_getWinner (me, form1, U"");
 		if (Melder_debug != 47 || ! OTMulti_candidateMatches (me, iwinner, form2, U""))
 			OTMulti_modifyRankings (me, iwinner, iloser, updateRule, plasticity, relativePlasticityNoise);
 	}
 	if (direction & OTMulti_LEARN_BACKWARD) {
 		if (Melder_debug == 47) OTMulti_newDisharmonies (me, 2.0);
-		long iwinner = OTMulti_getWinner (me, form2, U"");
+		integer iwinner = OTMulti_getWinner (me, form2, U"");
 		if (Melder_debug != 47 || ! OTMulti_candidateMatches (me, iwinner, form1, U""))
 			OTMulti_modifyRankings (me, iwinner, iloser, updateRule, plasticity, relativePlasticityNoise);
 	}
 	return 1;
 }
 
-static autoTable OTMulti_createHistory (OTMulti me, long storeHistoryEvery, long numberOfData)
+static autoTable OTMulti_createHistory (OTMulti me, integer storeHistoryEvery, integer numberOfData)
 {
 	try {
-		long numberOfSamplingPoints = numberOfData / storeHistoryEvery;   // e.g. 0, 20, 40, ...
+		integer numberOfSamplingPoints = numberOfData / storeHistoryEvery;   // e.g. 0, 20, 40, ...
 		autoTable thee = Table_createWithoutColumnNames (1 + numberOfSamplingPoints, 3 + my numberOfConstraints);
 		Table_setColumnLabel (thee.get(), 1, U"Datum");
 		Table_setColumnLabel (thee.get(), 2, U"Form1");
 		Table_setColumnLabel (thee.get(), 3, U"Form2");
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			Table_setColumnLabel (thee.get(), 3 + icons, my constraints [icons]. name);
 		}
 		Table_setNumericValue (thee.get(), 1, 1, 0);
 		Table_setStringValue (thee.get(), 1, 2, U"(initial)");
 		Table_setStringValue (thee.get(), 1, 3, U"(initial)");
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			Table_setNumericValue (thee.get(), 1, 3 + icons, my constraints [icons]. ranking);
 		}
 		return thee;
@@ -864,15 +864,15 @@ static autoTable OTMulti_createHistory (OTMulti me, long storeHistoryEvery, long
 	}
 }
 
-static int OTMulti_updateHistory (OTMulti me, Table thee, long storeHistoryEvery, long idatum, const char32 *form1, const char32 *form2)
+static int OTMulti_updateHistory (OTMulti me, Table thee, integer storeHistoryEvery, integer idatum, const char32 *form1, const char32 *form2)
 {
 	try {
 		if (idatum % storeHistoryEvery == 0) {
-			long irow = 1 + idatum / storeHistoryEvery;
+			integer irow = 1 + idatum / storeHistoryEvery;
 			Table_setNumericValue (thee, irow, 1, idatum);
 			Table_setStringValue (thee, irow, 2, form1);
 			Table_setStringValue (thee, irow, 3, form2);
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				Table_setNumericValue (thee, irow, 3 + icons, my constraints [icons]. ranking);
 			}
 		}
@@ -884,10 +884,10 @@ static int OTMulti_updateHistory (OTMulti me, Table thee, long storeHistoryEvery
 
 
 void OTMulti_PairDistribution_learn (OTMulti me, PairDistribution thee, double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, int direction,
-	double initialPlasticity, long replicationsPerPlasticity, double plasticityDecrement,
-	long numberOfPlasticities, double relativePlasticityNoise, long storeHistoryEvery, autoTable *history_out)
+	double initialPlasticity, integer replicationsPerPlasticity, double plasticityDecrement,
+	integer numberOfPlasticities, double relativePlasticityNoise, integer storeHistoryEvery, autoTable *history_out)
 {
-	long idatum = 0, numberOfData = numberOfPlasticities * replicationsPerPlasticity;
+	integer idatum = 0, numberOfData = numberOfPlasticities * replicationsPerPlasticity;
 	try {
 		double plasticity = initialPlasticity;
 		autoMelderMonitor monitor (U"Learning from partial pairs...");
@@ -898,22 +898,22 @@ void OTMulti_PairDistribution_learn (OTMulti me, PairDistribution thee, double e
 		if (storeHistoryEvery) {
 			history = OTMulti_createHistory (me, storeHistoryEvery, numberOfData);
 		}
-		for (long iplasticity = 1; iplasticity <= numberOfPlasticities; iplasticity ++) {
-			for (long ireplication = 1; ireplication <= replicationsPerPlasticity; ireplication ++) {
+		for (integer iplasticity = 1; iplasticity <= numberOfPlasticities; iplasticity ++) {
+			for (integer ireplication = 1; ireplication <= replicationsPerPlasticity; ireplication ++) {
 				char32 *form1, *form2;
 				PairDistribution_peekPair (thee, & form1, & form2);
 				++ idatum;
 				if (monitor.graphics() && idatum % (numberOfData / 400 + 1) == 0) {
-					long numberOfDrawnConstraints = my numberOfConstraints < 14 ? my numberOfConstraints : 14;
+					integer numberOfDrawnConstraints = my numberOfConstraints < 14 ? my numberOfConstraints : 14;
 					if (numberOfDrawnConstraints > 0) {
 						double sumOfRankings = 0.0;
-						for (long icons = 1; icons <= numberOfDrawnConstraints; icons ++) {
+						for (integer icons = 1; icons <= numberOfDrawnConstraints; icons ++) {
 							sumOfRankings += my constraints [icons]. ranking;
 						}
 						double meanRanking = sumOfRankings / numberOfDrawnConstraints;
 						Graphics_beginMovieFrame (monitor.graphics(), nullptr);
 						Graphics_setWindow (monitor.graphics(), 0, numberOfData, meanRanking - 50, meanRanking + 50);
-						for (long icons = 1; icons <= numberOfDrawnConstraints; icons ++) {
+						for (integer icons = 1; icons <= numberOfDrawnConstraints; icons ++) {
 							Graphics_setGrey (monitor.graphics(), (double) icons / numberOfDrawnConstraints);
 							Graphics_line (monitor.graphics(), idatum, my constraints [icons]. ranking,
 								idatum, my constraints [icons]. ranking+1);
@@ -954,15 +954,15 @@ void OTMulti_PairDistribution_learn (OTMulti me, PairDistribution thee, double e
 	}
 }
 
-static long OTMulti_crucialCell (OTMulti me, long icand, long iwinner, long numberOfOptimalCandidates, const char32 *form1, const char32 *form2)
+static integer OTMulti_crucialCell (OTMulti me, integer icand, integer iwinner, integer numberOfOptimalCandidates, const char32 *form1, const char32 *form2)
 {
 	if (my numberOfCandidates < 2) return 0;   // if there is only one candidate, all cells can be greyed
 	if (OTMulti_compareCandidates (me, icand, iwinner) == 0) {   // candidate equally good as winner?
 		if (numberOfOptimalCandidates > 1) {
 			/* All cells are important. */
 		} else {
-			long secondBest = 0;
-			for (long jcand = 1; jcand <= my numberOfCandidates; jcand ++) {
+			integer secondBest = 0;
+			for (integer jcand = 1; jcand <= my numberOfCandidates; jcand ++) {
 				if (OTMulti_candidateMatches (me, jcand, form1, form2) && OTMulti_compareCandidates (me, jcand, iwinner) != 0) {   // a non-optimal candidate?
 					if (secondBest == 0) {
 						secondBest = jcand;   // first guess
@@ -977,7 +977,7 @@ static long OTMulti_crucialCell (OTMulti me, long icand, long iwinner, long numb
 	} else {
 		int *candidateMarks = my candidates [icand]. marks;
 		int *winnerMarks = my candidates [iwinner]. marks;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int numberOfCandidateMarks = candidateMarks [my index [icons]];
 			int numberOfWinnerMarks = winnerMarks [my index [icons]];
 			if (numberOfCandidateMarks > numberOfWinnerMarks) {
@@ -1008,7 +1008,7 @@ static double OTMulti_constraintWidth (Graphics g, OTConstraint constraint, bool
 }
 
 void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const char32 *form2, bool vertical, bool showDisharmonies) {
-	long winner, winner1 = 0, winner2 = 0;
+	integer winner, winner1 = 0, winner2 = 0;
 	double x, y, fontSize = Graphics_inqFontSize (g);
 	Graphics_Colour colour = Graphics_inqColour (g);
 	char32 text [200];
@@ -1042,7 +1042,7 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 	double headerHeight;
 	if (vertical) {
 		headerHeight = 0.0;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			double constraintTextWidth = Graphics_textWidth (g, constraint -> name);
 			if (constraintTextWidth > headerHeight)
@@ -1052,7 +1052,7 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 		headerHeight *= worldAspectRatio;
 	} else {
 		headerHeight = rowHeight;
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			if (str32chr (constraint -> name, U'\n')) {
 				headerHeight += 0.7 * rowHeight;
@@ -1065,11 +1065,11 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 	 * Also count the number of optimal candidates (if there are more than one, the fingers will be drawn in red).
 	 */
 	double candWidth = Graphics_textWidth_ps (g, form1, true) + Graphics_textWidth_ps (g, form2, true);
-	long numberOfMatchingCandidates = 0;
-	long numberOfOptimalCandidates = 0;
-	long numberOfOptimalCandidates1 = 0;
-	long numberOfOptimalCandidates2 = 0;
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++) {
+	integer numberOfMatchingCandidates = 0;
+	integer numberOfOptimalCandidates = 0;
+	integer numberOfOptimalCandidates1 = 0;
+	integer numberOfOptimalCandidates2 = 0;
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++) {
 		if ((form1 [0] != U'\0' && OTMulti_candidateMatches (me, icand, form1, U"")) ||
 		    (form2 [0] != U'\0' && OTMulti_candidateMatches (me, icand, form2, U"")) ||
 		    (form1 [0] == U'\0' && form2 [0] == U'\0'))
@@ -1096,7 +1096,7 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 	if (vertical) {
 		tableauWidth += rowHeight * my numberOfConstraints / worldAspectRatio;
 	} else {
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			tableauWidth += OTMulti_constraintWidth (g, constraint, showDisharmonies);
 		}
@@ -1122,7 +1122,7 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 	 */
 	x += candWidth + doubleLineDx;
 	if (vertical) Graphics_setTextRotation (g, 90.0);
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTConstraint constraint = & my constraints [my index [icons]];
 		double width = vertical ? rowHeight / worldAspectRatio : OTMulti_constraintWidth (g, constraint, showDisharmonies) + margin * 2;
 		if (str32chr (constraint -> name, U'\n')) {
@@ -1156,12 +1156,12 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 	 * Draw candidates.
 	 */
 	y -= doubleLineDy;
-	for (long icand = 1; icand <= my numberOfCandidates; icand ++)
+	for (integer icand = 1; icand <= my numberOfCandidates; icand ++)
 		if ((form1 [0] != U'\0' && OTMulti_candidateMatches (me, icand, form1, U"")) ||
 		    (form2 [0] != U'\0' && OTMulti_candidateMatches (me, icand, form2, U"")) ||
 		    (form1 [0] == U'\0' && form2 [0] == U'\0'))
 	{
-		long crucialCell = OTMulti_crucialCell (me, icand, winner, numberOfOptimalCandidates, form1, form2);
+		integer crucialCell = OTMulti_crucialCell (me, icand, winner, numberOfOptimalCandidates, form1, form2);
 		int candidateIsOptimal = OTMulti_compareCandidates (me, icand, winner) == 0;
 		int candidateIsOptimal1 = winner1 != 0 && OTMulti_compareCandidates (me, icand, winner1) == 0;
 		int candidateIsOptimal2 = winner2 != 0 && OTMulti_compareCandidates (me, icand, winner2) == 0;
@@ -1205,7 +1205,7 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 		if (! bidirectional && my decisionStrategy == kOTGrammar_decisionStrategy::OPTIMALITY_THEORY) {
 			x = candWidth + 2 * doubleLineDx;
 			Graphics_setGrey (g, 0.9);
-			for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 				int index = my index [icons];
 				OTConstraint constraint = & my constraints [index];
 				double width = vertical ? rowHeight / worldAspectRatio : OTMulti_constraintWidth (g, constraint, showDisharmonies) + margin * 2;
@@ -1220,7 +1220,7 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 		 */
 		x = candWidth + 2 * doubleLineDx;
 		Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			int index = my index [icons];
 			OTConstraint constraint = & my constraints [index];
 			double width = vertical ? rowHeight / worldAspectRatio : OTMulti_constraintWidth (g, constraint, showDisharmonies) + margin * 2;
@@ -1251,25 +1251,25 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 				if (winnerMarks + 1 > 5) {
 					str32cpy (markString + str32len (markString), Melder_integer (winnerMarks + 1));
 				} else {
-					for (long imark = 1; imark <= winnerMarks + 1; imark ++)
+					for (integer imark = 1; imark <= winnerMarks + 1; imark ++)
 						str32cpy (markString + str32len (markString), U"*");
 				}
-				for (long imark = my candidates [icand]. marks [index]; imark < 0; imark ++)
+				for (integer imark = my candidates [icand]. marks [index]; imark < 0; imark ++)
 					str32cpy (markString + str32len (markString), U"+");
 				str32cpy (markString + str32len (markString), U"!");
 				if (my candidates [icand]. marks [index] - (winnerMarks + 2) + 1 > 5) {
 					str32cpy (markString + str32len (markString), Melder_integer (my candidates [icand]. marks [index] - (winnerMarks + 2) + 1));
 				} else {
-					for (long imark = winnerMarks + 2; imark <= my candidates [icand]. marks [index]; imark ++)
+					for (integer imark = winnerMarks + 2; imark <= my candidates [icand]. marks [index]; imark ++)
 						str32cpy (markString + str32len (markString), U"*");
 				}
 			} else {
 				if (my candidates [icand]. marks [index] > 5) {
 					str32cpy (markString + str32len (markString), Melder_integer (my candidates [icand]. marks [index]));
 				} else {
-					for (long imark = 1; imark <= my candidates [icand]. marks [index]; imark ++)
+					for (integer imark = 1; imark <= my candidates [icand]. marks [index]; imark ++)
 						str32cpy (markString + str32len (markString), U"*");
-					for (long imark = my candidates [icand]. marks [index]; imark < 0; imark ++)
+					for (integer imark = my candidates [icand]. marks [index]; imark < 0; imark ++)
 						str32cpy (markString + str32len (markString), U"+");
 				}
 			}
@@ -1304,14 +1304,14 @@ void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const cha
 }
 
 void OTMulti_reset (OTMulti me, double ranking) {
-	for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 		OTConstraint constraint = & my constraints [icons];
 		constraint -> disharmony = constraint -> ranking = ranking;
 	}
 	OTMulti_sort (me);
 }
 
-void OTMulti_setRanking (OTMulti me, long constraint, double ranking, double disharmony) {
+void OTMulti_setRanking (OTMulti me, integer constraint, double ranking, double disharmony) {
 	try {
 		if (constraint < 1)
 			Melder_throw (U"The constraint number should be positive, not ", constraint, U".");
@@ -1325,7 +1325,7 @@ void OTMulti_setRanking (OTMulti me, long constraint, double ranking, double dis
 	}
 }
 
-void OTMulti_setConstraintPlasticity (OTMulti me, long constraint, double plasticity) {
+void OTMulti_setConstraintPlasticity (OTMulti me, integer constraint, double plasticity) {
 	try {
 		if (constraint < 1)
 			Melder_throw (U"The constraint number should be positive, not ", constraint, U".");
@@ -1339,7 +1339,7 @@ void OTMulti_setConstraintPlasticity (OTMulti me, long constraint, double plasti
 
 void OTMulti_removeConstraint (OTMulti me, const char32 *constraintName) {
 	try {
-		long removed = 0;
+		integer removed = 0;
 
 		if (my numberOfConstraints <= 1)
 			Melder_throw (me, U": cannot remove last constraint.");
@@ -1347,7 +1347,7 @@ void OTMulti_removeConstraint (OTMulti me, const char32 *constraintName) {
 		/*
 		 * Look for the constraint to be removed.
 		 */
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			if (str32equ (constraint -> name, constraintName)) {
 				removed = icons;
@@ -1364,23 +1364,23 @@ void OTMulti_removeConstraint (OTMulti me, const char32 *constraintName) {
 		 * Shift constraints.
 		 */
 		Melder_free (my constraints [removed]. name);
-		for (long icons = removed; icons <= my numberOfConstraints; icons ++) {
+		for (integer icons = removed; icons <= my numberOfConstraints; icons ++) {
 			my constraints [icons] = my constraints [icons + 1];
 		}
 		/*
 		 * Shift tableau rows.
 		 */
-		for (long icand = 1; icand <= my numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= my numberOfCandidates; icand ++) {
 			OTCandidate candidate = & my candidates [icand];
 			candidate -> numberOfConstraints -= 1;
-			for (long icons = removed; icons <= my numberOfConstraints; icons ++) {
+			for (integer icons = removed; icons <= my numberOfConstraints; icons ++) {
 				candidate -> marks [icons] = candidate -> marks [icons + 1];
 			}
 		}
 		/*
 		 * Rebuild index.
 		 */
-		for (long icons = 1; icons <= my numberOfConstraints; icons ++) my index [icons] = icons;
+		for (integer icons = 1; icons <= my numberOfConstraints; icons ++) my index [icons] = icons;
 		OTMulti_sort (me);
 	} catch (MelderError) {
 		Melder_throw (me, U": constraint not removed.");
@@ -1390,7 +1390,7 @@ void OTMulti_removeConstraint (OTMulti me, const char32 *constraintName) {
 void OTMulti_generateOptimalForm (OTMulti me, const char32 *form1, const char32 *form2, char32 *optimalForm, double evaluationNoise) {
 	try {
 		OTMulti_newDisharmonies (me, evaluationNoise);
-		long winner = OTMulti_getWinner (me, form1, form2);
+		integer winner = OTMulti_getWinner (me, form1, form2);
 		str32cpy (optimalForm, my candidates [winner]. string);
 	} catch (MelderError) {
 		Melder_throw (me, U": optimal form not generated.");
@@ -1400,10 +1400,10 @@ void OTMulti_generateOptimalForm (OTMulti me, const char32 *form1, const char32
 autoStrings OTMulti_Strings_generateOptimalForms (OTMulti me, Strings thee, double evaluationNoise) {
 	try {
 		autoStrings outputs = Thing_new (Strings);
-		long n = thy numberOfStrings;
+		integer n = thy numberOfStrings;
 		outputs -> numberOfStrings = n;
 		outputs -> strings = NUMvector <char32 *> (1, n);
-		for (long i = 1; i <= n; i ++) {
+		for (integer i = 1; i <= n; i ++) {
 			char32 output [100];
 			OTMulti_generateOptimalForm (me, thy strings [i], U"", output, evaluationNoise);
 			outputs -> strings [i] = Melder_dup (output);
@@ -1414,12 +1414,12 @@ autoStrings OTMulti_Strings_generateOptimalForms (OTMulti me, Strings thee, doub
 	}
 }
 
-autoStrings OTMulti_generateOptimalForms (OTMulti me, const char32 *form1, const char32 *form2, long numberOfTrials, double evaluationNoise) {
+autoStrings OTMulti_generateOptimalForms (OTMulti me, const char32 *form1, const char32 *form2, integer numberOfTrials, double evaluationNoise) {
 	try {
 		autoStrings outputs = Thing_new (Strings);
 		outputs -> numberOfStrings = numberOfTrials;
 		outputs -> strings = NUMvector <char32 *> (1, numberOfTrials);
-		for (long i = 1; i <= numberOfTrials; i ++) {
+		for (integer i = 1; i <= numberOfTrials; i ++) {
 			char32 output [100];
 			OTMulti_generateOptimalForm (me, form1, form2, output, evaluationNoise);
 			outputs -> strings [i] = Melder_dup (output);
@@ -1431,14 +1431,14 @@ autoStrings OTMulti_generateOptimalForms (OTMulti me, const char32 *form1, const
 }
 
 autoDistributions OTMulti_to_Distribution (OTMulti me, const char32 *form1, const char32 *form2,
-	long numberOfTrials, double evaluationNoise)
+	integer numberOfTrials, double evaluationNoise)
 {
 	try {
-		long totalNumberOfOutputs = 0, iout = 0;
+		integer totalNumberOfOutputs = 0, iout = 0;
 		/*
 		 * Count the total number of outputs.
 		 */
-		for (long icand = 1; icand <= my numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= my numberOfCandidates; icand ++) {
 			if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 				totalNumberOfOutputs ++;
 			}
@@ -1447,12 +1447,12 @@ autoDistributions OTMulti_to_Distribution (OTMulti me, const char32 *form1, cons
 		 * Create the distribution. One row for every output form.
 		 */
 		autoDistributions thee = Distributions_create (totalNumberOfOutputs, 1);
-		autoNUMvector <long> index (1, my numberOfCandidates);
+		autoNUMvector <integer> index (1, my numberOfCandidates);
 		/*
 		 * Set the row labels to the output strings.
 		 */
 		iout = 0;
-		for (long icand = 1; icand <= my numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= my numberOfCandidates; icand ++) {
 			if (OTMulti_candidateMatches (me, icand, form1, form2)) {
 				thy rowLabels [++ iout] = Melder_dup (my candidates [icand]. string);
 				index [icand] = iout;
@@ -1461,9 +1461,9 @@ autoDistributions OTMulti_to_Distribution (OTMulti me, const char32 *form1, cons
 		/*
 		 * Compute a number of outputs and store the results.
 		 */
-		for (long itrial = 1; itrial <= numberOfTrials; itrial ++) {
+		for (integer itrial = 1; itrial <= numberOfTrials; itrial ++) {
 			OTMulti_newDisharmonies (me, evaluationNoise);
-			long iwinner = OTMulti_getWinner (me, form1, form2);
+			integer iwinner = OTMulti_getWinner (me, form1, form2);
 			thy data [index [iwinner]] [1] += 1;
 		}
 		return thee;
diff --git a/gram/OTMulti.h b/gram/OTMulti.h
index 292ef1a..e889c7b 100644
--- a/gram/OTMulti.h
+++ b/gram/OTMulti.h
@@ -2,7 +2,7 @@
 #define _OTMulti_h_
 /* OTMulti.h
  *
- * Copyright (C) 2005-2011,2014,2015,2017 Paul Boersma
+ * Copyright (C) 2005-2009,2011,2012,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
@@ -25,7 +25,7 @@
 
 #include "OTMulti_def.h"
 
-long OTMulti_getConstraintIndexFromName (OTMulti me, const char32 *name);
+integer OTMulti_getConstraintIndexFromName (OTMulti me, const char32 *name);
 
 void OTMulti_checkIndex (OTMulti me);
 
@@ -38,9 +38,9 @@ void OTMulti_sort (OTMulti me);
 
 void OTMulti_newDisharmonies (OTMulti me, double evaluationNoise);
 
-int OTMulti_candidateMatches (OTMulti me, long icand, const char32 *form1, const char32 *form2);
-int OTMulti_compareCandidates (OTMulti me, long icand1, long icand2);
-long OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2);
+int OTMulti_candidateMatches (OTMulti me, integer icand, const char32 *form1, const char32 *form2);
+int OTMulti_compareCandidates (OTMulti me, integer icand1, integer icand2);
+integer OTMulti_getWinner (OTMulti me, const char32 *form1, const char32 *form2);
 
 #define OTMulti_LEARN_FORWARD  1
 #define OTMulti_LEARN_BACKWARD  2
@@ -49,8 +49,8 @@ int OTMulti_learnOne (OTMulti me, const char32 *form1, const char32 *form2,
 	enum kOTGrammar_rerankingStrategy updateRule, int direction, double plasticity, double relativePlasticityNoise);
 void OTMulti_PairDistribution_learn (OTMulti me, PairDistribution thee,
 	double evaluationNoise, enum kOTGrammar_rerankingStrategy updateRule, int direction,
-	double initialPlasticity, long replicationsPerPlasticity, double plasticityDecrement,
-	long numberOfPlasticities, double relativePlasticityNoise, long storeHistoryEvery, autoTable *history_out);
+	double initialPlasticity, integer replicationsPerPlasticity, double plasticityDecrement,
+	integer numberOfPlasticities, double relativePlasticityNoise, integer storeHistoryEvery, autoTable *history_out);
 
 void OTMulti_drawTableau (OTMulti me, Graphics g, const char32 *form1, const char32 *form2, bool vertical, bool showDisharmonies);
 
@@ -61,13 +61,13 @@ autoOTMulti OTMulti_create_metrics (
 	int includeClashAndLapse, int includeCodas);
 
 void OTMulti_reset (OTMulti me, double ranking);
-void OTMulti_setRanking (OTMulti me, long constraint, double ranking, double disharmony);
-void OTMulti_setConstraintPlasticity (OTMulti me, long constraint, double plasticity);
+void OTMulti_setRanking (OTMulti me, integer constraint, double ranking, double disharmony);
+void OTMulti_setConstraintPlasticity (OTMulti me, integer constraint, double plasticity);
 void OTMulti_removeConstraint (OTMulti me, const char32 *constraintName);
 
 void OTMulti_generateOptimalForm (OTMulti me, const char32 *form1, const char32 *form2, char32 *optimalForm, double evaluationNoise);
-autoStrings OTMulti_generateOptimalForms (OTMulti me, const char32 *form1, const char32 *form2, long numberOfTrials, double evaluationNoise);
-autoDistributions OTMulti_to_Distribution (OTMulti me, const char32 *form1, const char32 *form2, long numberOfTrials, double evaluationNoise);
+autoStrings OTMulti_generateOptimalForms (OTMulti me, const char32 *form1, const char32 *form2, integer numberOfTrials, double evaluationNoise);
+autoDistributions OTMulti_to_Distribution (OTMulti me, const char32 *form1, const char32 *form2, integer numberOfTrials, double evaluationNoise);
 autoStrings OTMulti_Strings_generateOptimalForms (OTMulti me, Strings forms, double evaluationNoise);
 
 /* End of file OTMulti.h */
diff --git a/gram/OTMultiEditor.cpp b/gram/OTMultiEditor.cpp
index 1798ede..391e954 100644
--- a/gram/OTMultiEditor.cpp
+++ b/gram/OTMultiEditor.cpp
@@ -1,6 +1,6 @@
 /* OTMultiEditor.cpp
  *
- * Copyright (C) 2005-2011,2012,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 2005-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
@@ -191,7 +191,7 @@ void structOTMultiEditor :: v_draw () {
 	double rowHeight = 0.25, tableauHeight = 2 * rowHeight;
 	Graphics_clearWs (graphics.get());
 	HyperPage_listItem (this, U"\t\t      %%ranking value\t      %disharmony\t      %plasticity");
-	for (long icons = 1; icons <= grammar -> numberOfConstraints; icons ++) {
+	for (integer icons = 1; icons <= grammar -> numberOfConstraints; icons ++) {
 		OTConstraint constraint = & grammar -> constraints [grammar -> index [icons]];
 		MelderString_copy (& buffer, U"\t", ( icons == selectedConstraint ? U"♠︎ " : U"   " ), U"@@", icons,
 			U"|", constraint -> name, U"@\t      ", Melder_fixed (constraint -> ranking, 3),
@@ -202,7 +202,7 @@ void structOTMultiEditor :: v_draw () {
 	}
 	Graphics_setAtSignIsLink (graphics.get(), false);
 	drawTableau_grammar = grammar;
-	for (long icand = 1; icand <= grammar -> numberOfCandidates; icand ++) {
+	for (integer icand = 1; icand <= grammar -> numberOfCandidates; icand ++) {
 		if (OTMulti_candidateMatches (grammar, icand, form1, form2)) {
 			tableauHeight += rowHeight;
 		}
diff --git a/gram/OTMultiEditor.h b/gram/OTMultiEditor.h
index ca596ff..b1a18b2 100644
--- a/gram/OTMultiEditor.h
+++ b/gram/OTMultiEditor.h
@@ -2,7 +2,7 @@
 #define _OTMultiEditor_h_
 /* OTMultiEditor.h
  *
- * Copyright (C) 2005-2011,2012,2015 Paul Boersma
+ * Copyright (C) 2005,2007,2009-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
@@ -24,7 +24,7 @@
 Thing_define (OTMultiEditor, HyperPage) {
 	const char32 *form1, *form2;
 	GuiText form1Text, form2Text;
-	long selectedConstraint;
+	integer selectedConstraint;
 	bool d_constraintsAreDrawnVertically;
 
 	bool v_editable ()
diff --git a/gram/OTMulti_def.h b/gram/OTMulti_def.h
index bdb2ad3..8647a12 100644
--- a/gram/OTMulti_def.h
+++ b/gram/OTMulti_def.h
@@ -1,6 +1,6 @@
 /* OTMulti_def.h
  *
- * Copyright (C) 2005-2011,2015,2017 Paul Boersma
+ * Copyright (C) 2005,2007,2009-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
diff --git a/gram/OTMulti_ex_metrics.cpp b/gram/OTMulti_ex_metrics.cpp
index f12b42a..f224094 100644
--- a/gram/OTMulti_ex_metrics.cpp
+++ b/gram/OTMulti_ex_metrics.cpp
@@ -1,6 +1,7 @@
 /* OTMulti_ex_metrics.cpp
  *
- * Copyright (C) 2014,2015,2016 Paul Boersma
+ * Copyright (C) 2014-2017 Paul Boersma
+ * Forked from OTGrammar_ex_metrics.cpp, Copyright (C) 2001-2007,2009,2011,2012 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 +50,7 @@ static const char32 *constraintNames [1+NUMBER_OF_CONSTRAINTS] { 0,
 	U"WSP", U"FtNonfinal", U"Iambic", U"Parse", U"FootBin", U"WFL", U"WFR", U"Main-L", U"Main-R", U"AFL", U"AFR", U"Nonfinal",
 	U"Trochaic", U"FtBimor", U"FtBisyl", U"Peripheral", U"MainNonfinal", U"HeadNonfinal", U"*Clash", U"*Lapse", U"WeightByPosition", U"*C\\mu" };
 
-static void addCandidate (OTMulti me, const char32 *underlyingForm, long numberOfSyllables, int stress [],
+static void addCandidate (OTMulti me, const char32 *underlyingForm, integer numberOfSyllables, int stress [],
 	bool footedToTheLeft [], bool footedToTheRight [], int surfaceWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
@@ -58,14 +59,14 @@ static void addCandidate (OTMulti me, const char32 *underlyingForm, long numberO
 	char32 string [150];
 	str32cpy (string, underlyingForm);
 	str32cpy (string + str32len (string), U" /");
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		if (isyll > 1) str32cpy (string + str32len (string), U" ");
 		if (footedToTheRight [isyll] || (! footedToTheLeft [isyll] && stress [isyll] != 0)) str32cpy (string + str32len (string), U"(");
 		str32cpy (string + str32len (string), syllable [stress [isyll] + 3 * (surfaceWeightPattern [isyll] - 1)]);
 		if (footedToTheLeft [isyll] || (! footedToTheRight [isyll] && stress [isyll] != 0)) str32cpy (string + str32len (string), U")");
 	}
 	str32cpy (string + str32len (string), U"/ [");
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		if (isyll > 1) str32cpy (string + str32len (string), U" ");
 		str32cpy (string + str32len (string), ( overtFormsHaveSecondaryStress ? syllable : syllableWithoutSecondaryStress )
 				[stress [isyll] + 3 * (surfaceWeightPattern [isyll] - 1)]);
@@ -74,13 +75,13 @@ static void addCandidate (OTMulti me, const char32 *underlyingForm, long numberO
 	my candidates [++ my numberOfCandidates]. string = Melder_dup (string);
 }
 
-static void fillSurfaceWeightPattern (OTMulti me, const char32 *underlyingForm, long numberOfSyllables, int stress [],
+static void fillSurfaceWeightPattern (OTMulti me, const char32 *underlyingForm, integer numberOfSyllables, int stress [],
 	bool footedToTheLeft [], bool footedToTheRight [], int underlyingWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
 	int surfaceWeightPattern [1+7], minSurfaceWeight [1+7], maxSurfaceWeight [1+7];
 	int weight1, weight2, weight3, weight4, weight5;
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		if (underlyingWeightPattern [isyll] < 3) {
 			minSurfaceWeight [isyll] = maxSurfaceWeight [isyll] = underlyingWeightPattern [isyll];   // L -> L; H -> H
 		} else {
@@ -112,12 +113,12 @@ static void fillSurfaceWeightPattern (OTMulti me, const char32 *underlyingForm,
 	}
 }
 
-static void path (OTMulti me, const char32 *underlyingForm, long numberOfSyllables, int stress [],
+static void path (OTMulti me, const char32 *underlyingForm, integer numberOfSyllables, int stress [],
 	int startingSyllable, bool footedToTheLeft_in [], bool footedToTheRight_in [], int underlyingWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
 	bool footedToTheLeft [10], footedToTheRight [10];
-	long isyll;
+	integer isyll;
 	/* Localize all arguments. */
 	for (isyll = 1; isyll <= startingSyllable; isyll ++) {
 		footedToTheLeft [isyll] = footedToTheLeft_in [isyll];
@@ -149,7 +150,7 @@ static void path (OTMulti me, const char32 *underlyingForm, long numberOfSyllabl
 	}
 }
 
-static void fillOvertStressPattern (OTMulti me, const char32 *underlyingForm, long numberOfSyllables, int stress [], int underlyingWeightPattern [],
+static void fillOvertStressPattern (OTMulti me, const char32 *underlyingForm, integer numberOfSyllables, int stress [], int underlyingWeightPattern [],
 	int overtFormsHaveSecondaryStress)
 {
 	bool footedToTheLeft [10], footedToTheRight [10];
@@ -161,17 +162,17 @@ static void fillOvertStressPattern (OTMulti me, const char32 *underlyingForm, lo
 static int numberOfCandidates_noCodas [1+7] { 0, 1, 6, 24, 88, 300, 984, 3136 };
 static int numberOfCandidates_codas [1+7] { 0, 1, 24, 192, 1408, 9600, 984, 3136 };
 
-static void fillTableau (OTMulti me, long numberOfSyllables, int underlyingWeightPattern [], int overtFormsHaveSecondaryStress, int includeCodas) {
+static void fillTableau (OTMulti me, integer numberOfSyllables, int underlyingWeightPattern [], int overtFormsHaveSecondaryStress, int includeCodas) {
 	char32 underlyingForm [100];
 	str32cpy (underlyingForm, U"|");
-	for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+	for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 		static const char32 *syllable_noCodas [] = { U"", U"L", U"H" };
 		static const char32 *syllable_codas [] = { U"", U"cv", U"cv:", U"cvc" };
 		if (isyll > 1) str32cpy (underlyingForm + str32len (underlyingForm), includeCodas ? U"." : U" ");
 		str32cpy (underlyingForm + str32len (underlyingForm), ( includeCodas ? syllable_codas : syllable_noCodas ) [underlyingWeightPattern [isyll]]);
 	}
 	str32cpy (underlyingForm + str32len (underlyingForm), U"|");
-	for (long mainStressed = 1; mainStressed <= numberOfSyllables; mainStressed ++) {
+	for (integer mainStressed = 1; mainStressed <= numberOfSyllables; mainStressed ++) {
 		int stress [10];
 		stress [mainStressed] = 1;
 		for (int secondary1 = false; secondary1 <= true; secondary1 ++) {
@@ -429,7 +430,7 @@ autoOTMulti OTMulti_create_metrics (
 		int underlyingWeightPattern [1+7], maximumUnderlyingWeight = includeCodas ? 3 : 2;
 		autoOTMulti me = Thing_new (OTMulti);
 		my constraints = NUMvector <structOTConstraint> (1, my numberOfConstraints = NUMBER_OF_CONSTRAINTS);
-		for (long icons = 1; icons <= NUMBER_OF_CONSTRAINTS; icons ++) {
+		for (integer icons = 1; icons <= NUMBER_OF_CONSTRAINTS; icons ++) {
 			OTConstraint constraint = & my constraints [icons];
 			constraint -> name = Melder_dup (constraintNames [icons]);
 			constraint -> ranking = 100.0;
@@ -445,25 +446,25 @@ autoOTMulti OTMulti_create_metrics (
 			/* Quantity sensitivity high, foot form constraints in the second stratum. */
 			my constraints [WSP]. ranking = 102.0;
 		}
-		long numberOfCandidates = 0;
+		integer numberOfCandidates = 0;
 		for (int numberOfSyllables = 2; numberOfSyllables <= 7; numberOfSyllables ++) {
-			long numberOfUnderlyingWeightPatterns = numberOfSyllables > 5 ? 1 : lround (pow (maximumUnderlyingWeight, numberOfSyllables));
+			integer numberOfUnderlyingWeightPatterns = numberOfSyllables > 5 ? 1 : lround (pow (maximumUnderlyingWeight, numberOfSyllables));
 			numberOfCandidates += ( includeCodas ? numberOfCandidates_codas : numberOfCandidates_noCodas ) [numberOfSyllables] * numberOfUnderlyingWeightPatterns;
 		}
 		my candidates = NUMvector <structOTCandidate> (1, numberOfCandidates);
 		my numberOfCandidates = 0;
 		for (int numberOfSyllables = 2; numberOfSyllables <= 7; numberOfSyllables ++) {
-			long numberOfUnderlyingWeightPatterns = numberOfSyllables > 5 ? 1 : lround (pow (maximumUnderlyingWeight, numberOfSyllables));
-			for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) {
+			integer numberOfUnderlyingWeightPatterns = numberOfSyllables > 5 ? 1 : lround (pow (maximumUnderlyingWeight, numberOfSyllables));
+			for (integer isyll = 1; isyll <= numberOfSyllables; isyll ++) {
 				underlyingWeightPattern [isyll] = 1;   /* L or cv */
 			}
-			for (long iweightPattern = 1; iweightPattern <= numberOfUnderlyingWeightPatterns; iweightPattern ++) {
+			for (integer iweightPattern = 1; iweightPattern <= numberOfUnderlyingWeightPatterns; iweightPattern ++) {
 				fillTableau (me.get(), numberOfSyllables, underlyingWeightPattern, overtFormsHaveSecondaryStress, includeCodas);
 				/*
 				 * Cycle to next underlying weight pattern.
 				 */
 				underlyingWeightPattern [numberOfSyllables] += 1;
-				for (long isyll = numberOfSyllables; isyll >= 2; isyll --) {
+				for (integer isyll = numberOfSyllables; isyll >= 2; isyll --) {
 					if (underlyingWeightPattern [isyll] > maximumUnderlyingWeight) {
 						underlyingWeightPattern [isyll] = 1;
 						underlyingWeightPattern [isyll - 1] += 1;
@@ -473,7 +474,7 @@ autoOTMulti OTMulti_create_metrics (
 		}
 		Melder_assert (my numberOfCandidates == numberOfCandidates);
 		/* Compute violation marks. */
-		for (long icand = 1; icand <= my numberOfCandidates; icand ++) {
+		for (integer icand = 1; icand <= my numberOfCandidates; icand ++) {
 			computeViolationMarks (& my candidates [icand]);
 		}
 		OTMulti_checkIndex (me.get());
@@ -505,7 +506,7 @@ autoOTMulti OTMulti_create_metrics (
 			OTMulti_removeConstraint (me.get(), U"*C\\mu");
 		}
 		if (includeCodas) {
-			for (long icand = 1; icand <= my numberOfCandidates; icand ++) {
+			for (integer icand = 1; icand <= my numberOfCandidates; icand ++) {
 				replaceOutput (& my candidates [icand]);
 			}
 		}
diff --git a/gram/RBM.cpp b/gram/RBM.cpp
index f2da6c1..008e508 100644
--- a/gram/RBM.cpp
+++ b/gram/RBM.cpp
@@ -1,6 +1,6 @@
 /* RBM.cpp
  *
- * 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
@@ -18,6 +18,7 @@
 
 //#include <OpenCL/OpenCL.h>
 #include "RBM.h"
+#include "PAIRWISE_SUM.h"
 
 #include "oo_DESTROY.h"
 #include "RBM_def.h"
@@ -38,8 +39,7 @@
 #include "oo_DESCRIPTION.h"
 #include "RBM_def.h"
 
-void structRBM :: v_info ()
-{
+void structRBM :: v_info () {
 	structDaata :: v_info ();
 	MelderInfo_writeLine (U"Number of input nodes: ", our numberOfInputNodes);
 	MelderInfo_writeLine (U"Number of output nodes: ", our numberOfOutputNodes);
@@ -47,20 +47,20 @@ void structRBM :: v_info ()
 
 Thing_implement (RBM, Daata, 0);
 
-void RBM_init (RBM me, long numberOfInputNodes, long numberOfOutputNodes, bool inputsAreBinary) {
+void RBM_init (RBM me, integer numberOfInputNodes, integer numberOfOutputNodes, bool inputsAreBinary) {
 	my numberOfInputNodes = numberOfInputNodes;
 	my inputBiases = NUMvector <double> (1, numberOfInputNodes);
-	my inputActivities = NUMvector<double> (1, numberOfInputNodes);
-	my inputReconstruction = NUMvector<double> (1, numberOfInputNodes);
+	my inputActivities = NUMvector <double> (1, numberOfInputNodes);
+	my inputReconstruction = NUMvector <double> (1, numberOfInputNodes);
 	my numberOfOutputNodes = numberOfOutputNodes;
 	my outputBiases = NUMvector <double> (1, numberOfOutputNodes);
-	my outputActivities = NUMvector<double> (1, numberOfOutputNodes);
-	my outputReconstruction = NUMvector<double> (1, numberOfOutputNodes);
-	my weights = NUMmatrix<double> (1, numberOfInputNodes, 1, numberOfOutputNodes);
+	my outputActivities = NUMvector <double> (1, numberOfOutputNodes);
+	my outputReconstruction = NUMvector <double> (1, numberOfOutputNodes);
+	my weights = NUMmatrix <double> (1, numberOfInputNodes, 1, numberOfOutputNodes);
 	my inputsAreBinary = inputsAreBinary;
 }
 
-autoRBM RBM_create (long numberOfInputNodes, long numberOfOutputNodes, bool inputsAreBinary) {
+autoRBM RBM_create (integer numberOfInputNodes, integer numberOfOutputNodes, bool inputsAreBinary) {
 	try {
 		autoRBM me = Thing_new (RBM);
 		RBM_init (me.get(), numberOfInputNodes, numberOfOutputNodes, inputsAreBinary);
@@ -75,17 +75,21 @@ inline static double logistic (double excitation) {
 }
 
 void RBM_spreadUp (RBM me) {
-	for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
-		double excitation = my outputBiases [jnode];
-		for (long inode = 1; inode <= my numberOfInputNodes; inode ++) {
-			excitation += my inputActivities [inode] * my weights [inode] [jnode];
-		}
-		my outputActivities [jnode] = logistic (excitation);
+	integer numberOfOutputNodes = my numberOfOutputNodes;
+	for (integer jnode = 1; jnode <= numberOfOutputNodes; jnode ++) {
+		PAIRWISE_SUM (real80, excitation, integer, my numberOfInputNodes,
+ 			double *p_inputActivity = & my inputActivities [0];
+ 			double *p_weight = & my weights [1] [jnode] - numberOfOutputNodes,
+ 			( p_inputActivity += 1, p_weight += numberOfOutputNodes ),
+ 			(real80) *p_inputActivity * (real80) *p_weight
+		);
+		excitation += my outputBiases [jnode];
+		my outputActivities [jnode] = logistic ((real) excitation);
 	}
 }
 
 void RBM_sampleInput (RBM me) {
-	for (long inode = 1; inode <= my numberOfInputNodes; inode ++) {
+	for (integer inode = 1; inode <= my numberOfInputNodes; inode ++) {
 		if (my inputsAreBinary) {
 			double probability = my inputActivities [inode];
 			my inputActivities [inode] = (double) NUMrandomBernoulli (probability);
@@ -97,57 +101,67 @@ void RBM_sampleInput (RBM me) {
 }
 
 void RBM_sampleOutput (RBM me) {
-	for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
+	for (integer jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
 		double probability = my outputActivities [jnode];
 		my outputActivities [jnode] = (double) NUMrandomBernoulli (probability);
 	}
 }
 
 void RBM_spreadDown (RBM me) {
-	for (long inode = 1; inode <= my numberOfInputNodes; inode ++) {
-		double excitation = my inputBiases [inode];
-		for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
-			excitation += my weights [inode] [jnode] * my outputActivities [jnode];
-		}
+	for (integer inode = 1; inode <= my numberOfInputNodes; inode ++) {
+		PAIRWISE_SUM (real80, excitation, integer, my numberOfOutputNodes,
+ 			double *p_weight = & my weights [inode] [0];
+ 			double *p_outputActivity = & my outputActivities [0],
+ 			( p_weight += 1, p_outputActivity += 1 ),
+ 			(real80) *p_weight * (real80) *p_outputActivity
+		);
+		excitation += my inputBiases [inode];
 		if (my inputsAreBinary) {
-			my inputActivities [inode] = logistic (excitation);
+			my inputActivities [inode] = logistic ((real) excitation);
 		} else {   // linear
-			my inputActivities [inode] = excitation;
+			my inputActivities [inode] = (real) excitation;
 		}
 	}
 }
 
 void RBM_spreadDown_reconstruction (RBM me) {
-	for (long inode = 1; inode <= my numberOfInputNodes; inode ++) {
-		double excitation = my inputBiases [inode];
-		for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
-			excitation += my weights [inode] [jnode] * my outputActivities [jnode];
-		}
+	for (integer inode = 1; inode <= my numberOfInputNodes; inode ++) {
+		PAIRWISE_SUM (real80, excitation, integer, my numberOfOutputNodes,
+ 			double *p_weight = & my weights [inode] [0];
+ 			double *p_outputActivity = & my outputActivities [0],
+ 			( p_weight += 1, p_outputActivity += 1 ),
+ 			(real80) *p_weight * (real80) *p_outputActivity
+		);
+		excitation += my inputBiases [inode];
 		if (my inputsAreBinary) {
-			my inputReconstruction [inode] = logistic (excitation);
+			my inputReconstruction [inode] = logistic ((real) excitation);
 		} else {   // linear
-			my inputReconstruction [inode] = excitation;
+			my inputReconstruction [inode] = (real) excitation;
 		}
 	}
 }
 
 void RBM_spreadUp_reconstruction (RBM me) {
-	for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
-		double excitation = my outputBiases [jnode];
-		for (long inode = 1; inode <= my numberOfInputNodes; inode ++) {
-			excitation += my inputReconstruction [inode] * my weights [inode] [jnode];
-		}
-		my outputReconstruction [jnode] = logistic (excitation);
+	integer numberOfOutputNodes = my numberOfOutputNodes;
+	for (integer jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
+		PAIRWISE_SUM (real80, excitation, integer, my numberOfInputNodes,
+ 			double *p_inputActivity = & my inputReconstruction [0];
+ 			double *p_weight = & my weights [1] [jnode] - numberOfOutputNodes,
+ 			( p_inputActivity += 1, p_weight += numberOfOutputNodes ),
+ 			(real80) *p_inputActivity * (real80) *p_weight
+		);
+		excitation += my outputBiases [jnode];
+		my outputReconstruction [jnode] = logistic ((real) excitation);
 	}
 }
 
 void RBM_update (RBM me, double learningRate) {
-	for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
+	for (integer jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
 		my outputBiases [jnode] += learningRate * (my outputActivities [jnode] - my outputReconstruction [jnode]);
 	}
-	for (long inode = 1; inode <= my numberOfInputNodes; inode ++) {
+	for (integer inode = 1; inode <= my numberOfInputNodes; inode ++) {
 		my inputBiases [inode] += learningRate * (my inputActivities [inode] - my inputReconstruction [inode]);
-		for (long jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
+		for (integer jnode = 1; jnode <= my numberOfOutputNodes; jnode ++) {
 			my weights [inode] [jnode] += learningRate *
 				(my inputActivities [inode] * my outputActivities [jnode] -
 				 my inputReconstruction [inode] * my outputReconstruction [jnode]);
@@ -155,22 +169,22 @@ void RBM_update (RBM me, double learningRate) {
 	}
 }
 
-void RBM_PatternList_applyToInput (RBM me, PatternList thee, long rowNumber) {
+void RBM_PatternList_applyToInput (RBM me, PatternList thee, integer rowNumber) {
 	Melder_assert (my numberOfInputNodes == thy nx);
-	for (long ifeature = 1; ifeature <= my numberOfInputNodes; ifeature ++) {
+	for (integer ifeature = 1; ifeature <= my numberOfInputNodes; ifeature ++) {
 		my inputActivities [ifeature] = thy z [rowNumber] [ifeature];
 	}
 }
 
-void RBM_PatternList_applyToOutput (RBM me, PatternList thee, long rowNumber) {
+void RBM_PatternList_applyToOutput (RBM me, PatternList thee, integer rowNumber) {
 	Melder_assert (my numberOfOutputNodes == thy nx);
-	for (long icat = 1; icat <= my numberOfOutputNodes; icat ++) {
+	for (integer icat = 1; icat <= my numberOfOutputNodes; icat ++) {
 		my outputActivities [icat] = thy z [rowNumber] [icat];
 	}
 }
 
 void RBM_PatternList_learn (RBM me, PatternList thee, double learningRate) {
-	for (long ipattern = 1; ipattern <= thy ny; ipattern ++) {
+	for (integer ipattern = 1; ipattern <= thy ny; ipattern ++) {
 		RBM_PatternList_applyToInput (me, thee, ipattern);
 		RBM_spreadUp (me);
 		RBM_sampleOutput (me);
diff --git a/gram/RBM.h b/gram/RBM.h
index 20e41d0..b0eea2d 100644
--- a/gram/RBM.h
+++ b/gram/RBM.h
@@ -2,7 +2,7 @@
 #define _RBM_h_
 /* RBM
  *
- * 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
@@ -23,9 +23,9 @@
 
 #include "RBM_def.h"
 
-void RBM_init (RBM me, long numberOfInputNodes, long numberOfOutputNodes, bool inputsAreBinary);
+void RBM_init (RBM me, integer numberOfInputNodes, integer numberOfOutputNodes, bool inputsAreBinary);
 
-autoRBM RBM_create (long numberOfInputNodes, long numberOfOutputNodes, bool inputsAreBinary);
+autoRBM RBM_create (integer numberOfInputNodes, integer numberOfOutputNodes, bool inputsAreBinary);
 
 void RBM_spreadUp (RBM me);
 void RBM_spreadDown (RBM me);
@@ -35,8 +35,8 @@ void RBM_sampleInput (RBM me);
 void RBM_sampleOutput (RBM me);
 void RBM_update (RBM me, double learningRate);
 
-void RBM_PatternList_applyToInput (RBM me, PatternList thee, long rowNumber);
-void RBM_PatternList_applyToOutput (RBM me, PatternList thee, long rowNumber);
+void RBM_PatternList_applyToInput (RBM me, PatternList thee, integer rowNumber);
+void RBM_PatternList_applyToOutput (RBM me, PatternList thee, integer rowNumber);
 void RBM_PatternList_learn (RBM me, PatternList thee, double learningRate);
 
 autoMatrix RBM_extractInputActivities (RBM me);
diff --git a/gram/manual_gram.cpp b/gram/manual_gram.cpp
index d8359c7..e90bba3 100644
--- a/gram/manual_gram.cpp
+++ b/gram/manual_gram.cpp
@@ -1,6 +1,6 @@
 /* manual_gram.cpp
  *
- * Copyright (C) 1997-2011,2014,2015,2017 Paul Boersma
+ * Copyright (C) 1997-2011,2013-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
diff --git a/gram/praat_gram.cpp b/gram/praat_gram.cpp
index 720e27e..6150110 100644
--- a/gram/praat_gram.cpp
+++ b/gram/praat_gram.cpp
@@ -1,6 +1,6 @@
 /* praat_gram.cpp
  *
- * Copyright (C) 1997-2012,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1997-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 @@
 #include "OTMulti.h"
 #include "OTGrammarEditor.h"
 #include "OTMultiEditor.h"
-#include "RBM.h"
+#include "DeepBeliefNetwork.h"
 
 #include "praat_TableOfReal.h"
 
@@ -441,7 +441,7 @@ DO
 
 DIRECT (INTEGER_OTGrammar_getNumberOfConstraints) {
 	INTEGER_ONE (OTGrammar)
-		long result = my numberOfConstraints;
+		integer result = my numberOfConstraints;
 	INTEGER_ONE_END (U" constraints")
 }
 
@@ -480,7 +480,7 @@ DO
 
 DIRECT (INTEGER_OTGrammar_getNumberOfTableaus) {
 	INTEGER_ONE (OTGrammar)
-		long result = my numberOfTableaus;
+		integer result = my numberOfTableaus;
 	INTEGER_ONE_END (U" tableaus")
 }
 
@@ -502,7 +502,7 @@ DO
 	NUMBER_ONE (OTGrammar)
 		if (tableauNumber > my numberOfTableaus)
 			Melder_throw (U"The specified tableau number should not exceed the number of tableaus.");
-		long result = my tableaus [tableauNumber]. numberOfCandidates;
+		integer result = my tableaus [tableauNumber]. numberOfCandidates;
 	NUMBER_ONE_END (U" candidates in tableau ", tableauNumber)
 }
 
@@ -534,7 +534,7 @@ DO
 			Melder_throw (U"The specified candidate should not exceed the number of candidates.");
 		if (constraintNumber > my numberOfConstraints)
 			Melder_throw (U"The specified constraint number should not exceed the number of constraints.");
-		long result = my tableaus [tableauNumber]. candidates [candidateNumber]. marks [constraintNumber];
+		integer result = my tableaus [tableauNumber]. candidates [candidateNumber]. marks [constraintNumber];
 	NUMBER_ONE_END (U" violations")
 }
 
@@ -547,7 +547,7 @@ DO
 	NUMBER_ONE (OTGrammar)
 		if (tableauNumber > my numberOfTableaus)
 			Melder_throw (U"The specified tableau number should not exceed the number of tableaus.");
-		long result = OTGrammar_getWinner (me, tableauNumber);
+		integer result = OTGrammar_getWinner (me, tableauNumber);
 	NUMBER_ONE_END (U" (winner in tableau ", tableauNumber, U")")
 }
 
@@ -567,7 +567,7 @@ DO
 			Melder_throw (U"The specified tableau (number 2) should not exceed the number of tableaus.");
 		if (candidateNumber2 > my tableaus [tableauNumber2]. numberOfCandidates)
 			Melder_throw (U"The specified candidate (number 2) should not exceed the number of candidates for this tableau.");
-		long result = OTGrammar_compareCandidates (me, tableauNumber1, candidateNumber1, tableauNumber2, candidateNumber2);
+		integer result = OTGrammar_compareCandidates (me, tableauNumber1, candidateNumber1, tableauNumber2, candidateNumber2);
 	NUMBER_ONE_END (result == -1 ? U" (candidate 1 is better)" :
 					result == +1 ? U" (candidate 2 is better)" : U" (candidates are equally good)")
 }
@@ -579,7 +579,7 @@ DO
 	NUMBER_ONE (OTGrammar)
 		if (tableauNumber > my numberOfTableaus)
 			Melder_throw (U"The specified tableau number should not exceed the number of tableaus.");
-		long result = OTGrammar_getNumberOfOptimalCandidates (me, tableauNumber);
+		integer result = OTGrammar_getNumberOfOptimalCandidates (me, tableauNumber);
 	NUMBER_ONE_END (U" optimal candidates in tableau ", tableauNumber)
 }
 
@@ -593,7 +593,7 @@ DO
 			Melder_throw (U"The specified tableau number should not exceed the number of tableaus.");
 		if (candidateNumber > my tableaus [tableauNumber]. numberOfCandidates)
 			Melder_throw (U"The specified candidate should not exceed the number of candidates.");
-		long result = OTGrammar_isCandidateGrammatical (me, tableauNumber, candidateNumber);
+		integer result = OTGrammar_isCandidateGrammatical (me, tableauNumber, candidateNumber);
 	NUMBER_ONE_END (result ? U" (grammatical)" : U" (ungrammatical)")
 }
 
@@ -607,7 +607,7 @@ DO
 			Melder_throw (U"The specified tableau number should not exceed the number of tableaus.");
 		if (candidateNumber > my tableaus [tableauNumber]. numberOfCandidates)
 			Melder_throw (U"The specified candidate should not exceed the number of candidates.");
-		long result = OTGrammar_isCandidateSinglyGrammatical (me, tableauNumber, candidateNumber);
+		integer result = OTGrammar_isCandidateSinglyGrammatical (me, tableauNumber, candidateNumber);
 	NUMBER_ONE_END (result ? U" (singly grammatical)" : U" (not singly grammatical)")
 }
 
@@ -616,7 +616,7 @@ FORM (STRING_OTGrammar_getInterpretiveParse, U"OTGrammar: Interpretive parse", n
 	OK
 DO
 	FIND_ONE (OTGrammar)
-		long bestInput, bestOutput;
+		integer bestInput, bestOutput;
 		OTGrammar_getInterpretiveParse (me, partialOutput, & bestInput, & bestOutput);
 		Melder_information (U"Best input = ", bestInput, U": ", my tableaus [bestInput]. input,
 			U"\nBest output = ", bestOutput, U": ", my tableaus [bestInput]. candidates [bestOutput]. output);
@@ -628,7 +628,7 @@ FORM (BOOLEAN_OTGrammar_isPartialOutputGrammatical, U"Is partial output grammati
 	OK
 DO
 	NUMBER_ONE (OTGrammar)
-		long result = OTGrammar_isPartialOutputGrammatical (me, partialOutput);
+		integer result = OTGrammar_isPartialOutputGrammatical (me, partialOutput);
 	NUMBER_ONE_END (result ? U" (grammatical)" : U" (ungrammatical)")
 }
 
@@ -637,7 +637,7 @@ FORM (BOOLEAN_OTGrammar_isPartialOutputSinglyGrammatical, U"Is partial output si
 	OK
 DO
 	NUMBER_ONE (OTGrammar)
-		long result = OTGrammar_isPartialOutputSinglyGrammatical (me, partialOutput);
+		integer result = OTGrammar_isPartialOutputSinglyGrammatical (me, partialOutput);
 	NUMBER_ONE_END (result ? U" (singly grammatical)" : U" (not singly grammatical)")
 }
 
@@ -887,13 +887,13 @@ DO
 
 DIRECT (BOOLEAN_OTGrammar_Strings_areAllPartialOutputsGrammatical) {
 	NUMBER_TWO (OTGrammar, Strings)
-		long result = OTGrammar_areAllPartialOutputsGrammatical (me, you);
+		integer result = OTGrammar_areAllPartialOutputsGrammatical (me, you);
 	NUMBER_TWO_END (result ? U" (all grammatical)" : U" (not all grammatical)")
 }
 
 DIRECT (BOOLEAN_OTGrammar_Strings_areAllPartialOutputsSinglyGrammatical) {
 	NUMBER_TWO (OTGrammar, Strings)
-		long result = OTGrammar_areAllPartialOutputsSinglyGrammatical (me, you);
+		integer result = OTGrammar_areAllPartialOutputsSinglyGrammatical (me, you);
 	NUMBER_TWO_END (result ? U" (all singly grammatical)" : U" (not all singly grammatical)")
 }
 
@@ -1119,7 +1119,7 @@ FORM (INTEGER_MODIFY_OTGrammar_PairDistribution_getMinimumNumberCorrect, U"OTGra
 	OK
 DO
 	FIND_TWO (OTGrammar, PairDistribution)
-		long result;
+		integer result;
 		try {
 			result = OTGrammar_PairDistribution_getMinimumNumberCorrect (me, you,
 				evaluationNoise, replicationsPerInput);
@@ -1225,7 +1225,7 @@ DIRECT (WINDOW_OTMulti_viewAndEdit) {
 
 DIRECT (INTEGER_OTMulti_getNumberOfConstraints) {
 	NUMBER_ONE (OTMulti)
-		long result = my numberOfConstraints;
+		integer result = my numberOfConstraints;
 	NUMBER_ONE_END (U" constraints")
 }
 
@@ -1245,7 +1245,7 @@ FORM (INTEGER_OTMulti_getConstraintIndexFromName, U"OTMulti: Get constraint numb
 	OK
 DO
 	NUMBER_ONE (OTMulti)
-		long result = OTMulti_getConstraintIndexFromName (me, constraintName);
+		integer result = OTMulti_getConstraintIndexFromName (me, constraintName);
 	NUMBER_ONE_END (U" (index of constraint ", constraintName, U")")
 }
 
@@ -1273,7 +1273,7 @@ DO
 
 DIRECT (INTEGER_OTMulti_getNumberOfCandidates) {
 	NUMBER_ONE (OTMulti)
-		long result = my numberOfCandidates;
+		integer result = my numberOfCandidates;
 	NUMBER_ONE_END (U" candidates")
 }
 
@@ -1298,7 +1298,7 @@ DO
 			Melder_throw (U"Your candidate number should not exceed the number of candidates.");
 		if (constraintNumber > my numberOfConstraints)
 			Melder_throw (U"Your constraint number should not exceed the number of constraints.");
-		long result = my candidates [candidateNumber]. marks [constraintNumber];
+		integer result = my candidates [candidateNumber]. marks [constraintNumber];
 	NUMBER_ONE_END (U" violations")
 }
 
@@ -1308,7 +1308,7 @@ FORM (INTEGER_OTMulti_getWinner, U"OTMulti: Get winner", nullptr) {
 	OK
 DO
 	NUMBER_ONE (OTMulti)
-		long result = OTMulti_getWinner (me, partialForm1, partialForm2);
+		integer result = OTMulti_getWinner (me, partialForm1, partialForm2);
 	NUMBER_ONE_END (U" (winner)")
 }
 
@@ -1641,13 +1641,181 @@ DO
 	MODIFY_FIRST_OF_TWO_END
 }
 
+// MARK: - DEEP BELIEF NETWORK
+
+// MARK: New
+
+FORM (NEW1_Create_DeepBeliefNetwork, U"Create DeepBeliefNetwork", nullptr) {
+	WORD (name, U"Name", U"network")
+	NUMVEC (numbersOfNodes, U"Numbers of nodes", U"{ 30, 50, 20 }")
+	BOOLEAN (inputsAreBinary, U"Inputs are binary", false)
+	OK
+DO
+	CREATE_ONE
+		autoDeepBeliefNetwork result = DeepBeliefNetwork_create (numbersOfNodes, inputsAreBinary);
+	CREATE_ONE_END (name)
+}
+
+// MARK: Modify
+
+FORM (MODIFY_DeepBeliefNetwork_spreadUp, U"DeepBeliefNetwork: Spread up", nullptr) {
+	RADIO_ENUM (activationType, U"Activation type", kDeepBeliefNetwork_activationType, STOCHASTIC)
+	OK
+DO
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_spreadUp (me, activationType);
+	MODIFY_EACH_END
+}
+
+FORM (MODIFY_DeepBeliefNetwork_spreadDown, U"DeepBeliefNetwork: Spread down", nullptr) {
+	RADIO_ENUM (activationType, U"Activation type", kDeepBeliefNetwork_activationType, DETERMINISTIC)
+	OK
+DO
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_spreadDown (me, activationType);
+	MODIFY_EACH_END
+}
+
+DIRECT (MODIFY_DeepBeliefNetwork_spreadUp_reconstruction) {
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_spreadUp_reconstruction (me);
+	MODIFY_EACH_END
+}
+
+DIRECT (MODIFY_DeepBeliefNetwork_spreadDown_reconstruction) {
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_spreadDown_reconstruction (me);
+	MODIFY_EACH_END
+}
+
+DIRECT (MODIFY_DeepBeliefNetwork_sampleInput) {
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_sampleInput (me);
+	MODIFY_EACH_END
+}
+
+DIRECT (MODIFY_DeepBeliefNetwork_sampleOutput) {
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_sampleOutput (me);
+	MODIFY_EACH_END
+}
+
+FORM (MODIFY_DeepBeliefNetwork_update, U"DeepBeliefNetwork: Update", nullptr) {
+	POSITIVE (learningRate, U"Learning rate", U"0.001")
+	OK
+DO
+	MODIFY_EACH (DeepBeliefNetwork)
+		DeepBeliefNetwork_update (me, learningRate);
+	MODIFY_EACH_END
+}
+
+// MARK: Extract
+
+DIRECT (NEW_DeepBeliefNetwork_extractInputActivities) {
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractInputActivities (me);
+	CONVERT_EACH_END (my name, U"_inputActivities")
+}
+
+DIRECT (NEW_DeepBeliefNetwork_extractOutputActivities) {
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractOutputActivities (me);
+	CONVERT_EACH_END (my name, U"_outputActivities")
+}
+
+DIRECT (NEW_DeepBeliefNetwork_extractInputReconstruction) {
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractInputReconstruction (me);
+	CONVERT_EACH_END (my name, U"_inputReconstruction")
+}
+
+DIRECT (NEW_DeepBeliefNetwork_extractOutputReconstruction) {
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractOutputReconstruction (me);
+	CONVERT_EACH_END (my name, U"_outputReconstruction")
+}
+
+FORM (NEW_DeepBeliefNetwork_extractInputBiases, U"DeepBeliefNetwork: Extract input biases", nullptr) {
+	NATURAL (layerNumber, U"Layer number", U"1")
+	OK
+DO
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractInputBiases (me, layerNumber);
+	CONVERT_EACH_END (my name, U"_inputBiases")
+}
+
+FORM (NEW_DeepBeliefNetwork_extractOutputBiases, U"DeepBeliefNetwork: Extract output biases", nullptr) {
+	NATURAL (layerNumber, U"Layer number", U"1")
+	OK
+DO
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractOutputBiases (me, layerNumber);
+	CONVERT_EACH_END (my name, U"_outputBiases")
+}
+
+FORM (NEW_DeepBeliefNetwork_extractWeights, U"DeepBeliefNetwork: Extract weights", nullptr) {
+	NATURAL (layerNumber, U"Layer number", U"1")
+	OK
+DO
+	CONVERT_EACH (DeepBeliefNetwork)
+		autoMatrix result = DeepBeliefNetwork_extractWeights (me, layerNumber);
+	CONVERT_EACH_END (my name, U"_weights")
+}
+
+FORM (NUMMAT_DeepBeliefNetwork_getWeights, U"DeepBeliefNetwork: Get weigths", nullptr) {
+	NATURAL (layerNumber, U"Layer number", U"1")
+	OK
+DO
+	NUMMAT_ONE (DeepBeliefNetwork)
+		autonummat result = DeepBeliefNetwork_getWeights_nummat (me, layerNumber);
+	NUMMAT_ONE_END
+}
+
+// MARK: - RBM & PATTERN
+
+FORM (MODIFY_DeepBeliefNetwork_PatternList_applyToInput, U"DeepBeliefNetwork & PatternList: Apply to input", nullptr) {
+	NATURAL (rowNumber, U"Row number", U"1")
+	OK
+DO
+	MODIFY_FIRST_OF_TWO (DeepBeliefNetwork, PatternList)
+		DeepBeliefNetwork_PatternList_applyToInput (me, you, rowNumber);
+	MODIFY_FIRST_OF_TWO_END
+}
+
+FORM (MODIFY_DeepBeliefNetwork_PatternList_applyToOutput, U"DeepBeliefNetwork & PatternList: Apply to output", nullptr) {
+	NATURAL (rowNumber, U"Row number", U"1")
+	OK
+DO
+	MODIFY_FIRST_OF_TWO (DeepBeliefNetwork, PatternList)
+		DeepBeliefNetwork_PatternList_applyToOutput (me, you, rowNumber);
+	MODIFY_FIRST_OF_TWO_END
+}
+
+FORM (MODIFY_DeepBeliefNetwork_PatternList_learn, U"DeepBeliefNetwork & PatternList: Learn", nullptr) {
+	POSITIVE (learningRate, U"Learning rate", U"0.001")
+	OK
+DO
+	MODIFY_FIRST_OF_TWO (DeepBeliefNetwork, PatternList)
+		DeepBeliefNetwork_PatternList_learn (me, you, learningRate);
+	MODIFY_FIRST_OF_TWO_END
+}
+
+FORM (MODIFY_DeepBeliefNetwork_PatternList_learnByLayer, U"DeepBeliefNetwork & PatternList: Learn by layer", nullptr) {
+	POSITIVE (learningRate, U"Learning rate", U"0.001")
+	OK
+DO
+	MODIFY_FIRST_OF_TWO (DeepBeliefNetwork, PatternList)
+		DeepBeliefNetwork_PatternList_learnByLayer (me, you, learningRate);
+	MODIFY_FIRST_OF_TWO_END
+}
+
 // MARK: - buttons
 
 void praat_uvafon_gram_init ();
 void praat_uvafon_gram_init () {
 	Thing_recognizeClassesByName (classNetwork,
 		classOTGrammar, classOTHistory, classOTMulti,
-		classRBM,
+		classRBM, classDeepBeliefNetwork,
 		nullptr);
 	Thing_recognizeClassByOtherName (classOTGrammar, U"OTCase");
 
@@ -1772,6 +1940,7 @@ void praat_uvafon_gram_init () {
 		praat_addMenuCommand (U"Objects", U"New", U"Create rectangular Network...", nullptr, 1, NEW1_Create_rectangular_Network);
 		praat_addMenuCommand (U"Objects", U"New", U"Create rectangular Network (vertical)...", nullptr, 1, NEW1_Create_rectangular_Network_vertical);
 		praat_addMenuCommand (U"Objects", U"New", U"Create RBM...", nullptr, 1, NEW1_Create_RBM);
+		praat_addMenuCommand (U"Objects", U"New", U"Create DeepBeliefNetwork...", nullptr, 1, NEW1_Create_DeepBeliefNetwork);
 
 	praat_addAction1 (classNetwork, 0, U"Draw...", nullptr, 0, GRAPHICS_Network_draw);
 	praat_addAction1 (classNetwork, 1, U"Tabulate -", nullptr, 0, nullptr);
@@ -1820,6 +1989,30 @@ void praat_uvafon_gram_init () {
 	praat_addAction2 (classRBM, 1, classPatternList, 1, U"Apply to input...", nullptr, 0, MODIFY_RBM_PatternList_applyToInput);
 	praat_addAction2 (classRBM, 1, classPatternList, 1, U"Apply to output...", nullptr, 0, MODIFY_RBM_PatternList_applyToOutput);
 	praat_addAction2 (classRBM, 1, classPatternList, 1, U"Learn...", nullptr, 0, MODIFY_RBM_PatternList_learn);
+
+	praat_addAction1 (classDeepBeliefNetwork, 0, U"Query", nullptr, 0, nullptr);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Get weights...", nullptr, 0, NUMMAT_DeepBeliefNetwork_getWeights);
+	praat_addAction1 (classDeepBeliefNetwork, 0, U"Modify", nullptr, 0, nullptr);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Spread up...", nullptr, 0, MODIFY_DeepBeliefNetwork_spreadUp);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Spread down...", nullptr, 0, MODIFY_DeepBeliefNetwork_spreadDown);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Spread up (reconstruction)", nullptr, 0, MODIFY_DeepBeliefNetwork_spreadUp_reconstruction);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Spread down (reconstruction)", nullptr, 0, MODIFY_DeepBeliefNetwork_spreadDown_reconstruction);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Sample input", nullptr, 0, MODIFY_DeepBeliefNetwork_sampleInput);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Sample output", nullptr, 0, MODIFY_DeepBeliefNetwork_sampleOutput);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Update...", nullptr, 0, MODIFY_DeepBeliefNetwork_update);
+	praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract", nullptr, 0, nullptr);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract input activities", nullptr, 0, NEW_DeepBeliefNetwork_extractInputActivities);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract output activities", nullptr, 0, NEW_DeepBeliefNetwork_extractOutputActivities);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract input reconstruction", nullptr, 0, NEW_DeepBeliefNetwork_extractInputReconstruction);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract output reconstruction", nullptr, 0, NEW_DeepBeliefNetwork_extractOutputReconstruction);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract input biases...", nullptr, 0, NEW_DeepBeliefNetwork_extractInputBiases);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract output biases...", nullptr, 0, NEW_DeepBeliefNetwork_extractOutputBiases);
+		praat_addAction1 (classDeepBeliefNetwork, 0, U"Extract weights...", nullptr, 0, NEW_DeepBeliefNetwork_extractWeights);
+
+	praat_addAction2 (classDeepBeliefNetwork, 1, classPatternList, 1, U"Apply to input...", nullptr, 0, MODIFY_DeepBeliefNetwork_PatternList_applyToInput);
+	praat_addAction2 (classDeepBeliefNetwork, 1, classPatternList, 1, U"Apply to output...", nullptr, 0, MODIFY_DeepBeliefNetwork_PatternList_applyToOutput);
+	praat_addAction2 (classDeepBeliefNetwork, 1, classPatternList, 1, U"Learn...", nullptr, 0, MODIFY_DeepBeliefNetwork_PatternList_learn);
+	praat_addAction2 (classDeepBeliefNetwork, 1, classPatternList, 1, U"Learn by layer...", nullptr, 0, MODIFY_DeepBeliefNetwork_PatternList_learnByLayer);
 }
 
 /* End of file praat_gram.cpp */
diff --git a/num/NUM.cpp b/num/NUM.cpp
index fcdeacb..82bc1b5 100644
--- a/num/NUM.cpp
+++ b/num/NUM.cpp
@@ -361,7 +361,7 @@ double NUMcombinations (integer n, integer k) {
 
 #if defined (__POWERPC__)
 double NUM_interpolate_sinc (double y [], integer nx, double x, integer maxDepth) {
-	integer ix, midleft = floor (x), midright = midleft + 1, left, right;
+	integer ix, midleft = (integer) floor (x), midright = midleft + 1, left, right;
 	double result = 0.0, a, halfsina, aa, daa, cosaa, sinaa, cosdaa, sindaa;
 	NUM_interpolate_simple_cases
 	left = midright - maxDepth, right = midleft + maxDepth;
diff --git a/stat/Distributions.cpp b/stat/Distributions.cpp
index 29aa645..2624bf1 100644
--- a/stat/Distributions.cpp
+++ b/stat/Distributions.cpp
@@ -26,7 +26,7 @@ void structDistributions :: v_info () {
 	MelderInfo_writeLine (U"Number of values: ", numberOfRows);
 }
 
-autoDistributions Distributions_create (long numberOfRows, long numberOfColumns) {
+autoDistributions Distributions_create (integer numberOfRows, integer numberOfColumns) {
 	try {
 		autoDistributions me = Thing_new (Distributions);
 		TableOfReal_init (me.get(), numberOfRows, numberOfColumns);
@@ -36,30 +36,30 @@ autoDistributions Distributions_create (long numberOfRows, long numberOfColumns)
 	}
 }
 
-void Distributions_checkSpecifiedColumnNumberWithinRange (Distributions me, long columnNumber) {
+void Distributions_checkSpecifiedColumnNumberWithinRange (Distributions 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 Distributions_peek (Distributions me, long column, char32 **string, long *number) {
+void Distributions_peek (Distributions me, integer column, char32 **string, integer *number) {
 	Distributions_checkSpecifiedColumnNumberWithinRange (me, column);
 	if (my numberOfRows < 1)
 		Melder_throw (me, U": I have no candidates.");
 	real80 total = 0.0;
-	for (long irow = 1; irow <= my numberOfRows; irow ++) {
+	for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 		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;
+	integer irow;
 	do {
 		double rand = NUMrandomUniform (0, (real) total);
-		long double sum = 0.0;
+		real80 sum = 0.0;
 		for (irow = 1; irow <= my numberOfRows; irow ++) {
-			sum += (real80) my data [irow] [column];
-			if ((real80) rand <= sum) break;
+			sum += my data [irow] [column];
+			if (rand <= sum) break;
 		}
 	} while (irow > my numberOfRows);   // guard against rounding errors
 	if (! my rowLabels [irow])
@@ -70,12 +70,12 @@ void Distributions_peek (Distributions me, long column, char32 **string, long *n
 		*number = irow;
 }
 
-double Distributions_getProbability (Distributions me, const char32 *string, long column) {
-	long row, rowOfString = 0;
+double Distributions_getProbability (Distributions me, const char32 *string, integer column) {
+	integer row, rowOfString = 0;
 	real80 total = 0.0;
 	if (column < 1 || column > my numberOfColumns) return undefined;
 	for (row = 1; row <= my numberOfRows; row ++) {
-		total += (real80) my data [row] [column];
+		total += my data [row] [column];
 		if (my rowLabels [row] && str32equ (my rowLabels [row], string))
 			rowOfString = row;
 	}
@@ -84,11 +84,11 @@ double Distributions_getProbability (Distributions me, const char32 *string, lon
 	return my data [rowOfString] [column] / (real) total;
 }
 
-double Distributionses_getMeanAbsoluteDifference (Distributions me, Distributions thee, long column) {
+double Distributionses_getMeanAbsoluteDifference (Distributions me, Distributions thee, integer column) {
 	if (column < 1 || column > my numberOfColumns || column > thy numberOfColumns ||
 	    my numberOfRows != thy numberOfRows) return undefined;
 	real80 total = 0.0;
-	for (long irow = 1; irow <= my numberOfRows; irow ++) {
+	for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 		total += (real80) fabs (my data [irow] [column] - thy data [irow] [column]);
 	}
 	return (real) total / my numberOfRows;
@@ -96,8 +96,8 @@ double Distributionses_getMeanAbsoluteDifference (Distributions me, Distribution
 
 static void unicize (Distributions me) {
 	/* Must have been sorted beforehand. */
-	long nrow = 0, ifrom = 1;
-	for (long irow = 1; irow <= my numberOfRows; irow ++) {
+	integer nrow = 0, ifrom = 1;
+	for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 		if (irow == my numberOfRows || (my rowLabels [irow] == nullptr) != (my rowLabels [irow + 1] == nullptr) ||
 		    (my rowLabels [irow] != nullptr && ! str32equ (my rowLabels [irow], my rowLabels [irow + 1])))
 		{
@@ -105,7 +105,7 @@ static void unicize (Distributions me) {
 			 * Detected a change.
 			 */
 			nrow ++;
-			long ito = irow;
+			integer ito = irow;
 			/*
 			 * Move row 'ifrom' to 'nrow'. May be the same row.
 			 */
@@ -113,15 +113,15 @@ static void unicize (Distributions me) {
 				Melder_free (my rowLabels [nrow]);
 				my rowLabels [nrow] = my rowLabels [ifrom];   // surface copy
 				my rowLabels [ifrom] = nullptr;   // undangle
-				for (long icol = 1; icol <= my numberOfColumns; icol ++)
+				for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 					my data [nrow] [icol] = my data [ifrom] [icol];
 			}
 			/*
 			 * Purge rows from 'ifrom'+1 to 'ito'.
 			 */
-			for (long j = ifrom + 1; j <= ito; j ++) {
+			for (integer j = ifrom + 1; j <= ito; j ++) {
 				Melder_free (my rowLabels [j]);
-				for (long icol = 1; icol <= my numberOfColumns; icol ++)
+				for (integer icol = 1; icol <= my numberOfColumns; icol ++)
 					my data [nrow] [icol] += my data [j] [icol];
 			}
 			ifrom = ito + 1;
diff --git a/stat/Distributions.h b/stat/Distributions.h
index 89d5737..635c840 100644
--- a/stat/Distributions.h
+++ b/stat/Distributions.h
@@ -2,7 +2,7 @@
 #define _Distributions_h_
 /* Distributions.h
  *
- * Copyright (C) 1997-2011,2014,2015 Paul Boersma
+ * Copyright (C) 1997-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,17 +26,17 @@ Thing_define (Distributions, TableOfReal) {
 		override;
 };
 
-autoDistributions Distributions_create (long numberOfRows, long numberOfColumns);
+autoDistributions Distributions_create (integer numberOfRows, integer numberOfColumns);
 
-void Distributions_peek (Distributions me, long column, char32 **string, long *row);
+void Distributions_peek (Distributions me, integer column, char32 **string, integer *row);
 
-double Distributions_getProbability (Distributions me, const char32 *string, long column);
-double Distributionses_getMeanAbsoluteDifference (Distributions me, Distributions thee, long column);
+double Distributions_getProbability (Distributions me, const char32 *string, integer column);
+double Distributionses_getMeanAbsoluteDifference (Distributions me, Distributions thee, integer column);
 
 autoDistributions Distributions_addTwo (Distributions me, Distributions thee);
 autoDistributions Distributions_addMany (OrderedOf<structDistributions>* me);
 
-void Distributions_checkSpecifiedColumnNumberWithinRange (Distributions me, long columnNumber);
+void Distributions_checkSpecifiedColumnNumberWithinRange (Distributions me, integer columnNumber);
 
 /* End of file Distributions.h */
 #endif
diff --git a/stat/Distributions_and_Strings.cpp b/stat/Distributions_and_Strings.cpp
index 7819f63..19d1045 100644
--- a/stat/Distributions_and_Strings.cpp
+++ b/stat/Distributions_and_Strings.cpp
@@ -1,6 +1,6 @@
 /* Distributions_and_Strings.cpp
  *
- * Copyright (C) 1997-2011,2014,2015,2016 Paul Boersma
+ * Copyright (C) 1997-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
@@ -18,12 +18,12 @@
 
 #include "Distributions_and_Strings.h"
 
-autoStrings Distributions_to_Strings (Distributions me, long column, long numberOfStrings) {
+autoStrings Distributions_to_Strings (Distributions me, integer column, integer numberOfStrings) {
 	try {
 		autoStrings thee = Thing_new (Strings);
 		thy numberOfStrings = numberOfStrings;
 		thy strings = NUMvector <char32*> (1, numberOfStrings);
-		for (long istring = 1; istring <= numberOfStrings; istring ++) {
+		for (integer istring = 1; istring <= numberOfStrings; istring ++) {
 			char32 *string;
 			Distributions_peek (me, column, & string, nullptr);
 			thy strings [istring] = Melder_dup (string);
@@ -34,17 +34,17 @@ autoStrings Distributions_to_Strings (Distributions me, long column, long number
 	}
 }
 
-autoStrings Distributions_to_Strings_exact (Distributions me, long column) {
+autoStrings Distributions_to_Strings_exact (Distributions me, integer column) {
 	try {
-		long total = 0;
-		long istring = 0;
+		integer total = 0;
+		integer istring = 0;
 		if (column > my numberOfColumns)
 			Melder_throw (U"No column ", column, U".");
 		if (my numberOfRows < 1)
 			Melder_throw (U"No candidates.");
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
 			double value = my data [irow] [column];
-			if (value != floor (value))
+			if (value != Melder_roundDown (value))
 				Melder_throw (U"Non-integer value ", value, U" in row ", irow, U".");
 			if (value < 0.0)
 				Melder_throw (U"Found a negative value ", value, U" in row ", irow, U".");
@@ -55,12 +55,12 @@ autoStrings Distributions_to_Strings_exact (Distributions me, long column) {
 		autoStrings thee = Thing_new (Strings);
 		thy numberOfStrings = total;
 		thy strings = NUMvector <char32*> (1, total);
-		for (long irow = 1; irow <= my numberOfRows; irow ++) {
-			long number = my data [irow] [column];
+		for (integer irow = 1; irow <= my numberOfRows; irow ++) {
+			integer number = my data [irow] [column];
 			char32 *string = my rowLabels [irow];
 			if (! string)
 				Melder_throw (U"No string in row ", irow, U".");
-			for (long i = 1; i <= number; i ++) {
+			for (integer i = 1; i <= number; i ++) {
 				thy strings [++ istring] = Melder_dup (string);
 			}
 		}
@@ -74,11 +74,11 @@ autoStrings Distributions_to_Strings_exact (Distributions me, long column) {
 autoDistributions Strings_to_Distributions (Strings me) {
 	try {
 		autoDistributions thee = Distributions_create (my numberOfStrings, 1);
-		long idist = 0;
-		for (long i = 1; i <= my numberOfStrings; i ++) {
+		integer idist = 0;
+		for (integer i = 1; i <= my numberOfStrings; i ++) {
 			char32 *string = my strings [i];
-			long where = 0;
-			long j = 1;
+			integer where = 0;
+			integer j = 1;
 			for (; j <= idist; j ++)
 				if (str32equ (thy rowLabels [j], string))
 					{ where = j; break; }
diff --git a/stat/Distributions_and_Strings.h b/stat/Distributions_and_Strings.h
index 5bc2808..02c912c 100644
--- a/stat/Distributions_and_Strings.h
+++ b/stat/Distributions_and_Strings.h
@@ -1,6 +1,6 @@
 /* Distributions_and_Strings.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
@@ -19,8 +19,8 @@
 #include "Distributions.h"
 #include "Strings_.h"
 
-autoStrings Distributions_to_Strings (Distributions me, long column, long numberOfStrings);
-autoStrings Distributions_to_Strings_exact (Distributions me, long column);
+autoStrings Distributions_to_Strings (Distributions me, integer column, integer numberOfStrings);
+autoStrings Distributions_to_Strings_exact (Distributions me, integer column);
 autoDistributions Strings_to_Distributions (Strings me);
 
 /* End of file Distributions_and_Strings.h */
diff --git a/stat/PairDistribution.cpp b/stat/PairDistribution.cpp
index 19052fb..56cbd4e 100644
--- a/stat/PairDistribution.cpp
+++ b/stat/PairDistribution.cpp
@@ -1,6 +1,6 @@
 /* PairDistribution.cpp
  *
- * Copyright (C) 1997-2012,2013,2015,2016 Paul Boersma
+ * Copyright (C) 1997-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
@@ -67,14 +67,14 @@ int PairProbability_compare (PairProbability me, PairProbability thee) noexcept
 	return str32cmp (my string1, thy string1);
 }
 
-static void PairDistribution_checkSpecifiedPairNumber (PairDistribution me, long pairNumber) {
+static void PairDistribution_checkSpecifiedPairNumber (PairDistribution me, integer pairNumber) {
 	if (pairNumber < 1)
 		Melder_throw (me, U": the specified pair number is ", pairNumber, U", but should be at least 1.");
 	if (pairNumber > my pairs.size)
 		Melder_throw (me, U": the specified pair number is ", pairNumber, U", but should be at most my number of pairs (", my pairs.size, U").");
 }
 
-const char32 * PairDistribution_getString1 (PairDistribution me, long pairNumber) {
+const char32 * PairDistribution_getString1 (PairDistribution me, integer pairNumber) {
 	try {
 		PairDistribution_checkSpecifiedPairNumber (me, pairNumber);
 		PairProbability prob = my pairs.at [pairNumber];
@@ -84,7 +84,7 @@ const char32 * PairDistribution_getString1 (PairDistribution me, long pairNumber
 	}
 }
 
-const char32 * PairDistribution_getString2 (PairDistribution me, long pairNumber) {
+const char32 * PairDistribution_getString2 (PairDistribution me, integer pairNumber) {
 	try {
 		PairDistribution_checkSpecifiedPairNumber (me, pairNumber);
 		PairProbability prob = my pairs.at [pairNumber];
@@ -94,7 +94,7 @@ const char32 * PairDistribution_getString2 (PairDistribution me, long pairNumber
 	}
 }
 
-double PairDistribution_getWeight (PairDistribution me, long pairNumber) {
+double PairDistribution_getWeight (PairDistribution me, integer pairNumber) {
 	try {
 		PairDistribution_checkSpecifiedPairNumber (me, pairNumber);
 		PairProbability prob = my pairs.at [pairNumber];
@@ -110,7 +110,7 @@ void PairDistribution_add (PairDistribution me, const char32 *string1, const cha
 }
 
 void PairDistribution_removeZeroWeights (PairDistribution me) {
-	for (long ipair = my pairs.size; ipair > 0; ipair --) {
+	for (integer ipair = my pairs.size; ipair > 0; ipair --) {
 		PairProbability prob = my pairs.at [ipair];
 		if (prob -> weight <= 0.0) {
 			my pairs.removeItem (ipair);
@@ -119,7 +119,7 @@ void PairDistribution_removeZeroWeights (PairDistribution me) {
 }
 
 void PairDistribution_swapInputsAndOutputs (PairDistribution me) {
-	for (long ipair = my pairs.size; ipair > 0; ipair --) {
+	for (integer ipair = my pairs.size; ipair > 0; ipair --) {
 		PairProbability prob = my pairs.at [ipair];
 		char32 *tmp = prob -> string1;
 		prob -> string1 = prob -> string2;
@@ -128,20 +128,20 @@ void PairDistribution_swapInputsAndOutputs (PairDistribution me) {
 }
 
 static double PairDistributions_getTotalWeight_checkPositive (PairDistribution me) throw (MelderError) {
-	double totalWeight = 0.0;
-	for (long ipair = 1; ipair <= my pairs.size; ipair ++) {
+	real80 totalWeight = 0.0;
+	for (integer ipair = 1; ipair <= my pairs.size; ipair ++) {
 		PairProbability prob = my pairs.at [ipair];
 		totalWeight += prob -> weight;
 	}
 	if (totalWeight <= 0.0) {
 		Melder_throw (me, U": the total probability weight is ", Melder_half (totalWeight), U" but should be greater than zero for this operation.");
 	}
-	return totalWeight;
+	return (real) totalWeight;
 }
 
-void PairDistribution_to_Stringses (PairDistribution me, long nout, autoStrings *strings1_out, autoStrings *strings2_out) {
+void PairDistribution_to_Stringses (PairDistribution me, integer nout, autoStrings *strings1_out, autoStrings *strings2_out) {
 	try {
-		long nin = my pairs.size, iin;
+		integer nin = my pairs.size, iin;
 		if (nin < 1)
 			Melder_throw (U"No candidates.");
 		if (nout < 1)
@@ -153,7 +153,7 @@ void PairDistribution_to_Stringses (PairDistribution me, long nout, autoStrings
 		autoStrings strings2 = Thing_new (Strings);
 		strings2 -> numberOfStrings = nout;
 		strings2 -> strings = NUMvector <char32 *> (1, nout);
-		for (long iout = 1; iout <= nout; iout ++) {
+		for (integer iout = 1; iout <= nout; iout ++) {
 			do {
 				double rand = NUMrandomUniform (0, total), sum = 0.0;
 				for (iin = 1; iin <= nin; iin ++) {
@@ -179,7 +179,7 @@ void PairDistribution_peekPair (PairDistribution me, char32 **string1, char32 **
 	try {
 		*string1 = *string2 = nullptr;
 		double total = 0.0;
-		long nin = my pairs.size, iin;
+		integer nin = my pairs.size, iin;
 		PairProbability prob;
 		if (nin < 1) Melder_throw (U"No candidates.");
 		for (iin = 1; iin <= nin; iin ++) {
@@ -206,12 +206,12 @@ void PairDistribution_peekPair (PairDistribution me, char32 **string1, char32 **
 static double PairDistribution_getFractionCorrect (PairDistribution me, int which) {
 	try {
 		double correct = 0.0;
-		long pairmin = 1, ipair;
+		integer pairmin = 1, ipair;
 		autoPairDistribution thee = Data_copy (me);
 		thy pairs.sort (PairProbability_compare);
 		double total = PairDistributions_getTotalWeight_checkPositive (thee.get());
 		do {
-			long pairmax = pairmin;
+			integer pairmax = pairmin;
 			char32 *firstInput = thy pairs.at [pairmin] -> string1;
 			for (ipair = pairmin + 1; ipair <= thy pairs.size; ipair ++) {
 				PairProbability prob = thy pairs.at [ipair];
@@ -255,17 +255,17 @@ double PairDistribution_getFractionCorrect_probabilityMatching (PairDistribution
 	return PairDistribution_getFractionCorrect (me, 1);
 }
 
-double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, Distributions dist, long column) {
+double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, Distributions dist, integer column) {
 	try {
 		double correct = 0.0;
-		long pairmin = 1;
+		integer pairmin = 1;
 		char32 string [1000];
 		Distributions_checkSpecifiedColumnNumberWithinRange (dist, column);
 		autoPairDistribution thee = Data_copy (me);
 		thy pairs.sort (PairProbability_compare);
 		double total = PairDistributions_getTotalWeight_checkPositive (thee.get());
 		do {
-			long pairmax = pairmin, length, ipair;
+			integer pairmax = pairmin, length, ipair;
 			double sum = 0.0, sumDist = 0.0;
 			char32 *firstInput = thy pairs.at [pairmin] -> string1;
 			for (ipair = pairmin + 1; ipair <= thy pairs.size; ipair ++) {
@@ -280,7 +280,7 @@ double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, D
 				PairProbability prob = thy pairs.at [ipair];
 				double p = prob -> weight / total, pout = 0.0;
 				Melder_sprint (string, 1000, prob -> string1, U" \\-> ", prob -> string2);
-				for (long idist = 1; idist <= dist -> numberOfRows; idist ++) {
+				for (integer idist = 1; idist <= dist -> numberOfRows; idist ++) {
 					if (str32equ (string, dist -> rowLabels [idist])) {
 						pout = dist -> data [idist] [column];
 						break;
@@ -290,7 +290,7 @@ double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, D
 			}
 			Melder_sprint (string, 1000, firstInput, U" \\-> ");
 			length = str32len (string);
-			for (long idist = 1; idist <= dist -> numberOfRows; idist ++) {
+			for (integer idist = 1; idist <= dist -> numberOfRows; idist ++) {
 				if (str32nequ (string, dist -> rowLabels [idist], length)) {
 					sumDist += dist -> data [idist] [column];
 				}
@@ -307,7 +307,7 @@ double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, D
 autoTable PairDistribution_to_Table (PairDistribution me) {
 	try {
 		autoTable thee = Table_createWithColumnNames (my pairs.size, U"string1 string2 weight");
-		for (long ipair = 1; ipair <= my pairs.size; ipair ++) {
+		for (integer ipair = 1; ipair <= my pairs.size; ipair ++) {
 			PairProbability prob = my pairs.at [ipair];
 			Table_setStringValue (thee.get(), ipair, 1, prob -> string1);
 			Table_setStringValue (thee.get(), ipair, 2, prob -> string2);
diff --git a/stat/PairDistribution.h b/stat/PairDistribution.h
index 0afd26a..723fc27 100644
--- a/stat/PairDistribution.h
+++ b/stat/PairDistribution.h
@@ -2,7 +2,7 @@
 #define _PairDistribution_h_
 /* PairDistribution.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
@@ -30,20 +30,20 @@ int PairProbability_compare (PairProbability me, PairProbability thee) noexcept;
 
 autoPairDistribution PairDistribution_create ();
 
-const char32 * PairDistribution_getString1 (PairDistribution me, long pairNumber);
-const char32 * PairDistribution_getString2 (PairDistribution me, long pairNumber);
-double PairDistribution_getWeight (PairDistribution me, long pairNumber);
+const char32 * PairDistribution_getString1 (PairDistribution me, integer pairNumber);
+const char32 * PairDistribution_getString2 (PairDistribution me, integer pairNumber);
+double PairDistribution_getWeight (PairDistribution me, integer pairNumber);
 
 void PairDistribution_add (PairDistribution me, const char32 *string1, const char32 *string2, double weight);
 void PairDistribution_removeZeroWeights (PairDistribution me);
-void PairDistribution_to_Stringses (PairDistribution me, long nout, autoStrings *strings1, autoStrings *strings2);
+void PairDistribution_to_Stringses (PairDistribution me, integer nout, autoStrings *strings1, autoStrings *strings2);
 void PairDistribution_peekPair (PairDistribution me, char32 **string1, char32 **string2);
 
 void PairDistribution_swapInputsAndOutputs (PairDistribution me);
 
 double PairDistribution_getFractionCorrect_maximumLikelihood (PairDistribution me);
 double PairDistribution_getFractionCorrect_probabilityMatching (PairDistribution me);
-double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, Distributions thee, long column);
+double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, Distributions thee, integer column);
 
 autoTable PairDistribution_to_Table (PairDistribution me);
 
diff --git a/stat/Regression.cpp b/stat/Regression.cpp
index 7c2a0b6..0e70949 100644
--- a/stat/Regression.cpp
+++ b/stat/Regression.cpp
@@ -44,18 +44,18 @@ void structRegression :: v_info () {
 	Regression_Parent :: v_info ();
 	MelderInfo_writeLine (U"Factors:");
 	MelderInfo_writeLine (U"   Number of factors: ", our parameters.size);
-	for (long ivar = 1; ivar <= our parameters.size; ivar ++) {
+	for (integer ivar = 1; ivar <= our parameters.size; ivar ++) {
 		RegressionParameter parm = our parameters.at [ivar];
 		MelderInfo_writeLine (U"   Factor ", ivar, U": ", parm -> label);
 	}
 	MelderInfo_writeLine (U"Fitted coefficients:");
 	MelderInfo_writeLine (U"   Intercept: ", intercept);
-	for (long ivar = 1; ivar <= our parameters.size; ivar ++) {
+	for (integer ivar = 1; ivar <= our parameters.size; ivar ++) {
 		RegressionParameter parm = our parameters.at [ivar];
 		MelderInfo_writeLine (U"   Coefficient of factor ", parm -> label, U": ", parm -> value);
 	}
 	MelderInfo_writeLine (U"Ranges of values:");
-	for (long ivar = 1; ivar <= our parameters.size; ivar ++) {
+	for (integer ivar = 1; ivar <= our parameters.size; ivar ++) {
 		RegressionParameter parm = our parameters.at [ivar];
 		MelderInfo_writeLine (U"   Range of factor ", parm -> label, U": minimum ",
 			parm -> minimum, U", maximum ", parm -> maximum);
@@ -81,8 +81,8 @@ void Regression_addParameter (Regression me, const char32 *label, double minimum
 	}
 }
 
-long Regression_getFactorIndexFromFactorName_e (Regression me, const char32 *factorName) {
-	for (long iparm = 1; iparm <= my parameters.size; iparm ++) {
+integer Regression_getFactorIndexFromFactorName_e (Regression me, const char32 *factorName) {
+	for (integer iparm = 1; iparm <= my parameters.size; iparm ++) {
 		RegressionParameter parm = my parameters.at [iparm];
 		if (Melder_equ (factorName, parm -> label)) return iparm;
 	}
@@ -103,10 +103,10 @@ autoLinearRegression LinearRegression_create () {
 
 autoLinearRegression Table_to_LinearRegression (Table me) {
 	try {
-		long numberOfIndependentVariables = my numberOfColumns - 1, numberOfParameters = my numberOfColumns;
+		integer numberOfIndependentVariables = my numberOfColumns - 1, numberOfParameters = my numberOfColumns;
 		if (numberOfParameters < 1)   // includes intercept
 			Melder_throw (U"Not enough columns (has to be more than 1).");
-		long numberOfCells = my rows.size;
+		integer numberOfCells = my rows.size;
 		if (numberOfCells == 0)
 			Melder_throw (U"Not enough rows (0).");
 		if (numberOfCells < numberOfParameters) {
@@ -116,13 +116,13 @@ autoLinearRegression Table_to_LinearRegression (Table me) {
 		autoNUMvector <double> b (1, numberOfCells);
 		autoNUMvector <double> x (1, numberOfParameters);
 		autoLinearRegression thee = LinearRegression_create ();
-		for (long ivar = 1; ivar <= numberOfIndependentVariables; ivar ++) {
+		for (integer ivar = 1; ivar <= numberOfIndependentVariables; ivar ++) {
 			double minimum = Table_getMinimum (me, ivar);
 			double maximum = Table_getMaximum (me, ivar);
 			Regression_addParameter (thee.get(), my columnHeaders [ivar]. label, minimum, maximum, 0.0);
 		}
-		for (long icell = 1; icell <= numberOfCells; icell ++) {
-			for (long ivar = 1; ivar < numberOfParameters; ivar ++) {
+		for (integer icell = 1; icell <= numberOfCells; icell ++) {
+			for (integer ivar = 1; ivar < numberOfParameters; ivar ++) {
 				u [icell] [ivar] = Table_getNumericValue_Assert (me, icell, ivar);
 			}
 			u [icell] [numberOfParameters] = 1.0;   // for the intercept
@@ -130,7 +130,7 @@ autoLinearRegression Table_to_LinearRegression (Table me) {
 		}
 		NUMsolveEquation (u.peek(), numberOfCells, numberOfParameters, b.peek(), NUMeps * numberOfCells, x.peek());
 		thy intercept = x [numberOfParameters];
-		for (long ivar = 1; ivar <= numberOfIndependentVariables; ivar ++) {
+		for (integer ivar = 1; ivar <= numberOfIndependentVariables; ivar ++) {
 			RegressionParameter parm = thy parameters.at [ivar];
 			parm -> value = x [ivar];
 		}
diff --git a/stat/Regression.h b/stat/Regression.h
index 50ac8e6..09e33db 100644
--- a/stat/Regression.h
+++ b/stat/Regression.h
@@ -2,7 +2,7 @@
 #define _Regression_h_
 /* Regression.h
  *
- * Copyright (C) 2005-2011,2014,2015 Paul Boersma
+ * Copyright (C) 2005-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
@@ -24,7 +24,7 @@
 
 void Regression_init (Regression me);
 void Regression_addParameter (Regression me, const char32 *label, double minimum, double maximum, double value);
-long Regression_getFactorIndexFromFactorName_e (Regression me, const char32 *factorName);
+integer Regression_getFactorIndexFromFactorName_e (Regression me, const char32 *factorName);
 
 Thing_define (LinearRegression, Regression) {
 };
diff --git a/stat/praat_Stat.cpp b/stat/praat_Stat.cpp
index cd1a109..e6b1815 100644
--- a/stat/praat_Stat.cpp
+++ b/stat/praat_Stat.cpp
@@ -26,7 +26,7 @@
 
 #include "praat_TableOfReal.h"
 
-static const char32 * Table_messageColumn (Table me, long column) {
+static const char32 * Table_messageColumn (Table me, integer column) {
 	if (my columnHeaders [column]. label && my columnHeaders [column]. label [0] != U'\0')
 		return Melder_cat (U"\"", my columnHeaders [column]. label, U"\"");
 	else
@@ -110,8 +110,8 @@ FORM (GRAPHICS_LogisticRegression_drawBoundary, U"LogisticRegression: Draw bound
 	OK
 DO
 	GRAPHICS_EACH (LogisticRegression)
-		long xfactor = Regression_getFactorIndexFromFactorName_e (me, horizontalFactor);
-		long yfactor = Regression_getFactorIndexFromFactorName_e (me, verticalFactor);
+		integer xfactor = Regression_getFactorIndexFromFactorName_e (me, horizontalFactor);
+		integer yfactor = Regression_getFactorIndexFromFactorName_e (me, verticalFactor);
 		LogisticRegression_drawBoundary (me, GRAPHICS,
 			xfactor, fromHorizontal, toHorizontal,
 			yfactor, fromVertical, toVertical,
@@ -143,7 +143,7 @@ DIRECT (REAL_PairDistribution_getFractionCorrect_probabilityMatching) {
 
 DIRECT (INTEGER_PairDistribution_getNumberOfPairs) {
 	NUMBER_ONE (PairDistribution)
-		long result = my pairs.size;
+		integer result = my pairs.size;
 	NUMBER_ONE_END (U" pairs")
 }
 
@@ -324,9 +324,9 @@ FORM (GRAPHICS_Table_scatterPlot, U"Scatter plot", nullptr) {
 	OK
 DO
 	GRAPHICS_EACH (Table)
-		long xcolumn = Table_getColumnIndexFromColumnLabel (me, horizontalColumn);
-		long ycolumn = Table_getColumnIndexFromColumnLabel (me, verticalColumn);
-		long markColumn = Table_getColumnIndexFromColumnLabel (me, columnWithMarks);
+		integer xcolumn = Table_getColumnIndexFromColumnLabel (me, horizontalColumn);
+		integer ycolumn = Table_getColumnIndexFromColumnLabel (me, verticalColumn);
+		integer markColumn = Table_getColumnIndexFromColumnLabel (me, columnWithMarks);
 		Table_scatterPlot (me, GRAPHICS, xcolumn, ycolumn,
 			fromHorizontal, toHorizontal, fromVertical, toVertical, markColumn, fontSize, garnish);
 	GRAPHICS_EACH_END
@@ -345,8 +345,8 @@ FORM (GRAPHICS_Table_scatterPlot_mark, U"Scatter plot (marks)", nullptr) {
 	OK
 DO
 	GRAPHICS_EACH (Table)
-		long xcolumn = Table_getColumnIndexFromColumnLabel (me, horizontalColumn);
-		long ycolumn = Table_getColumnIndexFromColumnLabel (me, verticalColumn);
+		integer xcolumn = Table_getColumnIndexFromColumnLabel (me, horizontalColumn);
+		integer ycolumn = Table_getColumnIndexFromColumnLabel (me, verticalColumn);
 		Table_scatterPlot_mark (me, GRAPHICS, xcolumn, ycolumn,
 			fromHorizontal, toHorizontal, fromVertical, toVertical,
 			markSize, markString, garnish);
@@ -365,8 +365,8 @@ FORM (GRAPHICS_Table_drawEllipse, U"Draw ellipse (standard deviation)", nullptr)
 	OK
 DO
 	GRAPHICS_EACH (Table)
-		long xcolumn = Table_getColumnIndexFromColumnLabel (me, horizontalColumn);
-		long ycolumn = Table_getColumnIndexFromColumnLabel (me, verticalColumn);
+		integer xcolumn = Table_getColumnIndexFromColumnLabel (me, horizontalColumn);
+		integer ycolumn = Table_getColumnIndexFromColumnLabel (me, verticalColumn);
 		Table_drawEllipse_e (me, GRAPHICS, xcolumn, ycolumn,
 			fromHorizontal, toHorizontal, fromVertical, toVertical, numberOfSigmas, garnish);
 	GRAPHICS_EACH_END
@@ -379,8 +379,8 @@ FORM (INTEGER_Table_drawRowFromDistribution, U"Table: Draw row from distribution
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnWithDistribution);
-		long result = Table_drawRowFromDistribution (me, columnNumber);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnWithDistribution);
+		integer result = Table_drawRowFromDistribution (me, columnNumber);
 	NUMBER_ONE_END (U" (random row number)")
 }
 
@@ -389,7 +389,7 @@ FORM (INTEGER_Table_getColumnIndex, U"Table: Get column index", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long result = Table_findColumnIndexFromColumnLabel (me, columnLabel);
+		integer result = Table_findColumnIndexFromColumnLabel (me, columnLabel);
 	NUMBER_ONE_END (U" (index of column ", columnLabel, U")")
 }
 
@@ -411,8 +411,8 @@ FORM (REAL_Table_getGroupMean, U"Table: Get group mean", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long column = Table_getColumnIndexFromColumnLabel (me, columnLabel);
-		long groupColumn = Table_getColumnIndexFromColumnLabel (me, groupColumnLabel);
+		integer column = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer groupColumn = Table_getColumnIndexFromColumnLabel (me, groupColumnLabel);
 		double result = Table_getGroupMean (me, column, groupColumn, group);
 	NUMBER_ONE_END (U" (mean of ", columnLabel, U" in group ", group, U")")
 }
@@ -422,7 +422,7 @@ FORM (REAL_Table_getMaximum, U"Table: Get maximum", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		double result = Table_getMaximum (me, columnNumber);
 	NUMBER_ONE_END (U" (maximum of ", columnLabel, U")")
 }
@@ -432,7 +432,7 @@ FORM (REAL_Table_getMean, U"Table: Get mean", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		double result = Table_getMean (me, columnNumber);
 	NUMBER_ONE_END (U" (mean of ", columnLabel, U")")
 }
@@ -442,7 +442,7 @@ FORM (REAL_Table_getMinimum, U"Table: Get minimum", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		double result = Table_getMinimum (me, columnNumber);
 	NUMBER_ONE_END (U" (minimum of ", columnLabel, U")")
 }
@@ -453,7 +453,7 @@ FORM (REAL_Table_getQuantile, U"Table: Get quantile", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		double result = Table_getQuantile (me, columnNumber, quantile);
 	NUMBER_ONE_END (U" (", quantile, U" quantile of ", columnLabel, U")")
 }
@@ -463,20 +463,20 @@ FORM (REAL_Table_getStandardDeviation, U"Table: Get standard deviation", nullptr
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		double result = Table_getStdev (me, columnNumber);
 	NUMBER_ONE_END (U" (standard deviation of ", columnLabel, U")")
 }
 
 DIRECT (INTEGER_Table_getNumberOfColumns) {
 	NUMBER_ONE (Table)
-		long result = my numberOfColumns;
+		integer result = my numberOfColumns;
 	NUMBER_ONE_END (U" columns")
 }
 
 DIRECT (INTEGER_Table_getNumberOfRows) {
 	NUMBER_ONE (Table)
-		long result = my rows.size;
+		integer result = my rows.size;
 	NUMBER_ONE_END (U" rows")
 }
 
@@ -487,7 +487,7 @@ FORM (STRING_Table_getValue, U"Table: Get value", nullptr) {
 DO
 	STRING_ONE (Table)
 		Table_checkSpecifiedRowNumberWithinRange (me, rowNumber);
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		const char32 *result = my rows.at [rowNumber] -> cells [columnNumber]. string;
 	STRING_ONE_END
 }
@@ -498,8 +498,8 @@ FORM (INTEGER_Table_searchColumn, U"Table: Search column", nullptr) {
 	OK
 DO
 	NUMBER_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
-		long result = Table_searchColumn (me, columnNumber, value);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer result = Table_searchColumn (me, columnNumber, value);
 	NUMBER_ONE_END (U" (first row in which ", columnLabel, U" is ", value)
 }
 	
@@ -512,8 +512,8 @@ FORM (INFO_Table_reportCorrelation_kendallTau, U"Report correlation (Kendall tau
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		double correlation, significance, lowerLimit, upperLimit;
 		correlation = Table_getCorrelation_kendallTau (me, columnNumber1, columnNumber2, oneTailedUnconfidence,
 			& significance, & lowerLimit, & upperLimit);
@@ -538,8 +538,8 @@ FORM (INFO_Table_reportCorrelation_pearsonR, U"Report correlation (Pearson r)",
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		double correlation, significance, lowerLimit, upperLimit;
 		correlation = Table_getCorrelation_pearsonR (me, columnNumber1, columnNumber2, oneTailedUnconfidence,
 			& significance, & lowerLimit, & upperLimit);
@@ -565,8 +565,8 @@ FORM (INFO_Table_reportDifference_studentT, U"Report difference (Student t)", nu
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		double difference, t, numberOfDegreesOfFreedom, significance, lowerLimit, upperLimit;
 		difference = Table_getDifference_studentT (me, columnNumber1, columnNumber2, oneTailedUnconfidence,
 			& t, & numberOfDegreesOfFreedom, & significance, & lowerLimit, & upperLimit);
@@ -595,8 +595,8 @@ FORM (INFO_Table_reportGroupDifference_studentT, U"Report group difference (Stud
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
-		long groupColumnNumber = Table_getColumnIndexFromColumnLabel (me, groupColumn);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
+		integer groupColumnNumber = Table_getColumnIndexFromColumnLabel (me, groupColumn);
 		double mean, tFromZero, numberOfDegreesOfFreedom, significanceFromZero, lowerLimit, upperLimit;
 		mean = Table_getGroupDifference_studentT (me, columnNumber, groupColumnNumber, group1, group2, oneTailedUnconfidence,
 			& tFromZero, & numberOfDegreesOfFreedom, & significanceFromZero, & lowerLimit, & upperLimit);
@@ -624,8 +624,8 @@ FORM (INFO_Table_reportGroupDifference_wilcoxonRankSum, U"Report group differenc
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
-		long groupColumnNumber = Table_getColumnIndexFromColumnLabel (me, groupColumn);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
+		integer groupColumnNumber = Table_getColumnIndexFromColumnLabel (me, groupColumn);
 		double areaUnderCurve, rankSum, significanceFromZero;
 		areaUnderCurve = Table_getGroupDifference_wilcoxonRankSum (me, columnNumber, groupColumnNumber, group1, group2,
 			& rankSum, & significanceFromZero);
@@ -648,8 +648,8 @@ FORM (INFO_Table_reportGroupMean_studentT, U"Report group mean (Student t)", nul
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
-		long groupColumnNumber = Table_getColumnIndexFromColumnLabel (me, groupColumn);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
+		integer groupColumnNumber = Table_getColumnIndexFromColumnLabel (me, groupColumn);
 		double mean, tFromZero, numberOfDegreesOfFreedom, significanceFromZero, lowerLimit, upperLimit;
 		mean = Table_getGroupMean_studentT (me, columnNumber, groupColumnNumber, group, oneTailedUnconfidence,
 			& tFromZero, & numberOfDegreesOfFreedom, & significanceFromZero, & lowerLimit, & upperLimit);
@@ -675,7 +675,7 @@ FORM (INFO_Table_reportMean_studentT, U"Report mean (Student t)", nullptr) {
 	OK
 DO
 	INFO_ONE (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, column);
 		double mean, tFromZero, numberOfDegreesOfFreedom, significanceFromZero, lowerLimit, upperLimit;
 		mean = Table_getMean_studentT (me, columnNumber, oneTailedUnconfidence,
 			& tFromZero, & numberOfDegreesOfFreedom, & significanceFromZero, & lowerLimit, & upperLimit);
@@ -712,8 +712,8 @@ FORM (MODIFY_Table_appendDifferenceColumn, U"Table: Append difference column", n
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		Table_appendDifferenceColumn (me, columnNumber1, columnNumber2, label);
 	MODIFY_EACH_END
 }
@@ -725,8 +725,8 @@ FORM (MODIFY_Table_appendProductColumn, U"Table: Append product column", nullptr
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		Table_appendProductColumn (me, columnNumber1, columnNumber2, label);
 	MODIFY_EACH_END
 }
@@ -738,8 +738,8 @@ FORM (MODIFY_Table_appendQuotientColumn, U"Table: Append quotient column", nullp
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		Table_appendQuotientColumn (me, columnNumber1, columnNumber2, label);
 	MODIFY_EACH_END
 }
@@ -751,8 +751,8 @@ FORM (MODIFY_Table_appendSumColumn, U"Table: Append sum column", nullptr) {
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, column1);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, column2);
 		Table_appendSumColumn (me, columnNumber1, columnNumber2, label);
 	MODIFY_EACH_END
 }
@@ -769,7 +769,7 @@ FORM (MODIFY_Table_formula, U"Table: Formula", U"Table: Formula...") {
 	OK
 DO
 	MODIFY_EACH_WEAK (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		Table_formula (me, columnNumber, formula, interpreter);
 	MODIFY_EACH_WEAK_END
 }
@@ -781,8 +781,8 @@ FORM (MODIFY_Table_formula_columnRange, U"Table: Formula (column range)", U"Tabl
 	OK
 DO
 	MODIFY_EACH_WEAK (Table)
-		long columnNumber1 = Table_getColumnIndexFromColumnLabel (me, fromColumn);
-		long columnNumber2 = Table_getColumnIndexFromColumnLabel (me, toColumn);
+		integer columnNumber1 = Table_getColumnIndexFromColumnLabel (me, fromColumn);
+		integer columnNumber2 = Table_getColumnIndexFromColumnLabel (me, toColumn);
 		Table_formula_columnRange (me, columnNumber1, columnNumber2, formula, interpreter);
 	MODIFY_EACH_WEAK_END
 }
@@ -811,7 +811,7 @@ FORM (MODIFY_Table_removeColumn, U"Table: Remove column", nullptr) {
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		Table_removeColumn (me, columnNumber);
 	MODIFY_EACH_END
 }
@@ -841,7 +841,7 @@ FORM (MODIFY_Table_setColumnLabel_label, U"Set column label", nullptr) {
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, oldLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, oldLabel);
 		Table_setColumnLabel (me, columnNumber, newLabel);
 	MODIFY_EACH_END
 }
@@ -853,7 +853,7 @@ FORM (MODIFY_Table_setNumericValue, U"Table: Set numeric value", nullptr) {
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		Table_setNumericValue (me, rowNumber, columnNumber, numericValue);
 	MODIFY_EACH_END
 }
@@ -865,7 +865,7 @@ FORM (MODIFY_Table_setStringValue, U"Table: Set string value", nullptr) {
 	OK
 DO
 	MODIFY_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnLabel);
 		Table_setStringValue (me, rowNumber, columnNumber, stringValue);
 	MODIFY_EACH_END
 }
@@ -922,7 +922,7 @@ FORM (NEW_Table_extractRowsWhereColumn_number, U"Table: Extract rows where colum
 	OK
 DO
 	CONVERT_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, extractAllRowsWhereColumn___);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, extractAllRowsWhereColumn___);
 		autoTable result = Table_extractRowsWhereColumn_number (me, columnNumber, (kMelder_number) ___is___, ___theNumber);
 	CONVERT_EACH_END (my name, U"_", Table_messageColumn (me, columnNumber), U"_",
 		isdefined (___theNumber) ? Melder_integer (lround (___theNumber)) : U"undefined")
@@ -935,7 +935,7 @@ FORM (NEW_Table_extractRowsWhereColumn_text, U"Table: Extract rows where column
 	OK
 DO
 	CONVERT_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, extractAllRowsWhereColumn___);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, extractAllRowsWhereColumn___);
 		autoTable result = Table_extractRowsWhereColumn_string (me, columnNumber, (kMelder_string) ___, ___theText);
 	CONVERT_EACH_END (my name, U"_", ___theText)
 }
@@ -954,7 +954,7 @@ FORM (NEW_Table_rowsToColumns, U"Table: Rows to columns", nullptr) {
 	OK
 DO
 	CONVERT_EACH (Table)
-		long columnNumber = Table_getColumnIndexFromColumnLabel (me, columnToTranspose);
+		integer columnNumber = Table_getColumnIndexFromColumnLabel (me, columnToTranspose);
 		autoTable result = Table_rowsToColumns (me, factors, columnNumber, columnsToExpand);
 	CONVERT_EACH_END (my name, U"_nested")
 }
@@ -981,7 +981,7 @@ FORM (NEW_Table_to_TableOfReal, U"Table: Down to TableOfReal", nullptr) {
 	OK
 DO
 	CONVERT_EACH (Table)
-		long columnNumber = Table_findColumnIndexFromColumnLabel (me, columnForRowLabels);
+		integer columnNumber = Table_findColumnIndexFromColumnLabel (me, columnForRowLabels);
 		autoTableOfReal result = Table_to_TableOfReal (me, columnNumber);
 	CONVERT_EACH_END (my name)
 }
@@ -1004,7 +1004,7 @@ FORM_READ (READ1_TableOfReal_readFromHeaderlessSpreadsheetFile, U"Read TableOfRe
 }
 
 static bool isTabSeparated_8bit (integer nread, const char *header) {
-	for (long i = 0; i < nread; i ++) {
+	for (integer i = 0; i < nread; i ++) {
 		if (header [i] == '\t') return true;
 		if (header [i] == '\n' || header [i] == '\r') return false;
 	}
@@ -1012,7 +1012,7 @@ static bool isTabSeparated_8bit (integer nread, const char *header) {
 }
 
 static bool isTabSeparated_utf16be (integer nread, const char *header) {
-	for (long i = 2; i < nread; i += 2) {
+	for (integer i = 2; i < nread; i += 2) {
 		if (header [i] == '\0' && header [i + 1] == '\t') return true;
 		if (header [i] == '\0' && (header [i + 1] == '\n' || header [i + 1] == '\r')) return false;
 	}
@@ -1020,7 +1020,7 @@ static bool isTabSeparated_utf16be (integer nread, const char *header) {
 }
 
 static bool isTabSeparated_utf16le (integer nread, const char *header) {
-	for (long i = 2; i < nread; i += 2) {
+	for (integer i = 2; i < nread; i += 2) {
 		if (header [i + 1] == '\0' && header [i] == '\t') return true;
 		if (header [i + 1] == '\0' && (header [i] == '\n' || header [i] == '\r')) return false;
 	}
diff --git a/stat/praat_TableOfReal.cpp b/stat/praat_TableOfReal.cpp
index bfcb083..70bdd00 100644
--- a/stat/praat_TableOfReal.cpp
+++ b/stat/praat_TableOfReal.cpp
@@ -125,7 +125,7 @@ FORM (INTEGER_TableOfReal_getColumnIndex, U"Get column index", nullptr) {
 	OK
 DO
 	NUMBER_ONE (TableOfReal)
-		long result = TableOfReal_columnLabelToIndex (me, columnLabel);
+		integer result = TableOfReal_columnLabelToIndex (me, columnLabel);
 	NUMBER_ONE_END (U" (index of column ", columnLabel, U")")
 }
 	
@@ -156,7 +156,7 @@ FORM (REAL_TableOfReal_getColumnMean_label, U"Get column mean", nullptr) {
 	OK
 DO
 	NUMBER_ONE (TableOfReal)
-		long columnNumber = TableOfReal_columnLabelToIndex (me, columnLabel);
+		integer columnNumber = TableOfReal_columnLabelToIndex (me, columnLabel);
 		if (columnNumber == 0) Melder_throw (me, U": your column label does not exist.");
 		double result = TableOfReal_getColumnMean (me, columnNumber);
 	NUMBER_ONE_END (U" (mean of column ", columnLabel, U")")
@@ -178,7 +178,7 @@ FORM (REAL_TableOfReal_getColumnStdev_label, U"Get column standard deviation", n
 	OK
 DO
 	NUMBER_ONE (TableOfReal)
-		long columnNumber = TableOfReal_columnLabelToIndex (me, columnLabel);
+		integer columnNumber = TableOfReal_columnLabelToIndex (me, columnLabel);
 		if (columnNumber == 0) Melder_throw (me, U": column label does not exist.");
 		double result = TableOfReal_getColumnStdev (me, columnNumber);
 	NUMBER_ONE_END (U" (standard deviation of column ", columnLabel, U")")
@@ -186,13 +186,13 @@ DO
 
 DIRECT (INTEGER_TableOfReal_getNumberOfColumns) {
 	NUMBER_ONE (TableOfReal)
-		long result = my numberOfColumns;
+		integer result = my numberOfColumns;
 	NUMBER_ONE_END (U" columns")
 }
 
 DIRECT (INTEGER_TableOfReal_getNumberOfRows) {
 	NUMBER_ONE (TableOfReal)
-		long result = my numberOfRows;
+		integer result = my numberOfRows;
 	NUMBER_ONE_END (U" rows")
 }
 
@@ -201,7 +201,7 @@ FORM (INTEGER_TableOfReal_getRowIndex, U"Get row index", nullptr) {
 	OK
 DO
 	NUMBER_ONE (TableOfReal)
-		long result = TableOfReal_rowLabelToIndex (me, rowLabel);
+		integer result = TableOfReal_rowLabelToIndex (me, rowLabel);
 	NUMBER_ONE_END (U" (index of row ", rowLabel, U")")
 }
 
@@ -294,7 +294,7 @@ FORM (MODIFY_TableOfReal_setColumnLabel_label, U"Set column label", nullptr) {
 	OK
 DO
 	MODIFY_EACH (TableOfReal)
-		long columnNumber = TableOfReal_columnLabelToIndex (me, oldLabel);
+		integer columnNumber = TableOfReal_columnLabelToIndex (me, oldLabel);
 		TableOfReal_setColumnLabel (me, columnNumber, newLabel);
 	MODIFY_EACH_END
 }
@@ -330,7 +330,7 @@ FORM (MODIFY_TableOfReal_setRowLabel_label, U"Set row label", nullptr) {
 	OK
 DO
 	MODIFY_EACH (TableOfReal)
-		long rowNumber = TableOfReal_rowLabelToIndex (me, oldLabel);
+		integer rowNumber = TableOfReal_rowLabelToIndex (me, oldLabel);
 		TableOfReal_setRowLabel (me, rowNumber, newLabel);
 	MODIFY_EACH_END
 }
diff --git a/sys/Formula.cpp b/sys/Formula.cpp
index cfe11d7..e697617 100644
--- a/sys/Formula.cpp
+++ b/sys/Formula.cpp
@@ -2458,14 +2458,14 @@ inline static void nummat_multiplyByScalar (nummat x, real factor) {
 	}
 }
 inline static autonumvec add_numvec (numvec x, real addend) {
-	autonumvec result (x.size, false);
+	autonumvec result (x.size, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= x.size; i ++) {
 		result [i] = x [i] + addend;
 	}
 	return result;
 }
 inline static autonummat add_nummat (nummat x, real addend) {
-	autonummat result (x.nrow, x.ncol, false);
+	autonummat result (x.nrow, x.ncol, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= x.nrow; irow ++) {
 		for (integer icol = 1; icol <= x.ncol; icol ++) {
 			result [irow] [icol] = x [irow] [icol] + addend;
@@ -2728,21 +2728,21 @@ inline static void nummat_subtractNummatReversed (nummat x, nummat y) {
 	}
 }
 inline static autonumvec sub_numvec (numvec x, real y) {
-	autonumvec result (x.size, false);
+	autonumvec result (x.size, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= x.size; i ++) {
 		result [i] = x [i] - y;
 	}
 	return result;
 }
 inline static autonumvec sub_numvec (real x, numvec y) {
-	autonumvec result (y.size, false);
+	autonumvec result (y.size, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= y.size; i ++) {
 		result [i] = x - y [i];
 	}
 	return result;
 }
 inline static autonummat sub_nummat (nummat x, real y) {
-	autonummat result (x.nrow, x.ncol, false);
+	autonummat result (x.nrow, x.ncol, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= x.nrow; irow ++) {
 		for (integer icol = 1; icol <= x.ncol; icol ++) {
 			result [irow] [icol] = x [irow] [icol] - y;
@@ -2751,7 +2751,7 @@ inline static autonummat sub_nummat (nummat x, real y) {
 	return result;
 }
 inline static autonummat sub_nummat (real x, nummat y) {
-	autonummat result (y.nrow, y.ncol, false);
+	autonummat result (y.nrow, y.ncol, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= y.nrow; irow ++) {
 		for (integer icol = 1; icol <= y.ncol; icol ++) {
 			result [irow] [icol] = x - y [irow] [icol];
@@ -2879,7 +2879,7 @@ static void do_sub () {
 		if (newlength >= 0 && str32nequ (x->string + newlength, y->string, length2)) {
 			result = Melder_malloc (char32, newlength + 1);
 			str32ncpy (result, x->string, newlength);
-			result [newlength] = '\0';
+			result [newlength] = U'\0';
 		} else {
 			result = Melder_dup (x->string);
 		}
@@ -2916,7 +2916,7 @@ static void do_mul () {
 				w ++;
 			} else {
 				integer ny = y->numericVector.size;
-				autonumvec result { ny, false };
+				autonumvec result { ny, kTensorInitializationType::RAW };
 				for (integer i = 1; i <= ny; i ++) {
 					double yvalue = y->numericVector [i];
 					result [i] = xvalue * yvalue;
@@ -2936,7 +2936,7 @@ static void do_mul () {
 				w ++;
 			} else {
 				integer nrow = y->numericMatrix.nrow, ncol = y->numericMatrix.ncol;
-				autonummat result (nrow, ncol, false);
+				autonummat result (nrow, ncol, kTensorInitializationType::RAW);
 				for (integer irow = 1; irow <= nrow; irow ++) {
 					for (integer icol = 1; icol <= ncol; icol ++) {
 						double yvalue = y->numericMatrix [irow] [icol];
@@ -2955,7 +2955,7 @@ static void do_mul () {
 		integer 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".");
-		autonumvec result { nx, false };
+		autonumvec result { nx, kTensorInitializationType::RAW };
 		for (integer i = 1; i <= nx; i ++) {
 			double xvalue = x->numericVector [i];
 			double yvalue = y->numericVector [i];
@@ -2977,7 +2977,7 @@ static void do_rdiv () {
 			integer 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".");
-			autonumvec result { nelem1, false };
+			autonumvec result { nelem1, kTensorInitializationType::RAW };
 			for (integer ielem = 1; ielem <= nelem1; ielem ++)
 				result [ielem] = x->numericVector [ielem] / y->numericVector [ielem];
 			pushNumericVector (result.move());
@@ -2988,7 +2988,7 @@ static void do_rdiv () {
 				result# = x# / y
 			*/
 			integer xn = x->numericVector.size;
-			autonumvec result { xn, false };
+			autonumvec result { xn, kTensorInitializationType::RAW };
 			double yvalue = y->number;
 			if (yvalue == 0.0) {
 				Melder_throw (U"Cannot divide (/) ", Stackel_whichText (x), U" by zero.");
@@ -3063,7 +3063,7 @@ static void do_functionvec_n_n (double (*f) (double)) {
 				at [i] = f (at [i]);
 			}
 		} else {
-			autonumvec result { n, false };
+			autonumvec result { n, kTensorInitializationType::RAW };
 			for (integer i = 1; i <= n; i ++) {
 				result [i] = f (at [i]);
 			}
@@ -3149,7 +3149,7 @@ static void do_rectify_numvec () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
 		integer nelm = x->numericVector.size;
-		autonumvec result { nelm, false };
+		autonumvec result { nelm, kTensorInitializationType::RAW };
 		for (integer i = 1; i <= nelm; i ++) {
 			double xvalue = x->numericVector [i];
 			result [i] = isundef (xvalue) ? undefined : xvalue > 0.0 ? xvalue : 0.0;
@@ -3230,7 +3230,7 @@ static void do_exp_numvec () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_VECTOR) {
 		integer nelm = x->numericVector.size;
-		autonumvec result (nelm, false);
+		autonumvec result (nelm, kTensorInitializationType::RAW);
 		for (integer i = 1; i <= nelm; i ++) {
 			result [i] = exp (x->numericVector [i]);
 		}
@@ -3243,7 +3243,7 @@ static void do_exp_nummat () {
 	Stackel x = pop;
 	if (x->which == Stackel_NUMERIC_MATRIX) {
 		integer nrow = x->numericMatrix.nrow, ncol = x->numericMatrix.ncol;
-		autonummat result (nrow, ncol, false);
+		autonummat result (nrow, ncol, kTensorInitializationType::RAW);
 		for (integer irow = 1; irow <= nrow; irow ++) {
 			for (integer icol = 1; icol <= ncol; icol ++) {
 				result [irow] [icol] = exp (x->numericMatrix [irow] [icol]);
@@ -3355,7 +3355,7 @@ 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) {
 		integer numberOfElements = a->numericVector.size;
-		autonumvec newData (numberOfElements, false);
+		autonumvec newData (numberOfElements, kTensorInitializationType::RAW);
 		for (integer ielem = 1; ielem <= numberOfElements; ielem ++) {
 			newData [ielem] = f (x->number, y->number);
 		}
@@ -3375,7 +3375,7 @@ 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) {
 		integer numberOfRows = a->numericMatrix.nrow;
 		integer numberOfColumns = a->numericMatrix.ncol;
-		autonummat newData (numberOfRows, numberOfColumns, false);
+		autonummat newData (numberOfRows, numberOfColumns, kTensorInitializationType::RAW);
 		for (integer irow = 1; irow <= numberOfRows; irow ++) {
 			for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 				newData [irow] [icol] = f (x->number, y->number);
@@ -3396,7 +3396,7 @@ static void do_function_ll_l_numvec (integer (*f) (integer, integer)) {
 	Stackel y = pop, x = pop, a = pop;
 	if (a->which == Stackel_NUMERIC_VECTOR && x->which == Stackel_NUMBER) {
 		integer numberOfElements = a->numericVector.size;
-		autonumvec newData (numberOfElements, false);
+		autonumvec newData (numberOfElements, kTensorInitializationType::RAW);
 		for (integer ielem = 1; ielem <= numberOfElements; ielem ++) {
 			newData [ielem] = f (lround (x->number), lround (y->number));
 		}
@@ -3416,7 +3416,7 @@ static void do_function_ll_l_nummat (integer (*f) (integer, integer)) {
 	if (a->which == Stackel_NUMERIC_MATRIX && x->which == Stackel_NUMBER && y->which == Stackel_NUMBER) {
 		integer numberOfRows = a->numericMatrix.nrow;
 		integer numberOfColumns = a->numericMatrix.ncol;
-		autonummat newData (numberOfRows, numberOfColumns, false);
+		autonummat newData (numberOfRows, numberOfColumns, kTensorInitializationType::RAW);
 		for (integer irow = 1; irow <= numberOfRows; irow ++) {
 			for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 				newData [irow] [icol] = f (lround (x->number), lround (y->number));
@@ -3649,7 +3649,7 @@ static void shared_do_writeInfo (int numberOfArguments) {
 			integer numberOfColumns = arg->numericMatrix.ncol;
 			double **data = arg->numericMatrix.at;
 			for (integer irow = 1; irow <= numberOfRows; irow ++) {
-				for (integer icol = 1; icol <= numberOfRows; icol ++) {
+				for (integer icol = 1; icol <= numberOfColumns; icol ++) {
 					MelderInfo_write (data [irow] [icol], icol == numberOfColumns ? U"" : U" ");
 				}
 				MelderInfo_write (irow == numberOfRows ? U"" : U"\n");
@@ -4062,7 +4062,7 @@ static void do_zeroNumvec () {
 		Melder_throw (U"In the function \"zero#\", the number of elements is undefined.");
 	if (numberOfElements < 0.0)
 		Melder_throw (U"In the function \"zero#\", the number of elements should not be negative.");
-	autonumvec result (lround (numberOfElements), true);
+	autonumvec result (lround (numberOfElements), kTensorInitializationType::ZERO);
 	pushNumericVector (result.move());
 }
 static void do_zeroNummat () {
@@ -4087,7 +4087,7 @@ static void do_zeroNummat () {
 		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);
+	autonummat result (lround (numberOfRows), lround (numberOfColumns), kTensorInitializationType::ZERO);
 	pushNumericMatrix (result.move());
 }
 static void do_linearNumvec () {
@@ -4123,7 +4123,7 @@ static void do_linearNumvec () {
 	integer 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".");
-	autonumvec result { numberOfSteps, false };
+	autonumvec result { numberOfSteps, kTensorInitializationType::RAW };
 	for (integer ielem = 1; ielem <= numberOfSteps; ielem ++) {
 		result [ielem] = excludeEdges ?
 			minimum + (ielem - 0.5) * (maximum - minimum) / numberOfSteps :
@@ -4381,7 +4381,7 @@ static void do_leftStr () {
 			#endif
 			autostring32 result = Melder_malloc (char32, newlength + 1);
 			str32ncpy (result.peek(), s->string, newlength);
-			result [newlength] = '\0';
+			result [newlength] = U'\0';
 			pushString (result.transfer());
 		} else {
 			Melder_throw (U"The function \"left$\" requires a string, or a string and a number.");
@@ -5250,7 +5250,7 @@ static void do_numericVectorLiteral () {
 	Melder_assert (n->which == Stackel_NUMBER);
 	integer numberOfElements = lround (n->number);
 	Melder_assert (numberOfElements > 0);
-	autonumvec result { numberOfElements, false };
+	autonumvec result { numberOfElements, kTensorInitializationType::RAW };
 	for (integer ielement = numberOfElements; ielement > 0; ielement --) {
 		Stackel e = pop;
 		if (e->which != Stackel_NUMBER)
@@ -5316,7 +5316,7 @@ static void do_repeatNumvec () {
 	if (x->which == Stackel_NUMERIC_VECTOR && n->which == Stackel_NUMBER) {
 		integer n_old = x->numericVector.size;
 		integer times = lround (n->number);
-		autonumvec result { n_old * times, false };
+		autonumvec result { n_old * times, kTensorInitializationType::RAW };
 		for (integer i = 1; i <= times; i ++) {
 			for (integer j = 1; j <= n_old; j ++) {
 				result [(i - 1) * n_old + j] = x->numericVector [j];
diff --git a/sys/Graphics_image.cpp b/sys/Graphics_image.cpp
index d785dbe..9975073 100644
--- a/sys/Graphics_image.cpp
+++ b/sys/Graphics_image.cpp
@@ -272,14 +272,14 @@ static void _GraphicsScreen_cellArrayOrImage (GraphicsScreen me, double **z_floa
 				autoNUMvector <double> leftWeight (clipx1, clipx2);
 				for (xDC = clipx1; xDC < clipx2; xDC += undersampling) {
 					double ix_real = ix1 - 0.5 + ((double) nx * (xDC - x1DC)) / (x2DC - x1DC);
-					ileft [xDC] = floor (ix_real), iright [xDC] = ileft [xDC] + 1;
+					ileft [xDC] = (integer) floor (ix_real), iright [xDC] = ileft [xDC] + 1;
 					rightWeight [xDC] = ix_real - ileft [xDC], leftWeight [xDC] = 1.0 - rightWeight [xDC];
 					if (ileft [xDC] < ix1) ileft [xDC] = ix1;
 					if (iright [xDC] > ix2) iright [xDC] = ix2;
 				}
 				for (yDC = clipy2; yDC < clipy1; yDC += undersampling) {
 					double iy_real = iy2 + 0.5 - ((double) ny * (yDC - y2DC)) / (y1DC - y2DC);
-					integer itop = ceil (iy_real), ibottom = itop - 1;
+					integer itop = (integer) ceil (iy_real), ibottom = itop - 1;
 					double bottomWeight = itop - iy_real, topWeight = 1.0 - bottomWeight;
 					unsigned char *pixelAddress = ROW_START_ADDRESS;
 					if (itop > iy2) itop = iy2;
diff --git a/sys/Gui.cpp b/sys/Gui.cpp
index 682303a..2a6a244 100644
--- a/sys/Gui.cpp
+++ b/sys/Gui.cpp
@@ -1,6 +1,6 @@
 /* Gui.cpp
  *
- * Copyright (C) 1992-2011,2012,2016,2017 Paul Boersma
+ * Copyright (C) 1992-2008,2010-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
diff --git a/sys/Gui.h b/sys/Gui.h
index ab12c76..1b50e31 100644
--- a/sys/Gui.h
+++ b/sys/Gui.h
@@ -2,7 +2,7 @@
 #define _Gui_h_
 /* Gui.h
  *
- * Copyright (C) 1993-2011,2012,2013,2014,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1993-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
diff --git a/sys/GuiP.h b/sys/GuiP.h
index 3e00382..1a73761 100644
--- a/sys/GuiP.h
+++ b/sys/GuiP.h
@@ -2,7 +2,7 @@
 #define _GuiP_h_
 /* GuiP.h
  *
- * Copyright (C) 1993-2011,2012,2013,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1993-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
diff --git a/sys/GuiText.cpp b/sys/GuiText.cpp
index c809c44..6faf7b7 100644
--- a/sys/GuiText.cpp
+++ b/sys/GuiText.cpp
@@ -1,6 +1,6 @@
 /* GuiText.cpp
  *
- * Copyright (C) 1993-2011,2012,2013,2014,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1993-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
@@ -162,10 +162,10 @@ static integer NativeText_getLength (GuiObject widget) {
  * SELECTION
  */
 
-static int NativeText_getSelectionRange (GuiObject widget, integer *out_left, integer *out_right) {
-	uinteger left, right;
+static bool NativeText_getSelectionRange (GuiObject widget, integer *out_left, integer *out_right) {
 	Melder_assert (MEMBER (widget, Text));
-	SendMessage (widget -> window, EM_GETSEL, (WPARAM) & left, (LPARAM) & right);   // 32-bit (R&N: 579)
+	DWORD left, right;
+	SendMessage (widget -> window, EM_GETSEL, (WPARAM) & left, (LPARAM) & right);
 	if (out_left) *out_left = left;
 	if (out_right) *out_right = right;
 	return right > left;
@@ -195,11 +195,11 @@ void _GuiText_exit () {
 			} else {
 				GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
 				GtkTextIter from_it, to_it;
-				gtk_text_buffer_get_iter_at_offset (buffer, &from_it, from_pos);
-				gtk_text_buffer_get_iter_at_offset (buffer, &to_it, to_pos);
-				gtk_text_buffer_delete_interactive (buffer, &from_it, &to_it,
+				gtk_text_buffer_get_iter_at_offset (buffer, & from_it, from_pos);
+				gtk_text_buffer_get_iter_at_offset (buffer, & to_it, to_pos);
+				gtk_text_buffer_delete_interactive (buffer, & from_it, & to_it,
 					gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)));
-				gtk_text_buffer_place_cursor (buffer, &to_it);
+				gtk_text_buffer_place_cursor (buffer, & to_it);
 			}
 		#elif motif
 		#endif
@@ -209,15 +209,15 @@ void _GuiText_exit () {
 		#if gtk
 			if (G_OBJECT_TYPE (G_OBJECT (widget)) == GTK_TYPE_ENTRY) {
 				gint from_pos_gint = from_pos;
-				gtk_editable_insert_text (GTK_EDITABLE (widget), text, to_pos - from_pos, &from_pos_gint);
+				gtk_editable_insert_text (GTK_EDITABLE (widget), text, to_pos - from_pos, & from_pos_gint);
 			} else {
 				GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
 				GtkTextIter it;
-				gtk_text_buffer_get_iter_at_offset (buffer, &it, from_pos);
-				gtk_text_buffer_insert_interactive (buffer, &it, text, to_pos - from_pos,
-					gtk_text_view_get_editable (GTK_TEXT_VIEW(widget)));
-				gtk_text_buffer_get_iter_at_offset (buffer, &it, to_pos);
-				gtk_text_buffer_place_cursor (buffer, &it);
+				gtk_text_buffer_get_iter_at_offset (buffer, & it, from_pos);
+				gtk_text_buffer_insert_interactive (buffer, & it, text, to_pos - from_pos,
+					gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)));
+				gtk_text_buffer_get_iter_at_offset (buffer, & it, to_pos);
+				gtk_text_buffer_place_cursor (buffer, & it);
 			}
 		#elif motif
 		#endif
@@ -241,8 +241,8 @@ void _GuiText_exit () {
 			if (my d_prev->first == last) {
 				// most common for backspace key presses
 				he = my d_prev;
-				text_new = (char *) realloc (text_new, sizeof(*text_new) * (he->last - first + 1));
-				memcpy (text_new + last - first, he->text, sizeof(*text_new) * (he->last - he->first + 1));
+				text_new = (char *) realloc (text_new, sizeof (*text_new) * (he->last - first + 1));
+				memcpy (text_new + last - first, he->text, sizeof (*text_new) * (he->last - he->first + 1));
 				free (he->text);
 				he->text = text_new;
 				he->first = first;
@@ -250,16 +250,16 @@ void _GuiText_exit () {
 			} else if (my d_prev->last == first) {
 				// most common for ordinary text insertion
 				he = my d_prev;
-				he->text = (char *) realloc (he->text, sizeof(*he->text) * (last - he->first + 1));
-				memcpy (he->text + he->last - he->first, text_new, sizeof(*he->text) * (last - first + 1));
+				he->text = (char *) realloc (he->text, sizeof (*he->text) * (last - he->first + 1));
+				memcpy (he->text + he->last - he->first, text_new, sizeof (*he->text) * (last - first + 1));
 				free (text_new);
 				he->last = last;
 				
 			} else if (deleted && my d_prev->first == first) {
 				// most common for delete key presses
 				he = my d_prev;
-				he->text = (char *) realloc (he->text, sizeof(*he->text) * (last - first + he->last - he->first + 1));
-				memcpy (he->text + he->last - he->first, text_new, sizeof(*he->text) * (last - first + 1));
+				he->text = (char *) realloc (he->text, sizeof (*he->text) * (last - first + he->last - he->first + 1));
+				memcpy (he->text + he->last - he->first, text_new, sizeof (*he->text) * (last - first + 1));
 				free (text_new);
 				he->last = last + he->last - he->first;
 			}
@@ -731,7 +731,7 @@ char32 * GuiText_getSelection (GuiText me) {
 		}
 	#elif motif
 		integer startW, endW;
-		NativeText_getSelectionRange (my d_widget, & startW, & endW);
+		(void) NativeText_getSelectionRange (my d_widget, & startW, & endW);
 		if (endW > startW) {   // at least one character selected?
 			/*
 			 * Get all text.
@@ -796,7 +796,7 @@ char32 * GuiText_getStringAndSelectionPosition (GuiText me, integer *first, inte
 		WCHAR *bufferW = Melder_malloc_f (WCHAR, lengthW + 1);
 		GetWindowTextW (my d_widget -> window, bufferW, lengthW + 1);
 		integer firstW, lastW;
-		NativeText_getSelectionRange (my d_widget, & firstW, & lastW);
+		(void) NativeText_getSelectionRange (my d_widget, & firstW, & lastW);
 
 		integer differenceFirst = 0;
 		for (integer i = 0; i < firstW; i ++) {
diff --git a/sys/MelderGui.cpp b/sys/MelderGui.cpp
index ba1c837..b01c07d 100644
--- a/sys/MelderGui.cpp
+++ b/sys/MelderGui.cpp
@@ -1,6 +1,6 @@
 /* MelderGui.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma,
+ * Copyright (C) 1992-2017 Paul Boersma,
  *               2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
  *
  * This code is free software; you can redistribute it and/or modify
diff --git a/sys/MelderThread.h b/sys/MelderThread.h
index 0d54356..e1bd113 100644
--- a/sys/MelderThread.h
+++ b/sys/MelderThread.h
@@ -2,7 +2,7 @@
 #define _MelderThread_h_
 /* MelderThread.h
  *
- * Copyright (C) 2014,2016,2017 Paul Boersma
+ * Copyright (C) 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
diff --git a/sys/melder.cpp b/sys/melder.cpp
index df7c686..22121be 100644
--- a/sys/melder.cpp
+++ b/sys/melder.cpp
@@ -1,6 +1,6 @@
 /* melder.cpp
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1992-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
diff --git a/sys/melder.h b/sys/melder.h
index cfc57d8..459f5ae 100644
--- a/sys/melder.h
+++ b/sys/melder.h
@@ -2,7 +2,7 @@
 #define _melder_h_
 /* melder.h
  *
- * Copyright (C) 1992-2012,2013,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1992-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
@@ -63,6 +63,8 @@ typedef uint64_t uint64;
 #ifndef UINT24_MAX
 	#define UINT24_MAX   16777216
 #endif
+#define INTEGER_MAX  ( sizeof (integer) == 4 ? INT32_MAX : INT64_MAX )
+#define INTEGER_MIN  ( sizeof (integer) == 4 ? INT32_MIN : INT64_MIN )
 /*
 	The bounds of the contiguous set of integers that in a "double" can represent only themselves.
 */
@@ -326,7 +328,7 @@ 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
 
-/********** CONSOLE **********/
+#pragma mark - CONSOLE
 
 void Melder_writeToConsole (const char32 *message, bool useStderr);
 
@@ -656,35 +658,17 @@ void NUMscale (double *x, double xminfrom, double xmaxfrom, double xminto, doubl
 // 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 */
+#define undefined  (0.0/0.0)   /* NaN */
 
 /*
-	Ideally, isdefined() should capture not only `undefined`, but all infinities and nans.
+	isdefined() shall 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(),
+	The portable version of isdefined() involves both isinf() and isnan(), or perhaps just isfinite(),
 	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; }
@@ -1255,6 +1239,8 @@ typedef autodatavector <char *> autostring8vector;
 
 class autonumvec;   // forward declaration, needed in the declaration of numvec
 
+enum class kTensorInitializationType { RAW = 0, ZERO = 1 };
+
 class numvec {
 public:
 	double *at;
@@ -1262,8 +1248,8 @@ public:
 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);
+	numvec (integer givenSize, kTensorInitializationType initializationType) {
+		our _initAt (givenSize, initializationType);
 		our size = givenSize;
 	}
 	numvec (const numvec& other) = default;
@@ -1281,7 +1267,7 @@ public:
 		our size = 0;
 	}
 protected:
-	void _initAt (integer givenSize, bool zero);
+	void _initAt (integer givenSize, kTensorInitializationType initializationType);
 	void _freeAt () noexcept;
 };
 
@@ -1297,7 +1283,7 @@ protected:
 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 (integer givenSize, kTensorInitializationType initializationType): numvec (givenSize, initializationType) { }   // 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)
@@ -1312,9 +1298,9 @@ public:
 	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
+	void reset (integer newSize, kTensorInitializationType initializationType) {   // 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 _initAt (newSize, initializationType);   // ...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
@@ -1361,8 +1347,8 @@ public:
 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);
+	nummat (integer givenNrow, integer givenNcol, kTensorInitializationType initializationType) {
+		our _initAt (givenNrow, givenNcol, initializationType);
 		our nrow = givenNrow;
 		our ncol = givenNcol;
 	}
@@ -1382,7 +1368,7 @@ public:
 		our ncol = 0;
 	}
 protected:
-	void _initAt (integer givenNrow, integer givenNcol, bool zero);
+	void _initAt (integer givenNrow, integer givenNcol, kTensorInitializationType initializationType);
 	void _freeAt () noexcept;
 };
 
@@ -1398,7 +1384,7 @@ protected:
 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 (integer givenNrow, integer givenNcol, kTensorInitializationType initializationType): nummat { givenNrow, givenNcol, initializationType } { }   // 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)
@@ -1413,9 +1399,9 @@ public:
 	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
+	void reset (integer newNrow, integer newNcol, kTensorInitializationType initializationType) {   // 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 _initAt (newNrow, newNcol, initializationType);   // ...in case this line throws an exception
 		our nrow = newNrow;
 		our ncol = newNcol;
 	}
@@ -1925,6 +1911,7 @@ void Melder_appendError (Melder_12_OR_13_ARGS);
 void Melder_appendError (Melder_14_OR_15_ARGS);
 void Melder_appendError (Melder_16_TO_19_ARGS);
 #define Melder_throw(...)  do { Melder_appendError (__VA_ARGS__); throw MelderError (); } while (false)
+#define Melder_require(condition, ...)  do { if (! (condition)) Melder_throw (__VA_ARGS__); } while (false)
 
 void Melder_flushError ();
 void Melder_flushError (Melder_1_ARG);
@@ -2132,7 +2119,96 @@ public:
 	Graphics graphics () { return _graphics; }
 };
 
-/********** RECORD AND PLAY ROUTINES **********/
+#pragma mark - REAL TO INTEGER CONVERSION
+
+inline static double Melder_roundDown (double x) {
+	return floor (x);
+}
+
+inline static integer Melder_iroundDown (double x) {
+	double xround = Melder_roundDown (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,   // this formulation handles NaN correctly
+		U"When rounding down the real value ", x, U", the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+inline static double Melder_roundUp (double x) {
+	return ceil (x);
+}
+
+inline static integer Melder_iroundUp (double x) {
+	double xround = Melder_roundUp (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,
+		U"When rounding up the real value ", x, U", the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+inline static double Melder_roundTowardsZero (double x) {
+	return x >= 0.0 ? Melder_roundDown (x) : Melder_roundUp (x);
+}
+
+inline static integer Melder_iroundTowardsZero (double x) {
+	Melder_require (x >= (double) INTEGER_MIN && x <= (double) INTEGER_MAX,
+		U"When rounding the real value ", x, U" towards zero, the result cannot be represented in an integer.");
+	return (integer) x;
+}
+
+inline static double Melder_roundAwayFromZero (double x) {
+	return x >= 0.0 ? Melder_roundUp (x) : Melder_roundDown (x);
+}
+
+inline static integer Melder_iroundAwayFromZero (double x) {
+	double xround = Melder_roundAwayFromZero (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,
+		U"When rounding the real value ", x, U" away from zero, the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+inline static double Melder_round_tieUp (double x) {
+	return Melder_roundDown (x + 0.5);
+}
+
+inline static integer Melder_iround_tieUp (double x) {
+	double xround = Melder_round_tieUp (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,
+		U"When rounding the real value ", x, U", the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+inline static double Melder_round_tieDown (double x) {
+	return Melder_roundUp (x - 0.5);
+}
+
+inline static integer Melder_iround_tieDown (double x) {
+	double xround = Melder_round_tieDown (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,
+		U"When rounding the real value ", x, U", the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+inline static double Melder_round_tieTowardsZero (double x) {
+	return x >= 0.0 ? Melder_round_tieDown (x) : Melder_round_tieUp (x);
+}
+
+inline static integer Melder_iround_tieTowardsZero (double x) {
+	double xround = Melder_round_tieTowardsZero (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,
+		U"When rounding the real value ", x, U", the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+inline static double Melder_round_tieAwayFromZero (double x) {
+	return x >= 0.0 ? Melder_round_tieUp (x) : Melder_round_tieDown (x);
+}
+
+inline static integer Melder_iround_tieAwayFromZero (double x) {
+	double xround = Melder_round_tieAwayFromZero (x);
+	Melder_require (xround >= (double) INTEGER_MIN && xround <= (double) INTEGER_MAX,
+		U"When rounding the real value ", x, U", the result cannot be represented in an integer.");
+	return (integer) xround;
+}
+
+#pragma mark - RECORD AND PLAY FUNCTIONS
 
 int Melder_record (double duration);
 int Melder_recordFromFile (MelderFile file);
diff --git a/sys/melder_alloc.cpp b/sys/melder_alloc.cpp
index eb44d25..060cb11 100644
--- a/sys/melder_alloc.cpp
+++ b/sys/melder_alloc.cpp
@@ -1,6 +1,6 @@
 /* melder_alloc.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2017 Paul Boersma
+ * Copyright (C) 1992-2007,2009,2011,2012,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
diff --git a/sys/melder_atof.cpp b/sys/melder_atof.cpp
index 35699e4..7171582 100644
--- a/sys/melder_atof.cpp
+++ b/sys/melder_atof.cpp
@@ -1,6 +1,6 @@
 /* melder_atof.cpp
  *
- * Copyright (C) 2003-2011,2015,2017 Paul Boersma
+ * Copyright (C) 2003-2008,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
diff --git a/sys/melder_audio.cpp b/sys/melder_audio.cpp
index 0b42a05..fa5242a 100644
--- a/sys/melder_audio.cpp
+++ b/sys/melder_audio.cpp
@@ -1,6 +1,6 @@
 /* melder_audio.cpp
  *
- * Copyright (C) 1992-2011,2012,2013,2014,2015,2016,2017 Paul Boersma, David Weenink
+ * Copyright (C) 1992-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
diff --git a/sys/melder_audiofiles.cpp b/sys/melder_audiofiles.cpp
index 7a5014b..2807266 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,2017 Paul Boersma & David Weenink, 2007 Erez Volk (for FLAC)
+ * Copyright (C) 1992-2008,2010-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
diff --git a/sys/melder_console.cpp b/sys/melder_console.cpp
index ccc6454..cb6c369 100644
--- a/sys/melder_console.cpp
+++ b/sys/melder_console.cpp
@@ -1,6 +1,6 @@
 /* melder_console.cpp
  *
- * Copyright (C) 1992-2011,2017 Paul Boersma
+ * Copyright (C) 1992-2005,2007,2008,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
diff --git a/sys/melder_debug.cpp b/sys/melder_debug.cpp
index 3b5fa69..c79d31a 100644
--- a/sys/melder_debug.cpp
+++ b/sys/melder_debug.cpp
@@ -1,6 +1,6 @@
 /* melder_debug.cpp
  *
- * Copyright (C) 2000-2012,2014,2015,2016,2017 Paul Boersma
+ * Copyright (C) 2000-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
diff --git a/sys/melder_files.cpp b/sys/melder_files.cpp
index c91f03c..8f2e683 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,2017 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2008,2010-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
diff --git a/sys/melder_ftoa.cpp b/sys/melder_ftoa.cpp
index 344e94d..08ad614 100644
--- a/sys/melder_ftoa.cpp
+++ b/sys/melder_ftoa.cpp
@@ -1,6 +1,6 @@
 /* melder_ftoa.cpp
  *
- * Copyright (C) 1992-2011,2014,2015,2017 Paul Boersma
+ * Copyright (C) 1992-2008,2010-2012,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
diff --git a/sys/melder_info.cpp b/sys/melder_info.cpp
index b87dc85..5b47174 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,2017 Paul Boersma
+ * Copyright (C) 1992-2007,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
diff --git a/sys/melder_readtext.cpp b/sys/melder_readtext.cpp
index 16febe8..356dc59 100644
--- a/sys/melder_readtext.cpp
+++ b/sys/melder_readtext.cpp
@@ -1,6 +1,6 @@
 /* melder_readtext.cpp
  *
- * Copyright (C) 2008-2011,2014,2015,2017 Paul Boersma
+ * Copyright (C) 2008,2010-2012,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
diff --git a/sys/melder_strings.cpp b/sys/melder_strings.cpp
index d6543b6..6dd3240 100644
--- a/sys/melder_strings.cpp
+++ b/sys/melder_strings.cpp
@@ -1,6 +1,6 @@
 /* melder_strings.cpp
  *
- * Copyright (C) 2006-2011,2015,2017 Paul Boersma
+ * Copyright (C) 2006-2012,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
diff --git a/sys/melder_sysenv.cpp b/sys/melder_sysenv.cpp
index fce9fd2..964b492 100644
--- a/sys/melder_sysenv.cpp
+++ b/sys/melder_sysenv.cpp
@@ -1,6 +1,6 @@
 /* melder_sysenv.cpp
  *
- * Copyright (C) 1992-2011,2015,2016,2017 Paul Boersma
+ * Copyright (C) 1992-2007,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
diff --git a/sys/melder_textencoding.cpp b/sys/melder_textencoding.cpp
index f004a5f..490b884 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,2017 Paul Boersma
+ * Copyright (C) 2007-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
diff --git a/sys/melder_time.cpp b/sys/melder_time.cpp
index 2f0e4c1..7157caf 100644
--- a/sys/melder_time.cpp
+++ b/sys/melder_time.cpp
@@ -1,6 +1,6 @@
 /* melder_time.cpp
  *
- * Copyright (C) 1992-2011,2014 Paul Boersma
+ * Copyright (C) 1992-2008,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
diff --git a/sys/melder_token.cpp b/sys/melder_token.cpp
index f60cbf1..1ec6690 100644
--- a/sys/melder_token.cpp
+++ b/sys/melder_token.cpp
@@ -1,6 +1,6 @@
 /* melder_token.cpp
  *
- * Copyright (C) 2006-2011,2015,2017 Paul Boersma
+ * Copyright (C) 2006,2007,2009,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
diff --git a/sys/melder_writetext.cpp b/sys/melder_writetext.cpp
index 68b7747..48ca188 100644
--- a/sys/melder_writetext.cpp
+++ b/sys/melder_writetext.cpp
@@ -1,6 +1,6 @@
 /* melder_writetext.cpp
  *
- * Copyright (C) 2007-2011,2015,2016,2017 Paul Boersma
+ * Copyright (C) 2007,2008,2010-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
diff --git a/sys/motifEmulator.cpp b/sys/motifEmulator.cpp
index b452008..3f68335 100644
--- a/sys/motifEmulator.cpp
+++ b/sys/motifEmulator.cpp
@@ -183,7 +183,7 @@ static int NativeButton_preferredHeight (GuiObject me) {
 
 GuiObject _Gui_initializeWidget (int widgetClass, GuiObject parent, const char32 *name) {
 	GuiObject me = Melder_calloc_f (struct structGuiObject, 1);
-	if (Melder_debug == 34) fprintf (stderr, "from _Gui_initializeWidget\t%p\t%ld\t%ld\n", me, 1L, (integer) sizeof (struct structGuiObject));
+	if (Melder_debug == 34) fprintf (stderr, "from _Gui_initializeWidget\t%p\t%ld\t%ld\n", me, 1L, (long_not_integer) sizeof (struct structGuiObject));
 	my magicNumber = 15111959;
 	numberOfWidgets ++;
 	my widgetClass = widgetClass;
@@ -2125,13 +2125,16 @@ void XtNextEvent (XEvent *xevent) {
 }
 
 static void processWorkProcsAndTimeOuts () {
-	integer i;
-	if (theNumberOfWorkProcs) for (i = 9; i >= 1; i --)
-		if (theWorkProcs [i])
-			if (theWorkProcs [i] (theWorkProcClosures [i])) XtRemoveWorkProc (i);
+	if (theNumberOfWorkProcs) {
+		for (integer i = 9; i >= 1; i --) {
+			if (theWorkProcs [i]) {
+				if (theWorkProcs [i] (theWorkProcClosures [i])) XtRemoveWorkProc (i);
+			}
+		}
+	}
 	if (theNumberOfTimeOuts) {
 		clock_t now = clock ();
-		for (i = 1; i < 10; i ++) if (theTimeOutProcs [i]) {
+		for (integer i = 1; i < 10; i ++) if (theTimeOutProcs [i]) {
 			static volatile clock_t timeElapsed;   // careful: use 32-bit integers circularly; prevent optimization
 			timeElapsed = now - theTimeOutStarts [i];
 			if (timeElapsed > theTimeOutIntervals [i]) {
@@ -2232,7 +2235,7 @@ modifiers & _motif_COMMAND_MASK ? " control" : "",
 modifiers & _motif_OPTION_MASK ? " alt" : "",
 modifiers & _motif_SHIFT_MASK ? " shift" : "", message -> message == WM_KEYDOWN ? "keydown" : "syskeydown", kar);*/
 		if (me && my shell) {
-			uinteger acc = my shell -> motiff.shell.lowAccelerators [modifiers];
+			uint32 acc = my shell -> motiff.shell.lowAccelerators [modifiers];
 			//if (kar != VK_CONTROL) Melder_casual ("%d %d", acc, kar);
 			if (kar < 48) {
 				if (kar == VK_BACK) {   // shortcut or text
diff --git a/sys/oo_READ_BINARY.h b/sys/oo_READ_BINARY.h
index d648334..d8b5bf7 100644
--- a/sys/oo_READ_BINARY.h
+++ b/sys/oo_READ_BINARY.h
@@ -125,8 +125,8 @@
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,formatVersion)  \
 	{ \
-		int32 n = bingeti32 (f); \
-		for (int32 i = 1; i <= n; i ++) { \
+		integer n = bingetinteger (f); \
+		for (integer i = 1; i <= n; i ++) { \
 			auto##ItemClass item = Thing_new (ItemClass); \
 			item -> v_readBinary (f, formatVersion); \
 			our x.addItem_move (item.move()); \
@@ -135,9 +135,9 @@
 
 #define oo_AUTO_COLLECTION(Class,x,ItemClass,formatVersion)  \
 	{ \
-		int32 n = bingeti32 (f); \
+		integer n = bingetinteger (f); \
 		our x = Class##_create (); \
-		for (int32 i = 1; i <= n; i ++) { \
+		for (integer i = 1; i <= n; i ++) { \
 			auto##ItemClass item = Thing_new (ItemClass); \
 			item -> v_readBinary (f, formatVersion); \
 			our x -> addItem_move (item.move()); \
diff --git a/sys/oo_READ_TEXT.h b/sys/oo_READ_TEXT.h
index bb35dac..a5559c6 100644
--- a/sys/oo_READ_TEXT.h
+++ b/sys/oo_READ_TEXT.h
@@ -146,7 +146,7 @@
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,formatVersion)  \
 	{ \
-		integer n = texgeti32 (a_text); \
+		integer n = texgetinteger (a_text); \
 		for (integer 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)  \
 	{ \
-		integer n = texgeti32 (a_text); \
+		integer n = texgetinteger (a_text); \
 		our x = Class##_create (); \
 		for (integer 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 6858b6f..0edec5d 100644
--- a/sys/oo_WRITE_BINARY.h
+++ b/sys/oo_WRITE_BINARY.h
@@ -93,14 +93,14 @@
 		Data_writeBinary (our x.get(), f);
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,version)  \
-	binputi32 (our x.size, f); \
+	binputinteger (our x.size, f); \
 	for (integer 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)  \
-	binputi32 (our x ? our x->size : 0, f); \
+	binputinteger (our x ? our x->size : 0, f); \
 	if (our x) { \
 		for (integer 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 1e0d50a..ca06f94 100644
--- a/sys/oo_WRITE_TEXT.h
+++ b/sys/oo_WRITE_TEXT.h
@@ -134,7 +134,7 @@
 		Data_writeText (our x.get(), file);
 
 #define oo_COLLECTION_OF(Class,x,ItemClass,version)  \
-	texputi32 (file, our x.size, U"" #x U": size", 0,0,0,0,0); \
+	texputinteger (file, our x.size, U"" #x U": size", 0,0,0,0,0); \
 	for (integer 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)  \
-	texputi32 (file, our x ? our x->size : 0, U"" #x U": size", 0,0,0,0,0); \
+	texputinteger (file, our x ? our x->size : 0, U"" #x U": size", 0,0,0,0,0); \
 	if (our x) { \
 		for (integer i = 1; i <= our x->size; i ++) { \
 			ItemClass data = our x->at [i]; \
diff --git a/sys/praat.h b/sys/praat.h
index 73ddd6c..a078745 100644
--- a/sys/praat.h
+++ b/sys/praat.h
@@ -527,7 +527,6 @@ void praat_name2 (char32 *name, ClassInfo klas1, ClassInfo klas2);
 				}
 
 #define GET_FILE(name)  UiForm_getFile (dia, name)
-#define REQUIRE(c,t)  if (! (c)) Melder_throw (t);
 
 #endif // _EditorM_h_
 
@@ -575,7 +574,7 @@ void praat_name2 (char32 *name, ClassInfo klas1, ClassInfo klas2);
 	if (me && you && him) break; }
 
 #define FIND_ONE_AND_COUPLE(klas1,klas2)  \
-	klas1 me; klas2 you = nullptr, him = nullptr; \
+	klas1 me = nullptr; klas2 you = nullptr, him = nullptr; \
 	LOOP { if (CLASS == class##klas1) me = (klas1) OBJECT; else if (CLASS == class##klas2) (you ? him : you) = (klas2) OBJECT; \
 	if (me && you && him) break; }
 
diff --git a/sys/praat_version.h b/sys/praat_version.h
index c7d6857..5e49231 100644
--- a/sys/praat_version.h
+++ b/sys/praat_version.h
@@ -1,5 +1,5 @@
-#define PRAAT_VERSION_STR 6.0.34
-#define PRAAT_VERSION_NUM 6034
+#define PRAAT_VERSION_STR 6.0.35
+#define PRAAT_VERSION_NUM 6035
 #define PRAAT_YEAR 2017
 #define PRAAT_MONTH October
-#define PRAAT_DAY 10
+#define PRAAT_DAY 16
diff --git a/sys/tensor.cpp b/sys/tensor.cpp
index fc4ea48..5d83c05 100644
--- a/sys/tensor.cpp
+++ b/sys/tensor.cpp
@@ -20,10 +20,10 @@
 #include "NUM2.h"   /* for NUMsort2 */
 #include "PAIRWISE_SUM.h"
 
-void numvec :: _initAt (integer givenSize, bool zero) {
+void numvec :: _initAt (integer givenSize, kTensorInitializationType initializationType) {
 	Melder_assert (givenSize >= 0);
 	try {
-		our at = ( givenSize == 0 ? nullptr : NUMvector <double> (1, givenSize, zero) );
+		our at = ( givenSize == 0 ? nullptr : NUMvector <double> (1, givenSize, initializationType == kTensorInitializationType::ZERO) );
 	} catch (MelderError) {
 		Melder_throw (U"Numeric vector not created.");
 	}
@@ -33,11 +33,11 @@ void numvec :: _freeAt () noexcept {
 	if (our at) NUMvector_free (our at, 1);
 }
 
-void nummat :: _initAt (integer givenNrow, integer givenNcol, bool zero) {
+void nummat :: _initAt (integer givenNrow, integer givenNcol, kTensorInitializationType initializationType) {
 	Melder_assert (givenNrow >= 0);
 	Melder_assert (givenNcol >= 0);
 	try {
-		our at = ( givenNrow > 0 && givenNcol > 0 ? NUMmatrix <double> (1, givenNrow, 1, givenNcol, zero) : nullptr );
+		our at = ( givenNrow > 0 && givenNcol > 0 ? NUMmatrix <double> (1, givenNrow, 1, givenNcol, initializationType == kTensorInitializationType::ZERO) : nullptr );
 	} catch (MelderError) {
 		Melder_throw (U"Numeric matrix not created.");
 	}
@@ -265,7 +265,7 @@ real norm_scalar (numvec x, real power) noexcept {
 }
 
 autonumvec copy_numvec (numvec x) {
-	autonumvec result (x.size, false);
+	autonumvec result (x.size, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= x.size; i ++) {
 		result [i] = x [i];
 	}
@@ -273,7 +273,7 @@ autonumvec copy_numvec (numvec x) {
 }
 
 autonummat copy_nummat (nummat x) {
-	autonummat result (x.nrow, x.ncol, false);
+	autonummat result (x.nrow, x.ncol, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= x.nrow; irow ++) {
 		for (integer icol = 1; icol <= x.ncol; icol ++) {
 			result [irow] [icol] = x [irow] [icol];
@@ -283,7 +283,7 @@ autonummat copy_nummat (nummat x) {
 }
 
 autonummat outer_nummat (numvec x, numvec y) {
-	autonummat result (x.size, y.size, false);
+	autonummat result (x.size, y.size, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= x.size; irow ++) {
 		for (integer icol = 1; icol <= y.size; icol ++) {
 			result [irow] [icol] = x [irow] * y [icol];
@@ -306,7 +306,7 @@ autonummat peaks_nummat (numvec x, bool includeEdges, int interpolate, bool sort
 		if (x [1] > x [2]) numberOfPeaks ++;
 		if (x [x.size] > x [x.size - 1]) numberOfPeaks ++;
 	}
-	autonummat result (2, numberOfPeaks, false);
+	autonummat result (2, numberOfPeaks, kTensorInitializationType::RAW);
 	integer peakNumber = 0;
 	if (includeEdges && x [1] > x [2]) {
 		result [1] [++ peakNumber] = 1;
@@ -396,14 +396,14 @@ inline static void mul_inline (numvec target, nummat mat, numvec vec) {
 
 autonumvec mul_numvec (numvec vec, nummat mat) {
 	if (mat.nrow != vec.size) return autonumvec { nullptr, 0 };
-	autonumvec result { mat.ncol, false };
+	autonumvec result { mat.ncol, kTensorInitializationType::RAW };
 	mul_inline (result.get(), vec, mat);
 	return result;
 }
 
 autonumvec mul_numvec (nummat mat, numvec vec) {
 	if (vec.size != mat.ncol) return autonumvec { nullptr, 0 };
-	autonumvec result { mat.nrow, false };
+	autonumvec result { mat.nrow, kTensorInitializationType::RAW };
 	mul_inline (result.get(), mat, vec);
 	return result;
 }
diff --git a/sys/tensor.h b/sys/tensor.h
index 698fb35..b698d25 100644
--- a/sys/tensor.h
+++ b/sys/tensor.h
@@ -122,7 +122,7 @@ inline static void nummat_copyElements_nocheck (nummat from, nummat to) {
 
 inline static autonumvec add_numvec (numvec x, numvec y) {
 	if (x.size != y.size) return autonumvec { nullptr, 0 };
-	autonumvec result (x.size, false);
+	autonumvec result (x.size, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= x.size; i ++) {
 		result [i] = x [i] + y [i];
 	}
@@ -130,7 +130,7 @@ inline static autonumvec add_numvec (numvec x, numvec y) {
 }
 inline static autonummat add_nummat (nummat x, nummat y) {
 	if (x.nrow != y.nrow || x.ncol != y.ncol) return autonummat { nullptr, 0, 0 };
-	autonummat result (x.nrow, x.ncol, false);
+	autonummat result (x.nrow, x.ncol, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= x.nrow; irow ++) {
 		for (integer icol = 1; icol <= x.ncol; icol ++) {
 			result [irow] [icol] = x [irow] [icol] + y [irow] [icol];
@@ -140,7 +140,7 @@ inline static autonummat add_nummat (nummat x, nummat y) {
 }
 inline static autonumvec sub_numvec (numvec x, numvec y) {
 	if (x.size != y.size) return autonumvec { nullptr, 0 };
-	autonumvec result (x.size, false);
+	autonumvec result (x.size, kTensorInitializationType::RAW);
 	for (integer i = 1; i <= x.size; i ++) {
 		result [i] = x [i] - y [i];
 	}
@@ -148,7 +148,7 @@ inline static autonumvec sub_numvec (numvec x, numvec y) {
 }
 inline static autonummat sub_nummat (nummat x, nummat y) {
 	if (x.nrow != y.nrow || x.ncol != y.ncol) return autonummat { nullptr, 0, 0 };
-	autonummat result (x.nrow, x.ncol, false);
+	autonummat result (x.nrow, x.ncol, kTensorInitializationType::RAW);
 	for (integer irow = 1; irow <= x.nrow; irow ++) {
 		for (integer icol = 1; icol <= x.ncol; icol ++) {
 			result [irow] [icol] = x [irow] [icol] - y [irow] [icol];
diff --git a/test/gram/DBN.praat b/test/gram/DBN.praat
new file mode 100644
index 0000000..d9b02cc
--- /dev/null
+++ b/test/gram/DBN.praat
@@ -0,0 +1,59 @@
+writeInfoLine: "Training a DBN with a three-peaked distribution"
+stopwatch
+
+structure# = { 30, 50, 20 }
+numberOfVowels = 3
+mean# = { 8, 16, 23 }
+sigma = 1.8
+numberOfPatterns = 10000
+learningRate = 0.001
+
+my.DeepBeliefNetwork = Create DeepBeliefNetwork: "my", structure#, 0
+
+my.PatternList = Create PatternList: "patterns", structure# [1], numberOfPatterns
+formant# = zero# (numberOfPatterns)
+formant# ~ randomGauss (mean# [randomInteger (1, numberOfVowels)], sigma)
+Formula: ~ 5 * exp (-0.5/sigma^2 * (col - formant# [row]) ^ 2) - 0.5
+
+selectObject: my.DeepBeliefNetwork, my.PatternList
+Learn by layer: learningRate
+
+appendInfoLine: "Trained in ", stopwatch, " seconds"
+
+for ilayer to size (structure#) - 1
+	selectObject: my.DeepBeliefNetwork
+	weight## = Get weights: ilayer
+	appendInfoLine: weight##, newline$
+endfor
+
+numberOfTestPatterns = 15
+Erase all
+Font size: 10
+for itest to numberOfTestPatterns
+	appendInfoLine: "Test pattern #", itest, ":"
+	patternNumber = randomInteger (1, numberOfPatterns)
+	#
+	# Draw input.
+	#
+	Select outer viewport: 0, 3, (itest - 1) * 0.6, (itest - 1) * 0.6 + 1.0
+	selectObject: my.PatternList
+	Draw: patternNumber, 0.0, 0.0, -5.0, 5.0, "no"
+	#
+	# Spread up and down.
+	#
+	selectObject: my.DeepBeliefNetwork, my.PatternList
+	Apply to input: patternNumber
+	selectObject: my.DeepBeliefNetwork
+	Spread up: "deterministic"
+	Spread down: "deterministic"
+	#
+	# Draw reflection.
+	#
+	Select outer viewport: 3, 6, (itest - 1) * 0.6, (itest - 1) * 0.6 + 1.0
+	reflection.Matrix = Extract input activities
+	stdev = Get standard deviation: 0, 0, 0, 0
+	appendInfoLine: "   Energy in reflection: ", stdev
+	Draw rows: 0, 0, 0, 0, -5, 5
+	Remove
+endfor
+removeObject: my.PatternList, my.DeepBeliefNetwork
diff --git a/test/gram/DBNtry.txt b/test/gram/DBNtry.txt
new file mode 100644
index 0000000..12eea75
--- /dev/null
+++ b/test/gram/DBNtry.txt
@@ -0,0 +1,54 @@
+writeInfoLine: "Training a DBN with a three-peaked distribution"
+stopwatch
+
+structure# = { 30, 50, 20 }
+numberOfVowels = 3
+mean# = { 8, 16, 23 }
+sigma = 1.8
+numberOfPatterns = 10000
+learningRate = 0.001
+
+my.DeepBeliefNetwork = Create DeepBeliefNetwork: "my", structure#, 0
+
+my.PatternList = Create PatternList: "patterns", structure# [1], numberOfPatterns
+formant# = zero# (numberOfPatterns)
+formant# ~ randomGauss (mean# [randomInteger (1, numberOfVowels)], sigma)
+Formula: ~ 5 * exp (-0.5/sigma^2 * (col - formant# [row]) ^ 2) - 0.5
+
+my.DeepBeliefNetwork & my.PatternList: Learn by layer: learningRate
+
+appendInfoLine: "Trained in ", stopwatch, " seconds"
+
+for ilayer to size (structure#) - 1
+	weight## = my.DeepBeliefNetwork: Get weights: ilayer
+	appendInfoLine: weight##, newline$
+endfor
+
+numberOfTestPatterns = 15
+Erase all
+Font size: 10
+for itest to numberOfTestPatterns
+	appendInfoLine: "Test pattern #", itest, ":"
+	patternNumber = randomInteger (1, numberOfPatterns)
+	#
+	# Draw input.
+	#
+	Select outer viewport: 0, 3, (itest - 1) * 0.6, (itest - 1) * 0.6 + 1.0
+	my.PatternList: Draw: patternNumber, 0.0, 0.0, -5.0, 5.0, "no"
+	#
+	# Spread up and down.
+	#
+	my.DeepBeliefNetwork & my.PatternList: Apply to input: patternNumber
+	my.DeepBeliefNetwork: Spread up: "deterministic"
+	my.DeepBeliefNetwork: Spread down: "deterministic"
+	#
+	# Draw reflection.
+	#
+	Select outer viewport: 3, 6, (itest - 1) * 0.6, (itest - 1) * 0.6 + 1.0
+	reflection.Matrix = Extract input activities
+	stdev = reflection.Matrix: Get standard deviation: 0, 0, 0, 0
+	appendInfoLine: "   Energy in reflection: ", stdev
+	reflection.Matrix: Draw rows: 0, 0, 0, 0, -5, 5
+	reflection.Matrix: Remove
+endfor
+my.PatternList & my.DeepBeliefNetwork: Remove
diff --git a/test/script/RBM.praat b/test/script/RBM.praat
index dc23a93..a2bddd8 100644
--- a/test/script/RBM.praat
+++ b/test/script/RBM.praat
@@ -7,8 +7,8 @@ numberOfOutputNodes = 20
 numberOfVowels = 3
 mean# = { 8, 16, 23 }
 sigma = 1.8
-numberOfPatterns = 100000
-learningRate = 0.0001
+numberOfPatterns = 10000
+learningRate = 0.001
 
 #
 # Train first layer.
diff --git a/test/script/RBM.praat b/test/script/RBMparallel.praat
similarity index 76%
copy from test/script/RBM.praat
copy to test/script/RBMparallel.praat
index dc23a93..ebd28a6 100644
--- a/test/script/RBM.praat
+++ b/test/script/RBMparallel.praat
@@ -7,11 +7,11 @@ numberOfOutputNodes = 20
 numberOfVowels = 3
 mean# = { 8, 16, 23 }
 sigma = 1.8
-numberOfPatterns = 100000
-learningRate = 0.0001
+numberOfPatterns = 10000
+learningRate = 0.001
 
 #
-# Train first layer.
+# Train the first and second layer in parallel.
 #
 input1# = zero# (numberOfInputNodes)
 output1# = zero# (numberOfMiddleNodes)
@@ -20,34 +20,6 @@ outbias1# = zero# (numberOfMiddleNodes)
 weight1## = zero## (numberOfInputNodes, numberOfMiddleNodes)
 inrec1# = zero# (numberOfInputNodes)
 outrec1# = zero# (numberOfMiddleNodes)
-for idatum to numberOfPatterns
-	vowel = randomInteger (1, numberOfVowels)
-	formant = randomGauss (mean# [vowel], sigma)
-	input1# ~ 5 * exp (-0.5/sigma^2 * (col - formant) ^ 2) - 0.5
-	#
-	# Spread up, with Bernoulli sampling.
-	#
-	output1# = sigmoid# (outbias1# + mul# (input1#, weight1##))
-	output1# = randomBernoulli# (output1#)
-	#
-	# Spread down.
-	#
-	inrec1# = inbias1# + mul# (weight1##, output1#)   ; Gaussian
-	#
-	# Spread up.
-	#
-	outrec1# = sigmoid# (outbias1# + mul# (inrec1#, weight1##))
-	#
-	# Update.
-	#
-	inbias1# += learningRate * (input1# - inrec1#)
-	outbias1# += learningRate * (output1# - outrec1#)
-	weight1## += learningRate * (outer## (input1#, output1#) - outer## (inrec1#, outrec1#))
-endfor
-
-#
-# Train second layer.
-#
 input2# = zero# (numberOfMiddleNodes)
 output2# = zero# (numberOfOutputNodes)
 inbias2# = zero# (numberOfMiddleNodes)
@@ -60,48 +32,36 @@ for idatum to numberOfPatterns
 	formant = randomGauss (mean# [vowel], sigma)
 	input1# ~ 5 * exp (-0.5/sigma^2 * (col - formant) ^ 2) - 0.5
 	#
-	# Spread up through first layer, with Bernoulli sampling.
+	# Spread up, with Bernoulli sampling.
 	#
 	output1# = sigmoid# (outbias1# + mul# (input1#, weight1##))
 	output1# = randomBernoulli# (output1#)
-	;; output1# owned and target
-	;; output1# by reference (and target)
-	;; randomBernoulli# into output1# (because no use of output1# further on)
-	;; assignment is no-op
-	#
-	# Copy output of first layer to input of second layer.
-	#
 	input2# = output1#
-	#
-	# Spread up through second layer, with Bernoulli sampling.
-	#
 	output2# = sigmoid# (outbias2# + mul# (input2#, weight2##))
 	output2# = randomBernoulli# (output2#)
 	#
 	# Spread down.
 	#
+	inrec1# = inbias1# + mul# (weight1##, output1#)   ; Gaussian
 	inrec2# = sigmoid# (inbias2# + mul# (weight2##, output2#))
-	; inrec2# owned and target TODO
-	; inbias2# by reference OK
-	; weight2## by reference OK
-	; output2# by reference OK
-	; mul# ref and ref into target (size matches, and inrec# does not occur further on) TODO
-	; + ref into target TODO
-	; sigmoid# into target TODO
-
 	#
 	# Spread up.
 	#
+	outrec1# = sigmoid# (outbias1# + mul# (inrec1#, weight1##))
 	outrec2# = sigmoid# (outbias2# + mul# (inrec2#, weight2##))
 	#
 	# Update.
 	#
+	inbias1# += learningRate * (input1# - inrec1#)
+	outbias1# += learningRate * (output1# - outrec1#)
+	weight1## += learningRate * (outer## (input1#, output1#) - outer## (inrec1#, outrec1#))
 	inbias2# += learningRate * (input2# - inrec2#)
 	outbias2# += learningRate * (output2# - outrec2#)
 	weight2## += learningRate * (outer## (input2#, output2#) - outer## (inrec2#, outrec2#))
 endfor
 
 appendInfoLine: "Trained in ", stopwatch, " seconds"
+appendInfoLine: weight1##, newline$, newline$, weight2##
 
 numberOfTestPatterns = 15
 Erase all
@@ -148,6 +108,7 @@ for itest to numberOfTestPatterns
 	#
 	Select outer viewport: 3, 6, (itest - 1) * 0.6, (itest - 1) * 0.6 + 1.0
 	Create simple Matrix: "reflection", 1, numberOfInputNodes, "inrec1# [col]"
+	appendInfoLine: "   Energy in reflection: ", stdev (inrec1#)
 	Draw rows: 0, 0, 0, 0, -5, 5
 	Remove
 endfor

-- 
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