[med-svn] [praat] 01/10: Imported Upstream version 5.3.56
Rafael Laboissière
rlaboiss-guest at alioth.debian.org
Sat Oct 26 01:27:19 UTC 2013
This is an automated email from the git hooks/post-receive script.
rlaboiss-guest pushed a commit to branch master
in repository praat.
commit 89df83bf85f515d4572218b846ae486942d158c7
Author: Rafael Laboissiere <rafael at laboissiere.net>
Date: Sat Oct 26 01:51:38 2013 +0200
Imported Upstream version 5.3.56
---
EEG/Makefile | 4 +-
FFNet/Makefile | 2 +-
LPC/.kdev_include_paths | 3 +
LPC/Cepstrogram.cpp | 323 ++++++++++--
LPC/Cepstrogram.h | 31 +-
LPC/Cepstrum.cpp | 459 ++++++++++++++---
LPC/Cepstrum.h | 51 +-
LPC/Cepstrum_and_Spectrum.cpp | 122 ++++-
LPC/Cepstrum_and_Spectrum.h | 11 +-
LPC/Makefile | 4 +-
LPC/Sound_and_Cepstrum.cpp | 2 +-
LPC/manual_LPC.cpp | 60 ++-
LPC/praat_LPC_init.cpp | 531 ++++++++++++++++----
artsynth/ArtwordEditor.cpp | 3 +-
artsynth/Makefile | 4 +-
contrib/ola/Makefile | 4 +-
dwsys/Makefile | 4 +-
dwsys/NUM2.cpp | 112 +++--
dwsys/NUM2.h | 41 +-
dwsys/NUMstring.cpp | 8 +
dwtest/test_Ltas_reportSpectralTilt.praat | 29 ++
...st_OnewayAnova.praat => test_onewayAnova.praat} | 4 +-
dwtools/Ltas_extensions.cpp | 12 +-
dwtools/MFCC.cpp | 88 +++-
dwtools/MFCC.h | 4 +-
dwtools/Makefile | 8 +-
dwtools/SpeechSynthesizer.cpp | 16 +-
dwtools/SpeechSynthesizer.h | 12 +-
dwtools/Table_extensions.cpp | 392 ++++++++++++++-
dwtools/Table_extensions.h | 12 +-
dwtools/TextGrid_extensions.cpp | 23 +-
dwtools/manual_BSS.cpp | 22 +-
dwtools/manual_MDS.cpp | 31 +-
dwtools/manual_dwtools.cpp | 310 +++++++++---
dwtools/praat_David_init.cpp | 307 ++++++++++-
external/espeak/Makefile | 2 +-
external/espeak/speech.h | 12 +-
external/flac/Makefile | 4 +-
external/glpk/Makefile | 6 +-
external/gsl/Makefile | 2 +-
external/mp3/Makefile | 6 +-
external/portaudio/READ_ME.TXT | 4 +-
external/portaudio/pa_dither.c | 6 +-
external/portaudio/pa_process.c | 4 +-
external/portaudio/pa_types.h | 41 +-
fon/FunctionEditor.cpp | 62 ++-
fon/FunctionEditor.h | 9 +-
fon/Makefile | 4 +-
fon/RunnerMFC.cpp | 1 -
fon/Sound.cpp | 37 ++
fon/Sound.h | 1 +
fon/Sound_audio.cpp | 4 +
fon/Sound_files.cpp | 16 +-
fon/TextGrid.cpp | 11 +-
fon/TextGridEditor.cpp | 64 ++-
fon/TextGridEditor_enums.h | 28 ++
fon/TextGridEditor_prefs.h | 4 +
fon/TextGrid_Sound.cpp | 264 +++++++++-
fon/TextGrid_Sound.h | 5 +-
fon/TextGrid_def.h | 3 +
fon/TimeSoundAnalysisEditor.cpp | 4 +-
fon/TimeSoundAnalysisEditor_prefs.h | 2 +-
fon/TimeSoundEditor.cpp | 20 +
fon/TimeSoundEditor.h | 4 +-
fon/TimeSoundEditor_prefs.h | 1 +
fon/manual_Fon.cpp | 41 +-
fon/manual_Manual.cpp | 6 +-
fon/manual_Picture.cpp | 17 +-
fon/manual_Script.cpp | 312 +++++++-----
fon/manual_programming.cpp | 26 +-
fon/manual_tutorials.cpp | 138 ++++-
fon/praat_Fon.cpp | 4 +-
fon/praat_Sound_init.cpp | 16 +
gram/Makefile | 4 +-
gram/OTGrammar.cpp | 96 +++-
gram/OTGrammar_enums.h | 4 +-
gram/OTGrammar_ex_tongueRoot.cpp | 4 +-
gram/OTMulti.cpp | 72 ++-
gram/manual_gram.cpp | 24 +-
gram/praat_gram.cpp | 6 +-
kar/Makefile | 4 +-
main/main_Praat.cpp | 19 +-
makefiles/makefile.defs.linux.alsa | 3 +-
makefiles/makefile.defs.linux.silent | 3 +-
num/Makefile | 4 +-
praat64_xcodeproj.dmg | Bin 266966 -> 300908 bytes
praat_xcodeproj.dmg | Bin 333592 -> 355256 bytes
stat/Makefile | 4 +-
stat/PairDistribution.cpp | 15 +-
stat/PairDistribution_def.h | 4 +-
stat/TableEditor.cpp | 33 +-
stat/manual_statistics.cpp | 10 +-
stat/praat_Stat.cpp | 13 +-
sys/DemoEditor.cpp | 35 +-
sys/Editor.cpp | 10 +-
sys/Formula.cpp | 268 +++++++++-
sys/Graphics.h | 4 +-
sys/GraphicsP.h | 3 +-
sys/GraphicsScreen.cpp | 46 +-
sys/Graphics_colour.cpp | 226 ++++-----
sys/Graphics_linesAndAreas.cpp | 130 ++---
sys/Graphics_mouse.cpp | 59 +--
sys/Graphics_text.cpp | 409 +++++++++------
sys/Gui.h | 58 ++-
sys/GuiButton.cpp | 23 +-
sys/GuiCheckButton.cpp | 89 ++--
sys/GuiControl.cpp | 54 +-
sys/GuiDialog.cpp | 3 +-
sys/GuiDrawingArea.cpp | 399 ++++++---------
sys/GuiFileSelect.cpp | 74 ++-
sys/GuiLabel.cpp | 23 +-
sys/GuiList.cpp | 297 ++++++-----
sys/GuiMenu.cpp | 25 +-
sys/GuiMenuItem.cpp | 41 +-
sys/GuiObject.cpp | 15 +-
sys/GuiOptionMenu.cpp | 6 +-
sys/GuiP.h | 14 +-
sys/GuiProgressBar.cpp | 26 +-
sys/GuiRadioButton.cpp | 75 ++-
sys/GuiScrollBar.cpp | 223 ++++----
sys/GuiScrolledWindow.cpp | 2 +-
sys/GuiShell.cpp | 19 +-
sys/GuiText.cpp | 224 +++++++--
sys/GuiThing.cpp | 8 +-
sys/GuiWindow.cpp | 30 +-
sys/HyperPage.cpp | 23 +-
sys/InfoEditor.cpp | 14 +-
sys/Makefile | 4 +-
sys/ManPages.cpp | 2 +-
sys/Picture.cpp | 171 +------
sys/Picture.h | 4 +-
sys/Ui.cpp | 4 +-
sys/UiPause.cpp | 2 +-
sys/abcio.cpp | 26 +-
sys/machine.cpp | 4 +-
sys/melder.cpp | 106 +++-
sys/melder.h | 7 +
sys/melder_audiofiles.cpp | 4 +-
sys/motifEmulator.cpp | 4 +-
sys/praat.cpp | 36 +-
sys/praat_actions.cpp | 16 +-
sys/praat_objectMenus.cpp | 25 +-
sys/praat_picture.cpp | 12 +-
sys/praat_script.cpp | 2 +-
sys/praat_version.h | 8 +-
sys/sendpraat.c | 25 +-
test/code.praat | 2 +-
test/fon/soundFiles.praat | 2 +-
test/runAllTests.praat | 4 +-
test/sys/graphics.praat | Bin 3972 -> 8090 bytes
test/sys/procedures2.praat | 10 +
test/sys/progress.praat | Bin 0 -> 786 bytes
test/sys/script2.praat | Bin 0 -> 3930 bytes
test/test.txt | 17 +
154 files changed, 5696 insertions(+), 2318 deletions(-)
diff --git a/EEG/Makefile b/EEG/Makefile
index c4c19bd..e1441db 100644
--- a/EEG/Makefile
+++ b/EEG/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "EEG"
-# Paul Boersma, 20 February 2012
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -19,7 +19,7 @@ clean:
libEEG.a: $(OBJECTS)
touch libEEG.a
rm libEEG.a
- ar cq libEEG.a $(OBJECTS)
+ $(AR) cq libEEG.a $(OBJECTS)
$(RANLIB) libEEG.a
$(OBJECTS): *.h ../num/NUM.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
diff --git a/FFNet/Makefile b/FFNet/Makefile
index aa770f2..b8d4684 100644
--- a/FFNet/Makefile
+++ b/FFNet/Makefile
@@ -22,7 +22,7 @@ clean:
libFFNet.a: $(OBJECTS)
touch libFFNet.a
rm libFFNet.a
- ar cq libFFNet.a $(OBJECTS)
+ $(AR) cq libFFNet.a $(OBJECTS)
$(RANLIB) libFFNet.a
$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../dwtools/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h
diff --git a/LPC/.kdev_include_paths b/LPC/.kdev_include_paths
new file mode 100644
index 0000000..c1a8344
--- /dev/null
+++ b/LPC/.kdev_include_paths
@@ -0,0 +1,3 @@
+/home/david/praat/build/dwsys/
+/home/david/praat/build/num/
+/home/david/praat/build/fon/
diff --git a/LPC/Cepstrogram.cpp b/LPC/Cepstrogram.cpp
index 7b8ca6c..52fa4a5 100644
--- a/LPC/Cepstrogram.cpp
+++ b/LPC/Cepstrogram.cpp
@@ -30,7 +30,12 @@
#include "Sound_and_Spectrum.h"
#include "Sound_extensions.h"
+#define TOLOG(x) ((1 / NUMln10) * log ((x) + 1e-30))
+#define TO10LOG(x) ((10 / NUMln10) * log ((x) + 1e-30))
+#define FROMLOG(x) (exp ((x) * (NUMln10 / 10.0)) - 1e-30)
+
Thing_implement (Cepstrogram, Matrix, 2);
+Thing_implement (PowerCepstrogram, Cepstrogram, 2); // derives from Matrix -> also version 2
Cepstrogram Cepstrogram_create (double tmin, double tmax, long nt, double dt, double t1,
double qmin, double qmax, long nq, double dq, double q1) {
@@ -44,7 +49,19 @@ Cepstrogram Cepstrogram_create (double tmin, double tmax, long nt, double dt, do
}
}
-void Cepstrogram_paint (Cepstrogram me, Graphics g, double tmin, double tmax, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish) {
+PowerCepstrogram PowerCepstrogram_create (double tmin, double tmax, long nt, double dt, double t1,
+ double qmin, double qmax, long nq, double dq, double q1) {
+ try {
+ autoPowerCepstrogram me = Thing_new (PowerCepstrogram);
+
+ Matrix_init (me.peek(), tmin, tmax, nt, dt, t1, qmin, qmax, nq, dq, q1);
+ return me.transfer();
+ } catch (MelderError) {
+ Melder_throw ("PowerCepstrogram not created.");
+ }
+}
+
+void PowerCepstrogram_paint (PowerCepstrogram me, Graphics g, double tmin, double tmax, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish) {
if (tmax <= tmin) { tmin = my xmin; tmax = my xmax; }
if (qmax <= qmin) { qmin = my ymin; qmax = my ymax; }
long itmin, itmax, ifmin, ifmax;
@@ -56,9 +73,10 @@ void Cepstrogram_paint (Cepstrogram me, Graphics g, double tmin, double tmax, do
double min = 1e38, max = -min;
for (long i = 1; i <= my ny; i++) {
for (long j = 1; j <= my nx; j++) {
- double val = thy z[i][j] = 20 * log10 (fabs (my z[i][j]));
+ double val = TO10LOG (my z[i][j]);
min = val < min ? val : min;
max = val > max ? val : max;
+ thy z[i][j] = val;
}
}
if (dBmaximum <= dBminimum) {
@@ -85,20 +103,47 @@ void Cepstrogram_paint (Cepstrogram me, Graphics g, double tmin, double tmax, do
}
}
-Table Cepstrogram_to_Table_cpp (Cepstrogram me, double lowestQuefrency, double highestQuefrency, int interpolation, double qstartFit, double qendFit, int method) {
+void PowerCepstrogram_subtractTilt_inline (PowerCepstrogram me, double qstartFit, double qendFit, int lineType, int fitMethod) {
+ try {
+ autoPowerCepstrum thee = PowerCepstrum_create (my ymax, my ny);
+ for (long i = 1; i <= my nx; i++) {
+ for (long j = 1; j <= my ny; j++) {
+ thy z[1][j] = my z[j][i];
+ }
+ PowerCepstrum_subtractTilt_inline (thee.peek(), qstartFit, qendFit, lineType, fitMethod);
+ for (long j = 1; j <= my ny; j++) {
+ my z[j][i] = thy z[1][j];
+ }
+ }
+ } catch (MelderError) {
+ Melder_throw (me, ": no tilt subtracted (inline).");
+ }
+}
+
+PowerCepstrogram PowerCepstrogram_subtractTilt (PowerCepstrogram me, double qstartFit, double qendFit, int lineType, int fitMethod) {
+ try {
+ autoPowerCepstrogram thee = Data_copy (me);
+ PowerCepstrogram_subtractTilt_inline (thee.peek(), qstartFit, qendFit, lineType, fitMethod);
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": no tilt subtracted.");
+ }
+
+}
+
+Table PowerCepstrogram_to_Table_hillenbrand (PowerCepstrogram me, double pitchFloor, double pitchCeiling) {
try {
autoTable thee = Table_createWithColumnNames (my nx, L"time quefrency cpp f0");
- autoCepstrum him = Cepstrum_create (my ymin, my ymax, my ny);
+ autoPowerCepstrum him = PowerCepstrum_create (my ymax, my ny);
for (long i = 1; i <= my nx; i++) {
for (long j = 1; j <= my ny; j++) {
his z[1][j] = my z[j][i];
}
- double qpeak, cpp = Cepstrum_getPeakProminence (him.peek(), lowestQuefrency, highestQuefrency, interpolation,
- qstartFit, qendFit, method, &qpeak);
+ double qpeak, cpp = PowerCepstrum_getPeakProminence_hillenbrand (him.peek(), pitchFloor, pitchCeiling, &qpeak);
double time = Sampled_indexToX (me, i);
Table_setNumericValue (thee.peek(), i, 1, time);
Table_setNumericValue (thee.peek(), i, 2, qpeak);
- Table_setNumericValue (thee.peek(), i, 3, cpp);
+ Table_setNumericValue (thee.peek(), i, 3, cpp); // Cepstrogram_getCPPS depends on this index 3!!
Table_setNumericValue (thee.peek(), i, 4, 1.0 / qpeak);
}
return thee.transfer();
@@ -107,56 +152,64 @@ Table Cepstrogram_to_Table_cpp (Cepstrogram me, double lowestQuefrency, double h
}
}
-static void NUMvector_smoothByMovingAverage (double *xin, long n, long nwindow, double *xout) {
-// simple averaging, out of bound values are zero
- for (long i = 1; i <= n; i++) {
- long jfrom = i - nwindow / 2, jto = i + nwindow / 2;
- jfrom = jfrom < 1 ? 1 : jfrom;
- jto = jto > n ? n : jto;
- xout[i] = 0;
- for (long j = jfrom; j <= jto; j++) {
- xout[i] += xin[j];
+Table PowerCepstrogram_to_Table_cpp (PowerCepstrogram me, double pitchFloor, double pitchCeiling, double deltaF0, int interpolation, double qstartFit, double qendFit, int lineType, int fitMethod) {
+ try {
+ autoTable thee = Table_createWithColumnNames (my nx, L"time quefrency cpp f0 rnr");
+ autoPowerCepstrum him = PowerCepstrum_create (my ymax, my ny);
+ for (long i = 1; i <= my nx; i++) {
+ for (long j = 1; j <= my ny; j++) {
+ his z[1][j] = my z[j][i];
+ }
+ double qpeak, z, cpp = PowerCepstrum_getPeakProminence (him.peek(), pitchFloor, pitchCeiling, interpolation,
+ qstartFit, qendFit, lineType, fitMethod, &qpeak);
+ double rnr = PowerCepstrum_getRNR (him.peek(), pitchFloor, pitchCeiling, deltaF0);
+ double time = Sampled_indexToX (me, i);
+ Table_setNumericValue (thee.peek(), i, 1, time);
+ Table_setNumericValue (thee.peek(), i, 2, qpeak);
+ Table_setNumericValue (thee.peek(), i, 3, cpp); // Cepstrogram_getCPPS depends on this index!!
+ Table_setNumericValue (thee.peek(), i, 4, 1.0 / qpeak);
+ Table_setNumericValue (thee.peek(), i, 5, rnr);
}
- xout[i] /= jto - jfrom + 1;
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": no Table with cepstral peak prominence values created.");
}
}
-Cepstrogram Cepstrogram_smooth (Cepstrogram me, double timeAveragingWindow, double quefrencyAveragingWindow) {
+PowerCepstrogram PowerCepstrogram_smooth (PowerCepstrogram me, double timeAveragingWindow, double quefrencyAveragingWindow) {
try {
- autoCepstrogram thee = (Cepstrogram) Data_copy (me);
+ autoPowerCepstrogram thee = (PowerCepstrogram) Data_copy (me);
+ // 1. average across time
long numberOfFrames = timeAveragingWindow / my dx;
if (numberOfFrames > 1) {
- // 1. average across time
- if (numberOfFrames % 2 == 0) { // make symmetric
- numberOfFrames++;
- }
autoNUMvector<double> qin (1, my nx);
autoNUMvector<double> qout (1, my nx);
for (long iq = 1; iq <= my ny; iq++) {
for (long iframe = 1; iframe <= my nx; iframe++) {
- qin[iframe] = my z[iq][iframe] * my z[iq][iframe];
+ //qin[iframe] = TO10LOG (my z[iq][iframe]);
+ qin[iframe] = thy z[iq][iframe];
}
NUMvector_smoothByMovingAverage (qin.peek(), my nx, numberOfFrames, qout.peek());
for (long iframe = 1; iframe <= my nx; iframe++) {
- thy z[iq][iframe] = sqrt (qout[iframe]);
+ //thy z[iq][iframe] = FROMLOG (qout[iframe]); // inverse
+ thy z[iq][iframe] = qout[iframe]; // inverse
}
}
}
// 2. average across quefrencies
long numberOfQuefrencyBins = quefrencyAveragingWindow / my dy;
- if (numberOfQuefrencyBins > 0) {
- if (numberOfQuefrencyBins % 2 == 0) {
- numberOfQuefrencyBins++;
- }
+ if (numberOfQuefrencyBins > 1) {
autoNUMvector<double> qin (1, thy ny);
autoNUMvector<double> qout (1, thy ny);
for (long iframe = 1; iframe <= my nx; iframe++) {
for (long iq = 1; iq <= thy ny; iq++) {
- qin[iq] = thy z[iq][iframe] * thy z[iq][iframe]; //fabs (thy z[iq][iframe]);
+ //qin[iq] = TO10LOG (my z[iq][iframe]);
+ qin[iq] = thy z[iq][iframe];
}
NUMvector_smoothByMovingAverage (qin.peek(), thy ny, numberOfQuefrencyBins, qout.peek());
for (long iq = 1; iq <= thy ny; iq++) {
- thy z[iq][iframe] = sqrt (qout[iq]);
+ //thy z[iq][iframe] = FROMLOG (qout[iq]);
+ thy z[iq][iframe] = qout[iq];
}
}
}
@@ -166,7 +219,7 @@ Cepstrogram Cepstrogram_smooth (Cepstrogram me, double timeAveragingWindow, doub
}
}
-Matrix Cepstrogram_to_Matrix (Cepstrogram me) {
+Matrix PowerCepstrogram_to_Matrix (PowerCepstrogram me) {
try {
autoMatrix thee = Thing_new (Matrix);
my structMatrix :: v_copy (thee.peek());
@@ -176,11 +229,11 @@ Matrix Cepstrogram_to_Matrix (Cepstrogram me) {
}
}
-Cepstrum Cepstrogram_to_Cepstrum_slice (Cepstrogram me, double time) {
+PowerCepstrum PowerCepstrogram_to_PowerCepstrum_slice (PowerCepstrogram me, double time) {
try {
long iframe = Sampled_xToNearestIndex (me, time);
iframe = iframe < 1 ? 1 : iframe > my nx ? my nx : iframe;
- autoCepstrum thee = Cepstrum_create (my ymin, my ymax, my ny);
+ autoPowerCepstrum thee = PowerCepstrum_create (my ymax, my ny);
for (long i = 1; i <= my ny; i++) {
thy z[1][i] = my z[i][iframe];
}
@@ -190,18 +243,20 @@ Cepstrum Cepstrogram_to_Cepstrum_slice (Cepstrogram me, double time) {
}
}
-Cepstrogram Matrix_to_Cepstrogram (Matrix me) {
+PowerCepstrogram Matrix_to_PowerCepstrogram (Matrix me) {
try {
- autoCepstrogram thee = Thing_new (Cepstrogram);
+ autoPowerCepstrogram thee = Thing_new (PowerCepstrogram);
my structMatrix :: v_copy (thee.peek());
return thee.transfer();
} catch (MelderError) {
- Melder_throw (me, ": no Cepstrogram created.");
+ Melder_throw (me, ": no PowerCepstrogram created.");
}
}
-Cepstrogram Sound_to_Cepstrogram (Sound me, double analysisWidth, double dt, double maximumFrequency, double preEmphasisFrequency) {
+PowerCepstrogram Sound_to_PowerCepstrogram (Sound me, double pitchFloor, double dt, double maximumFrequency, double preEmphasisFrequency) {
try {
+ // minimum analysis window has 3 periods of lowest pitch
+ double analysisWidth = 3 / pitchFloor;
double windowDuration = 2 * analysisWidth; /* gaussian window */
long nFrames;
@@ -215,15 +270,12 @@ Cepstrogram Sound_to_Cepstrogram (Sound me, double analysisWidth, double dt, dou
Sampled_shortTermAnalysis (me, windowDuration, dt, & nFrames, & t1);
autoSound sframe = Sound_createSimple (1, windowDuration, samplingFrequency);
autoSound window = Sound_createGaussian (windowDuration, samplingFrequency);
- double qmin, qmax, dq, q1;
- long nq;
- { // laziness: find out the proper dimensions
- autoSpectrum spec = Sound_to_Spectrum (sframe.peek(), 1);
- autoCepstrum cepstrum = Spectrum_to_Cepstrum (spec.peek());
- qmin = cepstrum -> xmin; qmax = cepstrum -> xmax; dq = cepstrum -> dx;
- q1 = cepstrum -> x1; nq = cepstrum -> nx;
- }
- autoCepstrogram thee = Cepstrogram_create (my xmin, my xmax, nFrames, dt, t1, qmin, qmax, nq, dq, q1);
+ // find out the size of the FFT
+ long nfft = 2;
+ while (nfft < sframe -> nx) nfft *= 2;
+ long nq = nfft / 2 + 1;
+ double qmax = 0.5 * nfft / samplingFrequency, dq = qmax / (nq - 1);
+ autoPowerCepstrogram thee = PowerCepstrogram_create (my xmin, my xmax, nFrames, dt, t1, 0, qmax, nq, dq, 0);
autoMelderProgress progress (L"Cepstrogram analysis");
@@ -232,20 +284,191 @@ Cepstrogram Sound_to_Cepstrogram (Sound me, double analysisWidth, double dt, dou
Sound_into_Sound (sound.peek(), sframe.peek(), t - windowDuration / 2);
Vector_subtractMean (sframe.peek());
Sounds_multiply (sframe.peek(), window.peek());
- autoSpectrum spec = Sound_to_Spectrum (sframe.peek(), 1);
- autoCepstrum cepstrum = Spectrum_to_Cepstrum (spec.peek());
+ autoSpectrum spec = Sound_to_Spectrum (sframe.peek(), 1); // FFT yes
+ autoPowerCepstrum cepstrum = Spectrum_to_PowerCepstrum (spec.peek());
for (long i = 1; i <= nq; i++) {
thy z[i][iframe] = cepstrum -> z[1][i];
}
if ((iframe % 10) == 1) {
- Melder_progress ((double) iframe / nFrames, L"Cepstrogram analysis of frame ",
+ Melder_progress ((double) iframe / nFrames, L"PowerCepstrogram analysis of frame ",
Melder_integer (iframe), L" out of ", Melder_integer (nFrames), L".");
}
}
return thee.transfer();
} catch (MelderError) {
+ Melder_throw (me, ": no PowerCepstrogram created.");
+ }
+}
+
+Cepstrum Spectrum_to_Cepstrum_hillenbrand (Spectrum me) {
+ try {
+ autoNUMfft_Table fftTable;
+ // originalNumberOfSamplesProbablyOdd irrelevant
+ if (my x1 != 0.0) {
+ Melder_throw ("A Fourier-transformable Spectrum must have a first frequency of 0 Hz, not ", my x1, L" Hz.");
+ }
+ long numberOfSamples = my nx - 1;
+ autoCepstrum thee = Cepstrum_create (0.5 / my dx, my nx);
+ NUMfft_Table_init (&fftTable, my nx);
+ autoNUMvector<double> amp (1, my nx);
+
+ for (long i = 1; i <= my nx; i++) {
+ amp [i] = my v_getValueAtSample (i, 0, 2);
+ }
+ NUMfft_forward (&fftTable, amp.peek());
+
+ for (long i = 1; i <= my nx; i++) {
+ double val = amp[i] / numberOfSamples;// scaling 1/n because ifft(fft(1))= n;
+ thy z[1][i] = val * val; // power cepstrum
+ }
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": not converted to Sound.");
+ }
+}
+
+// 1 2 nfftdiv2
+// re im re im re im
+// ((fft[1],0) (fft[2],fft[3]), (,), (,), (fft[nfft], 0)) nfft even
+// ((fft[1],0) (fft[2],fft[3]), (,), (,), (fft[nfft-1], fft[nfft])) nfft uneven
+static void complexfftoutput_to_power (double *fft, long nfft, double *dbs, bool to_db) {
+ double valsq = fft[1] * fft[1];
+ dbs[1] = to_db ? TOLOG (valsq) : valsq;
+ long nfftdiv2p1 = (nfft + 2) / 2;
+ long nend = nfft % 2 == 0 ? nfftdiv2p1 : nfftdiv2p1 + 1;
+ for (long i = 2; i < nend; i++) {
+ double re = fft[i + i - 2], im = fft[i + i - 1];
+ valsq = re * re + im * im;
+ dbs[i] = to_db ? TOLOG (valsq) : valsq;
+ }
+ if (nfft % 2 == 0) {
+ valsq = fft[nfft] * fft[nfft];
+ dbs[nfftdiv2p1] = to_db ? TOLOG (valsq) : valsq;
+ }
+}
+
+
+PowerCepstrogram Sound_to_PowerCepstrogram_hillenbrand (Sound me, double minimumPitch, double dt) {
+ try {
+ // minimum analysis window has 3 periods of lowest pitch
+ double analysisWidth = 3 / minimumPitch;
+ if (analysisWidth > my dx * my nx) {
+ analysisWidth = my dx * my nx;
+ }
+ double t1, samplingFrequency = 1 / my dx;
+ autoSound thee;
+ if (samplingFrequency > 30000) {
+ samplingFrequency = samplingFrequency / 2;
+ thee.reset (Sound_resample (me, samplingFrequency, 1));
+ } else {
+ thee.reset (Data_copy (me));
+ }
+ // pre-emphasis with fixed coefficient 0.9
+ for (long i = thy nx; i > 1; i--) {
+ thy z[1][i] -= 0.9 * thy z[1][i - 1];
+ }
+ long nosInWindow = analysisWidth * samplingFrequency, nFrames;
+ if (nosInWindow < 8) {
+ Melder_throw ("Analysis window too short.");
+ }
+ Sampled_shortTermAnalysis (thee.peek(), analysisWidth, dt, & nFrames, & t1);
+ autoNUMvector<double> hamming (1, nosInWindow);
+ for (long i = 1; i <= nosInWindow; i++) {
+ hamming[i] = 0.54 -0.46 * cos(2 * NUMpi * (i - 1) / (nosInWindow - 1));
+ }
+ long nfft = 8; // minimum possible
+ while (nfft < nosInWindow) { nfft *= 2; }
+ long nfftdiv2 = nfft / 2;
+ autoNUMvector<double> fftbuf (1, nfft); // "complex" array
+ autoNUMvector<double> spectrum (1, nfftdiv2 + 1); // +1 needed
+ autoNUMfft_Table fftTable;
+ NUMfft_Table_init (&fftTable, nfft); // sound to spectrum
+
+ double qmax = 0.5 * nfft / samplingFrequency, dq = qmax / (nfftdiv2 + 1);
+ autoPowerCepstrogram him = PowerCepstrogram_create (my xmin, my xmax, nFrames, dt, t1, 0, qmax, nfftdiv2+1, dq, 0);
+
+ autoMelderProgress progress (L"Cepstrogram analysis");
+
+ for (long iframe = 1; iframe <= nFrames; iframe++) {
+ double tbegin = t1 + (iframe - 1) * dt - analysisWidth / 2;
+ tbegin = tbegin < thy xmin ? thy xmin : tbegin;
+ long istart = Sampled_xToIndex (thee.peek(), tbegin);
+ istart = istart < 1 ? 1 : istart;
+ long iend = istart + nosInWindow - 1;
+ iend = iend > thy nx ? thy nx : iend;
+ for (long i = 1; i <= nosInWindow; i++) {
+ fftbuf[i] = thy z[1][istart + i - 1] * hamming[i];
+ }
+ for (long i = nosInWindow + 1; i <= nfft; i++) {
+ fftbuf[i] = 0;
+ }
+ NUMfft_forward (&fftTable, fftbuf.peek());
+ complexfftoutput_to_power (fftbuf.peek(), nfft, spectrum.peek(), true); // log10(|fft|^2)
+ // subtract average
+ double specmean = spectrum[1];
+ for (long i = 2; i <= nfftdiv2 + 1; i++) {
+ specmean += spectrum[i];
+ }
+ specmean /= nfftdiv2 + 1;
+ for (long i = 1; i <= nfftdiv2 + 1; i++) {
+ spectrum[i] -= specmean;
+ }
+ /*
+ * Here we diverge from Hillenbrand as he takes the fft of half of the spectral values.
+ * H. forgets that the actual spectrum has nfft/2+1 values. Thefore, we take the inverse
+ * transform because this keeps the number of samples a power of 2.
+ * At the same time this results in twice as much numbers in the quefrency domain, i.e. we end with nfft/2+1
+ * numbers while H. has only nfft/4!
+ */
+ fftbuf[1] = spectrum[1];
+ for (long i = 2; i < nfftdiv2 + 1; i++) {
+ fftbuf[i+i-2] = spectrum[i];
+ fftbuf[i+i-1] = 0;
+ }
+ fftbuf[nfft] = spectrum[nfftdiv2 + 1];
+ NUMfft_backward (&fftTable, fftbuf.peek());
+ for (long i = 1; i <= nfftdiv2 + 1; i++) {
+ his z[i][iframe] = fftbuf[i] * fftbuf[i];
+ }
+ if ((iframe % 10) == 1) {
+ Melder_progress ((double) iframe / nFrames, L"Cepstrogram analysis of frame ",
+ Melder_integer (iframe), L" out of ", Melder_integer (nFrames), L".");
+ }
+ }
+ return him.transfer();
+ } catch (MelderError) {
Melder_throw (me, ": no Cepstrogram created.");
}
}
+double PowerCepstrogram_getCPPS (PowerCepstrogram me, bool subtractTiltBeforeSmoothing, double timeAveragingWindow, double quefrencyAveragingWindow, double pitchFloor, double pitchCeiling, double deltaF0, int interpolation, double qstartFit, double qendFit, int lineType, int fitMethod) {
+ try {
+ autoPowerCepstrogram him;
+ if (subtractTiltBeforeSmoothing) {
+ him.reset(PowerCepstrogram_subtractTilt (me, qstartFit, qendFit, lineType, fitMethod));
+ }
+ autoPowerCepstrogram smooth = PowerCepstrogram_smooth (subtractTiltBeforeSmoothing ? him.peek() : me, timeAveragingWindow, quefrencyAveragingWindow);
+ autoTable table = PowerCepstrogram_to_Table_cpp (smooth.peek(), pitchFloor, pitchCeiling, deltaF0, interpolation, qstartFit, qendFit, lineType, fitMethod);
+ double cpps = Table_getMean (table.peek(), 3);
+ return cpps;
+ } catch (MelderError) {
+ Melder_throw (me, ": no CPPS value calculated.");
+ }
+}
+
+double PowerCepstrogram_getCPPS_hillenbrand (PowerCepstrogram me, bool subtractTiltBeforeSmoothing, double timeAveragingWindow, double quefrencyAveragingWindow, double pitchFloor, double pitchCeiling) {
+ try {
+ autoPowerCepstrogram him;
+ if (subtractTiltBeforeSmoothing) {
+ him.reset(PowerCepstrogram_subtractTilt (me, 0.001, 0, 1, 1));
+ }
+ autoPowerCepstrogram smooth = PowerCepstrogram_smooth (subtractTiltBeforeSmoothing ? him.peek() : me, timeAveragingWindow, quefrencyAveragingWindow);
+ autoTable table = PowerCepstrogram_to_Table_hillenbrand (smooth.peek(), pitchFloor, pitchCeiling);
+ double cpps = Table_getMean (table.peek(), 3);
+ return cpps;
+ } catch (MelderError) {
+ Melder_throw (me, ": no CPPS value calculated.");
+ }
+}
+
/* End of file Cepstrogram.cpp */
diff --git a/LPC/Cepstrogram.h b/LPC/Cepstrogram.h
index d59cd18..59ac866 100644
--- a/LPC/Cepstrogram.h
+++ b/LPC/Cepstrogram.h
@@ -21,7 +21,7 @@
/*
djmw 20121017
- djmw 20121117 Latest modification.
+ djmw 20130502 Latest modification.
*/
/*
@@ -36,6 +36,8 @@
Thing_define (Cepstrogram, Matrix) {
};
+Thing_define (PowerCepstrogram, Cepstrogram) {
+};
/*
xmin, xmax : time domain
nx, dx, x1 : sampling in the time domain
@@ -49,15 +51,28 @@ Thing_define (Cepstrogram, Matrix) {
Cepstrogram Cepstrogram_create (double tmin, double tmax, long nt, double dt, double t1,
double qmin, double qmax, long nq, double dq, double q1);
+PowerCepstrogram PowerCepstrogram_create (double tmin, double tmax, long nt, double dt, double t1,
+ double qmin, double qmax, long nq, double dq, double q1);
+
+void PowerCepstrogram_paint (PowerCepstrogram me, Graphics g, double tmin, double tmax, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish);
+
+PowerCepstrogram PowerCepstrogram_smooth (PowerCepstrogram me, double timeAveragingWindow, double quefrencyAveragingWindow);
+
+PowerCepstrogram Sound_to_PowerCepstrogram (Sound me, double analysisWidth, double dt, double maximumFrequency, double preEmphasisFrequency);
+
+PowerCepstrogram Sound_to_PowerCepstrogram_hillenbrand (Sound me, double analysisWidth, double dt);
-void Cepstrogram_paint (Cepstrogram me, Graphics g, double tmin, double tmax, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish);
+Table PowerCepstrogram_to_Table_hillenbrand (PowerCepstrogram me, double pitchFloor, double pitchCeiling);
+Table PowerCepstrogram_to_Table_cpp (PowerCepstrogram me, double pitchFloor, double pitchCeiling, double deltaF0, int interpolation, double qstartFit, double qendFit, int lineType, int method);
+PowerCepstrum PowerCepstrogram_to_PowerCepstrum_slice (PowerCepstrogram me, double time);
- Cepstrogram Cepstrogram_smooth (Cepstrogram me, double timeAveragingWindow, double quefrencyAveragingWindow);
+PowerCepstrogram PowerCepstrogram_subtractTilt (PowerCepstrogram me, double qstartFit, double qendFit, int lineType, int fitMethod);
+void PowerCepstrogram_subtractTilt_inline (PowerCepstrogram me, double qstartFit, double qendFit, int lineType, int fitMethod);
- Cepstrogram Sound_to_Cepstrogram (Sound me, double analysisWidth, double dt, double maximumFrequency, double preEmphasisFrequency);
-Table Cepstrogram_to_Table_cpp (Cepstrogram me, double lowestQuefrency, double highestQuefrency, int interpolation, double qstartFit, double qendFit, int method);
-Cepstrum Cepstrogram_to_Cepstrum_slice (Cepstrogram me, double time);
+double PowerCepstrogram_getCPPS_hillenbrand (PowerCepstrogram me, bool subtractTiltBeforeSmoothing, double timeAveragingWindow, double quefrencyAveragingWindow, double pitchFloor, double pitchCeiling);
+double PowerCepstrogram_getCPPS (PowerCepstrogram me, bool subtractTiltBeforeSmoothing, double timeAveragingWindow, double quefrencyAveragingWindow,
+ double pitchFloor, double pitchCeiling, double deltaF0, int interpolation, double qstartFit, double qendFit, int lineType, int fitMethod);
-Matrix Cepstrogram_to_Matrix (Cepstrogram me);
-Cepstrogram Matrix_to_Cepstrogram (Matrix me);
+Matrix PowerCepstrogram_to_Matrix (PowerCepstrogram me);
+PowerCepstrogram Matrix_to_Cepstrogram (Matrix me);
#endif /* _Cepstrogram_h_ */
diff --git a/LPC/Cepstrum.cpp b/LPC/Cepstrum.cpp
index 6cea20c..c4840e4 100644
--- a/LPC/Cepstrum.cpp
+++ b/LPC/Cepstrum.cpp
@@ -28,32 +28,114 @@
#include "NUM2.h"
#include "Vector.h"
+static void NUMvector_gaussianBlur (double sigma, long filterLength, double *filter) {
+ if (filterLength <= 1) {
+ filter[1] = 1;
+ return;
+ }
+ double sum = 0, mid = (filterLength + 1) / 2;
+ for (long i = 1; i <= filterLength; i++) {
+ double val = (mid - i) / sigma;
+ filter[i] = exp (- 0.5 * val * val);
+ sum += filter[i];
+ }
+ for (long i = 1; i <= filterLength; i++) {
+ filter[i] /= sum;
+ }
+}
+
+// filter must be normalised: sum(i=1, nfilters, filter[i]) == 1
+static void NUMvector_filter (double *input, long numberOfDataPoints, double *filter, long numberOfFilterCoefficients, double *output, int edgeTreatment) {
+ long nleft = (numberOfFilterCoefficients - 1) / 2;
+ if (edgeTreatment == 0) { // outside values are zero
+ for (long i = 1; i <= numberOfDataPoints; i++) {
+ long ifrom = i - nleft, ito = i + nleft;
+ ito = numberOfFilterCoefficients % 2 == 0 ? ito - 1 : ito;
+ long jfrom = ifrom < 1 ? 1 : ifrom;
+ long jto = ito > numberOfDataPoints ? numberOfDataPoints : ito;
+ long index = ifrom < 1 ? 2 - ifrom : 1;
+ double out = 0, sum = 0;
+ for (long j = jfrom; j <= jto; j++, index++) {
+ out += filter[index] * input[j];
+ sum += filter[index];
+ }
+ output[i] = out / sum;
+ }
+ } else if (edgeTreatment == 1) { // wrap-around
+ for (long i = 1; i <= numberOfDataPoints; i++) {
+ double out = 0;
+ for (long j = 1; j <= numberOfFilterCoefficients; j++) {
+ long index = (i - nleft + j - 2) % numberOfDataPoints + 1;
+ out += filter[j] * input[index];
+ }
+ output[i] = out;
+ }
+ }
+
+
+}
+
Thing_implement (Cepstrum, Matrix, 2);
+Thing_implement (PowerCepstrum, Cepstrum, 2); // derives from Matrix therefore also version 2
double structCepstrum :: v_getValueAtSample (long isamp, long which, int units) {
(void) units;
- double valsq = z[1][isamp] * z[1][isamp];
if (which == 0) {
- return valsq;
+ return z[1][isamp];
} else {
- // dB's reference is 1.
- return valsq == 0.0 ? -300.0 : 10.0 * log10 (valsq);
+ // dB's
+ return 20.0 * log10 (fabs(z[1][isamp]) + 1e-30);
}
return NUMundefined;
}
-Cepstrum Cepstrum_create (double qmin, double qmax, long nq) {
+double structPowerCepstrum :: v_getValueAtSample (long isamp, long which, int units) {
+ (void) units;
+ if (which == 0) {
+ return z[1][isamp];
+ } else {
+ // dB's
+ return 10.0 * log10 (z[1][isamp] + 1e-30); // always positive
+ }
+ return NUMundefined;
+}
+
+Cepstrum Cepstrum_create (double qmax, long nq) {
try {
autoCepstrum me = Thing_new (Cepstrum);
- double dq = (qmax - qmin) / (nq - 1);
+ double dq = qmax / (nq - 1);
- Matrix_init (me.peek(), qmin, qmax, nq, dq, qmin, 1, 1, 1, 1, 1);
+ Matrix_init (me.peek(), 0, qmax, nq, dq, 0, 1, 1, 1, 1, 1);
return me.transfer();
} catch (MelderError) {
Melder_throw ("Cepstrum not created.");
}
}
+PowerCepstrum Cepstrum_downto_PowerCepstrum (Cepstrum me ) {
+ try {
+ autoPowerCepstrum thee = PowerCepstrum_create (my xmax, my nx);
+ for (long i = 1; i <= my nx; i++) {
+ thy z[1][i] = my z[1][i] * my z[1][i];
+ }
+ return thee.transfer ();
+ } catch (MelderError) {
+ Melder_throw (me, " not converted.");
+ }
+}
+
+PowerCepstrum PowerCepstrum_create (double qmax, long nq) {
+ try {
+ autoPowerCepstrum me = Thing_new (PowerCepstrum);
+ double dq = qmax / (nq - 1);
+
+ Matrix_init (me.peek(), 0, qmax, nq, dq, 0, 1, 1, 1, 1, 1);
+ return me.transfer();
+ } catch (MelderError) {
+ Melder_throw ("PowerCepstrum not created.");
+ }
+}
+
void _Cepstrum_draw (Cepstrum me, Graphics g, double qmin, double qmax, double minimum, double maximum, int power, int garnish) {
int autoscaling = minimum >= maximum;
@@ -75,16 +157,15 @@ void _Cepstrum_draw (Cepstrum me, Graphics g, double qmin, double qmax, double m
if (autoscaling) {
NUMvector_extrema (y.peek(), imin, imax, & minimum, & maximum);
- }
-
- for (long i = imin; i <= imax; i ++) {
- if (y[i] > maximum) {
- y[i] = maximum;
- } else if (y[i] < minimum) {
- y[i] = minimum;
+ } else {
+ for (long i = imin; i <= imax; i ++) {
+ if (y[i] > maximum) {
+ y[i] = maximum;
+ } else if (y[i] < minimum) {
+ y[i] = minimum;
+ }
}
}
-
Graphics_setWindow (g, qmin, qmax, minimum, maximum);
Graphics_function (g, y.peek(), imin, imax, Matrix_columnToX (me, imin), Matrix_columnToX (me, imax));
@@ -103,11 +184,11 @@ void Cepstrum_drawLinear (Cepstrum me, Graphics g, double qmin, double qmax, dou
_Cepstrum_draw (me, g, qmin, qmax, minimum, maximum, 0, garnish);
}
-void Cepstrum_draw (Cepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish) {
+void PowerCepstrum_draw (PowerCepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish) {
_Cepstrum_draw (me, g, qmin, qmax, dBminimum, dBmaximum, 1, garnish);
}
-void Cepstrum_drawTiltLine (Cepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, double qstart, double qend, int method) {
+void PowerCepstrum_drawTiltLine (PowerCepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, double qstart, double qend, int lineType, int method) {
Graphics_setInner (g);
@@ -131,64 +212,307 @@ void Cepstrum_drawTiltLine (Cepstrum me, Graphics g, double qmin, double qmax, d
}
Graphics_setWindow (g, qmin, qmax, dBminimum, dBmaximum);
- qend = qend == 0 ? qmax : qend;
- qstart = qstart < qmin ? qmin : qstart;
- qend = qend > qmax ? qmax : qend;
+ qend = qend == 0 ? my xmax : qend;
+ if (qend <= qstart) {
+ qend = my xmax; qstart = my xmin;
+ }
+ qstart = qstart < my xmin ? my xmin : qstart;
+ qend = qend > my xmax ? my xmax : qend;
double a, intercept;
- Cepstrum_fitTiltLine (me, qstart, qend, &a, &intercept, method);
-
- double y1 = a * qstart + intercept, y2 = a * qend + intercept;
+ PowerCepstrum_fitTiltLine (me, qstart, qend, &a, &intercept, lineType, method);
+ /*
+ * Don't draw part outside window
+ */
double lineWidth = Graphics_inqLineWidth (g);
Graphics_setLineWidth (g, 2);
- Graphics_line (g, qstart, y1, qend, y2);
+ if (lineType == 2) {
+ long n = 500;
+ double dq = (qend - qstart) / (n + 1);
+ double q1 = qstart;
+ if (qstart <= 0) {
+ qstart = 0.1 * dq; // some small offset to avoid log(0)
+ n--;
+ }
+ autoNUMvector<double> y (1, n);
+
+ for (long i = 1; i <= n; i++) {
+ double q = q1 + (i - 1) * dq;
+ y[i] = a * log (q) + intercept;
+ }
+ Graphics_function (g, y.peek(), 1, n, qstart, qend);
+ } else {
+ double y1 = a * qstart + intercept, y2 = a * qend + intercept;
+ if (y1 >= dBminimum && y2 >= dBminimum) {
+ Graphics_line (g, qstart, y1, qend, y2);
+ } else if (y1 < dBminimum) {
+ qstart = (dBminimum - intercept) / a;
+ Graphics_line (g, qstart, dBminimum, qend, y2);
+ } else if (y2 < dBminimum) {
+ qend = (dBminimum - intercept) / a;
+ Graphics_line (g, qstart, y1, qend, dBminimum);
+ } else {
+ // don't draw anything below lower limit?
+ }
+ }
Graphics_setLineWidth (g, lineWidth);
Graphics_unsetInner (g);
}
-/* Fit line y = ax+b in [qmin,qmax] interval */
-void Cepstrum_fitTiltLine (Cepstrum me, double qmin, double qmax, double *a, double *intercept, int method) {
- if (qmax <= qmin) {
- qmin = my xmin; qmax = my xmax;
+/* Fit line y = ax+b (lineType ==1) or y = a log(x) + b (lineType == 2) on interval [qmin,qmax]
+ * method == 1 : Least squares fit
+ * method == 2 : Theil's partial robust fit
+ */
+void PowerCepstrum_fitTiltLine (PowerCepstrum me, double qmin, double qmax, double *a, double *intercept, int lineType, int method) {
+ try {
+ if (qmax <= qmin) {
+ qmin = my xmin; qmax = my xmax;
+ }
+
+ long imin, imax;
+ if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
+ return;
+ }
+ imin = (lineType == 2 && imin == 1) ? 2 : imin; // log(0) is undefined!
+ long numberOfPoints = imax - imin + 1;
+ if (numberOfPoints < 2) {
+ Melder_throw ("Not enough points for fit.");
+ }
+ autoNUMvector<double> y (1, numberOfPoints);
+ autoNUMvector<double> x (1, numberOfPoints);
+ for (long i = 1; i <= numberOfPoints; i++) {
+ long isamp = imin + i - 1;
+ x[i] = my x1 + (isamp - 1) * my dx;
+ if (lineType == 2) {
+ x[i] = log (x[i]);
+ }
+ y[i] = my v_getValueAtSample (isamp, 1, 0);
+ }
+ if (method == 3) { // try local maxima first
+ autoNUMvector<double> ym (1, numberOfPoints / 2 + 1);
+ autoNUMvector<double> xm (1, numberOfPoints / 2 + 1);
+ long numberOfLocalPeaks = 0;
+ // forget y[1] if y[2]<y[1] and y[n] if y[n-1]<y[n] !
+ for (long i = 2; i <= numberOfPoints; i++) {
+ if (y[i - 1] <= y[i] && y[i] > y[i + 1]) {
+ ym[++numberOfLocalPeaks] = y[i];
+ xm[numberOfLocalPeaks] = x[i];
+ }
+ }
+ if (numberOfLocalPeaks > numberOfPoints / 10) {
+ for (long i = 1; i <= numberOfLocalPeaks; i++) {
+ x[i] = xm[i]; y[i] = ym[i];
+ }
+ numberOfPoints = numberOfLocalPeaks;
+ }
+ method = 2; // robust fit of peaks
+ }
+ // fit a straight line through (x,y)'s
+ NUMlineFit (x.peek(), y.peek(), numberOfPoints, a, intercept, method);
+ } catch (MelderError) {
+ Melder_throw (me, ": couldn't fit a line.");
}
+}
- long imin, imax;
- if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
- return;
+// Hillenbrand subtracts dB values and if the result is negative it is made zero
+void PowerCepstrum_subtractTiltLine_inline (PowerCepstrum me, double slope, double intercept, int lineType) {
+ for (long j = 1; j <= my nx; j++) {
+ double q = my x1 + (j - 1) * my dx;
+ q = j == 1 ? 0.5 * my dx : q; // approximation
+ double xq = lineType == 2 ? log(q) : q;
+ double db_background = slope * xq + intercept;
+ double db_cepstrum = my v_getValueAtSample (j, 1, 0);
+ double diff = exp ((db_cepstrum - db_background) * NUMln10 / 10) - 1e-30;
+ my z[1][j] = diff;
+ }
+}
+
+
+void PowerCepstrum_subtractTilt_inline (PowerCepstrum me, double qstartFit, double qendFit, int lineType, int fitMethod) {
+ double slope, intercept;
+ PowerCepstrum_fitTiltLine (me, qstartFit, qendFit, &slope, &intercept, lineType, fitMethod);
+ PowerCepstrum_subtractTiltLine_inline (me, slope, intercept, lineType);
+}
+
+PowerCepstrum PowerCepstrum_subtractTilt (PowerCepstrum me, double qstartFit, double qendFit, int lineType, int fitMethod) {
+ try {
+ autoPowerCepstrum thee = Data_copy (me);
+ PowerCepstrum_subtractTilt_inline (thee.peek(), qstartFit, qendFit, lineType, fitMethod);
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": couldn't subtract tilt line.");
+ }
+}
+
+void PowerCepstrum_smooth_inline2 (PowerCepstrum me, double quefrencyAveragingWindow) {
+ try {
+ long numberOfQuefrencyBins = quefrencyAveragingWindow / my dx;
+ if (numberOfQuefrencyBins > 1) {
+ autoNUMvector<double> qin (1, my nx);
+ autoNUMvector<double> qout (1, my nx);
+ for (long iq = 1; iq <= my nx; iq++) {
+ qin[iq] = my z[1][iq];
+ }
+ NUMvector_smoothByMovingAverage (qin.peek(), my nx, numberOfQuefrencyBins, qout.peek());
+ for (long iq = 1; iq <= my nx; iq++) {
+ my z[1][iq] = qout[iq];
+ }
+ }
+ } catch (MelderError) {
+ Melder_throw (me, ": not smoothed.");
}
- long numberOfPoints = imax - imin + 1;
- autoNUMvector<double> y (1, numberOfPoints);
- autoNUMvector<double> x (1, numberOfPoints);
- for (long i = 1; i <= numberOfPoints; i++) {
- long isamp = imin + i - 1;
- x[i] = my x1 + (isamp - 1) * my dx;
- y[i] = my v_getValueAtSample (isamp, 1, 0);
+}
+
+void PowerCepstrum_smooth_inline (PowerCepstrum me, double quefrencyAveragingWindow, long numberOfIterations) {
+ try {
+ long numberOfQuefrencyBins = quefrencyAveragingWindow / my dx;
+ if (numberOfQuefrencyBins > 1) {
+ autoNUMvector<double> qin (1, my nx);
+ autoNUMvector<double> qout (1, my nx);
+ for (long iq = 1; iq <= my nx; iq++) {
+ qin[iq] = my z[1][iq];
+ }
+ double *xin, *xout;
+ for (long k = 1; k <= numberOfIterations; k++) {
+ xin = k % 2 == 1 ? qin.peek() : qout.peek ();
+ xout = k % 2 == 1 ? qout.peek () : qin.peek();
+ NUMvector_smoothByMovingAverage (xin, my nx, numberOfQuefrencyBins, xout);
+ }
+ for (long iq = 1; iq <= my nx; iq++) {
+ my z[1][iq] = xout[iq];
+ }
+ }
+ } catch (MelderError) {
+ Melder_throw (me, ": not smoothed.");
}
- // fit a line through (x,y)'s
- NUMlineFit(x.peek(), y.peek(), numberOfPoints, a, intercept, method);
}
+PowerCepstrum PowerCepstrum_smooth (PowerCepstrum me, double quefrencyAveragingWindow, long numberOfIterations) {
+ autoPowerCepstrum thee = Data_copy (me);
+ PowerCepstrum_smooth_inline (thee.peek(), quefrencyAveragingWindow, numberOfIterations);
+ return thee.transfer();
+}
-void Cepstrum_getMaximumAndQuefrency (Cepstrum me, double lowestQuefrency, double highestQuefrency, int interpolation, double *peakdB, double *quefrency) {
+void PowerCepstrum_getMaximumAndQuefrency (PowerCepstrum me, double pitchFloor, double pitchCeiling, int interpolation, double *peakdB, double *quefrency) {
*peakdB = *quefrency = NUMundefined;
- autoCepstrum thee = Data_copy (me);
+ autoPowerCepstrum thee = Data_copy (me);
+ double lowestQuefrency = 1 / pitchCeiling, highestQuefrency = 1 / pitchFloor;
for (long i = 1; i <= my nx; i++) {
thy z[1][i] = my v_getValueAtSample (i, 1, 0); // 10 log val^2
}
Vector_getMaximumAndX ((Vector) thee.peek(), lowestQuefrency, highestQuefrency, 1, interpolation, peakdB, quefrency);
}
-double Cepstrum_getPeakProminence (Cepstrum me, double search_lowestQuefrency, double search_highestQuefrency, int interpolation, double fit_lowestFrequency, double fit_highestFrequency, int fitmethod, double *qpeak) {
+static void Cepstrum_getZ2 (Cepstrum me, long imin, long imax, double peakdB, long margin, long keep, double *z) {
+ *z = NUMundefined;
+ long npeaks = 0, n = (imax - imin) / 2 + keep;
+ autoNUMvector<double> ymax (1, n);
+ autoNUMvector<long> index (1, n);
+ for (long i = imin + 1; i < imax; i++) {
+ if (my z[1][i] > my z[1][i-1] && my z[1][i] > my z[1][i+1]) {
+ ymax[++npeaks] = my z[1][i];
+ index[npeaks] = i;
+ }
+ }
+ NUMsort2<double, long> (npeaks, ymax.peek(), index.peek());
+ long i = npeaks - 1, ipeak = 0;
+ while (i > 0 && ipeak < keep) {
+ if (labs(index[i] - index[npeaks]) > margin) {
+ ipeak++;
+ ymax[npeaks +ipeak] = ymax[i];
+ }
+ i--;
+ }
+ double mean, variance;
+ NUMvector_avevar (&ymax[npeaks], ipeak, &mean, &variance);
+ double sigma = sqrt (variance / (ipeak - 1));
+ double peak = exp (peakdB * NUMln10 / 10) - 1e-30;
+ *z = sigma <= 0 ? NUMundefined : peak / sigma;
+}
+
+static void Cepstrum_getZ (Cepstrum me, long imin, long imax, double peakdB, double slope, double intercept, int lineType, double *z) {
+ long ndata = imax - imin + 1;
+ autoNUMvector<double> dabs (1, ndata);
+ for (long i = imin; i <= imax; i++) {
+ double q = my x1 + (i - 1) * my dx;
+ q = i == 1 ? 0.5 * my dx : q; // approximation
+ double xq = lineType == 2 ? log(q) : q;
+ double db_background = slope * xq + intercept;
+ double db_cepstrum = my v_getValueAtSample (i, 1, 0);
+ double diff = exp ((db_cepstrum - db_background) * NUMln10 / 10) - 1e-30;
+ //double diff = fabs (db_cepstrum - db_background);
+ dabs[i - imin + 1] = diff;
+ }
+ double q50 = NUMquantile (ndata, dabs.peek(), 0.5);
+ double peak = exp (peakdB * NUMln10 / 10) - 1e-30;
+ //*z = peakdB / q50;
+ *z = peak / q50;
+}
+
+double PowerCepstrum_getRNR (PowerCepstrum me, double pitchFloor, double pitchCeiling, double f0fractionalWidth) {
+ double rnr = NUMundefined;
+ double qmin = 1 / pitchCeiling, qmax = 1 / pitchFloor, peakdB, qpeak;
+ PowerCepstrum_getMaximumAndQuefrency (me, pitchFloor, pitchCeiling, 2, &peakdB, &qpeak);
+ long imin, imax;
+ if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) {
+ return rnr;
+ }
+ long ndata = imax - imin + 1;
+ if (ndata < 2) {
+ return rnr;
+ }
+ // how many peaks in interval ?
+ long npeaks = 2;
+ while (qpeak > 0 && qpeak * npeaks <= qmax) { npeaks++; }
+ npeaks--;
+
+ double sum = 0, sumr = 0;
+ for (long i = imin; i <= imax; i++) {
+ double val = my v_getValueAtSample (i, 0, 0);
+ double qx = my x1 + (i - 1) * my dx;
+ sum += val;
+ // is qx within an interval around a multiple of the peak's q ?
+ for (long j = 1; j <= npeaks; j++) {
+ double f0c = 1 / (j * qpeak);
+ double f0clow = f0c * (1 - f0fractionalWidth);
+ double f0chigh = f0c * (1 + f0fractionalWidth);
+ double qclow = 1 / f0chigh;
+ double qchigh = f0fractionalWidth >= 1 ? qmax : 1 / f0clow;
+ if (qx >= qclow && qx <= qchigh) { // yes in rhamonic interval
+ sumr += val; break;
+ }
+ }
+ }
+ rnr = sumr >= sum ? 1000000 : sumr / (sum - sumr);
+ return rnr;
+}
+
+double PowerCepstrum_getPeakProminence_hillenbrand (PowerCepstrum me, double pitchFloor, double pitchCeiling, double *qpeak) {
+ double slope, intercept, quefrency, peakdB;
+ PowerCepstrum_fitTiltLine (me, 0.001, 0, &slope, &intercept, 1, 1);
+ autoPowerCepstrum thee = Data_copy (me);
+ PowerCepstrum_subtractTiltLine_inline (thee.peek(), slope, intercept, 1);
+ PowerCepstrum_getMaximumAndQuefrency (thee.peek(), pitchFloor, pitchCeiling, 0, &peakdB, &quefrency);
+ if (qpeak) {
+ *qpeak = quefrency;
+ }
+ return peakdB;
+}
+
+double PowerCepstrum_getPeakProminence (PowerCepstrum me, double pitchFloor, double pitchCeiling, int interpolation, double qstartFit, double qendFit, int lineType, int fitMethod, double *qpeak) {
double slope, intercept, quefrency, peakdB;
- Cepstrum_fitTiltLine (me, fit_lowestFrequency, fit_highestFrequency, &slope, &intercept, fitmethod);
- Cepstrum_getMaximumAndQuefrency (me, search_lowestQuefrency, search_highestQuefrency, interpolation, &peakdB, &quefrency);
+ PowerCepstrum_fitTiltLine (me, qstartFit, qendFit, &slope, &intercept, lineType, fitMethod);
+ PowerCepstrum_getMaximumAndQuefrency (me, pitchFloor, pitchCeiling, interpolation, &peakdB, &quefrency);
+ double xq = lineType == 2 ? log(quefrency) : quefrency;
+ double db_background = slope * xq + intercept;
+ double cpp = peakdB - db_background;
if (qpeak != NULL) {
*qpeak = quefrency;
}
- return peakdB - slope * quefrency - intercept;
+ return cpp;
}
-Matrix Cepstrum_to_Matrix (Cepstrum me) {
+Matrix PowerCepstrum_to_Matrix (PowerCepstrum me) {
try {
autoMatrix thee = Thing_new (Matrix);
my structMatrix :: v_copy (thee.peek());
@@ -198,22 +522,43 @@ Matrix Cepstrum_to_Matrix (Cepstrum me) {
}
}
-Cepstrum Matrix_to_Cepstrum (Matrix me, long row) {
+PowerCepstrum Matrix_to_PowerCepstrum (Matrix me) {
try {
- autoCepstrum thee = Cepstrum_create (my xmin, my xmax, my nx);
- if (row < 0) {
- row = my ny + 1 - row;
+ if (my ny != 1)
+ Melder_throw ("Matrix must have exactly 1 row.");
+ autoPowerCepstrum thee = Thing_new (PowerCepstrum);
+ my structMatrix :: v_copy (thee.peek());
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": not converted to PowerCepstrum.");
+ }
+}
+
+PowerCepstrum Matrix_to_PowerCepstrum_row (Matrix me, long row) {
+ try {
+ autoPowerCepstrum thee = PowerCepstrum_create (my xmax, my nx);
+ if (row < 1 || row > my ny) {
+ Melder_throw ("Row number must be between 1 and ", my ny, " inclusive.");
}
- if (row < 1) {
- row = 1;
+ NUMvector_copyElements (my z[row], thy z[1], 1, my nx);
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": no PowerCepstrum created.");
+ }
+}
+
+PowerCepstrum Matrix_to_PowerCepstrum_column (Matrix me, long col) {
+ try {
+ autoPowerCepstrum thee = PowerCepstrum_create (my ymax, my ny);
+ if (col < 1 || col > my nx) {
+ Melder_throw ("Column number must be between 1 and ", my nx, " inclusive.");
}
- if (row > my ny) {
- row = my ny;
+ for (long i = 1; i <= my ny; i++) {
+ thy z[1][i] = my z[i][col];
}
- NUMvector_copyElements (my z[row], thy z[1], 1, my nx);
return thee.transfer();
} catch (MelderError) {
- Melder_throw (me, ": no Cepstrum created.");
+ Melder_throw (me, ": no PowerCepstrum created.");
}
}
diff --git a/LPC/Cepstrum.h b/LPC/Cepstrum.h
index a8c50ce..86e65e2 100644
--- a/LPC/Cepstrum.h
+++ b/LPC/Cepstrum.h
@@ -27,7 +27,7 @@
/*
The Cepstrum is a sequence of REAL numbers.
- It is the power spectrum of the power spectrum of a (sound) signal.
+ It is the spectrum of the power spectrum of a (sound) signal.
*/
#include "Matrix.h"
@@ -37,6 +37,18 @@ Thing_define (Cepstrum, Matrix) {
public:
virtual double v_getValueAtSample (long isamp, long which, int units);
};
+
+/*
+ The Cepstrum is a sequence of REAL numbers.
+ It is the power spectrum of the power spectrum of a (sound) signal.
+*/
+
+Thing_define (PowerCepstrum, Cepstrum) {
+ // overridden methods:
+ public:
+ virtual double v_getValueAtSample (long isamp, long which, int units);
+};
+
/*
xmin // Lowest quefrency.
xmax // Highest quefrency.
@@ -48,22 +60,22 @@ Thing_define (Cepstrum, Matrix) {
ny = 1
*/
-Cepstrum Cepstrum_create (double qmin, double qmax, long nq);
+Cepstrum Cepstrum_create (double qmax, long nq);
+PowerCepstrum PowerCepstrum_create (double qmax, long nq);
/* Preconditions:
- qmin < qmax;
nq >= 2;
Postconditions:
- my xmin = qmin; my ymin = 1;
+ my xmin = 0; my ymin = 1;
my xmax = qmax; my ymax = 1;
my nx = nq; my ny = 1;
- my dx = qmax / nx; my dy = 1;
- my x1 = my dx / 2; my y1 = 1;
+ my dx = qmax / (nq -1); my dy = 1;
+ my x1 = 0; my y1 = 1;
my z [1..ny] [1..nx] = 0.0;
*/
-void Cepstrum_draw (Cepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish);
+void PowerCepstrum_draw (PowerCepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, int garnish);
void Cepstrum_drawLinear (Cepstrum me, Graphics g, double qmin, double qmax, double minimum, double maximum, int garnish);
-void Cepstrum_drawTiltLine (Cepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, double qstart, double qend, int method);
+void PowerCepstrum_drawTiltLine (PowerCepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, double qstart, double qend, int lineType, int method);
/*
Function:
Draw a Cepstrum
@@ -76,11 +88,24 @@ void Cepstrum_drawTiltLine (Cepstrum me, Graphics g, double qmin, double qmax, d
[minimum, maximum]: amplitude; y range of drawing.
*/
-void Cepstrum_getMaximumAndQuefrency (Cepstrum me, double lowestQuefrency, double highestQuefrency, int interpolation, double *maximum, double *quefrency);
-double Cepstrum_getPeakProminence (Cepstrum me, double search_lowestQuefrency, double search_highestQuefrency, int interpolation, double fit_lowestFrequency, double fit_highestFrequency, int fitmethod, double *qpeak);
-void Cepstrum_fitTiltLine (Cepstrum me, double qmin, double qmax, double *a, double *intercept, int method);
+void PowerCepstrum_getMaximumAndQuefrency (PowerCepstrum me, double pitchFloor, double pitchCeiling, int interpolation, double *maximum, double *quefrency);
+
+// The standard of Hillenbrand with fitting options
+double PowerCepstrum_getPeakProminence_hillenbrand (PowerCepstrum me, double pitchFloor, double pitchCeiling, double *qpeak);
+
+double PowerCepstrum_getRNR (PowerCepstrum me, double pitchFloor, double pitchCeiling, double f0fractionalWidth);
+double PowerCepstrum_getPeakProminence (PowerCepstrum me, double pitchFloor, double pitchCeiling, int interpolation, double qstartFit, double qendFit, int lineType, int fitMethod, double *qpeak);
+void PowerCepstrum_fitTiltLine (PowerCepstrum me, double qmin, double qmax, double *slope, double *intercept, int lineType, int method);
+PowerCepstrum PowerCepstrum_subtractTilt (PowerCepstrum me, double qstartFit, double qendFit, int lineType, int fitMethod);
+void PowerCepstrum_subtractTilt_inline (PowerCepstrum me, double qstartFit, double qendFit, int lineType, int fitMethod);
+PowerCepstrum PowerCepstrum_subtractTilt (PowerCepstrum me, double qstartFit, double qendFit, int lineType, int fitMethod);
+void PowerCepstrum_smooth_inline (PowerCepstrum me, double quefrencyAveragingWindow, long numberOfIterations);
+PowerCepstrum PowerCepstrum_smooth (PowerCepstrum me, double quefrencyAveragingWindow, long numberOfIterations);
-Matrix Cepstrum_to_Matrix (Cepstrum me);
-Cepstrum Matrix_to_Cepstrum (Matrix me, long row);
+Matrix PowerCepstrum_to_Matrix (PowerCepstrum me);
+PowerCepstrum Matrix_to_PowerCepstrum (Matrix me);
+PowerCepstrum Matrix_to_PowerCepstrum_row (Matrix me, long row);
+PowerCepstrum Matrix_to_PowerCepstrum_column (Matrix me, long col);
+PowerCepstrum Cepstrum_downto_PowerCepstrum (Cepstrum me);
#endif /* _Cepstrum_h_ */
diff --git a/LPC/Cepstrum_and_Spectrum.cpp b/LPC/Cepstrum_and_Spectrum.cpp
index 057356e..f63bf94 100644
--- a/LPC/Cepstrum_and_Spectrum.cpp
+++ b/LPC/Cepstrum_and_Spectrum.cpp
@@ -46,7 +46,7 @@ Cepstrum Spectrum_to_Cepstrum_cmplx (Spectrum me) {
// Compute complex cepstrum x.
autoSound x = Spectrum_to_Sound (sx.peek());
- autoCepstrum thee = Cepstrum_create (0, x -> xmax - x -> xmin, x -> nx);
+ autoCepstrum thee = Cepstrum_create (x -> xmax - x -> xmin, x -> nx);
NUMvector_copyElements (x -> z[1], thy z[1], 1, x -> nx);
return thee.transfer();
} catch (MelderError) {
@@ -54,52 +54,122 @@ Cepstrum Spectrum_to_Cepstrum_cmplx (Spectrum me) {
}
}
+PowerCepstrum Spectrum_to_PowerCepstrum (Spectrum me) {
+ try {
+ autoSpectrum dBspectrum = Data_copy (me);
+ double *re = dBspectrum -> z[1], *im = dBspectrum -> z[2];
+ for (long i = 1; i <= dBspectrum -> nx; i ++) {
+ re[i] = log (re[i] * re[i] + im[i] * im[i] + 1e-300);
+ im[i] = 0.0;
+ }
+ autoSound cepstrum = Spectrum_to_Sound (dBspectrum.peek());
+ autoPowerCepstrum thee = PowerCepstrum_create (0.5 / my dx, my nx);
+ for (long i = 1; i <= thy nx; i++) {
+ double val = cepstrum -> z[1][i];
+ thy z[1][i] = val * val;
+ }
+ return thee.transfer ();
+ } catch (MelderError) {
+ Melder_throw (me, ": not converted to Sound.");
+ }
+}
+
Cepstrum Spectrum_to_Cepstrum (Spectrum me) {
try {
+ autoSpectrum dBspectrum = Data_copy (me);
+ double *re = dBspectrum -> z[1], *im = dBspectrum -> z[2];
+ for (long i = 1; i <= dBspectrum -> nx; i++) {
+ re[i] = log (re[i] * re[i] + im[i] * im[i] + 1e-300);
+ im[i] = 0.0;
+ }
+ autoSound cepstrum = Spectrum_to_Sound (dBspectrum.peek());
+ autoCepstrum thee = Cepstrum_create (0.5 / my dx, my nx);
+ for (long i = 1; i <= thy nx; i++) {
+ double val = cepstrum -> z[1][i];
+ thy z[1][i] = val;
+ }
+ return thee.transfer ();
+ } catch (MelderError) {
+ Melder_throw (me, ": not converted to Sound.");
+ }
+}
+
+Spectrum Cepstrum_to_Spectrum (Cepstrum me) { //TODO power cepstrum
+ try {
+ autoCepstrum cepstrum = Data_copy (me);
+ cepstrum -> z[1][1] = my z[1][1];
+ for (long i = 2; i <= cepstrum -> nx; i++) {
+ cepstrum -> z[1][i] = 2 * my z[1][i];
+ }
+ autoSpectrum thee = Sound_to_Spectrum ((Sound) cepstrum.peek(), 1);
+
+ double *re = thy z[1], *im = thy z[2];
+ for (long i = 1; i <= thy nx; i ++) {
+ re[i] = exp (0.5 * re[i]); // i.e., sqrt (exp(re [i]))
+ im[i] = 0.0;
+ }
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": no Spectrum created.");
+ }
+}
+
+Cepstrum Spectrum_to_Cepstrum2 (Spectrum me) {
+ try {
autoNUMfft_Table fftTable;
// originalNumberOfSamplesProbablyOdd irrelevant
if (my x1 != 0.0) {
Melder_throw ("A Fourier-transformable Spectrum must have a first frequency of 0 Hz, not ", my x1, L" Hz.");
}
long numberOfSamples = 2 * my nx - 2;
- autoCepstrum thee = Cepstrum_create (0, 0.5 / my dx, my nx);
+ autoCepstrum thee = Cepstrum_create (0.5 / my dx, my nx);
+ // my dx = 1 / (dT * N) = 1 / (duration of sound)
+ thy dx = 1 / (my dx * numberOfSamples); // Cepstrum is on [-T/2, T/2] !
NUMfft_Table_init (&fftTable, numberOfSamples);
- autoNUMvector<double> amp (1, numberOfSamples);
+ autoNUMvector<double> fftbuf (1, numberOfSamples);
- amp[1] = my v_getValueAtSample (1, 0, 2);
+ fftbuf[1] = my v_getValueAtSample (1, 0, 2);
for (long i = 2; i < my nx; i++) {
- amp [i + i - 2] = my v_getValueAtSample (i, 0, 2);
- amp [i + i - 1] = 0;
+ fftbuf [i + i - 2] = my v_getValueAtSample (i, 0, 2);
+ fftbuf [i + i - 1] = 0;
}
- amp [numberOfSamples] = my v_getValueAtSample (my nx, 0, 2);
- NUMfft_backward (&fftTable, amp.peek());
+ fftbuf [numberOfSamples] = my v_getValueAtSample (my nx, 0, 2);
+ NUMfft_backward (&fftTable, fftbuf.peek());
for (long i = 1; i <= my nx; i++) {
- thy z[1][i] = amp[i] / numberOfSamples; // scaling 1/n because ifft(fft(1))= n;
+ double val = fftbuf[i] / numberOfSamples; // scaling 1/n because ifft(fft(1))= n;
+ thy z[1][i] = val * val; // power cepstrum
}
return thee.transfer();
} catch (MelderError) {
- Melder_throw (me, ": not converted to Sound.");
+ Melder_throw (me, ": not converted to Cepstrum.");
}
}
-Spectrum Cepstrum_to_Spectrum (Cepstrum me) {
+
+Spectrum Cepstrum_to_Spectrum2 (Cepstrum me) { //TODO power cepstrum
try {
- autoSound tmp = Sound_create (1, my xmin, my xmax, my nx, my dx, my x1);
- NUMvector_copyElements (my z[1], tmp -> z[1], 1, my nx); // v_getValueAtSample ???
- autoSpectrum thee = Sound_to_Spectrum (tmp.peek(), TRUE);
+ autoNUMfft_Table fftTable;
+ long numberOfSamples = 2 * my nx - 2;
- double *x = thy z[1], *y = thy z[2];
- double scaling = tmp -> dx, forwardbackwardfactor = sqrt (my nx) * (2e-5 / sqrt (4 * thy dx)); // my nx because of ifft
- for (long i = 1; i <= thy nx; i++) {
- x[i] = sqrt (x[i] * x[i] + y [i] * y[i]) / scaling;
- y[i] = 0;
- // 10*log10(2*p*dx/r) = X; sqrt(x^2), r = 4e-10
- // p = 10^(X/10) * r/ (2*dx) * numberOfSamples
- // amp= sqrt (10^(X/10) * sqrt (r / (2 *dx)) = 10 ^(X/20) * 2e-5 / sqrt (2 * dx)
- double logval = x[i] / 20;
- double amp = pow (10, logval) * forwardbackwardfactor;
- x[i] = amp;
- y[i] = 0;
+ autoNUMvector<double> fftbuf (1, numberOfSamples);
+ autoSpectrum thee = Spectrum_create (0.5 / my dx, my nx);
+ fftbuf[1] = sqrt (my z[1][1]);
+ for (long i = 2; i <= my nx; i++) {
+ fftbuf[i] = 2 * sqrt (my z[1][i]);
+ }
+ // fftbuf[my nx+1 ... numberOfSamples] = 0
+ NUMfft_Table_init (&fftTable, numberOfSamples);
+ NUMfft_forward (&fftTable, fftbuf.peek());
+
+ thy z[1][1] = fabs (fftbuf[1]);
+ for (long i = 2; i < my nx; i++) {
+ double br = fftbuf[i + i - 2], bi = fftbuf[i + i - 1];
+ thy z[1][i] = sqrt (br * br + bi * bi);
+ }
+ thy z[1][my nx] = fabs (fftbuf[numberOfSamples]);
+ for (long i = 1; i <= my nx; i++) {
+ thy z[1][i] = exp (NUMln10 * thy z[1][i] / 20) * 2e-5 / sqrt (2 * thy dx);
+ thy z[2][i] = 0;
}
return thee.transfer();
} catch (MelderError) {
diff --git a/LPC/Cepstrum_and_Spectrum.h b/LPC/Cepstrum_and_Spectrum.h
index ca0dfee..17daeae 100644
--- a/LPC/Cepstrum_and_Spectrum.h
+++ b/LPC/Cepstrum_and_Spectrum.h
@@ -5,16 +5,7 @@
#include "Spectrum.h"
#include "Cepstrum.h"
-#ifdef __cplusplus
- extern "C" {
-#endif
-
Cepstrum Spectrum_to_Cepstrum (Spectrum me);
-
Spectrum Cepstrum_to_Spectrum (Cepstrum me);
-
-#ifdef __cplusplus
- }
-#endif
-
+PowerCepstrum Spectrum_to_PowerCepstrum (Spectrum me);
#endif /* _Cepstrum_and_Spectrum_h_ */
diff --git a/LPC/Makefile b/LPC/Makefile
index 666c9d6..928cc09 100644
--- a/LPC/Makefile
+++ b/LPC/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "LPC"
-# David Weenink, 20121214
+# David Weenink, 20130826
include ../makefile.defs
@@ -28,7 +28,7 @@ clean:
libLPC.a: $(OBJECTS)
touch libLPC.a
rm libLPC.a
- ar cq libLPC.a $(OBJECTS)
+ $(AR) cq libLPC.a $(OBJECTS)
$(RANLIB) libLPC.a
$(OBJECTS): *.h ../num/NUM.h ../dwtools/*.h ../fon/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h
diff --git a/LPC/Sound_and_Cepstrum.cpp b/LPC/Sound_and_Cepstrum.cpp
index ad4acf4..9535a23 100644
--- a/LPC/Sound_and_Cepstrum.cpp
+++ b/LPC/Sound_and_Cepstrum.cpp
@@ -42,7 +42,7 @@ Cepstrum Sound_to_Cepstrum_bw (Sound me) {
}
double qmax = (my xmax - my xmin) * nfft / my nx;
- autoCepstrum thee = Cepstrum_create (0, qmax, nfft);
+ autoCepstrum thee = Cepstrum_create (qmax, nfft);
autoNUMvector<double> x (1, nfft);
autoNUMvector<double> nx (1, nfft);
diff --git a/LPC/manual_LPC.cpp b/LPC/manual_LPC.cpp
index d213910..7e847f2 100644
--- a/LPC/manual_LPC.cpp
+++ b/LPC/manual_LPC.cpp
@@ -65,18 +65,18 @@ NORMAL (L"where %z__%ji_ is the matrix element in row %j and column %i and "
"%c__%ij_ is the %j-th cepstral coefficient in frame %i.")
MAN_END
-MAN_BEGIN (L"Cepstrogram", L"djmw", 20121118)
+MAN_BEGIN (L"PowerCepstrogram", L"djmw", 20130616)
INTRO (L"One of the @@types of objects@ in P\\s{RAAT}.")
ENTRY (L"Description")
-NORMAL (L"The Cepstrogram shows @@Cepstrum|cepstral slices@ as a function of time.")
+NORMAL (L"The PowerCepstrogram shows @@PowerCepstrum|cepstral slices@ as a function of time.")
MAN_END
-MAN_BEGIN (L"Cepstrogram: To Table (peak prominence...", L"djmw", 20121118)
-INTRO (L"A command to create a table with @@Cepstrum: Get peak prominence...|cepstral peak prominence@ values.")
+MAN_BEGIN (L"PowerCepstrogram: To Table (peak prominence)...", L"djmw", 20130616)
+INTRO (L"A command to create a table with @@PowerCepstrum: Get peak prominence...|cepstral peak prominence@ values.")
ENTRY (L"Settings")
SCRIPT (7, Manual_SETTINGS_WINDOW_HEIGHT (7), L""
- Manual_DRAW_SETTINGS_WINDOW ("Cepstrogram: To Table (peak prominence)", 7)
- Manual_DRAW_SETTINGS_WINDOW_RANGE("Peak search quefrency range (s)", L"0.003 (=333 Hz)", L"0.0125 (=80 Hz)")
+ Manual_DRAW_SETTINGS_WINDOW ("PowerCepstrogram: To Table (peak prominence)", 7)
+ Manual_DRAW_SETTINGS_WINDOW_RANGE("Peak search pitch range (Hz)", L"60.0", L"300.0")
Manual_DRAW_SETTINGS_WINDOW_RADIO (L"Interpolation", L"None", 0)
Manual_DRAW_SETTINGS_WINDOW_RADIO (L"", L"Parabolic", 0)
Manual_DRAW_SETTINGS_WINDOW_RADIO (L"", L"Cubic", 1)
@@ -84,11 +84,11 @@ SCRIPT (7, Manual_SETTINGS_WINDOW_HEIGHT (7), L""
Manual_DRAW_SETTINGS_WINDOW_RANGE("Tilt line quefrency range (s)",L"0.001", L"0.0 (=end)")
Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU(L"Fit method", L"Robust")
)
-NORMAL (L"The meaning of these settings is explained @@Cepstrum: Get peak prominence...|here at .")
+NORMAL (L"The meaning of these settings is explained @@PowerCepstrum: Get peak prominence...|here at .")
MAN_END
-MAN_BEGIN (L"Cepstrogram: Smooth...", L"djmw", 20130410)
-INTRO (L"Smoothes the selected @Cepstrogram by averaging cepstra. The smoothed Cepstrogram is the result of two separate steps. "
+MAN_BEGIN (L"PowerCepstrogram: Smooth...", L"djmw", 20130410)
+INTRO (L"Smoothes the selected @PowerCepstrogram by averaging cepstra. The smoothed PowerCepstrogram is the result of two separate steps. "
"In the first step, cepsta are averaged across time. In the second step, cepstra are averaged across quefrency.")
ENTRY (L"Settings")
TAG (L"##Time averaging window (s)")
@@ -106,26 +106,32 @@ DEFINITION (L"determines how many quefrency bins will be used for the averaging
ENTRY (L"Note")
NORMAL (L"The following commands should reproduce the smoothing described in the @@Hillenbrand & Houde (1996)@ article, where they use a 20 ms "
"(10 frame) time smoothing and a 1 ms (10 bin) quefrency smoothing. ")
-CODE (L"select Sound xxx")
-CODE (L"do (\"To Cepstrogram...\", 0.041, 0.002, 5000.0)")
+CODE (L"selectObject (\"Sound xxx\")")
+CODE (L"do (\"To PowerCepstrogram...\", 0.041, 0.002, 5000.0)")
CODE (L"do (\"Smooth...\", 0.02, 0.001)")
MAN_END
-MAN_BEGIN (L"Cepstrum", L"djmw", 20130227)
+MAN_BEGIN (L"Cepstrum", L"djmw", 20130616)
INTRO (L"One of the @@types of objects@ in P\\s{RAAT}.")
ENTRY (L"Description")
-NORMAL (L"A Cepstrum is the log power spectrum of the log power spectrum. The vertical scale will show the amplitude expressed in dB. The horizontal scale shows %%quefrency% in units of seconds.")
+NORMAL (L"A Cepstrum is the log spectrum of the log power spectrum.")
MAN_END
-MAN_BEGIN (L"Cepstrum: Get peak prominence...", L"djmw", 20121203)
+MAN_BEGIN (L"PowerCepstrum", L"djmw", 20130616)
+INTRO (L"One of the @@types of objects@ in P\\s{RAAT}.")
+ENTRY (L"Description")
+NORMAL (L"A PowerCepstrum is the log power spectrum of the log power spectrum. The vertical scale will show the amplitude expressed in dB. The horizontal scale shows %%quefrency% in units of seconds.")
+MAN_END
+
+MAN_BEGIN (L"PowerCepstrum: Get peak prominence...", L"djmw", 20130616)
INTRO (L"Calculates the cepstral peak prominence measure (CPP) as defined by @@Hillenbrand et al. (1994)@")
NORMAL (L"The CPP measure is the difference in amplitude between the cepstral peak and the corresponding value on the regression "
"line that is directly below the peak (i.e., the predicted magnitude for the quefrency at the cepstral peak). "
"The CPP measure represents how far the cepstral peak emerges from the cepstrum background. ")
ENTRY (L"Settings")
SCRIPT (7, Manual_SETTINGS_WINDOW_HEIGHT (7), L""
- Manual_DRAW_SETTINGS_WINDOW (L"Cepstrum: Get peak prominence", 7)
- Manual_DRAW_SETTINGS_WINDOW_RANGE("Peak search quefrency range (s)",L"0.003 (=333 Hz)", L"0.0125 (=80 Hz)")
+ Manual_DRAW_SETTINGS_WINDOW (L"PowerCepstrum: Get peak prominence", 7)
+ Manual_DRAW_SETTINGS_WINDOW_RANGE("Search peak in pitch range (s)", L"60.0", L"333.3")
Manual_DRAW_SETTINGS_WINDOW_RADIO (L"Interpolation", L"None", 0)
Manual_DRAW_SETTINGS_WINDOW_RADIO (L"", L"Parabolic", 0)
Manual_DRAW_SETTINGS_WINDOW_RADIO (L"", L"Cubic", 1)
@@ -133,10 +139,10 @@ SCRIPT (7, Manual_SETTINGS_WINDOW_HEIGHT (7), L""
Manual_DRAW_SETTINGS_WINDOW_RANGE (L"Tilt line quefrency range (s)", L"0.001", L"0.0 (=end)")
Manual_DRAW_SETTINGS_WINDOW_OPTIONMENU (L"Fit method", L"Robust")
)
-TAG (L"##Peak search quefrency range")
-DEFINITION (L"limits the quefrency range where a peak is searched for. The value of the lower limit is in general more critical than "
- "the value of the upper quefrency. The lower peak search quefrency should be chosen at least 0.001 s as we don't want to find the peaks at the very start of the quefrency range. This lower quefrency corresponds to the inverse of the %%highest% fundamental frequency value "
- "that we are interested in. I.e. a value of 0.003 s corresponds to an inverse frequecy value of 1/0.003\\~~333 Hz.")
+TAG (L"##Search peak in pitch range")
+DEFINITION (L"determine the limits of the quefrency range where a peak is searched for. The lower quefrency is determined as "
+ "1 / %%pitchCeiling% and this value is in general more critical than "
+ "the value of the upper quefrency which equals 1 / %%pitchFloor%. A %%pitchCeiling% of 300 Hz will correspond to a lower quefrency of 1/300\\~~0.0033 seconds.")
TAG (L"##Interpolation")
DEFINITION (L"determines how the @@vector peak interpolation|amplitude of a peak is determined at .")
TAG (L"##Tilt line quefrency range")
@@ -150,8 +156,8 @@ ENTRY (L"Note")
NORMAL (L"The CPP value does not depend on the reference value used in the dB calculation of the power cepstrum.")
MAN_END
-MAN_BEGIN (L"Cepstrum: Draw tilt line...", L"djmw", 20121116)
-INTRO (L"Draws the straight line that models the backgound of the power cepstrum.")
+MAN_BEGIN (L"PowerCepstrum: Draw tilt line...", L"djmw", 20130616)
+INTRO (L"Draws the line that models the backgound of the power cepstrum.")
MAN_END
MAN_BEGIN (L"Formant & Spectrogram: To IntensityTier...", L"djmw", 20130109)
@@ -435,10 +441,11 @@ NORMAL (L"where %N represents the number of filters, %j runs from 1 to %N, and c
"%%fromCoefficient% and %k larger than %%toCoefficient% take zero values in the evaluation.")
MAN_END
-MAN_BEGIN (L"Sound: To Cepstrogram...", L"djmw", 20130227)
-INTRO (L"A command that creates a @@Cepstrogram@ from every selected @@Sound at .")
+MAN_BEGIN (L"Sound: To PowerCepstrogram...", L"djmw", 20130616)
+INTRO (L"A command that creates a @@PowerCepstrogram@ from every selected @@Sound at .")
ENTRY (L"Settings")
-TAG (L"##Window length (s)")
+TAG (L"##Pitch floor (Hz)")
+DEFINITION (L"determines the effective length of the analysis window: it will be 3 longest periods long, i.e. if the pitch floor is 60 Hz, the window will be 3/60 = 0.05 seconds long.")
TAG (L"##Time step (s)")
TAG (L"##Maximum frequency (Hz)")
TAG (L"##Pre-emphasis from (Hz)")
@@ -551,7 +558,7 @@ MAN_BEGIN (L"VocalTractTier", L"djmw", 20120423)
INTRO (L"One of the @@types of objects@ in Praat. A VocalTractTier objects contains a number of (%time, %VocalTract) points, where a @@VocalTract@ represents the area function of the vocal tract expressed as m^^2^, running from the glottis to the lips.")
MAN_END
-MAN_BEGIN (L"theil regression", L"djmw", 20121118)
+MAN_BEGIN (L"theil regression", L"djmw", 20130710)
NORMAL (L"a robust linear regression method, first proposed by @@Theil (1950)@. The slope of the regression line is estimated as "
"the median of all pairwise slopes between each pair of points in the data set. Because this number of pairs increases quadratically "
"with the number of data points, we have implemented a somewhat less computationally intensive procedure, the %%incomplete% theil regression. In the incomplete method we first split the data set of %N data points (%x__%i_, %y__%i_), %i = 1..%N, in two equal sets "
@@ -559,6 +566,7 @@ NORMAL (L"a robust linear regression method, first proposed by @@Theil (1950)@.
FORMULA (L"%m__%i_ = (%y__%N/2+%i_ - %y__%i_) / (%x__%N/2+%i_ - %x__%i_), for %i = 1..%N/2.")
NORMAL (L"The regression slope %m is calculated as the median of these %N/2 values %m__%i_.")
NORMAL (L"Given the slope %m, the offset %b is calculated as the median of the %N values %b__%i_= %y__%i_ - %m\\.c%x__%i_.")
+NORMAL (L"The theil regression has a breakdown point of 29.3\\% , which means that it can tolerate arbitrary corruption of up to 29.3% of the input data-points without degradation of its accuracy")
MAN_END
MAN_BEGIN (L"Anderson (1978)", L"djmw", 20030701)
diff --git a/LPC/praat_LPC_init.cpp b/LPC/praat_LPC_init.cpp
index f85f75c..11de9d7 100644
--- a/LPC/praat_LPC_init.cpp
+++ b/LPC/praat_LPC_init.cpp
@@ -45,6 +45,7 @@
#include "LPC_and_Tube.h"
#include "LPC_to_Spectrogram.h"
#include "LPC_to_Spectrum.h"
+#include "NUM2.h"
#include "MelFilter_and_MFCC.h"
#include "Sound_and_LPC.h"
#include "Sound_and_LPC_robust.h"
@@ -60,13 +61,21 @@ static const wchar_t *QUERY_BUTTON = L"Query -";
void praat_CC_init (ClassInfo klas);
void praat_TimeFrameSampled_query_init (ClassInfo klas);
+void praat_TimeFunction_modify_init (ClassInfo klas);
int praat_Fon_formula (UiForm dia, Interpreter interpreter);
/********************** Cepstrum ****************************************/
+DIRECT (Cepstrum_downto_PowerCepstrum)
+ LOOP {
+ iam (Cepstrum);
+ autoPowerCepstrum thee = Cepstrum_downto_PowerCepstrum (me);
+ praat_new (thee.transfer(), my name);
+ }
+END
-DIRECT (Cepstrum_help)
- Melder_help (L"Cepstrum");
+DIRECT (PowerCepstrum_help)
+ Melder_help (L"PowerCepstrum");
END
FORM (Cepstrum_drawLinear, L"Cepstrum: Draw linear", L"Cepstrum: Draw (linear)...")
@@ -74,7 +83,7 @@ FORM (Cepstrum_drawLinear, L"Cepstrum: Draw linear", L"Cepstrum: Draw (linear)..
REAL (L"right Quefrency range (s)", L"0.0")
REAL (L"Minimum", L"0.0")
REAL (L"Maximum", L"0.0")
- BOOLEAN (L"Garnish", 0)
+ BOOLEAN (L"Garnish", 1)
OK
DO
autoPraatPicture picture;
@@ -85,7 +94,7 @@ DO
}
END
-FORM (Cepstrum_draw, L"Cepstrum: Draw", L"Cepstrum: Draw...")
+FORM (PowerCepstrum_draw, L"PowerCepstrum: Draw", L"PowerCepstrum: Draw...")
REAL (L"left Quefrency range (s)", L"0.0")
REAL (L"right Quefrency range (s)", L"0.0")
REAL (L"Minimum (dB)", L"0.0")
@@ -95,13 +104,13 @@ FORM (Cepstrum_draw, L"Cepstrum: Draw", L"Cepstrum: Draw...")
DO
autoPraatPicture picture;
LOOP {
- iam (Cepstrum);
- Cepstrum_draw (me, GRAPHICS, GET_REAL (L"left Quefrency range"), GET_REAL (L"right Quefrency range"),
+ iam (PowerCepstrum);
+ PowerCepstrum_draw (me, GRAPHICS, GET_REAL (L"left Quefrency range"), GET_REAL (L"right Quefrency range"),
GET_REAL (L"Minimum"), GET_REAL (L"Maximum"), GET_INTEGER (L"Garnish"));
}
END
-FORM (Cepstrum_drawTiltLine, L"Cepstrum: Draw tilt line", L"Cepstrum: Draw tilt line...")
+FORM (PowerCepstrum_drawTiltLine, L"PowerCepstrum: Draw tilt line", L"PowerCepstrum: Draw tilt line...")
REAL (L"left Quefrency range (s)", L"0.0")
REAL (L"right Quefrency range (s)", L"0.0")
REAL (L"left Amplitude range (dB)", L"0.0")
@@ -109,6 +118,9 @@ FORM (Cepstrum_drawTiltLine, L"Cepstrum: Draw tilt line", L"Cepstrum: Draw tilt
LABEL (L"", L"Parameters for the tilt line fit")
REAL (L"left Tilt line quefrency range (s)", L"0.001")
REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 1)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
OPTIONMENU (L"Fit method", 2)
OPTION (L"Least squares")
OPTION (L"Robust")
@@ -116,14 +128,15 @@ FORM (Cepstrum_drawTiltLine, L"Cepstrum: Draw tilt line", L"Cepstrum: Draw tilt
DO
autoPraatPicture picture;
LOOP {
- iam (Cepstrum);
- Cepstrum_drawTiltLine (me, GRAPHICS, GET_REAL (L"left Quefrency range"), GET_REAL (L"right Quefrency range"),
+ iam (PowerCepstrum);
+ PowerCepstrum_drawTiltLine (me, GRAPHICS, GET_REAL (L"left Quefrency range"), GET_REAL (L"right Quefrency range"),
GET_REAL (L"left Amplitude range"), GET_REAL (L"right Amplitude range"),
- GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"), GET_INTEGER (L"Fit method"));
+ GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"),
+ GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
}
END
-FORM (Cepstrum_formula, L"Cepstrum: Formula...", L"Cepstrum: Formula...")
+FORM (PowerCepstrum_formula, L"PowerCepstrum: Formula...", L"PowerCepstrum: Formula...")
LABEL (L"label", L"y := y1; for row := 1 to nrow do { x := x1; "
"for col := 1 to ncol do { self [row, col] := `formula' ; x := x + dx } y := y + dy }")
TEXTFIELD (L"formula", L"self")
@@ -132,10 +145,10 @@ DO
praat_Fon_formula (dia, interpreter);
END
-FORM (Cepstrum_getPeak, L"Cepstrum: Get peak", 0)
- REAL (L"left Peak search quefrency range (s)", L"0.003 (=330 Hz)")
- REAL (L"right Peak search quefrency range (s)", L"0.0167 (=60 Hz)")
- RADIO (L"Interpolation", 3)
+FORM (PowerCepstrum_getPeak, L"PowerCepstrum: Get peak", 0)
+ REAL (L"left Search peak in pitch range (Hz)", L"60.0")
+ REAL (L"right Search peak in pitch range (Hz)", L"333.3")
+ RADIO (L"Interpolation", 2)
RADIOBUTTON (L"None")
RADIOBUTTON (L"Parabolic")
RADIOBUTTON (L"Cubic")
@@ -143,17 +156,17 @@ FORM (Cepstrum_getPeak, L"Cepstrum: Get peak", 0)
OK
DO
LOOP {
- iam (Cepstrum);
+ iam (PowerCepstrum);
double peakdB, quefrency;
- Cepstrum_getMaximumAndQuefrency (me, GET_REAL (L"left Peak search quefrency range"), GET_REAL (L"right Peak search quefrency range"), GET_INTEGER (L"Interpolation") - 1, &peakdB, &quefrency);
- Melder_informationReal (peakdB, NULL);
+ PowerCepstrum_getMaximumAndQuefrency (me, GET_REAL (L"left Search peak in pitch range"), GET_REAL (L"right Search peak in pitch range"), GET_INTEGER (L"Interpolation") - 1, &peakdB, &quefrency);
+ Melder_informationReal (peakdB, L" dB");
}
END
-FORM (Cepstrum_getQuefrencyOfPeak, L"Cepstrum: Get quefrency of peak", 0)
- REAL (L"left Peak search quefrency range (s)", L"0.003 (=330 Hz)")
- REAL (L"right Peak search quefrency range (s)", L"0.0167 (=60 Hz)")
- RADIO (L"Interpolation", 3)
+FORM (PowerCepstrum_getQuefrencyOfPeak, L"PowerCepstrum: Get quefrency of peak", 0)
+ REAL (L"left Search peak in pitch range (Hz)", L"60.0")
+ REAL (L"right Search peak in pitch range (Hz)", L"333.3")
+ RADIO (L"Interpolation", 2)
RADIOBUTTON (L"None")
RADIOBUTTON (L"Parabolic")
RADIOBUTTON (L"Cubic")
@@ -161,39 +174,171 @@ FORM (Cepstrum_getQuefrencyOfPeak, L"Cepstrum: Get quefrency of peak", 0)
OK
DO
LOOP {
- iam (Cepstrum);
+ iam (PowerCepstrum);
double peakdB, quefrency;
- Cepstrum_getMaximumAndQuefrency (me, GET_REAL (L"left Peak search quefrency range"), GET_REAL (L"right Peak search quefrency range"), GET_INTEGER (L"Interpolation") - 1, &peakdB, &quefrency);
+ PowerCepstrum_getMaximumAndQuefrency (me, GET_REAL (L"left Search peak in pitch range"), GET_REAL (L"right Search peak in pitch range"), GET_INTEGER (L"Interpolation") - 1, &peakdB, &quefrency);
double f = 1 / quefrency;
Melder_information (Melder_double (quefrency), L" s (f =", Melder_double (f), L" Hz)");
}
END
-FORM (Cepstrum_getPeakProminence, L"Cepstrum: Get peak prominence", L"Cepstrum: Get peak prominence...")
- REAL (L"left Peak search quefrency range (s)", L"0.003 (=330 Hz)")
- REAL (L"right Peak search quefrency range (s)", L"0.0167 (=60 Hz)")
- RADIO (L"Interpolation", 3)
+FORM (PowerCepstrum_getRNR, L"PowerCepstrum: Get rhamonics to noise ration", 0)
+ REAL (L"left Pitch range (Hz)", L"60.0")
+ REAL (L"right Pitch range (Hz)", L"333.3")
+ POSITIVE (L"Fractional width (0-1)", L"0.05")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ double rnr = PowerCepstrum_getRNR (me, GET_REAL (L"left Pitch range"), GET_REAL (L"right Pitch range"), GET_REAL (L"Fractional width"));
+ Melder_information (Melder_double (rnr), L" (rnr)");
+ }
+END
+
+FORM (PowerCepstrum_getPeakProminence_hillenbrand, L"PowerCepstrum: Get peak prominence (hillenbrand)", L"PowerCepstrum: Get peak prominence (hillenbrand)...")
+ REAL (L"left Search peak in pitch range (Hz)", L"60.0")
+ REAL (L"right Search peak in pitch range (Hz)", L"333.3")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ double qpeak, cpp = PowerCepstrum_getPeakProminence_hillenbrand (me,
+ GET_REAL (L"left Search peak in pitch range"), GET_REAL (L"right Search peak in pitch range"), &qpeak);
+ Melder_information (Melder_double (cpp), L" dB; quefrency=", Melder_double (qpeak), L" s (f=",
+ Melder_double (1 / qpeak), L" Hz).");
+ }
+END
+
+FORM (PowerCepstrum_getTiltLineSlope, L"PowerCepstrum: Get tilt line slope", 0)
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 1)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ double a, intercept;
+ int lineType = GET_INTEGER (L"Line type");
+ PowerCepstrum_fitTiltLine (me, GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"),
+ &a, &intercept, lineType, GET_INTEGER (L"Fit method"));
+ Melder_information (Melder_double (a), L" dB / ", lineType == 1 ? L"s" : L"ln (s)");
+ }
+END
+
+
+FORM (PowerCepstrum_getTiltLineIntercept, L"PowerCepstrum: Get tilt line intercept", 0)
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 1)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ double a, intercept;
+ int lineType = GET_INTEGER (L"Line type");
+ PowerCepstrum_fitTiltLine (me, GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"),
+ &a, &intercept, lineType, GET_INTEGER (L"Fit method"));
+ Melder_information (Melder_double (intercept), L" dB");
+ }
+END
+
+FORM (PowerCepstrum_getPeakProminence, L"PowerCepstrum: Get peak prominence", L"PowerCepstrum: Get peak prominence...")
+ REAL (L"left Search peak in pitch range (Hz)", L"60.0")
+ REAL (L"right Search peak in pitch range (Hz)", L"333.3")
+ RADIO (L"Interpolation", 2)
RADIOBUTTON (L"None")
RADIOBUTTON (L"Parabolic")
RADIOBUTTON (L"Cubic")
RADIOBUTTON (L"Sinc70")
REAL (L"left Tilt line quefrency range (s)", L"0.001")
REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 1)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
OPTIONMENU (L"Fit method", 2)
OPTION (L"Least squares")
OPTION (L"Robust")
OK
DO
LOOP {
- iam (Cepstrum);
- double qpeak, cpp = Cepstrum_getPeakProminence (me,
- GET_REAL (L"left Peak search quefrency range"), GET_REAL (L"right Peak search quefrency range"),
+ iam (PowerCepstrum);
+ double qpeak, cpp = PowerCepstrum_getPeakProminence (me,
+ GET_REAL (L"left Search peak in pitch range"), GET_REAL (L"right Search peak in pitch range"),
GET_INTEGER (L"Interpolation") - 1,
GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"),
- GET_INTEGER (L"Fit method"), &qpeak);
- double f = 1 / qpeak;
- Melder_information (Melder_double (cpp), L" dB, at position ", Melder_double (qpeak), L" s (f =",
- Melder_double (f), L" Hz)");
+ GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"), &qpeak);
+ Melder_information (Melder_double (cpp), L" dB; quefrency=", Melder_double (qpeak), L" s (f=",
+ Melder_double (1 / qpeak), L" Hz).");
+ }
+END
+
+FORM (PowerCepstrum_subtractTilt_inline, L"PowerCepstrum: Subtract tilt (in-line)", 0)
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 1)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ PowerCepstrum_subtractTilt_inline (me, GET_REAL (L"left Tilt line quefrency range"),
+ GET_REAL (L"right Tilt line quefrency range"), GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
+ }
+END
+
+FORM (PowerCepstrum_smooth_inline, L"PowerCepstrum: Smooth (in-line)", 0)
+ REAL (L"Quefrency averaging window (s)", L"0.0005")
+ NATURAL (L"Number of iterations", L"1");
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ PowerCepstrum_smooth_inline (me, GET_REAL (L"Quefrency averaging window"), GET_INTEGER (L"Number of iterations"));
+ }
+END
+
+FORM (PowerCepstrum_smooth, L"PowerCepstrum: Smooth", 0)
+ REAL (L"Quefrency averaging window (s)", L"0.0005")
+ NATURAL (L"Number of iterations", L"1");
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ autoPowerCepstrum thee = PowerCepstrum_smooth (me, GET_REAL (L"Quefrency averaging window"), GET_INTEGER (L"Number of iterations"));
+ praat_new (thee.transfer(), my name, L"_smooth");
+ }
+END
+
+FORM (PowerCepstrum_subtractTilt, L"PowerCepstrum: Subtract tilt", 0)
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 1)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrum);
+ autoPowerCepstrum thee = PowerCepstrum_subtractTilt (me, GET_REAL (L"left Tilt line quefrency range"),
+ GET_REAL (L"right Tilt line quefrency range"), GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
+ praat_new (thee.transfer(), my name, L"minusTilt");
}
END
@@ -204,21 +349,21 @@ DIRECT (Cepstrum_to_Spectrum)
}
END
-DIRECT (Cepstrum_to_Matrix)
+DIRECT (PowerCepstrum_to_Matrix)
LOOP {
- iam (Cepstrum);
- praat_new (Cepstrum_to_Matrix (me), my name);
+ iam (PowerCepstrum);
+ praat_new (PowerCepstrum_to_Matrix (me), my name);
}
END
/********************** Cepstrogram ****************************************/
-DIRECT (Cepstrogram_help)
- Melder_help (L"Cepstrogram");
+DIRECT (PowerCepstrogram_help)
+ Melder_help (L"PowerCepstrogram");
END
-FORM (Cepstrogram_paint, L"Cepstrogram: Paint", 0)
+FORM (PowerCepstrogram_paint, L"PowerCepstrogram: Paint", 0)
REAL (L"left Time range (s)", L"0.0")
REAL (L"right Time range (s)", L"0.0")
REAL (L"left Quefrency range (s)", L"0.0")
@@ -230,67 +375,225 @@ FORM (Cepstrogram_paint, L"Cepstrogram: Paint", 0)
DO
autoPraatPicture picture;
LOOP {
- iam (Cepstrogram);
- Cepstrogram_paint (me, GRAPHICS, GET_REAL (L"left Time range"), GET_REAL (L"right Time range"),
+ iam (PowerCepstrogram);
+ PowerCepstrogram_paint (me, GRAPHICS, GET_REAL (L"left Time range"), GET_REAL (L"right Time range"),
GET_REAL (L"left Quefrency range"), GET_REAL (L"right Quefrency range"),
GET_REAL (L"Minimum"), GET_REAL (L"Maximum"), GET_INTEGER (L"Garnish"));
}
END
-FORM (Cepstrogram_smooth, L"Cepstrogram: Smooth", L"Cepstrogram: Smooth...")
- REAL (L"Time averaging window (s)", L"0.01")
+FORM (PowerCepstrogram_smooth, L"PowerCepstrogram: Smooth", L"PowerCepstrogram: Smooth...")
+ REAL (L"Time averaging window (s)", L"0.02")
REAL (L"Quefrency averaging window (s)", L"0.0005")
OK
DO
LOOP {
- iam (Cepstrogram);
- autoCepstrogram thee = Cepstrogram_smooth (me, GET_REAL (L"Time averaging window"), GET_REAL (L"Quefrency averaging window"));
+ iam (PowerCepstrogram);
+ autoPowerCepstrogram thee = PowerCepstrogram_smooth (me, GET_REAL (L"Time averaging window"), GET_REAL (L"Quefrency averaging window"));
praat_new (thee.transfer(), my name, L"_smoothed");
}
END
+DIRECT (PowerCepstrogram_getStartQuefrency)
+ LOOP {
+ iam (PowerCepstrogram);
+ Melder_informationReal (my ymin, L" (s)");
+ }
+END
+
+DIRECT (PowerCepstrogram_getEndQuefrency)
+ LOOP {
+ iam (PowerCepstrogram);
+ Melder_informationReal (my ymax, L" (s)");
+ }
+END
+
+DIRECT (PowerCepstrogram_getNumberOfQuefrencyBins)
+ LOOP {
+ iam (PowerCepstrogram);
+ Melder_informationReal (my ny, L" quefrency bins");
+ }
+END
+
+DIRECT (PowerCepstrogram_getQuefrencyStep)
+ LOOP {
+ iam (PowerCepstrogram);
+ Melder_informationReal (my dy, L" quefrency step (s)");
+ }
+END
-FORM (Cepstrogram_to_Cepstrum_slice, L"", 0)
+FORM (PowerCepstrogram_subtractTilt, L"PowerCepstrogram: Subtract tilt", 0)
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 2)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrogram);
+ autoPowerCepstrogram thee = PowerCepstrogram_subtractTilt (me, GET_REAL (L"left Tilt line quefrency range"),
+ GET_REAL (L"right Tilt line quefrency range"), GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
+ praat_new (thee.transfer(), my name, L"_minusTilt");
+ }
+END
+
+FORM (PowerCepstrogram_subtractTilt_inline, L"PowerCepstrogram: Subtract tilt (in-line)", 0)
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 2)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrogram);
+ PowerCepstrogram_subtractTilt_inline (me, GET_REAL (L"left Tilt line quefrency range"),
+ GET_REAL (L"right Tilt line quefrency range"), GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
+ }
+END
+
+FORM (PowerCepstrogram_getCPPS_hillenbrand, L"PowerCepstrogram: Get CPPS", 0)
+ LABEL (L"", L"Smoothing:")
+ BOOLEAN (L"Subtract tilt before smoothing", 1)
+ REAL (L"Time averaging window (s)", L"0.001")
+ REAL (L"Quefrency averaging window (s)", L"0.00005")
+ LABEL (L"", L"Peak search:")
+ REAL (L"left Peak search pitch range (Hz)", L"60.0")
+ REAL (L"right Peak search pitch range (Hz)", L"330.0")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrogram);
+ double cpps = PowerCepstrogram_getCPPS_hillenbrand (me, GET_INTEGER (L"Subtract tilt before smoothing"), GET_REAL (L"Time averaging window"), GET_REAL (L"Quefrency averaging window"),
+ GET_REAL (L"left Peak search pitch range"), GET_REAL (L"right Peak search pitch range"));
+ Melder_informationReal (cpps, L" dB");
+ }
+END
+
+
+FORM (PowerCepstrogram_getCPPS, L"PowerCepstrogram: Get CPPS", 0)
+ LABEL (L"", L"Smoothing:")
+ BOOLEAN (L"Subtract tilt before smoothing", 1)
+ REAL (L"Time averaging window (s)", L"0.001")
+ REAL (L"Quefrency averaging window (s)", L"0.00005")
+ LABEL (L"", L"Peak search:")
+ REAL (L"left Peak search pitch range (Hz)", L"60.0")
+ REAL (L"right Peak search pitch range (Hz)", L"330.0")
+ POSITIVE (L"Tolerance (0-1)", L"0.05")
+ RADIO (L"Interpolation", 2)
+ RADIOBUTTON (L"None")
+ RADIOBUTTON (L"Parabolic")
+ RADIOBUTTON (L"Cubic")
+ RADIOBUTTON (L"Sinc70")
+ LABEL (L"", L"Tilt line:")
+ REAL (L"left Tilt line quefrency range (s)", L"0.001")
+ REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 2)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
+ OPTIONMENU (L"Fit method", 2)
+ OPTION (L"Least squares")
+ OPTION (L"Robust")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrogram);
+ double cpps = PowerCepstrogram_getCPPS (me, GET_INTEGER (L"Subtract tilt before smoothing"), GET_REAL (L"Time averaging window"),
+ GET_REAL (L"Quefrency averaging window"),
+ GET_REAL (L"left Peak search pitch range"), GET_REAL (L"right Peak search pitch range"), GET_REAL (L"Tolerance"),
+ GET_INTEGER (L"Interpolation") - 1, GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"),
+ GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
+ Melder_informationReal (cpps, L" dB");
+ }
+END
+
+FORM (PowerCepstrogram_formula, L"PowerCepstrogram: Formula", L"")
+ LABEL (L"label", L"Do for all times and quefrencies:")
+ LABEL (L"label", L" `x' is the time in seconds")
+ LABEL (L"label", L" `y' is the quefrency in seconds")
+ LABEL (L"label", L" `self' is the current value")
+ LABEL (L"label", L" Replace all values with:")
+ TEXTFIELD (L"formula", L"sqrt(self)")
+ OK
+DO
+ LOOP {
+ iam (PowerCepstrogram);
+ try {
+ Matrix_formula ((Matrix) me, GET_STRING (L"formula"), interpreter, NULL);
+ praat_dataChanged (me);
+ } catch (MelderError) {
+ praat_dataChanged (me); // in case of error, the PowerCepstrogram may have partially changed
+ throw;
+ }
+ }
+END
+
+FORM (PowerCepstrogram_to_PowerCepstrum_slice, L"PowerCepstrogram: To PowerCepstrum (slice)", 0)
REAL (L"Time (s)", L"0.1")
OK
DO
LOOP {
- iam (Cepstrogram);
- autoCepstrum thee = Cepstrogram_to_Cepstrum_slice (me, GET_REAL (L"Time"));
- praat_new (thee.transfer(), my name, L"_slice");
+ iam (PowerCepstrogram);
+ double time = GET_REAL (L"Time");
+ autoPowerCepstrum thee = PowerCepstrogram_to_PowerCepstrum_slice (me, time);
+ praat_new (thee.transfer(), my name, NUMstring_timeNoDot (time));
}
END
-FORM (Cepstrogram_to_Table_cpp, L"Cepstrogram: To Table (peak prominence)", L"Cepstrogram: To Table (peak prominence...")
- REAL (L"left Peak search quefrency range (s)", L"0.003 (=330 Hz)")
- REAL (L"right Peak search quefrency range (s)", L"0.0167 (=60 Hz)")
- RADIO (L"Interpolation", 3)
+FORM (PowerCepstrogram_to_Table_cpp, L"PowerCepstrogram: To Table (peak prominence)", L"PowerCepstrogram: To Table (peak prominence...")
+ REAL (L"left Peak search pitch range (Hz)", L"60.0")
+ REAL (L"right Peak search pitch range (Hz)", L"330.0")
+ POSITIVE (L"Tolerance (0-1)", L"0.05")
+ RADIO (L"Interpolation", 2)
RADIOBUTTON (L"None")
RADIOBUTTON (L"Parabolic")
RADIOBUTTON (L"Cubic")
RADIOBUTTON (L"Sinc70")
REAL (L"left Tilt line quefrency range (s)", L"0.001")
REAL (L"right Tilt line quefrency range (s)", L"0.0 (=end)")
+ OPTIONMENU (L"Line type", 2)
+ OPTION (L"Straight")
+ OPTION (L"Exponential decay")
OPTIONMENU (L"Fit method", 2)
OPTION (L"Least squares")
OPTION (L"Robust")
OK
DO
LOOP {
- iam (Cepstrogram);
- autoTable thee = Cepstrogram_to_Table_cpp (me,
- GET_REAL (L"left Peak search quefrency range"), GET_REAL (L"right Peak search quefrency range"),
- GET_INTEGER (L"Interpolation"),
+ iam (PowerCepstrogram);
+ autoTable thee = PowerCepstrogram_to_Table_cpp (me,
+ GET_REAL (L"left Peak search pitch range"), GET_REAL (L"right Peak search pitch range"), GET_REAL (L"Tolerance"),
+ GET_INTEGER (L"Interpolation") - 1,
GET_REAL (L"left Tilt line quefrency range"), GET_REAL (L"right Tilt line quefrency range"),
- GET_INTEGER (L"Fit method"));
+ GET_INTEGER (L"Line type"), GET_INTEGER (L"Fit method"));
praat_new (thee.transfer(), my name, L"_cpp");
}
END
-DIRECT (Cepstrogram_to_Matrix)
+FORM (PowerCepstrogram_to_Table_hillenbrand, L"PowerCepstrogram: To Table (hillenbrand)", L"PowerCepstrogram: To Table (peak prominence...")
+ REAL (L"left Peak search pitch range (Hz)", L"60.0")
+ REAL (L"right Peak search pitch range (Hz)", L"330.0")
+ OK
+DO
LOOP {
- iam (Cepstrogram);
- autoMatrix thee = Cepstrogram_to_Matrix (me);
+ iam (PowerCepstrogram);
+ autoTable thee = PowerCepstrogram_to_Table_hillenbrand (me,
+ GET_REAL (L"left Peak search pitch range"), GET_REAL (L"right Peak search pitch range"));
+ praat_new (thee.transfer(), my name, L"_cpp");
+ }
+END
+
+DIRECT (PowerCepstrogram_to_Matrix)
+ LOOP {
+ iam (PowerCepstrogram);
+ autoMatrix thee = PowerCepstrogram_to_Matrix (me);
praat_new (thee.transfer(), my name);
}
END
@@ -492,7 +795,8 @@ FORM (LPC_to_Polynomial, L"LPC: To Polynomial", L"LPC: To Polynomial (slice)..."
DO
LOOP {
iam (LPC);
- praat_new (LPC_to_Polynomial (me, GET_REAL (L"Time")), my name);
+ double time = GET_REAL (L"Time");
+ praat_new (LPC_to_Polynomial (me, time), my name, NUMstring_timeNoDot (time));
}
END
@@ -505,8 +809,9 @@ FORM (LPC_to_Spectrum, L"LPC: To Spectrum", L"LPC: To Spectrum (slice)...")
DO
LOOP {
iam (LPC);
- praat_new (LPC_to_Spectrum (me, GET_REAL (L"Time"), GET_REAL (L"Minimum frequency resolution"),
- GET_REAL (L"Bandwidth reduction"), GET_REAL (L"De-emphasis frequency")), my name);
+ double time = GET_REAL (L"Time");
+ praat_new (LPC_to_Spectrum (me, time, GET_REAL (L"Minimum frequency resolution"),
+ GET_REAL (L"Bandwidth reduction"), GET_REAL (L"De-emphasis frequency")), my name, NUMstring_timeNoDot (time));
}
END
@@ -535,7 +840,8 @@ DO
bool internalDamping = GET_INTEGER (L"Internal damping");
LOOP {
iam (LPC);
- praat_new (LPC_to_VocalTract (me, GET_REAL (L"Time"), glottalDamping, radiationDamping, internalDamping), my name);
+ double time = GET_REAL (L"Time");
+ praat_new (LPC_to_VocalTract (me, time, glottalDamping, radiationDamping, internalDamping), my name, NUMstring_timeNoDot (time));
}
END
@@ -546,7 +852,8 @@ FORM (LPC_to_VocalTract, L"LPC: To VocalTract", L"LPC: To VocalTract (slice)..."
DO
LOOP {
iam (LPC);
- praat_new (LPC_to_VocalTract (me, GET_REAL (L"Time"), GET_REAL (L"Length")), my name);
+ double time = GET_REAL (L"Time");
+ praat_new (LPC_to_VocalTract (me, time, GET_REAL (L"Length")), my name, NUMstring_timeNoDot (time));
}
END
@@ -573,8 +880,8 @@ END
/********************** Sound *******************************************/
-FORM (Sound_to_Cepstrogram, L"Sound: To Cepstrogram", L"Sound: To Cepstrogram...")
- POSITIVE (L"Window length (s)", L"0.025")
+FORM (Sound_to_PowerCepstrogram, L"Sound: To PowerCepstrogram", L"Sound: To PowerCepstrogram...")
+ POSITIVE (L"Pitch floor (Hz)", L"60.0")
POSITIVE (L"Time step (s)", L"0.002")
POSITIVE (L"Maximum frequency (Hz)", L"5000.0")
POSITIVE (L"Pre-emphasis from (Hz)", L"50")
@@ -582,12 +889,25 @@ FORM (Sound_to_Cepstrogram, L"Sound: To Cepstrogram", L"Sound: To Cepstrogram...
DO
LOOP {
iam (Sound);
- autoCepstrogram thee = Sound_to_Cepstrogram (me, GET_REAL (L"Window length"), GET_REAL (L"Time step"), GET_REAL(L"Maximum frequency"),
+ autoPowerCepstrogram thee = Sound_to_PowerCepstrogram (me, GET_REAL (L"Pitch floor"), GET_REAL (L"Time step"), GET_REAL(L"Maximum frequency"),
GET_REAL (L"Pre-emphasis from"));
praat_new (thee.transfer(), my name);
}
END
+
+FORM (Sound_to_PowerCepstrogram_hillenbrand, L"Sound: To PowerCepstrogram (hillenbrand)", L"Sound: To PowerCepstrogram...")
+ POSITIVE (L"Pitch floor (Hz)", L"60.0")
+ POSITIVE (L"Time step (s)", L"0.002")
+ OK
+DO
+ LOOP {
+ iam (Sound);
+ autoPowerCepstrogram thee = Sound_to_PowerCepstrogram_hillenbrand (me, GET_REAL (L"Pitch floor"), GET_REAL (L"Time step"));
+ praat_new (thee.transfer(), my name);
+ }
+END
+
FORM (Sound_to_Formant_robust, L"Sound: To Formant (robust)", L"Sound: To Formant (robust)...")
REAL (L"Time step (s)", L"0.0 (= auto)")
POSITIVE (L"Max. number of formants", L"5")
@@ -865,28 +1185,54 @@ extern void praat_TimeTier_query_init (ClassInfo klas);
extern void praat_TimeTier_modify_init (ClassInfo klas);
void praat_uvafon_LPC_init (void);
void praat_uvafon_LPC_init (void) {
- Thing_recognizeClassesByName (classCepstrumc, classCepstrogram, classLPC, classLFCC, classMFCC, classVocalTractTier, NULL);
+ Thing_recognizeClassesByName (classCepstrumc, classPowerCepstrum, classCepstrogram, classPowerCepstrogram, classLPC, classLFCC, classMFCC, classVocalTractTier, NULL);
- praat_addAction1 (classCepstrum, 0, L"Cepstrum help", 0, 0, DO_Cepstrum_help);
- praat_addAction1 (classCepstrum, 0, L"Draw...", 0, 0, DO_Cepstrum_draw);
- praat_addAction1 (classCepstrum, 0, L"Draw tilt line...", 0, 0, DO_Cepstrum_drawTiltLine);
+ praat_addAction1 (classPowerCepstrum, 0, L"PowerCepstrum help", 0, 0, DO_PowerCepstrum_help);
+ praat_addAction1 (classPowerCepstrum, 0, L"Draw...", 0, 0, DO_PowerCepstrum_draw);
+ praat_addAction1 (classPowerCepstrum, 0, L"Draw tilt line...", 0, 0, DO_PowerCepstrum_drawTiltLine);
praat_addAction1 (classCepstrum, 0, L"Draw (linear)...", 0, praat_HIDDEN, DO_Cepstrum_drawLinear);
- praat_addAction1 (classCepstrum, 1, L"Query -", 0, 0, 0);
- praat_addAction1 (classCepstrum, 0, L"Get peak...", 0, 1, DO_Cepstrum_getPeak);
- praat_addAction1 (classCepstrum, 0, L"Get quefrency of peak...", 0, 1, DO_Cepstrum_getQuefrencyOfPeak);
- praat_addAction1 (classCepstrum, 0, L"Get peak prominence...", 0, 1, DO_Cepstrum_getPeakProminence);
- praat_addAction1 (classCepstrum, 1, L"Modify -", 0, 0, 0);
- praat_addAction1 (classCepstrum, 0, L"Formula...", 0, 1, DO_Cepstrum_formula);
-
+ praat_addAction1 (classCepstrum, 0, L"Down to PowerCepstrum", 0, 0, DO_Cepstrum_downto_PowerCepstrum);
+
+ praat_addAction1 (classPowerCepstrum, 1, L"Query -", 0, 0, 0);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get peak...", 0, 1, DO_PowerCepstrum_getPeak);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get quefrency of peak...", 0, 1, DO_PowerCepstrum_getQuefrencyOfPeak);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get peak prominence (hillenbrand)...", 0, praat_DEPTH_1 + praat_HIDDEN, DO_PowerCepstrum_getPeakProminence_hillenbrand);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get peak prominence...", 0, 1, DO_PowerCepstrum_getPeakProminence);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get tilt line slope...", 0, 1, DO_PowerCepstrum_getTiltLineSlope);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get tilt line intercept...", 0, 1, DO_PowerCepstrum_getTiltLineIntercept);
+ praat_addAction1 (classPowerCepstrum, 0, L"Get rhamonics to noise ratio...", 0, 1, DO_PowerCepstrum_getRNR);
+ praat_addAction1 (classPowerCepstrum, 1, L"Modify -", 0, 0, 0);
+ praat_addAction1 (classPowerCepstrum, 0, L"Formula...", 0, 1, DO_PowerCepstrum_formula);
+ praat_addAction1 (classPowerCepstrum, 0, L"Subtract tilt (in-line)...", 0, 1, DO_PowerCepstrum_subtractTilt_inline);
+ praat_addAction1 (classPowerCepstrum, 0, L"Smooth (in-line)...", 0, 1, DO_PowerCepstrum_smooth_inline);
+
+ praat_addAction1 (classPowerCepstrum, 0, L"Subtract tilt...", 0, 0, DO_PowerCepstrum_subtractTilt);
+ praat_addAction1 (classPowerCepstrum, 0, L"Smooth...", 0, 0, DO_PowerCepstrum_smooth);
praat_addAction1 (classCepstrum, 0, L"To Spectrum", 0, praat_HIDDEN, DO_Cepstrum_to_Spectrum);
- praat_addAction1 (classCepstrum, 0, L"To Matrix", 0, 0, DO_Cepstrum_to_Matrix);
-
- praat_addAction1 (classCepstrogram, 0, L"Cepstrogram help", 0, 0, DO_Cepstrogram_help);
- praat_addAction1 (classCepstrogram, 0, L"Paint...", 0, 0, DO_Cepstrogram_paint);
- praat_addAction1 (classCepstrogram, 0, L"To Cepstrum (slice)...", 0, 0, DO_Cepstrogram_to_Cepstrum_slice);
- praat_addAction1 (classCepstrogram, 0, L"Smooth...", 0, 0, DO_Cepstrogram_smooth);
- praat_addAction1 (classCepstrogram, 0, L"To Table (peak prominence)...", 0, 0, DO_Cepstrogram_to_Table_cpp);
- praat_addAction1 (classCepstrogram, 0, L"To Matrix", 0, 0, DO_Cepstrogram_to_Matrix);
+ praat_addAction1 (classPowerCepstrum, 0, L"To Matrix", 0, 0, DO_PowerCepstrum_to_Matrix);
+
+ praat_addAction1 (classPowerCepstrogram, 0, L"PowerCepstrogram help", 0, 0, DO_PowerCepstrogram_help);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Paint...", 0, 0, DO_PowerCepstrogram_paint);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Query -", 0, 0, 0);
+ praat_TimeFrameSampled_query_init (classPowerCepstrogram);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Query quefrency domain", 0, 1, 0);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Get start quefrency", 0, 2, DO_PowerCepstrogram_getStartQuefrency);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Get end quefrency", 0, 2, DO_PowerCepstrogram_getEndQuefrency);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Query quefrency sampling", 0, 1, 0);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Get number of quefrency bins", 0, 2, DO_PowerCepstrogram_getNumberOfQuefrencyBins);
+ praat_addAction1 (classPowerCepstrogram, 1, L"Get quefrency step", 0, 2, DO_PowerCepstrogram_getQuefrencyStep);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Get CPPS (hillenbrand)...", 0, praat_DEPTH_1 + praat_HIDDEN, DO_PowerCepstrogram_getCPPS_hillenbrand);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Get CPPS...", 0, 1, DO_PowerCepstrogram_getCPPS);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Modify -", 0, 0, 0);
+ praat_TimeFunction_modify_init (classPowerCepstrogram);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Formula...", 0, 1, DO_PowerCepstrogram_formula);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Subtract tilt (in-line)...", 0, 1, DO_PowerCepstrogram_subtractTilt_inline);
+ praat_addAction1 (classPowerCepstrogram, 0, L"To PowerCepstrum (slice)...", 0, 0, DO_PowerCepstrogram_to_PowerCepstrum_slice);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Smooth...", 0, 0, DO_PowerCepstrogram_smooth);
+ praat_addAction1 (classPowerCepstrogram, 0, L"Subtract tilt...", 0, 0, DO_PowerCepstrogram_subtractTilt);
+ praat_addAction1 (classPowerCepstrogram, 0, L"To Table (hillenbrand)...", 0, praat_HIDDEN, DO_PowerCepstrogram_to_Table_hillenbrand);
+ praat_addAction1 (classPowerCepstrogram, 0, L"To Table (peak prominence)...", 0, praat_HIDDEN, DO_PowerCepstrogram_to_Table_cpp);
+ praat_addAction1 (classPowerCepstrogram, 0, L"To Matrix", 0, 0, DO_PowerCepstrogram_to_Matrix);
praat_addAction1 (classCepstrumc, 0, L"Analyse", 0, 0, 0);
praat_addAction1 (classCepstrumc, 0, L"To LPC", 0, 0, DO_Cepstrumc_to_LPC);
@@ -940,8 +1286,9 @@ void praat_uvafon_LPC_init (void) {
praat_addAction1 (classSound, 0, L"To LPC (marple)...", L"To LPC (burg)...", 1, DO_Sound_to_LPC_marple);
praat_addAction1 (classSound, 0, L"To MFCC...", L"To LPC (marple)...", 1, DO_Sound_to_MFCC);
praat_addAction1 (classSound, 0, L"To Formant (robust)...", L"To Formant (sl)...", 2, DO_Sound_to_Formant_robust);
- praat_addAction1 (classSound, 0, L"To Cepstrogram...", L"To Harmonicity (gne)...", 1, DO_Sound_to_Cepstrogram);
-
+ praat_addAction1 (classSound, 0, L"To PowerCepstrogram...", L"To Harmonicity (gne)...", 1, DO_Sound_to_PowerCepstrogram);
+ praat_addAction1 (classSound, 0, L"To PowerCepstrogram (hillenbrand)...", L"To Harmonicity (gne)...", praat_HIDDEN + praat_DEPTH_1, DO_Sound_to_PowerCepstrogram_hillenbrand);
+
praat_addAction1 (classVocalTract, 0, L"Draw segments...", L"Draw", 0, DO_VocalTract_drawSegments);
praat_addAction1 (classVocalTract, 1, L"Get length", L"Draw segments...", 0, DO_VocalTract_getLength);
praat_addAction1 (classVocalTract, 1, L"Set length", L"Formula...", 0, DO_VocalTract_getLength);
diff --git a/artsynth/ArtwordEditor.cpp b/artsynth/ArtwordEditor.cpp
index 453d251..a4e0be4 100644
--- a/artsynth/ArtwordEditor.cpp
+++ b/artsynth/ArtwordEditor.cpp
@@ -1,6 +1,6 @@
/* ArtwordEditor.cpp
*
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -108,7 +108,6 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (ArtwordEditor);
if (my graphics == NULL) return;
-if (gtk && event -> type != BUTTON_PRESS) return;
Artword artword = (Artword) my data;
Graphics_setWindow (my graphics, 0, artword -> totalTime, -1.0, 1.0);
Graphics_setInner (my graphics);
diff --git a/artsynth/Makefile b/artsynth/Makefile
index 9fc8584..059d82d 100644
--- a/artsynth/Makefile
+++ b/artsynth/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "artsynth"
-# Paul Boersma, 6 September 2011
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -22,7 +22,7 @@ clean:
libartsynth.a: $(OBJECTS)
touch libartsynth.a
rm libartsynth.a
- ar cq libartsynth.a $(OBJECTS)
+ $(AR) cq libartsynth.a $(OBJECTS)
$(RANLIB) libartsynth.a
$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../fon/*.h ../stat/*.h
diff --git a/contrib/ola/Makefile b/contrib/ola/Makefile
index 1b30e95..a583cd7 100644
--- a/contrib/ola/Makefile
+++ b/contrib/ola/Makefile
@@ -1,6 +1,6 @@
# Makefile of the library "contrib/ola"
# Ola So"der 19 January 2008
-# Paul Boersma, 14 January 2012
+# Paul Boersma, 24 August 2013
include ../../makefile.defs
@@ -20,7 +20,7 @@ clean:
libOla.a: $(OBJECTS)
touch libOla.a
rm libOla.a
- ar cq libOla.a $(OBJECTS)
+ $(AR) cq libOla.a $(OBJECTS)
$(RANLIB) libOla.a
$(OBJECTS): *.h ../../sys/*.h ../../dwtools/*.h ../../fon/*.h ../../dwsys/*.h ../../stat/*.h ../../num/*.h ../../external/gsl/*.h
diff --git a/dwsys/Makefile b/dwsys/Makefile
index ea43ed4..598c65e 100644
--- a/dwsys/Makefile
+++ b/dwsys/Makefile
@@ -1,5 +1,5 @@
# makefile for library "dwsys".
-# David Weenink 20121211
+# David Weenink 20130826
include ../makefile.defs
@@ -27,7 +27,7 @@ clean:
libdwsys.a: $(OBJECTS) NUMmachar.o
touch libdwsys.a
rm libdwsys.a
- ar cq libdwsys.a $(OBJECTS)
+ $(AR) cq libdwsys.a $(OBJECTS)
$(RANLIB) libdwsys.a
$(OBJECTS): *.h ../stat/*.h ../num/NUM.h ../sys/*.h ../external/gsl/*.h ../dwsys/*.h ../kar/*.h
diff --git a/dwsys/NUM2.cpp b/dwsys/NUM2.cpp
index d1cd64e..4701ea7 100644
--- a/dwsys/NUM2.cpp
+++ b/dwsys/NUM2.cpp
@@ -440,6 +440,23 @@ void NUMcolumn2_avevar (double **a, long nr, long nc, long icol1, long icol2,
}
}
+void NUMvector_smoothByMovingAverage (double *xin, long n, long nwindow, double *xout) {
+// simple averaging, out of bound values are zero
+ for (long i = 1; i <= n; i++) {
+ long jfrom = i - nwindow / 2, jto = i + nwindow / 2;
+ if ((nwindow % 2) == 0) {
+ jto--;
+ }
+ jfrom = jfrom < 1 ? 1 : jfrom;
+ jto = jto > n ? n : jto;
+ xout[i] = 0;
+ for (long j = jfrom; j <= jto; j++) {
+ xout[i] += xin[j];
+ }
+ xout[i] /= jto - jfrom + 1;
+ }
+}
+
void NUMcovarianceFromColumnCentredMatrix (double **x, long nrows, long ncols, long ndf, double **covar) {
if (ndf < 0 || nrows - ndf < 1 || covar == 0) {
Melder_throw ("Invalid arguments.");
@@ -2276,7 +2293,7 @@ int NUMgetOrientationOfPoints (double x1, double y1, double x2, double y2, doubl
int NUMgetIntersectionsWithRectangle (double x1, double y1, double x2, double y2,
double xmin, double ymin, double xmax, double ymax, double *xi, double *yi) {
- double x[6], y[6], t;
+ double x[6], y[6];
long ni = 0;
x[1] = x[4] = x[5] = xmin;
@@ -2313,21 +2330,33 @@ int NUMgetIntersectionsWithRectangle (double x1, double y1, double x2, double y2
for (long i = 1; i <= 4; i++) {
double denom = (x[i + 1] - x[i]) * (y2 - y1) - (y[i + 1] - y[i]) * (x2 - x1);
+ double s, t, x3, y3;
if (denom == 0) {
continue;
}
/* We have an intersection. */
- t = ( (y[i] - y1) * (x2 - x1) - (x[i] - x1) * (y2 - y1)) / denom;
+ t = ((y[i] - y1) * (x2 - x1) - (x[i] - x1) * (y2 - y1)) / denom;
if (t < 0 || t >= 1) {
continue;
}
/* Intersection is within rectangle side. */
+ x3 = x[i] + t * (x[i + 1] - x[i]);
+ y3 = y[i] + t * (y[i + 1] - y[i]);
+ /* s must also be valid */
+ if (x1 != x2) {
+ s = (x3 - x1) / (x2 - x1);
+ } else {
+ s = (y3 - y1) / (y2 - y1);
+ }
+ if (s < 0 || s >= 1) {
+ continue;
+ }
ni++;
if (ni > 2) {
Melder_throw ("Too many intersections.");
}
- xi[ni] = x[i] + t * (x[i + 1] - x[i]);
- yi[ni] = y[i] + t * (y[i + 1] - y[i]);
+ xi[ni] = x3;
+ yi[ni] = y3;
}
return ni;
}
@@ -2629,7 +2658,7 @@ long NUMgetIndexFromProbability (double *probs, long nprobs, double p) {
// straight line fitting
-void NUMlineFit_theil (double *x, double *y, long numberOfPoints, double *m, double *intercept) {
+void NUMlineFit_theil (double *x, double *y, long numberOfPoints, double *m, double *intercept, bool incompleteMethod) {
try {
/* Theil's incomplete method:
* Split (x[i],y[i]) as
@@ -2638,19 +2667,42 @@ void NUMlineFit_theil (double *x, double *y, long numberOfPoints, double *m, dou
* m = median (m[i])
* b = median(y[i]-m*x[i])
*/
- autoNUMvector<double> mbs (1, numberOfPoints);
- long n2 = numberOfPoints / 2;
- long n = numberOfPoints % 2 == 1 ? n2 + 1 : n2;
- for (long i = 1; i <= n2; i++) {
- mbs[i] = (y[n + i] - y[i]) / (x[n + i] - x[i]);
- }
- NUMsort_d (n2, mbs.peek());
- *m = NUMquantile (n2, mbs.peek(), 0.5);
- for (long i = 1; i <= numberOfPoints; i++) {
- mbs[i] = y[i] - *m * x[i];
- }
- NUMsort_d (numberOfPoints, mbs.peek());
- *intercept = NUMquantile (numberOfPoints, mbs.peek(), 0.5);
+ if (numberOfPoints <= 0) {
+ *m = *intercept = NUMundefined;
+ } else if (numberOfPoints == 1) {
+ *intercept = y[1];
+ *m = 0;
+ } else if (numberOfPoints == 2) {
+ *m = (y[2] - y[1]) / (x[2] - x[1]);
+ *intercept = y[1] - *m * x[1];
+ } else {
+ long numberOfCombinations;
+ autoNUMvector<double> mbs;
+ if (incompleteMethod) { // incomplete method
+ numberOfCombinations = numberOfPoints / 2;
+ mbs.reset (1, numberOfPoints); //
+ long n2 = numberOfPoints % 2 == 1 ? numberOfCombinations + 1 : numberOfCombinations;
+ for (long i = 1; i <= numberOfCombinations; i++) {
+ mbs[i] = (y[n2 + i] - y[i]) / (x[n2 + i] - x[i]);
+ }
+ } else { // use all combinations
+ numberOfCombinations = (numberOfPoints - 1) * numberOfPoints / 2;
+ mbs.reset (1, numberOfCombinations);
+ long index = 0;
+ for (long i = 1; i < numberOfPoints; i++) {
+ for (long j = i + 1; j <= numberOfPoints; j++) {
+ mbs[++index] = (y[j] - y[i]) / (x[j] - x[i]);
+ }
+ }
+ }
+ NUMsort_d (numberOfCombinations, mbs.peek());
+ *m = NUMquantile (numberOfCombinations, mbs.peek(), 0.5);
+ for (long i = 1; i <= numberOfPoints; i++) {
+ mbs[i] = y[i] - *m * x[i];
+ }
+ NUMsort_d (numberOfPoints, mbs.peek());
+ *intercept = NUMquantile (numberOfPoints, mbs.peek(), 0.5);
+ }
} catch (MelderError) {
Melder_throw ("No line fit (Theil's method)");
}
@@ -2675,31 +2727,13 @@ void NUMlineFit_LS (double *x, double *y, long numberOfPoints, double *m, double
*m = a;
}
-// y
-void NUMfitExponentialDecayWithKnownVerticalOffset (double *x, double *y, long numberOfPoints, double yOffset, double *a, double *y0, int method) {
- try {
- autoNUMvector<double> logy (1, numberOfPoints);
- for (long i = 1; i <= numberOfPoints; i++) {
- logy[i] = y[i] - yOffset;
- logy[i] = logy[i] <= 0 ? -30 : log (logy[i]);
- }
- double intercept;
- if (method == 1) {
- NUMlineFit_LS (x, logy.peek(), numberOfPoints, a, &intercept);
- } else {
- NUMlineFit_theil (x, logy.peek(), numberOfPoints, a, &intercept);
- }
- *y0 = exp (intercept);
- } catch (MelderError) {
- Melder_throw ("Exponential could not be fitted.");
- }
- }
-
void NUMlineFit (double *x, double *y, long numberOfPoints, double *m, double *intercept, int method) {
if (method == 1) {
NUMlineFit_LS (x, y, numberOfPoints, m, intercept);
+ } else if (method == 3) {
+ NUMlineFit_theil (x, y, numberOfPoints, m, intercept, false);
} else {
- NUMlineFit_theil (x, y, numberOfPoints, m, intercept);
+ NUMlineFit_theil (x, y, numberOfPoints, m, intercept, true);
}
}
diff --git a/dwsys/NUM2.h b/dwsys/NUM2.h
index 0810637..fa00292 100644
--- a/dwsys/NUM2.h
+++ b/dwsys/NUM2.h
@@ -50,7 +50,7 @@ double *NUMstring_to_numbers (const wchar_t *s, long *numbers_found);
*/
long *NUMstring_getElementsOfRanges (const wchar_t *ranges, long maximumElement, long *numberOfElements, long *numberOfMultiples, const wchar_t *elementType, bool sortedUniques);
-
+wchar_t * NUMstring_timeNoDot (double time);
int NUMstrings_equal (const wchar_t **s1, const wchar_t **s2, long lo, long hi);
void NUMstrings_copyElements (wchar_t **from, wchar_t**to, long lo, long hi);
void NUMstrings_free (wchar_t **s, long lo, long hi);
@@ -254,6 +254,9 @@ void NUMcolumn2_avevar (double **a, long nr, long nc, long icol1, long icol2,
NOT given.
*/
+void NUMvector_smoothByMovingAverage (double *xin, long n, long nwindow, double *xout);
+
+
void NUMcovarianceFromColumnCentredMatrix (double **x, long nrows, long ncols, long ndf, double **covar);
/*
Calculate covariance matrix(ncols x ncols) from data matrix (nrows x ncols);
@@ -1254,18 +1257,34 @@ void NUMrealft (double *data, long n, int direction);
long NUMgetIndexFromProbability (double *probs, long nprobs, double p);
+// Fit the line y= ax+b
+void NUMlineFit (double *x, double *y, long numberOfPoints, double *m, double *intercept, int method);
+/* method
+ * 1 least squares
+ * 2 rubust incomplete Theil O(N/2)
+ * 3 robust complete Theil (very slow for large N, O(N^2))
+ */
+
+void NUMlineFit_theil (double *x, double *y, long numberOfPoints, double *m, double *intercept, bool incompleteMethod);
+/*
+ * Preconditions:
+ * all x[i] must be different, i.e. x[i] != x[j] for all i = 1..(numberOfPoints - 1), j = (i+1) ..numberOfPoints
+ * Algorithm:
+ * Theils robust line fit method:
+ * 1. Use all combination of pairs (x[i],y[i]), (x[j],y[j]) to calculate an intercept m[k] as
+ * m[k] = (y[j] - y[i]) / (x[j] - x[i]).
+ * There will be (numberOfPoints - 1) * numberOfPoints / 2 numbers m[k].
+ * 2. Take the median value m of all the m[k].
+ * 3. Calculate the numberOfPoints intercepts b[i] as b[i] = y[i] - m * x[i]
+ * 4. Take the median value b of all the b[i] values
+ *
+ * If incompleteMethod we use Theil's incomplete method to reduce the number of combinations.
+ * I.e. split the data in two equal parts at n2 = numberOfPoints / 2 and then calculate the numberOfPoints/2 intercepts m[i] as
+ * m[i] = (y[n2+i] - y[i]) / (x[n2 + i] - x[i]).
+ * The rest proceeds as outlined above
+ */
-/* Model y = C * exp(a * x) + yOffset
- y - yOffset = C * exp (a * x) => log (y - yOffset) = a * x + log (C)
- Line fit of log() versus x:
- C = exp (intercept)
-*/
-void NUMfitExponentialDecayWithKnownVerticalOffset (double *x, double *y, long numberOfPoints, double yOffset, double *a, double *y0, int method);
-// Fit the line y= ax+b
-// method == 0 then theil, else LS
-void NUMlineFit (double *x, double *y, long numberOfPoints, double *m, double *intercept,int method);
-void NUMlineFit_theil (double *x, double *y, long numberOfPoints, double *m, double *intercept);
void NUMlineFit_LS (double *x, double *y, long numberOfPoints, double *m, double *intercept);
/* The binomial distribution has the form,
diff --git a/dwsys/NUMstring.cpp b/dwsys/NUMstring.cpp
index dc9a20c..f0d418f 100644
--- a/dwsys/NUMstring.cpp
+++ b/dwsys/NUMstring.cpp
@@ -533,4 +533,12 @@ long *NUMstring_getElementsOfRanges (const wchar_t *ranges, long maximumElement,
return elements.transfer();
}
+wchar_t * NUMstring_timeNoDot (double time) {
+ static wchar_t string[100];
+ long seconds = time;
+ long ms = round((double)((time - seconds) * 1000.0));
+ swprintf (string, 99, L"_%ld_%ld", seconds, ms);
+ return string;
+}
+
/* End of file NUMstring.cpp */
diff --git a/dwtest/test_Ltas_reportSpectralTilt.praat b/dwtest/test_Ltas_reportSpectralTilt.praat
new file mode 100644
index 0000000..32faf07
--- /dev/null
+++ b/dwtest/test_Ltas_reportSpectralTilt.praat
@@ -0,0 +1,29 @@
+# test_Ltas_reportSpectralTilt.praat
+# djmw 20130813
+
+appendInfoLine ("test_Ltas_reportSpectralTilt")
+
+s[1] = do ("Create Sound from formula...", "sineWithNoise", 1, 0, 1, 44100, "randomGauss(0,0.1)")
+s[2] = do ("Filter (de-emphasis)...", 50)
+# some of the following values are rough guesses, if the assertion failes adapt the values somewhat
+slope[1] = 0 ; dB/Hz (this value is exact)
+slopemargin[1] = 0.5 ; approximate
+slope[2] = -20 ; dB/decade (this value is exact)
+slopemargin[2] = 1.5 ; approximate
+offset[1] = 30.8 ; dB approximate
+offsetmargin[1] = 3 ; approximate
+offset[2] = 95 ; dB ; approximate
+offsetmargin[2] = 4 ; approximate
+for i to 2
+ selectObject (s[i])
+ ltas = do ("To Ltas...", 100)
+ info$ = do$ ("Report spectral tilt...", 100, 10000, "Logarithmic", "Robust")
+ slope = extractNumber (info$, "Slope:")
+ offset = extractNumber (info$, "Offset:")
+ appendInfoLine (tab$, "Slope= ", fixed$ (slope, 4), "; Offset= ", fixed$ (offset, 4))
+ assert slope > (slope[i] - slopemargin[i]) and slope < (slope[i] + slopemargin[i])
+ assert offset > (offset[i] - offsetmargin[i]) and offset < (offset[i] + offsetmargin[i])
+ removeObject (s[i], ltas)
+endfor
+
+appendInfoLine ("test_Ltas_reportSpectralTilt OK")
diff --git a/dwtest/test_OnewayAnova.praat b/dwtest/test_onewayAnova.praat
similarity index 93%
rename from dwtest/test_OnewayAnova.praat
rename to dwtest/test_onewayAnova.praat
index 2868063..e5ff87d 100644
--- a/dwtest/test_OnewayAnova.praat
+++ b/dwtest/test_onewayAnova.praat
@@ -1,4 +1,4 @@
-# test_OnewayAnova.praat
+# test_onewayAnova.praat
# djmw 20120625
printline One-way Anova test
@@ -14,7 +14,7 @@ total = extractNumber (report$, "Total")
assert abs (between-22.57) < 0.01
assert abs (within - 878.93) < 0.01
assert abs (total - 901.5) < 0.1
-
+Remove
printline One-way Anova test OK
diff --git a/dwtools/Ltas_extensions.cpp b/dwtools/Ltas_extensions.cpp
index 32c6482..e0df589 100644
--- a/dwtools/Ltas_extensions.cpp
+++ b/dwtools/Ltas_extensions.cpp
@@ -1,6 +1,6 @@
/* Ltas_extensions.cpp
*
- * Copyright (C) 2012 David Weenink
+ * Copyright (C) 2012-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
void Ltas_fitTiltLine (Ltas me, double fmin, double fmax, bool lnf, int method, double *a, double *b) {
try {
- if (fmax >= fmin) {
+ if (fmax <= fmin) {
fmin = my xmin; fmax = my xmax;
}
long ifmin, ifmax, numberOfSamples = Sampled_getWindowSamples (me, fmin, fmax, &ifmin, &ifmax);
@@ -32,11 +32,13 @@ void Ltas_fitTiltLine (Ltas me, double fmin, double fmax, bool lnf, int method,
autoNUMvector<double> x (1, numberOfSamples);
autoNUMvector<double> y (1, numberOfSamples);
for (long i = ifmin; i <= ifmax; i++) {
- x[i] = my x1 + (i - 1) * my dx;
+ long ixy = i - ifmin + 1;
+ x[ixy] = my x1 + (i - 1) * my dx;
if (lnf) {
- x[i] = log (x[i]);
+ // For Ltas always x1 > 0
+ x[ixy] = log10 (x[ixy]);
}
- y[i] = my z[1][i];
+ y[ixy] = my z[1][i];
}
NUMlineFit (x.peek(), y.peek(), numberOfSamples, a, b, method);
} catch (MelderError) {
diff --git a/dwtools/MFCC.cpp b/dwtools/MFCC.cpp
index 9f3f4be..bd9a09f 100644
--- a/dwtools/MFCC.cpp
+++ b/dwtools/MFCC.cpp
@@ -2,7 +2,7 @@
*
* Mel Frequency Cepstral Coefficients class.
*
- * Copyright (C) 1993-2012 David Weenink
+ * Copyright (C) 1993-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
* djmw 20110304 Thing_new
*/
-#include "MFCC.h"
+#include "MelFilter_and_MFCC.h"
#include "NUM2.h"
@@ -86,6 +86,7 @@ TableOfReal MFCC_to_TableOfReal (MFCC me, bool includeC0) {
}
}
+// as_Sound not to_Sound
Sound MFCC_to_Sound (MFCC me) {
try {
autoSound thee = Sound_create (my maximumNumberOfCoefficients, my xmin, my xmax, my nx, my dx, my x1);
@@ -100,6 +101,7 @@ Sound MFCC_to_Sound (MFCC me) {
Melder_throw (me, ": not represented as Sound.");
}
}
+
Sound MFCCs_crossCorrelate (MFCC me, MFCC thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain) {
try {
if (my dx != thy dx) {
@@ -134,4 +136,86 @@ Sound MFCCs_convolve (MFCC me, MFCC thee, enum kSounds_convolve_scaling scaling,
}
}
+static double CC_Frames_distance (CC_Frame me, CC_Frame thee, bool includeEnergy) {
+ double dist = 0;
+ if (includeEnergy) {
+ double d0 = my c0 - thy c0;
+ dist += d0 * d0;
+ }
+ for (long i = 1; i <= my numberOfCoefficients; i++) {
+ double di = my c[i] - thy c[i];
+ dist += di * di;
+ }
+ return sqrt (dist);
+}
+
+/* 1: cepstral difference function (d)
+ * 2: spectral stability (dstab)
+ * 3: spectral center of gravity (gs)
+ * 4: stable internal duration
+ */
+Matrix MFCC_to_Matrix_features (MFCC me, double windowLength, bool includeEnergy) {
+ try {
+ long nw = windowLength / my dx / 2;
+ autoMelFilter him = MFCC_to_MelFilter (me, 0, 0);
+ 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
+ for (long iframe = 2; iframe <= my nx - 1; iframe++) {
+ CC_Frame cfi = (CC_Frame) & my frame[iframe];
+ // 1. cepstral difference
+ long nwi = iframe > nw ? nw : iframe - 1;
+ nwi = iframe < my nx - nwi ? nwi : my nx - iframe;
+ double numer = 0;
+ for (long j = 1; j <= nwi; j++) {
+ numer += j * j;
+ }
+ numer *= 2;
+ double dsq = 0;
+ if (includeEnergy) {
+ double sumj = 0;
+ for (long j = 1; j <= nwi; j++) {
+ CC_Frame cfp = (CC_Frame) & my frame[iframe + j];
+ CC_Frame cfm = (CC_Frame) & my frame[iframe - j];
+ sumj += j * (cfp -> c0 - cfm -> c0);
+ }
+ sumj /= numer;
+ dsq += sumj * sumj;
+ }
+ for (long i = 1; i <= my maximumNumberOfCoefficients; i++) {
+ double sumj = 0;
+ for (long j = 1; j <= nwi; j++) {
+ CC_Frame cfp = (CC_Frame) & my frame[iframe + j];
+ CC_Frame cfm = (CC_Frame) & my frame[iframe - j];
+ sumj += j * (cfp -> c[j] - cfm -> c[j]);
+ }
+ sumj /= numer;
+ dsq += sumj * sumj;
+ }
+ thy z[1][iframe] = dsq;
+
+ // 2: spectral stability (dstab)
+ CC_Frame cfp = (CC_Frame) & my frame[iframe + 1];
+ CC_Frame cfm = (CC_Frame) & my frame[iframe - 1];
+ double dim1 = CC_Frames_distance (cfi, cfm, includeEnergy);
+ double dip1 = CC_Frames_distance (cfi, cfp, includeEnergy);
+ thy z[2][iframe] = (dim1 + dip1) / 2;
+
+ // 3: spectral centere of gravity (gs)
+ double msm = 0, sm = 0;
+ for (long j = 1; j <= his ny; j++) {
+ sm += his z[j][iframe];
+ msm += j * his z[j][iframe];
+ }
+ double gs = sm == 0 ? 0 : msm / sm;
+ thy z[3][iframe] = gs;
+
+ // 4: stable internal duration
+ }
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": no features calculated.");
+ }
+
+}
+
/* End of file MFCC.cpp */
diff --git a/dwtools/MFCC.h b/dwtools/MFCC.h
index 7135bff..732a2e4 100644
--- a/dwtools/MFCC.h
+++ b/dwtools/MFCC.h
@@ -4,7 +4,7 @@
*
* Mel Frequency Cepstral Coefficients class.
*
- * Copyright (C) 1993-2012 David Weenink
+ * Copyright (C) 1993-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,4 +55,6 @@ Sound MFCC_to_Sound (MFCC me);
Sound MFCCs_crossCorrelate (MFCC me, MFCC thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain);
Sound MFCCs_convolve (MFCC me, MFCC thee, enum kSounds_convolve_scaling scaling, enum kSounds_convolve_signalOutsideTimeDomain signalOutsideTimeDomain);
+Matrix MFCC_to_Matrix_features (MFCC me, double windowLength, bool includeEnergy);
+
#endif /* _MFCC_h_ */
diff --git a/dwtools/Makefile b/dwtools/Makefile
index 6d50544..60b39a3 100644
--- a/dwtools/Makefile
+++ b/dwtools/Makefile
@@ -1,10 +1,10 @@
# Makefile of the library "dwtools"
# David Weenink, 22 February 2010
-# djmw 20121214 Latest modification
+# djmw 20130826 Latest modification
include ../makefile.defs
-CPPFLAGS = -I ../num -I ../LPC -I ../fon -I ../sys -I ../stat -I ../dwsys -I ../external/portaudio -I ../external/espeak -I ../EEG
+CPPFLAGS = -I ../num -I ../LPC -I ../fon -I ../sys -I ../stat -I ../dwsys -I ../external/portaudio -I ../external/espeak -I ../EEG -I ../kar
OBJECTS = Activation.o AffineTransform.o \
Categories.o CategoriesEditor.o \
@@ -62,8 +62,8 @@ clean:
libdwtools.a: $(OBJECTS)
touch libdwtools.a
rm libdwtools.a
- ar cq libdwtools.a $(OBJECTS)
+ $(AR) cq libdwtools.a $(OBJECTS)
$(RANLIB) libdwtools.a
-$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h ../LPC/*.h
+$(OBJECTS): *.h ../num/NUM.h ../sys/*.h ../fon/*.h ../dwsys/*.h ../stat/*.h ../LPC/*.h ../external/espeak/*.h
diff --git a/dwtools/SpeechSynthesizer.cpp b/dwtools/SpeechSynthesizer.cpp
index 7924656..96866e6 100644
--- a/dwtools/SpeechSynthesizer.cpp
+++ b/dwtools/SpeechSynthesizer.cpp
@@ -1,6 +1,6 @@
/* SpeechSynthesizer.cpp
*
- * Copyright (C) 2011-2012 David Weenink
+// * Copyright (C) 2011-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ SpeechSynthesizerVoice SpeechSynthesizerVoice_create (long numberOfFormants) {
}
void SpeechSynthesizerVoice_setDefaults (SpeechSynthesizerVoice me) {
-
+ (void) me;
}
void SpeechSynthesizerVoice_initFromEspeakVoice (SpeechSynthesizerVoice me, voice_t *voice) {
@@ -199,7 +199,7 @@ static int synthCallback (short *wav, int numsamples, espeak_EVENT *events)
if (events -> type == espeakEVENT_MARK || events -> type == espeakEVENT_PLAY) {
Table_setStringValue (my d_events, irow, 8, Melder_peekUtf8ToWcs (events -> id.name));
} else {
- // Ugly hack because id.string in not 0-terminated if 8 chars long!
+ // Ugly hack because id.string is not 0-terminated if 8 chars long!
memcpy (phoneme_name, events -> id.string, 8);
phoneme_name[8] = 0;
Table_setStringValue (my d_events, irow, 8, Melder_peekUtf8ToWcs (phoneme_name));
@@ -365,6 +365,13 @@ static void Table_setEventTypeString (Table me) {
}
}
+static void MelderString_trimWhiteSpaceAtEnd (MelderString *me) {
+ while (my length > 1 && (my string[my length - 1] == ' ' or my string[my length - 1] == '\t'
+ or my string[my length - 1] == '\r' or my string[my length - 1] == '\n')) {
+ my string[my length - 1] = '\0'; my length--;
+ }
+}
+
static TextGrid Table_to_TextGrid (Table me, const wchar_t *text, double xmin, double xmax) {
//Table_createWithColumnNames (0, L"time type type-t t-pos length a-pos sample id uniq");
try {
@@ -402,6 +409,7 @@ static TextGrid Table_to_TextGrid (Table me, const wchar_t *text, double xmin, d
// End of clause: insert new boundary, and fill left interval with text
length = pos - p1c + 1;
MelderString_ncopy (&mark, text + p1c - 1, length);
+ MelderString_trimWhiteSpaceAtEnd (&mark);
if (time > xmin and time < xmax) {
IntervalTier_addBoundaryUnsorted (itc, itc -> intervals -> size, time, mark.string, true);
} else {
@@ -415,6 +423,7 @@ static TextGrid Table_to_TextGrid (Table me, const wchar_t *text, double xmin, d
if (pos <= textLength) {
length = pos - p1w + 1;
MelderString_ncopy (&mark, text + p1w - 1, length);
+ MelderString_trimWhiteSpaceAtEnd (&mark);
if (time > xmin and time < xmax) {
IntervalTier_addBoundaryUnsorted (itw, itw -> intervals -> size, time, mark.string, true);
} else {
@@ -430,6 +439,7 @@ static TextGrid Table_to_TextGrid (Table me, const wchar_t *text, double xmin, d
length = pos - p1w;
if (pos == textLength) length++;
MelderString_ncopy (&mark, text + p1w - 1, length);
+ MelderString_trimWhiteSpaceAtEnd (&mark);
IntervalTier_addBoundaryUnsorted (itw, itw -> intervals -> size, time, (wordEnd ? mark.string : L""), true);
MelderString_empty (&mark);
}
diff --git a/dwtools/SpeechSynthesizer.h b/dwtools/SpeechSynthesizer.h
index dd3a933..03a625e 100644
--- a/dwtools/SpeechSynthesizer.h
+++ b/dwtools/SpeechSynthesizer.h
@@ -2,7 +2,7 @@
#define _SpeechSynthesizer_h_
/* SpeechSynthesizer.h
*
- * Copyright (C) 2011-2012 David Weenink
+ * Copyright (C) 2011-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,11 +25,11 @@
#include "Sound.h"
#include "TextGrid.h"
-#include "speech.h"
-#include "speak_lib.h"
-#include "phoneme.h"
-#include "synthesize.h"
-#include "voice.h"
+#include "../external/espeak/speech.h"
+#include "../external/espeak/speak_lib.h"
+#include "../external/espeak/phoneme.h"
+#include "../external/espeak/synthesize.h"
+#include "../external/espeak/voice.h"
#define SpeechSynthesizer_PHONEMECODINGS_IPA 2
#define SpeechSynthesizer_PHONEMECODINGS_KIRSHENBAUM 1
diff --git a/dwtools/Table_extensions.cpp b/dwtools/Table_extensions.cpp
index 8131e74..c53998f 100644
--- a/dwtools/Table_extensions.cpp
+++ b/dwtools/Table_extensions.cpp
@@ -1,6 +1,6 @@
/* Table_extensions.cpp
*
- * Copyright (C) 1997-2012 David Weenink
+ * Copyright (C) 1997-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,11 +30,13 @@
F0, F1, F2, F3
*/
-
+#include "Formula.h"
#include "GraphicsP.h"
#include "Graphics_extensions.h"
#include "Index.h"
+#include "Matrix_extensions.h"
#include "NUM2.h"
+#include <ctype.h>
#include "Strings_extensions.h"
#include "Table_extensions.h"
@@ -3109,6 +3111,41 @@ Table Table_createFromWeeninkData () {
}
}
+// Keating&Esposito (2006),
+Table Table_createFromEspositoData () {
+ try {
+ autoTable me = Table_createWithColumnNames (10, L"Language Modal Breathy");
+ Table_setStringValue (me.peek(), 1, 1, L"Chong");Table_setNumericValue (me.peek(), 1, 2, -1.5);Table_setNumericValue (me.peek(), 1, 3, 5);
+ Table_setStringValue (me.peek(), 2, 1, L"Fuzhou");Table_setNumericValue (me.peek(), 2, 2, -1.5);Table_setNumericValue (me.peek(), 2, 3, 5);
+ Table_setStringValue (me.peek(), 3, 1, L"Green Hmong");Table_setNumericValue (me.peek(), 3, 2, 3);Table_setNumericValue (me.peek(), 3, 3, 12);
+ Table_setStringValue (me.peek(), 4, 1, L"White Hmong");Table_setNumericValue (me.peek(), 4, 2, 2);Table_setNumericValue (me.peek(), 4, 3, 11);
+ Table_setStringValue (me.peek(), 5, 1, L"Mon");Table_setNumericValue (me.peek(), 5, 2, -1.5);Table_setNumericValue (me.peek(), 5, 3, 0);
+ Table_setStringValue (me.peek(), 6, 1, L"SADV Zapotec");Table_setNumericValue (me.peek(), 6, 2, -6);Table_setNumericValue (me.peek(), 6, 3, -4);
+ Table_setStringValue (me.peek(), 7, 1, L"SLQ Zapotec");Table_setNumericValue (me.peek(), 7, 2, 3.5);Table_setNumericValue (me.peek(), 7, 3, 14);
+ Table_setStringValue (me.peek(), 8, 1, L"Tlacolula Zapotec");Table_setNumericValue (me.peek(), 8, 2, 3);Table_setNumericValue (me.peek(), 8, 3, 13);
+ Table_setStringValue (me.peek(), 9, 1, L"Tamang");Table_setNumericValue (me.peek(), 9, 2, 1);Table_setNumericValue (me.peek(), 9, 3, 1);
+ Table_setStringValue (me.peek(), 10, 1, L"!Xoo");Table_setNumericValue (me.peek(), 10, 2, 1);Table_setNumericValue (me.peek(), 10, 3, 14);
+ return me.transfer();
+ } catch (MelderError) {
+ Melder_throw ("Keating-Esposito table not created.");
+ }
+}
+
+Table Table_createFromGanongData () {
+ try {
+ autoTable me = Table_createWithColumnNames (6, L"VOT dash-tash dask-task");
+ Table_setNumericValue (me.peek(), 1, 1, -17.5);Table_setNumericValue (me.peek(), 1, 2, 0.98);Table_setNumericValue (me.peek(), 1, 3, 0.92);
+ Table_setNumericValue (me.peek(), 2, 1, -7.5);Table_setNumericValue (me.peek(), 2, 2, 0.95);Table_setNumericValue (me.peek(), 2, 3, 0.83);
+ Table_setNumericValue (me.peek(), 3, 1, -2.5);Table_setNumericValue (me.peek(), 3, 2, 0.71);Table_setNumericValue (me.peek(), 3, 3, 0.33);
+ Table_setNumericValue (me.peek(), 4, 1, 2.5);Table_setNumericValue (me.peek(), 4, 2, 0.29);Table_setNumericValue (me.peek(), 4, 3, 0.10);
+ Table_setNumericValue (me.peek(), 5, 1, 7.5);Table_setNumericValue (me.peek(), 5, 2, 0.12);Table_setNumericValue (me.peek(), 5, 3, 0.02);
+ Table_setNumericValue (me.peek(), 6, 1, 17.5);Table_setNumericValue (me.peek(), 6, 2, 0.10);Table_setNumericValue (me.peek(), 6, 3, 0.02);
+ return me.transfer();
+ } catch (MelderError) {
+ Melder_throw ("Ganong table not created.");
+ }
+}
+
void Table_scatterPlotWithConfidenceIntervals (Table me, Graphics g, long xcolumn, long ycolumn,
double xmin, double xmax, double ymin, double ymax, long xci_min, long xci_max,
long yci_min, long yci_max, double bar_mm, int garnish) {
@@ -3941,4 +3978,355 @@ void Table_boxPlots (Table me, Graphics g, long dataColumn, long factorColumn, d
}
}
+void Table_distributionPlotWhere (Table me, Graphics g, long dataColumn, double minimum, double maximum, long nBins, double freqMin, double freqMax, int garnish, const wchar_t *formula, Interpreter interpreter) {
+ try {
+ if (dataColumn < 1 || dataColumn > my numberOfColumns) return;
+ Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_UNKNOWN, TRUE);
+ Table_numericize_Assert (me, dataColumn);
+ long n = my rows -> size, mrow = 0;
+ autoMatrix thee = Matrix_create (1, 1, 1, 1, 1, 0, n + 1, n, 1, 1);
+ for (long irow = 1; irow <= n; irow++) {
+ struct Formula_Result result;
+ Formula_run (irow, dataColumn, & result);
+ if (result.result.numericResult) {
+ thy z[1][++mrow] = Table_getNumericValue_Assert (me, irow, dataColumn);
+ }
+ }
+ Matrix_drawDistribution (thee.peek(), g, 0, 1, 0.5, mrow+0.5, minimum, maximum, nBins, freqMin, freqMax, 0, garnish);
+ } catch (MelderError) {
+ //
+ }
+}
+
+static Strings itemizeColourString (const wchar_t *colourString) {
+ // remove all spaces within { } so each {1,2,3} can be itemized
+ const wchar_t *compileMsg;
+ long nmatches_sub = 0;
+ const wchar_t *searchRE = L"\\{\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*\\}";
+ regexp *compiledRE = CompileRE ((regularExp_CHAR *) searchRE, &compileMsg, 0);
+ if (compiledRE == NULL) {
+ Melder_throw ("No valid regexp");
+ }
+ autoMelderString colour;
+ MelderString_append (&colour, str_replace_regexp (colourString, compiledRE, L"{\\1,\\2,\\3}", 0, &nmatches_sub));
+ autoStrings thee = Strings_createAsTokens (colour.string);
+ return thee.transfer();
+}
+
+Graphics_Colour Strings_colourToValue (Strings me, long index) {
+ if (index < 0 || index > my numberOfStrings) {
+ return Graphics_GREY;
+ }
+ Graphics_Colour colourValue;
+ wchar_t *p = my strings[index];
+ while (*p == ' ' || *p == '\t') p ++;
+ *p = tolower (*p);
+ int first = *p;
+ if (first == '{') {
+ colourValue.red = Melder_atof (++ p);
+ p = (wchar_t *) wcschr (p, ',');
+ if (p == NULL) return Graphics_GREY;
+ colourValue.green = Melder_atof (++ p);
+ p = (wchar_t *) wcschr (p, ',');
+ if (p == NULL) return Graphics_GREY;
+ colourValue.blue = Melder_atof (++ p);
+ } else {
+ *p = tolower (*p);
+ if (wcsequ (p, L"black")) colourValue = Graphics_BLACK;
+ else if (wcsequ (p, L"white")) colourValue = Graphics_WHITE;
+ else if (wcsequ (p, L"red")) colourValue = Graphics_RED;
+ else if (wcsequ (p, L"green")) colourValue = Graphics_GREEN;
+ else if (wcsequ (p, L"blue")) colourValue = Graphics_BLUE;
+ else if (wcsequ (p, L"yellow")) colourValue = Graphics_YELLOW;
+ else if (wcsequ (p, L"cyan")) colourValue = Graphics_CYAN;
+ else if (wcsequ (p, L"magenta")) colourValue = Graphics_MAGENTA;
+ else if (wcsequ (p, L"maroon")) colourValue = Graphics_MAROON;
+ else if (wcsequ (p, L"lime")) colourValue = Graphics_LIME;
+ else if (wcsequ (p, L"navy")) colourValue = Graphics_NAVY;
+ else if (wcsequ (p, L"teal")) colourValue = Graphics_TEAL;
+ else if (wcsequ (p, L"purple")) colourValue = Graphics_PURPLE;
+ else if (wcsequ (p, L"olive")) colourValue = Graphics_OLIVE;
+ else if (wcsequ (p, L"pink")) colourValue = Graphics_PINK;
+ else if (wcsequ (p, L"silver")) colourValue = Graphics_SILVER;
+ else if (wcsequ (p, L"grey")) colourValue = Graphics_GREY;
+ else {
+ double grey = Melder_atof (p);
+ grey = grey < 0 ? 0 : (grey > 1 ? 1 : grey);
+ colourValue.red = colourValue.green = colourValue.blue = grey;
+ }
+ }
+ return colourValue;
+}
+
+long *Table_findRowsMatchingCriterion (Table me, const wchar_t *formula, Interpreter interpreter, long *numberOfMatches) {
+ try {
+ Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_UNKNOWN, TRUE);
+ autoNUMvector<long> selectedRows (1, my rows -> size);
+ long n = 0;
+ for (long irow =1; irow <= my rows -> size; irow++) {
+ struct Formula_Result result;
+ Formula_run (irow, 1, & result);
+ if (result.result.numericResult) {
+ selectedRows[++n] = irow;
+ }
+ }
+ if (n < 1) {
+ Melder_throw ("No rows selected.");
+ }
+ *numberOfMatches = n;
+ return selectedRows.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": cannot find matches.");
+ }
+}
+
+static bool Table_selectedColumnPartIsNumeric (Table me, long column, long *selectedRows, long numberOfSelectedRows) {
+ if (column < 1 || column > my numberOfColumns) return false;
+ for (long irow = 1; irow <= numberOfSelectedRows; irow++) {
+ if (! Table_isCellNumeric_ErrorFalse (me, selectedRows[irow], column)) return false;
+ }
+ return true;
+}
+
+// column and selectedRows are valid; *min & *max must be intialized
+static void Table_columnExtremesFromSelectedRows (Table me, long column, long *selectedRows, long numberOfSelectedRows, double *min, double *max) {
+ double cmin = 1e38, cmax = - cmin;
+ for (long irow = 1; irow <= numberOfSelectedRows; irow++) {
+ double val = Table_getNumericValue_Assert (me, selectedRows[irow], column);
+ if (val < cmin) { cmin = val; }
+ if (val > cmax) { cmax = val; }
+ }
+ *min = cmin;
+ *max = cmax;
+}
+
+void Table_barPlotWhere (Table me, Graphics g, const wchar_t *columnLabels, double ymin, double ymax,const wchar_t *labelColumn, double xoffsetFraction, double interbarFraction, double interbarsFraction, const wchar_t *colours, double angle, int garnish, const wchar_t *formula, Interpreter interpreter) {
+ try {
+ long numberOfColumns, numberOfRowMatches = 0;
+ autoNUMvector<long> columnIndex (Table_getColumnIndicesFromColumnLabelString (me, columnLabels, &numberOfColumns), 1);
+ long labelIndex = Table_findColumnIndexFromColumnLabel (me, labelColumn);
+ autoStrings colour = itemizeColourString (colours);// removes all spaces within { } so each {} can be parsed as 1 item
+
+ autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfRowMatches), 1);
+
+ if (ymax <= ymin) { // autoscaling
+ ymin = 1e38; ymax= - ymin;
+ for (long icol = 1; icol <= numberOfColumns; icol++) {
+ double cmin, cmax;
+ Table_columnExtremesFromSelectedRows (me, columnIndex[icol], selectedRows.peek(), numberOfRowMatches, &cmin, &cmax);
+ if (cmin < ymin) { ymin = cmin; }
+ if (cmax > ymax) { ymax = cmax; }
+ }
+ ymin = ymin > 0 ? 0 : ymin;
+ ymax = ymax < 0 ? 0 : ymax;
+ }
+ Graphics_setInner (g);
+ Graphics_setWindow (g, 0, 1, ymin, ymax);
+
+ long numberOfGroups = numberOfRowMatches;
+ long groupSize = numberOfColumns;
+ double bar_width = 1 / (numberOfGroups * groupSize + 2 * xoffsetFraction + (numberOfGroups - 1) * interbarsFraction + numberOfGroups * (groupSize - 1) * interbarFraction);
+ double dx = (interbarsFraction + groupSize + (groupSize - 1) * interbarFraction) * bar_width;
+
+ for (long icol = 1; icol <= groupSize; icol++) {
+ double xb = xoffsetFraction * bar_width + (icol - 1) * (1 + interbarFraction) * bar_width;
+ double x1 = xb;
+ Graphics_Colour color = Strings_colourToValue (colour.peek(), icol);
+ for (long irow = 1; irow <= numberOfRowMatches; irow++) {
+ double x2 = x1 + bar_width;
+ double y2 = Table_getNumericValue_Assert (me, selectedRows[irow], columnIndex[icol]);
+ y2 = y2 > ymax ? ymax : (y2 < ymin ? ymin : y2);
+ double y1 = ymin < 0 ? 0 : ymin;
+
+ Graphics_setColour (g, color);
+ Graphics_fillRectangle (g, x1, x2, y1, y2);
+ Graphics_setGrey (g, 0); /* Black */
+ Graphics_rectangle (g, x1, x2, y1, y2);
+
+ x1 += dx;
+ }
+ }
+
+ //Graphics_unsetInner (g);
+
+ if (garnish) {
+ if (labelIndex > 0) {
+ double y = ymin, xb = (xoffsetFraction + 0.5 * (groupSize + (groupSize - 1) * interbarFraction)) * bar_width;
+ double lineSpacing = Graphics_dyMMtoWC (g, 1.5 * Graphics_inqFontSize (g) * 25.4 / 72);
+ int currentFontSize = Graphics_inqFontSize (g);
+ Graphics_setTextRotation (g, angle);
+ if (angle < 0) {
+ y -= 0.3*lineSpacing;
+ xb -= 0.5 * bar_width;
+ Graphics_setFontSize (g, currentFontSize - (currentFontSize > 12 ? 2 : 1));
+ Graphics_setTextAlignment (g, Graphics_LEFT, Graphics_TOP);
+ } else if (angle > 0) {
+ y -= 0.3*lineSpacing;
+ xb += 0.5 * bar_width;
+ Graphics_setFontSize (g, currentFontSize - (currentFontSize > 12 ? 2 : 1));
+ Graphics_setTextAlignment (g, Graphics_RIGHT, Graphics_TOP);
+ } else {
+ Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_TOP);
+ }
+ for (long irow = 1; irow <= numberOfGroups; irow++) {
+ const wchar_t *label = Table_getStringValue_Assert (me, selectedRows[irow], labelIndex);
+ if (label) {
+ //Graphics_markBottom (g, xb, 0, 0, 0, label);
+ Graphics_text (g, xb, ymin - g -> vertTick, label); // was y
+ }
+ xb += dx;
+ }
+ Graphics_setFontSize (g, currentFontSize);
+ Graphics_setTextRotation (g, 0);
+ }
+ }
+ Graphics_unsetInner (g);
+ if (garnish) {
+ if (ymin * ymax < 0) {
+ Graphics_markLeft (g, 0, TRUE,TRUE, TRUE, NULL);
+ }
+
+ Graphics_drawInnerBox (g);
+ Graphics_marksLeft (g, 2, 1, 1, 0);
+ }
+ } catch (MelderError) {
+ //
+ }
+}
+
+static int Graphics_getConnectingLine (Graphics g, const wchar_t *text1, double x1, double y1, const wchar_t *text2, double x2, double y2, double *x3, double *y3, double *x4, double *y4) {
+ int drawLine = 0;
+ double width1 = Graphics_textWidth (g, text1), width2 = Graphics_textWidth (g, text2);
+ double h = Graphics_dyMMtoWC (g, 1.5 * Graphics_inqFontSize (g) * 25.4 / 72) / 1.5;
+ double xi[3], yi[3], xleft = x1 < x2 ? x1 : x2, xright = x2 > x1 ? x2 : x1;
+ int numberOfIntersections = NUMgetIntersectionsWithRectangle (x1, y1, x2, y2, xleft - width1 / 2, y1 - h/2, xleft +width1 / 2, y1 + h/2, xi, yi);
+ if (numberOfIntersections == 1) {
+ *x3 = xi[1]; *y3 = yi[1];
+ numberOfIntersections = NUMgetIntersectionsWithRectangle (x1, y1, x2, y2, xright - width2 / 2, y2 - h/2, xright + width2 / 2, y2 + h/2, xi, yi);
+ if (numberOfIntersections == 1) {
+ *x4 = xi[1]; *y4 = yi[1];
+ drawLine = 1;
+ }
+ }
+ return drawLine;
+}
+
+// take the xcolumn as labels if non-numeric column elsee as numbers and arrange distances accordingly.
+void Table_lineGraphWhere (Table me, Graphics g, long xcolumn, double xmin, double xmax, long ycolumn, double ymin, double ymax, const wchar_t *symbol, double angle, int garnish, const wchar_t *formula, Interpreter interpreter) {
+ try {
+ if (ycolumn < 1 || ycolumn > my rows -> size) return;
+ long numberOfSelectedRows = 0;
+ autoNUMvector<long> selectedRows (Table_findRowsMatchingCriterion (me, formula, interpreter, &numberOfSelectedRows), 1);
+ if (ymax <= ymin) { // autoscaling
+ Table_columnExtremesFromSelectedRows (me, ycolumn, selectedRows.peek(), numberOfSelectedRows, &ymin, &ymax);
+ }
+ // the following also catches xcolumn = 0 !
+ bool xIsNumeric = Table_selectedColumnPartIsNumeric (me, xcolumn, selectedRows.peek(), numberOfSelectedRows);
+ if (xmin >= xmax) {
+ if (xIsNumeric) {
+ Table_columnExtremesFromSelectedRows (me, xcolumn, selectedRows.peek(), numberOfSelectedRows, &xmin, &xmax);
+ } else {
+ xmin = 0; xmax = numberOfSelectedRows + 1;
+ }
+ }
+ Graphics_setInner (g);
+ Graphics_setWindow (g, xmin, xmax, ymin, ymax);
+ Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
+ double x1, y1;
+ double lineSpacing = Graphics_dyMMtoWC (g, 1.5 * Graphics_inqFontSize (g) * 25.4 / 72);
+ double symbolHeight = lineSpacing / 1.5;
+ for (long i = 1; i <= numberOfSelectedRows; i++) {
+ double y2 = Table_getNumericValue_Assert (me, selectedRows[i], ycolumn);
+ double x2 = xIsNumeric ? Table_getNumericValue_Assert (me, selectedRows[i], xcolumn) : i;
+ double symbolWidth = 0;
+ if (x2 >= xmin && (x2 <= xmax || x1 < xmax)) {
+ if (symbol && y2 >= ymin && y2 <= ymax && x2 <= xmax) {
+ Graphics_text (g, x2, y2, symbol);
+ symbolWidth = Graphics_textWidth (g, symbol);
+ }
+ if (i > 1) {
+ double x3, y3, x4, y4, xo1, yo1, xo2, yo2;
+ if (Graphics_getConnectingLine (g, symbol, x1, y1, symbol, x2, y2, &x3, &y3, &x4, &y4) &&
+ NUMclipLineWithinRectangle (x3, y3, x4, y4, xmin, ymin, xmax, ymax, &xo1, &yo1, &xo2, &yo2)) {
+ Graphics_line (g, xo1, yo1, xo2, yo2);
+ }
+ }
+ } else {
+ x2 = x2 < xmin ? xmin : xmax;
+ }
+ x1 = x2; y1 = y2;
+ }
+
+ if (garnish && ! xIsNumeric && xcolumn > 0) {
+ double y = ymin, dx = 0;
+
+ int currentFontSize = Graphics_inqFontSize (g);
+ Graphics_setTextRotation (g, angle);
+ if (angle < 0) {
+ y -= 0.3*lineSpacing;
+ dx = -0.5;
+ Graphics_setFontSize (g, currentFontSize - (currentFontSize > 12 ? 2 : 1));
+ Graphics_setTextAlignment (g, Graphics_LEFT, Graphics_TOP);
+ } else if (angle > 0) {
+ y -= 0.3*lineSpacing;
+ dx = 0.5;
+ Graphics_setFontSize (g, currentFontSize - (currentFontSize > 12 ? 2 : 1));
+ Graphics_setTextAlignment (g, Graphics_RIGHT, Graphics_TOP);
+ } else {
+ Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_TOP);
+ }
+ for (long i = 1; i <= numberOfSelectedRows; i++) {
+ double x2 = i;
+ if (x2 >= xmin && x2 <= xmax) {
+ const wchar_t *label = Table_getStringValue_Assert (me, selectedRows[i], xcolumn);
+ if (label) {
+ //Graphics_markBottom (g, xb, 0, 0, 0, label);
+ Graphics_text (g, x2 + dx, ymin - g -> vertTick, label); // was y
+ }
+ }
+ }
+ Graphics_setFontSize (g, currentFontSize);
+ Graphics_setTextRotation (g, 0);
+ }
+ Graphics_unsetInner (g);
+
+ if (garnish) {
+ Graphics_drawInnerBox (g);
+ Graphics_marksLeft (g, 2, 1, 1, 0);
+ if (xIsNumeric) {
+ Graphics_marksBottom (g, 2, 1, 1, 0);
+ }
+ }
+ } catch (MelderError) {
+ //
+ }
+}
+
+Table Table_extractRowsWhere (Table me, const wchar_t *formula, Interpreter interpreter) {
+ try {
+ Formula_compile (interpreter, me, formula, kFormula_EXPRESSION_TYPE_UNKNOWN, TRUE);
+ autoTable thee = Table_create (0, my numberOfColumns);
+ for (long icol = 1; icol <= my numberOfColumns; icol ++) {
+ autostring newLabel = Melder_wcsdup (my columnHeaders [icol]. label);
+ thy columnHeaders [icol]. label = newLabel.transfer();
+ }
+ for (long irow = 1; irow <= my rows -> size; irow ++) {
+ struct Formula_Result result;
+ Formula_run (irow, 1, & result);
+ if (result.result.numericResult) {
+ TableRow row = static_cast <TableRow> (my rows -> item [irow]);
+ autoTableRow newRow = Data_copy (row);
+ Collection_addItem (thy rows, newRow.transfer());
+ }
+ }
+ if (thy rows -> size == 0) {
+ Melder_warning (L"No row matches criterion.");
+ }
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": no Table could be extracted.");
+ }
+}
+
+
/* End of file Table_extensions.cpp */
diff --git a/dwtools/Table_extensions.h b/dwtools/Table_extensions.h
index 9fd6e09..da6156c 100644
--- a/dwtools/Table_extensions.h
+++ b/dwtools/Table_extensions.h
@@ -2,7 +2,7 @@
#define _Table_extensions_h_
/* Table_extensions.h
*
- * Copyright (C) 1993-2012 David Weenink
+ * Copyright (C) 1993-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
/*
djmw 20020411 initial GPL
- djmw 20120724 Latest modification.
+ djmw 20130602 Latest modification.
*/
#include "TableOfReal.h"
@@ -35,6 +35,8 @@
Table Table_createFromPetersonBarneyData ();
Table Table_createFromPolsVanNieropData ();
Table Table_createFromWeeninkData ();
+Table Table_createFromEspositoData ();
+Table Table_createFromGanongData ();
double Table_getMedianAbsoluteDeviation (Table me, long columnNumber);
@@ -55,7 +57,13 @@ void Table_quantileQuantilePlot (Table me, Graphics g, long xcolumn, long ycolum
void Table_quantileQuantilePlot_betweenLevels (Table me, Graphics g, long dataColumn, long factorColumn, wchar_t *xlevel, wchar_t *ylevel, long numberOfQuantiles, double xmin, double xmax, double ymin, double ymax, int labelSize, const wchar_t *label, int garnish);
void Table_boxPlots (Table me, Graphics g, long dataColumn, long factorColumn, double ymin, double ymax, int garnish);
+Table Table_extractRowsWhere (Table me, const wchar_t *formula, Interpreter interpreter);
+void Table_distributionPlotWhere (Table me, Graphics g, long dataColumn, double minimum, double maximum, long nBins, double freqMin, double freqMax, int garnish, const wchar_t *formula, Interpreter interpreter);
+void Table_barPlotWhere (Table me, Graphics g, const wchar_t *columnLabels, double ymin, double ymax, const wchar_t *labelColumn, double xoffsetFraction, double interbarFraction, double interbarsFraction, const wchar_t *colours, double angle, int garnish, const wchar_t *formula, Interpreter interpreter);
+
+void Table_lineGraphWhere (Table me, Graphics g, long xcolumn, double xmin, double xmax, long ycolumn, double ymin, double ymax, const wchar_t *symbol, double angle, int garnish, const wchar_t *formula, Interpreter interpreter);
void Table_printAsAnovaTable (Table me);
void Table_printAsMeansTable (Table me);
+
#endif // _Table_extensions_h_
diff --git a/dwtools/TextGrid_extensions.cpp b/dwtools/TextGrid_extensions.cpp
index a83585c..d84df4a 100644
--- a/dwtools/TextGrid_extensions.cpp
+++ b/dwtools/TextGrid_extensions.cpp
@@ -1,6 +1,6 @@
/* TextGrid_extensions.cpp
*
- * Copyright (C) 1993-2012 David Weenink
+ * Copyright (C) 1993-2013 David Weenink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -661,11 +661,24 @@ void IntervalTiers_append_inline (IntervalTier me, IntervalTier thee, bool prese
}
for (long iint = 1; iint <= thy intervals -> size; iint++) {
autoTextInterval ti = (TextInterval) Data_copy ((Data) thy intervals -> item[iint]);
- if (not preserveTimes) {
- ti -> xmin = xmax_previous;
- xmax_previous = ti -> xmax += time_shift;
+ if (preserveTimes) {
+ Collection_addItem (my intervals, ti.transfer());
+ } else {
+ /* the interval could be so short that if we test ti -> xmin < ti->xmax it might be true
+ * but after assigning ti->xmin = xmax_previous and ti->xmax += time_shift the test
+ * ti -> xmin < ti->xmax might be false!
+ * We want to make sure xmin and xmax are not register variables and therefore force double64
+ * by using volatile variables.
+ */
+ volatile double xmin = xmax_previous;
+ volatile double xmax = ti -> xmax + time_shift;
+ if (xmin < xmax) {
+ ti -> xmin = xmin; ti -> xmax = xmax;
+ Collection_addItem (my intervals, ti.transfer());
+ xmax_previous = xmax;
+ }
+ // else don't include interval
}
- Collection_addItem (my intervals, ti.transfer());
}
my xmax = preserveTimes ? thy xmax : xmax_previous;
} catch (MelderError) {
diff --git a/dwtools/manual_BSS.cpp b/dwtools/manual_BSS.cpp
index 6a1343f..c9f5717 100644
--- a/dwtools/manual_BSS.cpp
+++ b/dwtools/manual_BSS.cpp
@@ -101,7 +101,7 @@ INTRO (L"Detemines the @@Covariance|covariances@ between the channels of a selec
NORMAL (L"The covariance of a sound is determined by calculating the @@CrossCorrelationTable@ of a multichannel sound for a lag time equal to zero.")
MAN_END
-MAN_BEGIN (L"Sound: To Sound (blind source separation)...", L"djmw", 20130410)
+MAN_BEGIN (L"Sound: To Sound (blind source separation)...", L"djmw", 20130502)
INTRO (L"Analyze the selected multi-channel sound into its independent components by an iterative method.")
NORMAL (L"The @@blind source separation@ method to find the independent components tries to simultaneously diagonalize a number of "
"@@CrossCorrelationTable at s that are calculated from the multi-channel sound at different lag times.")
@@ -169,16 +169,16 @@ NORMAL (L"We start by creating a speech synthesizer that need to create two soun
CODE(L"synth = do (\"Create SpeechSynthesizer...\", \"English\", \"default\")")
CODE(L"s1 = do (\"To Sound...\", \"This is some text\", \"no\")")
NORMAL (L"The first speech sound was created from the text \"This is some text\" at a speed of 175 words per minute.")
-CODE(L"select synth")
+CODE(L"selectObject (synth)")
CODE(L"do (\"Set speech output settings...\", 44100, 0.01, 80, 50, 145, \"no\", \"IPA\")")
CODE(L"s2 = do (\"To Sound...\", \"Abracadabra, abra\", 0.01, 80, 50, 145, \"yes\", \"no\", \"no\", \"yes\")")
NORMAL (L"The second sound \"Abracadabra, abra\" was synthesized at 145 words per minute with a somewhat larger pitch excursion (80) than the previous sound (50).")
-CODE(L"plus s1")
+CODE(L"plusObject (s1)")
CODE(L"stereo = do (\"Combine to stereo\")")
NORMAL (L"We combine the two separate sounds into one stereo sound because our blind source separation works on multichannel sounds only.")
CODE(L"mm = do (\"Create simple MixingMatrix...\", \"mm\", 2, 2, \"1.0 2.0 2.0 1.0\")")
NORMAL (L"A two by two MixingMatrix is created.")
-CODE(L"plus stereo")
+CODE(L"plusObject (stereo)")
CODE(L"do (\"Mix\")")
NORMAL (L"The last command, Mix, creates a new two-channel sound where each channel is a linear mixture of the two "
"channels in the stereo sound, i.e. channel 1 is the sum of s1 and s2 with mixture strengths of 1 and 2, respectively. "
@@ -191,16 +191,16 @@ NORMAL (L"In the top panel the two speech sounds \"This is some text\" and \"abr
SCRIPT (6, 6, L" "
"syn = do (\"Create SpeechSynthesizer...\", \"English\", \"default\")\n"
"s1 = do (\"To Sound...\", \"This is some text\", \"no\")\n"
- "select syn\n"
+ "selectObject (syn)\n"
"do (\"Set speech output settings...\", 44100, 0.01, 80, 50, 145, \"no\", \"IPA\")\n"
"s2 = do (\"To Sound...\", \"abracadabra, abra\", \"no\")\n"
- "plus s1\n"
+ "plusObject (s1)\n"
"stereo = do (\"Combine to stereo\")\n"
"do (\"Select inner viewport...\", 1, 6, 0.1, 1.9)\n"
"do (\"Draw...\", 0, 0, 0, 0, \"no\", \"Curve\")\n"
"do (\"Draw inner box\")\n"
"mm = do (\"Create simple MixingMatrix...\", \"mm\", 2, 2, \"1.0 2.0 2.0 1.0\")\n"
- "plus stereo\n"
+ "plusObject (stereo)\n"
"mixed = do (\"Mix\")\n"
"do (\"Select inner viewport...\", 1, 6, 2.1, 3.9)\n"
"do (\"Draw...\", 0, 0, 0, 0, \"no\", \"Curve\")\n"
@@ -209,13 +209,7 @@ SCRIPT (6, 6, L" "
"do (\"Select inner viewport...\", 1, 6, 4.1, 5.9)\n"
"do (\"Draw...\", 0, 0, 0, 0, \"no\", \"Curve\")\n"
"do (\"Draw inner box\")\n"
- "plus syn\n"
- "plus stereo\n"
- "plus s1\n"
- "plus s2\n"
- "plus mixed\n"
- "plus mm\n"
- "do (\"Remove\")\n"
+ "removeObject (unmixed, syn, stereo, s1, s2, mixed, mm)\n"
)
NORMAL (L"The first two panels will not change between different sessions of praat. The last panel, which shows "
"the result of the blind source separation, i.e. unmixing, will not always be the same because of two things. In the first place the unmixing always starts with an initialisation with random values of the parameters that "
diff --git a/dwtools/manual_MDS.cpp b/dwtools/manual_MDS.cpp
index 28260d7..c307df6 100644
--- a/dwtools/manual_MDS.cpp
+++ b/dwtools/manual_MDS.cpp
@@ -1388,7 +1388,7 @@ INTRO (L"According to the measurement theory of @@Stevens (1951)@, there are fou
"two levels, Nominal and Ordinal, are often called %non-%metric. The last two are %metric.")
MAN_END
-MAN_BEGIN (L"Multidimensional scaling", L"djmw", 20130410)
+MAN_BEGIN (L"Multidimensional scaling", L"djmw", 20130502)
INTRO (L"This tutorial describes how you can use P\\s{RAAT} to "
"perform ##M#ulti##D#imensional ##S#caling (MDS) analysis.")
NORMAL (L"MDS helps us to represent %dissimilarities between objects as "
@@ -1420,9 +1420,8 @@ NORMAL (L"Select the Configuration and choose @@Configuration: Draw...|Draw...@
"and the following picture will result")
PICTURE (4.0, 4.0, drawLetterRConfigurationExample2)
NORMAL (L"The following script summarizes:")
-CODE (L"do (\"Create letter R example...\", 32.5)")
-CODE (L"select Dissimilarity R")
-CODE (L"do (\"To Configuration (monotone mds)...\", 2, \"Primary approach\", 0.00001, 50, 1)")
+CODE (L"dissimilarity = do (\"Create letter R example...\", 32.5)")
+CODE (L"configuration = do (\"To Configuration (monotone mds)...\", 2, \"Primary approach\", 0.00001, 50, 1)")
CODE (L"do (\"Draw...\", 1, 2, -0.8, 1.2, -0.8, 0.7, \"yes\")")
ENTRY (L"Obtaining the stress value")
NORMAL (L"Select the Dissimilarity and the Configuration together and query for "
@@ -1430,8 +1429,7 @@ NORMAL (L"Select the Dissimilarity and the Configuration together and query for
"@@Dissimilarity & Configuration: Get stress (monotone mds)...|"
"Get stress (monotone mds)... at . ")
NORMAL (L"The following script summarizes:")
-CODE (L"select Dissimilarity R")
-CODE (L"plus Configuration R_monotone")
+CODE (L"selectObject (dissimilarity, configuration)")
CODE (L"do (\"Get stress (monotone mds)...\", \"Primary approach\", \"Kruskals's "
"stress-1\")")
ENTRY (L"The Shepard diagram")
@@ -1440,8 +1438,7 @@ NORMAL (L"Select the Dissimilarity and the Configuration together to "
"draw the Shepard diagram at .")
PICTURE (4.0, 4.0, drawLetterRShepard)
NORMAL (L"The following script summarizes:")
-CODE (L"select Dissimilarity R")
-CODE (L"plus Configuration R_monotone")
+CODE (L"selectObject (dissimilarity, configuration)")
CODE (L"do (\"Draw Shepard diagram...\", 0, 200, 0, 2.2, 1, \"+\", \"yes\")")
ENTRY (L"The (monotone) regression")
NORMAL (L"Select the Dissimilarity and the Configuration together to "
@@ -1449,8 +1446,7 @@ NORMAL (L"Select the Dissimilarity and the Configuration together to "
"draw the monotone regression@ of distances on dissimilarities.")
PICTURE (4.0, 4.0, drawLetterRRegression)
NORMAL (L"The following script summarizes:")
-CODE (L"select Dissimilarity R")
-CODE (L"plus Configuration R_monotone")
+CODE (L"selectObject (dissimilarity, configuration)")
CODE (L"do (\"Draw monotone regresion...\", \"Primary approach\", 0, 200, 0, 2.2, 1, \"+\", \"yes\")")
NORMAL (L"When you enter %noiseRange = 0 in the form for the letter #R, perfect "
"reconstruction is possible. The Shepard diagram then will show "
@@ -1464,21 +1460,18 @@ NORMAL (L"When you can't have equal confidence in all the number in the "
"individual weights in the Weight object with the @@TableOfReal: Set "
"value...| Set value...@ command (remember: make %w__%ij_ = %w__%ji_).")
NORMAL (L"The following script summarizes:")
-CODE (L"select Dissimilarity R")
-CODE (L"do (\"To Weight\")")
+CODE (L"selectObject (dissimilarity)")
+CODE (L"weight = do (\"To Weight\")")
CODE (L"! Change [i][j] and [j][i] cells in the Weight object")
CODE (L"do (\"Set value...\", i, j, val)")
CODE (L"do (\"Set value...\", j, i, val)")
CODE (L"...")
CODE (L"! now we can do a weighed analysis.")
-CODE (L"select Dissimilarity R")
-CODE (L"plus Weight R")
+CODE (L"selectObject (dissimilarity, weight)")
CODE (L"do (\"To Configuration (monotone mds)...\", 2, \"Primary approach\", 0.00001, 50, 1)")
NORMAL (L"You can also query the @stress values with three objects selected. "
"The following script summarizes:")
-CODE (L"select Dissimilarity R")
-CODE (L"plus Weight R")
-CODE (L"plus Configuration R_s_monotone")
+CODE (L"selectObject (dissimilarity, weight, configuration)")
CODE (L"do (\"Get stress (monotone mds)...\", \"Primary approach\", \"Kruskals's "
"stress-1\")")
ENTRY (L"Using a start Configuration")
@@ -1489,9 +1482,7 @@ NORMAL (L"You could also use a Configuration object as a starting "
"You can than use this Configuration object as a "
"starting point for further analysis:")
NORMAL (L"The following script summarizes:")
-CODE (L"select Dissimilarity R")
-CODE (L"plus Configuration R_monotone")
-CODE (L"plus Weight R")
+CODE (L"selectObject (dissimilarity, configuration, weight)")
CODE (L"do (\"To Configuration (monotone mds)...\", 2, \"Primary approach\", 0.00001, 50, 1)")
ENTRY (L"Multiple Dissimilarity's (INDSCAL)")
NORMAL (L"When you have multiple Dissimilarity objects you can also perform "
diff --git a/dwtools/manual_dwtools.cpp b/dwtools/manual_dwtools.cpp
index 131bb91..ec71fb1 100644
--- a/dwtools/manual_dwtools.cpp
+++ b/dwtools/manual_dwtools.cpp
@@ -19,18 +19,16 @@
/*
djmw 20020313 GPL
- djmw 20101101 Latest modification
+ djmw 20130620 Latest modification
*/
#include "ManPagesM.h"
#include "Sound_extensions.h"
#include "TableOfReal_extensions.h"
-#ifndef _Configuration_h_
- #include "Configuration.h"
-#endif
-#ifndef _Discriminant_h_
- #include "Discriminant.h"
-#endif
+#include "Table_extensions.h"
+#include "Configuration.h"
+#include "Discriminant.h"
+
static TableOfReal getStandardizedLogFrequencyPolsData (int includeLevels) {
autoTableOfReal me = TableOfReal_createFromPolsData_50males (includeLevels);
@@ -473,7 +471,7 @@ NORMAL (L"The scores for the dependent data will be in the lower numbered column
MAN_END
-MAN_BEGIN (L"Canonical correlation analysis", L"djmw", 20130407)
+MAN_BEGIN (L"Canonical correlation analysis", L"djmw", 20130502)
INTRO (L"This tutorial will show you how to perform canonical correlation "
"analysis with P\\s{RAAT}.")
ENTRY (L"1. Objective of canonical correlation analysis")
@@ -495,7 +493,7 @@ NORMAL (L"As an example, we will use the dataset from @@Pols et al. (1973)@ "
"@@discriminant analysis@ tutorial you can find how to get these data, "
"how to take the logarithm of the formant frequency values and how to "
"standardize them. The following script summarizes:")
-CODE (L"do (\"Create TableOfReal (Pols 1973)...\", \"yes\")")
+CODE (L"pols50m = do (\"Create TableOfReal (Pols 1973)...\", \"yes\")")
CODE (L"do (\"Formula...\", \"if col < 4 then log10 (self) else self endif\")")
CODE (L"do (\"Standardize columns\")")
NORMAL (L"Before we start with the %canonical correlation analysis we will first have "
@@ -509,7 +507,7 @@ CODE (L"L1 0.384 -0.106 0.113 1 -0.038 0.085")
CODE (L"L2 -0.505 0.526 -0.038 -0.038 1 0.128")
CODE (L"L3 -0.014 -0.568 0.019 0.085 0.128 1")
NORMAL (L"The following script summarizes:")
-CODE (L"select TableOfReal pols_50males")
+CODE (L"selectObject (pols50m)")
CODE (L"do (\"To Correlation\")")
CODE (L"do (\"Draw as numbers...\", 1, 0, \"decimal\", 3)")
NORMAL (L"The correlation matrix shows that high correlations exist between some "
@@ -539,8 +537,8 @@ NORMAL (L"Select the TableOfReal and choose from the dynamic menu the option "
"\"Multivariate statistics\" action button. We fill out the form and supply "
"3 for %%Dimension of dependent variate%. The resulting CCA object will bear "
"the same name as the TableOfReal object. The following script summarizes:")
-CODE (L"select TableOfReal pols_50males")
-CODE (L"do (\"To CCA...\", 3)")
+CODE (L"selectObject (pols50m)")
+CODE (L"cca = do (\"To CCA...\", 3)")
ENTRY (L"3. How to get the canonical correlation coefficients")
NORMAL (L"You can get the canonical correlation coefficients by queries of the CCA "
"object. You will find that the three canonical correlation coefficients, "
@@ -571,8 +569,7 @@ CODE (L"v3 . . 0.070 . . 1")
NORMAL (L"The scores with a dot are zero to numerical precision. In this table the "
"only correlations that differ from zero are the canonical correlations. "
"The following script summarizes:")
-CODE (L"select CCA pols_50males")
-CODE (L"plus TableOfReal pols_50males")
+CODE (L"selectObject (cca, pols50m)")
CODE (L"do (\"To TableOfReal (scores)...\", 3)")
CODE (L"do (\"To Correlation\")")
CODE (L"do (\"Draw as numbers if...\", 1, 0, \"decimal\", 2, \"abs(self) > 1e-14\")")
@@ -1145,7 +1142,7 @@ INTRO (L"Extract those rows from the selected @TableOfReal object whose Mahalano
"quantile range.")
MAN_END
-MAN_BEGIN (L"Covariance & TableOfReal: To TableOfReal (mahalanobis)...", L"djmw", 20130407)
+MAN_BEGIN (L"Covariance & TableOfReal: To TableOfReal (mahalanobis)...", L"djmw", 20130502)
INTRO (L"Calculate Mahalanobis distance for the selected @TableOfReal with respect to the "
"selected @Covariance object.")
ENTRY (L"Setting")
@@ -1165,17 +1162,17 @@ CODE (L"n = 100000")
CODE (L"t0 = do (\"Create TableOfReal...\", \"table\", n, 1)")
CODE (L"do (\"Formula...\", randomGauss(0,1))")
CODE (L"c = do (\"To Covariance\")")
-CODE (L"plus t0")
+CODE (L"selectObject (c, t0)")
CODE (L"ts = do (\"To TableOfReal (mahalanobis)...\", \"no\")")
CODE (L"")
CODE (L"for nsigma to 5")
-CODE1 (L" select ts")
-CODE1 (L" do (\"Extract rows where...\", \"self < nsigma\")")
+CODE1 (L" selectObject (ts)")
+CODE1 (L" extraction = do (\"Extract rows where...\", \"self < nsigma\")")
CODE1 (L" nr = do (\"Get number of rows\")")
CODE1 (L" nrp = nr / n * 100")
CODE1 (L" expect = (1 - 2 * gaussQ (nsigma)) * 100")
CODE1 (L" writeInfoLine (nsigma, \"-sigma: \", nrp, \"%, \", expect, \"%\")")
-CODE1 (L" do(\"Remove\")")
+CODE1 (L" removeObject (extraction)")
CODE (L"endfor")
MAN_END
@@ -1340,7 +1337,7 @@ NORMAL (L"The following script generates 12 static Shepard tone complexes, 1 sem
CODE (L"fadeTime = 0.010")
CODE (L"for i to 12")
CODE1 (L"fraction = (i-1)/12")
-CODE1 (L"do (\"Create Sound from Shepard tone...\", \"s\" + string$(i), 0, 0.1, 22050, 4.863, 10, 0, 34, fraction)")
+CODE1 (L"do (\"Create Sound from Shepard tone...\", \"s\" + string\\$ (i), 0, 0.1, 22050, 4.863, 10, 0, 34, fraction)")
CODE1 (L"do (\"Fade in...\", 0, 0, fadeTime, \"no\")")
CODE1 (L"do (\"Fade out...\", 0, 0.1, -fadeTime, \"no\")")
CODE (L"endfor")
@@ -1482,7 +1479,7 @@ LIST_ITEM (L"\\bu Draw eigenvector...")
LIST_ITEM (L"\\bu @@Discriminant: Draw sigma ellipses...|Draw sigma ellipses...@")
MAN_END
-MAN_BEGIN (L"Discriminant analysis", L"djmw", 220130410)
+MAN_BEGIN (L"Discriminant analysis", L"djmw", 20130502)
INTRO (L"This tutorial will show you how to perform discriminant analysis with P\\s{RAAT}")
NORMAL (L"As an example, we will use the dataset from @@Pols et al. (1973)@ "
"with the frequencies and levels of the first three formants from the 12 "
@@ -1502,7 +1499,7 @@ NORMAL (L"Pols et al. use logarithms of frequency values, we will too. Because "
"the measurement units in the first three columns are in Hz and in the last "
"three columns in dB, it is probably better to standardize the columns. "
"The following script summarizes our achievements up till now:")
-CODE (L"do (\"Create TableOfReal (Pols 1973)...\", \"yes\"")
+CODE (L"table = do (\"Create TableOfReal (Pols 1973)...\", \"yes\"")
CODE (L"do (\"Formula...\", \"if col < 4 then log10 (self) else self fi\"")
CODE (L"do (\"Standardize columns\"")
CODE (L"\\# change the column labels too, for nice plot labels.")
@@ -1518,7 +1515,7 @@ NORMAL (L"To get an indication of what these data look like, we make a scatter "
"log-formant-frequency. With the next script fragment you can reproduce the "
"following picture.")
CODE (L"do (\"Viewport...\", 0, 5, 0, 5)")
-CODE (L"select TableOfReal pols_50males")
+CODE (L"selectObject (table)")
CODE (L"do (\"Draw scatter plot...\", 1, 2, 0, 0, -2.9, 2.9, -2.9, 2.9, 10, \"yes\", \"+\", \"yes\")")
PICTURE (5, 5, drawPolsF1F2_log)
NORMAL (L"Apart from a difference in scale this plot is the same as fig. 3 in the "
@@ -1529,8 +1526,8 @@ NORMAL (L"Select the TableOfReal and choose from the dynamic menu the option "
"in the \"Multivariate statistics\" action button. The resulting Discriminant "
"object will bear the same name as the TableOfReal object. The following "
"script summarizes:")
-CODE (L"select TableOfReal pols_50males")
-CODE (L"do (\"To Discriminant\")")
+CODE (L"selectObject (table)")
+CODE (L"discrimimant = do (\"To Discriminant\")")
ENTRY (L"2. How to project data on the discriminant space")
NORMAL (L"You select a TableOfReal and a Discriminant object together and choose: "
"@@Discriminant & TableOfReal: To Configuration...|To Configuration... at . "
@@ -1540,8 +1537,7 @@ NORMAL (L"You select a TableOfReal and a Discriminant object together and choose
"configuration are the eigenvectors from the Discriminant.")
PICTURE (5, 5, drawPolsDiscriminantConfiguration)
NORMAL (L"The following script summarizes:")
-CODE (L"select TableOfReal pols_50males")
-CODE (L"plus Discriminant pols_50males")
+CODE (L"selectObject (table, discriminant)")
CODE (L"do (\"To Configuration...\", 0)")
CODE (L"do (\"Viewport...\", 0, 5, 0, 5)")
CODE (L"do (\"Draw...\", 1, 2, -2.9, 2.9, -2.9, 2.9, 12, \"yes\", \"+\", \"yes\")")
@@ -1558,7 +1554,7 @@ NORMAL (L"Select the Discriminant object and choose @@Discriminant: Draw sigma "
"standardized log %F__1_ vs log %F__2_ plane. When the data are multinormally distributed, "
"a 1-%\\si ellipse will cover approximately 39.3\\% of the data. "
"The following code summarizes:")
-CODE (L"select Discriminant pols_50males")
+CODE (L"selectObject (discriminant)")
CODE (L"do (\"Draw sigma ellipses...\", 1.0, \"no\", 1, 2, -2.9, 2.9, -2.9, 2.9, 12, \"yes\")")
PICTURE (5, 5, drawPolsF1F2ConcentrationEllipses)
ENTRY (L"4. How to classify")
@@ -1720,7 +1716,7 @@ NORMAL (L"The number of columns in the TableOfReal must equal the dimension of t
NORMAL (L"See also @@Eigen & TableOfReal: Project... at .")
MAN_END
-MAN_BEGIN (L"Discriminant & TableOfReal: To TableOfReal (mahalanobis)...", L"djmw", 20130410)
+MAN_BEGIN (L"Discriminant & TableOfReal: To TableOfReal (mahalanobis)...", L"djmw", 20130502)
INTRO (L"Calculate Mahalanobis distances for the selected @TableOfReal with respect to one group in the "
"selected @Discriminant object.")
ENTRY (L"Settings")
@@ -1734,14 +1730,12 @@ ENTRY (L"Example")
NORMAL (L"Calculate the number of datapoints that are within the one-sigma elipses of two different groups, i.e. "
"the number of data points that are in the overlapping area. ")
NORMAL (L"Suppose the group labels are \\o/ and \\yc.")
-CODE (L"t = do (\"Create TableOfReal (Pols 1973)...\", \"no\")")
+CODE (L"pols50m = do (\"Create TableOfReal (Pols 1973)...\", \"no\")")
CODE (L"do (\"Formula...\", \"log10(self)\")")
-CODE (L"d = do (\"To Discriminant\")")
-CODE (L"select t")
-CODE (L"plus d")
+CODE (L"discriminant = do (\"To Discriminant\")")
+CODE (L"selectObject (pols50m, discriminant)")
CODE (L"t1 = do (\"To TableOfReal (mahalanobis)...\", \"\\bso/\", \"no\")")
-CODE (L"select t")
-CODE (L"plus d")
+CODE (L"selectObject (pols50m, discriminant)")
CODE (L"t2 = do (\"To TableOfReal (mahalanobis)...\", \"\\bsyc\", \"no\")")
NORMAL (L"Now we count when both the t1 and t2 values are smaller than 1 (sigma):")
CODE (L"do (\"Copy...\", \"tr\")")
@@ -1892,7 +1886,7 @@ DEFINITION (L"the number of different symbols in the source symbol set that you
"that fall in a %rest% category. If you don't want to treat any source symbol is a special way you may set this value 0.")
MAN_END
-MAN_BEGIN (L"EditCostsTable", L"djmw", 20130410)
+MAN_BEGIN (L"EditCostsTable", L"djmw", 20130502)
INTRO (L"One of the @@types of objects@ in Praat.")
NORMAL (L"The EditCostsTable determines the %%string edit costs%, i.e. the costs involved in changing one string of "
"symbols (the %%source%) into another one (the %%target%). "
@@ -1902,18 +1896,16 @@ NORMAL (L"The EditCostsTable determines the %%string edit costs%, i.e. the costs
"one insertion (i), one deletion (d) and three substitutions (s) as the following figure shows.")
SCRIPT (4, 1.0, L"target = do (\"Create Strings as characters...\", \"intention\")\n"
"source = do (\"Create Strings as characters...\", \"execution\")\n"
- "plus target\n"
+ "selectObject (source, target)\n"
"edt = do (\"To EditDistanceTable\")\n"
"do (\"Draw edit operations\")\n"
- "plus target\n"
- "plus source\n"
- "do (\"Remove\")\n")
+ "removeObject (edt, target, source)\n")
NORMAL (L"The figure above was produced with default values for the costs, i.e. the insertion and deletion costs were 1.0 while the "
"substitution cost was 2.0. The actual edit distance between the target and source strings is calculated by the @@EditDistanceTable@ "
"which uses an EditCostsTable to access the specific string edit costs. The figure above was produced by the following commands:")
CODE (L"target = do (\"Create Strings as characters...\", \"intention\")")
CODE (L"source = do (\"Create Strings as characters...\", \"execution\")")
-CODE (L"plus target")
+CODE (L"plusObject (target)")
CODE (L"edt = do (\"To EditDistanceTable\")")
CODE (L"do (\"Draw edit operations\")")
NORMAL (L"The default EditCostsTable which is in every new EditDistanceTable object has only two rows and two columns, "
@@ -1978,23 +1970,21 @@ ENTRY (L"How to use a special EditCostsTable")
NORMAL (L"After creating the special EditCostsTable you select it together with the EditDistanceTable and issue the command @@EditDistanceTable & EditCostsTable: Set new edit costs|Set new edit costs at . The EditDistanceTable will then find the minimum edit distance based on the new cost values.")
MAN_END
-MAN_BEGIN (L"EditDistanceTable", L"djmw", 20130410)
+MAN_BEGIN (L"EditDistanceTable", L"djmw", 20130502)
INTRO (L"One of the @@types of objects@ in Praat.")
NORMAL (L"An EditDistanceTable shows the accumulated distances between a target string and a source string. "
"For example, the accumulated distances between the target string \"intention\" and the source string "
"\"execution\" can be expressed by the following EditDistanceTable:")
SCRIPT (5, 3.5, L"target = do (\"Create Strings as characters...\", \"intention\")\n"
"source = do (\"Create Strings as characters...\", \"execution\")\n"
- "plus target\n"
+ "selectObject (source, target)\n"
"edt = do (\"To EditDistanceTable\")\n"
"do (\"Draw...\", \"decimal\", 1, 0)\n"
- "plus target\n"
- "plus source\n"
- "do (\"Remove\")\n")
+ "removeObject (edt, target, source)\n")
NORMAL (L"This figure was created by issuing the following commands:")
CODE (L"target = do (\"Create Strings as characters...\", \"intention\")")
CODE (L"source = do (\"Create Strings as characters...\", \"execution\")")
-CODE (L"plus target")
+CODE (L"plusObject (target)")
CODE (L"edt = do (\"To EditDistanceTable\")")
CODE (L"do (\"Draw...\", \"decimal\", 1, 0)")
NORMAL (L"The target string is always displayed vertically while the source string is displayed horizontally and the origin is at the bottom-left corner of the table. "
@@ -2008,12 +1998,10 @@ NORMAL (L"If we trace the path from its start at the origin to its end, we see t
"The next diagonal step substitutes an \"n\" for a \"u\". The path now continues in the diagonal direction until the end point and only identical substitutions occur in the last part. The following figure shows these operations more explicitly.")
SCRIPT (4, 1.5, L"target = do (\"Create Strings as characters...\", \"intention\")\n"
"source = do (\"Create Strings as characters...\", \"execution\")\n"
- "plus target\n"
+ "plusObject (target)\n"
"edt = do (\"To EditDistanceTable\")\n"
"do (\"Draw edit operations\")\n"
- "plus target\n"
- "plus source\n"
- "do (\"Remove\")\n")
+ "removeObject (edt, target, source)\n")
NORMAL (L"The value of the accumulated costs in a cell of the table is computed by taking the minimum of the accumulated distances from three possible paths that end in the current cell, i.e. the paths that come from the %%left%, from the %%diagonal% and from %%below%.")
CODE (L"dist[i,j] = min (d__left_, d__diag_, d__below_), ")
NORMAL (L"where ")
@@ -2630,7 +2618,7 @@ ENTRY (L"Algorithm")
NORMAL (L"We determine how often a horizontal line extending from the point crosses the polygon. If the number of crossings is even, the point is on the outside, else on the inside. Special care is taken to be able to detect if a point is on the boundary of the polygon. The used algorithm is from @@Hormann & Agathos (2001)@")
MAN_END
-MAN_BEGIN (L"Polygon: Simplify", L"djmw", 20130409)
+MAN_BEGIN (L"Polygon: Simplify", L"djmw", 20130502)
INTRO (L"Removes collinear vertices from a @@Polygon at .")
ENTRY (L"Example")
SCRIPT (4, 4,
@@ -2641,8 +2629,7 @@ SCRIPT (4, 4,
"p2 = do (\"Simplify\")\n"
"do (\"Colour...\", \"Black\")\n"
"do (\"Paint circles...\", 0, 0, 0, 0, 1.5)\n"
- "plus p1\n"
- "do (\"Remove\")\n"
+ "removeObject (p1, p2)\n"
)
NORMAL (L"Given the Polygon with the seven vertices indicated by the red open circles, the Simplify action results in the Polygon with four vertices indicated by the filled black circles.")
MAN_END
@@ -3357,7 +3344,7 @@ NORMAL (L"Draw parts where pitch is larger than 300 Hz in red:")
CODE (L"s = selected (\"Sound\")")
CODE (L"p = do (\"To Pitch...\", 0, 75, 600)")
CODE (L"pt = do (\"Down to PitchTier\")")
-CODE (L"select s")
+CODE (L"selectObject (s)")
CODE (L"do (\"Colour...\", \"Red\")")
CODE (L"do (\"Draw where...\", 0, 0, -1, 1, \"yes\", \"Curve\", \"Object_'pt'(x) > 300\")")
CODE (L"do (\"Colour...\", \"Black\")")
@@ -3458,7 +3445,7 @@ LIST_ITEM (L"2. We perform a filter bank analysis on a linear frequency scale. "
"Pitch: To FormantFilter...@ for details).")
MAN_END
-MAN_BEGIN (L"Sound: Paint where...", L"djmw", 20130409)
+MAN_BEGIN (L"Sound: Paint where...", L"djmw", 20130502)
INTRO (L"A command to paint only those parts of a @Sound where a condition holds. The painted area is the area "
"between the Sound and a horizontal line at a certain level.")
ENTRY (L"Settings")
@@ -3505,7 +3492,7 @@ SCRIPT (8, 5,
L"s = do (\"Create Sound from formula...\", \"s\", \"Mono\", 0, 1, 10000, \"0.5*sin(2*pi*5*x)\")\n"
"do (\"Paint where...\", \"Red\", 0, 0, -1, 1, 0, \"no\", \"self<0\")\n"
"do (\"Paint where...\", \"Green\", 0, 0, -1, 1, 0, \"yes\", \"self>0\")\n"
- "do (\"Remove\")\n")
+ "removeObject (s)\n")
ENTRY (L"Example 3")
NORMAL (L"To give an indication that the area under a 1/x curve between the points %a and %b and the area "
"between %c and %d are equal if %b/%a = %d/%c. For example, for %a=1, %b=2, %c=4 and %d=8: ")
@@ -3517,17 +3504,17 @@ CODE (L"do (\"One mark bottom...\", 2, \"yes\", \"yes\", \"no\", \"\")")
CODE (L"do (\"One mark bottom...\", 4, \"yes\", \"yes\", \"no\", \"\")")
CODE (L"do (\"One mark bottom...\", 8, \"yes\", \"yes\", \"no\", \"\")")
SCRIPT (8, 5,
- L"do (\"Create Sound from formula...\", \"1dx\", \"Mono\", 0, 20, 100, \"1/x\")\n"
+ L"s = do (\"Create Sound from formula...\", \"1dx\", \"Mono\", 0, 20, 100, \"1/x\")\n"
"do (\"Draw...\", 0, 20, 0, 1.5, \"yes\", \"Curve\")\n"
"do (\"Paint where...\", \"Grey\", 0, 20, 0, 1.5, 0, \"yes\", \"(x >= 1 and x <2) or (x>=4 and x<8)\")\n"
"do (\"One mark bottom...\", 1, \"yes\", \"yes\", \"no\", \"\")\n"
"do (\"One mark bottom...\", 2, \"yes\", \"yes\", \"no\", \"\")\n"
"do (\"One mark bottom...\", 4, \"yes\", \"yes\", \"no\", \"\")\n"
"do (\"One mark bottom...\", 8, \"yes\", \"yes\", \"no\", \"\")\n"
- "do (\"Remove\")\n")
+ "removeObject (s)\n")
MAN_END
-MAN_BEGIN (L"Sounds: Paint enclosed...", L"djmw", 20130409)
+MAN_BEGIN (L"Sounds: Paint enclosed...", L"djmw", 20130502)
INTRO (L"Paints the area between the two selected @@Sound at s. ")
ENTRY (L"Settings")
SCRIPT (5.4, Manual_SETTINGS_WINDOW_HEIGHT (4), L""
@@ -3547,17 +3534,17 @@ ENTRY (L"Example")
NORMAL (L"The following script paints the area enclosed between a sine tone of 5 Hz and the straight line %y = %x/2.")
CODE (L"s1 = do (\"Create Sound from formula...\", \"sine\", \"Mono\", 0, 1, 10000, \"1/2 * sin(2*pi*5*x)\")")
CODE (L"s2 = do (\"Create Sound from formula...\", \"line\", \"Mono\", 0, 1, 10000, \"x / 2\")")
-CODE (L"plus s1")
+CODE (L"plusObject (s1)")
CODE (L"do (\"Paint enclosed...\", \"Grey\", 0, 0, -1, 1, \"yes\")")
SCRIPT ( 4, 2,
- L"s1 = do (\"Create Sound from formula...\", \"sine\", \"Mono\", 0, 1, 10000, \"1/2 * sin(2*pi*5*x)\")\n"
- "s2 = do (\"Create Sound from formula...\", \"line\", \"Mono\", 0, 1, 10000, \"x / 2\")\n"
- "plus s1\n"
+ L"s1 = do (\"Create Sound from formula...\", \"sine\", \"Mono\", 0, 1, 10000, \"1/2 * sin(2*pi*5*x)\")\n"
+ "s2 = do (\"Create Sound from formula...\", \"line\", \"Mono\", 0, 1, 10000, \"x / 2\")\n"
+ "selectObject (s1, s2)\n"
"do (\"Paint enclosed...\", \"Grey\", 0, 0, -1, 1, \"yes\")\n"
- "do (\"Remove\")\n")
+ "removeObject (s1, s2)\n")
MAN_END
-MAN_BEGIN (L"Sound: To Polygon...", L"djmw", 20130409)
+MAN_BEGIN (L"Sound: To Polygon...", L"djmw", 20130502)
INTRO (L"A command that creates a @@Polygon@ from a selected @@Sound@, where the Polygon's "
" points are defined by the (%time, %amplitude) pairs of the sound. ")
ENTRY (L"Settings")
@@ -3576,7 +3563,7 @@ CODE (L"s = do (\"Create Sound from formula...\", \"s\", \"Mono\", 0, 1, 10000,
CODE (L"\\# Connection y-value is at amplitude -1: area under the curve.")
CODE (L"p1 = do (\"To Polygon...\", 1, 0, 0, -1, 1, -1)")
CODE (L"do (\"Paint...\", \"{1,0,0}\", 0, 0, -1, 1)")
-CODE (L"select s")
+CODE (L"selectObject (s)")
CODE (L"\\# Connection y-value is now at amplitude 1: area above the curve.")
CODE (L"p2 = do (\"To Polygon...\", 1, 0, 0, -1, 1, 1)")
CODE (L"do (\"Paint...\", \"{0,1,0}\", 0, 0, -1, 1)")
@@ -3584,12 +3571,10 @@ SCRIPT (4.5, 2,
L"s = do (\"Create Sound from formula...\", \"s\", \"Mono\", 0, 1, 10000, \"0.5*sin(2*pi*5*x)\")\n"
"p1 = do (\"To Polygon...\", 1, 0, 0, -1, 1, -1)\n"
"do (\"Paint...\", \"{1,0,0}\", 0, 0, -1, 1)\n"
- "do (\"Remove\")\n"
- "select s\n"
+ "selectObject (s)\n"
"p2 = do (\"To Polygon...\", 1, 0, 0, -1, 1, 1)\n"
"do (\"Paint...\", \"{0,1,0}\", 0, 0, -1, 1)\n"
- "plus s\n"
- "do (\"Remove\")\n"
+ "removeObject (p2, p1, s)\n"
)
MAN_END
@@ -3992,26 +3977,193 @@ NORMAL (L"@@Tenreiro (2009)@ recommends %h__%%s% _= 0.448 + 0.026\\.c%d for sho
" %h__%%l%_ = 0.928 + 0.049\\.c%d for long tailed alternatives.")
MAN_END
-MAN_BEGIN (L"Table: Normal probability plot...", L"djmw", 20130207)
+MAN_BEGIN (L"Table: Normal probability plot...", L"djmw", 20130619)
NORMAL (L"In a normal probability plot, the data in the selected column of the @Table are plotted "
"against a normal distribution in such a way that the points should form approximately a straight line. "
"Departures from a straight line indicate departures from normality.")
ENTRY (L"Settings")
TAG (L"##Number of quantiles#")
DEFINITION (L"the number of quantile points, %n, in the plot. From this number %n, the quantile points are "
- "determined as follows: the last quantile point %q__%n_ = 0.5^^1/%n^ and the first quantile point "
+ "determined as follows: the last quantile point is %q__%n_ = 0.5^^1/%n^ and the first quantile point is "
"%q__1_=1\\--%q__%n_. The intermediate quantile points %q__%i_ are determined according to "
"%q__%i_=(%i \\-- 0.3175)/(%n + 0.365), where %i runs from 2 to %n\\--1.")
TAG (L"##Number of sigmas#")
DEFINITION (L"determines the horizontal and vertical drawing ranges in units of standard deviations. ")
MAN_END
-MAN_BEGIN (L"Table: Quantile-quantile plot...", L"djmw", 20120810)
-NORMAL (L"In a quantile-quantile plot the quantiles of the data in the first selected column of the @Table is plotted against "
+MAN_BEGIN (L"Table: Quantile-quantile plot...", L"djmw", 20130619)
+NORMAL (L"In a quantile-quantile plot the quantiles of the data in the first selected column of the @Table are plotted against "
"the quantiles of the data in the second selected column. If the two sets come from a population with the "
"same distribution, the points should fall approximately along the reference line.")
MAN_END
+MAN_BEGIN (L"Table: Bar plot where...", L"djmw", 20130624)
+INTRO (L"Draws a bar plot from data in one or more columns of the selected @Table. In a bar plot the horizontal axis has nominal values (labels). ")
+ENTRY (L"Settings")
+SCRIPT (6, Manual_SETTINGS_WINDOW_HEIGHT (10), L""
+ Manual_DRAW_SETTINGS_WINDOW ("Table: Bar plot where", 10)
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Vertical column(s)", "")
+ Manual_DRAW_SETTINGS_WINDOW_RANGE("Vertical range", "0.0", "0.0 (=autoscaling)")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Column with labels", "")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Distance of first bar from border", "1.0")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Distance between bar groups", "1.0")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Distance between bars within group", "0.0")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Colours (0-1, name, {r,g,b})", "Grey")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Label text angle (degrees)", "0.0")
+ Manual_DRAW_SETTINGS_WINDOW_BOOLEAN("Garnish", 1)
+ Manual_DRAW_SETTINGS_WINDOW_TEXT("Formula:", "row>1 and row < 10")
+)
+TAG (L"##Vertical column(s)")
+DEFINITION (L"you list the table columns that you want to represent in the bar plot. The number of selected columns is the group size.")
+TAG (L"##Vertical range")
+DEFINITION (L"determine the lower and upper limit of the display.")
+TAG (L"##Column with labels")
+DEFINITION (L"determines the column whose labels will be put at the bottom of the plot.")
+TAG (L"##Distance of first bar from border")
+DEFINITION (L"determines how far the first (and last) bar wil be positioned from the borders (in units of the width of one bar).")
+TAG (L"##Distance between bar groups")
+DEFINITION (L"determines how far groups of bars are from each other. ")
+TAG (L"##Distance between bars within group")
+DEFINITION (L"determines the distance between the bars within each group.")
+TAG (L"##Colours")
+DEFINITION (L"determines the colours of the bars in a group.")
+TAG (L"##Label text angle (degrees)")
+DEFINITION (L"determines the angle of the labels written below the plot. If you have very long label texts you can prevent the label texts from overlapping.")
+TAG (L"##Formula:")
+DEFINITION (L"can be used to supply an expression to select only those rows for plotting where the expression evaluates to %%true%. A 1 value always evaluates to %%true%.")
+ENTRY (L"Examples")
+NORMAL (L"@@Keating & Esposito (2006)@ present a bar plot in their fig. 3 from which we estimate the following data table")
+CODE (L"Language Modal Breathy")
+CODE (L"Chong -1.5 5")
+CODE (L"Fuzhou 2 10")
+CODE (L"Green Hmong 3 12")
+CODE (L"White Hmong 2 11")
+CODE (L"Mon -1.5 0")
+CODE (L"SADV Zapotec -6 -4")
+CODE (L"SLQ Zapotec 3.5 14")
+CODE (L"Tlacolula Zapotec 3 13")
+CODE (L"Tamang 1 1")
+CODE (L"!Xoo 1 14")
+NORMAL (L"Given that we have these data in a Table with the three columns labeled \"Language\", \"Modal\" and \"Breathy\", "
+ "respectively, we can first try to reproduce their figure 3 (a bar plot with both Modal and Breathy columns displayed) ")
+NORMAL (L"As you can see the labels in the first column are very long texts and they will surely overlap if "
+ "plotted at the bottom of a plot. We therefore use a value of 15 degrees for the \"Label text angle\" " "parameter. This "
+ "will make the label texts nonoverlapping. We cannot make this angle much larger because then the label texts will run out of "
+ "the viewport. ")
+NORMAL (L"Sometimes you need to plot only a part of the Table and for the selection of this part, the \"Formula\" field can be "
+ "used. Since we only have a small table we put a \"1\" in this field which always evaluates to true. In effect, all the rows will be selected. The following script line will produce the picture below.")
+CODE (L"do (\"Bar plot where...\", \"Modal Breathy\", -10, 20, \"Language\", 1.0, 1.0, 0.0, \"0.9 0.5\", 15.0, \"yes\", \"1\")")
+SCRIPT (5, 3, L"h1h2 = do (\"Create H1H2 table (Esposito 2006)\")\n"
+ "do (\"Font size...\", 10)\n"
+ "do (\"Bar plot where...\", \"Modal Breathy\", -10, 20, \"Language\", 1.0, 1.0, 0.0, \"0.9 0.5\", 15.0, \"yes\", \"1\")\n"
+ "removeObject (h1h2)\n")
+NORMAL (L"The essentials of the bart plot in their paper are perfectly reproduced in the figure above. If you want the bars within a group to be placed somewhat more apart say 0.2 (times the bar width) you can set the \"Distance between bars in a group\" to a value of 0.2:")
+CODE (L"do (\"Bar plot where...\", \"Modal Breathy\", -10, 20, \"Language\", 1.0, 1.0, 0.2, \"0.9 0.5\", 15.0, \"yes\", \"1\")")
+SCRIPT (5, 3, L"h1h2 = do (\"Create H1H2 table (Esposito 2006)\")\n"
+ "do (\"Font size...\", 10)\n"
+ "do (\"Bar plot where...\", \"Modal Breathy\", -10, 20, \"Language\", 1.0, 1.0, 0.2, \"0.9 0.5\", 15.0, \"yes\", \"1\")\n"
+ "removeObject (h1h2)\n")
+NORMAL (L"Of course we can also work with colours and we can add vertical marks as the following sriptlet shows")
+CODE (L"do (\"Bar plot where...\", \"Modal Breathy\", -10, 20, \"Language\", 1.0, 1.0, 0.0, \"Green Red\", 15.0, \"yes\", \"1\")")
+CODE (L"do (\"Marks left every...\", 1, 5, 1, 1, 1)")
+CODE (L"do (\"Text left...\", 1, \"H__1_-H__2_ (dB)\")")
+SCRIPT (5, 3, L"h1h2 = do (\"Create H1H2 table (Esposito 2006)\")\n"
+ "do (\"Font size...\", 10)\n"
+ "do (\"Bar plot where...\", \"Modal Breathy\", -10, 20, \"Language\", 1.0, 1.0, 0.0, \"Green Red\", 15.0, \"yes\", \"1\")\n"
+ "do (\"Marks left every...\", 1, 5, 1, 1, 1)\n"
+ "do (\"Text left...\", 1, \"H__1_-H__2_ (dB)\")\n"
+ "removeObject (h1h2)\n")
+MAN_END
+
+MAN_BEGIN (L"Table: Line graph where...", L"djmw", 20130624)
+INTRO (L"Draws a line graph from the data in a column of the selected @Table. In a line plot the horizontal axis can have a nominal scale or a numeric scale. The data point are connected by line segments.")
+ENTRY (L"Settings")
+SCRIPT (6, Manual_SETTINGS_WINDOW_HEIGHT (8), L""
+ Manual_DRAW_SETTINGS_WINDOW ("Table: Line graph where", 8)
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Vertical column", "")
+ Manual_DRAW_SETTINGS_WINDOW_RANGE ("Vertical range", "0.0", "0.0 (=autoscaling)")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Horizontal column", "")
+ Manual_DRAW_SETTINGS_WINDOW_RANGE ("Horizontal range", "0.0", "0.0 (=autoscaling)")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Text", "+")
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Label text angle (degrees)", "0.0")
+ Manual_DRAW_SETTINGS_WINDOW_BOOLEAN("Garnish", 1)
+ Manual_DRAW_SETTINGS_WINDOW_TEXT("Formula:", "1; (=everything)")
+)
+TAG (L"##Vertical column")
+DEFINITION (L"The column whose data points you want to plot.")
+TAG (L"##Vertical range")
+DEFINITION (L"determine the lower and upper limit of the plot.")
+TAG (L"##Horizontal column")
+DEFINITION (L"determines the horizontal scale. If you leave it empty, or, if the (selected part of the) selected column contains nominal values, i.e. the values are not numeric but text, the horizontal "
+ "distance between the data points will be constant (i.e. 1) and the nominal values (texts) will be put as labels at the bottom of the horizontal axis. "
+ "On the other hand, if this column contains only numerical values, the horizontal position of the data points will be determined by the values in this column.")
+TAG (L"##Horizontal range")
+DEFINITION (L"determines the left and right limit of the plot.")
+TAG (L"##Text")
+DEFINITION (L"The text to put at the position of the data point in the plot.")
+TAG (L"##Label text angle (degrees)")
+DEFINITION (L"determines the angle of the labels written %%below% the plot. If you have very long label texts in the \"Horizontal column\", you can prevent the label texts from overlapping. This only has effect for a horizontal column with nominal values.")
+TAG (L"##Formula")
+DEFINITION (L"can be used to supply an expression to select only those rows for plotting where the expression evaluates to %%true%. A 1 value always evaluates to %%true%.")
+ENTRY (L"Examples")
+NORMAL (L"The following table was estimated from fig. 3 in @@Ganong (1980)@ and represents the fraction /d/ responses as a function of a "
+ "voice onset time (VOT) continuum. The second column shows the responses in a word - nonword continuum, while the third column shows "
+ "the responses to a nonword - word continuum.")
+CODE (L"VOT dash-tash dask-task")
+CODE (L"-17.5 0.98 0.92")
+CODE (L" -7.5 0.95 0.83")
+CODE (L" -2.5 0.71 0.33")
+CODE (L" 2.5 0.29 0.10")
+CODE (L" 7.5 0.12 0.02")
+CODE (L" 17.5 0.10 0.02")
+NORMAL (L"We can reproduce fig. 3 from Ganong (1980) with the following script, where we labeled the word - nonword curve with \"wn\" and the nonword - word curve with \"nw\". We deselect \"Garnish\" because we want to put special marks at the bottom.")
+CODE (L"do (\"Dotted line\")\n")
+CODE (L"do (\"Line graph where...\", \"dash-tash\", 0, 1, \"VOT\", -20, 20, \"wn\", 0, 0, \"1\")")
+CODE (L"do (\"Dashed line\")\n")
+CODE (L"do (\"Line graph where...\", \"dask-task\", 0, 1, \"VOT\", -20, 20, \"nw\", 0, 0, \"1\")")
+CODE (L"do (\"Draw inner box\")")
+CODE (L"do (\"One mark bottom...\", 2.5, 0, 1, 0, \"+2.5\")")
+CODE (L"do (\"One mark bottom...\", -2.5, 1, 1, 0, \"\")")
+CODE (L"do (\"One mark bottom...\", -7.5,1, 1, 0, \"\")")
+CODE (L"do (\"One mark bottom...\", 7.5, 0, 1, 0, \"+7.5\")")
+CODE (L"do (\"One mark bottom...\", 2.5, 0, 0, 0, \"+2.5\")")
+CODE (L"do (\"One mark bottom...\", -20, 0, 0, 0, \"Short VOT\")")
+CODE (L"do (\"One mark bottom...\", 20, 0, 0, 0, \"Long VOT\")")
+CODE (L"do (\"Text bottom...\", 1, \"VOT (ms)\")")
+CODE (L"do (\"Marks left every...\", 1, 0.2, 1, 1, 0)")
+CODE (L"do (\"Text left...\", 1, \"Prop. of voiced responses\")")
+
+SCRIPT (5,3, L"ganong = do (\"Create Table (Ganong 1980)\")\n"
+ "do (\"Dotted line\")\n"
+ "do (\"Line graph where...\", \"dash-tash\", 0, 1, \"VOT\", -20, 20, \"wn\", 0, 0, \"1\")\n"
+ "do (\"Dashed line\")\n"
+ "do (\"Line graph where...\", \"dask-task\", 0, 1, \"VOT\", -20, 20, \"nw\", 0, 0, \"1\")\n"
+ "do (\"Draw inner box\")\n"
+ "do (\"One mark bottom...\", 2.5, 0, 1, 0, \"+2.5\")\n"
+ "do (\"One mark bottom...\", -2.5, 1, 1, 0, \"\")\n"
+ "do (\"One mark bottom...\", -7.5,1, 1, 0, \"\")\n"
+ "do (\"One mark bottom...\", 7.5, 0, 1, 0, \"+7.5\")\n"
+ "do (\"One mark bottom...\", 2.5, 0, 0, 0, \"+2.5\")\n"
+ "do (\"One mark bottom...\", -20, 0, 0, 0, \"Short VOT\")\n"
+ "do (\"One mark bottom...\", 20, 0, 0, 0, \"Long VOT\")\n"
+ "do (\"Text bottom...\", 1, \"VOT (ms)\")\n"
+ "do (\"Marks left every...\", 1, 0.2, 1, 1, 0)\n"
+ "do (\"Text left...\", 1, \"Prop. of voiced responses\")\n"
+ "removeObject (ganong)\n"
+)
+NORMAL (L"As an example of what happens if you don't supply an argument for the \"Horizontal column\" we will use the same table as for the previous plot. However the resulting plot may not be as meaningful (note that the horizontal nominal scale makes all points equidistant in the horizontal direction.)")
+CODE (L"do (\"Dotted line\")\n")
+CODE (L"do (\"Line graph where...\", \"dash-tash\", 0, 1, \"\", 0, 0, \"wn\", 0, 1, \"1\")")
+CODE (L"do (\"One mark bottom...\", 1, 0, 1, 0, \"Short VOT\")")
+SCRIPT (5,3, L"ganong = do (\"Create Table (Ganong 1980)\")\n"
+ "do (\"Dotted line\")\n"
+ "do (\"Line graph where...\", \"dash-tash\", 0, 1, \"\", 0, 0, \"wn\", 0, 1, \"1\")\n"
+ "do (\"One mark bottom...\", 1, 0, 1, 0, \"Short VOT\")\n"
+ "removeObject (ganong)\n"
+)
+MAN_END
+
+
MAN_BEGIN (L"Table: Get median absolute deviation...", L"djmw", 20120405)
INTRO (L"Get the median absolute deviation (MAD) of the column in the selected @@Table@ (adjusted by a scale factor).")
ENTRY (L"Algorithm")
@@ -4621,6 +4773,10 @@ NORMAL (L"J.E.F. Friedl (1997): %%Mastering Regular Expressions%. "
"O'Reilly & Associates.")
MAN_END
+MAN_BEGIN (L"Ganong (1980)", L"djmw", 20130622)
+NORMAL (L"W.F. Ganong III (1980): \"Phonetic categorization in auditory word perception.\" %%Journal of Experimental Psychology: Human Perception and Performance% #6: 110\\--125.")
+MAN_END
+
MAN_BEGIN (L"Greiner & Hormann (1998)", L"djmw", 20110617)
NORMAL (L"G. Greiner & K. Hormann (1998): \"Efficient clipping of arbitrary polygons.\" %%ACM Transactions on Graphics% #17: 71\\--83.")
MAN_END
@@ -4661,6 +4817,10 @@ MAN_BEGIN (L"Johnson (1998)", L"djmw", 20000525)
NORMAL (L"D.E. Johnson (1998): %%Applied Multivariate methods%.")
MAN_END
+MAN_BEGIN (L"Keating & Esposito (2006)", L"djmw", 20130620)
+NORMAL (L"P.A. Keating & C. Esposito (2006): \"Linguistic voice quality.\" %%UCLA Working Papers in Phonetics% #105: 85\\--91.")
+MAN_END
+
MAN_BEGIN (L"Khuri (1998)", L"djmw", 20120702)
NORMAL (L"A. Khuri (1998): \"Unweighted sums of squares in unbalanced analysis of variance.\", %%Journal of Statistical Planning "
"and Inference% #74: 135\\--147.")
diff --git a/dwtools/praat_David_init.cpp b/dwtools/praat_David_init.cpp
index deb5c7d..ff8e7bb 100644
--- a/dwtools/praat_David_init.cpp
+++ b/dwtools/praat_David_init.cpp
@@ -3819,25 +3819,28 @@ END
/**************** Ltas *******************************************/
+#include "UnicodeData.h"
FORM (Ltas_reportSpectralTilt, L"Ltas: Report spectral tilt", 0)
POSITIVE (L"left Frequency range (Hz)", L"100.0")
POSITIVE (L"right Frequency range (Hz)", L"5000.0")
- BOOLEAN (L"Logarithmic frequecy scale", 0)
+ OPTIONMENU (L"Frequency scale", 1)
+ OPTION (L"Linear")
+ OPTION (L"Logarithmic")
OPTIONMENU (L"Fit method", 2)
OPTION (L"Least squares")
OPTION (L"Robust")
OK
DO
- bool logScale = GET_INTEGER (L"Logarithmic frequecy scale");
+ bool logScale = GET_INTEGER (L"Frequency scale") == 2;
LOOP {
iam (Ltas);
double a, b;
Ltas_fitTiltLine (me, GET_REAL (L"left Frequency range"), GET_REAL (L"right Frequency range"),
logScale, GET_INTEGER (L"Fit method"), &a, &b);
MelderInfo_open ();
- MelderInfo_writeLine (L"Spectral background decay model: ", (logScale ? L"a * ln (frequency) + b." : L"a * frequency + b."));
- MelderInfo_writeLine (Melder_double (a), L" (=a: decay rate)");
- MelderInfo_writeLine (Melder_double (b), L" (=b: offset at zero frequency)");
+ MelderInfo_writeLine (L"Spectral model: amplitude_dB(frequency_Hz) " UNITEXT_ALMOST_EQUAL_TO " ", logScale ? L"offset + slope * log (frequency_Hz)" : L"offset + slope * frequency_Hz");
+ MelderInfo_writeLine (L"Slope: ", Melder_double (a), logScale ? L" dB/decade" : L" dB/Hz");
+ MelderInfo_writeLine (L"Offset: ", Melder_double (b), L" dB");
MelderInfo_close ();
}
END
@@ -3870,6 +3873,17 @@ DO
}
END
+FORM (MFCC_to_Matrix_features, L"MFCC: To Matrix (features)", L"")
+ POSITIVE (L"Window length (s)", L"0.025")
+ BOOLEAN (L"Include energy", 0)
+ OK
+DO
+ LOOP {
+ iam (MFCC);
+ praat_new (MFCC_to_Matrix_features (me, GET_REAL (L"Window length"), GET_INTEGER (L"Include energy")), my name);
+ }
+END
+
FORM (MFCCs_crossCorrelate, L"MFCC & MFCC: Cross-correlate", 0)
RADIO_ENUM (L"Amplitude scaling", kSounds_convolve_scaling, DEFAULT)
RADIO_ENUM (L"Signal outside time domain is...", kSounds_convolve_signalOutsideTimeDomain, DEFAULT)
@@ -5642,6 +5656,13 @@ DIRECT (Spectrum_unwrap)
}
END
+DIRECT (Spectrum_to_PowerCepstrum)
+ LOOP {
+ iam (Spectrum);
+ praat_new (Spectrum_to_PowerCepstrum (me), my name);
+ }
+END
+
DIRECT (Spectrum_to_Cepstrum)
LOOP {
iam (Spectrum);
@@ -5807,7 +5828,7 @@ DO
autoTextGrid thee = SpeechSynthesizer_and_Sound_and_TextGrid_align (synth, s, tg,
GET_INTEGER (L"Tier number"), GET_INTEGER (L"From interval number"),
GET_INTEGER (L"To interval number"), silenceThreshold, minSilenceDuration, minSoundingDuration);
- praat_new (thee.transfer(), thy name, L"_aligned");
+ praat_new (thee.transfer(), s -> name, L"_aligned");
END
FORM (SpeechSynthesizer_and_Sound_and_TextGrid_align2, L"SpeechSynthesizer & Sound & TextGrid: To TextGrid (align, trim)", 0)
@@ -5833,7 +5854,7 @@ DO
autoTextGrid thee = SpeechSynthesizer_and_Sound_and_TextGrid_align2 (synth, s, tg,
GET_INTEGER (L"Tier number"), GET_INTEGER (L"From interval number"),
GET_INTEGER (L"To interval number"), silenceThreshold, minSilenceDuration, minSoundingDuration, trimDuration);
- praat_new (thee.transfer(), thy name, L"_aligned");
+ praat_new (thee.transfer(), s -> name, L"_aligned");
END
/************* Spline *************************************************/
@@ -6186,6 +6207,113 @@ DIRECT (Table_createFromWeeninkData)
praat_new (Table_createFromWeeninkData (), L"m10w10c10");
END
+FORM (Table_scatterPlotWhere, L"Table: Scatter plot where", 0)
+ WORD (L"Horizontal column", L"")
+ REAL (L"left Horizontal range", L"0.0")
+ REAL (L"right Horizontal range", L"0.0 (= auto)")
+ WORD (L"Vertical column", L"")
+ REAL (L"left Vertical range", L"0.0")
+ REAL (L"right Vertical range", L"0.0 (= auto)")
+ WORD (L"Column with marks", L"")
+ NATURAL (L"Font size", L"12")
+ BOOLEAN (L"Garnish", 1)
+ LABEL (L"", L"Use only data from rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long xcolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Horizontal column"));
+ long ycolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Vertical column"));
+ long markColumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Column with marks"));
+ autoTable thee = Table_extractRowsWhere (me, GET_STRING (L"Formula"), interpreter);
+ Table_scatterPlot (thee.peek(), GRAPHICS, xcolumn, ycolumn,
+ GET_REAL (L"left Horizontal range"), GET_REAL (L"right Horizontal range"),
+ GET_REAL (L"left Vertical range"), GET_REAL (L"right Vertical range"),
+ markColumn, GET_INTEGER (L"Font size"), GET_INTEGER (L"Garnish"));
+ }
+END
+
+FORM (Table_scatterPlotMarkWhere, L"Scatter plot where (marks)", 0)
+ WORD (L"Horizontal column", L"")
+ REAL (L"left Horizontal range", L"0.0")
+ REAL (L"right Horizontal range", L"0.0 (= auto)")
+ WORD (L"Vertical column", L"")
+ REAL (L"left Vertical range", L"0.0")
+ REAL (L"right Vertical range", L"0.0 (= auto)")
+ POSITIVE (L"Mark size (mm)", L"1.0")
+ BOOLEAN (L"Garnish", 1)
+ SENTENCE (L"Mark string (+xo.)", L"+")
+ LABEL (L"", L"Use only data from rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long xcolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Horizontal column"));
+ long ycolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Vertical column"));
+ autoTable thee = Table_extractRowsWhere (me, GET_STRING (L"Formula"), interpreter);
+ Table_scatterPlot_mark (thee.peek(), GRAPHICS, xcolumn, ycolumn,
+ GET_REAL (L"left Horizontal range"), GET_REAL (L"right Horizontal range"),
+ GET_REAL (L"left Vertical range"), GET_REAL (L"right Vertical range"),
+ GET_REAL (L"Mark size"), GET_STRING (L"Mark string"), GET_INTEGER (L"Garnish"));
+ }
+END
+
+FORM (Table_barPlotWhere, L"Table: Bar plot where", L"Table: Bar plot where...")
+ SENTENCE (L"Vertical column(s)", L"")
+ REAL (L"left Vertical range", L"0.0")
+ REAL (L"right Vertical range", L"0.0 (= auto)")
+ SENTENCE (L"Column with labels", L"")
+ LABEL (L"", L"Distances are in units of 'bar width'")
+ REAL (L"Distance of first bar from border", L"1.0")
+ REAL (L"Distance between bar groups", L"1.0")
+ REAL (L"Distance between bars within group", L"0.0")
+ SENTENCE (L"Colours", L"Grey")
+ REAL (L"Label text angle (degrees)", L"0.0");
+ BOOLEAN (L"Garnish", 1)
+ LABEL (L"", L"Use only data from rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"row >= 1 and row <= 8")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ Table_barPlotWhere (me, GRAPHICS, GET_STRING (L"Vertical column"), GET_REAL (L"left Vertical range"),
+ GET_REAL (L"right Vertical range"), GET_STRING (L"Column with labels"),
+ GET_REAL (L"Distance of first bar from border"), GET_REAL (L"Distance between bars within group"), GET_REAL (L"Distance between bar groups"),
+ GET_STRING (L"Colours"),GET_REAL (L"Label text angle"), GET_INTEGER (L"Garnish"), GET_STRING (L"Formula"), interpreter);
+ }
+END
+
+FORM (Table_LineGraphWhere, L"Table: Line graph where", L"Table: Line graph where...")
+ SENTENCE (L"Vertical column", L"")
+ REAL (L"left Vertical range", L"0.0")
+ REAL (L"right Vertical range", L"0.0 (= auto)")
+ SENTENCE (L"Horizonal column", L"")
+ REAL (L"left Horizontal range", L"0.0")
+ REAL (L"right Horizontal range", L"0.0 (= auto)")
+ WORD (L"Text", L"+")
+ REAL (L"Label text angle (degrees)", L"0.0");
+ BOOLEAN (L"Garnish", 1)
+ LABEL (L"", L"Use only data from rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; (= everything)")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long ycolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Vertical column"));
+ long xcolumn = Table_findColumnIndexFromColumnLabel (me, GET_STRING (L"Horizonal column"));
+ Table_lineGraphWhere (me, GRAPHICS, xcolumn, GET_REAL (L"left Horizontal range"), GET_REAL (L"right Horizontal range"),
+ ycolumn, GET_REAL (L"left Vertical range"), GET_REAL (L"right Vertical range"),
+ GET_STRING (L"Text"), GET_REAL (L"Label text angle"),
+ GET_INTEGER (L"Garnish"), GET_STRING (L"Formula"), interpreter);
+ }
+END
+
FORM (Table_boxPlots, L"Table: Box plots", 0)
WORD (L"Data column", L"")
WORD (L"Factor column", L"")
@@ -6206,6 +6334,55 @@ DO
}
END
+FORM (Table_boxPlotsWhere, L"Table: Box plots where", 0)
+ WORD (L"Data column", L"")
+ WORD (L"Factor column", L"")
+ REAL (L"left Vertical range", L"0.0")
+ REAL (L"right Vertical range", L"0.0")
+ BOOLEAN (L"Garnish", 1);
+ LABEL (L"", L"Use only data in rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ autoPraatPicture picture;
+ double ymin = GET_REAL (L"left Vertical range");
+ double ymax = GET_REAL (L"right Vertical range");
+ int garnish = GET_INTEGER (L"Garnish");
+ LOOP {
+ iam (Table);
+ long dataColumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Data column"));
+ long factorColumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Factor column"));
+ autoTable thee = Table_extractRowsWhere (me, GET_STRING (L"Formula"), interpreter);
+ Table_boxPlots (thee.peek(), GRAPHICS, dataColumn, factorColumn, ymin, ymax, garnish);
+ }
+END
+
+FORM (Table_drawEllipseWhere, L"Draw ellipse (standard deviation)", 0)
+ WORD (L"Horizontal column", L"")
+ REAL (L"left Horizontal range", L"0.0")
+ REAL (L"right Horizontal range", L"0.0 (= auto)")
+ WORD (L"Vertical column", L"")
+ REAL (L"left Vertical range", L"0.0")
+ REAL (L"right Vertical range", L"0.0 (= auto)")
+ POSITIVE (L"Number of sigmas", L"2.0")
+ BOOLEAN (L"Garnish", 1)
+ LABEL (L"", L"Use only data in rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long xcolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Horizontal column"));
+ long ycolumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Vertical column"));
+ autoTable thee = Table_extractRowsWhere (me, GET_STRING (L"Formula"), interpreter);
+ Table_drawEllipse_e (thee.peek(), GRAPHICS, xcolumn, ycolumn,
+ GET_REAL (L"left Horizontal range"), GET_REAL (L"right Horizontal range"),
+ GET_REAL (L"left Vertical range"), GET_REAL (L"right Vertical range"),
+ GET_REAL (L"Number of sigmas"), GET_INTEGER (L"Garnish"));
+ }
+END
+
FORM (Table_normalProbabilityPlot, L"Table: Normal probability plot", L"Table: Normal probability plot...")
WORD (L"Column", L"")
NATURAL (L"Number of quantiles", L"100")
@@ -6225,6 +6402,28 @@ DO
}
END
+FORM (Table_normalProbabilityPlotWhere, L"Table: Normal probability plot where", L"Table: Normal probability plot...")
+ WORD (L"Column", L"")
+ NATURAL (L"Number of quantiles", L"100")
+ REAL (L"Number of sigmas", L"0.0")
+ NATURAL (L"Label size", L"12")
+ WORD (L"Label", L"+")
+ BOOLEAN (L"Garnish", 1);
+ LABEL (L"", L"Use only data in rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long column = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Column"));
+ autoTable thee = Table_extractRowsWhere (me, GET_STRING (L"Formula"), interpreter);
+ Table_normalProbabilityPlot (thee.peek(), GRAPHICS, column,
+ GET_INTEGER (L"Number of quantiles"), GET_REAL (L"Number of sigmas"),
+ GET_INTEGER (L"Label size"), GET_STRING (L"Label"), GET_INTEGER (L"Garnish"));
+ }
+END
+
FORM (Table_quantileQuantilePlot, L"Table: Quantile-quantile plot", L"Table: Quantile-quantile plot...")
WORD (L"Horizontal axis column", L"")
WORD (L"Vertical axis column", L"")
@@ -6280,6 +6479,50 @@ DO
}
END
+FORM (Table_distributionPlot, L"Table: Distribution plot", 0)
+ WORD (L"Data column", L"data")
+ REAL (L"Minimum value", L"0.0")
+ REAL (L"Maximum value", L"0.0")
+ LABEL (L"", L"Display of the distribution")
+ NATURAL (L"Number of bins", L"10")
+ REAL (L"Minimum frequency", L"0.0")
+ REAL (L"Maximum frequency", L"0.0")
+ BOOLEAN (L"Garnish", 1)
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long dataColumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Data column"));
+ Table_distributionPlotWhere (me, GRAPHICS, dataColumn, GET_REAL (L"Minimum value"), GET_REAL (L"Maximum value"),
+ GET_INTEGER (L"Number of bins"), GET_REAL (L"Minimum frequency"), GET_REAL (L"Maximum frequency"), GET_INTEGER (L"Garnish"),
+ L"1", interpreter);
+ }
+END
+
+FORM (Table_distributionPlotWhere, L"Table: Distribution plot where", 0)
+ WORD (L"Data column", L"data")
+ REAL (L"Minimum value", L"0.0")
+ REAL (L"Maximum value", L"0.0")
+ LABEL (L"", L"Display of the distribution")
+ NATURAL (L"Number of bins", L"10")
+ REAL (L"Minimum frequency", L"0.0")
+ REAL (L"Maximum frequency", L"0.0")
+ BOOLEAN (L"Garnish", 1)
+ LABEL (L"", L"Use only data in rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ autoPraatPicture picture;
+ LOOP {
+ iam (Table);
+ long dataColumn = Table_getColumnIndexFromColumnLabel (me, GET_STRING (L"Data column"));
+ Table_distributionPlotWhere (me, GRAPHICS, dataColumn, GET_REAL (L"Minimum value"), GET_REAL (L"Maximum value"),
+ GET_INTEGER (L"Number of bins"), GET_REAL (L"Minimum frequency"), GET_REAL (L"Maximum frequency"), GET_INTEGER (L"Garnish"),
+ GET_STRING (L"Formula"), interpreter);
+ }
+END
+
FORM (Table_scatterPlotWithConfidenceIntervals, L"Table: Scatter plot (confidence intervals)", L"")
NATURAL (L"Horizontal axis column", L"1")
REAL (L"left Horizontal range", L"0.0")
@@ -6308,6 +6551,18 @@ DO
}
END
+FORM (Table_extractRowsWhere, L"Table: Extract rows where", 0)
+ LABEL (L"", L"Extractm rows where the following condition holds:")
+ TEXTFIELD (L"Formula", L"1; self$[\"gender\"]=\"male\"")
+ OK
+DO
+ LOOP {
+ iam (Table);
+ autoTable thee = Table_extractRowsWhere (me, GET_STRING (L"Formula"), interpreter);
+ praat_new (thee.transfer(), my name, L"_formula");
+ }
+END
+
/******************* TableOfReal ****************************/
DIRECT (New_CreateIrisDataset)
@@ -6363,6 +6618,14 @@ DO
praat_new (TableOfReal_createFromPolsData_50males (GET_INTEGER (L"Include formant levels")), L"pols_50males");
END
+DIRECT (Table_createFromEspositoData)
+ praat_new (Table_createFromEspositoData (), L"h1_h2");
+END
+
+DIRECT (Table_createFromGanongData)
+ praat_new (Table_createFromGanongData (), L"ganong");
+END
+
FORM (TableOfReal_createFromVanNieropData_25females, L"Create TableOfReal (Van Nierop 1973)...", L"Create TableOfReal (Van Nierop 1973)...")
BOOLEAN (L"Include formant levels", 0)
OK
@@ -7134,6 +7397,8 @@ void praat_uvafon_David_init () {
praat_addMenuCommand (L"Objects", L"New", L"Create formant table (Pols & Van Nierop 1973)", L"Create Table...", 1, DO_Table_createFromPolsVanNieropData);
praat_addMenuCommand (L"Objects", L"New", L"Create formant table (Peterson & Barney 1952)", L"Create Table...", 1, DO_Table_createFromPetersonBarneyData);
praat_addMenuCommand (L"Objects", L"New", L"Create formant table (Weenink 1985)", L"Create formant table (Peterson & Barney 1952)", 1, DO_Table_createFromWeeninkData);
+ praat_addMenuCommand (L"Objects", L"New", L"Create H1H2 table (Esposito 2006)", L"Create formant table (Weenink 1985)", praat_DEPTH_1+ praat_HIDDEN, DO_Table_createFromEspositoData);
+ praat_addMenuCommand (L"Objects", L"New", L"Create Table (Ganong 1980)", L"Create H1H2 table (Esposito 2006)", praat_DEPTH_1+ praat_HIDDEN, DO_Table_createFromGanongData);
praat_addMenuCommand (L"Objects", L"New", L"Create TableOfReal (Pols 1973)...", L"Create TableOfReal...", 1, DO_TableOfReal_createFromPolsData_50males);
praat_addMenuCommand (L"Objects", L"New", L"Create TableOfReal (Van Nierop 1973)...", L"Create TableOfReal (Pols 1973)...", 1, DO_TableOfReal_createFromVanNieropData_25females);
praat_addMenuCommand (L"Objects", L"New", L"Create TableOfReal (Weenink 1985)...", L"Create TableOfReal (Van Nierop 1973)...", 1, DO_TableOfReal_createFromWeeninkData);
@@ -7527,6 +7792,7 @@ void praat_uvafon_David_init () {
praat_CC_init (classMFCC);
praat_addAction1 (classMFCC, 0, L"To MelFilter...", 0, 0, DO_MFCC_to_MelFilter);
praat_addAction1 (classMFCC, 0, L"To TableOfReal...", 0, 0, DO_MFCC_to_TableOfReal);
+ praat_addAction1 (classMFCC, 0, L"To Matrix (features)...", 0, praat_HIDDEN, DO_MFCC_to_Matrix_features);
praat_addAction1 (classMFCC, 0, L"To Sound", 0, praat_HIDDEN, DO_MFCC_to_Sound);
praat_addAction1 (classMFCC, 2, L"Cross-correlate...", 0, 0, DO_MFCCs_crossCorrelate);
praat_addAction1 (classMFCC, 2, L"Convolve...", 0, 0, DO_MFCCs_convolve);
@@ -7692,7 +7958,8 @@ void praat_uvafon_David_init () {
praat_addAction1 (classSpectrum, 0, L"Shift frequencies...", L"To Matrix", praat_HIDDEN, DO_Spectrum_shiftFrequencies);
praat_addAction1 (classSpectrum, 0, L"Compress frequency domain...", L"Shift frequencies...", praat_HIDDEN, DO_Spectrum_compressFrequencyDomain);
praat_addAction1 (classSpectrum, 0, L"Resample...", L"Compress frequency domain...", praat_HIDDEN, DO_Spectrum_resample);
- praat_addAction1 (classSpectrum, 0, L"To Cepstrum", L"To Spectrogram", 0, DO_Spectrum_to_Cepstrum);
+ praat_addAction1 (classSpectrum, 0, L"To Cepstrum", L"To Spectrogram", 1, DO_Spectrum_to_Cepstrum);
+ praat_addAction1 (classSpectrum, 0, L"To PowerCepstrum", L"To Cepstrum", 1, DO_Spectrum_to_PowerCepstrum);
praat_addAction1 (classSpeechSynthesizer, 0, L"SpeechSynthesizer help", 0, 0, DO_SpeechSynthesizer_help);
praat_addAction1 (classSpeechSynthesizer, 0, L"Play text...", 0, 0, DO_SpeechSynthesizer_playText);
@@ -7736,14 +8003,26 @@ void praat_uvafon_David_init () {
praat_addAction1 (classSVD, 0, L"Extract right singular vectors", 0, 0, DO_SVD_extractRightSingularVectors);
praat_addAction1 (classSVD, 0, L"Extract singular values", 0, 0, DO_SVD_extractSingularValues);
- praat_addAction1 (classTable, 0, L"Box plots...", L"Draw ellipse (standard deviation)...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_boxPlots);
- praat_addAction1 (classTable, 0, L"Normal probability plot...", L"Box plots...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_normalProbabilityPlot);
- praat_addAction1 (classTable, 0, L"Quantile-quantile plot...", L"Normal probability plot...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_quantileQuantilePlot);
- praat_addAction1 (classTable, 0, L"Quantile-quantile plot (between levels)...", L"Quantile-quantile plot...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_quantileQuantilePlot_betweenLevels);
- praat_addAction1 (classTable, 0, L"Scatter plot (ci)...", 0, praat_DEPTH_1 | praat_HIDDEN, DO_Table_scatterPlotWithConfidenceIntervals);
- praat_addAction1 (classTable, 1, L"Report one-way anova...", L"Report group difference (Wilcoxon rank sum)...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_reportOneWayAnova);
+ praat_addAction1 (classTable, 0, L"Box plots...", L"Draw ellipse (standard deviation)...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_boxPlots);
+ praat_addAction1 (classTable, 0, L"Normal probability plot...", L"Box plots...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_normalProbabilityPlot);
+ praat_addAction1 (classTable, 0, L"Quantile-quantile plot...", L"Normal probability plot...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_quantileQuantilePlot);
+ praat_addAction1 (classTable, 0, L"Quantile-quantile plot (between levels)...", L"Quantile-quantile plot...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_quantileQuantilePlot_betweenLevels);
+ praat_addAction1 (classTable, 0, L"Scatter plot (ci)...", 0, praat_DEPTH_1, DO_Table_scatterPlotWithConfidenceIntervals);
+ praat_addAction1 (classTable, 0, L"Distribution plot...", L"Quantile-quantile plot...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_distributionPlot);
+ praat_addAction1 (classTable, 1, L"Draw where -", L"Quantile-quantile plot (between levels)...", 1 , 0);
+ praat_addAction1 (classTable, 0, L"Scatter plot where...", L"Draw where -", 2, DO_Table_scatterPlotWhere);
+ praat_addAction1 (classTable, 0, L"Scatter plot where (mark)...", L"Scatter plot where...", 2, DO_Table_scatterPlotMarkWhere);
+ praat_addAction1 (classTable, 0, L"Distribution plot where...", L"Scatter plot where (mark)...", 2, DO_Table_distributionPlotWhere);
+ praat_addAction1 (classTable, 0, L"Draw ellipse where (standard deviation)...", L"Distribution plot where...", 2, DO_Table_drawEllipseWhere);
+ praat_addAction1 (classTable, 0, L"Box plots where...", L"Draw ellipse where (standard deviation)...", 2, DO_Table_boxPlotsWhere);
+ praat_addAction1 (classTable, 0, L"Normal probability plot where...", L"Box plots where...", 2, DO_Table_normalProbabilityPlotWhere);
+ praat_addAction1 (classTable, 0, L"Bar plot where...", L"Normal probability plot where...", 2, DO_Table_barPlotWhere);
+ praat_addAction1 (classTable, 0, L"Line graph where...", L"Bar plot where...", 2, DO_Table_LineGraphWhere);
+
+ praat_addAction1 (classTable, 1, L"Report one-way anova...", L"Report group difference (Wilcoxon rank sum)...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_reportOneWayAnova);
praat_addAction1 (classTable, 1, L"Report one-way Kruskal-Wallis...", L"Report one-way anova...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_reportOneWayKruskalWallis);
praat_addAction1 (classTable, 1, L"Report two-way anova...", L"Report one-way Kruskal-Wallis...", praat_DEPTH_1 | praat_HIDDEN, DO_Table_reportTwoWayAnova);
+ praat_addAction1 (classTable, 1, L"Extract rows where...", L"Extract rows where column (text)...", praat_DEPTH_1, DO_Table_extractRowsWhere);
praat_addAction1 (classTable, 0, L"To KlattTable", 0, praat_HIDDEN, DO_Table_to_KlattTable);
praat_addAction1 (classTable, 1, L"Get median absolute deviation...", L"Get standard deviation...", 1, DO_Table_getMedianAbsoluteDeviation);
diff --git a/external/espeak/Makefile b/external/espeak/Makefile
index fb49cdc..54878b1 100644
--- a/external/espeak/Makefile
+++ b/external/espeak/Makefile
@@ -22,7 +22,7 @@ clean:
libespeak.a: $(OBJECTS)
touch libespeak.a
rm libespeak.a
- ar cq libespeak.a $(OBJECTS)
+ $(AR) cq libespeak.a $(OBJECTS)
$(RANLIB) libespeak.a
$(OBJECTS): *.h ../../num/NUM.h ../../kar/*.h ../../sys/*.h ../../stat/*.h
diff --git a/external/espeak/speech.h b/external/espeak/speech.h
index 78b7bf2..7f1dc96 100644
--- a/external/espeak/speech.h
+++ b/external/espeak/speech.h
@@ -56,13 +56,13 @@
//#define ESPEAK_API extern "C"
#ifdef LIBRARY
-#define USE_ASYNC
+ #define USE_ASYNC
#endif
#ifdef _ESPEAKEDIT
-#define USE_PORTAUDIO
-#define USE_ASYNC
-#define LOG_FRAMES // write keyframe info to log-espeakedit
+ #define USE_PORTAUDIO
+ #define USE_ASYNC
+ #define LOG_FRAMES // write keyframe info to log-espeakedit
#endif
// will look for espeak_data directory here, and also in user's home directory
@@ -97,9 +97,9 @@ int LookupMnem(MNEM_TAB *table, const char *string);
#ifdef PLATFORM_WINDOWS
-#define N_PATH_HOME 220
+ #define N_PATH_HOME 220
#else
-#define N_PATH_HOME 150
+ #define N_PATH_HOME 150
#endif
extern char path_home[N_PATH_HOME]; // this is the espeak-data directory
diff --git a/external/flac/Makefile b/external/flac/Makefile
index 864d999..76cfd44 100644
--- a/external/flac/Makefile
+++ b/external/flac/Makefile
@@ -1,7 +1,7 @@
# Makefile of the library "external/flac"
# Erez Volk, March 2007
# pb 20100108: include sys/melder.h
-# Paul Boersma, 14 January 2012
+# Paul Boersma, 24 August 2013
include ../../makefile.defs
@@ -43,7 +43,7 @@ clean:
libflac.a: $(OBJECTS)
touch libflac.a
rm libflac.a
- ar cq libflac.a $(OBJECTS)
+ $(AR) cq libflac.a $(OBJECTS)
$(RANLIB) libflac.a
$(OBJECTS): *.h ../../sys/melder.h
diff --git a/external/glpk/Makefile b/external/glpk/Makefile
index 5d01066..e7493cc 100644
--- a/external/glpk/Makefile
+++ b/external/glpk/Makefile
@@ -1,5 +1,5 @@
-# Makefile for library "num/glpk"
-# Paul Boersma, 3 September 2011
+# Makefile for library "external/glpk"
+# Paul Boersma, 24 August 2013
include ../../makefile.defs
@@ -37,7 +37,7 @@ clean:
libglpk.a: $(OBJECTS)
touch libglpk.a
rm libglpk.a
- ar cq libglpk.a $(OBJECTS)
+ $(AR) cq libglpk.a $(OBJECTS)
$(RANLIB) libglpk.a
$(OBJECTS): *.h
diff --git a/external/gsl/Makefile b/external/gsl/Makefile
index 2462aee..1e10701 100644
--- a/external/gsl/Makefile
+++ b/external/gsl/Makefile
@@ -215,7 +215,7 @@ clean:
libgsl.a: $(OBJECTS)
touch libgsl.a
rm libgsl.a
- ar cq libgsl.a $(OBJECTS)
+ $(AR) cq libgsl.a $(OBJECTS)
$(RANLIB) libgsl.a
$(OBJECTS): *.h
diff --git a/external/mp3/Makefile b/external/mp3/Makefile
index 26fed82..6c666c6 100644
--- a/external/mp3/Makefile
+++ b/external/mp3/Makefile
@@ -1,6 +1,6 @@
-# Makefile of the library "audio/mp3"
+# Makefile of the library "external/mp3"
# Erez Volk, 24 May 2007
-# Paul Boersma, 6 September 2011
+# Paul Boersma, 24 August 2013
include ../../makefile.defs
@@ -30,7 +30,7 @@ clean:
libmp3.a: $(OBJECTS)
touch libmp3.a
rm libmp3.a
- ar cq libmp3.a $(OBJECTS)
+ $(AR) cq libmp3.a $(OBJECTS)
$(RANLIB) libmp3.a
$(OBJECTS): *.h ../../sys/*.h
diff --git a/external/portaudio/READ_ME.TXT b/external/portaudio/READ_ME.TXT
index 1f60244..14c6705 100644
--- a/external/portaudio/READ_ME.TXT
+++ b/external/portaudio/READ_ME.TXT
@@ -1,5 +1,5 @@
Praats/external/portaudio/READ_ME.TXT
-Paul Boersma, 4 January 2010
+Paul Boersma, 1 September 2013
This file describes the adaptations to the PortAudio v19 sources (2007/11)
that are needed to make them compatible with Praat.
@@ -18,3 +18,5 @@ In pa_mac_core.c:
#include <Components.h>
Duplicate pa_unix_util.c to pa_mac_util.c, but only for allocation and time routines.
+
+Remove the hard-coded definition of SIZEOF_LONG from pa_types.h and instead use <stdint.h> to define PaInt32 and the like. Correct the associated error in pa_dither.c: SIZEOF_LONG -> sizeof(long).
\ No newline at end of file
diff --git a/external/portaudio/pa_dither.c b/external/portaudio/pa_dither.c
index 6f6c9a1..f5bdcb6 100644
--- a/external/portaudio/pa_dither.c
+++ b/external/portaudio/pa_dither.c
@@ -40,6 +40,8 @@
@ingroup common_src
@brief Functions for generating dither noise
+
+ Paul Boersma 2013: corrected for sizeof(long)
*/
@@ -69,7 +71,7 @@ signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerato
* Shift before adding to prevent overflow which would skew the distribution.
* Also shift an extra bit for the high pass filter.
*/
-#define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
+#define DITHER_SHIFT_ ((sizeof(long)*8 - PA_DITHER_BITS_) + 1)
current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
(((signed long)state->randSeed2)>>DITHER_SHIFT_);
@@ -96,7 +98,7 @@ float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *sta
* Shift before adding to prevent overflow which would skew the distribution.
* Also shift an extra bit for the high pass filter.
*/
-#define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
+#define DITHER_SHIFT_ ((sizeof(long)*8 - PA_DITHER_BITS_) + 1)
current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
(((signed long)state->randSeed2)>>DITHER_SHIFT_);
diff --git a/external/portaudio/pa_process.c b/external/portaudio/pa_process.c
index fac474d..59bf434 100644
--- a/external/portaudio/pa_process.c
+++ b/external/portaudio/pa_process.c
@@ -818,8 +818,8 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
userOutput = bp->tempOutputBufferPtrs;
}
}
-
- *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
if( *streamCallbackResult == paAbort )
diff --git a/external/portaudio/pa_types.h b/external/portaudio/pa_types.h
index 5b647d6..fd9bfe3 100644
--- a/external/portaudio/pa_types.h
+++ b/external/portaudio/pa_types.h
@@ -51,43 +51,18 @@
A PA_VALIDATE_SIZES macro is provided to assert that the values set in this
file are correct.
-*/
-
-#ifndef SIZEOF_SHORT
-#define SIZEOF_SHORT 2
-#endif
-#ifndef SIZEOF_INT
-#define SIZEOF_INT 4
-#endif
-
-#ifndef SIZEOF_LONG
-#define SIZEOF_LONG 4
-#endif
+ Paul Boersma 2013: the sizes should not be handcoded if this header file is to be included in both 32-bit and 64-bit applications;
+ instead, we use int32_t and the like from <stdint.h>.
+*/
+#include <stdint.h>
-#if SIZEOF_SHORT == 2
-typedef signed short PaInt16;
-typedef unsigned short PaUint16;
-#elif SIZEOF_INT == 2
-typedef signed int PaInt16;
-typedef unsigned int PaUint16;
-#else
-#error pa_types.h was unable to determine which type to use for 16bit integers on the target platform
-#endif
+typedef int16_t PaInt16;
+typedef uint16_t PaUint16;
-#if SIZEOF_SHORT == 4
-typedef signed short PaInt32;
-typedef unsigned short PaUint32;
-#elif SIZEOF_INT == 4
-typedef signed int PaInt32;
-typedef unsigned int PaUint32;
-#elif SIZEOF_LONG == 4
-typedef signed long PaInt32;
-typedef unsigned long PaUint32;
-#else
-#error pa_types.h was unable to determine which type to use for 32bit integers on the target platform
-#endif
+typedef int32_t PaInt32;
+typedef uint32_t PaUint32;
/* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to
diff --git a/fon/FunctionEditor.cpp b/fon/FunctionEditor.cpp
index b83ffd3..c2d0774 100644
--- a/fon/FunctionEditor.cpp
+++ b/fon/FunctionEditor.cpp
@@ -47,6 +47,8 @@ Thing_implement (FunctionEditor, Editor, 0);
static int nGroup = 0;
static FunctionEditor theGroup [1 + maxGroup];
+static void drawWhileDragging (FunctionEditor me, double x1, double x2);
+
static int group_equalDomain (double tmin, double tmax) {
if (nGroup == 0) return 1;
for (int i = 1; i <= maxGroup; i ++)
@@ -537,15 +539,19 @@ static void do_zoomToSelection (FunctionEditor me) {
if (my d_endSelection > my d_startSelection) {
my startZoomHistory = my d_startWindow; // remember for Zoom Back
my endZoomHistory = my d_endWindow; // remember for Zoom Back
- //Melder_casual ("Zoomed in to %f ~ %f seconds.", my startSelection, my endSelection);
+ trace ("Zooming in to %.17g ~ %.17g seconds.", my d_startSelection, my d_endSelection);
my d_startWindow = my d_startSelection;
my d_endWindow = my d_endSelection;
+ trace ("Zoomed in to %.17g ~ %.17g seconds (1).", my d_startWindow, my d_endWindow);
my v_updateText ();
+ trace ("Zoomed in to %.17g ~ %.17g seconds (2).", my d_startWindow, my d_endWindow);
updateScrollBar (me);
+ trace ("Zoomed in to %.17g ~ %.17g seconds (3).", my d_startWindow, my d_endWindow);
/*Graphics_updateWs (my d_graphics);*/ drawNow (me);
if (my pref_synchronizedZoomAndScroll ()) {
updateGroup (me);
}
+ trace ("Zoomed in to %.17g ~ %.17g seconds (4).", my d_startWindow, my d_endWindow);
}
}
@@ -763,6 +769,7 @@ static void menu_cb_moveEby (EDITOR_ARGS) {
void FunctionEditor_shift (FunctionEditor me, double shift, bool needsUpdateGroup) {
double windowLength = my d_endWindow - my d_startWindow;
MelderAudio_stopPlaying (MelderAudio_IMPLICIT); /* Quickly, before window changes. */
+ trace ("shifting by %.17g", shift);
if (shift < 0.0) {
my d_startWindow += shift;
if (my d_startWindow < my d_tmin + 1e-12)
@@ -1030,7 +1037,6 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (FunctionEditor);
if (my d_graphics == NULL) return; // Could be the case in the very beginning.
-if (gtk && event -> type != BUTTON_PRESS) return;
double xWC, yWC;
my shiftKeyPressed = event -> shiftKeyPressed;
Graphics_setWindow (my d_graphics, my functionViewerLeft, my functionViewerRight, 0, my height);
@@ -1048,9 +1054,6 @@ if (gtk && event -> type != BUTTON_PRESS) return;
Melder_casual ("FunctionEditor::gui_drawingarea_cb_click: button %d shift %d option %d command %d control %d",
event -> button, my shiftKeyPressed, event -> optionKeyPressed, event -> commandKeyPressed, event -> extraControlKeyPressed);
}
-#if cocoa
- my clickEvent = event;
-#endif
#if defined (macintosh)
needsUpdate =
event -> optionKeyPressed || event -> extraControlKeyPressed ? my v_clickB (xWC, yWC) :
@@ -1070,13 +1073,14 @@ if (gtk && event -> type != BUTTON_PRESS) return;
#endif
if (needsUpdate) my v_updateText ();
Graphics_setViewport (my d_graphics, my functionViewerLeft, my functionViewerRight, 0, my height);
- if (needsUpdate) /*Graphics_updateWs (my d_graphics);*/ drawNow (me);
+ if (needsUpdate) {
+ #if cocoa
+ Graphics_updateWs (my d_graphics);
+ #else
+ drawNow (me);
+ #endif
+ }
if (needsUpdate) updateGroup (me);
-#if cocoa
- if (needsUpdate) {
- [(GuiCocoaDrawingArea*)my drawingArea -> d_widget flush];
- }
-#endif
}
else /* Clicked outside signal region? Let us hear it. */
{
@@ -1142,6 +1146,10 @@ void structFunctionEditor :: v_createChildren () {
#if gtk
Melder_assert (text -> d_widget);
gtk_widget_grab_focus (GTK_WIDGET (text -> d_widget)); // BUG: can hardly be correct (the text should grab the focus of the window, not the global focus)
+ #elif cocoa
+ Melder_assert ([(NSView *) text -> d_widget window]);
+ //[[(NSView *) text -> d_widget window] setInitialFirstResponder: (NSView *) text -> d_widget];
+ [[(NSView *) text -> d_widget window] makeFirstResponder: (NSView *) text -> d_widget];
#endif
}
@@ -1187,20 +1195,12 @@ static void drawWhileDragging (FunctionEditor me, double x1, double x2) {
Graphics_setTextAlignment (my d_graphics, Graphics_LEFT, Graphics_BOTTOM);
Graphics_text1 (my d_graphics, xright, 0.0, Melder_fixed (xright, 6));
Graphics_xorOff (my d_graphics);
-#if cocoa
- [(GuiCocoaDrawingArea*)my drawingArea -> d_widget flush];
-#endif
}
int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKeyPressed) {
bool drag = false;
double x = xbegin, y = ybegin;
-#if cocoa
- // Need to rewrite this to handle moved events
- if (clickEvent->type == BUTTON_RELEASE || clickEvent->type == MOTION_NOTIFY)
- return FunctionEditor_NO_UPDATE_NEEDED;
-#endif
/*
* The 'anchor' is the point that will stay fixed during dragging.
@@ -1209,8 +1209,10 @@ int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKey
* even if she later chooses to drag the mouse to the left of it.
* Another example: if she shift-clicks near E, B will become (and stay) the anchor.
*/
- double anchorForDragging = xbegin; // the default (for if the shift key isn't pressed)
+
Graphics_setWindow (d_graphics, d_startWindow, d_endWindow, 0, 1);
+
+ double anchorForDragging = xbegin; // the default (for if the shift key isn't pressed)
if (shiftKeyPressed) {
/*
* Extend the selection.
@@ -1293,6 +1295,7 @@ int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKey
/*
* Find out whether this is a click or a drag.
*/
+
while (Graphics_mouseStillDown (d_graphics)) {
Graphics_getMouseLocation (d_graphics, & x, & y);
if (x < d_startWindow) x = d_startWindow;
@@ -1302,6 +1305,7 @@ int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKey
break;
}
}
+
if (drag) {
/*
* First undraw the old selection.
@@ -1322,7 +1326,7 @@ int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKey
* Draw the text at least once.
*/
/*if (x < d_startWindow) x = d_startWindow; else if (x > d_endWindow) x = d_endWindow;*/
- drawWhileDragging (this, anchorForDragging, x);
+ drawWhileDragging (this, anchorForDragging, x);
/*
* Draw the dragged selection at least once.
*/
@@ -1334,21 +1338,25 @@ int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKey
/*
* Drag for the new selection.
*/
- while (Graphics_mouseStillDown (d_graphics)) {
+
+ while (Graphics_mouseStillDown (d_graphics))
+ {
double xold = x, x1, x2;
Graphics_getMouseLocation (d_graphics, & x, & y);
/*
* Clip to the visible window. Ideally, we should perform autoscrolling instead, though...
*/
if (x < d_startWindow) x = d_startWindow; else if (x > d_endWindow) x = d_endWindow;
+
if (x == xold)
continue;
+
/*
- * Undraw and redraw the text at the top.
+ * Undraw the text.
*/
drawWhileDragging (this, anchorForDragging, xold);
/*
- * Remove previous dragged selection.
+ * Undraw previous dragged selection.
*/
if (xold > anchorForDragging) x1 = anchorForDragging, x2 = xold; else x1 = xold, x2 = anchorForDragging;
if (x1 != x2) v_unhighlightSelection (x1, x2, 0, 1);
@@ -1358,10 +1366,10 @@ int structFunctionEditor :: v_click (double xbegin, double ybegin, bool shiftKey
if (x > anchorForDragging) x1 = anchorForDragging, x2 = x; else x1 = x, x2 = anchorForDragging;
if (x1 != x2) v_highlightSelection (x1, x2, 0, 1);
/*
- * Redraw the text at the top.
+ * Redraw the text at the new location.
*/
- drawWhileDragging (this, anchorForDragging, x);
- } ;
+ drawWhileDragging (this, anchorForDragging, x);
+ } ;
/*
* Set the new selection.
*/
diff --git a/fon/FunctionEditor.h b/fon/FunctionEditor.h
index 253a0cb..8d19aaf 100644
--- a/fon/FunctionEditor.h
+++ b/fon/FunctionEditor.h
@@ -125,11 +125,10 @@ Thing_define (FunctionEditor, Editor) {
virtual void v_form_pictureSelection (EditorCommand cmd);
virtual void v_ok_pictureSelection (EditorCommand cmd);
virtual void v_do_pictureSelection (EditorCommand cmd);
- // new preferences:
- #include "FunctionEditor_prefs.h"
-#if cocoa
- GuiDrawingAreaClickEvent clickEvent;
-#endif
+
+ // new preferences:
+ #include "FunctionEditor_prefs.h"
+
};
int theFunctionEditor_playCallback (void *void_me, int phase, double tmin, double tmax, double t);
diff --git a/fon/Makefile b/fon/Makefile
index b7d96d9..74977ba 100644
--- a/fon/Makefile
+++ b/fon/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "fon"
-# Paul Boersma, 14 January 2012
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -50,7 +50,7 @@ clean:
libfon.a: $(OBJECTS)
touch libfon.a
rm libfon.a
- ar cq libfon.a $(OBJECTS)
+ $(AR) cq libfon.a $(OBJECTS)
$(RANLIB) libfon.a
$(OBJECTS): *.h ../num/NUM.h ../external/portaudio/*.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../LPC/*.h ../external/flac/*.h ../external/mp3/mp3.h
diff --git a/fon/RunnerMFC.cpp b/fon/RunnerMFC.cpp
index 6a95804..e533cca 100644
--- a/fon/RunnerMFC.cpp
+++ b/fon/RunnerMFC.cpp
@@ -272,7 +272,6 @@ static void do_replay (RunnerMFC me) {
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (RunnerMFC);
if (my graphics == NULL) return; // Could be the case in the very beginning.
-if (gtk && event -> type != BUTTON_PRESS) return;
ExperimentMFC experiment = (ExperimentMFC) my data;
if (my data == NULL) return;
double reactionTime = Melder_clock () - experiment -> startingTime;
diff --git a/fon/Sound.cpp b/fon/Sound.cpp
index 14cf1df..8175246 100644
--- a/fon/Sound.cpp
+++ b/fon/Sound.cpp
@@ -1095,6 +1095,43 @@ Sound Sound_extractPart (Sound me, double t1, double t2, enum kSound_windowShape
}
}
+Sound Sound_extractPartForOverlap (Sound me, double t1, double t2, double overlap) {
+ try {
+ if (t1 == t2) { t1 = my xmin; t2 = my xmax; }; // autowindow
+ if (overlap > 0.0) {
+ double margin = 0.5 * overlap;
+ t1 -= margin;
+ t2 += margin;
+ }
+ if (t1 < my xmin) t1 = my xmin; // clip to my time domain
+ if (t2 > my xmax) t2 = my xmax;
+ /*
+ * 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);
+ if (ix2 < ix1) Melder_throw ("Extracted Sound would contain no samples.");
+ /*
+ * Create sound.
+ */
+ autoSound thee = Sound_create (my ny, t1, t2, ix2 - ix1 + 1, my dx, my x1 + (ix1 - 1) * my dx);
+ thy xmin = 0.0;
+ thy xmax -= t1;
+ thy x1 -= t1;
+ /*
+ * Copy only *real* samples into the new sound.
+ * The *virtual* samples will remain at zero.
+ */
+ for (long 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 ));
+ }
+ return thee.transfer();
+ } catch (MelderError) {
+ Melder_throw (me, ": part not extracted.");
+ }
+}
+
void Sound_filterWithFormants (Sound me, double tmin, double tmax,
int numberOfFormants, double formant [], double bandwidth [])
{
diff --git a/fon/Sound.h b/fon/Sound.h
index 97acb59..c6097b8 100644
--- a/fon/Sound.h
+++ b/fon/Sound.h
@@ -172,6 +172,7 @@ void Sound_multiplyByWindow (Sound me, enum kSound_windowShape windowShape);
void Sound_scaleIntensity (Sound me, double newAverageIntensity);
void Sound_overrideSamplingFrequency (Sound me, double newSamplingFrequency);
Sound Sound_extractPart (Sound me, double t1, double t2, enum kSound_windowShape windowShape, double relativeWidth, bool preserveTimes);
+Sound Sound_extractPartForOverlap (Sound me, double t1, double t2, double overlap);
void Sound_filterWithFormants (Sound me, double tmin, double tmax,
int numberOfFormants, double formant [], double bandwidth []);
Sound Sound_filter_oneFormant (Sound me, double frequency, double bandwidth);
diff --git a/fon/Sound_audio.cpp b/fon/Sound_audio.cpp
index 1a17533..f5f85bc 100644
--- a/fon/Sound_audio.cpp
+++ b/fon/Sound_audio.cpp
@@ -136,6 +136,8 @@ static int portaudioStreamCallback (
unsigned long dsamples = samplesLeft > frameCount ? frameCount : samplesLeft;
memcpy (info -> buffer + 1 + info -> numberOfSamplesRead, input, 2 * dsamples);
info -> numberOfSamplesRead += dsamples;
+ short *input2 = (short*) input;
+ trace ("read %d samples: %d, %d, %d...", (int) dsamples, (int) input2 [0], (int) input2 [1], (int) input2 [3]);
if (info -> numberOfSamplesRead >= info -> numberOfSamples) return paComplete;
} else /*if (info -> numberOfSamplesRead >= info -> numberOfSamples)*/ {
info -> numberOfSamplesRead = info -> numberOfSamples;
@@ -391,6 +393,7 @@ Sound Sound_recordFixedTime (int inputSource, double gain, double balance, doubl
Melder_throw ("Error ", err, " while opening.");
#endif
}
+for (i = 1; i <= numberOfSamples; i ++) trace ("Started %d", (int) buffer [i]);
/* Read the sound into the buffer. */
@@ -400,6 +403,7 @@ Sound Sound_recordFixedTime (int inputSource, double gain, double balance, doubl
//Pa_Sleep (1);
//Melder_casual ("filled %ld/%ld", getNumberOfSamplesRead (& info), numberOfSamples);
}
+for (i = 1; i <= numberOfSamples; i ++) trace ("Recorded %d", (int) buffer [i]);
} else {
#if defined (macintosh)
#elif defined (_WIN32)
diff --git a/fon/Sound_files.cpp b/fon/Sound_files.cpp
index 9365b00..ed61ca9 100644
--- a/fon/Sound_files.cpp
+++ b/fon/Sound_files.cpp
@@ -199,14 +199,16 @@ Sound Sound_readFromKayFile (MelderFile file) {
if (! strnequ (data, "FORMDS16", 8))
Melder_throw ("Not a KAY DS-16 file.");
- /* HEDR chunk */
+ /* HEDR or HDR8 chunk */
if (fread (data, 1, 4, f) < 4) readError ();
- if (! strnequ (data, "HEDR", 4))
- Melder_throw ("Missing HEDR chunk.");
+ if (! strnequ (data, "HEDR", 4) && ! strnequ (data, "HDR8", 4))
+ Melder_throw ("Missing HEDR or HDR8 chunk. Please report to paul.boersma at uva.nl.");
unsigned long chunkSize = bingetu4LE (f);
if (chunkSize & 1) ++ chunkSize;
- if (fread (data, 1, chunkSize - 12, f) < chunkSize - 12) readError ();
+ if (chunkSize != 32 && chunkSize != 44)
+ Melder_throw ("Unknown chunk size %ld. Please report to paul.boersma at uva.nl.", chunkSize);
+ if (fread (data, 1, 20, f) < 20) readError ();
double samplingFrequency = bingetu4LE (f);
unsigned long numberOfSamples = bingetu4LE (f);
if (samplingFrequency <= 0 || samplingFrequency > 1e7 || numberOfSamples >= 1000000000)
@@ -214,13 +216,15 @@ Sound Sound_readFromKayFile (MelderFile file) {
signed int tmp1 = bingeti2LE (f);
signed int tmp2 = bingeti2LE (f);
long numberOfChannels = tmp1 == -1 || tmp2 == -1 ? 1 : 2;
+ if (chunkSize == 44)
+ if (fread (data, 1, 12, f) < 12) readError ();
/* SD chunk */
if (fread (data, 1, 4, f) < 4) readError ();
while (! strnequ (data, "SDA_", 4) && ! strnequ (data, "SD_B", 4)) {
if (feof (f))
- Melder_throw ("Missing or unreadable SD chunk.");
+ Melder_throw ("Missing or unreadable SD chunk. Please report to paul.boersma at uva.nl.");
chunkSize = bingetu4LE (f);
if (chunkSize & 1) ++ chunkSize;
if (fread (data, 1, chunkSize, f) < chunkSize) readError ();
@@ -228,7 +232,7 @@ Sound Sound_readFromKayFile (MelderFile file) {
}
chunkSize = bingetu4LE (f);
if (chunkSize != numberOfSamples * 2)
- Melder_throw ("Incomplete SD chunk.");
+ Melder_throw ("Incomplete SD chunk. Please report to paul.boersma at uva.nl.");
autoSound me = Sound_createSimple (numberOfChannels, numberOfSamples / samplingFrequency, samplingFrequency);
for (long ichan = 1; ichan <= numberOfChannels; ichan ++) {
diff --git a/fon/TextGrid.cpp b/fon/TextGrid.cpp
index 277c7a5..88adc7f 100644
--- a/fon/TextGrid.cpp
+++ b/fon/TextGrid.cpp
@@ -369,7 +369,7 @@ IntervalTier TextGrid_checkSpecifiedTierIsIntervalTier (TextGrid me, long tierNu
TextGrid_checkSpecifiedTierNumberWithinRange (me, tierNumber);
Function tier = (Function) my tiers -> item [tierNumber];
if (tier -> classInfo != classIntervalTier)
- Melder_throw ("Tier ", tierNumber, " should be an interval tier.");
+ Melder_throw ("Tier ", tierNumber, " is not an interval tier.");
return (IntervalTier) tier;
}
@@ -377,7 +377,7 @@ TextTier TextGrid_checkSpecifiedTierIsPointTier (TextGrid me, long tierNumber) {
TextGrid_checkSpecifiedTierNumberWithinRange (me, tierNumber);
Function tier = (Function) my tiers -> item [tierNumber];
if (tier -> classInfo != classTextTier)
- Melder_throw ("Tier ", tierNumber, " should be a point tier.");
+ Melder_throw ("Tier ", tierNumber, " is not a point tier.");
return (TextTier) tier;
}
@@ -606,7 +606,7 @@ PointProcess TextGrid_getStartingPoints (TextGrid me, long tierNumber, int which
IntervalTier tier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
autoPointProcess thee = PointProcess_create (my xmin, my xmax, 10);
for (long iinterval = 1; iinterval <= tier -> intervals -> size; iinterval ++) {
- TextInterval interval = (TextInterval) tier -> intervals -> item [iinterval];
+ TextInterval interval = tier -> f_item (iinterval);
if (Melder_stringMatchesCriterion (interval -> text, which_Melder_STRING, criterion)) {
PointProcess_addPoint (thee.peek(), interval -> xmin);
}
@@ -622,7 +622,7 @@ PointProcess TextGrid_getEndPoints (TextGrid me, long tierNumber, int which_Meld
IntervalTier tier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
autoPointProcess thee = PointProcess_create (my xmin, my xmax, 10);
for (long iinterval = 1; iinterval <= tier -> intervals -> size; iinterval ++) {
- TextInterval interval = (TextInterval) tier -> intervals -> item [iinterval];
+ TextInterval interval = tier -> f_item (iinterval);
if (Melder_stringMatchesCriterion (interval -> text, which_Melder_STRING, criterion)) {
PointProcess_addPoint (thee.peek(), interval -> xmax);
}
@@ -638,7 +638,7 @@ PointProcess TextGrid_getCentrePoints (TextGrid me, long tierNumber, int which_M
IntervalTier tier = TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
autoPointProcess thee = PointProcess_create (my xmin, my xmax, 10);
for (long iinterval = 1; iinterval <= tier -> intervals -> size; iinterval ++) {
- TextInterval interval = (TextInterval) tier -> intervals -> item [iinterval];
+ TextInterval interval = tier -> f_item (iinterval);
if (Melder_stringMatchesCriterion (interval -> text, which_Melder_STRING, criterion)) {
PointProcess_addPoint (thee.peek(), 0.5 * (interval -> xmin + interval -> xmax));
}
@@ -1625,6 +1625,7 @@ void TextGrid_correctRoundingErrors (TextGrid me) {
TextInterval left = (TextInterval) tier -> intervals -> item [iinterval];
TextInterval right = (TextInterval) tier -> intervals -> item [iinterval + 1];
right -> xmin = left -> xmax;
+ trace ("tier %ld, interval %ld, %17g %17g", itier, iinterval, right -> xmin, right -> xmax);
Melder_assert (right -> xmin < right -> xmax);
}
TextInterval last = (TextInterval) tier -> intervals -> item [tier -> intervals -> size];
diff --git a/fon/TextGridEditor.cpp b/fon/TextGridEditor.cpp
index 3b1b634..831ad65 100644
--- a/fon/TextGridEditor.cpp
+++ b/fon/TextGridEditor.cpp
@@ -23,6 +23,7 @@
#include "SoundEditor.h"
#include "Sound_and_Spectrogram.h"
#include "TextGrid_Sound.h"
+#include "SpeechSynthesizer_and_TextGrid.h"
#include "enums_getText.h"
#include "TextGridEditor_enums.h"
@@ -673,6 +674,56 @@ static void menu_cb_InsertIntervalOnTier6 (EDITOR_ARGS) { EDITOR_IAM (TextGridEd
static void menu_cb_InsertIntervalOnTier7 (EDITOR_ARGS) { EDITOR_IAM (TextGridEditor); do_insertIntervalOnTier (me, 7); }
static void menu_cb_InsertIntervalOnTier8 (EDITOR_ARGS) { EDITOR_IAM (TextGridEditor); do_insertIntervalOnTier (me, 8); }
+static void menu_cb_AlignInterval (EDITOR_ARGS) {
+ EDITOR_IAM (TextGridEditor);
+ TextGrid grid = (TextGrid) my data;
+ checkTierSelection (me, L"align words");
+ AnyTier tier = static_cast <AnyTier> (grid -> tiers -> item [my selectedTier]);
+ if (tier -> classInfo != classIntervalTier)
+ Melder_throw ("Alignment works only for interval tiers, whereas tier ", my selectedTier, " is a point tier.\nSelect an interval tier instead.");
+ long intervalNumber = getSelectedInterval (me);
+ if (! intervalNumber)
+ Melder_throw ("Select an interval first");
+ if (! my p_align_includeWords && ! my p_align_includePhonemes)
+ Melder_throw ("Nothing to be done.\nPlease switch on \"Include words\" and/or \"Include phonemes\" in the \"Alignment settings\".");
+ {// scope
+ autoMelderProgressOff noprogress;
+ Function anySound = my d_sound.data;
+ if (my d_longSound.data) anySound = my d_longSound.data;
+ Editor_save (me, L"Align interval");
+ TextGrid_anySound_alignInterval (grid, anySound, my selectedTier, intervalNumber,
+ my p_align_language, my p_align_includeWords, my p_align_includePhonemes);
+ }
+ FunctionEditor_redraw (me);
+ my broadcastDataChanged ();
+}
+
+static void menu_cb_AlignmentSettings (EDITOR_ARGS) {
+ EDITOR_IAM (TextGridEditor);
+ EDITOR_FORM (L"Alignment settings", 0)
+ OPTIONMENU (L"Language", Strings_findString (espeakdata_voices_names, L"English"))
+ for (long i = 1; i <= espeakdata_voices_names -> numberOfStrings; i ++) {
+ OPTION ((const wchar_t *) espeakdata_voices_names -> strings [i]);
+ }
+ BOOLEAN (L"Include words", my default_align_includeWords ())
+ BOOLEAN (L"Include phonemes", my default_align_includePhonemes ())
+ BOOLEAN (L"Allow silences", my default_align_allowSilences ())
+ EDITOR_OK
+ long prefVoice = Strings_findString (espeakdata_voices_names, my p_align_language);
+ if (prefVoice == 0) prefVoice = Strings_findString (espeakdata_voices_names, L"English");
+ SET_INTEGER (L"Language", prefVoice);
+ SET_INTEGER (L"Include words", my p_align_includeWords)
+ SET_INTEGER (L"Include phonemes", my p_align_includePhonemes)
+ SET_INTEGER (L"Allow silences", my p_align_allowSilences)
+ EDITOR_DO
+ //my pref_align_language () = my p_align_language = GET_ENUM (kTextGrid_language, L"Language");
+ pref_wcscpy2 (my pref_align_language (), my p_align_language, GET_STRING (L"Language"));
+ my pref_align_includeWords () = my p_align_includeWords = GET_INTEGER (L"Include words");
+ my pref_align_includePhonemes () = my p_align_includePhonemes = GET_INTEGER (L"Include phonemes");
+ my pref_align_allowSilences () = my p_align_allowSilences = GET_INTEGER (L"Allow silences");
+ EDITOR_END
+}
+
/***** BOUNDARY/POINT MENU *****/
static void menu_cb_RemovePointOrBoundary (EDITOR_ARGS) {
@@ -1176,6 +1227,11 @@ void structTextGridEditor :: v_createMenus () {
Editor_addCommand (this, L"Query", L"Get label of interval", 0, menu_cb_GetLabelOfInterval);
menu = Editor_addMenu (this, L"Interval", 0);
+ if (d_sound.data || d_longSound.data) {
+ EditorMenu_addCommand (menu, L"Align interval", 'D', menu_cb_AlignInterval);
+ EditorMenu_addCommand (menu, L"Alignment settings...", 0, menu_cb_AlignmentSettings);
+ EditorMenu_addCommand (menu, L"-- add interval --", 0, NULL);
+ }
EditorMenu_addCommand (menu, L"Add interval on tier 1", GuiMenu_COMMAND | '1', menu_cb_InsertIntervalOnTier1);
EditorMenu_addCommand (menu, L"Add interval on tier 2", GuiMenu_COMMAND | '2', menu_cb_InsertIntervalOnTier2);
EditorMenu_addCommand (menu, L"Add interval on tier 3", GuiMenu_COMMAND | '3', menu_cb_InsertIntervalOnTier3);
@@ -1188,9 +1244,10 @@ void structTextGridEditor :: v_createMenus () {
menu = Editor_addMenu (this, L"Boundary", 0);
/*EditorMenu_addCommand (menu, L"Move to B", 0, menu_cb_MoveToB);
EditorMenu_addCommand (menu, L"Move to E", 0, menu_cb_MoveToE);*/
- if (d_sound.data)
+ if (d_sound.data) {
EditorMenu_addCommand (menu, L"Move to nearest zero crossing", 0, menu_cb_MoveToZero);
- EditorMenu_addCommand (menu, L"-- insert boundary --", 0, NULL);
+ EditorMenu_addCommand (menu, L"-- insert boundary --", 0, NULL);
+ }
EditorMenu_addCommand (menu, L"Add on selected tier", GuiMenu_ENTER, menu_cb_InsertOnSelectedTier);
EditorMenu_addCommand (menu, L"Add on tier 1", GuiMenu_COMMAND | GuiMenu_F1, menu_cb_InsertOnTier1);
EditorMenu_addCommand (menu, L"Add on tier 2", GuiMenu_COMMAND | GuiMenu_F2, menu_cb_InsertOnTier2);
@@ -2021,6 +2078,7 @@ void structTextGridEditor :: v_play (double tmin, double tmax) {
void structTextGridEditor :: v_updateText () {
TextGrid grid = (TextGrid) data;
const wchar_t *newText = L"";
+ trace ("selected tier %ld", selectedTier);
if (selectedTier) {
IntervalTier intervalTier;
TextTier textTier;
@@ -2045,6 +2103,7 @@ void structTextGridEditor :: v_updateText () {
}
//Melder_casual ("v_updateText in editor %ld %ls %d", this, name, (int) suppressRedraw);
suppressRedraw = TRUE; // prevent valueChangedCallback from redrawing
+ trace ("setting new text %ls", newText);
text -> f_setString (newText);
long cursor = wcslen (newText); // at end
text -> f_setSelection (cursor, cursor);
@@ -2145,6 +2204,7 @@ void structTextGridEditor :: f_init (const wchar_t *title, TextGrid grid, Sample
structTimeSoundAnalysisEditor :: f_init (title, grid, a_sound, a_ownSound);
this -> selectedTier = 1;
+ v_updateText (); // to reflect changed tier selection
if (d_endWindow - d_startWindow > 30.0) {
d_endWindow = d_startWindow + 30.0;
if (d_startWindow == d_tmin)
diff --git a/fon/TextGridEditor_enums.h b/fon/TextGridEditor_enums.h
index ca5f8fc..364a70c 100644
--- a/fon/TextGridEditor_enums.h
+++ b/fon/TextGridEditor_enums.h
@@ -23,4 +23,32 @@ enums_begin (kTextGridEditor_showNumberOf, 1)
enums_add (kTextGridEditor_showNumberOf, 3, NONEMPTY_INTERVALS_OR_POINTS, L"non-empty intervals or points")
enums_end (kTextGridEditor_showNumberOf, 3, INTERVALS_OR_POINTS)
+enums_begin (kTextGridEditor_language, 1)
+ enums_add (kTextGridEditor_language, 1, AFRIKAANS, L"Afrikaans")
+ enums_add (kTextGridEditor_language, 2, AKAN, L"Akan")
+ enums_add (kTextGridEditor_language, 3, ALBANIAN, L"Albanian")
+ enums_add (kTextGridEditor_language, 4, AMHARIC, L"Amharic")
+ enums_add (kTextGridEditor_language, 5, ARMENIAN, L"Armenian")
+ enums_add (kTextGridEditor_language, 6, ARMENIAN_WEST, L"Armenian (West)")
+ enums_add (kTextGridEditor_language, 7, AZERBAIJANI, L"Azerbaijani")
+ enums_add (kTextGridEditor_language, 8, BOSNIAN, L"Bosnian")
+ enums_add (kTextGridEditor_language, 9, BULGARIAN, L"Bulgarian")
+ enums_add (kTextGridEditor_language, 10, CANTONESE, L"Cantonese")
+ enums_add (kTextGridEditor_language, 11, CATALAN, L"Catalan")
+ enums_add (kTextGridEditor_language, 12, CROATIAN, L"Croatian")
+ enums_add (kTextGridEditor_language, 13, CZECH, L"Czech")
+ enums_add (kTextGridEditor_language, 14, DARI, L"Danish")
+ enums_add (kTextGridEditor_language, 15, DEFAULT_LANGUAGE, L"Default language")
+ enums_add (kTextGridEditor_language, 16, DIVEHI, L"Divehi")
+ enums_add (kTextGridEditor_language, 17, DUTCH, L"Dutch-test")
+ enums_add (kTextGridEditor_language, 18, ENGLISH_AMERICAN, L"English (American)")
+ enums_add (kTextGridEditor_language, 19, ENGLISH_RP, L"English (RP)")
+ enums_add (kTextGridEditor_language, 20, ENGLISH_SCOTLAND, L"English (Scotland)")
+ enums_add (kTextGridEditor_language, 21, ENGLISH_SOUTHERN_ENGLAND, L"English (Southern England)")
+ enums_add (kTextGridEditor_language, 22, ENGLISH_WEST_INDIES, L"English (West Indies)")
+ enums_add (kTextGridEditor_language, 22, ENGLISH_WEST_MIDLANDS, L"English (West Midlands)")
+ enums_add (kTextGridEditor_language, 23, PORTUGUESE_BRAZILIAN, L"Portuguese (Brazilian)")
+ enums_add (kTextGridEditor_language, 24, PORTUGUESE_EUROPEAN, L"Portuguese (European)")
+enums_end (kTextGridEditor_language, 2, ENGLISH_AMERICAN)
+
/* End of file TextGridEditor_enums.h */
diff --git a/fon/TextGridEditor_prefs.h b/fon/TextGridEditor_prefs.h
index e9cae69..fa51467 100644
--- a/fon/TextGridEditor_prefs.h
+++ b/fon/TextGridEditor_prefs.h
@@ -32,6 +32,10 @@ prefs_begin (TextGridEditor)
prefs_add_string_with_data (TextGridEditor, greenString, 1, L"some text here for green paint")
prefs_add_bool (TextGridEditor, picture_showBoundaries, 1, true)
prefs_add_bool (TextGridEditor, picture_pitch_speckle, 1, false)
+ prefs_add_string_with_data (TextGridEditor, align_language, 1, L"English")
+ prefs_add_bool_with_data (TextGridEditor, align_includeWords, 1, true)
+ prefs_add_bool_with_data (TextGridEditor, align_includePhonemes, 1, false)
+ prefs_add_bool_with_data (TextGridEditor, align_allowSilences, 1, false)
prefs_end (TextGridEditor)
/* End of file TextGridEditor_prefs.h */
diff --git a/fon/TextGrid_Sound.cpp b/fon/TextGrid_Sound.cpp
index 9fa0e56..fb22c3a 100644
--- a/fon/TextGrid_Sound.cpp
+++ b/fon/TextGrid_Sound.cpp
@@ -1,6 +1,6 @@
/* TextGrid_Sound.cpp
*
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,268 @@
#include "TextGrid_Sound.h"
#include "Pitch_to_PitchTier.h"
+#include "SpeechSynthesizer_and_TextGrid.h"
+#include "LongSound.h"
+
+static void IntervalTier_insertIntervalDestructively (IntervalTier me, double tmin, double tmax) {
+ Melder_assert (tmin < tmax);
+ Melder_assert (tmin >= my xmin);
+ Melder_assert (tmax <= my xmax);
+ /*
+ * Make sure that the tier has boundaries at the edges of the interval.
+ */
+ long firstIntervalNumber = IntervalTier_hasTime (me, tmin);
+ if (! firstIntervalNumber) {
+ long intervalNumber = IntervalTier_timeToIndex (me, tmin);
+ if (intervalNumber == 0)
+ Melder_throw ("Cannot add a boundary at ", Melder_fixed (tmin, 6), " seconds, because this is outside the time domain of the intervals.");
+ Thing_cast (TextInterval, interval, my intervals -> item [intervalNumber]);
+ /*
+ * Move the text to the left of the boundary.
+ */
+ autoTextInterval newInterval = TextInterval_create (tmin, interval -> xmax, L"");
+ interval -> xmax = tmin;
+ Collection_addItem (my intervals, newInterval.transfer());
+ firstIntervalNumber = IntervalTier_hasTime (me, interval -> xmin);
+ }
+ Melder_assert (firstIntervalNumber >= 1 && firstIntervalNumber <= my intervals -> size);
+ long lastIntervalNumber = IntervalTier_hasTime (me, tmax);
+ if (! lastIntervalNumber) {
+ long intervalNumber = IntervalTier_timeToIndex (me, tmax);
+ if (intervalNumber == 0)
+ Melder_throw ("Cannot add a boundary at ", Melder_fixed (tmin, 6), " seconds, because this is outside the time domain of the intervals.");
+ Thing_cast (TextInterval, interval, my intervals -> item [intervalNumber]);
+ /*
+ * Move the text to the right of the boundary.
+ */
+ autoTextInterval newInterval = TextInterval_create (interval -> xmin, tmax, L"");
+ interval -> xmin = tmax;
+ Collection_addItem (my intervals, newInterval.transfer());
+ lastIntervalNumber = IntervalTier_hasTime (me, interval -> xmax);
+ }
+ Melder_assert (lastIntervalNumber >= 1 && lastIntervalNumber <= my intervals -> size);
+ /*
+ * Empty the interval in the word tier.
+ */
+ trace ("Empty interval %ld down to %ld.", lastIntervalNumber, firstIntervalNumber);
+ for (long iinterval = lastIntervalNumber; iinterval >= firstIntervalNumber; iinterval --) {
+ Thing_cast (TextInterval, interval, my intervals -> item [iinterval]);
+ if (interval -> xmin > tmin && interval -> xmin < tmax) {
+ Melder_assert (iinterval > 1);
+ TextInterval previous = (TextInterval) my intervals -> item [iinterval - 1];
+ previous -> xmax = tmax; // collapse left and right intervals into left interval
+ TextInterval_setText (previous, L"");
+ Collection_removeItem (my intervals, iinterval); // remove right interval
+ }
+ if (interval -> xmax == tmax) {
+ TextInterval_setText (interval, L"");
+ }
+ }
+}
+
+static double IntervalTier_boundaryTimeClosestTo (IntervalTier me, double tmin, double tmax) {
+ long intervalNumber = IntervalTier_timeToLowIndex (me, tmax);
+ if (intervalNumber != 0) {
+ TextInterval interval = static_cast <TextInterval> (my intervals -> item [intervalNumber]);
+ if (interval -> xmin > tmin && interval -> xmin < tmax) {
+ return interval -> xmin;
+ }
+ }
+ return 0.5 * (tmin + tmax);
+}
+
+static void IntervalTier_removeEmptyIntervals (IntervalTier me, IntervalTier boss) {
+ IntervalTier_removeBoundariesBetweenIdenticallyLabeledIntervals (me, L"");
+ if (my intervals -> size < 2) return;
+ Thing_cast (TextInterval, firstInterval, my intervals -> item [1]);
+ if (Melder_wcsequ (firstInterval -> text, L"")) {
+ IntervalTier_removeLeftBoundary (me, 2);
+ }
+ if (my intervals -> size < 2) return;
+ Thing_cast (TextInterval, lastInterval, my intervals -> item [my intervals -> size]);
+ if (Melder_wcsequ (lastInterval -> text, L"")) {
+ IntervalTier_removeLeftBoundary (me, my intervals -> size);
+ }
+ if (my intervals -> size < 3) return;
+ for (long iinterval = my intervals -> size - 1; iinterval >= 2; iinterval --) {
+ Thing_cast (TextInterval, interval, my intervals -> item [iinterval]);
+ if (Melder_wcsequ (interval -> text, L"")) {
+ /*
+ * Distribute the empty interval between its neigbours.
+ */
+ double newBoundaryTime =
+ boss ?
+ IntervalTier_boundaryTimeClosestTo (boss, interval -> xmin, interval -> xmax) :
+ 0.5 * (interval -> xmin + interval -> xmax);
+ Thing_cast (TextInterval, previous, my intervals -> item [iinterval - 1]);
+ Thing_cast (TextInterval, next, my intervals -> item [iinterval + 1]);
+ previous -> xmax = newBoundaryTime;
+ next -> xmin = newBoundaryTime;
+ Collection_removeItem (my intervals, iinterval);
+ }
+ }
+}
+
+void TextGrid_anySound_alignInterval (TextGrid me, Function anySound, long tierNumber, long intervalNumber, const wchar_t *languageName, bool includeWords, bool includePhonemes) {
+ try {
+ TextGrid_checkSpecifiedTierIsIntervalTier (me, tierNumber);
+ IntervalTier headTier = (IntervalTier) my tiers -> item [tierNumber];
+ if (intervalNumber < 1 || intervalNumber > headTier -> intervals -> size)
+ Melder_throw ("Interval ", intervalNumber, " does not exist.");
+ TextInterval interval = (TextInterval) headTier -> intervals -> item [intervalNumber];
+ if (! includeWords && ! includePhonemes)
+ Melder_throw ("Nothing to be done, because you asked neither for word alignment nor for phoneme alignment.");
+ if (wcsstr (headTier -> name, L"/") )
+ Melder_throw ("The current tier already has a slash (\"/\") in its name. Cannot create a word or phoneme tier from it.");
+ autoSound part =
+ anySound -> classInfo == classLongSound ?
+ LongSound_extractPart (static_cast <LongSound> (anySound), interval -> xmin, interval -> xmax, true) :
+ Sound_extractPart (static_cast <Sound> (anySound), interval -> xmin, interval -> xmax, kSound_windowShape_RECTANGULAR, 1.0, true);
+ autoSpeechSynthesizer synthesizer = SpeechSynthesizer_create (languageName, L"default");
+ double silenceThreshold = -35, minSilenceDuration = 0.1, minSoundingDuration = 0.1;
+ autoTextGrid analysis = NULL;
+ if (! Melder_wcsequ (interval -> text, L"")) {
+ try {
+ analysis.reset (SpeechSynthesizer_and_Sound_and_TextInterval_align
+ (synthesizer.peek(), part.peek(), interval, silenceThreshold, minSilenceDuration, minSoundingDuration));
+ } catch (MelderError) {
+ Melder_clearError (); // ignore all error messages from DTW and the like
+ }
+ }
+ if (analysis.peek()) {
+ /*
+ * Clean up the analysis.
+ */
+ Melder_assert (analysis -> xmin == interval -> xmin);
+ Melder_assert (analysis -> xmax == interval -> xmax);
+ Melder_assert (analysis -> tiers -> size == 4);
+ Thing_cast (IntervalTier, analysisWordTier, analysis -> tiers -> item [3]);
+ IntervalTier_removeEmptyIntervals (analysisWordTier, NULL);
+ Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers -> item [4]);
+ IntervalTier_removeEmptyIntervals (analysisPhonemeTier, analysisWordTier);
+ }
+ long wordTierNumber = 0, phonemeTierNumber = 0;
+ IntervalTier wordTier = NULL, phonemeTier = NULL;
+ /*
+ * Include a word tier.
+ */
+ if (includeWords) {
+ /*
+ * Make sure that the word tier exists.
+ */
+ autoMelderString newWordTierName;
+ MelderString_copy (& newWordTierName, headTier -> name);
+ MelderString_append (& newWordTierName, L"/word");
+ for (long itier = 1; itier <= my tiers -> size; itier ++) {
+ IntervalTier tier = static_cast <IntervalTier> (my tiers -> item [itier]);
+ if (Melder_wcsequ (newWordTierName.string, tier -> name)) {
+ if (tier -> classInfo != classIntervalTier)
+ Melder_throw ("A tier with the prospective word tier name (", tier -> name, ") already exists, but it is not an interval tier."
+ "\nPlease change its name or remove it.");
+ wordTierNumber = itier;
+ break;
+ }
+ }
+ if (! wordTierNumber) {
+ autoIntervalTier newWordTier = IntervalTier_create (my xmin, my xmax);
+ Thing_setName (newWordTier.peek(), newWordTierName.string);
+ Ordered_addItemPos (my tiers, newWordTier.transfer(), wordTierNumber = tierNumber + 1);
+ }
+ Melder_assert (wordTierNumber >= 1 && wordTierNumber <= my tiers -> size);
+ wordTier = static_cast <IntervalTier> (my tiers -> item [wordTierNumber]);
+ /*
+ * Make sure that the word tier has boundaries at the edges of the interval.
+ */
+ IntervalTier_insertIntervalDestructively (wordTier, interval -> xmin, interval -> xmax);
+ /*
+ * Copy the contents of the word analysis into the interval in the word tier.
+ */
+ long wordIntervalNumber = IntervalTier_hasTime (wordTier, interval -> xmin);
+ Melder_assert (wordIntervalNumber != 0);
+ if (analysis.peek()) {
+ Thing_cast (IntervalTier, analysisWordTier, analysis -> tiers -> item [3]);
+ for (long ianalysisInterval = 1; ianalysisInterval <= analysisWordTier -> intervals -> size; ianalysisInterval ++) {
+ Thing_cast (TextInterval, analysisInterval, analysisWordTier -> intervals -> item [ianalysisInterval]);
+ TextInterval wordInterval = NULL;
+ double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax;
+ if (tmax == analysis -> xmax) {
+ wordInterval = (TextInterval) wordTier -> intervals -> item [wordIntervalNumber];
+ TextInterval_setText (wordInterval, analysisInterval -> text);
+ } else {
+ wordInterval = (TextInterval) wordTier -> intervals -> item [wordIntervalNumber];
+ autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text);
+ wordInterval -> xmin = tmax;
+ Collection_addItem (wordTier -> intervals, newInterval.transfer());
+ wordIntervalNumber ++;
+ }
+ }
+ }
+ }
+ /*
+ * Include a phoneme tier.
+ */
+ if (includePhonemes) {
+ /*
+ * Make sure that the phoneme tier exists.
+ */
+ autoMelderString newPhonemeTierName;
+ MelderString_copy (& newPhonemeTierName, headTier -> name);
+ MelderString_append (& newPhonemeTierName, L"/phon");
+ for (long itier = 1; itier <= my tiers -> size; itier ++) {
+ IntervalTier tier = static_cast <IntervalTier> (my tiers -> item [itier]);
+ if (Melder_wcsequ (newPhonemeTierName.string, tier -> name)) {
+ if (tier -> classInfo != classIntervalTier)
+ Melder_throw ("A tier with the prospective phoneme tier name (", tier -> name, ") already exists, but it is not an interval tier."
+ "\nPlease change its name or remove it.");
+ phonemeTierNumber = itier;
+ break;
+ }
+ }
+ if (! phonemeTierNumber) {
+ autoIntervalTier newPhonemeTier = IntervalTier_create (my xmin, my xmax);
+ Thing_setName (newPhonemeTier.peek(), newPhonemeTierName.string);
+ Ordered_addItemPos (my tiers, newPhonemeTier.transfer(), phonemeTierNumber = wordTierNumber ? wordTierNumber + 1 : tierNumber + 1);
+ }
+ Melder_assert (phonemeTierNumber >= 1 && phonemeTierNumber <= my tiers -> size);
+ phonemeTier = static_cast <IntervalTier> (my tiers -> item [phonemeTierNumber]);
+ /*
+ * Make sure that the phoneme tier has boundaries at the edges of the interval.
+ */
+ IntervalTier_insertIntervalDestructively (phonemeTier, interval -> xmin, interval -> xmax);
+ /*
+ * Copy the contents of the phoneme analysis into the interval in the phoneme tier.
+ */
+ long phonemeIntervalNumber = IntervalTier_hasTime (phonemeTier, interval -> xmin);
+ Melder_assert (phonemeIntervalNumber != 0);
+ if (analysis.peek()) {
+ Thing_cast (IntervalTier, analysisPhonemeTier, analysis -> tiers -> item [4]);
+ for (long ianalysisInterval = 1; ianalysisInterval <= analysisPhonemeTier -> intervals -> size; ianalysisInterval ++) {
+ Thing_cast (TextInterval, analysisInterval, analysisPhonemeTier -> intervals -> item [ianalysisInterval]);
+ TextInterval phonemeInterval = NULL;
+ double tmin = analysisInterval -> xmin, tmax = analysisInterval -> xmax;
+ if (tmax == analysis -> xmax) {
+ phonemeInterval = (TextInterval) phonemeTier -> intervals -> item [phonemeIntervalNumber];
+ TextInterval_setText (phonemeInterval, analysisInterval -> text);
+ } else {
+ phonemeInterval = (TextInterval) phonemeTier -> intervals -> item [phonemeIntervalNumber];
+ autoTextInterval newInterval = TextInterval_create (tmin, tmax, analysisInterval -> text);
+ phonemeInterval -> xmin = tmax;
+ Collection_addItem (phonemeTier -> intervals, newInterval.transfer());
+ phonemeIntervalNumber ++;
+ }
+ }
+ }
+ if (includeWords) {
+ /*
+ * Synchronize the boundaries between the word tier and the phoneme tier.
+ */
+ //for (long iinterval = 1; iinterval <=
+ }
+ }
+ } catch (MelderError) {
+ Melder_throw (me, " & ", anySound, ": interval not aligned.");
+ }
+}
void TextGrid_Sound_draw (TextGrid me, Sound sound, Graphics g, double tmin, double tmax,
int showBoundaries, int useTextStyles, int garnish) // STEREO BUG
diff --git a/fon/TextGrid_Sound.h b/fon/TextGrid_Sound.h
index a7b27da..4b055f7 100644
--- a/fon/TextGrid_Sound.h
+++ b/fon/TextGrid_Sound.h
@@ -1,6 +1,6 @@
/* TextGrid_Sound.h
*
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,4 +34,7 @@ void TextGrid_Pitch_draw (TextGrid grid, Pitch pitch, Graphics g,
void TextGrid_Pitch_drawSeparately (TextGrid grid, Pitch pitch, Graphics g, double tmin, double tmax,
double fmin, double fmax, int showBoundaries, int useTextStyles, int garnish, int speckle, int yscale);
+void TextGrid_anySound_alignInterval (TextGrid me, Function anySound, long tierNumber, long intervalNumber,
+ const wchar_t *languageName, bool includeWords, bool includePhonemes);
+
/* End of file TextGrid_Sound.h */
diff --git a/fon/TextGrid_def.h b/fon/TextGrid_def.h
index 3621179..d341cff 100644
--- a/fon/TextGrid_def.h
+++ b/fon/TextGrid_def.h
@@ -53,6 +53,7 @@ oo_DEFINE_CLASS (TextTier, Function)
oo_COLLECTION (SortedSetOfDouble, points, TextPoint, 0)
#if oo_DECLARING
+ TextPoint f_item (long i) { return static_cast <TextPoint> (points -> item [i]); }
virtual int v_domainQuantity () { return MelderQuantity_TIME_SECONDS; }
virtual void v_shiftX (double xfrom, double xto);
virtual void v_scaleX (double xminfrom, double xmaxfrom, double xminto, double xmaxto);
@@ -68,6 +69,8 @@ oo_DEFINE_CLASS (IntervalTier, Function)
oo_COLLECTION (SortedSetOfDouble, intervals, TextInterval, 0)
#if oo_DECLARING
+ TextInterval f_item (long i) { return static_cast <TextInterval> (intervals -> item [i]); }
+ //TextInterval operator[] (long i) { return static_cast <TextInterval> (intervals -> item [i]); } // oops: operator[] not for pointer objects
virtual int v_domainQuantity () { return MelderQuantity_TIME_SECONDS; }
virtual void v_shiftX (double xfrom, double xto);
virtual void v_scaleX (double xminfrom, double xmaxfrom, double xminto, double xmaxto);
diff --git a/fon/TimeSoundAnalysisEditor.cpp b/fon/TimeSoundAnalysisEditor.cpp
index 7cfa01e..2060445 100644
--- a/fon/TimeSoundAnalysisEditor.cpp
+++ b/fon/TimeSoundAnalysisEditor.cpp
@@ -163,7 +163,9 @@ static int makeQueriable (TimeSoundAnalysisEditor me, int allowCursor, double *t
Melder_throw ("Make a selection first.");
}
} else if (my d_startSelection < my d_startWindow || my d_endSelection > my d_endWindow) {
- Melder_throw ("Command ambiguous: a part of the selection is out of view. Either zoom or re-select.");
+ Melder_throw ("Command ambiguous: a part of the selection (", my d_startSelection, ", ", my d_endSelection, ") "
+ "is outside of the window (", my d_startWindow, ", ", my d_endWindow, "). "
+ "Either zoom or re-select.");
}
*tmin = my d_startSelection;
*tmax = my d_endSelection;
diff --git a/fon/TimeSoundAnalysisEditor_prefs.h b/fon/TimeSoundAnalysisEditor_prefs.h
index e1eccb6..8aa3a03 100644
--- a/fon/TimeSoundAnalysisEditor_prefs.h
+++ b/fon/TimeSoundAnalysisEditor_prefs.h
@@ -62,7 +62,7 @@ prefs_begin (TimeSoundAnalysisEditor)
prefs_add_bool_with_data (TimeSoundAnalysisEditor, intensity_picture_garnish, 1, true)
prefs_add_bool_with_data (TimeSoundAnalysisEditor, formant_show, 1, false)
prefs_add_double_with_data (TimeSoundAnalysisEditor, formant_maximumFormant, 1, L"5500.0") // Hz
- prefs_add_long_with_data (TimeSoundAnalysisEditor, formant_numberOfFormants, 1, L"5.0")
+ prefs_add_double_with_data (TimeSoundAnalysisEditor, formant_numberOfFormants, 1, L"5.0")
prefs_add_double_with_data (TimeSoundAnalysisEditor, formant_windowLength, 1, L"0.025") // seconds
prefs_add_double_with_data (TimeSoundAnalysisEditor, formant_dynamicRange, 1, L"30.0") // dB
prefs_add_double_with_data (TimeSoundAnalysisEditor, formant_dotSize, 1, L"1.0") // mm
diff --git a/fon/TimeSoundEditor.cpp b/fon/TimeSoundEditor.cpp
index 7826de8..914960e 100644
--- a/fon/TimeSoundEditor.cpp
+++ b/fon/TimeSoundEditor.cpp
@@ -173,6 +173,24 @@ static void menu_cb_ExtractSelectedSound_windowed (EDITOR_ARGS) {
EDITOR_END
}
+static void menu_cb_ExtractSelectedSoundForOverlap (EDITOR_ARGS) {
+ EDITOR_IAM (TimeSoundEditor);
+ EDITOR_FORM (L"Extract selected sound for overlap)", 0)
+ WORD (L"Name", L"slice")
+ POSITIVE (L"Overlap (s)", my default_extract_overlap ())
+ EDITOR_OK
+ SET_REAL (L"Overlap", my pref_extract_overlap ())
+ EDITOR_DO
+ Sound sound = my d_sound.data;
+ Melder_assert (sound != NULL);
+ my pref_extract_overlap () = GET_REAL (L"Overlap");
+ autoSound extract = Sound_extractPartForOverlap (sound, my d_startSelection, my d_endSelection,
+ my pref_extract_overlap ());
+ Thing_setName (extract.peek(), GET_STRING (L"Name"));
+ my broadcastPublication (extract.transfer());
+ EDITOR_END
+}
+
static void do_write (TimeSoundEditor me, MelderFile file, int format, int numberOfBitsPersamplePoint) {
if (my d_startSelection >= my d_endSelection)
Melder_throw ("No samples selected.");
@@ -297,6 +315,7 @@ void structTimeSoundEditor :: v_createMenuItems_file_extract (EditorMenu menu) {
publishWindowButton = EditorMenu_addCommand (menu, L"Extract selected sound (windowed)...", 0, menu_cb_ExtractSelectedSound_windowed);
EditorMenu_addCommand (menu, L"Extract windowed sound selection...", Editor_HIDDEN, menu_cb_ExtractSelectedSound_windowed);
EditorMenu_addCommand (menu, L"Extract windowed selection...", Editor_HIDDEN, menu_cb_ExtractSelectedSound_windowed);
+ publishOverlapButton = EditorMenu_addCommand (menu, L"Extract selected sound for overlap...", 0, menu_cb_ExtractSelectedSoundForOverlap);
}
}
}
@@ -410,6 +429,7 @@ void structTimeSoundEditor :: v_updateMenuItems_file () {
publishButton -> f_setSensitive (selectedSamples != 0);
publishPreserveButton -> f_setSensitive (selectedSamples != 0);
if (publishWindowButton) publishWindowButton -> f_setSensitive (selectedSamples != 0);
+ if (publishOverlapButton) publishOverlapButton -> f_setSensitive (selectedSamples != 0);
}
writeWavButton -> f_setSensitive (selectedSamples != 0);
if (d_saveAs24BitWavButton)
diff --git a/fon/TimeSoundEditor.h b/fon/TimeSoundEditor.h
index d4844e2..589595c 100644
--- a/fon/TimeSoundEditor.h
+++ b/fon/TimeSoundEditor.h
@@ -2,7 +2,7 @@
#define _TimeSoundEditor_h_
/* TimeSoundEditor.h
*
- * Copyright (C) 1992-2012 Paul Boersma
+ * Copyright (C) 1992-2012, 2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@ Thing_define (TimeSoundEditor, FunctionEditor) {
bool d_ownSound;
struct TimeSoundEditor_sound d_sound;
struct { LongSound data; } d_longSound;
- GuiMenuItem drawButton, publishButton, publishPreserveButton, publishWindowButton;
+ GuiMenuItem drawButton, publishButton, publishPreserveButton, publishWindowButton, publishOverlapButton;
GuiMenuItem writeAiffButton, d_saveAs24BitWavButton, d_saveAs32BitWavButton, writeAifcButton, writeWavButton, writeNextSunButton, writeNistButton, writeFlacButton;
// messages:
public:
diff --git a/fon/TimeSoundEditor_prefs.h b/fon/TimeSoundEditor_prefs.h
index 8b472eb..2141dd4 100644
--- a/fon/TimeSoundEditor_prefs.h
+++ b/fon/TimeSoundEditor_prefs.h
@@ -30,6 +30,7 @@ prefs_begin (TimeSoundEditor)
prefs_add_enum (TimeSoundEditor, extract_windowShape, 1, kSound_windowShape, DEFAULT)
prefs_add_double (TimeSoundEditor, extract_relativeWidth, 1, L"1.0")
prefs_add_bool (TimeSoundEditor, extract_preserveTimes, 1, true)
+ prefs_add_double (TimeSoundEditor, extract_overlap, 1, L"0.01")
prefs_end (TimeSoundEditor)
/* End of file TimeSoundEditor_prefs.h */
diff --git a/fon/manual_Fon.cpp b/fon/manual_Fon.cpp
index c0e8851..327aaef 100644
--- a/fon/manual_Fon.cpp
+++ b/fon/manual_Fon.cpp
@@ -202,47 +202,52 @@ INTRO (L"A command in the @@New menu@ to create a @Strings object containing a l
"It works completely analogously to @@Create Strings as file list... at .")
MAN_END
-MAN_BEGIN (L"Create Strings as file list...", L"ppgb", 20060919)
+MAN_BEGIN (L"Create Strings as file list...", L"ppgb", 20130521)
INTRO (L"A command in the @@New menu@ to create a @Strings object containing a list of files in a given directory.")
ENTRY (L"Settings")
+SCRIPT (5.4, Manual_SETTINGS_WINDOW_HEIGHT (2.6), L""
+ Manual_DRAW_SETTINGS_WINDOW ("Create Strings as file list", 2.6)
+ Manual_DRAW_SETTINGS_WINDOW_FIELD ("Name", "fileList")
+ Manual_DRAW_SETTINGS_WINDOW_TEXT ("File path", "/Users/miep/Sounds/*.wav")
+)
TAG (L"##Name")
-DEFINITION (L"the name of the resulting Strings object, usually \"fileList\".")
-TAG (L"##Path")
-DEFINITION (L"the directory name, with an optional wildcard for selecting files.")
+DEFINITION (L"the name of the resulting Strings object.")
+TAG (L"##File path")
+DEFINITION (L"the directory name, with an optional %wildcard (see below) for selecting files.")
ENTRY (L"Behaviour")
NORMAL (L"The resulting Strings object will contain an alphabetical list of file names, "
- "without the preceding path through the directory structures. If there are not files that match %path, "
+ "without the preceding path through the directory structures. If there are no files that match the file path, "
"the Strings object will contain no strings.")
ENTRY (L"Usage")
-NORMAL (L"There are two ways to specify the path.")
-NORMAL (L"One way is to specify a directory name only. On Unix, you could type "
+NORMAL (L"There are two ways to specify the file path.")
+NORMAL (L"One way is to specify a directory name only. On Unix, the file path could be "
"##/usr/people/miep/sounds# or ##/usr/people/miep/sounds/#, for instance. On Windows, "
- "##C:\\bsDocument and Settings\\bsMiep\\bsSounds# or ##C:\\bsDocument and Settings\\bsMiep\\bsSounds\\bs#. "
- "On Macintosh, ##/Users/miep/Sounds# or ##/Users/miep/Sounds/#. Any of these return "
+ "##C:\\bsDocuments and Settings\\bsMiep\\bsSounds# or ##C:\\bsDocuments and Settings\\bsMiep\\bsSounds\\bs#. "
+ "On Macintosh, ##/Users/miep/Sounds# or ##/Users/miep/Sounds/#. Any of these produce "
"a list of all the files in the specified directory.")
NORMAL (L"The other way is to specify a wildcard (a single asterisk) for the file names. "
"To get a list of all the files whose names start with \"hal\" and end in \".wav\", "
- "type ##/usr/people/miep/sounds/hal*.wav#, ##C:\\bsDocument and Settings\\bsMiep\\bsSounds\\bshal*.wav#, "
+ "type ##/usr/people/miep/sounds/hal*.wav#, ##C:\\bsDocuments and Settings\\bsMiep\\bsSounds\\bshal*.wav#, "
"or ##/Users/miep/Sounds/hal*.wav#.")
ENTRY (L"Script usage")
NORMAL (L"In a script, you can use this command to cycle through the files in a directory. "
"For instance, to read in all the sound files in a specified directory, "
"you could use the following script:")
CODE (L"directory\\$ = \"/usr/people/miep/sounds\"")
-CODE (L"Create Strings as file list... list 'directory\\$ '/*.wav")
-CODE (L"numberOfFiles = Get number of strings")
+CODE (L"strings = do (\"Create Strings as file list...\", \"list\", directory\\$ + \"/*.wav\")")
+CODE (L"numberOfFiles = do (\"Get number of strings\")")
CODE (L"for ifile to numberOfFiles")
-CODE (L" select Strings list")
-CODE (L" fileName\\$ = Get string... ifile")
-CODE (L" Read from file... 'directory\\$ '/'fileName\\$ '")
+ CODE1 (L"selectObject (strings)")
+ CODE1 (L"fileName\\$ = do\\$ (\"Get string...\", ifile)")
+ CODE1 (L"do (\"Read from file...\", directory\\$ + \"/\" + fileName\\$ )")
CODE (L"endfor")
-NORMAL (L"If the script has been saved to a script file, you can use paths that are relative to the directory "
+NORMAL (L"If the script has been saved to a script file, you can use file paths that are relative to the directory "
"where you saved the script. Thus, with")
-CODE (L"Create Strings as file list... list *.wav")
+CODE (L"do (\"Create Strings as file list...\", \"list\", \"*.wav\")")
NORMAL (L"you get a list of all the .wav files that are in the same directory as the script that contains this line. "
"And to get a list of all the .wav files in the directory Sounds that resides in the same directory as your script, "
"you can do")
-CODE (L"Create Strings as file list... list Sounds/*.wav")
+CODE (L"do (\"Create Strings as file list...\", \"list\", \"Sounds/*.wav\")")
NORMAL (L"As is usual in Praat scripting, the forward slash (\"/\") in this example can be used on all platforms, including Windows. "
"This makes your script portable across platforms.")
ENTRY (L"See also")
diff --git a/fon/manual_Manual.cpp b/fon/manual_Manual.cpp
index 544e84d..0374a96 100644
--- a/fon/manual_Manual.cpp
+++ b/fon/manual_Manual.cpp
@@ -1,6 +1,6 @@
/* manual_Manual.cpp
*
- * Copyright (C) 1992-2011 Paul Boersma
+ * Copyright (C) 1992-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,7 +53,7 @@ ENTRY (L"Your own manual pages")
NORMAL (L"To create your own manual pages, create @ManPages text files.")
MAN_END
-MAN_BEGIN (L"ManPages", L"ppgb", 20110129)
+MAN_BEGIN (L"ManPages", L"ppgb", 20130814)
INTRO (L"You can create a documentation or education system with files that you and others "
"can read into Praat (with the @@Read from file...@ command). "
"Your files will become a hypertext system very similar to the usual @Manual.")
@@ -203,7 +203,7 @@ NORMAL (L"For obvious safety reasons, embedded scripts cannot contain commands t
NORMAL (L"The commands ##Set outer viewport...# and ##Set inner viewport...# are available; "
"they count in inches (if the font size of the manual is 12). The (0, 0) point is in the upper left corner, "
"as in the Picture window, so that you can test your picture with a normal Praat script; "
- "for instance, the following script draw a cross in the bottom half of the picture and a rectangle in the upper half:")
+ "for instance, the following script draws a cross in the upper half of the picture and a rectangle in the lower half:")
CODE (L"<script> 4.5 4 \"")
CODE1 (L"Axes... 0 100 0 100")
CODE1 (L"Select inner viewport... 0 4.5 0 2")
diff --git a/fon/manual_Picture.cpp b/fon/manual_Picture.cpp
index 4055b59..1938c3d 100644
--- a/fon/manual_Picture.cpp
+++ b/fon/manual_Picture.cpp
@@ -1,6 +1,6 @@
/* manual_Picture.cpp
*
- * Copyright (C) 1992-2011,2012 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@
*/
#include "ManPagesM.h"
+#include "UnicodeData.h"
static void drawOneIpaSymbol (Graphics g, double x, double y, const wchar_t *symbol) {
wchar_t buffer [30], *p = & buffer [0];
@@ -336,14 +337,14 @@ LIST_ITEM (L"e\\3v e\\bs3v (%%combining right half ring below%): slightly rounde
LIST_ITEM (L"u\\cv u\\bscv (%%combining left half ring below%): slightly unrounded")
NORMAL (L"Overstrikes:")
LIST_ITEM (L"\\gf\\0^ \\bsgf\\bs0\\^ (%%combining ring above%): voiceless")
-LIST_ITEM (L"\\ep\\\'^ \\bsep\\bs\'\\^ (%%combining acute accent%): high tone")
-LIST_ITEM (L"\\ep\\`^ \\bsep\\bs`\\^ (%%combining grave accent%): low tone")
-LIST_ITEM (L"\\ep\\-^ \\bsep\\bs-\\^ (%%combining macron%): mid tone (or so)")
-LIST_ITEM (L"\\ep\\~^ \\bsep\\bs~\\^ (%%combining tilde%): nasalized")
-LIST_ITEM (L"\\ep\\v^ \\bsep\\bsv\\^ (%%combining caron%, %hac\\v^ek, %wedge): rising tone")
-LIST_ITEM (L"\\ep\\^^ \\bsep\\bs\\^ \\^ (%%combining circumflex accent%): falling tone")
+LIST_ITEM (L"\\ef\\\'^ \\bsef\\bs\'\\^ (%%combining acute accent%): high tone")
+LIST_ITEM (L"\\ef\\`^ \\bsef\\bs`\\^ (%%combining grave accent%): low tone")
+LIST_ITEM (L"\\ef\\-^ \\bsef\\bs-\\^ (%%combining macron%): mid tone (or so)")
+LIST_ITEM (L"\\ef\\~^ \\bsef\\bs~\\^ (%%combining tilde%): nasalized")
+LIST_ITEM (L"\\ef\\v^ \\bsef\\bsv\\^ (%%combining caron%, %%háček%, %wedge): rising tone") // UNITEXT_LATIN_SMALL_LETTER_C_WITH_CARON
+LIST_ITEM (L"\\ef\\^^ \\bsef\\bs\\^ \\^ (%%combining circumflex accent%): falling tone")
LIST_ITEM (L"o\\:^ o\\bs:\\^ (%%combining diaeresis%): centralized")
-LIST_ITEM (L"\\ep\\N^ \\ep\\bsN\\^ (%%combining breve%): short")
+LIST_ITEM (L"\\ef\\N^ \\bsef\\bsN\\^ (%%combining breve%): short")
LIST_ITEM (L"k\\lip t\\lis k\\bslip (%%combining double inverted breve%, %ligature): simultaneous articulation, or single segment")
NORMAL (L"In line:")
LIST_ITEM (L"\\:f \\bs:f the phonetic length sign")
diff --git a/fon/manual_Script.cpp b/fon/manual_Script.cpp
index f87f8dd..37b9f93 100644
--- a/fon/manual_Script.cpp
+++ b/fon/manual_Script.cpp
@@ -844,7 +844,7 @@ TAG (L"##besselI (%n, %x)")
TAG (L"##besselK (%n, %x)")
MAN_END
-MAN_BEGIN (L"Formulas 5. String functions", L"ppgb", 20130421)
+MAN_BEGIN (L"Formulas 5. String functions", L"ppgb", 20130522)
INTRO (L"String functions are functions that either return a text string or have at least one text string as an argument. "
"Since string computations are not very useful in the @calculator, in settings windows, or in creation and "
"modification formulas, this page only gives examples of strings in scripts, so that the example may contain "
@@ -902,7 +902,8 @@ TAG (L"##replace_regex\\$ (a\\$ , b\\$ , c\\$ , n)")
DEFINITION (L"gives a string that is like %%a\\$ %, but where (at most %n) substrings that match the @@regular expressions|regular expression@ %%b\\$ % "
"are replaced with the expression %%c\\$ %. After")
CODE2 (L"s\\$ = replace_regex\\$ (\"hello\", \".\", \"&&\", 0)")
-DEFINITION (L"the variable %%s\\$ % contains the string \"hheelllloo\". If there is no match, the outcome is the empty string \"\". After")
+DEFINITION (L"the variable %%s\\$ % contains the string \"hheelllloo\". If there is no match, "
+ "the outcome is the original string a\\$ . After")
CODE2 (L"s\\$ = replace_regex\\$ (\"hello\", \".\", \"&&\", 1)")
DEFINITION (L"the variable %%s\\$ % contains the string \"hhello\". The number %n determines the maximum number of text pieces "
"that can be replaced. If %n is 0, all matching text pieces are replaced.")
@@ -935,7 +936,7 @@ TAG (L"##extractNumber (\"Type: Sound\" + newline\\$ + \"Name: hello there\" +
DEFINITION (L"looks for a number after the first occurrence of \"Size:\" in the long string. Outcome: 44007. "
"This is useful in scripts that try to get information from long reports, as the following script that "
"runs in the Sound editor window:")
- CODE2 (L"report\\$ = do (\"Editor info\")")
+ CODE2 (L"report\\$ = do\\$ (\"Editor info\")")
CODE2 (L"maximumFrequency = extractNumber (report\\$ , \"Spectrogram window length:\")")
TAG (L"##extractWord\\$ (\"Type: Sound\" + newline\\$ + \"Name: hello there\" + newline\\$ + \"Size: 44007\", \"Type:\")")
DEFINITION (L"looks for a word without spaces after the first occurrence of \"Type:\" in the long string. Outcome: Sound.")
@@ -1372,7 +1373,7 @@ NORMAL (L"In scripts, the command ##%%Run script...#% is automatically replaced
"by the script directive #execute.")
MAN_END
-MAN_BEGIN (L"Scripting", L"ppgb", 20130421)
+MAN_BEGIN (L"Scripting", L"ppgb", 20130428)
INTRO (L"This is one of the tutorials of the Praat program. It assumes you are familiar with the @Intro.")
NORMAL (L"A %script is a text that consists of menu commands and action commands. "
"If you %run the script (perhaps from a @ScriptEditor), "
@@ -1388,7 +1389,10 @@ LIST_ITEM1 (L"@@Scripting 3.4. String variables@ (assignments)")
LIST_ITEM1 (L"@@Scripting 3.5. String queries")
LIST_ITEM1 (L"@@Scripting 3.6. \"For\" loops@ (for, endfor)")
LIST_ITEM1 (L"@@Scripting 3.7. Layout@ (white space, comments, continuation lines)")
-LIST_ITEM (L"@@Scripting 4. Object selection@ (selecting and querying)")
+LIST_ITEM (L"@@Scripting 4. Object selection@")
+LIST_ITEM1 (L"@@Scripting 4.1. Selecting objects")
+LIST_ITEM1 (L"@@Scripting 4.2. Removing objects")
+LIST_ITEM1 (L"@@Scripting 4.3. Querying objects")
LIST_ITEM (L"@@Scripting 5. Language elements reference@")
LIST_ITEM1 (L"@@Scripting 5.1. Variables@ (numeric, string)")
LIST_ITEM1 (L"@@Scripting 5.2. Expressions@ (numeric, string)")
@@ -1402,7 +1406,7 @@ LIST_ITEM (L"@@Scripting 6. Communication outside the script")
LIST_ITEM1 (L"@@Scripting 6.1. Arguments to the script@ (form/endform, execute)")
LIST_ITEM1 (L"@@Scripting 6.2. Writing to the Info window@ (writeInfoLine, appendInfoLine, appendInfo, tab\\$ )")
LIST_ITEM1 (L"@@Scripting 6.3. Query commands@ (Get, Count)")
-LIST_ITEM1 (L"@@Scripting 6.4. Files@ (fileReadable, <, >, >>, filedelete, fileappend)")
+LIST_ITEM1 (L"@@Scripting 6.4. Files@ (fileReadable, readFile, writeFile, deleteFile, createDirectory)")
LIST_ITEM1 (L"@@Scripting 6.5. Calling system commands@ (system, environment\\$ , stopwatch)")
LIST_ITEM1 (L"@@Scripting 6.6. Controlling the user@ (pause, beginPause/endPause, chooseReadFile\\$ )")
LIST_ITEM1 (L"@@Scripting 6.7. Sending a message to another program@ (sendsocket)")
@@ -1575,7 +1579,7 @@ SCRIPT (5.4, Manual_SETTINGS_WINDOW_HEIGHT (6.6), L""
Manual_DRAW_SETTINGS_WINDOW_TEXT ("Formula", "1/2 * sin(2*pi*377*x)")
)
NORMAL (L"In a script this would look like:")
-CODE (L"do (\"Create Sound from formula...\", \"sine\", 1, 0.0, 1.0, 44100, \"1/2 * sin(2*pi*377*x)\"")
+CODE (L"do (\"Create Sound from formula...\", \"sine\", 1, 0.0, 1.0, 44100, \"1/2 * sin(2*pi*377*x))\"")
NORMAL (L"Both the first argument (#Name) and the sixth argument (#Formula) are %%text arguments%. "
"In a script they are written within quotes.")
ENTRY (L"5. File arguments")
@@ -2088,41 +2092,104 @@ CODE (L"...gogerychwyrndrobwllllantysiliogogogoch,")
CODE (L"... unless you start from Tyddyn-y-felin.\")")
MAN_END
-MAN_BEGIN (L"Scripting 4. Object selection", L"ppgb", 20130407)
+MAN_BEGIN (L"Scripting 4. Object selection", L"ppgb", 20130501)
INTRO (L"This chapter is about how to select objects from your script, "
"and how to find out what objects are currently selected.")
-ENTRY (L"Selecting objects")
+LIST_ITEM (L"@@Scripting 4.1. Selecting objects")
+LIST_ITEM (L"@@Scripting 4.2. Removing objects")
+LIST_ITEM (L"@@Scripting 4.3. Querying objects")
+MAN_END
+
+MAN_BEGIN (L"Scripting 4.1. Selecting objects", L"ppgb", 20130501)
NORMAL (L"To simulate the mouse-clicked and dragged selection in the list of objects, "
- "you have the following commands:")
-TAG (L"#select %object")
-DEFINITION (L"selects one object, and deselects all others. If there are more "
- "objects with the same name, the most recently created one "
- "(i.e., the one nearest to the bottom of the list of objects) is selected:")
-CODE1 (L"#select Sound hallo")
-CODE1 (L"Play")
-TAG (L"#plus %object")
-DEFINITION (L"adds one object to the current selection.")
-TAG (L"#minus %object")
-DEFINITION (L"removes one object from the current selection.")
-TAG (L"##select all")
-DEFINITION (L"selects all objects (please try not to use this, because it will remove even the objects that your script did not create!):")
-CODE1 (L"##select all")
-CODE1 (L"Remove")
-NORMAL (L"In the Praat shell, newly created objects are automatically selected. "
- "This is also true in scripts:")
-CODE (L"! Generate a sine wave, play it, and draw its spectrum.")
-CODE (L"do (\"Create Sound as pure tone...\", \"sine377\", 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01)")
+ "you have the commands #selectObject, #plusObject and #minusObject.")
+NORMAL (L"Suppose you start Praat and use ##Create Sound as tone...# to create a Sound called %tone. "
+ "In the object list it looks like \"1. Sound tone\". "
+ "Suppose you then do ##To Spectrum...# from the ##Analyse Spectrum# menu. "
+ "A second object, called \"2. Spectrum tone\" appears in the list and is selected. "
+ "To select and play the Sound, you can do either")
+CODE (L"#selectObject (1)")
CODE (L"do (\"Play\")")
+NORMAL (L"or")
+CODE (L"#selectObject (\"Sound tone\")")
+CODE (L"do (\"Play\")")
+NORMAL (L"So you can select an object either by its unique ID (identifier: the unique number by which it appears in the list) "
+ "or by name.")
+NORMAL (L"The function #selectObject works by first deselecting all objects, and then selecting the one you mention. "
+ "If you don't want to deselect the existing selection, you can use #plusObject or #minusObject. "
+ "When the Sound is selected, you can select the Spectrum as well by doing")
+CODE (L"#plusObject (2)")
+NORMAL (L"or")
+CODE (L"#plusObject (\"Spectrum tone\")")
+NORMAL (L"If you then want to deselect the Sound, and keep the Spectrum selected, you can do")
+CODE (L"#minusObject (1)")
+NORMAL (L"or")
+CODE (L"#minusObject (\"Sound tone\")")
+NORMAL (L"All these functions can take more than one argument. To select the Sound and the Spectrum together, you can do")
+CODE (L"#selectObject (1, 2)")
+NORMAL (L"or")
+CODE (L"#selectObject (\"Sound tone\", \"Spectrum tone\")")
+NORMAL (L"or even")
+CODE (L"#selectObject (1, \"Spectrum tone\")")
+ENTRY (L"How to refer to objects created in your script")
+NORMAL (L"In a script, you typically don't know whether the IDs of the objects are 1 and 2, or much higher numbers. "
+ "Fortunately, the #do function gives you the ID of the object that is created, "
+ "so that you can refer to the object later on. For instance, suppose you want to generate a sine wave, play it, "
+ "draw its spectrum, and then throw away both the Sound and the Spectrum. Here is how you do it:")
+CODE (L"sound = do (\"Create Sound as pure tone...\", \"sine377\",")
+CODE (L"... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01) ; remember the ID of the Sound")
+CODE (L"do (\"Play\") ; the Sound is selected, so it plays")
CODE (L"do (\"To Spectrum...\", \"yes\")")
-CODE (L"! Draw the Spectrum:")
-CODE (L"do (\"Draw...\", 0, 5000, 20, 80, \"yes\")")
-CODE (L"! Remove the created Spectrum and Sound:")
-CODE (L"#plus Sound sine377")
-CODE (L"Remove")
-NORMAL (L"Instead of by name, you can also select objects by their sequential ID:")
-CODE (L"#select 43")
-NORMAL (L"This selects the 43rd object that you created since you started the program (see below).")
-ENTRY (L"Querying selected objects")
+CODE (L"do (\"Draw...\", 0, 5000, 20, 80, \"yes\") ; the Spectrum is selected, so it is drawn")
+CODE (L"\\# Remove the created Spectrum and Sound:")
+CODE (L"#plusObject (sound) ; the Spectrum was already selected")
+CODE (L"do (\"Remove\")")
+NORMAL (L"You could also select the objects by name:")
+CODE (L"do (\"Create Sound as pure tone...\", \"sine377\",")
+CODE (L"... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01) ; no need to remember the ID of the Sound")
+CODE (L"do (\"Play\") ; the Sound is selected, so it plays")
+CODE (L"do (\"To Spectrum...\", \"yes\")")
+CODE (L"do (\"Draw...\", 0, 5000, 20, 80, \"yes\") ; the Spectrum is selected, so it is drawn")
+CODE (L"\\# Remove the created Spectrum and Sound:")
+CODE (L"#plusObject (\"Sound sine377\") ; the Spectrum was already selected")
+CODE (L"do (\"Remove\")")
+NORMAL (L"This works even if there are multiple objects called \"Sound sine377\", "
+ "because if there are more objects with the same name, #selectedObject and #plusObject select the most recently created one, "
+ "i.e., the one nearest to the bottom of the list of objects.")
+MAN_END
+
+MAN_BEGIN (L"Scripting 4.2. Removing objects", L"ppgb", 20130501)
+NORMAL (L"In @@Scripting 4.1. Selecting objects|\\SS4.1@ we saw that objects could be removed by selecting them first and then calling the #Remove command. "
+ "A faster way is the #removeObject function, which can also remove unselected objects:")
+CODE (L"sound = do (\"Create Sound as pure tone...\", \"sine377\",")
+CODE (L"... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01) ; remember the ID of the Sound")
+CODE (L"do (\"Play\") ; the Sound is selected, so it plays")
+CODE (L"spectrum = do (\"To Spectrum...\", \"yes\") ; remember the ID of the Spectrum")
+CODE (L"do (\"Draw...\", 0, 5000, 20, 80, \"yes\") ; the Spectrum is selected, so it is drawn")
+CODE (L"\\# Remove the created Spectrum and Sound:")
+CODE (L"#removeObject (sound, spectrum) ; remove one selected and one unselected object")
+NORMAL (L"The #removeObject function keeps the objects selected that were selected before "
+ "(except of course the ones it throws away). "
+ "This allows you to easily throw away objects as soon as you no longer need them:")
+CODE (L"sound = do (\"Create Sound as pure tone...\", \"sine377\",")
+CODE (L"... 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01) ; remember the ID of the Sound")
+CODE (L"do (\"Play\") ; the Sound is selected, so it plays")
+CODE (L"spectrum = do (\"To Spectrum...\", \"yes\")")
+CODE (L"#removeObject (sound) ; we no longer need the Sound, so we remove it")
+CODE (L"do (\"Draw...\", 0, 5000, 20, 80, \"yes\") ; the Spectrum is still selected, so it is drawn")
+CODE (L"#removeObject (spectrum) ; remove the last object created by the script")
+ENTRY (L"Selecting and removing all objects from the list (don't)")
+NORMAL (L"A very strange command, which you should not normally use, is ##select all#:")
+CODE1 (L"##select all")
+CODE1 (L"do (\"Remove\")")
+NORMAL (L"This selects all objects in the list and then removes them. "
+ "Please try not to use this, because it will remove even the objects that your script did not create! "
+ "After all, you don't want the users of your script to lose the objects they created! "
+ "So please try to remove in your script only the objects that your script created, "
+ "even if the script is for your own use (because if it is a nice script, others will want to use it).")
+MAN_END
+
+MAN_BEGIN (L"Scripting 4.3. Querying objects", L"ppgb", 20130501)
NORMAL (L"You can get the name of a selected object into a string variable. "
"For instance, the following reads the name of the second selected Sound "
"(as counted from the top of the list of objects) into the variable %name\\$ :")
@@ -2151,13 +2218,13 @@ CODE (L"soundName\\$ = ##selected\\$ # (\"Sound\", -1)")
CODE (L"pitchName\\$ = ##selected\\$ # (\"Pitch\")")
CODE (L"\\# But the following line is questionable, since it doesn't")
CODE (L"\\# necessarily select the previously selected Pitch again:")
-CODE (L"#select Pitch 'pitchName\\$ '")
+CODE (L"#selectObject (\"Pitch \" + pitchName\\$ )")
NORMAL (L"Instead of this error-prone approach, you should get the object's unique ID. "
"The correct version of our example becomes:")
CODE (L"sound = #selected (\"Sound\", -1)")
CODE (L"pitch = #selected (\"Pitch\")")
CODE (L"\\# Correct:")
-CODE (L"#select pitch")
+CODE (L"#selectObject (pitch)")
NORMAL (L"To get the number of selected Sound objects into a variable, use")
CODE (L"numberOfSelectedSounds = #numberOfSelected (\"Sound\")")
NORMAL (L"To get the number of selected objects into a variable, use")
@@ -2165,34 +2232,21 @@ CODE (L"numberOfSelectedObjects = #numberOfSelected ()")
ENTRY (L"Example: doing something to every selected Sound")
CODE (L"n = #numberOfSelected (\"Sound\")")
CODE (L"#for i to n")
- CODE1 (L"sound'i' = #selected (\"Sound\", i)")
+ CODE1 (L"sound [i] = #selected (\"Sound\", i)")
CODE (L"#endfor")
CODE (L"\\# Median pitches of all selected sounds:")
CODE (L"#for i to n")
- CODE1 (L"#select sound'i'")
+ CODE1 (L"#selectObject (sound [i])")
CODE1 (L"do (\"To Pitch...\", 0.0, 75, 600)")
CODE1 (L"f0 = do (\"Get quantile...\", 0, 0, 0.50, \"Hertz\")")
+ CODE1 (L"appendInfoLine (f0)")
CODE1 (L"do (\"Remove\")")
CODE (L"#endfor")
CODE (L"\\# Restore selection:")
-CODE (L"#if n >= 1")
- CODE1 (L"#select sound1")
- CODE1 (L"#for i from 2 to n")
- CODE2 (L"#plus sound'i'")
- CODE1 (L"#endfor")
-CODE (L"#endif")
-ENTRY (L"A shortcut")
-NORMAL (L"Instead of")
-CODE (L"do (\"Create Sound as pure tone...\", \"sine377\", 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01)")
-CODE (L"sound = #selected (\"Sound\")")
-NORMAL (L"you can just write")
-CODE (L"sound = do (\"Create Sound as pure tone...\", \"sine377\", 1, 0, 1, 44100, 377, 0.2, 0.01, 0.01)")
-NORMAL (L"and instead of")
-CODE (L"do (\"To Pitch...\", 0.0, 75, 600)")
-CODE (L"pitch = #selected (\"Pitch\")")
-NORMAL (L"you can write")
-CODE (L"pitch = do (\"To Pitch...\", 0.0, 75, 600)")
-NORMAL (L"This only works if the command creates a single object.")
+CODE (L"#selectObject () ; deselect all objects")
+CODE (L"#for i from 1 to n")
+ CODE1 (L"#plusObject (sound [i])")
+CODE (L"#endfor")
MAN_END
MAN_BEGIN (L"Scripting 5. Language elements reference", L"ppgb", 20130421)
@@ -2209,22 +2263,26 @@ LIST_ITEM (L"@@Scripting 5.7. Including other scripts@")
LIST_ITEM (L"@@Scripting 5.8. Quitting@ (exit)")
MAN_END
-MAN_BEGIN (L"Scripting 5.1. Variables", L"ppgb", 20130415)
-INTRO (L"In a Praat script, you can use numeric variables as well as string variables.")
+MAN_BEGIN (L"Scripting 5.1. Variables", L"ppgb", 20130501)
+INTRO (L"A %variable is a location in your computer's memory that has a name and where you can store something, "
+ "as explained in @@Scripting 3.2. Numeric variables|\\SS3.2@ and @@Scripting 3.4. String variables|\\SS3.4 at . "
+ "In a Praat script, you can store numbers and texts, i.e. you can use %%numeric variables% and %%string variables%.")
ENTRY (L"Numeric variables")
-NORMAL (L"Numeric variables contain integer numbers between -1,000,000,000,000,000 and +1,000,000,000,000,000 "
+NORMAL (L"Numeric variables can hold integer numbers between -1,000,000,000,000,000 and +1,000,000,000,000,000 "
"or real numbers between -10^^308^ and +10^^308^. The smallest numbers lie near -10^^-308^ and +10^^-308^.")
-NORMAL (L"You can use %%numeric variables% in your script:")
-TAG (L"%variable = %expression")
-DEFINITION (L"evaluates a numeric expression and assign the result to a variable.")
-NORMAL (L"Example:")
-CODE (L"length = 10")
-CODE (L"do (\"Draw line...\", 0, length, 1, 1)")
+NORMAL (L"You use numeric variables in your script like this:")
+CODE (L"#length = 10")
+CODE (L"do (\"Draw line...\", 0, #length, 1, 1)")
+NORMAL (L"This draws a line in the Picture window from position (0, 10) to position (1, 1). "
+ "In the first line, you assign the value 10 to the variable called %length, "
+ "and in the second line you use the value of %length as the second argument to the command \"Draw line...\".")
NORMAL (L"Names of numeric variables must start with a lower-case letter, optionally followed by a sequence "
"of letters, digits, and underscores.")
ENTRY (L"String variables")
-NORMAL (L"You can also use %%string variables%, which contain text:")
-CODE (L"title\\$ = \"Dutch nasal place assimilation\"")
+NORMAL (L"You use string variables, which contain text, as follows:")
+CODE (L"##title\\$ # = \"Dutch nasal place assimilation\"")
+CODE (L"do (\"Text top...\", \"yes\", ##title\\$ #)")
+NORMAL (L"This writes the text \"Dutch nasal place assimilation\"")
NORMAL (L"As in the programming language Basic, the names of string variables end in a dollar sign.")
ENTRY (L"Making numeric variables visible")
NORMAL (L"You can write the content of numeric variables directly to the info window:")
@@ -2236,23 +2294,23 @@ CODE (L"The square root of 2 is 1.4142135623730951.")
NORMAL (L"You can fix the number of digits after the decimal point by use of the ##fixed\\$ # function:")
CODE (L"x = 2.0")
CODE (L"root = sqrt (x)")
-CODE (L"#writeInfoLine (\"The square root of \", fixed\\$ (x, 3), \" is approximately \", fixed\\$ (root, 3), \".\")")
+CODE (L"writeInfoLine (\"The square root of \", ##fixed\\$ # (x, 3), \" is approximately \", ##fixed\\$ # (root, 3), \".\")")
NORMAL (L"This will write the following text to the Info window:")
CODE (L"The square root of 2.000 is approximately 1.414.")
NORMAL (L"By using 0 decimal digits, you round to whole values:")
CODE (L"root = sqrt (2)")
-CODE (L"#writeInfoLine (\"The square root of 2 is very approximately \", fixed\\$ (root, 0), \".\")")
+CODE (L"writeInfoLine (\"The square root of 2 is very approximately \", ##fixed\\$ # (root, #0), \".\")")
NORMAL (L"This will write the following text to the Info window:")
CODE (L"The square root of 2 is very approximately 1.")
NORMAL (L"By using the ##percent\\$ # function, you give the result in a percent format:")
CODE (L"jitter = 0.0156789")
-CODE (L"#writeInfoLine (\"The jitter is \", percent\\$ (jitter, 3), \".\")")
+CODE (L"writeInfoLine (\"The jitter is \", ##percent\\$ # (jitter, 3), \".\")")
NORMAL (L"This will write the following text to the Info window:")
CODE (L"The jitter is 1.568\\% .")
NORMAL (L"The number 0, however, will always be written as 0, and for small numbers the number of "
"significant digits will never be less than 1:")
CODE (L"jitter = 0.000000156789")
-CODE (L"#writeInfoLine (\"The jitter is \", percent\\$ (jitter, 3), \".\")")
+CODE (L"writeInfoLine (\"The jitter is \", percent\\$ (jitter, 3), \".\")")
NORMAL (L"This will write the following text to the Info window:")
CODE (L"The jitter is 0.00002\\% .")
ENTRY (L"Predefined variables")
@@ -2269,7 +2327,7 @@ NORMAL (L"Some ##predefined string variables# are $$newline\\$ $, $$tab\\$ $, a
"Likewise, there exist the predefined string variables $$homeDirectory\\$ $, "
"$$preferencesDirectory\\$ $, and $$temporaryDirectory\\$ $. These three refer to your home directory "
"(which is where you log in), the Praat @@preferences directory@, and a directory for saving temporary files; "
- "if you want to know what they are on your computer, try to #echo them in a script window. "
+ "if you want to know what they are on your computer, try to write them into a script window. "
"The variable $$defaultDirectory\\$ $ is available for formulas in scripts; it is the directory that contains the script file. "
"Finally, we have $$praatVersion\\$ $, which is \"" xstr(PRAAT_VERSION_STR) "\" for the current version of Praat.")
ENTRY (L"Functions that handle variables")
@@ -2678,11 +2736,11 @@ DEFINITION (L"stops the execution of the script while sending an error message t
NORMAL (L"For an example, see @@Scripting 6.8. Messages to the user at .")
MAN_END
-MAN_BEGIN (L"Scripting 6. Communication outside the script", L"ppgb", 20130421)
+MAN_BEGIN (L"Scripting 6. Communication outside the script", L"ppgb", 20130428)
LIST_ITEM (L"@@Scripting 6.1. Arguments to the script@ (form/endform, execute)")
LIST_ITEM (L"@@Scripting 6.2. Writing to the Info window@ (writeInfoLine, appendInfoLine, appendInfo, tab\\$ )")
LIST_ITEM (L"@@Scripting 6.3. Query commands@ (Get, Count)")
-LIST_ITEM (L"@@Scripting 6.4. Files@ (fileReadable, <, >, >>, filedelete, fileappend)")
+LIST_ITEM (L"@@Scripting 6.4. Files@ (fileReadable, readFile, writeFile, deleteFile, createDirectory)")
LIST_ITEM (L"@@Scripting 6.5. Calling system commands@ (system, environment\\$ , stopwatch)")
LIST_ITEM (L"@@Scripting 6.6. Controlling the user@ (pause, beginPause/endPause, chooseReadFile\\$ )")
LIST_ITEM (L"@@Scripting 6.7. Sending a message to another program@ (sendsocket)")
@@ -2807,27 +2865,17 @@ CODE (L"#execute \"fill attributes.praat\" \"Navy blue\" With holes")
NORMAL (L"You can pass values for #boolean either as \"yes\" and \"no\" or 1 and 0.")
MAN_END
-MAN_BEGIN (L"Scripting 6.2. Writing to the Info window", L"ppgb", 20130407)
+MAN_BEGIN (L"Scripting 6.2. Writing to the Info window", L"ppgb", 20130501)
NORMAL (L"With the @Info button and several commands in the #Query menus, "
"you write to the @@Info window@ (if your program is run from the command line, "
"the text goes to the console window or to %stdout instead; see @@Scripting 6.9. Calling from the command line|\\SS6.9).")
-NORMAL (L"The following commands allow you to write to the Info window from a script:")
-TAG (L"#writeInfoLine (%text)")
-DEFINITION (L"clears the Info window and writes some text to it:")
- CODE1 (L"#writeInfoLine (\"Starting simulation...\")")
-TAG (L"#clearinfo")
-DEFINITION (L"clears the Info window.")
-TAG (L"#appendInfo (%text)")
-DEFINITION (L"appends some text to the Info window, without clearing it and "
- "without going to a new line.")
-TAG (L"#appendInfo (tab\\$ )")
-DEFINITION (L"appends a %tab character to the Info window. This allows you to create "
- "table files that can be read by some spreadsheet programs.")
-TAG (L"#appendInfoLine (%text)")
-DEFINITION (L"appends some text to the Info window, without clearing it. The next text will begin at a new line.")
-NORMAL (L"The following script builds a table with statistics about a pitch contour:")
-CODE (L"#clearinfo")
-CODE (L"#appendInfoLine (\" Minimum Maximum\")")
+NORMAL (L"The commands #writeInfo, #writeInfoLine, #appendInfo and #appendInfoLine "
+ "allow you to write to the Info window from a script. Those with #write in their name clear the Info window "
+ "before they write to it, those with #append in their name do not. Those with #Line in their name make sure "
+ "that a following #appendInfo or #appendInfoLine will write on the next line.")
+NORMAL (L"These four functions take a variable number of numeric and/or string arguments, separated by commas. "
+ "The following script builds a table with statistics about a pitch contour:")
+CODE (L"#writeInfoLine (\" Minimum Maximum\")")
CODE (L"do (\"Create Sound as pure tone...\", \"sine\", 1, 0, 0.1, 44100, 377, 0.2, 0.01, 0.01)")
CODE (L"do (\"To Pitch...\", 0.01, 75, 600)")
CODE (L"minimum = do (\"Get minimum...\", 0, 0, \"Hertz\", \"Parabolic\")")
@@ -2840,6 +2888,13 @@ NORMAL (L"You could combine the last four print statements into:")
CODE (L"#appendInfoLine (minimum, tab\\$ , maximum)")
NORMAL (L"which is the same as:")
CODE (L"#appendInfo (minimum, tab\\$ , maximum, newline\\$ )")
+NORMAL (L"The little string ##tab\\$ # is a %tab character; it allows you to create "
+ "table files that can be read by some spreadsheet programs. The little string ##newline\\$ # is a %newline character; "
+ "it moves the following text to the next line.")
+NORMAL (L"To clear the Info window, you can do")
+CODE (L"#writeInfo ()")
+NORMAL (L"or")
+CODE (L"#clearinfo")
MAN_END
MAN_BEGIN (L"Scripting 6.3. Query commands", L"ppgb", 20130407)
@@ -2855,7 +2910,7 @@ NORMAL (L"The string variable \"mean\\$ \" now contains the entire string \"150
NORMAL (L"This works for every command that would otherwise write into the Info window.")
MAN_END
-MAN_BEGIN (L"Scripting 6.4. Files", L"ppgb", 20100314)
+MAN_BEGIN (L"Scripting 6.4. Files", L"ppgb", 20130501)
INTRO (L"You can read from and write to text files from a Praat script.")
ENTRY (L"Reading a file")
NORMAL (L"You can check the availability of a file for reading with the function")
@@ -2865,36 +2920,36 @@ NORMAL (L"which returns 1 (true) if the file exists and can be read, and 0 (fals
"for instance, if your script is in the directory ##Paolo/project1#, then the file name "
"\"hello.wav\" refers to ##Paolo/project1/hello.wav#, the file name \"yesterday/hello.wav\" "
"refers to ##Paolo/project1/yesterday/hello.wav#, and the file name \"../project2/hello.wav\" "
- "refers to ##Paola/project2/hello.wav# (\"..\" goes one directory up). "
+ "refers to ##Paolo/project2/hello.wav# (\"..\" goes one directory up). "
"You can also use full path names such as \"C:/Documents and Settings/Paolo/project1/hello.wav\" "
"on Windows and \"/Users/Paolo/project1/hello.wav\" on the Mac.")
-NORMAL (L"To read the contents of an existing text file into a string variable, you use")
-CODE (L"text\\$ ##<# %fileName")
-NORMAL (L"where $$text\\$ $ is any string variable and $$%fileName$ is an unquoted string. "
- "If the file does not exist, the script terminates with an error message.")
+NORMAL (L"To read the contents of an existing text file into a string variable or into a numeric variable, you use")
+CODE (L"text\\$ = readFile\\$ (\"myFile.txt\")")
+NORMAL (L"or")
+CODE (L"number = readFile (\"myFile.txt\")")
+NORMAL (L"If the file does not exist, the script terminates with an error message.")
ENTRY (L"Example: reading a settings file")
NORMAL (L"Suppose that the file ##height.inf# may contain an appropriate value for a numeric variable "
"called $height, which we need to use in our script. We would like to read it with")
-CODE (L"height\\$ < height.inf")
-CODE (L"height = 'height\\$ '")
+CODE (L"height = readFile (\"height.inf\")")
NORMAL (L"However, this script will fail if the file ##height.inf# does not exist. To guard "
"against this situation, we could check the existence of the file, and supply a default "
"value in case the file does not exist:")
CODE (L"fileName\\$ = \"height.inf\"")
CODE (L"if fileReadable (fileName\\$ )")
- CODE1 (L"height\\$ < 'fileName\\$ '")
- CODE1 (L"height = number (height\\$ )")
+ CODE1 (L"height = readFile (fileName\\$ )")
CODE (L"else")
CODE1 (L"height = 180")
CODE (L"endif")
ENTRY (L"Writing a file")
-NORMAL (L"To write the contents of an existing string into a new text file, you use")
-CODE (L"text\\$ ##># %fileName")
-NORMAL (L"where $$text\\$ $ is any string variable and $$%fileName$ is an unquoted string. "
+NORMAL (L"You write into a new text file just as you write into the Info window:")
+CODE (L"writeFileLine (\"myFile.txt\", \"The present year is \", 2000 + 13, \".\")")
+NORMAL (L"and likewise you use %writeFile if you don't want a newline symbol at the end of the file. "
"If the file cannot be created, the script terminates with an error message.")
-NORMAL (L"To append the contents of an existing string at the end of an existing text file, you use")
-CODE (L"text\\$ ##>># %fileName")
-NORMAL (L"If the file does not yet exist, it is created first.")
+NORMAL (L"To append text at the end of an existing file, you use")
+CODE (L"appendFileLine (\"myFile.txt\", \"Next year it will be \", 2000 + 14, \".\")")
+NORMAL (L"With %appendFileLine (and %appendFile, which does not add the newline), "
+ "we follow the rule that if the file does not yet exist, it is created first.")
NORMAL (L"You can create a directory with")
CODE (L"#createDirectory (%%directoryName\\$ %)")
NORMAL (L"where, as with file names, %%directoryName\\$ % can be relative to the directory of the script "
@@ -2904,11 +2959,7 @@ NORMAL (L"where, as with file names, %%directoryName\\$ % can be relative to the
"If the directory already exists, this command does nothing.")
NORMAL (L"You can delete an existing file with the function")
CODE (L"#deleteFile (%%fileName\\$ %)")
-NORMAL (L"or with the directive")
-CODE (L"#filedelete %fileName")
-NORMAL (L"If the file does not exist, these commands do nothing.")
-NORMAL (L"The simplest way to append text to a file is by using #fileappend:")
-CODE (L"#fileappend out.txt Hello world!")
+NORMAL (L"If the file does not exist, this command does nothing.")
ENTRY (L"Example: writing a table of squares")
NORMAL (L"Suppose that we want to create a file with the following text:")
CODE (L"The square of 1 is 1")
@@ -2916,31 +2967,21 @@ CODE (L"The square of 2 is 4")
CODE (L"The square of 3 is 9")
CODE (L"...")
CODE (L"The square of 100 is 10000")
-NORMAL (L"We can do this by collecting each line in a variable:")
+NORMAL (L"We can do this by appending 100 lines:")
CODE (L"deleteFile (\"squares.txt\")")
CODE (L"for i to 100")
- CODE1 (L"square = i * i")
- CODE1 (L"fileappend squares.txt The square of 'i' is 'square''newline\\$ '")
+ CODE1 (L"appendFileLine (\"squares.txt\", \"The square of \", i, \" is \", i * i)")
CODE (L"endfor")
NORMAL (L"Note that we delete the file before appending to it, "
"in order that we do not append to an already existing file.")
-NORMAL (L"If you put the name of the file into a variable, make sure to surround it "
- "with double quotes when using #fileappend, since the file name may contain spaces "
- "and is not at the end of the line:")
-CODE (L"name\\$ = \"C:/Documents and Settings/Paul Boersma/Desktop/squares.text\"")
-CODE (L"filedelete 'name\\$ '")
-CODE (L"for i to 100")
- CODE1 (L"square = i * i")
- CODE1 (L"fileappend \"'name\\$ '\" The square of 'i' is 'square''newline\\$ '")
-CODE (L"endfor")
-NORMAL (L"Finally, you can append the contents of the Info window to a file with")
-CODE (L"#fappendinfo %fileName")
+NORMAL (L"You can append the contents of the Info window to a file with")
+CODE (L"appendFile (\"out.txt\", info\\$ ())")
ENTRY (L"Directory listings")
NORMAL (L"To get the names of the files if a certain type in a certain directory, "
"use @@Create Strings as file list... at .")
MAN_END
-MAN_BEGIN (L"Scripting 6.5. Calling system commands", L"ppgb", 20130407)
+MAN_BEGIN (L"Scripting 6.5. Calling system commands", L"ppgb", 20130821)
INTRO (L"From a Praat script you can call system commands. "
"These are the same commands that you would normally type into a terminal window or into the Window command line prompt.")
TAG (L"#system %command")
@@ -2973,7 +3014,7 @@ CODE (L"for i to 1000000")
CODE1 (L"a = 1.23456789e123")
CODE (L"endfor")
CODE (L"time = stopwatch")
-CODE (L"writeInfoLine (a, \" \", fixed$ (time, 3))")
+CODE (L"writeInfoLine (a, \" \", fixed\\$ (time, 3))")
MAN_END
MAN_BEGIN (L"Scripting 6.6. Controlling the user", L"ppgb", 20130407)
@@ -3377,6 +3418,13 @@ NORMAL (L"This causes the program #Praat to execute the script ##doAll.praat# wi
ENTRY (L"How to download")
NORMAL (L"You can download the source code of the sendpraat subroutine and program "
"via ##www.praat.org# or from ##http://www.fon.hum.uva.nl/praat/sendpraat.html#.")
+ENTRY (L"Instead")
+NORMAL (L"Instead of using sendpraat, you can also just take the following simple steps in your program:")
+LIST_ITEM (L"1. on Linux, write the script that you want to execute, and save it as ##~/.praat-dir/message#;")
+LIST_ITEM (L"2. get Praat's process id from ##~/.praat-dir/pid#;")
+LIST_ITEM (L"3. if Praat's process id is eg. 1178, send it a SIGUSR1 signal: $$kill -USR1 1178")
+NORMAL (L"If the first line of your script is the comment \"\\# 999\", where 999 stands for the process id of your program, "
+ "Praat will send your program a SIGUSR2 signal back when it finishes handling the script.")
ENTRY (L"See also")
NORMAL (L"To start a program from the command line instead and sending it a message, "
"you would not use #sendpraat, but instead run the program with a script file as an argument. "
diff --git a/fon/manual_programming.cpp b/fon/manual_programming.cpp
index a1badd5..fe7bd6c 100644
--- a/fon/manual_programming.cpp
+++ b/fon/manual_programming.cpp
@@ -22,7 +22,7 @@
void manual_programming_init (ManPages me);
void manual_programming_init (ManPages me) {
-MAN_BEGIN (L"Programming with Praat", L"ppgb", 20110831)
+MAN_BEGIN (L"Programming with Praat", L"ppgb", 20130429)
INTRO (L"You can extend the functionality of the Praat program "
"by adding modules written in C or C++ to it. All of Praat's source code "
"is available under the General Public Licence.")
@@ -34,17 +34,15 @@ NORMAL (L"Before trying the task of learning how to write Praat extensions in C
"If you have a set of scripts, you can distribute them as a @@plug-ins|plug-in at .")
ENTRY (L"2. Getting the existing source code")
NORMAL (L"You obtain the Praat source code via ##www.praat.org#, in a file with a name like "
- "##praat5218_sources.tar.gz# (depending on the Praat version), and unpack this by double-clicking "
- "(on old computers, use #gunzip and ##tar xvf# if Unix, or ##StuffIt^\\re Expander^\\tm# if Macintosh, "
- "or ##Aladdin^\\re Expander^\\tm# if Windows). The result will be a set of directories "
- "called #kar, #GSL, #num, #audio (with #FLAC and #mp3 in it), #sys, #dwsys, #stat, #fon, #dwtools, #LPC, #FFNet, #gram, #artsynth, #contrib, #main, #makefiles, and #test, "
- "plus a makefile, a Codewarrior project for Windows, and an Xcode project for Macintosh.")
+ "##praat5347_sources.zip# or ##praat5347_sources.tar.gz# (depending on the Praat version), and unpack this by double-clicking. "
+ "The result will be a set of directories "
+ "called #kar, #num, #external (with #GSL, #glpk, #FLAC, #mp3, #portaudio and #espeak in it), "
+ "#sys, #dwsys, #stat, #fon, #dwtools, #LPC, #FFNet, #gram, #artsynth, #EEG, #contrib, #main, #makefiles, and #test, "
+ "plus a makefile and an Xcode project for Macintosh.")
ENTRY (L"3. Building Praat on Macintosh")
-NORMAL (L"Open ##praat.xcodeproj# in Xcode and choose #Build and #Run.")
+NORMAL (L"Open ##praat.xcodeproj# in Xcode and choose #Build and #Run. For more details see the download page.")
ENTRY (L"4. Building Praat on Windows")
-NORMAL (L"Open ##praat.mcp# in CodeWarrior (version 9.0 or higher), choose the target "
- "##praat_win#, and choose #Make or #Run.")
-NORMAL (L"Praat may compile under MinGW as well.")
+NORMAL (L"Praat for Windows is compiled with MinGW. See the download page for instructions.")
ENTRY (L"5. Building Praat on Linux")
NORMAL (L"To compile and link Praat on Linux, you go to the directory that "
"contains the source directories and the makefile, and copy a ##makefile.defs# "
@@ -56,7 +54,7 @@ NORMAL (L"On other Unixes, you do the same, but the file ##makefile.defs# may re
ENTRY (L"6. Extending Praat")
NORMAL (L"You can edit ##main/main_Praat.cpp#. "
"This example shows you how to create a very simple program with all the functionality "
- "of the Praat program, and a single bit more:")
+ "of the Praat program, and a single bit more (namely an additional command in the New menu):")
CODE (L"\\# include \"praat.h\"")
CODE (L"")
CODE (L"DIRECT (HelloFromJane)")
@@ -73,12 +71,12 @@ CODE (L"}")
ENTRY (L"7. Learning how to program")
NORMAL (L"To see how objects are defined, take a look at ##sys/Thing.h#, ##sys/Data.h#, "
"##sys/oo.h#, the ##XXX_def.h# files in the #fon directory, and the corresponding "
- "##XXX.c# and ##XXX.cpp# files in the #fon directory. To see how commands show up on the buttons "
+ "##XXX.cpp# files in the #fon directory. To see how commands show up on the buttons "
"in the fixed and dynamic menus, take a look at the large interface description file "
"##fon/praat_Fon.cpp#.")
ENTRY (L"8. Using the Praat shell only")
-NORMAL (L"For building the Praat shell (the Objects and Picture windows) only, you need only the code in the six directories "
- "#kar, #GSL, #num, #audio, #sys, and #dwsys. You delete the inclusion of praat_uvafon_init from #main. "
+NORMAL (L"For building the Praat shell (the Objects and Picture windows) only, you need only the code in the eight directories "
+ "#kar, #GSL, #num, ##external/{FLAC,MP3,portaudio}#, #sys, and #dwsys. You delete the inclusion of praat_uvafon_init from #main. "
"You will be able to build a Praat shell, i.e. an Objects and a Picture window, "
"which has no knowledge of the world, i.e., which does not know any objects "
"that can be included in the list of objects. You could use this Praat shell "
diff --git a/fon/manual_tutorials.cpp b/fon/manual_tutorials.cpp
index 91514d7..e05b288 100644
--- a/fon/manual_tutorials.cpp
+++ b/fon/manual_tutorials.cpp
@@ -23,9 +23,32 @@
void manual_tutorials_init (ManPages me);
void manual_tutorials_init (ManPages me) {
-MAN_BEGIN (L"What's new?", L"ppgb", 20130421)
+MAN_BEGIN (L"What's new?", L"ppgb", 20130915)
INTRO (L"Latest changes in Praat.")
/*LIST_ITEM (L"\\bu Manual page about @@drawing a vowel triangle at .")*/
+NORMAL (L"##5.3.56# (15 September 2013)")
+LIST_ITEM (L"\\bu Mac: 64-bit alpha version.")
+LIST_ITEM (L"\\bu Linux: improved selecting in the Picture window.")
+NORMAL (L"##5.3.55# (2 September 2013)")
+LIST_ITEM (L"\\bu Corrected a bug introduced in 5.3.54 by which you couldn't select a file for saving.")
+NORMAL (L"##5.3.54# (1 September 2013)")
+LIST_ITEM (L"\\bu Sound window: removed a bug introduced in 5.3.42 by which you couldn't ask for an odd number of poles in Formant Settings "
+ "(by e.g. specifying \"5.5\" for the number of formants).")
+LIST_ITEM (L"Linux: improved dragging of selections in the Picture window and the Sound window.")
+NORMAL (L"##5.3.53# (9 July 2013)")
+LIST_ITEM (L"\\bu Table: more drawing commands.")
+NORMAL (L"##5.3.52# (12 June 2013)")
+LIST_ITEM (L"\\bu Scripting: editor windows understand #do and ##do\\$ #.")
+NORMAL (L"##5.3.51# (30 May 2013)")
+LIST_ITEM (L"\\bu Sound window: ##Extract selected sound for overlap...#.")
+NORMAL (L"##5.3.49# (13 May 2013)")
+LIST_ITEM (L"\\bu TextGrid window: alignment of the sound and the annotation in an interval, via Espeak.")
+LIST_ITEM (L"\\bu Scripting: repaired a bug introduced in 5.3.32 that could cause very slow running of scripts.")
+NORMAL (L"##5.3.48# (1 May 2013)")
+LIST_ITEM (L"\\bu Scripting: variable-substitution-free object selection and file writing.")
+LIST_ITEM (L"\\bu Scripting: #selectObject and #removeObject can select or remove multiple objects at a time.")
+NORMAL (L"##5.3.47# (23 April 2013)")
+LIST_ITEM (L"\\bu OTGrammar: included Giorgio Magri's (2012) update rule (weighted all up, high down).")
NORMAL (L"##5.3.46# (21 April 2013)")
LIST_ITEM (L"\\bu Scripting: variable-substitution-free procedure calls.")
LIST_ITEM (L"\\bu Linux: made the Save menu compatible with Ubuntu 12.04.")
@@ -144,6 +167,29 @@ NORMAL (L"##5.3.01# (1 November 2011)")
LIST_ITEM (L"\\bu Macintosh and Windows: better window positioning if the Dock or Task Bar is on the left or right.")
LIST_ITEM (L"\\bu IPA symbol: you can now use \\bs.f for the half-length sign (\\.f).")
LIST_ITEM (L"\\bu EEG window.")
+ENTRY (L"What used to be new?")
+LIST_ITEM (L"\\bu @@What was new in 5.3?")
+LIST_ITEM (L"\\bu @@What was new in 5.2?")
+LIST_ITEM (L"\\bu @@What was new in 5.1?")
+LIST_ITEM (L"\\bu @@What was new in 5.0?")
+LIST_ITEM (L"\\bu @@What was new in 4.6?")
+LIST_ITEM (L"\\bu @@What was new in 4.5?")
+LIST_ITEM (L"\\bu @@What was new in 4.4?")
+LIST_ITEM (L"\\bu @@What was new in 4.3?")
+LIST_ITEM (L"\\bu @@What was new in 4.2?")
+LIST_ITEM (L"\\bu @@What was new in 4.1?")
+LIST_ITEM (L"\\bu @@What was new in 4.0?")
+LIST_ITEM (L"\\bu @@What was new in 3.9?")
+LIST_ITEM (L"\\bu @@What was new in 3.8?")
+LIST_ITEM (L"\\bu @@What was new in 3.7?")
+LIST_ITEM (L"\\bu @@What was new in 3.6?")
+LIST_ITEM (L"\\bu @@What was new in 3.5?")
+LIST_ITEM (L"\\bu @@What was new in 3.3?")
+LIST_ITEM (L"\\bu @@What was new in 3.2?")
+LIST_ITEM (L"\\bu @@What was new in 3.1?")
+MAN_END
+
+MAN_BEGIN (L"What was new in 5.3?", L"ppgb", 20111015)
NORMAL (L"##5.3# (15 October 2011)")
NORMAL (L"##5.2.46# (7 October 2011)")
LIST_ITEM (L"\\bu Corrected the same very old bug as in 5.2.44, but now also for opening and saving files.")
@@ -284,6 +330,9 @@ LIST_ITEM (L"\\bu Linux: made spectrogram drawing compatible with Ubuntu 10.10."
LIST_ITEM (L"\\bu Linux: made sound more easily available on Ubuntu 10.10.")
NORMAL (L"##5.2.01# (4 November 2010)")
LIST_ITEM (L"\\bu Scripting: support for numeric @@Scripting 5.6. Arrays|arrays at .")
+MAN_END
+
+MAN_BEGIN (L"What was new in 5.2?", L"ppgb", 20101029)
NORMAL (L"##5.2# (29 October 2010)")
NORMAL (L"##5.1.45# (26 October 2010)")
LIST_ITEM (L"\\bu Linux/GTK: allow Praat to run without an X display.")
@@ -463,6 +512,9 @@ LIST_ITEM (L"\\bu TextGrid: ##List...# and ##Down to Table...#.")
LIST_ITEM (L"\\bu OT learning: Giorgio Magri's \"Weighted all up, highest down\" update rule.")
NORMAL (L"##5.1.01# (26 February 2009)")
LIST_ITEM (L"\\bu Corrected several bugs in Klatt synthesis.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 5.1?", L"ppgb", 20090131)
NORMAL (L"##5.1# (31 January 2009)")
LIST_ITEM (L"\\bu Editors for Klatt synthesis.")
LIST_ITEM (L"\\bu Corrected many bugs.")
@@ -594,6 +646,9 @@ LIST_ITEM (L"\\bu TextGrid window: corrected the drawing of numbers to the right
LIST_ITEM (L"\\bu Corrected a bug that caused Praat to crash when doing ##SpectrumTier: List#.")
NORMAL (L"##5.0.01# (18 December 2007)")
LIST_ITEM (L"\\bu Corrected a bug that could cause Praat to crash when redrawing the sound or TextGrid window.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 5.0?", L"ppgb", 20071210)
NORMAL (L"##5.0# (10 December 2007)")
LIST_ITEM (L"\\bu Corrected many bugs.")
LIST_ITEM (L"\\bu Display font sizes in points rather than pixels.")
@@ -719,6 +774,9 @@ LIST_ITEM (L"\\bu Sound files: saving FLAC audio files (implemented by Erez Volk
NORMAL (L"##4.6.01# (16 May 2007)")
LIST_ITEM (L"\\bu Removed a bug that caused downsampling (and therefore formant measurements) "
"to be incorrect for stereo sounds.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.6?", L"ppgb", 20070512)
NORMAL (L"##4.6# (12 May 2007)")
NORMAL (L"##4.5.26# (8 May 2007)")
LIST_ITEM (L"\\bu Sound files: reading FLAC audio files (implemented by Erez Volk).")
@@ -806,6 +864,9 @@ LIST_ITEM (L"\\bu Corrected yet another bug in the new @@Sound: To TextGrid (sil
NORMAL (L"##4.5.01# (28 October 2006)")
LIST_ITEM (L"\\bu Sound window: the pitch drawing method is #Curves, #Speckles, or #Automatic.")
LIST_ITEM (L"\\bu Corrected another bug in the new @@Sound: To TextGrid (silences)... at .")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.5?", L"ppgb", 20061026)
NORMAL (L"##4.5# (26 October 2006)")
NORMAL (L"##4.4.35# (20 October 2006)")
LIST_ITEM (L"\\bu In @ManPages you can now draw pictures.")
@@ -904,6 +965,9 @@ NORMAL (L"##4.4.01# (2 January 2006)")
LIST_ITEM (L"\\bu Picture window: \"Logarithmic marks\" allows reversed axes.")
LIST_ITEM (L"\\bu Manipulation window: removed a bug from \"Shift frequencies\" that caused much too small shifts in semitones.")
LIST_ITEM (L"\\bu TextGrid: \"Remove point...\".")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.4?", L"ppgb", 20051219)
NORMAL (L"##4.4# (19 December 2005)")
NORMAL (L"##4.3.37# (15 December 2005)")
LIST_ITEM (L"\\bu @@Principal component analysis@: now accepts tables with more variables (columns) than cases (rows).")
@@ -999,6 +1063,9 @@ LIST_ITEM (L"\\bu Replaced PostScript font SILDoulosIPA with XIPA (adapted for P
LIST_ITEM (L"\\bu Sound: Set part to zero...")
LIST_ITEM (L"\\bu Pitch: To Sound (sine)...")
LIST_ITEM (L"\\bu Sound & TextGrid: Clone time domain.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.3?", L"ppgb", 20050126)
ENTRY (L"Praat 4.3, 26 January 2005")
NORMAL (L"General:")
LIST_ITEM (L"\\bu `Apply' button in settings windows for menu commands and in script forms.")
@@ -1036,6 +1103,9 @@ ENTRY (L"Praat 4.3, 26 January 2005")
NORMAL (L"Scripting:")
LIST_ITEM (L"\\bu nowarn, noprogress, nocheck.")
LIST_ITEM (L"\\bu Line numbers.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.2?", L"ppgb", 20040304)
ENTRY (L"Praat 4.2, 4 March 2004")
NORMAL (L"General:")
LIST_ITEM (L"\\bu July 10, 2003: Open source code (General Public Licence).")
@@ -1074,6 +1144,9 @@ ENTRY (L"Praat 4.2, 4 March 2004")
LIST_ITEM (L"\\bu ManPages: variable duration of recording.")
LIST_ITEM (L"\\bu Support for unlimited size of script files in editor window on Windows XP and MacOS X (the Unix editions already had this).")
LIST_ITEM (L"\\bu Improved the reception of %sendpraat commands on Windows XP.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.1?", L"ppgb", 20030605)
ENTRY (L"Praat 4.1, 5 June 2003")
NORMAL (L"General:")
LIST_ITEM (L"\\bu MacOS X edition.")
@@ -1128,6 +1201,9 @@ ENTRY (L"Praat 4.1, 5 June 2003")
"#let, #getnumber, #getstring, #ARGS, #copy, #proc, variables with capitals, and strings in numeric variables; "
"there are messages about how to modify your old scripts.")
LIST_ITEM (L"\\bu Disallowed ambiguous expressions like -3\\^ 2.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 4.0?", L"ppgb", 20011015)
ENTRY (L"Praat 4.0, 15 October 2001")
NORMAL (L"Editors:")
LIST_ITEM (L"\\bu Simplified selection and cursor in editor windows.")
@@ -1168,6 +1244,9 @@ ENTRY (L"Praat 4.0, 15 October 2001")
NORMAL (L"Documentation:")
LIST_ITEM (L"\\bu @@Multidimensional scaling@ tutorial.")
LIST_ITEM (L"\\bu Enabled debugging-at-a-distance.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.9?", L"ppgb", 20001018)
ENTRY (L"Praat 3.9, 18 October 2000")
NORMAL (L"Editors:")
LIST_ITEM (L"\\bu Shift-click and shift-drag extend or shrink selection in editor windows.")
@@ -1238,6 +1317,9 @@ ENTRY (L"Praat 3.9, 18 October 2000")
LIST_ITEM (L"\\bu Script links in @ManPages.")
NORMAL (L"Documentation")
LIST_ITEM (L"\\bu Tutorials on all subjects available through @Intro.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.8?", L"ppgb", 19990112)
ENTRY (L"Praat 3.8, 12 January 1999")
NORMAL (L"Phonetics library")
LIST_ITEM (L"\\bu New objects: @LongSound (view and label long sound files), with editor; PairDistribution.")
@@ -1281,6 +1363,9 @@ ENTRY (L"Praat 3.8, 12 January 1999")
LIST_ITEM (L"\\bu June 22: unlimited number of script variables.")
LIST_ITEM (L"\\bu April 5: suspended chopping of trailing spaces.")
LIST_ITEM (L"\\bu March 29: enabled formulas as arguments to dialogs (also interactive).")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.7?", L"ppgb", 19980324)
ENTRY (L"Praat 3.7, 24 March 1998")
NORMAL (L"Editors:")
LIST_ITEM (L"\\bu In all FunctionEditors: drag to get a selection.")
@@ -1310,6 +1395,9 @@ ENTRY (L"Praat 3.7, 24 March 1998")
NORMAL (L"Documentation:")
LIST_ITEM (L"\\bu 230 more man pages (now 630).")
LIST_ITEM (L"\\bu Hypertext: increased readability of formulas, navigation with keyboard.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.6?", L"ppgb", 19971027)
ENTRY (L"Praat 3.6, 27 October 1997")
NORMAL (L"Editors:")
LIST_ITEM (L"\\bu Intuitive position of B and E buttons on left-handed mice.")
@@ -1348,6 +1436,9 @@ ENTRY (L"Praat 3.6, 27 October 1997")
LIST_ITEM (L"\\bu Use the @sendpraat program for sending messages to running Praat programs.")
NORMAL (L"Mac:")
LIST_ITEM (L"\\bu Praat looks best with the new and beautiful System 8.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.5?", L"ppgb", 19970527)
ENTRY (L"Praat 3.5, 27 May 1997")
NORMAL (L"New editors:")
LIST_ITEM (L"\\bu #TextGridEditor replaces and extends LabelEditor: edit points as well as intervals.")
@@ -1394,6 +1485,9 @@ ENTRY (L"Praat 3.5, 27 May 1997")
LIST_ITEM (L"\\bu Fast and interpolating spectrogram drawing.")
LIST_ITEM (L"\\bu Phonetic Mac screen font included in source code (as a fallback to using SIL Doulos IPA).")
LIST_ITEM (L"\\bu Keyboard shortcuts, text editor, help under question mark, etc.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.3?", L"ppgb", 19961006)
ENTRY (L"Praat 3.3, 6 October 1996")
LIST_ITEM (L"\\bu Documentation: hypertext help browser, including the first 190 man pages.")
LIST_ITEM (L"\\bu New editors: type #TextTier for labelling times instead of intervals.")
@@ -1414,6 +1508,9 @@ ENTRY (L"Praat 3.3, 6 October 1996")
LIST_ITEM (L"\\bu Object type changes: #StylPitch and #MarkTier are now called #PitchTier and #TextTier, respectively. "
"Old files can still be read.")
LIST_ITEM (L"\\bu Script warning: all times in dialogs are in seconds now: milliseconds have gone.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.2?", L"ppgb", 19960429)
ENTRY (L"Praat 3.2, 29 April 1996")
LIST_ITEM (L"\\bu Sound I/O for HPUX, Sun Sparc 5, and Sun Sparc LX.")
LIST_ITEM (L"\\bu Cross-correlation pitch and HNR analysis.")
@@ -1425,45 +1522,48 @@ ENTRY (L"Praat 3.2, 29 April 1996")
LIST_ITEM (L"\\bu Read and write Bell-Labs sound files and Kay CSL audio files.")
LIST_ITEM (L"\\bu Replaced IpaTimes font by free SILDoulos-IPA font, and embedded phonetic font in PostScript picture.")
LIST_ITEM (L"\\bu Completed main phonetic characters.")
+MAN_END
+
+MAN_BEGIN (L"What was new in 3.1?", L"ppgb", 19951205)
ENTRY (L"Praat 3.1, 5 December 1995")
LIST_ITEM (L"\\bu Add and remove buttons dynamically.")
LIST_ITEM (L"\\bu DataEditor (Inspect button).")
LIST_ITEM (L"\\bu Initialization scripts.")
LIST_ITEM (L"\\bu Logarithmic axes.")
LIST_ITEM (L"\\bu Call remote ADDA server directly.")
+MAN_END
+/*
+ BUGBASE
+
+>* The Artword editor would be easier to read if the vertical axis of the
+>graphs were squeezed a little. As it is, the line for a target of 1
+>throughout the utterance merges into the top bounding box and is
+>invisible.
+>
+
+>* In drawing a picture of an Artword for a Speaker, the Pen|Line-width
+>option only works for dotted and dashed lines. It's ignored for plain
+>lines (and is WAY too wide).
+
ENTRY (L"To do")
LIST_ITEM (L"\\bu TextGrid & Sound: Extract intervals with margins.")
LIST_ITEM (L"\\bu Spectrum: draw power, re, im, phase.")
LIST_ITEM (L"\\bu Formant: To Spectrum (slice)... (combines Formant-to-LPC and LPC-to-Spectrum-slice)")
- LIST_ITEM (L"\\bu Read and/or write Matlab files, MBROLA files, Xwaves files, CHAT files.") /* Aix */
+ LIST_ITEM (L"\\bu Read and/or write Matlab files, MBROLA files, Xwaves files, CHAT files.") // Aix
LIST_ITEM (L"\\bu Matrix: draw numbers.")
LIST_ITEM (L"\\bu Fractions with \\bsf{a|b}.")
LIST_ITEM (L"\\bu Move objects up and down list.")
LIST_ITEM (L"\\bu Spectrogram cross-correlation.")
- LIST_ITEM (L"\\bu Labels in AIFC file.") /* Theo Veenker 19980323 */
+ LIST_ITEM (L"\\bu Labels in AIFC file.") // Theo Veenker 19980323
LIST_ITEM (L"\\bu Improve scrolling and add selection in hyperpages.")
- LIST_ITEM (L"\\bu Segment spectrograph?") /* Ton Wempe, Jul 16 1996 */
- LIST_ITEM (L"\\bu Phoneme-to-articulation conversion??") /* Mirjam Ernestus, Jul 1 1996 */
+ LIST_ITEM (L"\\bu Segment spectrograph?") // Ton Wempe, Jul 16 1996
+ LIST_ITEM (L"\\bu Phoneme-to-articulation conversion??") // Mirjam Ernestus, Jul 1 1996
ENTRY (L"Known bugs in the Windows version")
LIST_ITEM (L"\\bu Cannot stand infinitesimal zooming in SpectrogramEditor.")
LIST_ITEM (L"\\bu Clipboards with greys sometimes become black-and-white after use of colour.")
ENTRY (L"Known bugs in the Linux version")
LIST_ITEM (L"\\bu Sounds shorter than 200 ms do not always play (workaround: add zeroes in prefs).")
LIST_ITEM (L"\\bu Keyboard shortcuts do not work if NumLock is on.")
- LIST_ITEM (L"\\bu Keyboard shortcut \"tab\" does not work.")
-MAN_END
-/*
- BUGBASE
-
->* The Artword editor would be easier to read if the vertical axis of the
->graphs were squeezed a little. As it is, the line for a target of 1
->throughout the utterance merges into the top bounding box and is
->invisible.
->
-
->* In drawing a picture of an Artword for a Speaker, the Pen|Line-width
->option only works for dotted and dashed lines. It's ignored for plain
->lines (and is WAY too wide).
*/
MAN_BEGIN (L"Acknowledgments", L"ppgb", 20130406)
diff --git a/fon/praat_Fon.cpp b/fon/praat_Fon.cpp
index ffe708b..710cc44 100644
--- a/fon/praat_Fon.cpp
+++ b/fon/praat_Fon.cpp
@@ -1,6 +1,6 @@
/* praat_Fon.cpp
*
- * Copyright (C) 1992-2012 Paul Boersma
+ * Copyright (C) 1992-2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -5406,7 +5406,7 @@ END
FORM (Strings_createAsFileList, L"Create Strings as file list", L"Create Strings as file list...")
SENTENCE (L"Name", L"fileList")
- LABEL (L"", L"Path:")
+ LABEL (L"", L"File path:")
TEXTFIELD (L"path", L"/people/Miep/*.wav")
OK
static int inited;
diff --git a/fon/praat_Sound_init.cpp b/fon/praat_Sound_init.cpp
index 92ffa14..fb779ea 100644
--- a/fon/praat_Sound_init.cpp
+++ b/fon/praat_Sound_init.cpp
@@ -774,6 +774,21 @@ DO
}
END
+FORM (Sound_extractPartForOverlap, L"Sound: Extract part for overlap", 0)
+ REAL (L"left Time range (s)", L"0")
+ REAL (L"right Time range (s)", L"0.1")
+ POSITIVE (L"Overlap (s)", L"0.01")
+ OK
+DO
+ LOOP {
+ iam (Sound);
+ autoSound thee = Sound_extractPartForOverlap (me,
+ GET_REAL (L"left Time range"), GET_REAL (L"right Time range"),
+ GET_REAL (L"Overlap"));
+ praat_new (thee.transfer(), my name, L"_part");
+ }
+END
+
DIRECT (Sound_extractRightChannel)
LOOP {
iam (Sound);
@@ -2541,6 +2556,7 @@ void praat_uvafon_Sound_init (void) {
praat_addAction1 (classSound, 0, L"Extract right channel", 0, praat_HIDDEN + praat_DEPTH_1, DO_Sound_extractRightChannel); // deprecated 2010
praat_addAction1 (classSound, 0, L"Extract one channel...", 0, 1, DO_Sound_extractChannel);
praat_addAction1 (classSound, 0, L"Extract part...", 0, 1, DO_Sound_extractPart);
+ praat_addAction1 (classSound, 0, L"Extract part for overlap...", 0, 1, DO_Sound_extractPartForOverlap);
praat_addAction1 (classSound, 0, L"Resample...", 0, 1, DO_Sound_resample);
praat_addAction1 (classSound, 0, L"-- enhance --", 0, 1, 0);
praat_addAction1 (classSound, 0, L"Lengthen (overlap-add)...", 0, 1, DO_Sound_lengthen_overlapAdd);
diff --git a/gram/Makefile b/gram/Makefile
index 85e74d6..89ec503 100644
--- a/gram/Makefile
+++ b/gram/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "gram"
-# Paul Boersma, 14 January 2012
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -20,7 +20,7 @@ clean:
libgram.a: $(OBJECTS)
touch libgram.a
rm libgram.a
- ar cq libgram.a $(OBJECTS)
+ $(AR) cq libgram.a $(OBJECTS)
$(RANLIB) libgram.a
$(OBJECTS): *.h ../num/NUM.h ../kar/*.h ../sys/*.h ../dwsys/*.h ../stat/*.h ../dwtools/*.h ../fon/*.h
diff --git a/gram/OTGrammar.cpp b/gram/OTGrammar.cpp
index 53c95e0..c4e9430 100644
--- a/gram/OTGrammar.cpp
+++ b/gram/OTGrammar.cpp
@@ -1339,12 +1339,12 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
int winnerMarks = winner -> marks [icons];
int loserMarks = loser -> marks [icons];
if (loserMarks > 0) {
- if (multiplyStepByNumberOfViolations) constraintStep *= loserMarks - winnerMarks;
+ if (multiplyStepByNumberOfViolations) constraintStep *= loserMarks /*- winnerMarks*/;
constraint -> ranking -= constraintStep * (1.0 + constraint -> ranking * my leak) / losingConstraints;
if (grammarHasChanged != NULL) *grammarHasChanged = true;
}
if (winnerMarks > 0) {
- if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
+ if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks /*- loserMarks*/;
constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) / winningConstraints;
if (grammarHasChanged != NULL) *grammarHasChanged = true;
}
@@ -1439,7 +1439,6 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
offendingConstraint -> ranking -= constraintStep;
if (grammarHasChanged != NULL) *grammarHasChanged = true;
} else if (updateRule == kOTGrammar_rerankingStrategy_WEIGHTED_ALL_UP_HIGHEST_DOWN) {
- bool changed = false;
long numberOfUp = 0;
for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
int winnerMarks = winner -> marks [icons];
@@ -1457,6 +1456,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
if (winnerMarks > loserMarks) {
if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) / numberOfUp;
+ if (grammarHasChanged != NULL) *grammarHasChanged = true;
}
}
long crucialLoserMark, winnerMarks = 0, loserMarks = 0;
@@ -1481,10 +1481,9 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
double constraintStep = step * offendingConstraint -> plasticity;
if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
offendingConstraint -> ranking -= /*numberOfUp **/ constraintStep * (1.0 - offendingConstraint -> ranking * my leak);
+ if (grammarHasChanged != NULL) *grammarHasChanged = true;
}
- if (grammarHasChanged != NULL) *grammarHasChanged = changed;
- } else { Melder_assert (updateRule == kOTGrammar_rerankingStrategy_WEIGHTED_ALL_UP_HIGHEST_DOWN_2012);
- bool changed = false;
+ } else if (updateRule == kOTGrammar_rerankingStrategy_WEIGHTED_ALL_UP_HIGHEST_DOWN_2012) {
long numberOfUp = 0;
for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
int winnerMarks = winner -> marks [icons];
@@ -1493,7 +1492,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
numberOfUp ++;
}
}
- if (true || numberOfUp > 0) {
+ if (numberOfUp > 0) {
for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
OTGrammarConstraint constraint = & my constraints [icons];
double constraintStep = step * constraint -> plasticity;
@@ -1502,6 +1501,7 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
if (winnerMarks > loserMarks) {
if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) / (numberOfUp + 1);
+ if (grammarHasChanged != NULL) *grammarHasChanged = true;
}
}
long crucialLoserMark, winnerMarks = 0, loserMarks = 0;
@@ -1526,8 +1526,88 @@ static void OTGrammar_modifyRankings (OTGrammar me, long itab, long iwinner, lon
double constraintStep = step * offendingConstraint -> plasticity;
if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
offendingConstraint -> ranking -= /*numberOfUp **/ constraintStep * (1.0 - offendingConstraint -> ranking * my leak);
+ if (grammarHasChanged != NULL) *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 ++) {
+ int winnerMarks = winner -> marks [my index [icons]]; // the order is important, therefore indirect
+ int loserMarks = loser -> marks [my index [icons]];
+ if (loserMarks < winnerMarks) {
+ numberOfUp ++;
+ } else if (loserMarks > winnerMarks) {
+ if (numberOfUp == 0) {
+ numberOfDown ++;
+ lowestDemotableConstraint = icons;
+ }
+ }
+ }
+ if (warnIfStalled && numberOfDown == 0) {
+ Melder_warning ("Correct output is harmonically bounded (by having strict superset violations as compared to the learner's output)! EDCD stalls.\n"
+ "Input: ", tableau -> input, "\nCorrect output: ", loser -> output, "\nLearner's output: ", winner -> output);
+ return;
+ }
+ if (numberOfUp > 0) {
+ for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+ long 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
+ int loserMarks = loser -> marks [constraintIndex];
+ if (my constraints [constraintIndex]. tiedToTheRight)
+ Melder_throw ("Demotion-only learning cannot handle tied constraints.");
+ if (loserMarks < winnerMarks) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
+ constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) * numberOfDown / (numberOfUp + 0.0);
+ } else if (loserMarks > winnerMarks) {
+ if (icons <= lowestDemotableConstraint) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= loserMarks - winnerMarks;
+ constraint -> ranking -= constraintStep * (1.0 - constraint -> ranking * my leak);
+ }
+ }
+ }
+ if (grammarHasChanged != NULL) *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 ++) {
+ int winnerMarks = winner -> marks [my index [icons]]; // the order is important, therefore indirect
+ int loserMarks = loser -> marks [my index [icons]];
+ if (loserMarks < winnerMarks) {
+ numberOfUp ++;
+ } else if (loserMarks > winnerMarks) {
+ if (numberOfUp == 0) {
+ numberOfDown ++;
+ lowestDemotableConstraint = icons;
+ }
+ }
+ }
+ if (warnIfStalled && numberOfDown == 0) {
+ Melder_warning ("Correct output is harmonically bounded (by having strict superset violations as compared to the learner's output)! EDCD stalls.\n"
+ "Input: ", tableau -> input, "\nCorrect output: ", loser -> output, "\nLearner's output: ", winner -> output);
+ return;
+ }
+ if (numberOfUp > 0) {
+ for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+ long 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
+ int loserMarks = loser -> marks [constraintIndex];
+ if (my constraints [constraintIndex]. tiedToTheRight)
+ Melder_throw ("Demotion-only learning cannot handle tied constraints.");
+ if (loserMarks < winnerMarks) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
+ constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) * numberOfDown / (numberOfUp + 1.0);
+ } else if (loserMarks > winnerMarks) {
+ if (icons <= lowestDemotableConstraint) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= loserMarks - winnerMarks;
+ constraint -> ranking -= constraintStep * (1.0 - constraint -> ranking * my leak);
+ }
+ }
+ }
+ if (grammarHasChanged != NULL) *grammarHasChanged = true;
}
- if (grammarHasChanged != NULL) *grammarHasChanged = changed;
}
if (honourLocalRankings && my numberOfFixedRankings) {
OTGrammar_honourLocalRankings (me, plasticity, relativePlasticityNoise, grammarHasChanged);
diff --git a/gram/OTGrammar_enums.h b/gram/OTGrammar_enums.h
index d9b48eb..b5398f0 100644
--- a/gram/OTGrammar_enums.h
+++ b/gram/OTGrammar_enums.h
@@ -37,6 +37,8 @@ enums_begin (kOTGrammar_rerankingStrategy, 0)
enums_add (kOTGrammar_rerankingStrategy, 6, EDCD_WITH_VACATION, L"EDCD with vacation")
enums_add (kOTGrammar_rerankingStrategy, 7, WEIGHTED_ALL_UP_HIGHEST_DOWN, L"Weighted all up, highest down")
enums_add (kOTGrammar_rerankingStrategy, 8, WEIGHTED_ALL_UP_HIGHEST_DOWN_2012, L"Weighted all up, highest down (2012)")
-enums_end (kOTGrammar_rerankingStrategy, 8, SYMMETRIC_ALL)
+ enums_add (kOTGrammar_rerankingStrategy, 9, WEIGHTED_ALL_UP_HIGH_DOWN, L"Weighted all up, high down")
+ enums_add (kOTGrammar_rerankingStrategy, 10, WEIGHTED_ALL_UP_HIGH_DOWN_2012, L"Weighted all up, high down (2012)")
+enums_end (kOTGrammar_rerankingStrategy, 10, SYMMETRIC_ALL)
/* End of file OTGrammar_enums.h */
diff --git a/gram/OTGrammar_ex_tongueRoot.cpp b/gram/OTGrammar_ex_tongueRoot.cpp
index 4911ce9..2e6bc23 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 Paul Boersma
+ * Copyright (C) 1997-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#include "OTGrammar.h"
-static const wchar_t *vowels [] = { L"i", L"e", L"\\sw", L"\\ic", L"\\ep", L"a" };
+static const wchar_t *vowels [] = { L"i", L"e", L"\\sw", L"\\ic", L"\\ef", L"a" };
#define i 0
#define e 1
#define schwa 2
diff --git a/gram/OTMulti.cpp b/gram/OTMulti.cpp
index 4c0baba..cbcd606 100644
--- a/gram/OTMulti.cpp
+++ b/gram/OTMulti.cpp
@@ -659,7 +659,7 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
}
}
if (grammarHasChanged != NULL) *grammarHasChanged = changed;
- } else { Melder_assert (updateRule == kOTGrammar_rerankingStrategy_WEIGHTED_ALL_UP_HIGHEST_DOWN_2012);
+ } 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 ++) {
@@ -715,6 +715,76 @@ static void OTMulti_modifyRankings (OTMulti me, long iwinner, long iloser,
}
}
if (grammarHasChanged != NULL) *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 ++) {
+ int winnerMarks = winner -> marks [my index [icons]]; // the order is important, therefore indirect
+ int loserMarks = loser -> marks [my index [icons]];
+ if (loserMarks < winnerMarks) {
+ numberOfUp ++;
+ } else if (loserMarks > winnerMarks) {
+ if (numberOfUp == 0) {
+ numberOfDown ++;
+ lowestDemotableConstraint = icons;
+ }
+ }
+ }
+ if (numberOfUp > 0) {
+ for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+ long 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
+ int loserMarks = loser -> marks [constraintIndex];
+ if (my constraints [constraintIndex]. tiedToTheRight)
+ Melder_throw ("Demotion-only learning cannot handle tied constraints.");
+ if (loserMarks < winnerMarks) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
+ constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) * numberOfDown / (numberOfUp + 0.0);
+ } else if (loserMarks > winnerMarks) {
+ if (icons <= lowestDemotableConstraint) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= loserMarks - winnerMarks;
+ constraint -> ranking -= constraintStep * (1.0 - constraint -> ranking * my leak);
+ }
+ }
+ }
+ if (grammarHasChanged != NULL) *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 ++) {
+ int winnerMarks = winner -> marks [my index [icons]]; // the order is important, therefore indirect
+ int loserMarks = loser -> marks [my index [icons]];
+ if (loserMarks < winnerMarks) {
+ numberOfUp ++;
+ } else if (loserMarks > winnerMarks) {
+ if (numberOfUp == 0) {
+ numberOfDown ++;
+ lowestDemotableConstraint = icons;
+ }
+ }
+ }
+ if (numberOfUp > 0) {
+ for (long icons = 1; icons <= my numberOfConstraints; icons ++) {
+ long 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
+ int loserMarks = loser -> marks [constraintIndex];
+ if (my constraints [constraintIndex]. tiedToTheRight)
+ Melder_throw ("Demotion-only learning cannot handle tied constraints.");
+ if (loserMarks < winnerMarks) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= winnerMarks - loserMarks;
+ constraint -> ranking += constraintStep * (1.0 - constraint -> ranking * my leak) * numberOfDown / (numberOfUp + 1.0);
+ } else if (loserMarks > winnerMarks) {
+ if (icons <= lowestDemotableConstraint) {
+ if (multiplyStepByNumberOfViolations) constraintStep *= loserMarks - winnerMarks;
+ constraint -> ranking -= constraintStep * (1.0 - constraint -> ranking * my leak);
+ }
+ }
+ }
+ if (grammarHasChanged != NULL) *grammarHasChanged = true;
+ }
}
}
diff --git a/gram/manual_gram.cpp b/gram/manual_gram.cpp
index 31eca5c..84a8a15 100644
--- a/gram/manual_gram.cpp
+++ b/gram/manual_gram.cpp
@@ -76,12 +76,12 @@ static void draw_Wolof_ItI (Graphics g) {
}
static void draw_Wolof_itE (Graphics g) {
OTGrammar ot = OTGrammar_create_tongueRoot_grammar (1, 4);
- OTGrammar_drawTableau (ot, g, false, L"it\\ep");
+ OTGrammar_drawTableau (ot, g, false, L"it\\ef");
forget (ot);
}
static void draw_Wolof_etE (Graphics g) {
OTGrammar ot = OTGrammar_create_tongueRoot_grammar (1, 4);
- OTGrammar_drawTableau (ot, g, false, L"et\\ep");
+ OTGrammar_drawTableau (ot, g, false, L"et\\ef");
forget (ot);
}
static void draw_Wolof_schwatschwa (Graphics g) {
@@ -114,13 +114,13 @@ MAN_END
MAN_BEGIN (L"Create tongue-root grammar...", L"ppgb", 20021204)
INTRO (L"A command in the @@New menu@ for creating an @OTGrammar object with a tongue-root-harmony grammar.")
NORMAL (L"These OTGrammar grammars only accept inputs of the form V__1_tV__2_, where V__1_ and V__2_ are "
- "chosen from the six front vowels i, \\ic, e, \\ep, \\sw, and a. In a text field, these "
+ "chosen from the six front vowels i, \\ic, e, \\ef, \\sw, and a. In a text field, these "
"vowels should be typed as $$##i#$, $$##\\bsic#$, $$##e#$, $$##\\bsep#$, $$##\\bssw#$, "
"and $$##a#$, respectively (see @@Special symbols@).")
NORMAL (L"The following phonological features are relevant:")
LIST_ITEM (L"\t\tATR\tRTR")
LIST_ITEM (L"\thigh\ti\t\\ic")
-LIST_ITEM (L"\tmid\te\t\\ep")
+LIST_ITEM (L"\tmid\te\t\\ef")
LIST_ITEM (L"\tlow\t\\sw\ta")
ENTRY (L"Constraints")
NORMAL (L"The resulting OTGrammar will usually contain at least the following five constraints:")
@@ -662,11 +662,11 @@ NORMAL (L"With this way of generating candidates, we see that the five constrain
"First, the absolute prohibition on surface [\\ic] shows that *[rtr / hi] outranks RTR faithfulness "
"(otherwise, [\\ict\\ic] would have been the winner):")
PICTURE (4.0, 1.5, draw_Wolof_ItI)
-NORMAL (L"Second, the faithful surfacing of the disharmonic /it\\ep/ shows that RTR faithfulness must outrank "
+NORMAL (L"Second, the faithful surfacing of the disharmonic /it\\ef/ shows that RTR faithfulness must outrank "
"the harmony (anti-contour) constraint (otherwise, [ite] would have been the winner):")
PICTURE (4.0, 1.5, draw_Wolof_itE)
-NORMAL (L"Third, the RTR-dominant harmonicization of underlying disharmonic /et\\ep/ shows that harmony must outrank ATR faithfulness "
- "(otherwise, [et\\ep] would have won):")
+NORMAL (L"Third, the RTR-dominant harmonicization of underlying disharmonic /et\\ef/ shows that harmony must outrank ATR faithfulness "
+ "(otherwise, [et\\ef] would have won):")
PICTURE (4.0, 1.5, draw_Wolof_etE)
NORMAL (L"Finally, the faithful surfacing of the low ATR vowel /\\sw/ even if not forced by harmony, shows that "
"ATR faithfulness outranks *[atr / lo] (otherwise, [ata] would have been the winning candidate):")
@@ -678,7 +678,7 @@ NORMAL (L"According to @@Prince & Smolensky (1993)@, the input to an OT grammar
"When doing a practical investigation, however, we are only interested in the inputs "
"that will illustrate the properties of our partial grammars. "
"In the case of simplified Wolof, this means the 36 possible V__1_tV__2_ sequences "
- "where V__1_ and V__2_ are any of the six front vowels i, \\ic, e, \\ep, \\sw, and a "
+ "where V__1_ and V__2_ are any of the six front vowels i, \\ic, e, \\ef, \\sw, and a "
"(see @@Create tongue-root grammar...@).")
NORMAL (L"A set of inputs can be generated from an @OTGrammar object by inspecting the list of tableaus. "
"So select the Wolof tongue-root grammar and choose @@OTGrammar: Generate inputs...|Generate inputs... at . "
@@ -686,7 +686,7 @@ NORMAL (L"A set of inputs can be generated from an @OTGrammar object by inspecti
"will appear in the list. Click Inspect and examine the 100 input strings. "
"You will see that they have been randomly chosen from the 36 possible V__1_tV__2_ sequences "
"as described at @@Create tongue-root grammar...@:")
-FORMULA (L"\\epta, et\\ep, \\epti, it\\ep, \\ept\\ep, iti, \\ept\\ic, it\\ic, \\icti, et\\ep, ...")
+FORMULA (L"\\epta, et\\ef, \\epti, it\\ef, \\ept\\ef, iti, \\eft\\ic, it\\ic, \\icti, et\\ef, ...")
NORMAL (L"Thus, when asked to generate a random input, these grammars produce any of the 36 possible V__1_tV__2_ "
"sequences, all with equal probability.")
ENTRY (L"Generating outputs from the grammar")
@@ -695,7 +695,7 @@ NORMAL (L"To compute the outputs for the above set of input forms, select %both
"perhaps specifying zero evaluation noise. "
"A new Strings objects called \"Wolof_out\" will appear in the list. "
"If you Inspect it, you will see that it contains a string sequence aligned with the original input strings:")
-FORMULA (L"\\epta, \\ept\\ep, \\epti, it\\ep, \\ept\\ep, iti, \\epti, iti, iti, \\ept\\ep, ...")
+FORMULA (L"\\epta, \\ept\\ef, \\efti, it\\ef, \\eft\\ef, iti, \\efti, iti, iti, \\eft\\ef, ...")
NORMAL (L"In this way, we have created two Strings objects, which together form a series of input-output pairs "
"needed for learning a grammar that contains faithfulness constraints.")
MAN_END
@@ -1073,8 +1073,8 @@ LIST_ITEM (L"##*G\\s{ESTURE} (contour)# 99.000 99.000")
LIST_ITEM (L"##*[atr / lo]# 99.000 99.000")
NORMAL (L"You will get a comparable result with @@OTAnyGrammar & Strings: Learn output (GLA)... at .")
NORMAL (L"The resulting grammar represents the learner's state after the acquisition of "
- "all the relevant gestures. The learner will now faithfully reproduce /et\\ep/ "
- "if that were in her lexicon. Before being able to render such an underlying form as [\\ept\\ep], "
+ "all the relevant gestures. The learner will now faithfully reproduce /et\\ef/ "
+ "if that were in her lexicon. Before being able to render such an underlying form as [\\eft\\ef], "
"she must learn that faithfulness can be violated.")
ENTRY (L"Example 2: When underlying forms are irrelevant")
NORMAL (L"Underlying forms are relevant only if faithfulness constraints are involved. "
diff --git a/gram/praat_gram.cpp b/gram/praat_gram.cpp
index 1a721b5..a624271 100644
--- a/gram/praat_gram.cpp
+++ b/gram/praat_gram.cpp
@@ -1,6 +1,6 @@
/* praat_gram.cpp
*
- * Copyright (C) 1997-2012 Paul Boersma
+ * Copyright (C) 1997-2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -941,7 +941,7 @@ DO
Melder_informationReal (result, NULL);
END
-FORM (OTGrammar_Distributions_learnFromPartialOutputs, L"OTGrammar & Distributions: Learn from partial outputs", L"OT learning 6. Shortcut to OT learning")
+FORM (OTGrammar_Distributions_learnFromPartialOutputs, L"OTGrammar & Distributions: Learn from partial outputs", L"OT learning 6. Shortcut to grammar learning")
NATURAL (L"Column number", L"1")
REAL (L"Evaluation noise", L"2.0")
OPTIONMENU_ENUM (L"Update rule", kOTGrammar_rerankingStrategy, SYMMETRIC_ALL)
@@ -1034,7 +1034,7 @@ DO
Melder_information (Melder_integer (result));
END
-FORM (OTGrammar_PairDistribution_learn, L"OTGrammar & PairDistribution: Learn", L"OT learning 6. Shortcut to OT learning")
+FORM (OTGrammar_PairDistribution_learn, L"OTGrammar & PairDistribution: Learn", L"OT learning 6. Shortcut to grammar learning")
REAL (L"Evaluation noise", L"2.0")
OPTIONMENU_ENUM (L"Update rule", kOTGrammar_rerankingStrategy, SYMMETRIC_ALL)
POSITIVE (L"Initial plasticity", L"1.0")
diff --git a/kar/Makefile b/kar/Makefile
index a8d975b..7b8c6cd 100644
--- a/kar/Makefile
+++ b/kar/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "kar"
-# Paul Boersma, 6 September 2011
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -16,7 +16,7 @@ clean:
libkar.a: $(OBJECTS)
touch libkar.a
rm libkar.a
- ar cq libkar.a $(OBJECTS)
+ $(AR) cq libkar.a $(OBJECTS)
$(RANLIB) libkar.a
$(OBJECTS): *.h
diff --git a/main/main_Praat.cpp b/main/main_Praat.cpp
index 50360b9..6bb087f 100644
--- a/main/main_Praat.cpp
+++ b/main/main_Praat.cpp
@@ -1,6 +1,6 @@
/* main_Praat.cpp
*
- * Copyright (C) 1992-2012 Paul Boersma
+ * Copyright (C) 1992-2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,14 +45,15 @@ static void logo (Graphics g) {
}
int main (int argc, char *argv []) {
- #if cocoa
- Melder_setTracing (true);
- #endif
- praat_setLogo (130, 80, logo);
- praat_init ("Praat", argc, argv);
- INCLUDE_LIBRARY (praat_uvafon_init)
- INCLUDE_LIBRARY (praat_contrib_Ola_KNN_init)
- praat_run ();
+ try {
+ praat_setLogo (130, 80, logo);
+ praat_init ("Praat", argc, argv);
+ INCLUDE_LIBRARY (praat_uvafon_init)
+ INCLUDE_LIBRARY (praat_contrib_Ola_KNN_init)
+ praat_run ();
+ } catch (MelderError) {
+ Melder_flushError ("This error message percolated all the way to the top."); // an attempt to catch Apache errors
+ }
return 0;
}
diff --git a/makefiles/makefile.defs.linux.alsa b/makefiles/makefile.defs.linux.alsa
index 5fe6cd9..86500a9 100644
--- a/makefiles/makefile.defs.linux.alsa
+++ b/makefiles/makefile.defs.linux.alsa
@@ -1,7 +1,7 @@
# File: makefile.defs.linux.alsa
# System: Linux
-# Paul Boersma, 20 November 2012
+# Paul Boersma, 24 August 2013
CC = gcc -std=gnu99
@@ -17,6 +17,7 @@ EXECUTABLE = praat
LIBS = `pkg-config --libs gtk+-2.0` -lm -lasound
+AR = ar
RANLIB = ls
ICON =
MAIN_ICON =
diff --git a/makefiles/makefile.defs.linux.silent b/makefiles/makefile.defs.linux.silent
index 87697ef..ea6fbd5 100644
--- a/makefiles/makefile.defs.linux.silent
+++ b/makefiles/makefile.defs.linux.silent
@@ -1,7 +1,7 @@
# File: makefile.defs.linux.silent
# System: Linux without sound
-# Paul Boersma, 20 November 2012
+# Paul Boersma, 24 August 2013
CC = gcc -std=gnu99
@@ -17,6 +17,7 @@ EXECUTABLE = praat
LIBS = `pkg-config --libs gtk+-2.0` -lm
+AR = ar
RANLIB = ls
ICON =
MAIN_ICON =
diff --git a/num/Makefile b/num/Makefile
index 0b4ff17..e54819a 100644
--- a/num/Makefile
+++ b/num/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "num"
-# Paul Boersma, 14 January 2012
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -18,7 +18,7 @@ clean:
libnum.a: $(OBJECTS)
touch libnum.a
rm libnum.a
- ar cq libnum.a $(OBJECTS)
+ $(AR) cq libnum.a $(OBJECTS)
$(RANLIB) libnum.a
$(OBJECTS): *.h ../external/gsl/*.h ../external/glpk/*.h ../sys/*.h ../dwsys/*.h
diff --git a/praat64_xcodeproj.dmg b/praat64_xcodeproj.dmg
index 9e24bad..f4262f6 100644
Binary files a/praat64_xcodeproj.dmg and b/praat64_xcodeproj.dmg differ
diff --git a/praat_xcodeproj.dmg b/praat_xcodeproj.dmg
index 41d34d2..ebc6b87 100644
Binary files a/praat_xcodeproj.dmg and b/praat_xcodeproj.dmg differ
diff --git a/stat/Makefile b/stat/Makefile
index d5dae53..715485f 100644
--- a/stat/Makefile
+++ b/stat/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "stat"
-# Paul Boersma, 14 January 2012
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -16,7 +16,7 @@ all: libstat.a
libstat.a: $(OBJECTS)
touch libstat.a
rm libstat.a
- ar cq libstat.a $(OBJECTS)
+ $(AR) cq libstat.a $(OBJECTS)
$(RANLIB) libstat.a
clean:
diff --git a/stat/PairDistribution.cpp b/stat/PairDistribution.cpp
index 050dc45..44cd67b 100644
--- a/stat/PairDistribution.cpp
+++ b/stat/PairDistribution.cpp
@@ -1,6 +1,6 @@
/* PairDistribution.cpp
*
- * Copyright (C) 1997-2012 Paul Boersma
+ * Copyright (C) 1997-2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,13 +40,13 @@
Thing_implement (PairProbability, Data, 0);
+Thing_implement (PairDistribution, Data, 0);
+
void structPairDistribution :: v_info () {
PairDistribution_Parent :: v_info ();
MelderInfo_writeLine (L"Number of pairs: ", Melder_integer (pairs -> size));
}
-Thing_implement (PairDistribution, Data, 0);
-
PairProbability PairProbability_create (const wchar_t *string1, const wchar_t *string2, double weight) {
autoPairProbability me = Thing_new (PairProbability);
my string1 = Melder_wcsdup (string1);
@@ -116,6 +116,15 @@ void PairDistribution_removeZeroWeights (PairDistribution me) {
}
}
+void structPairDistribution :: f_swapInputsAndOutputs () {
+ for (long ipair = pairs -> size; ipair > 0; ipair --) {
+ PairProbability prob = static_cast <PairProbability> (pairs -> item [ipair]);
+ wchar_t *tmp = prob -> string1;
+ prob -> string1 = prob -> string2;
+ prob -> string2 = tmp;
+ }
+}
+
static double PairDistributions_getTotalWeight_checkPositive (PairDistribution me) throw (MelderError) {
double totalWeight = 0.0;
for (long ipair = 1; ipair <= my pairs -> size; ipair ++) {
diff --git a/stat/PairDistribution_def.h b/stat/PairDistribution_def.h
index 7f4c178..5b14c1e 100644
--- a/stat/PairDistribution_def.h
+++ b/stat/PairDistribution_def.h
@@ -1,6 +1,6 @@
/* PairDistribution_def.h
*
- * Copyright (C) 1997-2011 Paul Boersma
+ * Copyright (C) 1997-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +35,8 @@ oo_DEFINE_CLASS (PairDistribution, Data)
oo_COLLECTION (Ordered, pairs, PairProbability, 0)
#if oo_DECLARING
+ // functions:
+ void f_swapInputsAndOutputs ();
// overridden methods:
virtual void v_info ();
#endif
diff --git a/stat/TableEditor.cpp b/stat/TableEditor.cpp
index 2b62e24..0700dcd 100644
--- a/stat/TableEditor.cpp
+++ b/stat/TableEditor.cpp
@@ -1,6 +1,6 @@
/* TableEditor.cpp
*
- * Copyright (C) 2006-2011 Paul Boersma
+ * Copyright (C) 2006-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,24 +34,12 @@ void structTableEditor :: v_destroy () {
static void updateVerticalScrollBar (TableEditor me) {
Table table = static_cast<Table> (my data);
- #if motif
- /*int value, slider, incr, pincr;
- XmScrollBarGetValues (my verticalScrollBar, & value, & slider, & incr, & pincr);
- XmScrollBarSetValues (my verticalScrollBar, my topRow, slider, incr, pincr, False);*/
- XtVaSetValues (my verticalScrollBar -> d_widget,
- XmNvalue, my topRow, XmNmaximum, table -> rows -> size + 1, NULL);
- #endif
+ my verticalScrollBar -> f_set (NUMundefined, table -> rows -> size + 1, my topRow, NUMundefined, NUMundefined, NUMundefined);
}
static void updateHorizontalScrollBar (TableEditor me) {
Table table = static_cast<Table> (my data);
- #if motif
- /*int value, slider, incr, pincr;
- XmScrollBarGetValues (my horizontalScrollBar, & value, & slider, & incr, & pincr);
- XmScrollBarSetValues (my horizontalScrollBar, my topRow, slider, incr, pincr, False);*/
- XtVaSetValues (my horizontalScrollBar -> d_widget,
- XmNvalue, my leftColumn, XmNmaximum, table -> numberOfColumns + 1, NULL);
- #endif
+ my horizontalScrollBar -> f_set (NUMundefined, table -> numberOfColumns + 1, my leftColumn, NUMundefined, NUMundefined, NUMundefined);
}
void structTableEditor :: v_dataChanged () {
@@ -202,7 +190,6 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (TableEditor);
if (my graphics == NULL) return;
-if (gtk && event -> type != BUTTON_PRESS) return;
double xWC, yWC;
Graphics_DCtoWC (my graphics, event -> x, event -> y, & xWC, & yWC);
// TODO: implement selection
@@ -219,7 +206,12 @@ static void gui_cb_scrollHorizontal (I, GuiScrollBarEvent event) {
int value = event -> scrollBar -> f_getValue ();
if (value != my leftColumn) {
my leftColumn = value;
- my v_draw ();
+ #if cocoa || gtk || win
+ Graphics_updateWs (my graphics); // wait for expose event
+ #else
+ Graphics_clearWs (my graphics);
+ my v_draw (); // do not wait for expose event
+ #endif
}
}
@@ -228,7 +220,12 @@ static void gui_cb_scrollVertical (I, GuiScrollBarEvent event) {
int value = event -> scrollBar -> f_getValue ();
if (value != my topRow) {
my topRow = value;
- my v_draw ();
+ #if cocoa || gtk || win
+ Graphics_updateWs (my graphics); // wait for expose event
+ #else
+ Graphics_clearWs (my graphics);
+ my v_draw (); // do not wait for expose event
+ #endif
}
}
diff --git a/stat/manual_statistics.cpp b/stat/manual_statistics.cpp
index efc55c0..7ab8635 100644
--- a/stat/manual_statistics.cpp
+++ b/stat/manual_statistics.cpp
@@ -136,7 +136,7 @@ NORMAL (L"In this table we see 10 different stimuli, each characterized by a cer
"of the factors (independent variables) %F1 (first formant in Hertz) and %Dur (duration in milliseconds). "
"The first row of the table means that there was a stimulus with an F1 of 764 Hz and a duration of 87 ms, "
"and that the listener responded to this stimulus 2 times with the response category /\\ae/, "
- "and the remaining 8 times with the category /\\ep/.")
+ "and the remaining 8 times with the category /\\ef/.")
NORMAL (L"A table as above can be typed into a text file. The columns can be separated with spaces and/or tab stops. "
"The file can be read into Praat with ##Read Table from table file...#. "
"The command ##To logistic regression...# will become available in the #Statistics menu.")
@@ -156,15 +156,15 @@ ENTRY (L"What does it do?")
"Draw ellipse... mdur_ae-sdur mdur_ae+sdur mf1_ae-sf1 mf1_ae+sf1\n"
"Text... mdur_ae Centre mf1_ae Half /\\ae/\n"
"Draw ellipse... mdur_ep-sdur mdur_ep+sdur mf1_ep-sf1 mf1_ep+sf1\n"
- "Text... mdur_ep Centre mf1_ep Half /\\ep/\n"
+ "Text... mdur_ep Centre mf1_ep Half /\\ef/\n"
"Draw inner box\n"
)*/
NORMAL (L"The logistic regression method will find values %\\al, %%\\be__F1_% and %%\\be__dur_% "
"that optimize")
-FORMULA (L"%\\al + %%\\be__F1_% %F1__%k_ + %%\\be__dur_% %Dur__%k_ = ln (%p__%k_(/\\ep/)/%p__%k_(/\\ae/))")
-NORMAL (L"where %k runs from 1 to 10, and %p__%k_(/\\ae/) + %p__%k_(/\\ep/) = 1.")
+FORMULA (L"%\\al + %%\\be__F1_% %F1__%k_ + %%\\be__dur_% %Dur__%k_ = ln (%p__%k_(/\\ef/)/%p__%k_(/\\ae/))")
+NORMAL (L"where %k runs from 1 to 10, and %p__%k_(/\\ae/) + %p__%k_(/\\ef/) = 1.")
NORMAL (L"The optimization criterion is %%maximum likelihood%, i.e. those %\\al, %%\\be__F1_% and %%\\be__dur_% "
- "will be chosen that lead to values for %p__%k_(/\\ae/) and %p__%k_(/\\ep/) that make the observations in the table "
+ "will be chosen that lead to values for %p__%k_(/\\ae/) and %p__%k_(/\\ef/) that make the observations in the table "
"most likely.")
NORMAL (L"Praat will create an object of type #LogisticRegression in the list. "
"When you then click the #Info button, Praat will write the values of %\\al (the %intercept), "
diff --git a/stat/praat_Stat.cpp b/stat/praat_Stat.cpp
index 5923b1f..c735269 100644
--- a/stat/praat_Stat.cpp
+++ b/stat/praat_Stat.cpp
@@ -1,6 +1,6 @@
/* praat_Stat.cpp
*
- * Copyright (C) 1992-2012 Paul Boersma
+ * Copyright (C) 1992-2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -191,6 +191,14 @@ DIRECT (PairDistribution_removeZeroWeights)
}
END
+DIRECT (PairDistribution_swapInputsAndOutputs)
+ LOOP {
+ iam (PairDistribution);
+ my f_swapInputsAndOutputs ();
+ praat_dataChanged (me);
+ }
+END
+
FORM (PairDistribution_to_Stringses, L"Generate two Strings objects", 0)
NATURAL (L"Number", L"1000")
SENTENCE (L"Name of first Strings", L"input")
@@ -1812,7 +1820,8 @@ void praat_uvafon_stat_init () {
praat_addAction1 (classPairDistribution, 1, L"Get fraction correct (maximum likelihood)", 0, 1, DO_PairDistribution_getFractionCorrect_maximumLikelihood);
praat_addAction1 (classPairDistribution, 1, L"Get fraction correct (probability matching)", 0, 1, DO_PairDistribution_getFractionCorrect_probabilityMatching);
praat_addAction1 (classPairDistribution, 0, L"Modify -", 0, 0, 0);
- praat_addAction1 (classPairDistribution, 1, L"Remove zero weights", 0, 0, DO_PairDistribution_removeZeroWeights);
+ praat_addAction1 (classPairDistribution, 0, L"Remove zero weights", 0, 1, DO_PairDistribution_removeZeroWeights);
+ praat_addAction1 (classPairDistribution, 0, L"Swap inputs and outputs", 0, 1, DO_PairDistribution_swapInputsAndOutputs);
praat_addAction1 (classTable, 0, L"Table help", 0, 0, DO_Table_help);
praat_addAction1 (classTable, 1, L"Save as tab-separated file...", 0, 0, DO_Table_writeToTabSeparatedFile);
diff --git a/sys/DemoEditor.cpp b/sys/DemoEditor.cpp
index 675da9a..eed4904 100644
--- a/sys/DemoEditor.cpp
+++ b/sys/DemoEditor.cpp
@@ -1,6 +1,6 @@
/* DemoEditor.cpp
*
- * Copyright (C) 2009-2011 Paul Boersma
+ * Copyright (C) 2009-2011,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -73,7 +73,6 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (DemoEditor);
if (my graphics == NULL) return; // Could be the case in the very beginning.
-if (gtk && event -> type != BUTTON_PRESS) return;
my clicked = true;
my keyPressed = false;
my x = event -> x;
@@ -93,6 +92,7 @@ static void gui_drawingarea_cb_key (I, GuiDrawingAreaKeyEvent event) {
my x = 0;
my y = 0;
my key = event -> key;
+ trace ("%d", (int) my key);
my shiftKeyPressed = event -> shiftKeyPressed;
my commandKeyPressed = event -> commandKeyPressed;
my optionKeyPressed = event -> optionKeyPressed;
@@ -103,6 +103,7 @@ static void gui_drawingarea_cb_resize (I, GuiDrawingAreaResizeEvent event) {
iam (DemoEditor);
if (my graphics == NULL) return; // Could be the case in the very beginning.
int marginWidth = 0, marginHeight = 0;
+ trace ("%d %d", event -> width, event -> height);
Graphics_setWsViewport (my graphics, marginWidth, event -> width - marginWidth, marginHeight, event -> height - marginHeight);
Graphics_setWsWindow (my graphics, 0, 100, 0, 100);
Graphics_setViewport (my graphics, 0, 100, 0, 100);
@@ -204,7 +205,7 @@ void Demo_waitForInput (Interpreter interpreter) {
theDemoEditor -> keyPressed = false;
theDemoEditor -> waitingForInput = true;
#if ! defined (CONSOLE_APPLICATION)
- { // scope
+ {// scope
autoMelderSaveDefaultDir saveDir;
bool wasBackgrounding = Melder_backgrounding;
if (wasBackgrounding) praat_foreground ();
@@ -213,6 +214,21 @@ void Demo_waitForInput (Interpreter interpreter) {
do {
gtk_main_iteration ();
} while (! theDemoEditor -> clicked && ! theDemoEditor -> keyPressed && ! theDemoEditor -> userWantsToClose);
+ #elif cocoa
+ do {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [theDemoEditor -> d_windowForm -> d_cocoaWindow flushWindow];
+ NSEvent *nsEvent = [NSApp
+ nextEventMatchingMask: NSAnyEventMask
+ untilDate: [NSDate distantFuture] // wait
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES
+ ];
+ Melder_assert (nsEvent != NULL);
+ [NSApp sendEvent: nsEvent];
+ [NSApp updateWindows]; // called automatically?
+ [pool release];
+ } while (! theDemoEditor -> clicked && ! theDemoEditor -> keyPressed && ! theDemoEditor -> userWantsToClose);
#elif defined (_WIN32)
do {
XEvent event;
@@ -220,14 +236,11 @@ void Demo_waitForInput (Interpreter interpreter) {
XtDispatchEvent (& event);
} while (! theDemoEditor -> clicked && ! theDemoEditor -> keyPressed && ! theDemoEditor -> userWantsToClose);
#elif defined (macintosh)
- #if useCarbon
- do {
- XEvent event;
- GuiNextEvent (& event);
- XtDispatchEvent (& event);
- } while (! theDemoEditor -> clicked && ! theDemoEditor -> keyPressed && ! theDemoEditor -> userWantsToClose);
- #else
- #endif
+ do {
+ XEvent event;
+ GuiNextEvent (& event);
+ XtDispatchEvent (& event);
+ } while (! theDemoEditor -> clicked && ! theDemoEditor -> keyPressed && ! theDemoEditor -> userWantsToClose);
#endif
} catch (MelderError) {
Melder_flushError ("An error made it to the outer level in the Demo window; should not occur! Please write to paul.boersma at uva.nl");
diff --git a/sys/Editor.cpp b/sys/Editor.cpp
index 114fe20..2fcbcd0 100644
--- a/sys/Editor.cpp
+++ b/sys/Editor.cpp
@@ -211,12 +211,14 @@ void Editor_doMenuCommand (Editor me, const wchar_t *commandTitle, int narg, Sta
/********** class Editor **********/
void structEditor :: v_destroy () {
+ trace ("enter");
MelderAudio_stopPlaying (MelderAudio_IMPLICIT);
/*
* The following command must be performed before the shell is destroyed.
* Otherwise, we would be forgetting dangling command dialogs here.
*/
forget (menus);
+ broadcastDestruction ();
if (d_windowForm) {
#if gtk
if (d_windowForm -> d_gtkWindow) {
@@ -224,13 +226,17 @@ void structEditor :: v_destroy () {
gtk_widget_destroy (GTK_WIDGET (d_windowForm -> d_gtkWindow));
}
#elif cocoa
+ if (d_windowForm -> d_cocoaWindow) {
+ NSWindow *cocoaWindow = d_windowForm -> d_cocoaWindow;
+ //d_windowForm -> d_cocoaWindow = NULL;
+ [cocoaWindow close];
+ }
#elif motif
if (d_windowForm -> d_xmShell) {
XtDestroyWidget (d_windowForm -> d_xmShell);
}
#endif
}
- broadcastDestruction ();
forget (previousData);
if (d_ownData) forget (data);
Editor_Parent :: v_destroy ();
@@ -378,6 +384,8 @@ void structEditor :: v_do_pictureMargins (EditorCommand cmd) {
static void gui_window_cb_goAway (I) {
iam (Editor);
+ Melder_assert (me != NULL);
+ Melder_assert (Thing_member (me, classEditor));
my v_goAway ();
}
diff --git a/sys/Formula.cpp b/sys/Formula.cpp
index f954e6c..81a73f3 100644
--- a/sys/Formula.cpp
+++ b/sys/Formula.cpp
@@ -126,7 +126,7 @@ enum { GEENSYMBOOL_,
WRITE_FILE_, WRITE_FILE_LINE_, APPEND_FILE_, APPEND_FILE_LINE_,
MIN_, MAX_, IMIN_, IMAX_,
LEFTSTR_, RIGHTSTR_, MIDSTR_,
- SELECTED_, SELECTEDSTR_, NUMBER_OF_SELECTED_,
+ SELECTED_, SELECTEDSTR_, NUMBER_OF_SELECTED_, SELECT_OBJECT_, PLUS_OBJECT_, MINUS_OBJECT_, REMOVE_OBJECT_,
BEGIN_PAUSE_FORM_, PAUSE_FORM_ADD_REAL_, PAUSE_FORM_ADD_POSITIVE_, PAUSE_FORM_ADD_INTEGER_, PAUSE_FORM_ADD_NATURAL_,
PAUSE_FORM_ADD_WORD_, PAUSE_FORM_ADD_SENTENCE_, PAUSE_FORM_ADD_TEXT_, PAUSE_FORM_ADD_BOOLEAN_,
PAUSE_FORM_ADD_CHOICE_, PAUSE_FORM_ADD_OPTION_MENU_, PAUSE_FORM_ADD_OPTION_,
@@ -140,11 +140,12 @@ enum { GEENSYMBOOL_,
#define HIGH_FUNCTION_N NUMBER_OF_COLUMNS_
/* String functions. */
- #define LOW_STRING_FUNCTION LOW_FUNCTION_STRNUM
- #define LOW_FUNCTION_STRNUM LENGTH_
+ #define LOW_STRING_FUNCTION LOW_FUNCTION_STR1
+ #define LOW_FUNCTION_STR1 LENGTH_
LENGTH_, STRING_TO_NUMBER_, FILE_READABLE_, DELETE_FILE_, CREATE_DIRECTORY_, VARIABLE_EXISTS_,
- #define HIGH_FUNCTION_STRNUM VARIABLE_EXISTS_
- DATESTR_,
+ READ_FILE_, READ_FILESTR_,
+ #define HIGH_FUNCTION_STR1 READ_FILESTR_
+ DATESTR_, INFOSTR_,
ENVIRONMENTSTR_, INDEX_, RINDEX_,
STARTS_WITH_, ENDS_WITH_, REPLACESTR_, INDEX_REGEX_, RINDEX_REGEX_, REPLACE_REGEXSTR_,
EXTRACT_NUMBER_, EXTRACT_WORDSTR_, EXTRACT_LINESTR_,
@@ -221,7 +222,7 @@ static const wchar_t *Formula_instructionNames [1 + hoogsteSymbool] = { L"",
L"writeFile", L"writeFileLine", L"appendFile", L"appendFileLine",
L"min", L"max", L"imin", L"imax",
L"left$", L"right$", L"mid$",
- L"selected", L"selected$", L"numberOfSelected",
+ L"selected", L"selected$", L"numberOfSelected", L"selectObject", L"plusObject", L"minusObject", L"removeObject",
L"beginPause", L"real", L"positive", L"integer", L"natural",
L"word", L"sentence", L"text", L"boolean",
L"choice", L"optionMenu", L"option",
@@ -234,7 +235,8 @@ static const wchar_t *Formula_instructionNames [1 + hoogsteSymbool] = { L"",
L"numberOfRows", L"numberOfColumns",
L"length", L"number", L"fileReadable", L"deleteFile", L"createDirectory", L"variableExists",
- L"date$",
+ L"readFile", L"readFile$",
+ L"date$", L"info$",
L"environment$", L"index", L"rindex",
L"startsWith", L"endsWith", L"replace$", L"index_regex", L"rindex_regex", L"replace_regex$",
L"extractNumber", L"extractWord$", L"extractLine$",
@@ -1242,7 +1244,7 @@ static void parsePowerFactor (void) {
}
if (symbol >= LOW_STRING_FUNCTION && symbol <= HIGH_STRING_FUNCTION) {
- if (symbol >= LOW_FUNCTION_STRNUM && symbol <= HIGH_FUNCTION_STRNUM) {
+ if (symbol >= LOW_FUNCTION_STR1 && symbol <= HIGH_FUNCTION_STR1) {
pas (HAAKJEOPENEN_);
parseExpression ();
pas (HAAKJESLUITEN_);
@@ -1255,7 +1257,7 @@ static void parsePowerFactor (void) {
pas (KOMMA_);
parseExpression ();
pas (HAAKJESLUITEN_);
- } else if (symbol == DATESTR_) {
+ } else if (symbol == DATESTR_ || symbol == INFOSTR_) {
pas (HAAKJEOPENEN_);
pas (HAAKJESLUITEN_);
} else if (symbol == EXTRACT_WORDSTR_ || symbol == EXTRACT_LINESTR_) {
@@ -2394,7 +2396,13 @@ static void do_do (void) {
Melder_throw ("The first argument of the function \"do\" has to be a string, namely a menu command, and not ", Stackel_whichText (& stack [0]), ".");
const wchar_t *command = stack [0]. string;
if (theCurrentPraatObjects == & theForegroundPraatObjects && praatP. editor != NULL) {
+ autoMelderString valueString;
+ MelderString_empty (& valueString);
+ autoMelderDivertInfo divert (& valueString);
+ MelderString_appendCharacter (& valueString, 1);
Editor_doMenuCommand ((Editor) praatP. editor, command, numberOfArguments, & stack [0], NULL, theInterpreter);
+ pushNumber (Melder_atof (valueString.string));
+ return;
} else if (theCurrentPraatObjects != & theForegroundPraatObjects &&
(wcsnequ (command, L"Save ", 5) || wcsnequ (command, L"Write ", 6) || wcsnequ (command, L"Append ", 7) || wcsequ (command, L"Quit")))
{
@@ -2442,7 +2450,12 @@ static void do_doStr (void) {
Melder_throw ("The first argument of the function \"do$\" has to be a string, namely a menu command, and not ", Stackel_whichText (& stack [0]), ".");
const wchar_t *command = stack [0]. string;
if (theCurrentPraatObjects == & theForegroundPraatObjects && praatP. editor != NULL) {
+ static MelderString info;
+ MelderString_empty (& info);
+ autoMelderDivertInfo divert (& info);
Editor_doMenuCommand ((Editor) praatP. editor, command, numberOfArguments, & stack [0], NULL, theInterpreter);
+ pushString (Melder_wcsdup (info.string));
+ return;
} else if (theCurrentPraatObjects != & theForegroundPraatObjects &&
(wcsnequ (command, L"Save ", 5) || wcsnequ (command, L"Write ", 6) || wcsnequ (command, L"Append ", 7) || wcsequ (command, L"Quit")))
{
@@ -2527,6 +2540,104 @@ static void do_appendInfoLine () {
MelderInfo_drain ();
pushNumber (1);
}
+static void do_writeFile () {
+ if (theCurrentPraatObjects != & theForegroundPraatObjects)
+ Melder_throw ("The function \"writeFile\" is not available inside manuals.");
+ Stackel narg = pop;
+ Melder_assert (narg->which == Stackel_NUMBER);
+ int numberOfArguments = narg->number;
+ w -= numberOfArguments;
+ Stackel fileName = & theStack [1];
+ if (fileName -> which != Stackel_STRING) {
+ Melder_throw ("The first argument of \"writeFile\" has to be a string (a file name), not ", Stackel_whichText (fileName), ".");
+ }
+ autoMelderString text;
+ for (int iarg = 2; iarg <= numberOfArguments; iarg ++) {
+ Stackel arg = & theStack [w + iarg];
+ if (arg->which == Stackel_NUMBER)
+ MelderString_append (& text, Melder_double (arg->number));
+ else if (arg->which == Stackel_STRING)
+ MelderString_append (& text, arg->string);
+ }
+ structMelderFile file = { 0 };
+ Melder_relativePathToFile (fileName -> string, & file);
+ MelderFile_writeText (& file, text.transfer(), Melder_getOutputEncoding ());
+ pushNumber (1);
+}
+static void do_writeFileLine () {
+ if (theCurrentPraatObjects != & theForegroundPraatObjects)
+ Melder_throw ("The function \"writeFile\" is not available inside manuals.");
+ Stackel narg = pop;
+ Melder_assert (narg->which == Stackel_NUMBER);
+ int numberOfArguments = narg->number;
+ w -= numberOfArguments;
+ Stackel fileName = & theStack [1];
+ if (fileName -> which != Stackel_STRING) {
+ Melder_throw ("The first argument of \"writeFile\" has to be a string (a file name), not ", Stackel_whichText (fileName), ".");
+ }
+ autoMelderString text;
+ for (int iarg = 2; iarg <= numberOfArguments; iarg ++) {
+ Stackel arg = & theStack [w + iarg];
+ if (arg->which == Stackel_NUMBER)
+ MelderString_append (& text, Melder_double (arg->number));
+ else if (arg->which == Stackel_STRING)
+ MelderString_append (& text, arg->string);
+ }
+ MelderString_appendCharacter (& text, '\n');
+ structMelderFile file = { 0 };
+ Melder_relativePathToFile (fileName -> string, & file);
+ MelderFile_writeText (& file, text.transfer(), Melder_getOutputEncoding ());
+ pushNumber (1);
+}
+static void do_appendFile () {
+ if (theCurrentPraatObjects != & theForegroundPraatObjects)
+ Melder_throw ("The function \"writeFile\" is not available inside manuals.");
+ Stackel narg = pop;
+ Melder_assert (narg->which == Stackel_NUMBER);
+ int numberOfArguments = narg->number;
+ w -= numberOfArguments;
+ Stackel fileName = & theStack [1];
+ if (fileName -> which != Stackel_STRING) {
+ Melder_throw ("The first argument of \"writeFile\" has to be a string (a file name), not ", Stackel_whichText (fileName), ".");
+ }
+ autoMelderString text;
+ for (int iarg = 2; iarg <= numberOfArguments; iarg ++) {
+ Stackel arg = & theStack [w + iarg];
+ if (arg->which == Stackel_NUMBER)
+ MelderString_append (& text, Melder_double (arg->number));
+ else if (arg->which == Stackel_STRING)
+ MelderString_append (& text, arg->string);
+ }
+ structMelderFile file = { 0 };
+ Melder_relativePathToFile (fileName -> string, & file);
+ MelderFile_appendText (& file, text.transfer());
+ pushNumber (1);
+}
+static void do_appendFileLine () {
+ if (theCurrentPraatObjects != & theForegroundPraatObjects)
+ Melder_throw ("The function \"writeFile\" is not available inside manuals.");
+ Stackel narg = pop;
+ Melder_assert (narg->which == Stackel_NUMBER);
+ int numberOfArguments = narg->number;
+ w -= numberOfArguments;
+ Stackel fileName = & theStack [1];
+ if (fileName -> which != Stackel_STRING) {
+ Melder_throw ("The first argument of \"writeFile\" has to be a string (a file name), not ", Stackel_whichText (fileName), ".");
+ }
+ autoMelderString text;
+ for (int iarg = 2; iarg <= numberOfArguments; iarg ++) {
+ Stackel arg = & theStack [w + iarg];
+ if (arg->which == Stackel_NUMBER)
+ MelderString_append (& text, Melder_double (arg->number));
+ else if (arg->which == Stackel_STRING)
+ MelderString_append (& text, arg->string);
+ }
+ MelderString_appendCharacter (& text, '\n');
+ structMelderFile file = { 0 };
+ Melder_relativePathToFile (fileName -> string, & file);
+ MelderFile_appendText (& file, text.transfer());
+ pushNumber (1);
+}
static void do_min (void) {
Stackel n = pop, last;
double result;
@@ -2826,6 +2937,10 @@ static void do_dateStr (void) {
if (newline) *newline = '\0';
pushString (date);
}
+static void do_infoStr (void) {
+ wchar_t *info = Melder_wcsdup (Melder_getInfo ());
+ pushString (info);
+}
static void do_leftStr (void) {
//Melder_casual ("entering left$");
Stackel narg = pop;
@@ -3150,6 +3265,102 @@ static void do_numberOfSelected (void) {
}
pushNumber (result);
}
+static int praat_findObjectById (int id) {
+ int IOBJECT;
+ WHERE_DOWN (ID == id)
+ return IOBJECT;
+ Melder_throw ("No object with number ", id, ".");
+}
+static int praat_findObjectFromString (const wchar_t *name) {
+ int IOBJECT;
+ if (*name >= 'A' && *name <= 'Z') {
+ /*
+ * Find the object by its name.
+ */
+ static MelderString buffer = { 0 };
+ MelderString_copy (& buffer, name);
+ wchar_t *space = wcschr (buffer.string, ' ');
+ if (space == NULL)
+ Melder_throw ("Missing space in object name \"", name, "\".");
+ *space = '\0';
+ wchar_t *className = & buffer.string [0], *givenName = space + 1;
+ WHERE_DOWN (1) {
+ Data object = (Data) OBJECT;
+ if (wcsequ (className, Thing_className ((Thing) OBJECT)) && wcsequ (givenName, object -> name))
+ return IOBJECT;
+ }
+ }
+ Melder_throw ("No object with name \"", name, "\".");
+}
+static void do_selectObject (void) {
+ Stackel n = pop;
+ praat_deselectAll ();
+ for (int iobject = 1; iobject <= n -> number; iobject ++) {
+ Stackel object = pop;
+ if (object -> which == Stackel_NUMBER) {
+ int IOBJECT = praat_findObjectById (object -> number);
+ praat_select (IOBJECT);
+ } else if (object -> which == Stackel_STRING) {
+ int IOBJECT = praat_findObjectFromString (object -> string);
+ praat_select (IOBJECT);
+ } else {
+ Melder_throw ("The function \"selectObject\" takes numbers and strings, not ", Stackel_whichText (object));
+ }
+ }
+ praat_show ();
+ pushNumber (1);
+}
+static void do_plusObject (void) {
+ Stackel n = pop;
+ for (int iobject = 1; iobject <= n -> number; iobject ++) {
+ Stackel object = pop;
+ if (object -> which == Stackel_NUMBER) {
+ int IOBJECT = praat_findObjectById (object -> number);
+ praat_select (IOBJECT);
+ } else if (object -> which == Stackel_STRING) {
+ int IOBJECT = praat_findObjectFromString (object -> string);
+ praat_select (IOBJECT);
+ } else {
+ Melder_throw ("The function \"plusObject\" takes numbers and strings, not ", Stackel_whichText (object));
+ }
+ }
+ praat_show ();
+ pushNumber (1);
+}
+static void do_minusObject (void) {
+ Stackel n = pop;
+ for (int iobject = 1; iobject <= n -> number; iobject ++) {
+ Stackel object = pop;
+ if (object -> which == Stackel_NUMBER) {
+ int IOBJECT = praat_findObjectById (object -> number);
+ praat_deselect (IOBJECT);
+ } else if (object -> which == Stackel_STRING) {
+ int IOBJECT = praat_findObjectFromString (object -> string);
+ praat_deselect (IOBJECT);
+ } else {
+ Melder_throw ("The function \"minusObject\" takes numbers and strings, not ", Stackel_whichText (object));
+ }
+ }
+ praat_show ();
+ pushNumber (1);
+}
+static void do_removeObject (void) {
+ Stackel n = pop;
+ for (int iobject = 1; iobject <= n -> number; iobject ++) {
+ Stackel object = pop;
+ if (object -> which == Stackel_NUMBER) {
+ int IOBJECT = praat_findObjectById (object -> number);
+ praat_removeObject (IOBJECT);
+ } else if (object -> which == Stackel_STRING) {
+ int IOBJECT = praat_findObjectFromString (object -> string);
+ praat_removeObject (IOBJECT);
+ } else {
+ Melder_throw ("The function \"removeObject\" takes numbers and strings, not ", Stackel_whichText (object));
+ }
+ }
+ praat_show ();
+ pushNumber (1);
+}
static void do_stringStr (void) {
Stackel value = pop;
if (value->which == Stackel_NUMBER) {
@@ -3204,7 +3415,7 @@ static void do_createDirectory (void) {
#endif
pushNumber (1);
} else {
- Melder_throw ("The function \"deleteFile\" requires a string, not ", Stackel_whichText (f), ".");
+ Melder_throw ("The function \"createDirectory\" requires a string, not ", Stackel_whichText (f), ".");
}
}
static void do_variableExists (void) {
@@ -3216,6 +3427,28 @@ static void do_variableExists (void) {
Melder_throw ("The function \"variableExists\" requires a string, not ", Stackel_whichText (f), ".");
}
}
+static void do_readFile (void) {
+ Stackel f = pop;
+ if (f->which == Stackel_STRING) {
+ structMelderFile file = { 0 };
+ Melder_relativePathToFile (f->string, & file);
+ autostring text = MelderFile_readText (& file);
+ pushNumber (Melder_atof (text.peek()));
+ } else {
+ Melder_throw ("The function \"readFile\" requires a string (a file name), not ", Stackel_whichText (f), ".");
+ }
+}
+static void do_readFileStr (void) {
+ Stackel f = pop;
+ if (f->which == Stackel_STRING) {
+ structMelderFile file = { 0 };
+ Melder_relativePathToFile (f->string, & file);
+ autostring text = MelderFile_readText (& file);
+ pushString (text.transfer());
+ } else {
+ Melder_throw ("The function \"readFile$\" requires a string (a file name), not ", Stackel_whichText (f), ".");
+ }
+}
static void do_beginPauseForm (void) {
if (theCurrentPraatObjects != & theForegroundPraatObjects)
Melder_throw ("The function \"beginPauseForm\" is not available inside manuals.");
@@ -4382,10 +4615,10 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
} break; case WRITE_INFO_LINE_ : { do_writeInfoLine ();
} break; case APPEND_INFO_ : { do_appendInfo ();
} break; case APPEND_INFO_LINE_: { do_appendInfoLine ();
-//} break; case WRITE_FILE_ : { do_writeFile ();
-//} break; case WRITE_FILE_LINE_ : { do_writeFileLine ();
-//} break; case APPEND_FILE_ : { do_appendFile ();
-//} break; case APPEND_FILE_LINE_: { do_appendFileLine ();
+} break; case WRITE_FILE_ : { do_writeFile ();
+} break; case WRITE_FILE_LINE_ : { do_writeFileLine ();
+} break; case APPEND_FILE_ : { do_appendFile ();
+} break; case APPEND_FILE_LINE_: { do_appendFileLine ();
} break; case MIN_: { do_min ();
} break; case MAX_: { do_max ();
} break; case IMIN_: { do_imin ();
@@ -4402,6 +4635,7 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
} break; case STRING_TO_NUMBER_: { do_number ();
} break; case FILE_READABLE_: { do_fileReadable ();
} break; case DATESTR_: { do_dateStr ();
+} break; case INFOSTR_: { do_infoStr ();
} break; case LEFTSTR_: { do_leftStr ();
} break; case RIGHTSTR_: { do_rightStr ();
} break; case MIDSTR_: { do_midStr ();
@@ -4420,12 +4654,18 @@ case NUMBER_: { pushNumber (f [programPointer]. content.number);
} break; case SELECTED_: { do_selected ();
} break; case SELECTEDSTR_: { do_selectedStr ();
} break; case NUMBER_OF_SELECTED_: { do_numberOfSelected ();
+} break; case SELECT_OBJECT_: { do_selectObject ();
+} break; case PLUS_OBJECT_ : { do_plusObject ();
+} break; case MINUS_OBJECT_ : { do_minusObject ();
+} break; case REMOVE_OBJECT_: { do_removeObject ();
} break; case STRINGSTR_: { do_stringStr ();
} break; case FIXEDSTR_: { do_fixedStr ();
} break; case PERCENTSTR_: { do_percentStr ();
} break; case DELETE_FILE_: { do_deleteFile ();
} break; case CREATE_DIRECTORY_: { do_createDirectory ();
} break; case VARIABLE_EXISTS_: { do_variableExists ();
+} break; case READ_FILE_: { do_readFile ();
+} break; case READ_FILESTR_: { do_readFileStr ();
/********** Pause window functions: **********/
} break; case BEGIN_PAUSE_FORM_: { do_beginPauseForm ();
} break; case PAUSE_FORM_ADD_REAL_: { do_pauseFormAddReal ();
diff --git a/sys/Graphics.h b/sys/Graphics.h
index c554d22..eb8e4a0 100644
--- a/sys/Graphics.h
+++ b/sys/Graphics.h
@@ -2,7 +2,7 @@
#define _Graphics_h_
/* Graphics.h
*
- * Copyright (C) 1992-2011,2012 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,7 +35,7 @@ typedef struct {
unsigned long code;
wchar_t kar;
double width;
- union { long integer; const char *string; } font;
+ union { long integer; const char *string; void *pointer; } font;
int cell, line, run;
} _Graphics_widechar;
diff --git a/sys/GraphicsP.h b/sys/GraphicsP.h
index 8dcc5bc..b221dc9 100644
--- a/sys/GraphicsP.h
+++ b/sys/GraphicsP.h
@@ -42,7 +42,8 @@ void Graphics_init (Graphics me);
#define kGraphics_font_SYMBOL (kGraphics_font_MAX + 1)
#define kGraphics_font_IPATIMES (kGraphics_font_MAX + 2)
-#define kGraphics_font_DINGBATS (kGraphics_font_MAX + 3)
+#define kGraphics_font_IPAPALATINO (kGraphics_font_MAX + 3)
+#define kGraphics_font_DINGBATS (kGraphics_font_MAX + 4)
Thing_define (GraphicsScreen, Graphics) {
// new data:
diff --git a/sys/GraphicsScreen.cpp b/sys/GraphicsScreen.cpp
index d7f6c1d..3338730 100644
--- a/sys/GraphicsScreen.cpp
+++ b/sys/GraphicsScreen.cpp
@@ -107,10 +107,17 @@ void structGraphicsScreen :: v_destroy () {
void structGraphicsScreen :: v_flushWs () {
#if cairo
// Ik weet niet of dit is wat het zou moeten zijn ;)
- // gdk_window_process_updates (my window, TRUE);
- gdk_flush ();
+ //gdk_window_process_updates (d_window, TRUE); // this "works" but is incorrect because it's not the expose events that have to be carried out
+ //gdk_window_flush (d_window);
+ //gdk_flush ();
// TODO: een aanroep die de eventuele grafische buffer ledigt,
// zodat de gebruiker de grafica ziet ook al blijft Praat in hetzelfde event zitten
+ #elif cocoa
+ if (d_drawingArea) {
+ GuiShell shell = d_drawingArea -> d_shell;
+ Melder_assert (shell != NULL);
+ [shell -> d_cocoaWindow flushWindow];
+ }
#elif win
/*GdiFlush ();*/
#elif mac
@@ -155,8 +162,7 @@ void structGraphicsScreen :: v_clearWs () {
cairo_set_source_rgb (d_cairoGraphicsContext, 0.0, 0.0, 0.0);
}
#elif cocoa
-
- GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea*) d_drawingArea -> d_widget;
+ GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea *) d_drawingArea -> d_widget;
if (cocoaDrawingArea) {
NSRect rect;
if (this -> d_x1DC < this -> d_x2DC) {
@@ -173,17 +179,24 @@ void structGraphicsScreen :: v_clearWs () {
rect.origin.y = this -> d_y2DC;
rect.size.height = this -> d_y1DC - this -> d_y2DC;
}
-
- CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState(context);
+ [cocoaDrawingArea lockFocus];
+ CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState (context);
CGContextSetAlpha (context, 1.0);
CGContextSetBlendMode (context, kCGBlendModeNormal);
CGContextSetRGBFillColor (context, 1.0, 1.0, 1.0, 1.0);
+ //rect.origin.x -= 1000;
+ //rect.origin.y -= 1000;
+ //rect.size.width += 2000;
+ //rect.size.height += 2000;
+ trace ("clearing %f %f %f %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+ //CGContextTranslateCTM (context, 0, cocoaDrawingArea.bounds.size.height);
+ //CGContextScaleCTM (context, 1.0, -1.0);
CGContextFillRect (context, rect);
- CGContextSynchronize ( context);
- CGContextRestoreGState(context);
+ //CGContextSynchronize (context);
+ CGContextRestoreGState (context);
+ [cocoaDrawingArea unlockFocus];
}
-
#elif win
RECT rect;
rect. left = rect. top = 0;
@@ -263,7 +276,8 @@ void structGraphicsScreen :: v_updateWs () {
rect.size.height = this -> d_y1DC - this -> d_y2DC;
}
- [view setNeedsDisplayInRect:rect];
+ //[view setNeedsDisplayInRect: rect];
+ [view setNeedsDisplay: YES];
#elif win
//clear (this); // lll
@@ -554,12 +568,12 @@ Graphics Graphics_create_pdf (void *context, int resolution,
#else
if (my d_macView) {
[my d_macView lockFocus];
- my d_macGraphicsContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- NSCAssert(my d_macGraphicsContext, @"nil context");
- GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea*)my d_drawingArea -> d_widget;
+ my d_macGraphicsContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+ Melder_assert (my d_macGraphicsContext != NULL);
+ GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea *) my d_drawingArea -> d_widget;
CGContextTranslateCTM (my d_macGraphicsContext, 0, cocoaDrawingArea.bounds.size.height);
CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
- }
+ }
#endif
}
void GraphicsQuartz_exitDraw (GraphicsScreen me) {
@@ -570,7 +584,7 @@ Graphics Graphics_create_pdf (void *context, int resolution,
}
#else
if (my d_macView) {
- CGContextSynchronize (my d_macGraphicsContext);
+ CGContextSynchronize (my d_macGraphicsContext); // BUG: should not be needed
[my d_macView unlockFocus];
}
#endif
diff --git a/sys/Graphics_colour.cpp b/sys/Graphics_colour.cpp
index dfc5802..2f91c9b 100644
--- a/sys/Graphics_colour.cpp
+++ b/sys/Graphics_colour.cpp
@@ -1,6 +1,6 @@
/* Graphics_colour.cpp
*
- * Copyright (C) 1992-2011,2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,6 +32,7 @@
* pb 2010/06/05 set my colour in setColour
* pb 2011/01/15 Windows: inverted the colour in XOR mode
* pb 2011/03/17 C++
+ * pb 2013/08/27 Cocoa: trick: triple kCGBlendModeDifference approximates coloured XOR
*/
#include "GraphicsP.h"
@@ -74,7 +75,7 @@ const wchar_t * Graphics_Colour_name (Graphics_Colour colour) {
Graphics_Colour_equal (colour, Graphics_OLIVE) ? L"olive" :
Graphics_Colour_equal (colour, Graphics_SILVER) ? L"silver" :
Graphics_Colour_equal (colour, Graphics_GREY) ? L"grey" :
- colour. red == colour. green && colour. red == colour. blue ? Melder_fixed (colour. red, 6) :
+ //colour. red == colour. green && colour. red == colour. blue ? Melder_fixed (colour. red, 6) :
Melder_wcscat (L"{", Melder_fixed (colour. red, 6), L",", Melder_fixed (colour. green, 6), L",",
Melder_fixed (colour. blue, 6), L"}");
}
@@ -154,7 +155,7 @@ void Graphics_setGrey (Graphics me, double grey) {
if (my recording) { op (SET_GREY, 1); put (grey); }
}
-static void highlight (Graphics graphics, long x1DC, long x2DC, long y1DC, long y2DC) {
+static void highlight (Graphics graphics, long x1DC, long x2DC, long y1DC, long y2DC, int direction) {
if (graphics -> screen) {
GraphicsScreen me = static_cast <GraphicsScreen> (graphics);
#if cairo
@@ -167,47 +168,44 @@ static void highlight (Graphics graphics, long x1DC, long x2DC, long y1DC, long
gdk_draw_rectangle (my d_window, my d_gdkGraphicsContext, TRUE, x1DC, y2DC, width, height);
gdk_gc_set_rgb_fg_color (my d_gdkGraphicsContext, & black);
gdk_gc_set_function (my d_gdkGraphicsContext, GDK_COPY);
- gdk_flush (); //tryout 20110207
- //cairo_set_source_rgba (my d_cairoGraphicsContext, 1.0, 0.8, 0.8, 0.5);
- //cairo_set_operator (my d_cairoGraphicsContext, CAIRO_OPERATOR_BITXOR); // this blend mode doesn't exist
- //cairo_rectangle (my d_cairoGraphicsContext, x1DC, y2DC, width, height);
- //cairo_fill (my d_cairoGraphicsContext);
- //cairo_set_source_rgb (my d_cairoGraphicsContext, 0.0, 0.0, 0.0);
- //cairo_set_operator (my d_cairoGraphicsContext, CAIRO_OPERATOR_OVER);
+ gdk_flush ();
#elif cocoa
- int width = x2DC - x1DC, height = y1DC - y2DC;
- if (width <= 0 || height <= 0) return;
-
- GuiCocoaDrawingArea *drawingArea = (GuiCocoaDrawingArea*) my d_drawingArea -> d_widget;
-
- if (drawingArea) {
- [drawingArea lockFocus];
-
- CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState (context);
- NSCAssert(context, @"nil context");
- CGContextTranslateCTM (context, 0, drawingArea.bounds.size.height);
- CGContextScaleCTM (context, 1.0, -1.0);
-
- NSRect rect = NSMakeRect(x1DC, y2DC, width, height);
- CGContextSetBlendMode(context, kCGBlendModeDifference);
-
- // FIXME: Need user selection color
- CGContextSetRGBFillColor (context, .2, .0, .0, 1.0);
- CGContextFillRect (context, rect);
- CGContextRestoreGState (context);
-
- [drawingArea unlockFocus];
- }
-
+ int width = x2DC - x1DC, height = y1DC - y2DC;
+ if (width <= 0 || height <= 0) return;
+ GuiCocoaDrawingArea *drawingArea = (GuiCocoaDrawingArea *) my d_drawingArea -> d_widget;
+ if (drawingArea) {
+ [drawingArea lockFocus];
+ CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState (context);
+ NSCAssert (context, @"nil context");
+ CGContextTranslateCTM (context, 0, drawingArea. bounds. size. height);
+ CGContextScaleCTM (context, 1.0, -1.0);
+ NSRect rect = NSMakeRect (x1DC, y2DC, width, height);
+ CGContextSetBlendMode (context, kCGBlendModeDifference);
+ CGContextSetShouldAntialias (context, false);
+ NSColor *colour = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
+ double red = 0.5 + 0.5 * colour.redComponent, green = 0.5 + 0.5 * colour.greenComponent, blue = 0.5 + 0.5 * colour.blueComponent;
+ if (direction == 1) { // forward
+ CGContextSetRGBFillColor (context, 1.0 - red, 1.0 - green, 1.0 - blue, 1.0);
+ CGContextFillRect (context, rect);
+ } else { // backward
+ CGContextSetRGBFillColor (context, red, green, blue, 1.0);
+ CGContextFillRect (context, rect);
+ CGContextSetRGBFillColor (context, 1.0, 1.0, 1.0, 1.0);
+ CGContextFillRect (context, rect);
+ }
+ CGContextRestoreGState (context);
+ //CGContextSynchronize (context);
+ [drawingArea unlockFocus];
+ }
#elif mac
- Rect rect;
- if (my d_drawingArea) GuiMac_clipOn (my d_drawingArea -> d_widget);
- SetRect (& rect, x1DC, y2DC, x2DC, y1DC);
- SetPort (my d_macPort);
- LMSetHiliteMode (LMGetHiliteMode () & ~ 128L); /* see IM V-61 */
- InvertRect (& rect);
- if (my d_drawingArea) GuiMac_clipOff ();
+ Rect rect;
+ if (my d_drawingArea) GuiMac_clipOn (my d_drawingArea -> d_widget);
+ SetRect (& rect, x1DC, y2DC, x2DC, y1DC);
+ SetPort (my d_macPort);
+ LMSetHiliteMode (LMGetHiliteMode () & ~ 128L); // see IM V-61
+ InvertRect (& rect);
+ if (my d_drawingArea) GuiMac_clipOff ();
#elif win
static HBRUSH highlightBrush;
RECT rect;
@@ -226,92 +224,95 @@ static void highlight (Graphics graphics, long x1DC, long x2DC, long y1DC, long
}
void Graphics_highlight (Graphics me, double x1WC, double x2WC, double y1WC, double y2WC) {
- highlight (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC));
+ highlight (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC), 1);
if (my recording)
{ op (HIGHLIGHT, 4); put (x1WC); put (x2WC); put (y1WC); put (y2WC); }
}
void Graphics_unhighlight (Graphics me, double x1WC, double x2WC, double y1WC, double y2WC) {
- highlight (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC));
+ highlight (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC), 2);
if (my recording)
{ op (UNHIGHLIGHT, 4); put (x1WC); put (x2WC); put (y1WC); put (y2WC); }
}
static void highlight2 (Graphics graphics, long x1DC, long x2DC, long y1DC, long y2DC,
- long x1DC_inner, long x2DC_inner, long y1DC_inner, long y2DC_inner)
+ long x1DC_inner, long x2DC_inner, long y1DC_inner, long y2DC_inner, int direction)
{
if (graphics -> screen) {
GraphicsScreen me = static_cast <GraphicsScreen> (graphics);
#if cairo
if (my d_cairoGraphicsContext == NULL) return;
- cairo_save (my d_cairoGraphicsContext);
- cairo_set_source_rgba (my d_cairoGraphicsContext, 1.0, 0.8, 0.8, 0.5);
- //cairo_set_operator (my d_cairoGraphicsContext, CAIRO_OPERATOR_XOR);
- cairo_rectangle (my d_cairoGraphicsContext, x1DC, y2DC, x2DC - x1DC, y2DC_inner - y2DC); // upper
- cairo_rectangle (my d_cairoGraphicsContext, x1DC, y2DC_inner, x1DC_inner - x1DC, y1DC_inner - y2DC_inner); // left part
- cairo_rectangle (my d_cairoGraphicsContext, x2DC_inner, y2DC_inner, x2DC - x2DC_inner, y1DC_inner - y2DC_inner); // right part
- cairo_rectangle (my d_cairoGraphicsContext, x1DC, y1DC_inner, x2DC - x1DC, y1DC - y1DC_inner); // lower
- cairo_fill (my d_cairoGraphicsContext);
- cairo_restore (my d_cairoGraphicsContext);
+ int width = x2DC - x1DC, height = y1DC - y2DC;
+ if (width <= 0 || height <= 0) return;
+ gdk_gc_set_function (my d_gdkGraphicsContext, GDK_XOR);
+ GdkColor pinkXorWhite = { 0, 0x0000, 0x4000, 0x4000 }, black = { 0, 0x0000, 0x0000, 0x0000 };
+ gdk_gc_set_rgb_fg_color (my d_gdkGraphicsContext, & pinkXorWhite);
+ gdk_draw_rectangle (my d_window, my d_gdkGraphicsContext, TRUE, x1DC, y2DC, x2DC - x1DC, y2DC_inner - y2DC); // upper
+ gdk_draw_rectangle (my d_window, my d_gdkGraphicsContext, TRUE, x1DC, y2DC_inner, x1DC_inner - x1DC, y1DC_inner - y2DC_inner); // left part
+ gdk_draw_rectangle (my d_window, my d_gdkGraphicsContext, TRUE, x2DC_inner, y2DC_inner, x2DC - x2DC_inner, y1DC_inner - y2DC_inner); // right part
+ gdk_draw_rectangle (my d_window, my d_gdkGraphicsContext, TRUE, x1DC, y1DC_inner, x2DC - x1DC, y1DC - y1DC_inner); // lower
+ gdk_gc_set_rgb_fg_color (my d_gdkGraphicsContext, & black);
+ gdk_gc_set_function (my d_gdkGraphicsContext, GDK_COPY);
+ gdk_flush ();
#elif cocoa
-
- NSView *view = (NSView*)my d_drawingArea -> d_widget;
- if (view) {
- [view lockFocus];
+ GuiCocoaDrawingArea *drawingArea = (GuiCocoaDrawingArea*) my d_drawingArea -> d_widget;
+ if (drawingArea) {
+ [drawingArea lockFocus];
- my d_macGraphicsContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState (my d_macGraphicsContext);
-
- NSCAssert(my d_macGraphicsContext, @"nil context");
- CGContextTranslateCTM (my d_macGraphicsContext, 0, view.bounds.size.height);
- CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
+ my d_macGraphicsContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState (my d_macGraphicsContext);
- CGContextSetBlendMode(my d_macGraphicsContext, kCGBlendModeDifference);
+ NSCAssert (my d_macGraphicsContext, @"nil context");
+ CGContextTranslateCTM (my d_macGraphicsContext, 0, drawingArea. bounds. size. height);
+ CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
- // CGContextSetRGBFillColor (context, 2.0, 2.0, 2.0, 2.0);
- // FIXME: Need user selection color
- CGContextSetRGBFillColor (my d_macGraphicsContext, .2, .0, .0, 1.0);
-
- NSRect upperRect = NSMakeRect(x1DC, y2DC, x2DC - x1DC, y2DC_inner - y2DC);
- NSRect leftRect = NSMakeRect(x1DC, y2DC_inner, x1DC_inner - x1DC, y1DC_inner - y2DC_inner);
- NSRect rightRect = NSMakeRect(x2DC_inner, y2DC_inner, x2DC - x2DC_inner, y1DC_inner - y2DC_inner);
- NSRect lowerRect = NSMakeRect(x1DC, y1DC_inner, x2DC - x1DC, y1DC - y1DC_inner);
- NSRect unionRect = NSUnionRect(upperRect, leftRect);
- unionRect = NSUnionRect(unionRect, rightRect);
- unionRect = NSUnionRect(unionRect, lowerRect);
-
- CGContextFillRect (my d_macGraphicsContext, upperRect);
- CGContextFillRect (my d_macGraphicsContext, leftRect);
- CGContextFillRect (my d_macGraphicsContext, rightRect);
- CGContextFillRect (my d_macGraphicsContext, lowerRect);
-
- CGContextRestoreGState (my d_macGraphicsContext);
- CGContextSynchronize ( my d_macGraphicsContext);
- [view unlockFocus];
-
- // See comments in gui_drawingarea_cb_click
- // [view setNeedsDisplayInRect:unionRect];
-// [[view window] flushWindow];
-
- }
+ NSRect upperRect = NSMakeRect (x1DC, y2DC, x2DC - x1DC, y2DC_inner - y2DC);
+ NSRect leftRect = NSMakeRect (x1DC, y2DC_inner, x1DC_inner - x1DC, y1DC_inner - y2DC_inner);
+ NSRect rightRect = NSMakeRect (x2DC_inner, y2DC_inner, x2DC - x2DC_inner, y1DC_inner - y2DC_inner);
+ NSRect lowerRect = NSMakeRect (x1DC, y1DC_inner, x2DC - x1DC, y1DC - y1DC_inner);
+ CGContextSetBlendMode (my d_macGraphicsContext, kCGBlendModeDifference);
+ NSColor *colour = [[NSColor selectedTextBackgroundColor] colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
+ double red = 0.5 + 0.5 * colour.redComponent, green = 0.5 + 0.5 * colour.greenComponent, blue = 0.5 + 0.5 * colour.blueComponent;
+ if (direction == 1) {
+ CGContextSetRGBFillColor (my d_macGraphicsContext, 1.0 - red, 1.0 - green, 1.0 - blue, 1.0);
+ CGContextFillRect (my d_macGraphicsContext, upperRect);
+ CGContextFillRect (my d_macGraphicsContext, leftRect);
+ CGContextFillRect (my d_macGraphicsContext, rightRect);
+ CGContextFillRect (my d_macGraphicsContext, lowerRect);
+ } else {
+ CGContextSetRGBFillColor (my d_macGraphicsContext, red, green, blue, 1.0);
+ CGContextFillRect (my d_macGraphicsContext, upperRect);
+ CGContextFillRect (my d_macGraphicsContext, leftRect);
+ CGContextFillRect (my d_macGraphicsContext, rightRect);
+ CGContextFillRect (my d_macGraphicsContext, lowerRect);
+ CGContextSetRGBFillColor (my d_macGraphicsContext, 1.0, 1.0, 1.0, 1.0);
+ CGContextFillRect (my d_macGraphicsContext, upperRect);
+ CGContextFillRect (my d_macGraphicsContext, leftRect);
+ CGContextFillRect (my d_macGraphicsContext, rightRect);
+ CGContextFillRect (my d_macGraphicsContext, lowerRect);
+ }
+ CGContextRestoreGState (my d_macGraphicsContext);
+ //CGContextSynchronize ( my d_macGraphicsContext); // needed?
+ [drawingArea unlockFocus];
+ }
#elif mac
- Rect rect;
- if (my d_drawingArea) GuiMac_clipOn (my d_drawingArea -> d_widget);
- SetPort (my d_macPort);
- LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
- SetRect (& rect, x1DC, y2DC, x2DC, y2DC_inner);
- InvertRect (& rect);
- LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
- SetRect (& rect, x1DC, y2DC_inner, x1DC_inner, y1DC_inner);
- InvertRect (& rect);
- LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
- SetRect (& rect, x2DC_inner, y2DC_inner, x2DC, y1DC_inner);
- InvertRect (& rect);
- LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
- SetRect (& rect, x1DC, y1DC_inner, x2DC, y1DC);
- InvertRect (& rect);
- if (my d_drawingArea) GuiMac_clipOff ();
+ Rect rect;
+ if (my d_drawingArea) GuiMac_clipOn (my d_drawingArea -> d_widget);
+ SetPort (my d_macPort);
+ LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
+ SetRect (& rect, x1DC, y2DC, x2DC, y2DC_inner);
+ InvertRect (& rect);
+ LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
+ SetRect (& rect, x1DC, y2DC_inner, x1DC_inner, y1DC_inner);
+ InvertRect (& rect);
+ LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
+ SetRect (& rect, x2DC_inner, y2DC_inner, x2DC, y1DC_inner);
+ InvertRect (& rect);
+ LMSetHiliteMode (LMGetHiliteMode () & ~ 128L);
+ SetRect (& rect, x1DC, y1DC_inner, x2DC, y1DC);
+ InvertRect (& rect);
+ if (my d_drawingArea) GuiMac_clipOff ();
#elif win
static HBRUSH highlightBrush;
if (! highlightBrush)
@@ -333,7 +334,7 @@ static void highlight2 (Graphics graphics, long x1DC, long x2DC, long y1DC, long
void Graphics_highlight2 (Graphics me, double x1WC, double x2WC, double y1WC, double y2WC,
double x1WC_inner, double x2WC_inner, double y1WC_inner, double y2WC_inner)
{
- highlight2 (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC), wdx (x1WC_inner), wdx (x2WC_inner), wdy (y1WC_inner), wdy (y2WC_inner));
+ highlight2 (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC), wdx (x1WC_inner), wdx (x2WC_inner), wdy (y1WC_inner), wdy (y2WC_inner), 1);
if (my recording)
{ op (HIGHLIGHT2, 8); put (x1WC); put (x2WC); put (y1WC); put (y2WC); put (x1WC_inner); put (x2WC_inner); put (y1WC_inner); put (y2WC_inner); }
}
@@ -341,9 +342,7 @@ void Graphics_highlight2 (Graphics me, double x1WC, double x2WC, double y1WC, do
void Graphics_unhighlight2 (Graphics me, double x1WC, double x2WC, double y1WC, double y2WC,
double x1WC_inner, double x2WC_inner, double y1WC_inner, double y2WC_inner)
{
- #if ! cairo
- highlight2 (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC), wdx (x1WC_inner), wdx (x2WC_inner), wdy (y1WC_inner), wdy (y2WC_inner));
- #endif
+ highlight2 (me, wdx (x1WC), wdx (x2WC), wdy (y1WC), wdy (y2WC), wdx (x1WC_inner), wdx (x2WC_inner), wdy (y1WC_inner), wdy (y2WC_inner), 2);
if (my recording)
{ op (UNHIGHLIGHT2, 8); put (x1WC); put (x2WC); put (y1WC); put (y2WC); put (x1WC_inner); put (x2WC_inner); put (y1WC_inner); put (y2WC_inner); }
}
@@ -367,6 +366,7 @@ void Graphics_xorOn (Graphics graphics, Graphics_Colour colour) {
colour. green = ((uint16_t) (colour. green * 65535.0) ^ 0xFFFF) / 65535.0;
colour. blue = ((uint16_t) (colour. blue * 65535.0) ^ 0xFFFF) / 65535.0;
_Graphics_setColour (me, colour);
+ #elif cocoa
#elif mac
//CGContextSetBlendMode (my macGraphicsContext, kCGBlendModeDifference);
#endif
@@ -384,10 +384,12 @@ void Graphics_xorOff (Graphics graphics) {
gdk_gc_set_function (my d_gdkGraphicsContext, GDK_COPY);
//cairo_set_source_rgba (my d_cairoGraphicsContext, 0.0, 0.0, 0.0, 1.0);
//cairo_set_operator (my d_cairoGraphicsContext, CAIRO_OPERATOR_OVER);
- gdk_flush ();
+ gdk_flush (); // to undraw the last drawing
#elif win
SetROP2 (my d_gdiGraphicsContext, R2_COPYPEN);
_Graphics_setColour (me, my colour);
+ #elif cocoa
+ Graphics_flushWs (graphics); // to undraw the last drawing
#elif mac
//CGContextSetBlendMode (my macGraphicsContext, kCGBlendModeNormal);
#endif
diff --git a/sys/Graphics_linesAndAreas.cpp b/sys/Graphics_linesAndAreas.cpp
index 8b59fa8..89cbfec 100644
--- a/sys/Graphics_linesAndAreas.cpp
+++ b/sys/Graphics_linesAndAreas.cpp
@@ -1,6 +1,6 @@
/* Graphics_linesAndAreas.cpp
*
- * Copyright (C) 1992-2011,2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -148,7 +148,6 @@ static void psRevertLine (GraphicsPostscript me) {
CGContextSetBlendMode (my d_macGraphicsContext, kCGBlendModeNormal);
CGContextSetRGBFillColor (my d_macGraphicsContext, my d_macColour.red / 65536.0, my d_macColour.green / 65536.0, my d_macColour.blue / 65536.0, 1.0);
}
- static RGBColor theBlackColour = { 0, 0, 0 };
#endif
/* First level. */
@@ -605,100 +604,46 @@ void structGraphicsScreen :: v_button (long x1DC, long x2DC, long y1DC, long y2D
}
}
cairo_restore (d_cairoGraphicsContext);
- #elif cocoa
-#define SetRect(r, left, top, right, bottom) r.origin.x = left; r.origin.y = top; r.size.width = right - left; r.size.height = bottom - top;
-
- NSView *view = d_macView;
- NSCAssert(view, @"nil view");
- [view lockFocus];
- d_macGraphicsContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea*) d_drawingArea -> d_widget;
- CGContextSaveGState (d_macGraphicsContext);
- NSCAssert(d_macGraphicsContext, @"nil context");
-
- CGContextTranslateCTM (d_macGraphicsContext, 0, cocoaDrawingArea.bounds.size.height);
- CGContextScaleCTM (d_macGraphicsContext, 1.0, -1.0);
-
- CGRect rect;
- int width, height;
- width = x2DC - x1DC, height = y1DC - y2DC;
- if (width <= 0 || height <= 0) return;
-
- CGContextSetRGBStrokeColor(d_macGraphicsContext, 0.1 , 0.1 , 0.1 , 1.0);
- SetRect (rect, x1DC - 1, y2DC - 1, x2DC, y1DC);
-
-
-
- if (width > 2 && height > 2) {
-
- CGContextSetRGBStrokeColor(d_macGraphicsContext, 0.3 , 0.3 , 0.3 , 1.0);
-
- CGContextMoveToPoint(d_macGraphicsContext, x1DC, y1DC - 2);
- CGContextAddLineToPoint(d_macGraphicsContext, x2DC - 2, y1DC - 2);
-
- CGContextMoveToPoint(d_macGraphicsContext, x2DC - 2, y1DC - 2);
- CGContextAddLineToPoint(d_macGraphicsContext, x2DC - 2, y2DC);
-
-
- CGContextSetRGBStrokeColor(d_macGraphicsContext, 1.0 , 1.0 , 1.0 , 1.0);
-
- CGContextMoveToPoint(d_macGraphicsContext, x1DC, y1DC - 2);
- CGContextAddLineToPoint(d_macGraphicsContext, x1DC, y2DC);
-
-
- CGContextMoveToPoint(d_macGraphicsContext, x1DC, y2DC);
- CGContextAddLineToPoint(d_macGraphicsContext, x2DC - 2, y2DC);
-
- if (width > 4 && height > 4) {
-
- CGContextSetRGBStrokeColor(d_macGraphicsContext, 0.65 , 0.65 , 0.65 , 1.0);
-
-
- SetRect ( rect, x1DC + 1, y2DC + 1, x2DC - 2, y1DC - 2);
- CGContextAddRect(d_macGraphicsContext, rect);
-
- CGContextSetLineWidth(d_macGraphicsContext, 2.0);
- CGContextStrokePath(d_macGraphicsContext);
-
- }
- }
-
- CGContextSetRGBStrokeColor(d_macGraphicsContext, 0.65 , 0.65 , 0.65 , 1.0);
- CGContextSynchronize ( d_macGraphicsContext);
-
- CGContextFlush(d_macGraphicsContext);
- CGContextRestoreGState (d_macGraphicsContext);
-
- [ d_macView unlockFocus];
-
-
#elif mac
- int width, height;
- Rect rect;
- RGBColor rgb;
- width = x2DC - x1DC, height = y1DC - y2DC;
+ int width = x2DC - x1DC, height = y1DC - y2DC;
if (width <= 0 || height <= 0) return;
- if (d_drawingArea) GuiMac_clipOn (d_drawingArea -> d_widget);
- SetPort (d_macPort);
- /* Dark grey. */
- rgb. red = rgb. green = rgb. blue = (int) (unsigned int) (0.1 * 65535.0); RGBForeColor (& rgb);
- SetRect (& rect, x1DC - 1, y2DC - 1, x2DC, y1DC);
- FrameRect (& rect);
+
+ #define SetRect(r, left, top, right, bottom) r.origin.x = left; r.origin.y = top; r.size.width = right - left; r.size.height = bottom - top;
+
+ GraphicsQuartz_initDraw (this);
+ CGContextSetLineWidth (d_macGraphicsContext, 1.0);
+ CGContextSetAllowsAntialiasing (d_macGraphicsContext, false); // because we want to draw by pixel
+ CGFloat gray = 0.1;
+ CGContextSetRGBStrokeColor (d_macGraphicsContext, gray, gray, gray, 1.0);
+ CGRect rect;
+ SetRect (rect, x1DC - 1, y2DC, x2DC + 1, y1DC);
+ CGContextAddRect (d_macGraphicsContext, rect);
+ CGContextStrokePath (d_macGraphicsContext);
if (width > 2 && height > 2) {
- rgb. red = rgb. green = rgb. blue = (int) (unsigned int) (0.3 * 65535.0); RGBForeColor (& rgb);
- MoveTo (x1DC, y1DC - 2); LineTo (x2DC - 2, y1DC - 2);
- MoveTo (x2DC - 2, y1DC - 2); LineTo (x2DC - 2, y2DC);
- rgb. red = rgb. green = rgb. blue = (int) (unsigned int) (1.0 * 65535.0); RGBForeColor (& rgb);
- MoveTo (x1DC, y1DC - 2); LineTo (x1DC, y2DC);
- MoveTo (x1DC, y2DC); LineTo (x2DC - 2, y2DC);
+ gray = 0.3;
+ CGContextSetRGBStrokeColor (d_macGraphicsContext, gray, gray, gray, 1.0);
+ CGContextMoveToPoint (d_macGraphicsContext, x1DC, y1DC - 1);
+ CGContextAddLineToPoint (d_macGraphicsContext, x2DC - 2, y1DC - 1);
+ CGContextMoveToPoint (d_macGraphicsContext, x2DC - 2, y1DC - 1);
+ CGContextAddLineToPoint (d_macGraphicsContext, x2DC - 2, y2DC);
+ CGContextStrokePath (d_macGraphicsContext);
+ gray = 1.0;
+ CGContextSetRGBStrokeColor (d_macGraphicsContext, gray, gray, gray, 1.0);
+ CGContextMoveToPoint (d_macGraphicsContext, x1DC, y1DC - 1);
+ CGContextAddLineToPoint (d_macGraphicsContext, x1DC, y2DC + 1);
+ CGContextMoveToPoint (d_macGraphicsContext, x1DC, y2DC + 1);
+ CGContextAddLineToPoint (d_macGraphicsContext, x2DC - 2, y2DC + 1);
+ CGContextStrokePath (d_macGraphicsContext);
if (width > 4 && height > 4) {
- rgb. red = rgb. green = rgb. blue = (int) (unsigned int) (0.65 * 65535.0); RGBForeColor (& rgb);
- SetRect (& rect, x1DC + 1, y2DC + 1, x2DC - 2, y1DC - 2);
- PaintRect (& rect);
- }
- }
- RGBForeColor (& theBlackColour);
- if (d_drawingArea) GuiMac_clipOff ();
+ gray = 0.65;
+ CGContextSetRGBFillColor (d_macGraphicsContext, gray, gray, gray, 1.0);
+ SetRect (rect, x1DC + 1, y2DC + 1, x2DC - 4, y1DC - 4);
+ CGContextFillRect (d_macGraphicsContext, rect);
+ }
+ }
+ CGContextSetAllowsAntialiasing (d_macGraphicsContext, true);
+ CGContextSetLineDash (d_macGraphicsContext, 0, NULL, 0);
+ GraphicsQuartz_exitDraw (this);
#elif win
RECT rect;
rect. left = x1DC, rect. right = x2DC, rect. top = y2DC, rect. bottom = y1DC;
@@ -708,7 +653,6 @@ void structGraphicsScreen :: v_button (long x1DC, long x2DC, long y1DC, long y2D
Rectangle (d_gdiGraphicsContext, x1DC + 1, y2DC + 1, x2DC - 1, y1DC - 1);
SelectPen (d_gdiGraphicsContext, GetStockPen (BLACK_PEN));
SelectBrush (d_gdiGraphicsContext, GetStockBrush (NULL_BRUSH));
-
#endif
}
diff --git a/sys/Graphics_mouse.cpp b/sys/Graphics_mouse.cpp
index 64e809f..2223f04 100644
--- a/sys/Graphics_mouse.cpp
+++ b/sys/Graphics_mouse.cpp
@@ -1,6 +1,6 @@
/* Graphics_mouse.cpp
*
- * Copyright (C) 1992-2011 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2011,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,10 +20,6 @@
#include "GraphicsP.h"
#include "Gui.h"
-#if cairo
- static bool theMouseDown = true;
-#endif
-
/*
* Graphics_mouseStillDown () can only be used in a loop
* if Graphics_getMouseLocation () is called in that same loop.
@@ -32,11 +28,23 @@
bool structGraphicsScreen :: v_mouseStillDown () {
#if cairo
- if (theMouseDown) return true;
- else { theMouseDown = true; return false; }
+ Graphics_flushWs (this);
+ GdkEvent *gevent = gdk_display_get_event (d_display);
+ if (! gevent) return true;
+ int gdkEventType = gevent -> type;
+ gdk_event_free (gevent);
+ return gdkEventType != GDK_BUTTON_RELEASE;
#elif cocoa
- NSUInteger buttons = [NSEvent pressedMouseButtons];
- return buttons;
+ Graphics_flushWs (this);
+ NSEvent *nsEvent = [[d_macView window]
+ nextEventMatchingMask: NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSKeyDownMask
+ untilDate: [NSDate distantFuture]
+ inMode: NSEventTrackingRunLoopMode
+ dequeue: YES
+ ];
+ NSUInteger nsEventType = [nsEvent type];
+ if (nsEventType == NSKeyDown) NSBeep ();
+ return nsEventType != NSLeftMouseUp;
#elif win
return motif_win_mouseStillDown ();
#elif mac
@@ -50,40 +58,23 @@ bool Graphics_mouseStillDown (Graphics me) {
void structGraphicsScreen :: v_getMouseLocation (double *xWC, double *yWC) {
#if cairo
- GdkEvent *gevent = gdk_display_get_event (d_display);
- if (gevent != NULL) {
- if (gevent -> type == GDK_BUTTON_RELEASE) {
- theMouseDown = false;
- }
- gdk_event_free (gevent);
- }
gint xDC, yDC;
gdk_window_get_pointer (d_window, & xDC, & yDC, NULL);
Graphics_DCtoWC (this, xDC, yDC, xWC, yWC);
#elif cocoa
-
- // get mouse position in Window
- NSPoint mouseLoc = [[d_macView window] mouseLocationOutsideOfEventStream];
- mouseLoc = [d_macView convertPoint:mouseLoc fromView:nil];
- mouseLoc.y = d_macView.bounds.size.height - mouseLoc.y;
- Graphics_DCtoWC (this, mouseLoc.x, mouseLoc.y, xWC, yWC);
-
+ NSPoint mouseLoc = [[d_macView window] mouseLocationOutsideOfEventStream];
+ mouseLoc = [d_macView convertPoint: mouseLoc fromView: nil];
+ mouseLoc. y = d_macView. bounds. size. height - mouseLoc. y;
+ Graphics_DCtoWC (this, mouseLoc. x, mouseLoc. y, xWC, yWC);
#elif win
POINT pos;
- if (! GetCursorPos (& pos)) { Melder_warning (L"Cannot get cursor position."); return; }
+ if (! GetCursorPos (& pos)) { Melder_warning (L"Cannot find the location of the mouse."); return; }
ScreenToClient (d_winWindow, & pos);
Graphics_DCtoWC (this, pos. x, pos. y, xWC, yWC);
#elif mac
- if (HIGetMousePosition != NULL && false) { // AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
- //Melder_casual ("HIGetMousePosition exists");
- HIPoint mouseLoc;
- HIGetMousePosition (kHICoordSpaceWindow, GetWindowFromPort (d_macPort), & mouseLoc);
- Graphics_DCtoWC (this, mouseLoc. x, mouseLoc. y, xWC, yWC);
- } else {
- Point mouseLoc;
- GetMouse (& mouseLoc); // AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5
- Graphics_DCtoWC (this, mouseLoc. h, mouseLoc. v, xWC, yWC);
- }
+ Point mouseLoc;
+ GetMouse (& mouseLoc);
+ Graphics_DCtoWC (this, mouseLoc. h, mouseLoc. v, xWC, yWC);
#endif
}
diff --git a/sys/Graphics_text.cpp b/sys/Graphics_text.cpp
index b0fd135..59173b9 100644
--- a/sys/Graphics_text.cpp
+++ b/sys/Graphics_text.cpp
@@ -1,6 +1,6 @@
/* Graphics_text.cpp
*
- * Copyright (C) 1992-2011,2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -90,8 +90,7 @@ extern const char * ipaSerifRegular24 [1 + 255-33+1 + 1] [24 + 1];
#include "macport_off.h"
static ATSFontRef theTimesAtsuiFont, theHelveticaAtsuiFont, theCourierAtsuiFont, theSymbolAtsuiFont,
thePalatinoAtsuiFont, theIpaTimesAtsuiFont, theIpaPalatinoAtsuiFont, theZapfDingbatsAtsuiFont, theArabicAtsuiFont;
- static CTFontRef theTimesCoreTextFont, theHelveticaCoreTextFont, theCourierCoreTextFont, theSymbolCoreTextFont,
- thePalatinoCoreTextFont, theIpaTimesCoreTextFont, theIpaPalatinoCoreTextFont, theZapfDingbatsCoreTextFont, theArabicCoreTextFont;
+ static CTFontRef theScreenFonts [1 + kGraphics_font_DINGBATS] [1 + Graphics_BOLD_ITALIC];
static RGBColor theWhiteColour = { 0xFFFF, 0xFFFF, 0xFFFF }, theBlueColour = { 0, 0, 0xFFFF };
#endif
@@ -270,77 +269,115 @@ static void charSize (I, _Graphics_widechar *lc) {
lc -> size = size; // 0..4 instead of 10..24
lc -> style = style; // without Graphics_CODE
#elif cocoa
-
- int normalSize = my fontSize * my resolution / 72.0;
- lc -> size = lc -> size < 100 ? (3 * normalSize + 2) / 4 : /*lc -> size > 100 ? 1.2 * normalSize :*/ normalSize;
+ /*
+ * Determine the font family.
+ */
+ Longchar_Info info = Longchar_getInfoFromNative (lc -> kar);
+ int font =
+ info -> alphabet == Longchar_SYMBOL ? kGraphics_font_SYMBOL :
+ info -> alphabet == Longchar_PHONETIC ?
+ ( my font == kGraphics_font_TIMES && lc -> style == 0 ? kGraphics_font_IPATIMES : kGraphics_font_IPAPALATINO ) :
+ lc -> kar == '/' ? kGraphics_font_PALATINO : // override Courier
+ info -> alphabet == Longchar_DINGBATS ? kGraphics_font_DINGBATS :
+ lc -> font.integer == kGraphics_font_COURIER ? kGraphics_font_COURIER :
+ my font == kGraphics_font_TIMES ? ( lc -> style == 0 ? kGraphics_font_IPATIMES : kGraphics_font_TIMES ) :
+ my font == kGraphics_font_HELVETICA ? kGraphics_font_HELVETICA :
+ my font == kGraphics_font_PALATINO ? kGraphics_font_IPAPALATINO :
+ my font; // why not lc -> font.integer?
+ Melder_assert (font >= 0 && font <= kGraphics_font_DINGBATS);
lc -> font.string = NULL; // this erases font.integer!
+
+ /*
+ * Determine the style.
+ */
+ int style = lc -> style;
+ Melder_assert (style >= 0 && style <= Graphics_BOLD_ITALIC);
+
+ /*
+ * Determine the font-style combination.
+ */
+ CTFontRef ctFont = theScreenFonts [font] [style];
+ if (ctFont == NULL) {
+ CTFontSymbolicTraits ctStyle = ( style & Graphics_BOLD ? kCTFontBoldTrait : 0 ) | ( lc -> style & Graphics_ITALIC ? kCTFontItalicTrait : 0 );
+ NSMutableDictionary *styleDict = [[NSMutableDictionary alloc] initWithCapacity: 1];
+ [styleDict setObject: [NSNumber numberWithUnsignedInt: ctStyle] forKey: (id) kCTFontSymbolicTrait];
+ NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithCapacity: 2];
+ [attributes setObject: styleDict forKey: (id) kCTFontTraitsAttribute];
+ switch (font) {
+ case kGraphics_font_TIMES: { [attributes setObject: @"Times" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_HELVETICA: { [attributes setObject: @"Arial" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_COURIER: { [attributes setObject: @"Courier New" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_PALATINO: { [attributes setObject: @"Palatino" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_SYMBOL: { [attributes setObject: @"Symbol" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_IPATIMES: { [attributes setObject: @"Doulos SIL" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_IPAPALATINO: { [attributes setObject: @"Charis SIL" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_DINGBATS: { [attributes setObject: @"Zapf Dingbats" forKey: (id) kCTFontNameAttribute]; } break;
+ }
+ CTFontDescriptorRef ctFontDescriptor = CTFontDescriptorCreateWithAttributes ((CFMutableDictionaryRef) attributes);
+ [styleDict release];
+ [attributes release];
+ ctFont = CTFontCreateWithFontDescriptor (ctFontDescriptor, 100.0, NULL);
+ CFRelease (ctFontDescriptor);
+ theScreenFonts [font] [style] = ctFont;
+ }
+
+ int normalSize = my fontSize * my resolution / 72.0;
+ lc -> size = lc -> size < 100 ? (3 * normalSize + 2) / 4 : normalSize;
+
+ uint16_t codes16 [2];
+ int nchars = 1;
+ if (lc -> kar > 0xFFFF) {
+ MelderUtf32 kar = lc -> kar - 0x10000;
+ codes16 [0] = 0xD800 + (kar >> 10);
+ codes16 [1] = 0xDC00 + (kar & 0x3FF);
+ nchars = 2;
+ } else {
+ codes16 [0] = lc -> kar;
+ }
+ NSString *s = [[NSString alloc]
+ initWithBytes: codes16
+ length: nchars * 2
+ encoding: NSUTF16LittleEndianStringEncoding // BUG: should be NSUTF16NativeStringEncoding, except that that doesn't exist
+ ];
+ //CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+ //NSCAssert (context, @"nil context");
+
+ //[NSGraphicsContext setCurrentContext: my d_macGraphicsContext];
+ //Melder_assert (my d_macGraphicsContext != NULL);
+ //Melder_assert (context == my d_macGraphicsContext);
+ //CGContextSaveGState (context);
+ //CGContextSetTextMatrix (context, CGAffineTransformIdentity); // this could set the "current context" for CoreText
+
+ CFRange textRange = CFRangeMake (0, [s length]);
-
- NSString *s =[[NSString alloc] initWithBytes: &lc -> kar length:4 encoding:NSUTF16LittleEndianStringEncoding];
- CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- NSCAssert(context, @"nil context");
-
- CGContextSaveGState(context);
- CGContextSetTextMatrix(context, CGAffineTransformIdentity);
- Boolean boldStyle = (lc -> style & Graphics_BOLD) != 0;
- Boolean italicStyle = (lc -> style & Graphics_ITALIC) != 0;
-
- CTFontSymbolicTraits theSymbolicTraits = 0;
- if (boldStyle)
- theSymbolicTraits |= kCTFontBoldTrait;
- if (italicStyle)
- theSymbolicTraits |= kCTFontItalicTrait;
-
- NSMutableDictionary *traitsDict = [NSMutableDictionary dictionary];
- [traitsDict setObject:[NSNumber numberWithUnsignedInt:theSymbolicTraits] forKey:(id)kCTFontSymbolicTrait];
- NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
- if (my font == kGraphics_font_TIMES) {
- [attributes setObject:@"Times" forKey:(id)kCTFontNameAttribute];
- } else if (my font == kGraphics_font_HELVETICA) {
- [attributes setObject:@"Helvetica" forKey:(id)kCTFontNameAttribute];
- } else if (my font == kGraphics_font_COURIER) {
- [attributes setObject:@"Courier" forKey:(id)kCTFontNameAttribute];
- }
-
- [attributes setObject:traitsDict forKey:(id)kCTFontTraitsAttribute];
- CTFontDescriptorRef fontDesc = CTFontDescriptorCreateWithAttributes(( CFDictionaryRef)attributes);
- CTFontRef ctFont = CTFontCreateWithFontDescriptor(fontDesc, lc -> size, NULL);
- CTTextAlignment textAlignment = kCTNaturalTextAlignment;
- CTParagraphStyleSetting paragraphSettings[1] = { {kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &textAlignment} };
-
- CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
- CFRange textRange = CFRangeMake(0, [s length]);
-
- CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, [s length]);
- CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) s);
- CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont);
- CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);
- RGBColor *macColor = lc -> link ? & theBlueColour : my duringXor ? & theWhiteColour : & my d_macColour;
- CGColorRef color = CGColorCreateGenericRGB(macColor->red / 65536.0, macColor->green / 65536.0, macColor->blue / 65536.0, 1.0);
- CFAttributedStringSetAttribute(string, textRange, kCTForegroundColorAttributeName, color);
+ CFMutableAttributedStringRef string = CFAttributedStringCreateMutable (kCFAllocatorDefault, [s length]);
+ CFAttributedStringReplaceString (string, CFRangeMake (0, 0), (CFStringRef) s);
+ CFAttributedStringSetAttribute (string, textRange, kCTFontAttributeName, ctFont);
/*
* Measure.
*/
// Create a path to render text in
- CGMutablePathRef path = CGPathCreateMutable();
- NSRect measureRect = NSMakeRect(0, 0, CGFLOAT_MAX, CGFLOAT_MAX);
- CGPathAddRect(path, NULL, measureRect );
+ CGMutablePathRef path = CGPathCreateMutable ();
+ NSRect measureRect = NSMakeRect (0, 0, CGFLOAT_MAX, CGFLOAT_MAX);
+ CGPathAddRect (path, NULL, (CGRect) measureRect);
- CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(( CFAttributedStringRef)string);
- CFRange fitRange;
- CGSize targetSize = CGSizeMake(lc -> width, CGFLOAT_MAX);
- CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, targetSize, &fitRange);
- CFRelease(framesetter);
- CFRelease(string);
+ CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString ((CFAttributedStringRef) string);
+ CFRange fitRange;
+ CGSize targetSize = CGSizeMake (lc -> width, CGFLOAT_MAX);
+ CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints (framesetter, textRange, NULL, targetSize, & fitRange);
+ CFRelease (framesetter);
+ CFRelease (string);
[s release];
- CGContextRestoreGState(context);
-
- lc -> width = frameSize.width ;
+ //CGContextRestoreGState (context);
+
+ bool isDiacritic = info -> ps.times == 0;
+ lc -> width = isDiacritic ? 0.0 : frameSize.width * lc -> size / 100.0;
+ if (font == kGraphics_font_IPATIMES || font == kGraphics_font_IPAPALATINO) lc -> baseline -= 6; // BUG: not good enough
lc -> baseline *= my fontSize * 0.01;
lc -> code = lc -> kar;
-
+ lc -> font.integer = font;
#elif mac
Longchar_Info info = Longchar_getInfoFromNative (lc -> kar);
int normalSize = my fontSize * my resolution / 72.0;
@@ -644,103 +681,183 @@ static void charDraw (I, int xDC, int yDC, _Graphics_widechar *lc,
int font = lc -> font.integer;
int needBitmappedIPA = 0;
#elif cocoa
+ /*
+ * Determine the font family.
+ */
+ int font = lc -> font.integer; // the font of the first character
+
+ /*
+ * Determine the style.
+ */
+ int style = lc -> style; // the style of the first character
+
+ /*
+ * Determine the font-style combination.
+ */
+ CTFontSymbolicTraits ctStyle = ( style & Graphics_BOLD ? kCTFontBoldTrait : 0 ) | ( lc -> style & Graphics_ITALIC ? kCTFontItalicTrait : 0 );
+ #if 1
+ CFStringRef key = kCTFontSymbolicTrait;
+ CFNumberRef value = CFNumberCreate (NULL, kCFNumberIntType, & ctStyle);
+ CFIndex numberOfValues = 1;
+ CFDictionaryRef styleDict = CFDictionaryCreate (NULL, (const void **) & key, (const void **) & value, numberOfValues,
+ & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
+ CFRelease (value);
+ CFStringRef keys [2];
+ keys [0] = kCTFontTraitsAttribute;
+ keys [1] = kCTFontNameAttribute;
+ CFStringRef cfFont;
+ switch (font) {
+ case kGraphics_font_TIMES: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Times New Roman"); } break;
+ case kGraphics_font_HELVETICA: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Arial" ); } break;
+ case kGraphics_font_COURIER: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Courier New" ); } break;
+ case kGraphics_font_PALATINO: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Palatino" ); } break;
+ case kGraphics_font_SYMBOL: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Symbol" ); } break;
+ case kGraphics_font_IPATIMES: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Doulos SIL" ); } break;
+ case kGraphics_font_IPAPALATINO: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Charis SIL" ); } break;
+ case kGraphics_font_DINGBATS: { cfFont = (CFStringRef) Melder_peekWcsToCfstring (L"Zapf Dingbats" ); } break;
+ }
+ void *values [2] = { (void *) styleDict, (void *) cfFont };
+ CFDictionaryRef attributes = CFDictionaryCreate (NULL, (const void **) & keys, (const void **) & values, 2,
+ & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
+ CFRelease (styleDict);
+ CTFontDescriptorRef ctFontDescriptor = CTFontDescriptorCreateWithAttributes (attributes);
+ CFRelease (attributes);
+ #else
+ NSMutableDictionary *styleDict = [[NSMutableDictionary alloc] initWithCapacity: 1];
+ [styleDict setObject: [NSNumber numberWithUnsignedInt: ctStyle] forKey: (id) kCTFontSymbolicTrait];
+ NSMutableDictionary *attributes = [[NSMutableDictionary alloc] initWithCapacity: 2];
+ [attributes setObject: styleDict forKey: (id) kCTFontTraitsAttribute];
+ switch (font) {
+ case kGraphics_font_TIMES: { [attributes setObject: @"Times New Roman" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_HELVETICA: { [attributes setObject: @"Arial" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_COURIER: { [attributes setObject: @"Courier New" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_PALATINO: { [attributes setObject: @"Palatino" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_SYMBOL: { [attributes setObject: @"Symbol" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_IPATIMES: { [attributes setObject: @"Doulos SIL" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_IPAPALATINO: { [attributes setObject: @"Charis SIL" forKey: (id) kCTFontNameAttribute]; } break;
+ case kGraphics_font_DINGBATS: { [attributes setObject: @"Zapf Dingbats" forKey: (id) kCTFontNameAttribute]; } break;
+ }
+ CTFontDescriptorRef ctFontDescriptor = CTFontDescriptorCreateWithAttributes ((CFMutableDictionaryRef) attributes);
+ [styleDict release];
+ [attributes release];
+ #endif
+ CTFontRef ctFont = CTFontCreateWithFontDescriptor (ctFontDescriptor, lc -> size, NULL);
+ CFRelease (ctFontDescriptor);
+
int needBitmappedIPA = 0;
- CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- NSCAssert(context, @"nil context");
- CGContextSaveGState(context);
- CGContextSetTextMatrix(context, CGAffineTransformIdentity);
- NSString *s = [[NSString alloc] initWithBytes:Melder_peekWcsToUtf16 (codes) length:nchars * 2 encoding:NSUTF16LittleEndianStringEncoding];
-
- Boolean boldStyle = (lc -> style & Graphics_BOLD) != 0;
- Boolean italicStyle = (lc -> style & Graphics_ITALIC) != 0;
- CTFontSymbolicTraits theSymbolicTraits = 0;
- if (boldStyle)
- theSymbolicTraits |= kCTFontBoldTrait;
- if (italicStyle)
- theSymbolicTraits |= kCTFontItalicTrait;
-
- NSMutableDictionary *traitsDict = [NSMutableDictionary dictionary];
- [traitsDict setObject:[NSNumber numberWithUnsignedInt:theSymbolicTraits] forKey:(id)kCTFontSymbolicTrait];
- NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
- if (my font == kGraphics_font_TIMES) {
- [attributes setObject:@"Times" forKey:(id)kCTFontNameAttribute];
- } else if (my font == kGraphics_font_HELVETICA) {
- [attributes setObject:@"Helvetica" forKey:(id)kCTFontNameAttribute];
- } else if (my font == kGraphics_font_COURIER) {
- [attributes setObject:@"Courier" forKey:(id)kCTFontNameAttribute];
- }
+ bool hasHighUnicodeValues = false;
+ for (long i = 0; i < nchars; i ++) {
+ hasHighUnicodeValues |= codes [i] > 0xFFFF;
+ }
+ if (hasHighUnicodeValues) {
+ nchars = wcslen_utf16 (codes, 0);
+ codes16 = Melder_peekWcsToUtf16 (codes);
+ }
+ #if 1
+ CFStringRef s = CFStringCreateWithBytes (NULL, (const UInt8 *) codes16, nchars * 2, kCFStringEncodingUTF16LE, false);
+ int length = CFStringGetLength (s);
+ #else
+ NSString *s = [[NSString alloc] initWithBytes: codes16 length: nchars * 2 encoding: NSUTF16LittleEndianStringEncoding];
+ int length = [s length];
+ #endif
- [attributes setObject:traitsDict forKey:(id)kCTFontTraitsAttribute];
- CTFontDescriptorRef fontDesc = CTFontDescriptorCreateWithAttributes(( CFDictionaryRef)attributes);
- CTFontRef ctFont = CTFontCreateWithFontDescriptor(fontDesc, lc -> size, NULL);
- CGFloat descent = CTFontGetDescent( ctFont );
-
- CTTextAlignment textAlignment = kCTNaturalTextAlignment;
- CTParagraphStyleSetting paragraphSettings[1] = { {kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), &textAlignment} };
- CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
- CFRange textRange = CFRangeMake(0, [s length]);
-
- CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, [s length]);
- CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) s);
- CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont);
- CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);
-
- RGBColor *macColor = lc -> link ? & theBlueColour : my duringXor ? & theWhiteColour : & my d_macColour;
- CGColorRef color = CGColorCreateGenericRGB(macColor->red / 65536.0, macColor->green / 65536.0, macColor->blue / 65536.0, 1.0);
+ CGFloat descent = CTFontGetDescent (ctFont);
- CFAttributedStringSetAttribute(string, textRange, kCTForegroundColorAttributeName, color);
+ CFMutableAttributedStringRef string = CFAttributedStringCreateMutable (kCFAllocatorDefault, length);
+ CFAttributedStringReplaceString (string, CFRangeMake (0, 0), (CFStringRef) s);
+ CFRange textRange = CFRangeMake (0, length);
+ CFAttributedStringSetAttribute (string, textRange, kCTFontAttributeName, ctFont);
+
+ static CFNumberRef cfKerning;
+ if (! cfKerning) {
+ double kerning = 0.0;
+ cfKerning = CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, & kerning);
+ }
+ CFAttributedStringSetAttribute (string, textRange, kCTKernAttributeName, cfKerning);
+
+ static CTParagraphStyleRef paragraphStyle;
+ if (! paragraphStyle) {
+ CTTextAlignment textAlignment = kCTLeftTextAlignment;
+ CTParagraphStyleSetting paragraphSettings [1] = { { kCTParagraphStyleSpecifierAlignment, sizeof (CTTextAlignment), & textAlignment } };
+ paragraphStyle = CTParagraphStyleCreate (paragraphSettings, 1);
+ Melder_assert (paragraphStyle != NULL);
+ }
+ CFAttributedStringSetAttribute (string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);
+
+ RGBColor *macColor = lc -> link ? & theBlueColour : my duringXor ? & theWhiteColour : & my d_macColour;
+ CGColorRef color = CGColorCreateGenericRGB (macColor->red / 65536.0, macColor->green / 65536.0, macColor->blue / 65536.0, 1.0);
+ Melder_assert (color != NULL);
+ CFAttributedStringSetAttribute (string, textRange, kCTForegroundColorAttributeName, color);
/*
* Draw.
*/
// Create a path to render text in
- CGMutablePathRef path = CGPathCreateMutable();
- NSRect measureRect = NSMakeRect(0, 0, CGFLOAT_MAX, CGFLOAT_MAX);
- CGPathAddRect(path, NULL, measureRect );
+ CGMutablePathRef path = CGPathCreateMutable ();
+ NSRect measureRect = NSMakeRect (0, 0, CGFLOAT_MAX, CGFLOAT_MAX);
+ CGPathAddRect (path, NULL, (CGRect) measureRect);
+
+ CGContextSetTextMatrix (my d_macGraphicsContext, CGAffineTransformIdentity); // this could set the "current context" for CoreText
// create the framesetter and render text
- CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
- CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
- CFRangeMake(0, [s length]), path, NULL);
+ CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString ((CFAttributedStringRef) string);
+ Melder_assert (framesetter != NULL);
+ CTFrameRef frame = CTFramesetterCreateFrame (framesetter, CFRangeMake (0, length), path, NULL);
+ Melder_assert (frame != NULL);
CFRange fitRange;
- CGSize targetSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
- CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, targetSize, &fitRange);
- CFRelease(path);
- CFRelease(color);
- CFRelease(frame);
- path = CGPathCreateMutable();
- NSRect drawRect = NSMakeRect(0, 0, frameSize.width, frameSize.height);
- CGPathAddRect(path, NULL, drawRect );
- frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [s length]), path, NULL);
-
- NSCAssert(my d_macGraphicsContext, @"nil context");
-
+ CGSize targetSize = CGSizeMake (CGFLOAT_MAX, CGFLOAT_MAX);
+ CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints (framesetter, textRange, NULL, targetSize, & fitRange);
+ CFRelease (path);
+ CFRelease (color);
+ CFRelease (frame);
+ path = CGPathCreateMutable ();
+ NSRect drawRect = NSMakeRect (0, 0, frameSize.width, frameSize.height);
+ trace ("frame %f %f", frameSize.width, frameSize.height);
+ CGPathAddRect (path, NULL, (CGRect) drawRect);
+ frame = CTFramesetterCreateFrame (framesetter, CFRangeMake (0, length), path, NULL);
+ Melder_assert (frame != NULL);
+
+ if (my d_macView) {
+ [my d_macView lockFocus];
+ my d_macGraphicsContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+ }
CGContextSaveGState (my d_macGraphicsContext);
CGContextTranslateCTM (my d_macGraphicsContext, xDC, yDC + descent);
if (my yIsZeroAtTheTop) CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
CGContextRotateCTM (my d_macGraphicsContext, my textRotation * NUMpi / 180.0);
+
+ //CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+ //Melder_assert (my d_macGraphicsContext != NULL);
+ //Melder_assert (context == my d_macGraphicsContext);
if (my duringXor) {
CGContextSetBlendMode (my d_macGraphicsContext, kCGBlendModeDifference);
CGContextSetAllowsAntialiasing (my d_macGraphicsContext, false);
- CTFrameDraw(frame, context);
+ CTFrameDraw (frame, my d_macGraphicsContext);
CGContextSetBlendMode (my d_macGraphicsContext, kCGBlendModeNormal);
CGContextSetAllowsAntialiasing (my d_macGraphicsContext, true);
} else {
- CTFrameDraw(frame, context);
+ CTFrameDraw (frame, my d_macGraphicsContext);
}
CGContextRestoreGState (my d_macGraphicsContext);
+ //CGContextRestoreGState (my d_macGraphicsContext);
-
// Clean up
- CFRelease(frame);
- CFRelease(path);
- CFRelease(framesetter);
- CFRelease(string);
- CGContextRestoreGState(context);
- [s release];
-
+ CFRelease (frame);
+ CFRelease (path);
+ CFRelease (framesetter);
+ CFRelease (string);
+ #if 1
+ CFRelease (s);
+ #else
+ [s release];
+ #endif
+ CFRelease (ctFont);
+ if (my d_macView) {
+ CGContextSynchronize (my d_macGraphicsContext);
+ [my d_macView unlockFocus];
+ }
#elif win
int font = lc -> font.integer;
@@ -1794,34 +1911,6 @@ bool _GraphicsMac_tryToInitializeAtsuiFonts (void) {
}
Melder_assert (theTimesAtsuiFont != 0);
ATSUFindFontFromName (NULL, 0, 0, 0, 0, kFontArabicLanguage, & theArabicAtsuiFont);
- if (theTimesCoreTextFont != 0) return true; // once
- theTimesCoreTextFont = CTFontCreateWithName (CFSTR ("Times"), 0.0, NULL);
- if (! theTimesCoreTextFont) theTimesCoreTextFont = CTFontCreateWithName (CFSTR ("Times New Roman"), 0.0, NULL);
- theHelveticaCoreTextFont = CTFontCreateWithName (CFSTR ("Helvetica"), 0.0, NULL);
- if (! theHelveticaCoreTextFont) theHelveticaCoreTextFont = CTFontCreateWithName (CFSTR ("Arial"), 0.0, NULL);
- theCourierCoreTextFont = CTFontCreateWithName (CFSTR ("Courier"), 0.0, NULL);
- if (! theCourierCoreTextFont) theCourierCoreTextFont = CTFontCreateWithName (CFSTR ("Courier New"), 0.0, NULL);
- theSymbolCoreTextFont = CTFontCreateWithName (CFSTR ("Symbol"), 0.0, NULL);
- thePalatinoCoreTextFont = CTFontCreateWithName (CFSTR ("Palatino"), 0.0, NULL);
- if (! thePalatinoCoreTextFont) thePalatinoCoreTextFont = CTFontCreateWithName (CFSTR ("Book Antiqua"), 0.0, NULL);
- if (! thePalatinoCoreTextFont) thePalatinoCoreTextFont = theTimesCoreTextFont;
- theZapfDingbatsCoreTextFont = CTFontCreateWithName (CFSTR ("Zapf Dingbats"), 0.0, NULL);
- if (! theZapfDingbatsCoreTextFont) theZapfDingbatsCoreTextFont = theTimesCoreTextFont;
- theIpaTimesCoreTextFont = CTFontCreateWithName (CFSTR ("Doulos SIL"), 0.0, NULL);
- theIpaPalatinoCoreTextFont = CTFontCreateWithName (CFSTR ("Charis SIL"), 0.0, NULL);
- if (! theIpaTimesCoreTextFont) {
- if (theIpaPalatinoCoreTextFont) {
- theIpaTimesCoreTextFont = theIpaPalatinoCoreTextFont;
- } else {
- Melder_warning (L"Praat cannot find the Charis SIL or Doulos SIL font.\n"
- "Phonetic characters will not look well."); // because ATSUI will use the "last resort font"
- theIpaTimesCoreTextFont = theTimesCoreTextFont;
- theIpaPalatinoCoreTextFont = thePalatinoCoreTextFont;
- }
- } else if (! theIpaPalatinoCoreTextFont) {
- theIpaPalatinoCoreTextFont = theIpaTimesCoreTextFont;
- }
- Melder_assert (theTimesCoreTextFont != 0);
return true;
}
#endif
diff --git a/sys/Gui.h b/sys/Gui.h
index 763bc58..f04696f 100644
--- a/sys/Gui.h
+++ b/sys/Gui.h
@@ -80,7 +80,7 @@
#define Gui_CHECKBUTTON_HEIGHT 20
#define Gui_LABEL_SPACING 8
#define Gui_OPTIONMENU_HEIGHT 20
-#if gtk || cocoa
+#if gtk
#define Gui_PUSHBUTTON_HEIGHT 25
#else
#define Gui_PUSHBUTTON_HEIGHT 20
@@ -105,26 +105,25 @@
- (void) setUserData: (GuiThing) userData;
@end
typedef NSObject <GuiCocoaAny> *GuiObject;
- @interface GuiCocoaButton : NSButton <GuiCocoaAny> @end
- @interface GuiCocoaScrollBar : NSScroller <GuiCocoaAny> @end
+ @interface GuiCocoaButton : NSButton <GuiCocoaAny> @end
+ @interface GuiCocoaCheckButton : NSButton <GuiCocoaAny> @end
+ @interface GuiCocoaDrawingArea : NSView <GuiCocoaAny> @end
@interface GuiCocoaLabel : NSTextField <GuiCocoaAny> @end
+ @interface GuiCocoaList : NSView <GuiCocoaAny, NSTableViewDataSource, NSTableViewDelegate>
+ @property (nonatomic, retain) NSMutableArray *contents;
+ @property (nonatomic, retain) NSTableView *tableView;
+ @end
@interface GuiCocoaMenu : NSMenu <GuiCocoaAny> @end
@interface GuiCocoaMenuButton : NSPopUpButton <GuiCocoaAny> @end
@interface GuiCocoaMenuItem : NSMenuItem <GuiCocoaAny> @end
- @interface GuiCocoaText : NSTextField <GuiCocoaAny> @end
- @interface GuiCocoaWindow : NSWindow <GuiCocoaAny> @end
- @interface GuiCocoaScrolledWindow : NSScrollView <GuiCocoaAny> @end
- @interface GuiCocoaCheckButton : NSButton <GuiCocoaAny> @end
- @interface GuiCocoaDrawingArea : NSView <GuiCocoaAny>
- - (void)flush;
- @end
- @interface GuiCocoaOptionMenu : NSPopUpButton <GuiCocoaAny> @end
- @interface GuiCocoaList : NSView <GuiCocoaAny, NSTableViewDataSource, NSTableViewDelegate>
- @property (nonatomic, retain) NSMutableArray *contents;
- @property (nonatomic, retain) NSTableView *tableView;
- @end
-
-
+ @interface GuiCocoaOptionMenu : NSPopUpButton <GuiCocoaAny> @end
+ @interface GuiCocoaProgressBar : NSProgressIndicator <GuiCocoaAny> @end
+ @interface GuiCocoaRadioButton : NSButton <GuiCocoaAny> @end
+ @interface GuiCocoaScrollBar : NSScroller <GuiCocoaAny> @end
+ @interface GuiCocoaScrolledWindow : NSScrollView <GuiCocoaAny> @end
+ @interface GuiCocoaTextField : NSTextField <GuiCocoaAny> @end
+ @interface GuiCocoaTextView : NSTextView <GuiCocoaAny, NSTextViewDelegate> @end
+ @interface GuiCocoaWindow : NSWindow <GuiCocoaAny> @end
#elif motif
typedef class structGuiObject *GuiObject; // Opaque
@@ -323,6 +322,7 @@ Thing_define (GuiThing, Thing) { public:
/*
* Methods:
*/
+ virtual void v_destroy ();
virtual void v_show ();
virtual void v_hide ();
virtual void v_setSensitive (bool sensitive);
@@ -330,6 +330,7 @@ Thing_define (GuiThing, Thing) { public:
Thing_define (GuiControl, GuiThing) { public:
int d_left, d_right, d_top, d_bottom;
+ bool d_blockValueChangedCallbacks;
/*
* Messages:
*/
@@ -367,6 +368,10 @@ Thing_define (GuiShell, GuiForm) { public:
int f_getShellHeight ();
void f_setTitle (const wchar_t *title);
void f_drain (); // drain the double graphics buffer
+ /*
+ * Overridden methods:
+ */
+ virtual void v_destroy ();
};
/********** GuiButton **********/
@@ -409,9 +414,6 @@ typedef struct structGuiCheckButtonEvent {
Thing_define (GuiCheckButton, GuiControl) { public:
void (*d_valueChangedCallback) (void *boss, GuiCheckButtonEvent event);
void *d_valueChangedBoss;
- #if gtk
- gulong d_valueChangedHandlerId;
- #endif
/*
* Messages:
*/
@@ -444,7 +446,6 @@ GuiDialog GuiDialog_create (GuiWindow parent, int x, int y, int width, int heigh
Thing_declare (GuiDrawingArea);
Thing_declare (GuiScrollBar);
-enum mouse_events { MOTION_NOTIFY = 1, BUTTON_PRESS, BUTTON_RELEASE };
typedef struct structGuiDrawingAreaExposeEvent {
GuiDrawingArea widget;
int x, y, width, height;
@@ -454,7 +455,6 @@ typedef struct structGuiDrawingAreaClickEvent {
int x, y;
bool shiftKeyPressed, commandKeyPressed, optionKeyPressed, extraControlKeyPressed;
int button;
- enum mouse_events type;
} *GuiDrawingAreaClickEvent;
typedef struct structGuiDrawingAreaKeyEvent {
GuiDrawingArea widget;
@@ -546,7 +546,7 @@ typedef struct structGuiListEvent {
} *GuiListEvent;
Thing_define (GuiList, GuiControl) { public:
- bool d_allowMultipleSelection, d_blockSelectionChangedCallback;
+ bool d_allowMultipleSelection;
void (*d_selectionChangedCallback) (void *boss, GuiListEvent event);
void *d_selectionChangedBoss;
void (*d_doubleClickCallback) (void *boss, GuiListEvent event);
@@ -720,6 +720,9 @@ GuiOptionMenu GuiOptionMenu_createShown (GuiForm parent, int left, int right, in
Thing_declare (GuiProgressBar);
Thing_define (GuiProgressBar, GuiControl) { public:
+ #if cocoa
+ GuiCocoaProgressBar *d_cocoaProgressBar;
+ #endif
/*
* Messages:
*/
@@ -742,8 +745,8 @@ Thing_define (GuiRadioButton, GuiControl) { public:
GuiRadioButton d_previous, d_next; // there's a linked list of grouped radio buttons
void (*d_valueChangedCallback) (void *boss, GuiRadioButtonEvent event);
void *d_valueChangedBoss;
- #if gtk
- gulong d_valueChangedHandlerId;
+ #if cocoa
+ GuiCocoaRadioButton *d_cocoaRadioButton;
#endif
/*
* Messages:
@@ -844,7 +847,10 @@ struct _history_entry_s {
Thing_define (GuiText, GuiControl) { public:
void (*d_changeCallback) (void *boss, GuiTextEvent event);
void *d_changeBoss;
- #if useCarbon
+ #if cocoa
+ GuiCocoaScrolledWindow *d_cocoaScrollView;
+ GuiCocoaTextView *d_cocoaTextView;
+ #elif defined (macintosh)
TXNObject d_macMlteObject;
TXNFrameID d_macMlteFrameId;
#else
diff --git a/sys/GuiButton.cpp b/sys/GuiButton.cpp
index 8c3f3f9..75b3d9b 100644
--- a/sys/GuiButton.cpp
+++ b/sys/GuiButton.cpp
@@ -192,7 +192,7 @@ GuiButton GuiButton_create (GuiForm parent, int left, int right, int top, int bo
// parent -> shell -> cancelButton = parent -> cancelButton = my widget;
// }
#elif cocoa
- GuiCocoaButton *button = [GuiCocoaButton alloc];
+ GuiCocoaButton *button = [[GuiCocoaButton alloc] init];
my d_widget = (GuiObject) button;
my v_positionInForm (my d_widget, left, right, top, bottom, parent);
[button setUserData: me];
@@ -200,14 +200,24 @@ GuiButton GuiButton_create (GuiForm parent, int left, int right, int top, int bo
[button setBezelStyle: NSRoundedBezelStyle];
[button setImagePosition: NSNoImage];
[button setBordered: YES];
+ static NSFont *theButtonFont;
+ if (! theButtonFont) {
+ theButtonFont = [NSFont systemFontOfSize: 13.0];
+ }
+ [button setFont: theButtonFont];
[button setTitle: (NSString *) Melder_peekWcsToCfstring (buttonText)];
[button setTarget: (id) my d_widget];
[button setAction: @selector (_guiCocoaButton_activateCallback:)];
-
- if (flags & GuiButton_DEFAULT || flags & GuiButton_ATTRACTIVE) {
- [button setKeyEquivalent:@"\r"];
- }
-
+ //[button setAutoresizingMask: NSViewNotSizable];
+ if (flags & GuiButton_DEFAULT) {
+ [button setKeyEquivalent: @"\r"];
+ }
+ if (flags & GuiButton_ATTRACTIVE) {
+ //[button setKeyEquivalent: @"\r"]; // slow!
+ [button highlight: YES]; // lasts only till it's clicked!
+ //[button setBezelStyle: NSThickerSquareBezelStyle];
+ //[button setFont: [NSFont boldSystemFontOfSize: 14.0]];
+ }
#elif win
my d_widget = _Gui_initializeWidget (xmPushButtonWidgetClass, parent -> d_widget, buttonText);
_GuiObject_setUserData (my d_widget, me);
@@ -248,7 +258,6 @@ GuiButton GuiButton_create (GuiForm parent, int left, int right, int top, int bo
if (flags & GuiButton_INSENSITIVE) {
my f_setSensitive (false);
}
-
return me;
}
diff --git a/sys/GuiCheckButton.cpp b/sys/GuiCheckButton.cpp
index 66aaf68..8f21ba9 100644
--- a/sys/GuiCheckButton.cpp
+++ b/sys/GuiCheckButton.cpp
@@ -1,6 +1,6 @@
/* GuiCheckButton.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2007-2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2007-2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,36 +40,37 @@ Thing_implement (GuiCheckButton, GuiControl, 0);
}
static void _GuiGtkCheckButton_valueChangedCallback (GuiObject widget, gpointer void_me) {
iam (GuiCheckButton);
- struct structGuiCheckButtonEvent event = { me };
- if (my d_valueChangedCallback != NULL) {
+ if (my d_valueChangedCallback != NULL && ! my d_blockValueChangedCallbacks) {
+ struct structGuiCheckButtonEvent event = { me };
my d_valueChangedCallback (my d_valueChangedBoss, & event);
}
}
#elif cocoa
- at implementation GuiCocoaCheckButton {
- GuiCheckButton d_userData;
-}
-- (void) dealloc { // override
- GuiCheckButton me = d_userData;
- forget (me);
- trace ("deleting a check button");
- [super dealloc];
-}
-- (GuiThing) userData {
- return d_userData;
-}
-- (void) setUserData: (GuiThing) userData {
- Melder_assert (userData == NULL || Thing_member (userData, classGuiCheckButton));
- d_userData = static_cast <GuiCheckButton> (userData);
-}
-- (void) _guiCocoaButton_activateCallback: (id) widget {
- Melder_assert (self == widget); // sender (widget) and receiver (self) happen to be the same object
- GuiCheckButton me = d_userData;
- if (my d_valueChangedCallback != NULL) {
- struct structGuiCheckButtonEvent event = { me };
- my d_valueChangedCallback (my d_valueChangedBoss, & event);
- }
-}
+ @implementation GuiCocoaCheckButton {
+ GuiCheckButton d_userData;
+ }
+ - (void) dealloc { // override
+ GuiCheckButton me = d_userData;
+ forget (me);
+ trace ("deleting a check button");
+ [super dealloc];
+ }
+ - (GuiThing) userData {
+ return d_userData;
+ }
+ - (void) setUserData: (GuiThing) userData {
+ Melder_assert (userData == NULL || Thing_member (userData, classGuiCheckButton));
+ d_userData = static_cast <GuiCheckButton> (userData);
+ }
+ - (void) _guiCocoaButton_activateCallback: (id) widget {
+ Melder_assert (self == widget); // sender (widget) and receiver (self) happen to be the same object
+ GuiCheckButton me = d_userData;
+ if (my d_valueChangedCallback != NULL) {
+ Melder_assert (! my d_blockValueChangedCallbacks);
+ struct structGuiCheckButtonEvent event = { me };
+ my d_valueChangedCallback (my d_valueChangedBoss, & event);
+ }
+ }
@end
#elif win
@@ -122,23 +123,19 @@ GuiCheckButton GuiCheckButton_create (GuiForm parent, int left, int right, int t
my f_setSensitive (false);
}
g_signal_connect (G_OBJECT (my d_widget), "destroy", G_CALLBACK (_GuiGtkCheckButton_destroyCallback), me);
- my d_valueChangedHandlerId = g_signal_connect (GTK_TOGGLE_BUTTON (my d_widget), "toggled", G_CALLBACK (_GuiGtkCheckButton_valueChangedCallback), me);
+ g_signal_connect (GTK_TOGGLE_BUTTON (my d_widget), "toggled", G_CALLBACK (_GuiGtkCheckButton_valueChangedCallback), me);
#elif cocoa
-
- GuiCocoaCheckButton *checkButton = [GuiCocoaCheckButton alloc];
- my d_widget = (GuiObject) checkButton;
- my v_positionInForm (my d_widget, left, right, top, bottom, parent);
- [checkButton setUserData:me];
- [checkButton setButtonType:NSSwitchButton];
- [checkButton setTitle:(NSString *) Melder_peekWcsToCfstring (buttonText)];
- [checkButton setTarget:checkButton];
- [checkButton setAction:@selector (_guiCocoaButton_activateCallback:)];
-
- if (flags & GuiCheckButton_SET) {
- [checkButton setState:NSOnState];
- }
-
-
+ GuiCocoaCheckButton *checkButton = [[GuiCocoaCheckButton alloc] init];
+ my d_widget = (GuiObject) checkButton;
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [checkButton setUserData: me];
+ [checkButton setButtonType: NSSwitchButton];
+ [checkButton setTitle: (NSString *) Melder_peekWcsToCfstring (buttonText)];
+ [checkButton setTarget: checkButton];
+ [checkButton setAction: @selector (_guiCocoaButton_activateCallback:)];
+ if (flags & GuiCheckButton_SET) {
+ [checkButton setState: NSOnState];
+ }
#elif win
my d_widget = _Gui_initializeWidget (xmToggleButtonWidgetClass, parent -> d_widget, buttonText);
_GuiObject_setUserData (my d_widget, me);
@@ -203,12 +200,10 @@ void structGuiCheckButton :: f_setValue (bool value) {
* The value should be set without calling the valueChanged callback.
*/
#if gtk
- g_signal_handler_disconnect (GTK_TOGGLE_BUTTON (d_widget), d_valueChangedHandlerId);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (d_widget), value);
- d_valueChangedHandlerId = g_signal_connect (GTK_TOGGLE_BUTTON (d_widget), "toggled", G_CALLBACK (_GuiGtkCheckButton_valueChangedCallback), this);
#elif cocoa
- GuiCocoaCheckButton *checkButton = (GuiCocoaCheckButton*)d_widget;
- [checkButton setState: value ? NSOnState: NSOffState];
+ GuiCocoaCheckButton *checkButton = (GuiCocoaCheckButton *) d_widget;
+ [checkButton setState: value ? NSOnState: NSOffState];
#elif win
Button_SetCheck (d_widget -> window, value ? BST_CHECKED : BST_UNCHECKED);
#elif mac
diff --git a/sys/GuiControl.cpp b/sys/GuiControl.cpp
index ba0cd4e..932d261 100644
--- a/sys/GuiControl.cpp
+++ b/sys/GuiControl.cpp
@@ -1,6 +1,6 @@
/* GuiControl.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2008 Stefan de Koninck, 2010 Franz Brausse, 2013 Tom Naughton
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2008 Stefan de Koninck, 2010 Franz Brausse, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@ int structGuiControl :: f_getX () {
#if gtk
return GTK_WIDGET (d_widget) -> allocation.x;
#elif cocoa
- return 100;//[(NSView *) d_widget x];
+ return [(NSView *) d_widget frame]. origin. x;
#elif motif
return d_widget -> x;
#endif
@@ -34,7 +34,7 @@ int structGuiControl :: f_getY () {
#if gtk
return GTK_WIDGET (d_widget) -> allocation.y;
#elif cocoa
- return 100;//[(NSView *) d_widget y];
+ return [(NSView *) d_widget frame]. origin. y;
#elif motif
return d_widget -> y;
#endif
@@ -44,7 +44,7 @@ int structGuiControl :: f_getWidth () {
#if gtk
return GTK_WIDGET (d_widget) -> allocation.width;
#elif cocoa
- return 100;//[(NSView *) d_widget width];
+ return [(NSView *) d_widget frame]. size. width;
#elif motif
return d_widget -> width;
#endif
@@ -54,7 +54,7 @@ int structGuiControl :: f_getHeight () {
#if gtk
return GTK_WIDGET (d_widget) -> allocation.height;
#elif cocoa
- return 100;//[(NSView *) d_widget height];
+ return [(NSView *) d_widget frame]. size. height;
#elif motif
return d_widget -> height;
#endif
@@ -101,14 +101,14 @@ void structGuiControl :: v_positionInForm (GuiObject widget, int left, int right
//parentHeight = GTK_WIDGET (parent -> d_widget) -> allocation.height;
if (left < 0) left += parentWidth;
if (right <= 0) right += parentWidth;
- if (top < 0) top += parentHeight;
+ if (top < 0) top += parentHeight;
if (bottom <= 0) bottom += parentHeight;
trace ("fixed: parent width %d height %d", parentWidth, parentHeight);
gtk_widget_set_size_request (GTK_WIDGET (widget), right - left, bottom - top);
gtk_fixed_put (GTK_FIXED (parent -> d_widget), GTK_WIDGET (widget), left, top);
#elif cocoa
- NSView *superView = (NSView*)parent -> d_widget;
- NSView *widgetView = (NSView*) d_widget;
+ NSView *superView = (NSView *) parent -> d_widget;
+ NSView *widgetView = (NSView *) widget;
NSRect parentRect = [superView frame];
int parentWidth = parentRect.size.width;
int parentHeight = parentRect.size.height;
@@ -136,12 +136,24 @@ void structGuiControl :: v_positionInForm (GuiObject widget, int left, int right
if (bottom <= 0) bottom += parentHeight;
top = parentHeight - top; // flip
bottom = parentHeight - bottom; // flip
- NSRect rect = { { left, bottom }, { right - left, top - bottom } };
- [widgetView initWithFrame: rect];
-
- [widgetView setAutoresizingMask:horizMask | vertMask];
- [superView addSubview:widgetView]; // parent will retain the subview...
- [widgetView setBounds: rect];
+ int width = right - left;
+ int height = top - bottom;
+ if ([widgetView isKindOfClass: [NSButton class]]) {
+ if (! [widgetView isKindOfClass: [NSPopUpButton class]]) {
+ /*
+ * On Cocoa, NSButton views show up 12 pixels less wide and 5 pixels less high than their frame.
+ * Compensate for this (undocumented?) Cocoa phenomenon.
+ */
+ left -= 6;
+ width += 12;
+ bottom -= 5;
+ height += 5;
+ }
+ }
+ NSRect rect = NSMakeRect (left, bottom, width, height);
+ [widgetView setAutoresizingMask: horizMask | vertMask];
+ [superView addSubview: widgetView]; // parent will retain the subview...
+ [widgetView setFrame: rect];
[widgetView release]; // ... so we can release the item already
#elif motif
(void) parent;
@@ -177,13 +189,13 @@ void structGuiControl :: v_positionInScrolledWindow (GuiObject widget, int width
gtk_widget_set_size_request (GTK_WIDGET (widget), width, height);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (parent -> d_widget), GTK_WIDGET (widget));
#elif cocoa
- GuiCocoaScrolledWindow *scrolledWindow = (GuiCocoaScrolledWindow*)parent->d_widget;
- NSView *widgetView = (NSView*)widget;
- NSRect rect = NSMakeRect(0, 0, width, height);
- [widgetView initWithFrame:rect];
- [widgetView setBounds:rect];
- [scrolledWindow setDocumentView:widgetView];
- [widgetView release]; // ... so we can release the item already
+ GuiCocoaScrolledWindow *scrolledWindow = (GuiCocoaScrolledWindow *) parent -> d_widget;
+ NSView *widgetView = (NSView *) widget;
+ NSRect rect = NSMakeRect (0, 0, width, height);
+ [widgetView initWithFrame: rect];
+ [widgetView setBounds: rect];
+ [scrolledWindow setDocumentView: widgetView];
+ [widgetView release]; // ... so we can release the item already
#elif motif
(void) parent;
XtVaSetValues (widget, XmNwidth, width, XmNheight, height, NULL);
diff --git a/sys/GuiDialog.cpp b/sys/GuiDialog.cpp
index ec72d82..1115703 100644
--- a/sys/GuiDialog.cpp
+++ b/sys/GuiDialog.cpp
@@ -1,6 +1,6 @@
/* GuiDialog.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -120,6 +120,7 @@ GuiDialog GuiDialog_create (GuiWindow parent, int x, int y, int width, int heigh
//[nsWindow makeKeyAndOrderFront: nil];
my d_widget = (GuiObject) [nsWindow contentView];
[(GuiCocoaDialog *) nsWindow setUserData: me];
+ [nsWindow setReleasedWhenClosed: NO];
#elif motif
my d_xmShell = XmCreateDialogShell (mac ? NULL : parent -> d_widget, "dialogShell", NULL, 0);
XtVaSetValues (my d_xmShell, XmNdeleteResponse, goAwayCallback ? XmDO_NOTHING : XmUNMAP, XmNx, x, XmNy, y, NULL);
diff --git a/sys/GuiDrawingArea.cpp b/sys/GuiDrawingArea.cpp
index 6af8fdf..d5f44cb 100644
--- a/sys/GuiDrawingArea.cpp
+++ b/sys/GuiDrawingArea.cpp
@@ -1,6 +1,6 @@
/* GuiDrawingArea.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,7 +46,7 @@ Thing_implement (GuiDrawingArea, GuiControl, 0);
trace ("begin");
iam (GuiDrawingArea);
Melder_assert (me);
- // TODO: that helps agains the damaged regions outside the rect where the
+ // TODO: that helps against the damaged regions outside the rect where the
// Graphics drawing is done, but where does that margin come from in the
// first place?? Additionally this causes even more flickering
//gdk_window_clear_area(widget->window, expose->area.x, expose->area.y, expose->area.width, expose->area.height);
@@ -76,42 +76,19 @@ Thing_implement (GuiDrawingArea, GuiControl, 0);
}
static gboolean _GuiGtkDrawingArea_clickCallback (GuiObject widget, GdkEvent *e, gpointer void_me) {
iam (GuiDrawingArea);
+ if (e -> type != GDK_BUTTON_PRESS) return FALSE;
if (my d_clickCallback) {
struct structGuiDrawingAreaClickEvent event = { me, 0 };
- trace ("event type %ld", (long) e -> type);
- switch (e -> type) {
- case GDK_BUTTON_PRESS:
- event. type = BUTTON_PRESS;
- event. button = ((GdkEventButton *) e) -> button;
- break;
- case GDK_BUTTON_RELEASE:
- event. type = BUTTON_RELEASE;
- event. button = ((GdkEventButton *) e) -> button;
- break;
- case GDK_MOTION_NOTIFY:
- event. type = MOTION_NOTIFY;
- event. button =
- ((GdkEventMotion *) e) -> state & GDK_BUTTON1_MASK ? 1 :
- ((GdkEventMotion *) e) -> state & GDK_BUTTON2_MASK ? 2 :
- ((GdkEventMotion *) e) -> state & GDK_BUTTON3_MASK ? 3 :
- ((GdkEventMotion *) e) -> state & GDK_BUTTON4_MASK ? 4 :
- ((GdkEventMotion *) e) -> state & GDK_BUTTON5_MASK ? 5 : 0;
- break;
- default:
- // Do NOTHING
- return FALSE;
- }
+ event. button = ((GdkEventButton *) e) -> button;
event. x = ((GdkEventButton *) e) -> x;
event. y = ((GdkEventButton *) e) -> y;
event. shiftKeyPressed = (((GdkEventButton *) e) -> state & GDK_SHIFT_MASK) != 0;
- if (e -> type == GDK_BUTTON_PRESS || 1) {
- try {
- my d_clickCallback (my d_clickBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Mouse click not completely handled.");
- }
- return TRUE;
+ try {
+ my d_clickCallback (my d_clickBoss, & event);
+ } catch (MelderError) {
+ Melder_flushError ("Mouse click not completely handled.");
}
+ return TRUE;
}
return FALSE;
}
@@ -164,211 +141,137 @@ Thing_implement (GuiDrawingArea, GuiControl, 0);
return FALSE;
}
#elif cocoa
- at interface GuiCocoaDrawingArea ()
- at property (nonatomic, assign) BOOL inited;
- at property (nonatomic, retain) NSTrackingArea *trackingArea;
- at end
- at implementation GuiCocoaDrawingArea {
- GuiDrawingArea d_userData;
-}
-- (id)initWithFrame:(NSRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- _trackingArea = [[[NSTrackingArea alloc] initWithRect:[self visibleRect]
- // feed in NSTrackingMouseMoved to get mouseMoved: events too
- options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect |NSTrackingActiveAlways
- owner:self
- userInfo:nil] autorelease];
-
- [self addTrackingArea:_trackingArea];
-
- }
- return self;
-}
-- (void) dealloc { // override
- GuiDrawingArea me = d_userData;
- forget (me);
- [self removeTrackingArea:_trackingArea];
-
- Melder_casual ("deleting a drawing area");
- [super dealloc];
-}
-- (GuiThing) userData {
- return d_userData;
-}
-- (void) setUserData: (GuiThing) userData {
- d_userData = static_cast <GuiDrawingArea> (userData);
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
-#pragma unused (dirtyRect)
-
- if (!_inited) {
- // Last chance to do this. Is there a better place?
- [self resizeCallback:self.frame];
- _inited = YES;
- }
-
-
- GuiDrawingArea me = (GuiDrawingArea) d_userData;
-
- if (my d_exposeCallback) {
- struct structGuiDrawingAreaExposeEvent event = { me };
- try {
- my d_exposeCallback (my d_exposeBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Redrawing not completed");
- }
- }
-}
-
-- (void)resizeCallback:(NSRect)rect {
- GuiDrawingArea me = (GuiDrawingArea) d_userData;
-
- if (my d_resizeCallback) {
- struct structGuiDrawingAreaResizeEvent event = { me, 0 };
- event. width = rect.size.width;
- event. height = rect.size.height;
-
- try {
- my d_resizeCallback (my d_resizeBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Window resizing not completely handled.");
- }
- }
-
-}
-
-- (void)flush {
- [self lockFocus];
- CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- NSCAssert(context, @"nil context");
- CGContextFlush(context);
- [self unlockFocus];
-}
-
-- (void)setFrame:(NSRect)rect {
- [self resizeCallback:rect];
- [super setFrame:rect];
-}
-
-- (BOOL)acceptsFirstResponder
-{
- return YES;
-}
-
-- (void)mouseEntered:(NSEvent *)theEvent{
-#pragma unused (theEvent)
- [[NSCursor crosshairCursor] push];
-
-}
-
-- (void)mouseExited:(NSEvent *)theEvent{
-#pragma unused (theEvent)
- [[NSCursor currentCursor] pop];
-}
-
-- (void)mouseDown:(NSEvent *)theEvent {
- // [self becomeFirstResponder];
- GuiDrawingArea me = (GuiDrawingArea) d_userData;
- if (my d_clickCallback) {
-
- NSPoint event_location = [theEvent locationInWindow];
- NSPoint local_point = [self convertPoint:event_location fromView:nil];
- NSUInteger modifiers = [theEvent modifierFlags];
-
- struct structGuiDrawingAreaClickEvent event = { me, 0 };
- event. x = local_point.x;
- event. y = [self frame].size.height - local_point.y;
- event. shiftKeyPressed = NSShiftKeyMask & modifiers;
- event. optionKeyPressed = NSAlternateKeyMask & modifiers;
- event. commandKeyPressed = NSCommandKeyMask & modifiers;
- event.type = BUTTON_PRESS;
- try {
- my d_clickCallback (my d_clickBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Mouse click not completely handled.");
- }
- }
-}
-
-- (void)mouseUp:(NSEvent *)theEvent {
- GuiDrawingArea me = (GuiDrawingArea) d_userData;
- if (my d_clickCallback) {
-
- NSPoint event_location = [theEvent locationInWindow];
- NSPoint local_point = [self convertPoint:event_location fromView:nil];
- NSUInteger modifiers = [theEvent modifierFlags];
-
- struct structGuiDrawingAreaClickEvent event = { me, 0 };
- event. x = local_point.x;
- event. y = [self frame].size.height - local_point.y;
- event. shiftKeyPressed = NSShiftKeyMask & modifiers;
- event. optionKeyPressed = NSAlternateKeyMask & modifiers;
- event. commandKeyPressed = NSCommandKeyMask & modifiers;
- event.type = BUTTON_RELEASE;
- try {
- my d_clickCallback (my d_clickBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Mouse click not completely handled.");
- }
- }
-}
-
-- (void)mouseDragged:(NSEvent *)theEvent {
- GuiDrawingArea me = (GuiDrawingArea) d_userData;
- if (my d_clickCallback) {
-
- NSPoint event_location = [theEvent locationInWindow];
- NSPoint local_point = [self convertPoint:event_location fromView:nil];
- NSUInteger modifiers = [theEvent modifierFlags];
-
- struct structGuiDrawingAreaClickEvent event = { me, 0 };
- event. x = local_point.x;
- event. y = [self frame].size.height - local_point.y;
- event. shiftKeyPressed = NSShiftKeyMask & modifiers;
- event. optionKeyPressed = NSAlternateKeyMask & modifiers;
- event. commandKeyPressed = NSCommandKeyMask & modifiers;
- event. type = MOTION_NOTIFY;
- try {
- my d_clickCallback (my d_clickBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Mouse click not completely handled.");
- }
- }
-}
-
-- (void)keyDown:(NSEvent *)theEvent {
- GuiDrawingArea me = (GuiDrawingArea) d_userData;
- NSUInteger modifiers = [theEvent modifierFlags];
- unsigned short keyCode = [theEvent keyCode];
- struct structGuiDrawingAreaKeyEvent event = { me, 0 };
- event.key = keyCode;
-
- NSLog(@"keyCode %d", keyCode);
-
- // FIXME: Map these keys
- // if (event. key == VK_RETURN) event. key = 10;
- // if (event. key == VK_LEFT) event. key = 0x2190;
- // if (event. key == VK_RIGHT) event. key = 0x2192;
- // if (event. key == VK_UP) event. key = 0x2191;
- // if (event. key == VK_DOWN) event. key = 0x2193;
-
- event.shiftKeyPressed = NSShiftKeyMask & modifiers;
- event.optionKeyPressed = NSAlternateKeyMask & modifiers;
- event.commandKeyPressed = NSCommandKeyMask & modifiers;
-
- if (my d_keyCallback) {
- try {
- my d_keyCallback (my d_keyBoss, & event);
- } catch (MelderError) {
- Melder_flushError ("Key press not completely handled.");
- }
- }
-}
-
- at end
-
+ @interface GuiCocoaDrawingArea ()
+ @property (nonatomic, assign) BOOL inited;
+ @property (nonatomic, retain) NSTrackingArea *trackingArea;
+ @end
+ @implementation GuiCocoaDrawingArea {
+ GuiDrawingArea d_userData;
+ }
+ - (id) initWithFrame: (NSRect) frame {
+ self = [super initWithFrame: frame];
+ if (self) {
+ _trackingArea = [[[NSTrackingArea alloc]
+ initWithRect: [self visibleRect]
+ options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways
+ owner: self
+ userInfo: nil]
+ autorelease];
+ [self addTrackingArea: _trackingArea];
+ }
+ return self;
+ }
+ - (void) dealloc { // override
+ GuiDrawingArea me = d_userData;
+ forget (me);
+ [self removeTrackingArea: _trackingArea];
+ trace ("deleting a drawing area");
+ [super dealloc];
+ }
+ - (GuiThing) userData {
+ return d_userData;
+ }
+ - (void) setUserData: (GuiThing) userData {
+ d_userData = static_cast <GuiDrawingArea> (userData);
+ }
+ - (void) resizeCallback: (NSRect) rect {
+ GuiDrawingArea me = (GuiDrawingArea) d_userData;
+ if (me && my d_resizeCallback) {
+ struct structGuiDrawingAreaResizeEvent event = { me, 0 };
+ event. width = rect. size. width;
+ event. height = rect. size. height;
+ try {
+ my d_resizeCallback (my d_resizeBoss, & event);
+ } catch (MelderError) {
+ Melder_flushError ("Window resizing not completely handled.");
+ }
+ }
+ }
+ - (void) drawRect: (NSRect) dirtyRect {
+ trace ("dirtyRect: %f, %f, %f, %f", dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height);
+ GuiDrawingArea me = (GuiDrawingArea) d_userData;
+ if (! _inited) {
+ // Last chance to do this. Is there a better place?
+ [self resizeCallback: self. frame];
+ _inited = YES;
+ }
+ if (my d_exposeCallback) {
+ struct structGuiDrawingAreaExposeEvent event = { me };
+ try {
+ my d_exposeCallback (my d_exposeBoss, & event);
+ } catch (MelderError) {
+ Melder_flushError ("Redrawing not completed");
+ }
+ }
+ }
+ - (void) setFrame: (NSRect) rect {
+ [self resizeCallback: rect];
+ [super setFrame: rect];
+ }
+ - (BOOL) acceptsFirstResponder {
+ /*
+ * This overridden method tells the event chain whether the drawing area can accept key events.
+ * It is important that the Demo window and the RunnerMFC window accept key events.
+ * A side effect of accepting key events is that the drawing area obtains the key focus when the user clicks in the drawing area.
+ * It is important, however, that the drawing area of the TextGrid window cannot take away the key focus
+ * from the text field at the top; therefore, that drawing area should not accept key events.
+ * The implementation below is based on the fact that, naturally, the Demo window and the RunnerMFC window
+ * have a key callback, and the drawing area of the TextGrid window has not
+ * (a side effect of this implementation is that the drawing area of the Manual window does not take away
+ * the key focus from the Search field, a situation that cannot hurt).
+ */
+ GuiDrawingArea me = (GuiDrawingArea) d_userData;
+ return my d_keyCallback != NULL;
+ }
+ - (void) mouseEntered: (NSEvent *) nsEvent {
+ (void) nsEvent;
+ [[NSCursor crosshairCursor] push];
+ }
+ - (void) mouseExited: (NSEvent *) nsEvent{
+ (void) nsEvent;
+ [[NSCursor currentCursor] pop];
+ }
+ - (void) mouseDown: (NSEvent *) nsEvent {
+ // [self becomeFirstResponder];
+ GuiDrawingArea me = (GuiDrawingArea) d_userData;
+ if (my d_clickCallback) {
+ struct structGuiDrawingAreaClickEvent event = { me, 0 };
+ NSPoint local_point = [self convertPoint: [nsEvent locationInWindow] fromView: nil];
+ event. x = local_point. x;
+ event. y = [self frame]. size. height - local_point. y;
+ NSUInteger modifiers = [nsEvent modifierFlags];
+ event. shiftKeyPressed = modifiers & NSShiftKeyMask;
+ event. optionKeyPressed = modifiers & NSAlternateKeyMask;
+ event. commandKeyPressed = modifiers & NSCommandKeyMask;
+ try {
+ my d_clickCallback (my d_clickBoss, & event);
+ } catch (MelderError) {
+ Melder_flushError ("Mouse click not completely handled.");
+ }
+ }
+ }
+ - (void) keyDown: (NSEvent *) nsEvent {
+ GuiDrawingArea me = (GuiDrawingArea) d_userData;
+ if (my d_keyCallback) {
+ struct structGuiDrawingAreaKeyEvent event = { me, 0 };
+ event. key = [[nsEvent charactersIgnoringModifiers] characterAtIndex: 0];
+ if (event. key == NSLeftArrowFunctionKey) event. key = 0x2190;
+ if (event. key == NSRightArrowFunctionKey) event. key = 0x2192;
+ if (event. key == NSUpArrowFunctionKey) event. key = 0x2191;
+ if (event. key == NSDownArrowFunctionKey) event. key = 0x2193;
+ trace ("key %d", (int) event. key);
+ NSUInteger modifiers = [nsEvent modifierFlags];
+ event. shiftKeyPressed = modifiers & NSShiftKeyMask;
+ event. optionKeyPressed = modifiers & NSAlternateKeyMask;
+ event. commandKeyPressed = modifiers & NSCommandKeyMask;
+ try {
+ my d_keyCallback (my d_keyBoss, & event);
+ } catch (MelderError) {
+ Melder_flushError ("Key press not completely handled.");
+ }
+ }
+ }
+ @end
#elif win
void _GuiWinDrawingArea_destroy (GuiObject widget) {
iam_drawingarea;
@@ -594,12 +497,13 @@ GuiDrawingArea GuiDrawingArea_create (GuiForm parent, int left, int right, int t
my v_positionInForm (my d_widget, left, right, top, bottom, parent);
gtk_widget_set_double_buffered (GTK_WIDGET (my d_widget), FALSE);
#elif cocoa
-
- GuiCocoaDrawingArea *drawingArea = [GuiCocoaDrawingArea alloc];
+ GuiCocoaDrawingArea *drawingArea = [[GuiCocoaDrawingArea alloc] init];
my d_widget = (GuiObject) drawingArea;
- my v_positionInForm (my d_widget, left, right, top, bottom, parent);
- [drawingArea setUserData:me];
-
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [drawingArea setUserData: me];
+ if (keyCallback) {
+ [[drawingArea window] makeFirstResponder: drawingArea]; // needed in DemoWindow
+ }
#elif win
my d_widget = _Gui_initializeWidget (xmDrawingAreaWidgetClass, parent -> d_widget, L"drawingArea");
_GuiObject_setUserData (my d_widget, me);
@@ -664,17 +568,14 @@ GuiDrawingArea GuiDrawingArea_create (GuiScrolledWindow parent, int width, int h
G_CALLBACK (_GuiGtkDrawingArea_keyCallback), me);
}
g_signal_connect (G_OBJECT (my d_widget), "size-allocate", G_CALLBACK (_GuiGtkDrawingArea_resizeCallback), me);
-
_GuiObject_setUserData (my d_widget, me);
my v_positionInScrolledWindow (my d_widget, width, height, parent);
gtk_widget_set_double_buffered (GTK_WIDGET (my d_widget), FALSE);
#elif cocoa
-
- GuiCocoaDrawingArea *drawingArea = [GuiCocoaDrawingArea alloc];
- my d_widget = (GuiObject) drawingArea;
- my v_positionInScrolledWindow (my d_widget, width, height, parent);
- [drawingArea setUserData:me];
-
+ GuiCocoaDrawingArea *drawingArea = [[GuiCocoaDrawingArea alloc] init];
+ my d_widget = (GuiObject) drawingArea;
+ my v_positionInScrolledWindow (my d_widget, width, height, parent);
+ [drawingArea setUserData: me];
#elif win
my d_widget = _Gui_initializeWidget (xmDrawingAreaWidgetClass, parent -> d_widget, L"drawingArea");
_GuiObject_setUserData (my d_widget, me);
diff --git a/sys/GuiFileSelect.cpp b/sys/GuiFileSelect.cpp
index c50b2ae..3bf2f0b 100644
--- a/sys/GuiFileSelect.cpp
+++ b/sys/GuiFileSelect.cpp
@@ -1,6 +1,6 @@
/* GuiFileSelect.cpp
*
- * Copyright (C) 2010-2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 2010-2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "Gui.h"
+#include "GuiP.h"
#include <locale.h>
#ifdef _WIN32
#include <Shlobj.h>
@@ -52,25 +52,20 @@ SortedSetOfString GuiFileSelect_getInfileNames (GuiWindow parent, const wchar_t
gtk_widget_destroy (GTK_WIDGET (dialog));
setlocale (LC_ALL, "C");
#elif cocoa
-
- (void) parent;
- static structMelderDir dir;
- if (MelderDir_isNull (& dir)) // first time?
- Melder_getDefaultDir (& dir);
-
- NSOpenPanel *openPanel = [NSOpenPanel openPanel];
- [openPanel setTitle:[NSString stringWithUTF8String:Melder_peekWcsToUtf8(title)]];
- [openPanel setAllowsMultipleSelection:allowMultipleFiles];
- [openPanel setCanChooseDirectories:NO];
- [openPanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:Melder_peekWcsToUtf8 (Melder_dirToPath (& dir))]]];
-
- if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
- for (NSURL *url in [openPanel URLs]) {
- my addString (Melder_peekUtf8ToWcs ([[url path] UTF8String]));
- }
- }
-
- #elif defined (macintosh)
+ (void) parent;
+ NSOpenPanel *openPanel = [NSOpenPanel openPanel];
+ [openPanel setTitle: [NSString stringWithUTF8String: Melder_peekWcsToUtf8 (title)]];
+ [openPanel setAllowsMultipleSelection: allowMultipleFiles];
+ [openPanel setCanChooseDirectories: NO];
+ if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
+ for (NSURL *url in [openPanel URLs]) {
+ structMelderFile file = { 0 };
+ Melder_8bitFileRepresentationToWcs_inline ([[url path] UTF8String], file. path);
+ my addString (file. path);
+ }
+ }
+ setlocale (LC_ALL, "en_US");
+ #elif mac
(void) parent;
OSStatus err;
NavDialogRef dialogRef;
@@ -103,7 +98,7 @@ SortedSetOfString GuiFileSelect_getInfileNames (GuiWindow parent, const wchar_t
NavDialogDispose (dialogRef);
}
setlocale (LC_ALL, "en_US");
- #elif defined (_WIN32)
+ #elif win
static OPENFILENAMEW openFileName, dummy;
static wchar_t fullFileName [3000+2];
ZeroMemory (& openFileName, sizeof (OPENFILENAMEW));
@@ -179,7 +174,18 @@ wchar_t * GuiFileSelect_getOutfileName (GuiWindow parent, const wchar_t *title,
gtk_widget_destroy (GTK_WIDGET (dialog));
setlocale (LC_ALL, "C");
#elif cocoa
- #elif defined (macintosh)
+ (void) parent;
+ NSSavePanel *savePanel = [NSSavePanel savePanel];
+ [savePanel setTitle: [NSString stringWithUTF8String: Melder_peekWcsToUtf8 (title)]];
+ [savePanel setNameFieldStringValue: [NSString stringWithUTF8String: Melder_peekWcsToUtf8 (defaultName)]];
+ if ([savePanel runModal] == NSFileHandlingPanelOKButton) {
+ const char *outfileName_utf8 = [[[savePanel URL] path] UTF8String];
+ structMelderFile file = { 0 };
+ Melder_8bitFileRepresentationToWcs_inline (outfileName_utf8, file. path);
+ outfileName = Melder_wcsdup (file. path);
+ }
+ setlocale (LC_ALL, "en_US");
+ #elif mac
(void) parent;
const wchar_t *lastSlash = wcsrchr (defaultName, Melder_DIRECTORY_SEPARATOR);
OSStatus err;
@@ -227,7 +233,7 @@ wchar_t * GuiFileSelect_getOutfileName (GuiWindow parent, const wchar_t *title,
NavDialogDispose (dialogRef);
}
setlocale (LC_ALL, "en_US");
- #elif defined (_WIN32)
+ #elif win
OPENFILENAMEW openFileName;
static wchar_t customFilter [100+2];
static wchar_t fullFileName [300+2];
@@ -274,7 +280,23 @@ wchar_t * GuiFileSelect_getDirectoryName (GuiWindow parent, const wchar_t *title
gtk_widget_destroy (GTK_WIDGET (dialog));
setlocale (LC_ALL, "C");
#elif cocoa
- #elif defined (macintosh)
+ (void) parent;
+ NSOpenPanel *openPanel = [NSOpenPanel openPanel];
+ [openPanel setTitle: [NSString stringWithUTF8String: Melder_peekWcsToUtf8 (title)]];
+ [openPanel setAllowsMultipleSelection: NO];
+ [openPanel setCanChooseDirectories: YES];
+ [openPanel setCanChooseFiles: NO];
+ [openPanel setPrompt: @"Choose"];
+ if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
+ for (NSURL *url in [openPanel URLs]) {
+ const char *directoryName_utf8 = [[url path] UTF8String];
+ structMelderDir dir = { 0 };
+ Melder_8bitFileRepresentationToWcs_inline (directoryName_utf8, dir. path);
+ directoryName = Melder_wcsdup (dir. path);
+ }
+ }
+ setlocale (LC_ALL, "en_US");
+ #elif mac
(void) parent;
OSStatus err;
NavDialogRef dialogRef;
@@ -306,7 +328,7 @@ wchar_t * GuiFileSelect_getDirectoryName (GuiWindow parent, const wchar_t *title
NavDialogDispose (dialogRef);
}
setlocale (LC_ALL, "en_US");
- #elif defined (_WIN32)
+ #elif win
static wchar_t fullFileName [3000+2];
static bool comInited = false;
if (! comInited) {
diff --git a/sys/GuiLabel.cpp b/sys/GuiLabel.cpp
index 24f1566..56c284a 100644
--- a/sys/GuiLabel.cpp
+++ b/sys/GuiLabel.cpp
@@ -1,6 +1,6 @@
/* GuiLabel.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2007 Stefan de Konink
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2007 Stefan de Konink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@ Thing_implement (GuiLabel, GuiControl, 0);
- (void) dealloc { // override
GuiLabel me = d_userData;
forget (me);
- Melder_casual ("deleting a label");
+ trace ("deleting a label");
[super dealloc];
}
- (GuiThing) userData {
@@ -83,19 +83,26 @@ GuiLabel GuiLabel_create (GuiForm parent, int left, int right, int top, int bott
gtk_misc_set_alignment (GTK_MISC (my d_widget), flags & GuiLabel_RIGHT ? 1.0 : flags & GuiLabel_CENTRE ? 0.5 : 0.0, 0.5);
#elif cocoa
trace ("create");
- my d_widget = [[GuiCocoaLabel alloc] init];
+ GuiCocoaLabel *label = [[GuiCocoaLabel alloc] init];
+ my d_widget = label;
trace ("position");
my v_positionInForm (my d_widget, left, right, top, bottom, parent);
trace ("set user data");
- [(GuiCocoaLabel *) my d_widget setUserData: me];
+ [label setUserData: me];
trace ("set bezel style");
- [(NSTextField *) my d_widget setBezelStyle: NSRoundedBezelStyle];
+ [label setBezelStyle: NSRoundedBezelStyle];
trace ("set bordered");
- [(NSTextField *) my d_widget setBordered: NO];
+ [label setBordered: NO];
trace ("set selectable");
- [(NSTextField *) my d_widget setSelectable: NO];
+ [label setSelectable: NO];
trace ("title");
- [(NSTextField *) my d_widget setTitleWithMnemonic: (NSString *) Melder_peekWcsToCfstring (labelText)];
+ [label setTitleWithMnemonic: (NSString *) Melder_peekWcsToCfstring (labelText)];
+ [label setAlignment:( flags & GuiLabel_RIGHT ? NSRightTextAlignment : flags & GuiLabel_CENTRE ? NSCenterTextAlignment : NSLeftTextAlignment )];
+ static NSFont *theLabelFont;
+ if (! theLabelFont) {
+ theLabelFont = [NSFont systemFontOfSize: 13.0];
+ }
+ [label setFont: theLabelFont];
#elif win
my d_widget = _Gui_initializeWidget (xmLabelWidgetClass, parent -> d_widget, labelText);
_GuiObject_setUserData (my d_widget, me);
diff --git a/sys/GuiList.cpp b/sys/GuiList.cpp
index b17dfbe..addd16b 100644
--- a/sys/GuiList.cpp
+++ b/sys/GuiList.cpp
@@ -1,6 +1,6 @@
/* GuiList.cpp
*
- * Copyright (C) 1993-2011,2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1993-2011,2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -47,7 +47,6 @@ Thing_implement (GuiList, GuiControl, 0);
#define CELL_HEIGHT 15
#elif mac
#define CELL_HEIGHT 18
- #define USE_MAC_LISTBOX_CONTROL 0
#endif
#if gtk
@@ -57,94 +56,115 @@ Thing_implement (GuiList, GuiControl, 0);
}
static void _GuiGtkList_selectionChangedCallback (GtkTreeSelection *sel, gpointer void_me) {
iam (GuiList);
- if (my d_selectionChangedCallback != NULL && ! my d_blockSelectionChangedCallback) {
+ if (my d_selectionChangedCallback != NULL && ! my d_blockValueChangedCallbacks) {
//Melder_casual ("Selection changed.");
struct structGuiListEvent event = { me };
my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
}
}
#elif cocoa
- at implementation GuiCocoaList {
- GuiList d_userData;
- NSMutableArray *items;
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
- self = [super initWithFrame:frameRect];
- if (self) {
- _tableView = [[NSTableView alloc] initWithFrame:frameRect];
- NSTableColumn *tc = [[NSTableColumn alloc] initWithIdentifier:@"list"];
- tc.width = frameRect.size.width;
- [_tableView addTableColumn:tc];
-
- _tableView.delegate = self;
- _tableView.dataSource = self;
- _tableView.allowsEmptySelection = YES;
- _tableView.headerView = nil;
- _tableView.target = self;
- _tableView.action = @selector(clicked:);
-
- NSScrollView *sv = [[NSScrollView alloc] initWithFrame:frameRect];
- [sv setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [sv setBorderType:NSGrooveBorder];
- [sv setDocumentView:_tableView];
- [sv setHasVerticalScroller:YES];
-
- [self addSubview:sv];
- [sv release];
- [_tableView release];
-
- _contents = [[NSMutableArray alloc] init];
- }
- return self;
-}
-
-- (void)setAllowMultipleSelection:(BOOL)allowMultipleSelection {
- _tableView.allowsMultipleSelection = allowMultipleSelection;
-}
-
-- (void) dealloc {
- [_contents release];
- GuiThing me = d_userData;
- forget (me);
- Melder_casual ("deleting a list");
- [super dealloc];
-}
-
-- (GuiThing) userData {
- return d_userData;
-}
-
-- (void) setUserData: (GuiThing) userData {
- Melder_assert (userData == NULL || Thing_member (userData, classGuiList));
- d_userData = static_cast <GuiList> (userData);
-}
-
+ @implementation GuiCocoaList {
+ GuiList d_userData;
+ }
-- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
-#pragma unused (tableView)
- return [_contents count];
-}
+ /*
+ * Override NSObject methods.
+ */
+ - (void) dealloc {
+ [_contents release];
+ GuiThing me = d_userData;
+ forget (me);
+ Melder_casual ("deleting a list");
+ [super dealloc];
+ }
-- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
-#pragma unused (tableColumn, tableView)
- return [_contents objectAtIndex:row];
-}
+ /*
+ * Override NSView methods.
+ */
+ - (id) initWithFrame: (NSRect) frameRect {
+ self = [super initWithFrame: frameRect];
+ if (self) {
+ _tableView = [[NSTableView alloc] initWithFrame: frameRect];
+ Melder_assert ([_tableView retainCount] == 1); // this asserts that ARC is off (if ARC were on, the retain count would be 2, because tableView is a retain property)
+ NSTableColumn *tc = [[NSTableColumn alloc] initWithIdentifier: @"list"];
+ tc.width = frameRect. size. width;
+ [tc setEditable: NO];
+ [_tableView addTableColumn: tc];
+
+ _tableView. delegate = self;
+ _tableView. dataSource = self;
+ _tableView. allowsEmptySelection = YES;
+ _tableView. headerView = nil;
+ _tableView. target = self;
+ _tableView. action = @selector (_GuiCocoaList_clicked:);
+
+ NSScrollView *sv = [[NSScrollView alloc] initWithFrame: frameRect];
+ [sv setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
+ [sv setBorderType: NSGrooveBorder];
+ [sv setDocumentView: _tableView]; // this retains the table view
+ [sv setHasVerticalScroller: YES];
+ //[sv setHasHorizontalScroller: YES];
+
+ [self addSubview: sv]; // this retains the scroll view
+ //Melder_assert ([sv retainCount] == 2); // not always true on 10.6
+ [sv release];
+ Melder_assert ([_tableView retainCount] == 2);
+ [_tableView release];
+
+ _contents = [[NSMutableArray alloc] init];
+ }
+ return self;
+ }
-- (IBAction)clicked:(id)sender {
-#pragma unused (sender)
- GuiList me = (GuiList)d_userData;
+ /*
+ * Implement GuiCocoaAny protocol.
+ */
+ - (GuiThing) userData {
+ return d_userData;
+ }
+ - (void) setUserData: (GuiThing) userData {
+ Melder_assert (userData == NULL || Thing_member (userData, classGuiList));
+ d_userData = static_cast <GuiList> (userData);
+ }
- if (me) {
- if (me -> d_selectionChangedCallback) {
- struct structGuiListEvent event = { me };
- me -> d_selectionChangedCallback (me -> d_selectionChangedBoss, & event);
- }
- }
+ /*
+ * Implement GuiCocaList methods.
+ */
+ - (IBAction) _GuiCocoaList_clicked: (id) sender {
+ (void) sender;
+ GuiList me = d_userData;
+ if (me && my d_selectionChangedCallback) {
+ struct structGuiListEvent event = { me };
+ my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
+ }
+ }
-}
- at end
+ /*
+ * Override TableViewDataSource methods.
+ */
+ - (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView {
+ (void) tableView;
+ return [_contents count];
+ }
+ - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row {
+ (void) tableColumn;
+ (void) tableView;
+ return [_contents objectAtIndex: row];
+ }
+ /*
+ * Override TableViewDelegate methods.
+ */
+ - (void) tableViewSelectionDidChange: (NSNotification *) notification {
+ (void) notification;
+ trace ("enter");
+ GuiList me = d_userData;
+ if (me && my d_selectionChangedCallback && ! my d_blockValueChangedCallbacks) {
+ struct structGuiListEvent event = { me };
+ my d_selectionChangedCallback (my d_selectionChangedBoss, & event);
+ }
+ }
+ @end
#elif win
void _GuiWinList_destroy (GuiObject widget) {
iam_list;
@@ -410,13 +430,11 @@ GuiList GuiList_create (GuiForm parent, int left, int right, int top, int bottom
my v_positionInForm (scrolled, left, right, top, bottom, parent);
g_signal_connect (sel, "changed", G_CALLBACK (_GuiGtkList_selectionChangedCallback), me);
#elif cocoa
-
- GuiCocoaList *list = [GuiCocoaList alloc];
- my d_widget = (GuiObject) list;
- my v_positionInForm (my d_widget, left, right, top, bottom, parent);
- [list setAllowMultipleSelection:allowMultipleSelection];
- [list setUserData:me];
-
+ GuiCocoaList *list = [[GuiCocoaList alloc] init];
+ my d_widget = (GuiObject) list;
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [[list tableView] setAllowsMultipleSelection: allowMultipleSelection];
+ [list setUserData:me];
#elif win
my d_widget = _Gui_initializeWidget (xmListWidgetClass, parent -> d_widget, L"list");
_GuiObject_setUserData (my d_widget, me);
@@ -465,17 +483,14 @@ GuiList GuiList_createShown (GuiForm parent, int left, int right, int top, int b
}
void structGuiList :: f_deleteAllItems () {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
- d_blockSelectionChangedCallback = true;
GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget)));
gtk_list_store_clear (list_store);
- d_blockSelectionChangedCallback = false;
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
[list.contents removeAllObjects];
[list.tableView reloadData];
-
#elif win
ListBox_ResetContent (d_widget -> window);
#elif mac
@@ -486,20 +501,17 @@ void structGuiList :: f_deleteAllItems () {
}
void structGuiList :: f_deleteItem (long position) {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
- d_blockSelectionChangedCallback = true;
GtkTreeIter iter;
GtkTreeModel *tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget));
if (gtk_tree_model_iter_nth_child (tree_model, & iter, NULL, (gint) (position - 1))) {
gtk_list_store_remove (GTK_LIST_STORE (tree_model), & iter);
}
- d_blockSelectionChangedCallback = false;
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- [list.contents removeObjectAtIndex:position - 1];
- [list.tableView reloadData];
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ [list. contents removeObjectAtIndex: position - 1];
+ [list. tableView reloadData];
#elif win
ListBox_DeleteString (d_widget -> window, position - 1);
#elif mac
@@ -512,16 +524,13 @@ void structGuiList :: f_deleteItem (long position) {
}
void structGuiList :: f_deselectAllItems () {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
- d_blockSelectionChangedCallback = true;
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d_widget));
gtk_tree_selection_unselect_all (selection);
- d_blockSelectionChangedCallback = false;
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- [list.tableView deselectAll:nil];
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ [list.tableView deselectAll:nil];
#elif win
ListBox_SetSel (d_widget -> window, False, -1);
#elif mac
@@ -534,8 +543,8 @@ void structGuiList :: f_deselectAllItems () {
}
void structGuiList :: f_deselectItem (long position) {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
- d_blockSelectionChangedCallback = true;
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d_widget));
/* GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget)));
GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position);*/
@@ -546,12 +555,9 @@ void structGuiList :: f_deselectItem (long position) {
if (gtk_tree_model_iter_nth_child (tree_model, & iter, NULL, (gint) (position - 1))) {
gtk_tree_selection_unselect_iter (selection, & iter);
}
- d_blockSelectionChangedCallback = false;
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- [list.tableView deselectRow:position - 1];
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ [list. tableView deselectRow: position - 1];
#elif win
ListBox_SetSel (d_widget -> window, False, position - 1);
#elif mac
@@ -587,17 +593,15 @@ long * structGuiList :: f_getSelectedPositions (long *numberOfSelectedPositions)
}
return selectedPositions;
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- NSIndexSet *indexSet = [list.tableView selectedRowIndexes];
- *numberOfSelectedPositions = 0;
- selectedPositions = NUMvector <long> (1, [indexSet count]);
- NSUInteger currentIndex = [indexSet firstIndex];
- while (currentIndex != NSNotFound) {
- selectedPositions [++ *numberOfSelectedPositions] = currentIndex + 1;
- currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
- }
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ NSIndexSet *indexSet = [list. tableView selectedRowIndexes];
+ *numberOfSelectedPositions = 0;
+ selectedPositions = NUMvector <long> (1, [indexSet count]);
+ NSUInteger currentIndex = [indexSet firstIndex];
+ while (currentIndex != NSNotFound) {
+ selectedPositions [++ *numberOfSelectedPositions] = currentIndex + 1;
+ currentIndex = [indexSet indexGreaterThanIndex: currentIndex];
+ }
#elif win
int n = ListBox_GetSelCount (d_widget -> window), *indices;
if (n == 0) {
@@ -674,10 +678,8 @@ long structGuiList :: f_getNumberOfItems () {
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget));
numberOfItems = gtk_tree_model_iter_n_children (model, NULL);
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- numberOfItems = [list.contents count];
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ numberOfItems = [[list contents] count];
#elif win
numberOfItems = ListBox_GetCount (d_widget -> window);
#elif mac
@@ -711,27 +713,28 @@ long structGuiList :: f_getTopPosition () {
}
void structGuiList :: f_insertItem (const wchar_t *itemText, long position) {
+ GuiControlBlockValueChangedCallbacks block (this);
/*
* 'position' is the position of the new item in the list after insertion:
* a value of 1 therefore puts the new item at the top of the list;
* a value of 0 is special: the item is put at the bottom of the list.
*/
#if gtk
- d_blockSelectionChangedCallback = true;
GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget)));
gtk_list_store_insert_with_values (list_store, NULL, (gint) position - 1, COLUMN_STRING, Melder_peekWcsToUtf8 (itemText), -1);
- d_blockSelectionChangedCallback = false;
// TODO: Tekst opsplitsen
// does GTK know the '0' trick?
// it does know about NULL, to append in another function
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- const char *itemText_utf8 = Melder_peekWcsToUtf8 (itemText);
- NSString *string = [NSString stringWithUTF8String:itemText_utf8];
- [list.contents insertObject:string atIndex:position - 1];
- [list.tableView reloadData];
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ NSString *nsString = [[NSString alloc] initWithUTF8String: Melder_peekWcsToUtf8 (itemText)];
+ if (position)
+ [[list contents] insertObject: nsString atIndex: position - 1]; // cocoa lists start with item 0
+ else
+ [[list contents] addObject: nsString]; // insert at end
+ //Melder_assert ([nsString retainCount] == 2);
+ [nsString release];
+ [[list tableView] reloadData];
#elif win
if (position)
ListBox_InsertString (d_widget -> window, position - 1, itemText); // win lists start with item 0
@@ -754,14 +757,13 @@ void structGuiList :: f_insertItem (const wchar_t *itemText, long position) {
}
void structGuiList :: f_replaceItem (const wchar_t *itemText, long position) {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
- d_blockSelectionChangedCallback = true;
GtkTreeIter iter;
GtkTreeModel *tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget));
if (gtk_tree_model_iter_nth_child (tree_model, & iter, NULL, (gint) (position - 1))) {
gtk_list_store_set (GTK_LIST_STORE (tree_model), & iter, COLUMN_STRING, Melder_peekWcsToUtf8 (itemText), -1);
}
- d_blockSelectionChangedCallback = false;
/*
GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position);
GtkTreeIter iter;
@@ -771,13 +773,12 @@ void structGuiList :: f_replaceItem (const wchar_t *itemText, long position) {
// gtk_list_store_set (list_store, & iter, 0, Melder_peekWcsToUtf8 (itemText), -1);
// TODO: Tekst opsplitsen
#elif cocoa
-
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- const char *itemText_utf8 = Melder_peekWcsToUtf8 (itemText);
- NSString *string = [NSString stringWithUTF8String:itemText_utf8];
- [list.contents replaceObjectAtIndex:position - 1 withObject:string];
- [list.tableView reloadData];
-
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ NSString *nsString = [[NSString alloc] initWithUTF8String: Melder_peekWcsToUtf8 (itemText)];
+ [[list contents] replaceObjectAtIndex: position - 1 withObject: nsString];
+ Melder_assert ([nsString retainCount] == 2);
+ [nsString release];
+ [[list tableView] reloadData];
#elif win
long nativePosition = position - 1; // convert from 1-based to zero-based
ListBox_DeleteString (d_widget -> window, nativePosition);
@@ -795,13 +796,12 @@ void structGuiList :: f_replaceItem (const wchar_t *itemText, long position) {
}
void structGuiList :: f_selectItem (long position) {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
- d_blockSelectionChangedCallback = true;
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d_widget));
GtkTreePath *path = gtk_tree_path_new_from_indices ((gint) position - 1, -1);
gtk_tree_selection_select_path (selection, path);
gtk_tree_path_free (path);
- d_blockSelectionChangedCallback = false;
// TODO: check of het bovenstaande werkt, dan kan dit weg
// GtkListStore *list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (d_widget)));
@@ -810,11 +810,10 @@ void structGuiList :: f_selectItem (long position) {
// gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), & iter, path);
// gtk_tree_selection_select_iter (selection, & iter);
#elif cocoa
-
- NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:position + 1];
- GuiCocoaList *list = (GuiCocoaList*)d_widget;
- [list.tableView selectRowIndexes:indexSet byExtendingSelection:NO];
-
+ NSIndexSet *indexSet = [[NSIndexSet alloc] initWithIndex: position - 1];
+ GuiCocoaList *list = (GuiCocoaList *) d_widget;
+ [[list tableView] selectRowIndexes: indexSet byExtendingSelection: d_allowMultipleSelection];
+ [indexSet release];
#elif win
if (! d_allowMultipleSelection) {
ListBox_SetCurSel (d_widget -> window, position - 1);
diff --git a/sys/GuiMenu.cpp b/sys/GuiMenu.cpp
index 0a49aa1..1a94c6a 100644
--- a/sys/GuiMenu.cpp
+++ b/sys/GuiMenu.cpp
@@ -46,6 +46,10 @@ void structGuiMenu :: v_destroy () {
gtk_widget_destroy (GTK_WIDGET (my d_widget));
}
#elif cocoa
+ static void (*theOpenDocumentCallback) (MelderFile file);
+ void Gui_setOpenDocumentCallback (void (*openDocumentCallback) (MelderFile file)) {
+ theOpenDocumentCallback = openDocumentCallback;
+ }
static NSMenu *theMenuBar;
static int theNumberOfMenuBarItems = 0;
static NSMenuItem *theMenuBarItems [30];
@@ -60,6 +64,16 @@ void structGuiMenu :: v_destroy () {
[theMenuBarItems [imenu] release]; // ... so we can release the item
}
}
+ - (void) application: (NSApplication *) sender openFiles: (NSArray *) fileNames
+ {
+ for (int i = 1; i <= [fileNames count]; i ++) {
+ NSString *cocoaFileName = [fileNames objectAtIndex: i - 1];
+ structMelderFile file = { 0 };
+ Melder_8bitFileRepresentationToWcs_inline ([cocoaFileName UTF8String], file. path);
+ if (theOpenDocumentCallback)
+ theOpenDocumentCallback (& file);
+ }
+ }
@end
static id theGuiCocoaApplicationDelegate;
#elif motif
@@ -139,7 +153,7 @@ void structGuiMenu :: f_empty () {
- (void) dealloc { // override
GuiMenu me = d_userData;
forget (me);
- trace ("deleting a button");
+ trace ("deleting a menu button");
[super dealloc];
}
- (GuiThing) userData {
@@ -156,7 +170,7 @@ void structGuiMenu :: f_empty () {
- (void) dealloc { // override
GuiMenu me = d_userData;
forget (me);
- trace ("deleting a menu item");
+ trace ("deleting a menu");
[super dealloc];
}
- (GuiThing) userData {
@@ -221,7 +235,7 @@ GuiMenu GuiMenu_createInWindow (GuiWindow window, const wchar_t *title, long fla
int parentWidth = parentRect.size.width, parentHeight = parentRect.size.height;
if (window -> d_menuBarWidth == 0)
window -> d_menuBarWidth = -1;
- int width = 18 + 7 * wcslen (title), height = 25;
+ int width = 18 + 7 * wcslen (title), height = 35 /*25*/;
int x = window -> d_menuBarWidth, y = parentHeight + 1 - height;
NSUInteger resizingMask = NSViewMinYMargin;
if (Melder_wcsequ (title, L"Help")) {
@@ -237,9 +251,10 @@ GuiMenu GuiMenu_createInWindow (GuiWindow window, const wchar_t *title, long fla
[my d_cocoaMenuButton setBezelStyle: NSShadowlessSquareBezelStyle];
[my d_cocoaMenuButton setImagePosition: NSImageAbove]; // this centers the text
//[nsPopupButton setBordered: NO];
- [my d_cocoaMenuButton setAutoresizingMask:resizingMask]; // stick to top
+ [my d_cocoaMenuButton setAutoresizingMask: resizingMask]; // stick to top
[[my d_cocoaMenuButton cell] setArrowPosition: NSPopUpNoArrow /*NSPopUpArrowAtBottom*/];
+ [[my d_cocoaMenuButton cell] setPreferredEdge: NSMaxYEdge];
/*
* Apparently, Cocoa swallows title setting only if there is already a menu with a dummy item.
*/
@@ -406,7 +421,7 @@ GuiMenu GuiMenu_createInForm (GuiForm form, int left, int right, int top, int bo
_GuiObject_setUserData (my d_widget, me);
_GuiObject_setUserData (my d_cascadeButton -> d_widget, me);
#elif cocoa
- my d_cascadeButton -> d_widget = my d_cocoaMenuButton = [GuiCocoaMenuButton alloc];
+ my d_cascadeButton -> d_widget = my d_cocoaMenuButton = [[GuiCocoaMenuButton alloc] init];
my d_cascadeButton -> v_positionInForm (my d_cocoaMenuButton, left, right, top, bottom, form);
[my d_cocoaMenuButton setUserData: me];
[my d_cocoaMenuButton setPullsDown: YES];
diff --git a/sys/GuiMenuItem.cpp b/sys/GuiMenuItem.cpp
index 2137e03..53cb4ca 100644
--- a/sys/GuiMenuItem.cpp
+++ b/sys/GuiMenuItem.cpp
@@ -198,19 +198,21 @@ GuiMenuItem GuiMenu_addItem (GuiMenu menu, const wchar_t *title, long flags,
gtk_menu_shell_append (GTK_MENU_SHELL (menu -> d_widget), GTK_WIDGET (my d_widget));
_GuiObject_setUserData (my d_widget, me);
#elif cocoa
- NSString *string = (NSString *) Melder_peekWcsToCfstring (title);
+ NSString *string = (NSString *) Melder_peekWcsToCfstring (title);
GuiCocoaMenuItem *menuItem = [[GuiCocoaMenuItem alloc]
initWithTitle:string
action: NULL
keyEquivalent: @""];
- my d_widget = menuItem;
+ //Melder_assert ([string retainCount] == 2 || [string retainCount] == -1); // the menu item retains the string (assertion can fail on 10.6)
+ trace ("string retain count = %d", (int) [string retainCount]);
+ my d_widget = menuItem;
trace ("installing item in GuiMenu %p (NSMenu %p); retain count = %d", menu, menu -> d_cocoaMenu, [menuItem retainCount]);
[menu -> d_cocoaMenu addItem: (NSMenuItem *) my d_widget]; // the menu will retain the item...
trace ("installed item in GuiMenu %p (NSMenu %p); retain count = %d", menu, menu -> d_cocoaMenu, [menuItem retainCount]);
trace ("release the item");
[menuItem release]; // ... so we can release the item already
trace ("set user data");
- [menuItem setUserData:me];
+ [menuItem setUserData: me];
#elif motif
my d_widget = XtVaCreateManagedWidget (Melder_peekWcsToUtf8 (title),
toggle ? xmToggleButtonGadgetClass : xmPushButtonGadgetClass, menu -> d_widget, NULL);
@@ -227,7 +229,7 @@ GuiMenuItem GuiMenu_addItem (GuiMenu menu, const wchar_t *title, long flags,
#if gtk
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (my d_widget), TRUE);
#elif cocoa
- [menuItem setState:NSOnState];
+ [menuItem setState: NSOnState];
#elif motif
XmToggleButtonGadgetSetState (my d_widget, True, False);
#endif
@@ -267,19 +269,28 @@ GuiMenuItem GuiMenu_addItem (GuiMenu menu, const wchar_t *title, long flags,
ag, key, modifiers, GTK_ACCEL_VISIBLE);
#elif cocoa
-
- NSUInteger mask = 0;
- if (flags & GuiMenu_COMMAND) mask |= NSCommandKeyMask;
- if (flags & GuiMenu_SHIFT) mask |= NSShiftKeyMask;
- if (flags & GuiMenu_OPTION) mask |= NSAlternateKeyMask;
- [menuItem setKeyEquivalentModifierMask:mask];
- [menuItem setKeyEquivalent:[NSString stringWithFormat:@"%c", accelerator]];
-
+ accelerator = tolower (accelerator); // otherwise, a Shift key is introduced in the mask
+ NSUInteger mask = 0;
+ if (flags & GuiMenu_COMMAND) mask |= NSCommandKeyMask;
+ if (flags & GuiMenu_SHIFT) mask |= NSShiftKeyMask;
+ if (flags & GuiMenu_OPTION) mask |= NSAlternateKeyMask;
+ [menuItem setKeyEquivalentModifierMask: mask];
+ if (accelerator > 0 && accelerator < 32) {
+ static unichar acceleratorKeys [] = { 0,
+ NSLeftArrowFunctionKey, NSRightArrowFunctionKey, NSUpArrowFunctionKey, NSDownArrowFunctionKey, NSPauseFunctionKey, NSDeleteFunctionKey, NSInsertFunctionKey, NSBackspaceCharacter,
+ NSTabCharacter, NSNewlineCharacter, NSHomeFunctionKey, NSEndFunctionKey, NSCarriageReturnCharacter, NSPageUpFunctionKey, NSPageDownFunctionKey, 27,
+ NSF1FunctionKey, NSF2FunctionKey, NSF3FunctionKey, NSF4FunctionKey, NSF5FunctionKey, NSF6FunctionKey,
+ NSF7FunctionKey, NSF8FunctionKey, NSF9FunctionKey, NSF10FunctionKey, NSF11FunctionKey, NSF12FunctionKey,
+ 0, 0, 0 };
+ [menuItem setKeyEquivalent: [NSString stringWithCharacters: & acceleratorKeys [accelerator] length: 1]];
+ } else {
+ [menuItem setKeyEquivalent: [NSString stringWithFormat: @"%c", accelerator]];
+ }
#elif motif
int modifiers = 0;
if (flags & GuiMenu_COMMAND) modifiers |= _motif_COMMAND_MASK;
- if (flags & GuiMenu_SHIFT) modifiers |= _motif_SHIFT_MASK;
- if (flags & GuiMenu_OPTION) modifiers |= _motif_OPTION_MASK;
+ if (flags & GuiMenu_SHIFT) modifiers |= _motif_SHIFT_MASK;
+ if (flags & GuiMenu_OPTION) modifiers |= _motif_OPTION_MASK;
if (accelerator > 0 && accelerator < 32) {
if (my d_widget -> shell) {
my d_widget -> shell -> motiff.shell.lowAccelerators [modifiers] |= 1 << accelerator;
@@ -388,6 +399,8 @@ void structGuiMenuItem :: f_check (bool check) {
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (d_widget), check);
d_callbackBlocked = false;
#elif cocoa
+ GuiCocoaMenuItem *item = (GuiCocoaMenuItem*)d_widget;
+ [item setState: check];
#elif motif
XmToggleButtonGadgetSetState (d_widget, check, False);
#endif
diff --git a/sys/GuiObject.cpp b/sys/GuiObject.cpp
index 6876ff2..34f7e18 100644
--- a/sys/GuiObject.cpp
+++ b/sys/GuiObject.cpp
@@ -53,7 +53,20 @@ void GuiObject_destroy (GuiObject widget) {
#if gtk
gtk_widget_destroy (GTK_WIDGET (widget));
#elif cocoa
- [(GuiCocoaView *) widget release];
+ if ([widget isKindOfClass: [NSMenuItem class]]) {
+ NSMenuItem *cocoaMenuItem = (NSMenuItem *) widget;
+ [[cocoaMenuItem menu] removeItem: cocoaMenuItem]; // this also releases the item
+ } else {
+ Melder_assert ([widget isKindOfClass: [NSView class]]);
+ NSView *cocoaView = (NSView *) widget;
+ if (cocoaView == [[cocoaView window] contentView]) {
+ [[cocoaView window] orderOut: nil];
+ [[cocoaView window] close];
+ [[cocoaView window] release];
+ } else {
+ [cocoaView removeFromSuperview]; // this also releases the view
+ }
+ }
#elif motif
XtDestroyWidget (widget);
#endif
diff --git a/sys/GuiOptionMenu.cpp b/sys/GuiOptionMenu.cpp
index c2f52e2..d8a819e 100644
--- a/sys/GuiOptionMenu.cpp
+++ b/sys/GuiOptionMenu.cpp
@@ -1,6 +1,6 @@
/* GuiOptionMenu.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2007 Stefan de Konink, 2013 Tom Naughton
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2007 Stefan de Konink, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,7 +49,7 @@ Thing_implement (GuiOptionMenu, GuiControl, 0);
forget (my d_options);
forget (me);
- Melder_casual ("deleting an option menu");
+ trace ("deleting an option menu");
[super dealloc];
}
- (GuiThing) userData {
@@ -91,7 +91,7 @@ void structGuiOptionMenu :: f_init (GuiForm parent, int left, int right, int top
GTK_WIDGET_UNSET_FLAGS (d_widget, GTK_CAN_DEFAULT);
#elif cocoa
- GuiCocoaOptionMenu *optionMenu = [GuiCocoaOptionMenu alloc];
+ GuiCocoaOptionMenu *optionMenu = [[GuiCocoaOptionMenu alloc] init];
d_widget = (GuiObject) optionMenu;
v_positionInForm (d_widget, left, right, top, bottom, parent);
diff --git a/sys/GuiP.h b/sys/GuiP.h
index db04962..251c5ed 100644
--- a/sys/GuiP.h
+++ b/sys/GuiP.h
@@ -2,7 +2,7 @@
#define _GuiP_h_
/* GuiP.h
*
- * Copyright (C) 1993-2011,2012 Paul Boersma
+ * Copyright (C) 1993-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,6 +44,18 @@ void _GuiObject_position (GuiObject me, int left, int right, int top, int bottom
void * _GuiObject_getUserData (GuiObject me);
void _GuiObject_setUserData (GuiObject me, void *userData);
+class GuiControlBlockValueChangedCallbacks {
+ private:
+ GuiControl d_control;
+ public:
+ GuiControlBlockValueChangedCallbacks (GuiControl control) : d_control (control) {
+ d_control -> d_blockValueChangedCallbacks = true;
+ }
+ ~GuiControlBlockValueChangedCallbacks () {
+ d_control -> d_blockValueChangedCallbacks = false;
+ }
+};
+
#if gtk
void GuiGtk_initialize ();
#elif motif
diff --git a/sys/GuiProgressBar.cpp b/sys/GuiProgressBar.cpp
index d08fc9d..f6c5a3e 100644
--- a/sys/GuiProgressBar.cpp
+++ b/sys/GuiProgressBar.cpp
@@ -1,6 +1,6 @@
/* GuiProgressBar.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2008 Stefan de Konink
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2008 Stefan de Konink
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,23 @@ Thing_implement (GuiProgressBar, GuiControl, 0);
Melder_free (me);
}
#elif cocoa
+ @implementation GuiCocoaProgressBar {
+ GuiProgressBar d_userData;
+ }
+ - (void) dealloc { // override
+ GuiProgressBar me = d_userData;
+ forget (me);
+ trace ("deleting a progress bar");
+ [super dealloc];
+ }
+ - (GuiThing) userData {
+ return d_userData;
+ }
+ - (void) setUserData: (GuiThing) userData {
+ Melder_assert (userData == NULL || Thing_member (userData, classGuiProgressBar));
+ d_userData = static_cast <GuiProgressBar> (userData);
+ }
+ @end
#elif motif
static void _guiMotifProgressBar_destroyCallback (GuiObject widget, XtPointer void_me, XtPointer call) {
(void) widget; (void) call;
@@ -48,6 +65,12 @@ GuiProgressBar GuiProgressBar_create (GuiForm parent, int left, int right, int t
_GuiObject_setUserData (my d_widget, me);
my v_positionInForm (my d_widget, left, right, top, bottom, parent);
#elif cocoa
+ my d_cocoaProgressBar = [[GuiCocoaProgressBar alloc] init];
+ my d_widget = my d_cocoaProgressBar;
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [my d_cocoaProgressBar setUserData: me];
+ [my d_cocoaProgressBar setIndeterminate: false];
+ [my d_cocoaProgressBar setMaxValue: 1.0];
#elif motif
my d_widget = XmCreateScale (parent -> d_widget, "scale", NULL, 0);
_GuiObject_setUserData (my d_widget, me);
@@ -84,6 +107,7 @@ void structGuiProgressBar :: f_setValue (double value) {
#if gtk
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (d_widget), value);
#elif cocoa
+ [d_cocoaProgressBar setDoubleValue: value];
#elif motif
XmScaleSetValue (d_widget, round (value * 10000));
#endif
diff --git a/sys/GuiRadioButton.cpp b/sys/GuiRadioButton.cpp
index 32f8b81..3dde9f5 100644
--- a/sys/GuiRadioButton.cpp
+++ b/sys/GuiRadioButton.cpp
@@ -1,6 +1,6 @@
/* GuiRadioButton.cpp
*
- * Copyright (C) 1993-2011,2012 Paul Boersma
+ * Copyright (C) 1993-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,14 +59,51 @@ static int _GuiRadioButton_getPosition (GuiRadioButton me) {
static void _GuiGtkRadioButton_handleToggle (GuiObject widget, gpointer void_me) {
iam (GuiRadioButton);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
- struct structGuiRadioButtonEvent event = { me };
- event. position = _GuiRadioButton_getPosition (me);
- if (my d_valueChangedCallback != NULL) {
+ if (my d_valueChangedCallback != NULL && ! my d_blockValueChangedCallbacks) {
+ struct structGuiRadioButtonEvent event = { me };
+ event. position = _GuiRadioButton_getPosition (me);
my d_valueChangedCallback (my d_valueChangedBoss, & event);
}
}
}
#elif cocoa
+ @implementation GuiCocoaRadioButton {
+ GuiRadioButton d_userData;
+ }
+ - (void) dealloc { // override
+ GuiRadioButton me = d_userData;
+ forget (me);
+ trace ("deleting a radio button");
+ [super dealloc];
+ }
+ - (GuiThing) userData {
+ return d_userData;
+ }
+ - (void) setUserData: (GuiThing) userData {
+ Melder_assert (userData == NULL || Thing_member (userData, classGuiRadioButton));
+ d_userData = static_cast <GuiRadioButton> (userData);
+ }
+ - (void) _guiCocoaRadioButton_activateCallback: (id) widget {
+ trace ("enter");
+ Melder_assert (self == widget); // sender (widget) and receiver (self) happen to be the same object
+ GuiRadioButton me = d_userData;
+ /*
+ * Deselect the sister buttons.
+ */
+ for (GuiRadioButton sibling = my d_previous; sibling != NULL; sibling = sibling -> d_previous) {
+ [sibling -> d_cocoaRadioButton setState: NSOffState];
+ }
+ for (GuiRadioButton sibling = my d_next; sibling != NULL; sibling = sibling -> d_next) {
+ [sibling -> d_cocoaRadioButton setState: NSOffState];
+ }
+ if (my d_valueChangedCallback != NULL) {
+ Melder_assert (! my d_blockValueChangedCallbacks);
+ struct structGuiRadioButtonEvent event = { me };
+ event. position = _GuiRadioButton_getPosition (me);
+ my d_valueChangedCallback (my d_valueChangedBoss, & event);
+ }
+ }
+ @end
#elif win
void _GuiWinRadioButton_destroy (GuiObject widget) {
iam_radiobutton;
@@ -152,8 +189,19 @@ GuiRadioButton GuiRadioButton_create (GuiForm parent, int left, int right, int t
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (my d_widget), FALSE);
}
g_signal_connect (G_OBJECT (my d_widget), "destroy", G_CALLBACK (_GuiGtkRadioButton_destroyCallback), me);
- my d_valueChangedHandlerId = g_signal_connect (GTK_TOGGLE_BUTTON (my d_widget), "toggled", G_CALLBACK (_GuiGtkRadioButton_handleToggle), me);
+ g_signal_connect (GTK_TOGGLE_BUTTON (my d_widget), "toggled", G_CALLBACK (_GuiGtkRadioButton_handleToggle), me);
#elif cocoa
+ my d_cocoaRadioButton = [[GuiCocoaRadioButton alloc] init];
+ my d_widget = my d_cocoaRadioButton;
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [my d_cocoaRadioButton setUserData: me];
+ [my d_cocoaRadioButton setButtonType: NSRadioButton];
+ [my d_cocoaRadioButton setTitle: (NSString *) Melder_peekWcsToCfstring (buttonText)];
+ if (flags & GuiCheckButton_SET) {
+ [my d_cocoaRadioButton setState: NSOnState];
+ }
+ [my d_cocoaRadioButton setTarget: my d_cocoaRadioButton];
+ [my d_cocoaRadioButton setAction: @selector (_guiCocoaRadioButton_activateCallback:)];
#elif win
my d_widget = _Gui_initializeWidget (xmToggleButtonWidgetClass, parent -> d_widget, buttonText);
_GuiObject_setUserData (my d_widget, me);
@@ -209,6 +257,7 @@ bool structGuiRadioButton :: f_getValue () {
#if gtk
value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (d_widget)); // gtk_check_button inherits from gtk_toggle_button
#elif cocoa
+ value = [d_cocoaRadioButton state] == NSOnState;
#elif win
value = (Button_GetState (d_widget -> window) & 0x0003) == BST_CHECKED;
#elif mac
@@ -218,14 +267,20 @@ bool structGuiRadioButton :: f_getValue () {
}
void structGuiRadioButton :: f_set () {
- /*
- * The value should be set without calling the valueChanged callback.
- */
+ GuiControlBlockValueChangedCallbacks block (this); // the value should be set without calling the valueChanged callback (crucial on GTK)
#if gtk
- g_signal_handler_disconnect (GTK_TOGGLE_BUTTON (d_widget), d_valueChangedHandlerId);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (d_widget), TRUE);
- d_valueChangedHandlerId = g_signal_connect (GTK_TOGGLE_BUTTON (d_widget), "toggled", G_CALLBACK (_GuiGtkRadioButton_handleToggle), this);
#elif cocoa
+ [d_cocoaRadioButton setState: NSOnState];
+ /*
+ * Deselect the sister buttons.
+ */
+ for (GuiRadioButton sibling = d_previous; sibling != NULL; sibling = sibling -> d_previous) {
+ [sibling -> d_cocoaRadioButton setState: NSOffState];
+ }
+ for (GuiRadioButton sibling = d_next; sibling != NULL; sibling = sibling -> d_next) {
+ [sibling -> d_cocoaRadioButton setState: NSOffState];
+ }
#elif win
Button_SetCheck (d_widget -> window, BST_CHECKED);
/*
diff --git a/sys/GuiScrollBar.cpp b/sys/GuiScrollBar.cpp
index faca580..719e5b1 100644
--- a/sys/GuiScrollBar.cpp
+++ b/sys/GuiScrollBar.cpp
@@ -1,6 +1,6 @@
/* GuiScrollBar.cpp
*
- * Copyright (C) 1993-2011,2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1993-2011,2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,8 +40,9 @@ Thing_implement (GuiScrollBar, GuiControl, 0);
}
static void _GuiGtkScrollBar_valueChangedCallback (GuiObject widget, gpointer void_me) {
iam (GuiScrollBar);
- struct structGuiScrollBarEvent event = { me };
- if (my d_valueChangedCallback != NULL) {
+ trace ("enter");
+ if (my d_valueChangedCallback != NULL && ! my d_blockValueChangedCallbacks) {
+ struct structGuiScrollBarEvent event = { me };
try {
my d_valueChangedCallback (my d_valueChangedBoss, & event);
} catch (MelderError) {
@@ -52,13 +53,12 @@ Thing_implement (GuiScrollBar, GuiControl, 0);
}
#elif cocoa
@interface GuiCocoaScrollBar ()
- at property (nonatomic, assign) float knobPosition;
- at property (nonatomic, assign) float m_minimum;
- at property (nonatomic, assign) float m_maximum;
- at property (nonatomic, assign) float m_value;
- at property (nonatomic, assign) float m_sliderSize;
- at property (nonatomic, assign) float m_increment;
- at property (nonatomic, assign) float m_pageIncrement;
+ at property (nonatomic, assign) double m_minimum;
+ at property (nonatomic, assign) double m_maximum;
+ at property (nonatomic, assign) double m_value;
+ at property (nonatomic, assign) double m_sliderSize;
+ at property (nonatomic, assign) double m_increment;
+ at property (nonatomic, assign) double m_pageIncrement;
@end
// http://www.lucernesys.com/blog/2010/02/11/nsscroller/
@@ -76,77 +76,65 @@ Thing_implement (GuiScrollBar, GuiControl, 0);
return d_userData;
}
- (void) setUserData: (GuiThing) userData {
- Melder_assert (userData == NULL || Thing_member (userData, classGuiScrollBar));
- d_userData = static_cast <GuiScrollBar> (userData);
-
- // Proportion is the amount of the scroller that
- // the knob takes up,
- // the width of the knob for a horizontal scroller,
- // or the height for a vertical scroller.
- [self setKnobProportion:0.05];
- // the scroller double value is the position of
- // the knob on the slider, with a range of
- // 0.0 to 1.0
- [self setDoubleValue:0.5];
- [self setEnabled:YES];
-
-}
-
-- (void)setFrame:(NSRect)frameRect {
- NSLog(@"GuiScrollBar setFrame %@", NSStringFromRect(frameRect));
+ Melder_assert (userData == NULL || Thing_member (userData, classGuiScrollBar));
+ d_userData = static_cast <GuiScrollBar> (userData);
}
-
--(void)setMinimum:(double)minimum maximum:(double)maximum value:(double)value sliderSize:(double)sliderSize increment:(double)increment pageIncrement:(double)pageIncrement {
-
- if (minimum == NUMundefined) {
- minimum = 0.0;
- }
- _m_minimum = minimum;
- _m_maximum = maximum;
- _m_value = value;
- _m_sliderSize = sliderSize;
- _m_increment = increment;
- _m_pageIncrement = pageIncrement;
-
- value -= minimum;
- maximum -= minimum;
-
-
- double floatValue = value / maximum;
- double knobProportion = sliderSize / maximum;
-
- NSLog(@"floatValue %f knobProportion %f sliderSize %f", floatValue, knobProportion, sliderSize);
-
- [self setKnobProportion:knobProportion];
- [self setDoubleValue:floatValue];
+- (void) setMinimum:(double)minimum maximum:(double)maximum value:(double)value sliderSize:(double)sliderSize increment:(double)increment pageIncrement:(double)pageIncrement {
+ Melder_assert (NUMdefined (minimum));
+ _m_minimum = minimum;
+ _m_maximum = maximum;
+ _m_value = value;
+ _m_sliderSize = sliderSize;
+ _m_increment = increment;
+ _m_pageIncrement = pageIncrement;
+ double spaceLeft = (maximum - minimum) - sliderSize;
+ if (spaceLeft <= 0.0) {
+ [self setKnobProportion: 1.0];
+ [self setDoubleValue: 0.5];
+ } else {
+ [self setKnobProportion: sliderSize / (maximum - minimum)];
+ [self setDoubleValue: (value - minimum) / spaceLeft];
+ }
}
-
--(void)valueChanged {
-
- GuiScrollBar me = (GuiScrollBar) d_userData;
-
- switch ([self hitPart]) {
- case NSScrollerIncrementLine:
+- (void) valueChanged {
+ GuiScrollBar me = (GuiScrollBar) d_userData;
+ switch ([self hitPart]) {
+ case NSScrollerIncrementLine: {
// Include code here for the case where the down arrow is pressed
- break;
- case NSScrollerIncrementPage:
+ _m_value += _m_increment;
+ if (_m_value > _m_maximum - _m_sliderSize)
+ _m_value = _m_maximum - _m_sliderSize;
+ [self setMinimum: _m_minimum maximum: _m_maximum value: _m_value sliderSize: _m_sliderSize increment: _m_increment pageIncrement: _m_pageIncrement];
+ } break;
+ case NSScrollerIncrementPage: {
// Include code here for the case where CTRL + down arrow is pressed, or the space the scroll knob moves in is pressed
- break;
- case NSScrollerDecrementLine:
+ _m_value += _m_pageIncrement;
+ if (_m_value > _m_maximum - _m_sliderSize)
+ _m_value = _m_maximum - _m_sliderSize;
+ [self setMinimum: _m_minimum maximum: _m_maximum value: _m_value sliderSize: _m_sliderSize increment: _m_increment pageIncrement: _m_pageIncrement];
+ } break;
+ case NSScrollerDecrementLine: {
// Include code here for the case where the up arrow is pressed
- break;
- case NSScrollerDecrementPage:
+ _m_value -= _m_increment;
+ if (_m_value < _m_minimum)
+ _m_value = _m_minimum;
+ [self setMinimum: _m_minimum maximum: _m_maximum value: _m_value sliderSize: _m_sliderSize increment: _m_increment pageIncrement: _m_pageIncrement];
+ } break;
+ case NSScrollerDecrementPage: {
// Include code here for the case where CTRL + up arrow is pressed, or the space the scroll knob moves in is pressed
- break;
- case NSScrollerKnob:
+ _m_value -= _m_pageIncrement;
+ if (_m_value < _m_minimum)
+ _m_value = _m_minimum;
+ [self setMinimum: _m_minimum maximum: _m_maximum value: _m_value sliderSize: _m_sliderSize increment: _m_increment pageIncrement: _m_pageIncrement];
+ } break;
+ case NSScrollerKnob: {
// This case is when the knob itself is pressed
- _knobPosition = [self floatValue];
- // Do something with the view
- default:
- break;
+ double spaceLeft = (_m_maximum - _m_minimum) - _m_sliderSize;
+ _m_value = _m_minimum + [self doubleValue] * (spaceLeft <= 0.0 ? 0.0 : spaceLeft);
+ } break;
+ default: {
+ } break;
}
-
-
if (my d_valueChangedCallback) {
struct structGuiScrollBarEvent event = { me };
try {
@@ -155,15 +143,7 @@ Thing_implement (GuiScrollBar, GuiControl, 0);
Melder_flushError ("Scroll not completely handled.");
}
}
-
-}
-
-- (int)getScrollerValue {
- double diff = abs(_m_maximum - _m_minimum);
- double result = [self doubleValue] * diff + _m_minimum;
- return result;
}
-
@end
#elif win
void _GuiWinScrollBar_destroy (GuiObject widget) {
@@ -208,26 +188,16 @@ GuiScrollBar GuiScrollBar_create (GuiForm parent, int left, int right, int top,
my v_positionInForm (my d_widget, left, right, top, bottom, parent);
g_signal_connect (G_OBJECT (my d_widget), "value-changed", G_CALLBACK (_GuiGtkScrollBar_valueChangedCallback), me);
#elif cocoa
- GuiCocoaScrollBar *scroller = [GuiCocoaScrollBar alloc];
- my d_widget = (GuiObject) scroller;
- my v_positionInForm (my d_widget, left, right, top, bottom, parent);
- [scroller setUserData:me];
-
- NSLog(@"[scroller frame] %@", NSStringFromRect([scroller frame]));
-
- [scroller setMinimum:minimum maximum:maximum value:value sliderSize:sliderSize increment:increment pageIncrement:pageIncrement];
-
-
- [scroller setKnobProportion:1.0];
- // the scroller double value is the position of
- // the knob on the slider, with a range of
- // 0.0 to 1.0
- [scroller setDoubleValue:0.5];
- [scroller setEnabled:YES];
- [scroller setScrollerStyle:NSScrollerStyleLegacy];
- [scroller setTarget:scroller];
- [scroller setAction:@selector(valueChanged)];
-
+ NSRect dummyFrame = flags & GuiScrollBar_HORIZONTAL ? NSMakeRect (20, 20, 100, [NSScroller scrollerWidth]) : NSMakeRect (20, 20, [NSScroller scrollerWidth], 100);
+ GuiCocoaScrollBar *scroller = [[GuiCocoaScrollBar alloc] initWithFrame: dummyFrame];
+ my d_widget = scroller;
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [scroller setUserData: me];
+ [scroller setEnabled: YES];
+ [scroller setMinimum: minimum maximum: maximum value: value sliderSize: sliderSize increment: increment pageIncrement: pageIncrement];
+ //[scroller setScrollerStyle: NSScrollerStyleOverlay];
+ [scroller setTarget: scroller];
+ [scroller setAction: @selector (valueChanged)];
#elif win
my d_widget = XtVaCreateWidget (flags & GuiScrollBar_HORIZONTAL ? "horizontalScrollBar" : "verticalScrollBar", // the name is checked for deciding the orientation...
xmScrollBarWidgetClass, parent -> d_widget,
@@ -266,9 +236,6 @@ GuiScrollBar GuiScrollBar_createShown (GuiForm parent, int left, int right, int
double minimum, double maximum, double value, double sliderSize, double increment, double pageIncrement,
void (*valueChangedCallback) (void *boss, GuiScrollBarEvent event), void *valueChangedBoss, unsigned long flags)
{
- //NSLog(@"GuiScrollBar_createShown %f minimum, %f maximum, %f value, %f sliderSize, %f increment, %f pageIncrement",
- // minimum, maximum, value, sliderSize, increment, pageIncrement);
-
GuiScrollBar me = GuiScrollBar_create (parent, left, right, top, bottom,
minimum, maximum, value, sliderSize, increment, pageIncrement,
valueChangedCallback, valueChangedBoss, flags);
@@ -277,36 +244,37 @@ GuiScrollBar GuiScrollBar_createShown (GuiForm parent, int left, int right, int
}
void structGuiScrollBar :: f_set (double minimum, double maximum, double value, double sliderSize, double increment, double pageIncrement) {
+ GuiControlBlockValueChangedCallbacks block (this);
#if gtk
GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (d_widget));
gtk_adjustment_configure (GTK_ADJUSTMENT (adj),
- NUMdefined (value) ? value : gtk_adjustment_get_value (GTK_ADJUSTMENT (adj)),
- NUMdefined (minimum) ? minimum : gtk_adjustment_get_lower (GTK_ADJUSTMENT (adj)),
- NUMdefined (maximum) ? maximum : gtk_adjustment_get_upper (GTK_ADJUSTMENT (adj)),
- NUMdefined (increment) ? increment : gtk_adjustment_get_step_increment (GTK_ADJUSTMENT (adj)),
+ NUMdefined (value) ? value : gtk_adjustment_get_value (GTK_ADJUSTMENT (adj)),
+ NUMdefined (minimum) ? minimum : gtk_adjustment_get_lower (GTK_ADJUSTMENT (adj)),
+ NUMdefined (maximum) ? maximum : gtk_adjustment_get_upper (GTK_ADJUSTMENT (adj)),
+ NUMdefined (increment) ? increment : gtk_adjustment_get_step_increment (GTK_ADJUSTMENT (adj)),
NUMdefined (pageIncrement) ? pageIncrement : gtk_adjustment_get_page_increment (GTK_ADJUSTMENT (adj)),
- NUMdefined (sliderSize) ? sliderSize : gtk_adjustment_get_page_size (GTK_ADJUSTMENT (adj)));
+ NUMdefined (sliderSize) ? sliderSize : gtk_adjustment_get_page_size (GTK_ADJUSTMENT (adj)));
#elif cocoa
-
- NSLog(@"f_set %f minimum, %f maximum, %f value, %f sliderSize, %f increment, %f pageIncrement",
- minimum, maximum, value, sliderSize, increment, pageIncrement);
-
- GuiCocoaScrollBar *scroller = (GuiCocoaScrollBar*)d_widget;
- [scroller setMinimum:minimum maximum:maximum value:value sliderSize:sliderSize increment:increment pageIncrement:pageIncrement];
-
-
+ GuiCocoaScrollBar *scroller = (GuiCocoaScrollBar *) d_widget;
+ [scroller
+ setMinimum: NUMdefined (minimum) ? minimum : [scroller m_minimum]
+ maximum: NUMdefined (maximum) ? maximum : [scroller m_maximum]
+ value: NUMdefined (value) ? value : [scroller m_value]
+ sliderSize: NUMdefined (sliderSize) ? sliderSize : [scroller m_sliderSize]
+ increment: NUMdefined (increment) ? increment : [scroller m_increment]
+ pageIncrement: NUMdefined (pageIncrement) ? pageIncrement : [scroller m_pageIncrement]];
#elif motif
- if (minimum != NUMundefined)
+ if (NUMdefined (minimum))
XtVaSetValues (d_widget, XmNminimum, (int) minimum, NULL);
- if (maximum != NUMundefined)
+ if (NUMdefined (maximum))
XtVaSetValues (d_widget, XmNmaximum, (int) maximum, NULL);
int oldValue, oldSliderSize, oldIncrement, oldPageIncrement;
XmScrollBarGetValues (d_widget, & oldValue, & oldSliderSize, & oldIncrement, & oldPageIncrement);
XmScrollBarSetValues (d_widget,
- NUMdefined (value) ? value : oldValue,
- NUMdefined (sliderSize) ? sliderSize : oldSliderSize,
- NUMdefined (increment) ? increment : oldIncrement,
- NUMdefined (pageIncrement) ? pageIncrement : pageIncrement,
+ NUMdefined (value) ? value : oldValue,
+ NUMdefined (sliderSize) ? sliderSize : oldSliderSize,
+ NUMdefined (increment) ? increment : oldIncrement,
+ NUMdefined (pageIncrement) ? pageIncrement : oldPageIncrement,
False);
#endif
}
@@ -315,13 +283,8 @@ int structGuiScrollBar :: f_getValue () {
#if gtk
return gtk_range_get_value (GTK_RANGE (d_widget));
#elif cocoa
-
- GuiCocoaScrollBar *scroller = (GuiCocoaScrollBar*)d_widget;
-
- NSLog(@"f_getValue %d ", [scroller getScrollerValue]);
-
- return [scroller getScrollerValue];
-
+ GuiCocoaScrollBar *scroller = (GuiCocoaScrollBar *) d_widget;
+ return [scroller m_value];
#elif motif
int value, slider, incr, pincr;
XmScrollBarGetValues (d_widget, & value, & slider, & incr, & pincr);
diff --git a/sys/GuiScrolledWindow.cpp b/sys/GuiScrolledWindow.cpp
index d140ec9..d82e843 100644
--- a/sys/GuiScrolledWindow.cpp
+++ b/sys/GuiScrolledWindow.cpp
@@ -90,7 +90,7 @@ GuiScrolledWindow GuiScrolledWindow_create (GuiForm parent, int left, int right,
g_signal_connect (G_OBJECT (my d_widget), "destroy", G_CALLBACK (_GuiGtkScrolledWindow_destroyCallback), me);
#elif cocoa
- GuiCocoaScrolledWindow *scrollView = [GuiCocoaScrolledWindow alloc];
+ GuiCocoaScrolledWindow *scrollView = [[GuiCocoaScrolledWindow alloc] init];
my d_widget = (GuiObject) scrollView;
my v_positionInForm (my d_widget, left, right, top, bottom, parent);
[scrollView setUserData:me];
diff --git a/sys/GuiShell.cpp b/sys/GuiShell.cpp
index 0bc9eaf..be5a59c 100644
--- a/sys/GuiShell.cpp
+++ b/sys/GuiShell.cpp
@@ -22,6 +22,20 @@
Thing_implement (GuiShell, GuiForm, 0);
+void structGuiShell :: v_destroy () {
+ #if cocoa
+ if (d_cocoaWindow) {
+ [d_cocoaWindow setUserData: NULL]; // undangle reference to this
+ Melder_fatal ("ordering out?");
+ [d_cocoaWindow orderOut: nil];
+ [d_cocoaWindow close];
+ [d_cocoaWindow release];
+ d_cocoaWindow = NULL; // undangle
+ }
+ #endif
+ GuiShell_Parent :: v_destroy ();
+}
+
int structGuiShell :: f_getShellWidth () {
int width = 0;
#if gtk
@@ -63,8 +77,9 @@ void structGuiShell :: f_drain () {
//gdk_window_flush (gtk_widget_get_window (me));
gdk_flush ();
#elif cocoa
- // Probably never needed, unless we diabled flushing
- [d_cocoaWindow flushWindowIfNeeded];
+ //[d_cocoaWindow displayIfNeeded];
+ [d_cocoaWindow flushWindow];
+ [d_cocoaWindow display];
#elif win
#elif mac
Melder_assert (d_xmShell != NULL);
diff --git a/sys/GuiText.cpp b/sys/GuiText.cpp
index 387cb04..52ddd47 100644
--- a/sys/GuiText.cpp
+++ b/sys/GuiText.cpp
@@ -42,6 +42,7 @@
* pb 2010/05/30 GTK selections
* pb 2010/11/28 removed Motif
* pb 2011/04/06 C++
+ * pb,tm 2013 Cocoa
*/
#include "GuiP.h"
@@ -103,7 +104,7 @@ Thing_implement (GuiText, GuiControl, 0);
* (It is true that Windows itself stores the global text focus, but this is not always a text widget;
* we want it to always be a text widget, e.g. in the TextGrid editor it is always the text widget,
* never the drawing area, that receives key strokes. In Motif, we will have to program this text
- * preference explicitly; see the discussion in FunctionEditor.c.)
+ * preference explicitly; see the discussion in FunctionEditor.cpp.)
*/
void _GuiText_handleFocusReception (GuiObject widget) {
@@ -860,13 +861,13 @@ void _GuiText_exit (void) {
forget (me);
}
#elif cocoa
- @implementation GuiCocoaText {
+ @implementation GuiCocoaTextField {
GuiText d_userData;
}
- (void) dealloc { // override
GuiText me = d_userData;
forget (me);
- Melder_casual ("deleting a label");
+ trace ("deleting a text field");
[super dealloc];
}
- (GuiThing) userData {
@@ -876,6 +877,47 @@ void _GuiText_exit (void) {
Melder_assert (userData == NULL || Thing_member (userData, classGuiText));
d_userData = static_cast <GuiText> (userData);
}
+ - (void) textDidChange: (NSNotification *) notification {
+ (void) notification;
+ GuiText me = d_userData;
+ if (me && my d_changeCallback) {
+ struct structGuiTextEvent event = { me };
+ my d_changeCallback (my d_changeBoss, & event);
+ }
+ }
+ @end
+ @implementation GuiCocoaTextView {
+ GuiText d_userData;
+ }
+ - (void) dealloc { // override
+ GuiText me = d_userData;
+ forget (me);
+ trace ("deleting a text view");
+ [super dealloc];
+ }
+ - (GuiThing) userData {
+ return d_userData;
+ }
+ - (void) setUserData: (GuiThing) userData {
+ Melder_assert (userData == NULL || Thing_member (userData, classGuiText));
+ d_userData = static_cast <GuiText> (userData);
+ }
+ /*
+ * The NSTextViewDelegate protocol.
+ * While NSTextDelegate simply has textDidChange:, that method doesn't seem to respond when the text is changed programmatically.
+ */
+// - (void) textDidChange: (NSNotification *) notification {
+ - (BOOL) textView: (NSTextView *) aTextView shouldChangeTextInRange: (NSRange) affectedCharRange replacementString: (NSString *) replacementString {
+ (void) aTextView;
+ (void) affectedCharRange;
+ (void) replacementString;
+ GuiText me = d_userData;
+ if (me && my d_changeCallback) {
+ struct structGuiTextEvent event = { me };
+ my d_changeCallback (my d_changeBoss, & event);
+ }
+ return YES;
+ }
@end
#elif win
#elif mac
@@ -926,22 +968,50 @@ GuiText GuiText_create (GuiForm parent, int left, int right, int top, int bottom
my d_redo_item = NULL;
g_signal_connect (G_OBJECT (my d_widget), "destroy", G_CALLBACK (_GuiGtkText_destroyCallback), me);
#elif cocoa
- trace ("create");
- my d_widget = [GuiCocoaText alloc];
- trace ("position");
- my v_positionInForm (my d_widget, left, right, top, bottom, parent);
- trace ("set user data");
- [(GuiCocoaText *) my d_widget setUserData: me];
- trace ("set bezeled");
- //[(NSTextField *) my d_widget setBezeled: YES];
- trace ("set bezel style");
- //[(NSTextField *) my d_widget setBezelStyle: NSRoundedBezelStyle];
- trace ("set bordered");
- //[(NSTextField *) my d_widget setBordered: YES];
- trace ("set editable");
- [(NSTextField *) my d_widget setEditable: YES];
- //NSColor *white = [NSColor whiteColor];
- //[(NSTextField *) my d_widget setBackgroundColor: white];
+ if (flags & GuiText_SCROLLED) {
+ my d_cocoaScrollView = [[GuiCocoaScrolledWindow alloc] init];
+ [my d_cocoaScrollView setUserData: NULL]; // because those user data can only be GuiScrolledWindow
+ my d_widget = my d_cocoaScrollView;
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [my d_cocoaScrollView setBorderType: NSNoBorder];
+ [my d_cocoaScrollView setHasHorizontalScroller: YES];
+ [my d_cocoaScrollView setHasVerticalScroller: YES];
+ [my d_cocoaScrollView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
+ NSSize contentSize = [my d_cocoaScrollView contentSize];
+ my d_cocoaTextView = [[GuiCocoaTextView alloc] initWithFrame: NSMakeRect (0, 0, contentSize. width, contentSize. height)];
+ [my d_cocoaTextView setUserData: me];
+ [my d_cocoaTextView setMinSize: NSMakeSize (0.0, contentSize.height)];
+ [my d_cocoaTextView setMaxSize: NSMakeSize (FLT_MAX, FLT_MAX)];
+ [my d_cocoaTextView setVerticallyResizable: YES];
+ [my d_cocoaTextView setHorizontallyResizable: YES];
+ [my d_cocoaTextView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
+ [[my d_cocoaTextView textContainer] setContainerSize: NSMakeSize (FLT_MAX, FLT_MAX)];
+ [[my d_cocoaTextView textContainer] setWidthTracksTextView: NO];
+ [my d_cocoaScrollView setDocumentView: my d_cocoaTextView];
+ [[my d_cocoaScrollView window] makeFirstResponder: my d_cocoaTextView];
+ static NSFont *theTextFont;
+ if (! theTextFont) {
+ theTextFont = [[NSFont systemFontOfSize: 13.0] retain];
+ }
+ [my d_cocoaTextView setFont: theTextFont];
+ [my d_cocoaTextView setAllowsUndo: YES];
+ //[my d_cocoaTextView turnOffLigatures: nil];
+ [my d_cocoaTextView setSmartInsertDeleteEnabled: NO];
+ //[my d_cocoaTextView setAutomaticQuoteSubstitutionEnabled: NO];
+ [my d_cocoaTextView setAutomaticTextReplacementEnabled: NO];
+ //[my d_cocoaTextView setAutomaticDashSubstitutionEnabled: NO];
+ [my d_cocoaTextView setDelegate: my d_cocoaTextView];
+ } else {
+ my d_widget = [[GuiCocoaTextField alloc] init];
+ my v_positionInForm (my d_widget, left, right, top, bottom, parent);
+ [(GuiCocoaTextField *) my d_widget setUserData: me];
+ [(NSTextField *) my d_widget setEditable: YES];
+ static NSFont *theTextFont;
+ if (! theTextFont) {
+ theTextFont = [[NSFont systemFontOfSize: 13.0] retain];
+ }
+ [(NSTextField *) my d_widget setFont: theTextFont];
+ }
#elif win
my d_widget = _Gui_initializeWidget (xmTextWidgetClass, parent -> d_widget, flags & GuiText_SCROLLED ? L"scrolledText" : L"text");
_GuiObject_setUserData (my d_widget, me);
@@ -1033,6 +1103,11 @@ void structGuiText :: f_copy () {
gtk_text_buffer_copy_clipboard (buffer, cb);
}
#elif cocoa
+ if (d_cocoaTextView) {
+ [d_cocoaTextView copy: nil];
+ } else {
+ [[[(GuiCocoaTextField *) d_widget window] fieldEditor: NO forObject: nil] copy: nil];
+ }
#elif win
if (! NativeText_getSelectionRange (d_widget, NULL, NULL)) return;
SendMessage (d_widget -> window, WM_COPY, 0, 0);
@@ -1056,6 +1131,11 @@ void structGuiText :: f_cut () {
gtk_text_buffer_cut_clipboard (buffer, cb, gtk_text_view_get_editable (GTK_TEXT_VIEW (d_widget)));
}
#elif cocoa
+ if (d_cocoaTextView) {
+ [d_cocoaTextView cut: nil];
+ } else {
+ [[[(GuiCocoaTextField *) d_widget window] fieldEditor: NO forObject: nil] cut: nil];
+ }
#elif win
if (! d_editable || ! NativeText_getSelectionRange (d_widget, NULL, NULL)) return;
SendMessage (d_widget -> window, WM_CUT, 0, 0); // this will send the EN_CHANGE message, hence no need to call the valueChangedCallbacks
@@ -1098,6 +1178,16 @@ wchar_t * structGuiText :: f_getSelection () {
}
}
#elif cocoa
+ long start, end;
+ autostring selection = f_getStringAndSelectionPosition (& start, & end);
+ long length = end - start;
+ if (length > 0) {
+ wchar_t *result = Melder_malloc_f (wchar_t, length + 1);
+ memcpy (result, & selection [start], length * sizeof (wchar_t));
+ result [length] = '\0';
+ Melder_killReturns_inlineW (result);
+ return result;
+ }
#elif win
long start, end;
NativeText_getSelectionRange (d_widget, & start, & end);
@@ -1174,10 +1264,26 @@ wchar_t * structGuiText :: f_getStringAndSelectionPosition (long *first, long *l
}
return NULL;
#elif cocoa
- NSString *nsString = [(NSTextField *) d_widget stringValue];
- wchar_t *result = Melder_utf8ToWcs ([nsString UTF8String]);
- trace ("string %ls", result);
- return result; // TODO
+ if (d_cocoaTextView) {
+ NSString *nsString = [d_cocoaTextView string];
+ wchar_t *result = Melder_utf8ToWcs ([nsString UTF8String]);
+ trace ("string %ls", result);
+ NSRange nsRange = [d_cocoaTextView selectedRange];
+ *first = nsRange. location;
+ *last = *first + nsRange. length;
+ for (long i = 0; i < *first; i ++) if (result [i] > 0xFFFF) { (*first) --; (*last) --; }
+ for (long i = *first; i < *last; i ++) if (result [i] > 0xFFFF) { (*last) --; }
+ return result;
+ } else {
+ NSString *nsString = [(NSTextField *) d_widget stringValue];
+ wchar_t *result = Melder_utf8ToWcs ([nsString UTF8String]);
+ trace ("string %ls", result);
+ NSRange nsRange = [[[(NSTextField *) d_widget window] fieldEditor: NO forObject: nil] selectedRange];
+ *first = nsRange. location;
+ *last = *first + nsRange. length;
+ for (long i = 0; i < *first; i ++) if (result [i] > 0xFFFF) { (*first) --; (*last) --; }
+ return result;
+ }
#elif win
long length = NativeText_getLength (d_widget);
wchar_t *result = Melder_malloc_f (wchar_t, length + 1);
@@ -1212,6 +1318,11 @@ void structGuiText :: f_paste () {
gtk_text_buffer_paste_clipboard (buffer, cb, NULL, gtk_text_view_get_editable (GTK_TEXT_VIEW (d_widget)));
}
#elif cocoa
+ if (d_cocoaTextView) {
+ [d_cocoaTextView pasteAsPlainText: nil];
+ } else {
+ [[[(GuiCocoaTextField *) d_widget window] fieldEditor: NO forObject: nil] pasteAsPlainText: nil];
+ }
#elif win
if (! d_editable) return;
SendMessage (d_widget -> window, WM_PASTE, 0, 0); // this will send the EN_CHANGE message, hence no need to call the valueChangedCallbacks
@@ -1230,14 +1341,15 @@ void structGuiText :: f_paste () {
}
void structGuiText :: f_redo () {
- #if mac
- #if useCarbon
- if (isMLTE (this)) {
- TXNRedo (d_macMlteObject);
- }
- _GuiText_handleValueChanged (d_widget);
- #else
- #endif
+ #if cocoa
+ if (d_cocoaTextView) {
+ [[d_cocoaTextView undoManager] redo];
+ }
+ #elif mac
+ if (isMLTE (this)) {
+ TXNRedo (d_macMlteObject);
+ }
+ _GuiText_handleValueChanged (d_widget);
#else
history_do (this, 0);
#endif
@@ -1287,6 +1399,20 @@ void structGuiText :: f_replace (long from_pos, long to_pos, const wchar_t *text
gtk_text_view_get_editable (GTK_TEXT_VIEW (d_widget)));
}
#elif cocoa
+ if (d_cocoaTextView) {
+ long numberOfLeadingHighUnicodeValues = 0, numberOfSelectedHighUnicodeValues = 0;
+ {// scope
+ autostring oldText = f_getString ();
+ for (long i = 0; i < from_pos; i ++) if (oldText [i] > 0xFFFF) numberOfLeadingHighUnicodeValues ++;
+ for (long i = from_pos; i < to_pos; i ++) if (oldText [i] > 0xFFFF) numberOfSelectedHighUnicodeValues ++;
+ }
+ from_pos += numberOfLeadingHighUnicodeValues;
+ to_pos += numberOfLeadingHighUnicodeValues + numberOfSelectedHighUnicodeValues;
+ NSRange nsRange = NSMakeRange (from_pos, to_pos - from_pos);
+ NSString *nsString = (NSString *) Melder_peekWcsToCfstring (text);
+ [d_cocoaTextView shouldChangeTextInRange: nsRange replacementString: nsString]; // ignore the returned BOOL: only interested in the side effect of having undo support
+ [[d_cocoaTextView textStorage] replaceCharactersInRange: nsRange withString: nsString];
+ }
#elif win
const wchar_t *from;
wchar_t *winText = Melder_malloc_f (wchar_t, 2 * wcslen (text) + 1), *to; /* All new lines plus one null byte. */
@@ -1393,6 +1519,9 @@ void structGuiText :: f_setFontSize (int size) {
modStyle -> font_desc = fontDesc;
gtk_widget_modify_style (GTK_WIDGET (d_widget), modStyle);
#elif cocoa
+ if (d_cocoaTextView) {
+ [d_cocoaTextView setFont: [NSFont systemFontOfSize: size]];
+ }
#elif win
// a trick to update the window. BUG: why doesn't UpdateWindow seem to suffice?
long first, last;
@@ -1453,6 +1582,24 @@ void structGuiText :: f_setSelection (long first, long last) {
gtk_text_buffer_select_range (buffer, & from_it, & to_it);
}
#elif cocoa
+ /*
+ * On Cocoa, characters are counted in UTF-16 units, whereas 'first' and 'last' are in UTF-32 units. Convert.
+ */
+ wchar_t *text = f_getString ();
+ if (first < 0) first = 0;
+ if (last < 0) last = 0;
+ long length = wcslen (text);
+ if (first >= length) first = length;
+ if (last >= length) last = length;
+ long numberOfLeadingHighUnicodeValues = 0, numberOfSelectedHighUnicodeValues = 0;
+ for (long i = 0; i < first; i ++) if (text [i] > 0xFFFF) numberOfLeadingHighUnicodeValues ++;
+ for (long i = first; i < last; i ++) if (text [i] > 0xFFFF) numberOfSelectedHighUnicodeValues ++;
+ first += numberOfLeadingHighUnicodeValues;
+ last += numberOfLeadingHighUnicodeValues + numberOfSelectedHighUnicodeValues;
+ Melder_free (text);
+ if (d_cocoaTextView) {
+ [d_cocoaTextView setSelectedRange: NSMakeRange (first, last - first)];
+ }
#elif win
/* 'first' and 'last' are the positions of the selection in the text when separated by LF alone. */
/* We have to convert this to the positions that the selection has in a text separated by CR/LF sequences. */
@@ -1509,7 +1656,17 @@ void structGuiText :: f_setString (const wchar_t *text) {
}
#elif cocoa
trace ("title");
- [(NSTextField *) d_widget setStringValue: (NSString *) Melder_peekWcsToCfstring (text)];
+ if (d_cocoaTextView) {
+ NSRange nsRange = NSMakeRange (0, [[d_cocoaTextView textStorage] length]);
+ NSString *nsString = (NSString *) Melder_peekWcsToCfstring (text);
+ [d_cocoaTextView shouldChangeTextInRange: nsRange replacementString: nsString]; // to make this action undoable
+ //[[d_cocoaTextView textStorage] replaceCharactersInRange: nsRange withString: nsString];
+ [d_cocoaTextView setString: nsString];
+ //[[d_cocoaTextView window] setViewsNeedDisplay: YES];
+ //[[d_cocoaTextView window] display];
+ } else {
+ [(NSTextField *) d_widget setStringValue: (NSString *) Melder_peekWcsToCfstring (text)];
+ }
#elif win
const wchar_t *from;
wchar_t *winText = Melder_malloc_f (wchar_t, 2 * wcslen (text) + 1), *to; /* All new lines plus one null byte. */
@@ -1590,6 +1747,9 @@ void structGuiText :: f_undo () {
#if gtk
history_do (this, 1);
#elif cocoa
+ if (d_cocoaTextView) {
+ [[d_cocoaTextView undoManager] undo];
+ }
#elif win
#elif mac
if (isMLTE (this)) {
diff --git a/sys/GuiThing.cpp b/sys/GuiThing.cpp
index 8954a4c..39b413c 100644
--- a/sys/GuiThing.cpp
+++ b/sys/GuiThing.cpp
@@ -1,6 +1,6 @@
/* GuiThing.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,10 @@
#include "GuiP.h"
#include "machine.h"
+void structGuiThing :: v_destroy () {
+ GuiThing_Parent :: v_destroy ();
+}
+
void structGuiThing :: f_hide () {
v_hide ();
}
@@ -99,9 +103,11 @@ void structGuiThing :: v_show () {
}
#elif cocoa
if ([(NSObject *) d_widget isKindOfClass: [NSWindow class]]) {
+ trace ("trying to show a window");
[(NSWindow *) d_widget makeKeyAndOrderFront: nil];
} else if ([(NSObject *) d_widget isKindOfClass: [NSView class]]) {
if ((NSView *) d_widget == [[(NSView *) d_widget window] contentView]) {
+ trace ("trying to show a window through its content view");
[[(NSView *) d_widget window] makeKeyAndOrderFront: nil];
} else {
[(NSView *) d_widget setHidden: NO];
diff --git a/sys/GuiWindow.cpp b/sys/GuiWindow.cpp
index 2a6e513..ae74fae 100644
--- a/sys/GuiWindow.cpp
+++ b/sys/GuiWindow.cpp
@@ -1,6 +1,6 @@
/* GuiWindow.cpp
*
- * Copyright (C) 1993-2012 Paul Boersma, 2013 Tom Naughton
+ * Copyright (C) 1993-2012,2013 Paul Boersma, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -112,6 +112,7 @@ Thing_implement (GuiWindow, GuiShell, 0);
}
- (void) dealloc { // override
GuiWindow me = d_userData;
+ my d_cocoaWindow = NULL; // this is already under destruction, so undangle
forget (me);
trace ("deleting a window");
[super dealloc];
@@ -124,6 +125,23 @@ Thing_implement (GuiWindow, GuiShell, 0);
d_userData = static_cast <GuiWindow> (userData);
}
@end
+ @interface GuiCocoaWindowDelegate : NSObject <NSWindowDelegate> { } @end
+ @implementation GuiCocoaWindowDelegate {
+ }
+ - (BOOL) windowShouldClose: (id) sender {
+ GuiCocoaWindow *widget = (GuiCocoaWindow *) sender;
+ GuiWindow me = (GuiWindow) [widget userData];
+ if (my d_goAwayCallback != NULL) {
+ trace ("calling goAwayCallback)");
+ my d_goAwayCallback (my d_goAwayBoss);
+ } else {
+ trace ("hiding window");
+ [widget orderOut: nil];
+ }
+ return FALSE;
+ }
+ @end
+ static GuiCocoaWindowDelegate *theGuiCocoaWindowDelegate;
#elif motif
static void _GuiMotifWindow_destroyCallback (GuiObject widget, XtPointer void_me, XtPointer call) {
(void) widget; (void) call;
@@ -171,11 +189,15 @@ GuiWindow GuiWindow_create (int x, int y, int width, int height,
styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask
backing: NSBackingStoreBuffered
defer: false];
- [my d_cocoaWindow setMinSize:NSMakeSize(500.0, 500.0)];
+ [my d_cocoaWindow setMinSize: NSMakeSize (150.0, 150.0)];
my f_setTitle (title);
[my d_cocoaWindow makeKeyAndOrderFront: nil];
my d_widget = [my d_cocoaWindow contentView];
_GuiObject_setUserData (my d_cocoaWindow, me);
+ if (! theGuiCocoaWindowDelegate) {
+ theGuiCocoaWindowDelegate = [[GuiCocoaWindowDelegate alloc] init];
+ }
+ [my d_cocoaWindow setDelegate: theGuiCocoaWindowDelegate];
#elif motif
my d_xmShell = XmCreateShell (NULL, flags & GuiWindow_FULLSCREEN ? "Praatwulgfullscreen" : "Praatwulg", NULL, 0);
XtVaSetValues (my d_xmShell, XmNdeleteResponse, goAwayCallback ? XmDO_NOTHING : XmUNMAP, NULL);
@@ -232,8 +254,8 @@ bool structGuiWindow :: f_setDirty (bool dirty) {
(void) dirty;
return false;
#elif cocoa
- (void) dirty;
- return false;
+ [d_cocoaWindow setDocumentEdited: dirty];
+ return true;
#elif win
(void) dirty;
return false;
diff --git a/sys/HyperPage.cpp b/sys/HyperPage.cpp
index 5a7f889..6c68eba 100644
--- a/sys/HyperPage.cpp
+++ b/sys/HyperPage.cpp
@@ -468,7 +468,7 @@ if (! my printing) {
theCurrentPraatPicture -> y2NDC = height_inches;
Graphics_setViewport (my g, theCurrentPraatPicture -> x1NDC, theCurrentPraatPicture -> x2NDC, theCurrentPraatPicture -> y1NDC, theCurrentPraatPicture -> y2NDC);
- { // scope
+ {// scope
autoMelderProgressOff progress;
autoMelderWarningOff warning;
autoMelderSaveDefaultDir saveDir;
@@ -564,7 +564,7 @@ if (! my printing) {
theCurrentPraatPicture -> y2NDC = height_inches;
Graphics_setViewport (my ps, theCurrentPraatPicture -> x1NDC, theCurrentPraatPicture -> x2NDC, theCurrentPraatPicture -> y1NDC, theCurrentPraatPicture -> y2NDC);
- { // scope
+ {// scope
autoMelderProgressOff progress;
autoMelderWarningOff warning;
autoMelderSaveDefaultDir saveDir;
@@ -634,6 +634,7 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
if (my g == NULL) return; // Could be the case in the very beginning.
Graphics_clearWs (my g);
initScreen (me);
+ trace ("going to draw");
my v_draw ();
if (my entryHint && my entryPosition) {
Melder_free (my entryHint);
@@ -649,10 +650,11 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (HyperPage);
if (my g == NULL) return; // Could be the case in the very beginning.
-if (gtk && event -> type != BUTTON_PRESS) return;
if (! my links) return;
for (long ilink = 1; ilink <= my links -> size; ilink ++) {
- HyperLink link = (HyperLink) my links -> item [ilink];
+ HyperLink link = (HyperLink) my links -> item [ilink];
+ if (link == NULL)
+ Melder_fatal ("gui_drawingarea_cb_click: empty link %ld/%ld.", ilink, my links -> size);
if (event -> y > link -> y2DC && event -> y < link -> y1DC && event -> x > link -> x1DC && event -> x < link -> x2DC) {
saveHistory (me, my currentPageTitle);
try {
@@ -779,10 +781,15 @@ static void gui_cb_verticalScroll (I, GuiScrollBarEvent event) {
iam (HyperPage);
double value = event -> scrollBar -> f_getValue ();
if (value != my top) {
+ trace ("scroll from %f to %f", (double) my top, value);
my top = value;
- Graphics_clearWs (my g);
- initScreen (me);
- my v_draw (); // do not wait for expose event
+ #if cocoa || gtk || win
+ Graphics_updateWs (my g); // wait for expose event
+ #else
+ initScreen (me);
+ Graphics_clearWs (my g);
+ my v_draw (); // do not wait for expose event
+ #endif
updateVerticalScrollBar (me);
}
}
@@ -960,7 +967,7 @@ void structHyperPage :: v_createChildren () {
/***** Create drawing area. *****/
- drawingArea = GuiDrawingArea_createShown (d_windowForm, 0, - Machine_getScrollBarWidth (), y + height + 8, - Machine_getScrollBarWidth (),
+ drawingArea = GuiDrawingArea_createShown (d_windowForm, 0, - Machine_getScrollBarWidth (), y + height + 9, - Machine_getScrollBarWidth (),
gui_drawingarea_cb_expose, gui_drawingarea_cb_click, NULL, gui_drawingarea_cb_resize, this, GuiDrawingArea_BORDER);
drawingArea -> f_setSwipable (NULL, verticalScrollBar);
}
diff --git a/sys/InfoEditor.cpp b/sys/InfoEditor.cpp
index 4e7c9b2..c702efd 100644
--- a/sys/InfoEditor.cpp
+++ b/sys/InfoEditor.cpp
@@ -1,6 +1,6 @@
/* InfoEditor.cpp
*
- * Copyright (C) 2004-2011,2012 Paul Boersma
+ * Copyright (C) 2004-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,7 +41,17 @@ void gui_information (const wchar_t *message) {
}
theInfoEditor -> textWidget -> f_setString (message);
theInfoEditor -> d_windowForm -> f_show ();
- theInfoEditor -> d_windowForm -> f_drain ();
+ /*
+ * Try to make sure that the invalidated text widget and the elements of the fronted window are redrawn before the next event.
+ */
+ #if cocoa
+ //[theInfoEditor -> d_windowForm -> d_cocoaWindow displayIfNeeded]; // apparently, this does not suffice
+ [theInfoEditor -> d_windowForm -> d_cocoaWindow display]; // this displays the menu as well as the text
+ //[theInfoEditor -> textWidget -> d_cocoaTextView displayIfNeeded]; // this displays only the text
+ //[theInfoEditor -> textWidget -> d_cocoaTextView display];
+ #elif defined (macintosh)
+ theInfoEditor -> d_windowForm -> f_drain ();
+ #endif
}
/* End of file InfoEditor.cpp */
diff --git a/sys/Makefile b/sys/Makefile
index 553b142..5c68e49 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -1,5 +1,5 @@
# Makefile of the library "sys"
-# Paul Boersma, 11 September 2012
+# Paul Boersma, 24 August 2013
include ../makefile.defs
@@ -39,7 +39,7 @@ clean:
libsys.a: $(OBJECTS)
touch libsys.a
rm libsys.a
- ar cq libsys.a $(OBJECTS)
+ $(AR) cq libsys.a $(OBJECTS)
$(RANLIB) libsys.a
$(OBJECTS): *.h ../num/NUM.h ../dwsys/*.h ../kar/*.h ../external/portaudio/*.h ../external/flac/*.h ../external/mp3/mp3.h
diff --git a/sys/ManPages.cpp b/sys/ManPages.cpp
index 9a4bca8..c19ca6e 100644
--- a/sys/ManPages.cpp
+++ b/sys/ManPages.cpp
@@ -566,7 +566,7 @@ static void writeParagraphsAsHtml (ManPages me, MelderFile file, ManPage_Paragra
theCurrentPraatPicture -> y1NDC = 0;
theCurrentPraatPicture -> y2NDC = paragraph -> height;
Graphics_setViewport (graphics, theCurrentPraatPicture -> x1NDC, theCurrentPraatPicture -> x2NDC, theCurrentPraatPicture -> y1NDC, theCurrentPraatPicture -> y2NDC);
- { // scope
+ {// scope
autoMelderProgressOff progress;
autoMelderWarningOff warning;
autoMelderSaveDefaultDir saveDir;
diff --git a/sys/Picture.cpp b/sys/Picture.cpp
index a6e3fa4..ccac239 100644
--- a/sys/Picture.cpp
+++ b/sys/Picture.cpp
@@ -1,6 +1,6 @@
/* Picture.cpp
*
- * Copyright (C) 1992-2011,2012 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
* fb 2010/03/01 cairo fix for black 1px borders
* pb 2011/05/15 C++
* pb 2011/07/08 C++
+ * pb 2013/08/31 removed all GTK code that redrew the whole Picture window while dragging
*/
#include "melder.h"
@@ -47,13 +48,6 @@ struct structPicture {
void (*selectionChangedCallback) (struct structPicture *, void *, double, double, double, double);
void *selectionChangedClosure;
int backgrounding, mouseSelectsInnerViewport;
- #if gtk
- bool selectionInProgress;
- double ixstart, iystart;
- #elif cocoa
- bool selectionInProgress;
- double ixstart, iystart;
- #endif
};
static void drawMarkers (Picture me)
@@ -157,97 +151,16 @@ static void gui_drawingarea_cb_expose (I, GuiDrawingAreaExposeEvent event) {
// Stefan, zoals gezegd, er zijn goede redenen waarom sommige platforms dit synchroon oplossen;
// misschien maar splitsen tussen die platforms en platforms die met events kunnen werken.
-// On Cocoa this leads to flashing, it definitely needs to be event based..
+// (Tom:) On Cocoa this leads to flashing, it definitely needs to be event based.
+
+// (Paul:) No, running this through the normal event loop with mouse-down-drag-up events and generating exposes
+// redrew the entire picture window on every change of the selection during dragging. Much too slow!
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
iam (Picture);
int xstart = event -> x;
int ystart = event -> y;
double xWC, yWC;
-#if gtk
- int ix, iy;
-
- Graphics_DCtoWC (my selectionGraphics, xstart, ystart, & xWC, & yWC);
- ix = 1 + floor (xWC * SQUARES / SIDE);
- iy = SQUARES - floor (yWC * SQUARES / SIDE);
-// if (my ixstart < 1 || my ixstart > SQUARES || my iystart < 1 || my iystart > SQUARES) return;
-
- if (my selectionInProgress == 0) {
- if (event->type == BUTTON_PRESS) {
- my selectionInProgress = 1;
- my ixstart = ix;
- my iystart = iy;
- }
- } else {
- int ix1, ix2, iy1, iy2;
- if (ix < my ixstart) { ix1 = ix; ix2 = my ixstart; }
- else { ix1 = my ixstart; ix2 = ix; }
- if (iy < my iystart) { iy1 = iy; iy2 = my iystart; }
- else { iy1 = my iystart; iy2 = iy; }
- if (my mouseSelectsInnerViewport) {
- int fontSize = Graphics_inqFontSize (my graphics);
- double xmargin = fontSize * 4.2 / 72.0, ymargin = fontSize * 2.8 / 72.0;
- if (xmargin > ix2 - ix1 + 1) xmargin = ix2 - ix1 + 1;
- if (ymargin > iy2 - iy1 + 1) ymargin = iy2 - iy1 + 1;
- Picture_setSelection (me, 0.5 * (ix1 - 1) - xmargin, 0.5 * ix2 + xmargin,
- 0.5 * (SQUARES - iy2) - ymargin, 0.5 * (SQUARES + 1 - iy1) + ymargin, False);
- } else {
- Picture_setSelection (me, 0.5 * (ix1 - 1), 0.5 * ix2,
- 0.5 * (SQUARES - iy2), 0.5 * (SQUARES + 1 - iy1), False);
- }
-
- if (event->type == BUTTON_RELEASE) {
- my selectionInProgress = 0;
- if (my selectionChangedCallback) {
- //Melder_casual ("selectionChangedCallback from gui_drawingarea_cb_click");
- my selectionChangedCallback (me, my selectionChangedClosure,
- my selx1, my selx2, my sely1, my sely2);
- }
- }
- }
-#elif cocoa
- int ix, iy;
-
- Graphics_DCtoWC (my selectionGraphics, xstart, ystart, & xWC, & yWC);
- ix = 1 + floor (xWC * SQUARES / SIDE);
- iy = SQUARES - floor (yWC * SQUARES / SIDE);
- // if (my ixstart < 1 || my ixstart > SQUARES || my iystart < 1 || my iystart > SQUARES) return;
-
- if (my selectionInProgress == 0) {
- if (event->type == BUTTON_PRESS) {
- my selectionInProgress = 1;
- my ixstart = ix;
- my iystart = iy;
- }
- } else {
- int ix1, ix2, iy1, iy2;
- if (ix < my ixstart) { ix1 = ix; ix2 = my ixstart; }
- else { ix1 = my ixstart; ix2 = ix; }
- if (iy < my iystart) { iy1 = iy; iy2 = my iystart; }
- else { iy1 = my iystart; iy2 = iy; }
- if (my mouseSelectsInnerViewport) {
- int fontSize = Graphics_inqFontSize (my graphics);
- double xmargin = fontSize * 4.2 / 72.0, ymargin = fontSize * 2.8 / 72.0;
- if (xmargin > ix2 - ix1 + 1) xmargin = ix2 - ix1 + 1;
- if (ymargin > iy2 - iy1 + 1) ymargin = iy2 - iy1 + 1;
- Picture_setSelection (me, 0.5 * (ix1 - 1) - xmargin, 0.5 * ix2 + xmargin,
- 0.5 * (SQUARES - iy2) - ymargin, 0.5 * (SQUARES + 1 - iy1) + ymargin, NO);
- } else {
- Picture_setSelection (me, 0.5 * (ix1 - 1), 0.5 * ix2,
- 0.5 * (SQUARES - iy2), 0.5 * (SQUARES + 1 - iy1), NO);
- }
-
- if (event->type == BUTTON_RELEASE) {
- my selectionInProgress = 0;
- if (my selectionChangedCallback) {
- //Melder_casual ("selectionChangedCallback from gui_drawingarea_cb_click");
- my selectionChangedCallback (me, my selectionChangedClosure,
- my selx1, my selx2, my sely1, my sely2);
- }
- }
- }
-
-#else
int ixstart, iystart, ix, iy, oldix = 0, oldiy = 0;
Graphics_DCtoWC (my selectionGraphics, xstart, ystart, & xWC, & yWC);
@@ -262,7 +175,10 @@ static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
ixstart = ix < (ix1 + ix2) / 2 ? ix2 : ix1;
iystart = iy < (iy1 + iy2) / 2 ? iy2 : iy1;
}
- while (Graphics_mouseStillDown (my selectionGraphics)) {
+ do {
+ Graphics_getMouseLocation (my selectionGraphics, & xWC, & yWC);
+ ix = 1 + floor (xWC * SQUARES / SIDE);
+ iy = SQUARES - floor (yWC * SQUARES / SIDE);
if (ix >= 1 && ix <= SQUARES && iy >= 1 && iy <= SQUARES && (ix != oldix || iy != oldiy)) {
int ix1, ix2, iy1, iy2;
if (ix < ixstart) { ix1 = ix; ix2 = ixstart; }
@@ -279,31 +195,24 @@ static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
} else {
Picture_setSelection (me, 0.5 * (ix1 - 1), 0.5 * ix2,
0.5 * (SQUARES - iy2), 0.5 * (SQUARES + 1 - iy1), false);
- #if gtk
- Graphics_flushWs (my graphics);
- #endif
}
oldix = ix; oldiy = iy;
}
- Graphics_getMouseLocation (my selectionGraphics, & xWC, & yWC);
- ix = 1 + floor (xWC * SQUARES / SIDE);
- iy = SQUARES - floor (yWC * SQUARES / SIDE);
- }
+ } while (Graphics_mouseStillDown (my selectionGraphics));
+ #if cocoa
+ Graphics_updateWs (my selectionGraphics); // to change the dark red back into black
+ #endif
if (my selectionChangedCallback) {
//Melder_casual ("selectionChangedCallback from gui_drawingarea_cb_click");
my selectionChangedCallback (me, my selectionChangedClosure,
my selx1, my selx2, my sely1, my sely2);
}
-#endif
}
Picture Picture_create (GuiDrawingArea drawingArea, bool sensitive) {
Picture me = NULL;
try {
me = Melder_calloc (struct structPicture, 1);
- #if gtk
- my selectionInProgress = 0;
- #endif
my drawingArea = drawingArea;
/*
* The initial viewport is a rectangle 6 inches wide and 4 inches high.
@@ -534,7 +443,7 @@ void Picture_writeToEpsFile (Picture me, MelderFile file, int includeFonts, int
MelderFile_delete (file); // to kill resources as well (fopen only kills data fork)
/* BUG: no message if file cannot be deleted (e.g. because still open by Microsoft Word 2001 after reading). */
- { // scope
+ {// scope
autoGraphics ps = Graphics_create_epsfile (file, 600, thePrinter. spots,
my selx1, my selx2, my sely1, my sely2, includeFonts, useSilipaPS);
Graphics_play ((Graphics) my graphics, ps.peek());
@@ -571,48 +480,14 @@ void Picture_setSelection
{
if (my drawingArea) {
Melder_assert (my drawingArea -> d_widget);
-#if gtk
- long x1, x2, y1, y2;
- Graphics_WCtoDC (my selectionGraphics, my selx1, my sely1, & x1, & y1);
- Graphics_WCtoDC (my selectionGraphics, my selx2, my sely2, & x2, & y2);
- gtk_widget_queue_draw_area (GTK_WIDGET (my drawingArea -> d_widget), x1, y2, abs (x2 - x1), abs (y2 - y1));
-#elif cocoa
- long x1, x2, y1, y2;
- Graphics_WCtoDC (my selectionGraphics, my selx1, my sely1, & x1, & y1);
- Graphics_WCtoDC (my selectionGraphics, my selx2, my sely2, & x2, & y2);
- GuiCocoaDrawingArea *drawingArea = (GuiCocoaDrawingArea*)my drawingArea -> d_widget;
-// long height = [drawingArea frame].size.height;
-// NSRect changedRect = NSMakeRect(x1, height - y2, abs (x2 - x1), abs (y2 - y1));
-// [drawingArea setNeedsDisplayInRect:changedRect];
- [drawingArea setNeedsDisplay:YES];
-
-#else
- drawSelection (me, 0); // unselect
- #endif
+ drawSelection (me, 0); // unselect
}
my selx1 = x1NDC;
my selx2 = x2NDC;
my sely1 = y1NDC;
my sely2 = y2NDC;
if (my drawingArea) {
-#if gtk
- long x1, x2, y1, y2;
- Graphics_WCtoDC (my selectionGraphics, my selx1, my sely1, & x1, & y1);
- Graphics_WCtoDC (my selectionGraphics, my selx2, my sely2, & x2, & y2);
- gtk_widget_queue_draw_area (GTK_WIDGET (my drawingArea -> d_widget), x1, y2, abs (x2 - x1), abs (y2 - y1));
-#elif cocoa
- long x1, x2, y1, y2;
- Graphics_WCtoDC (my selectionGraphics, my selx1, my sely1, & x1, & y1);
- Graphics_WCtoDC (my selectionGraphics, my selx2, my sely2, & x2, & y2);
- GuiCocoaDrawingArea *drawingArea = (GuiCocoaDrawingArea*)my drawingArea -> d_widget;
-// long height = [drawingArea frame].size.height;
-// NSRect changedRect = NSMakeRect(x1, height- y2, abs (x2 - x1), abs (y2 - y1));
-// [drawingArea setNeedsDisplayInRect:changedRect];
- [drawingArea setNeedsDisplay:YES];
-
-#else
- drawSelection (me, 1); // select
- #endif
+ drawSelection (me, 1); // select
}
if (notify && my selectionChangedCallback) {
@@ -625,16 +500,4 @@ void Picture_setSelection
void Picture_background (Picture me) { my backgrounding = TRUE; }
void Picture_foreground (Picture me) { my backgrounding = FALSE; }
-#if gtk
-void Picture_selfExpose (Picture me) {
- if (my drawingArea) {
- Melder_assert (my drawingArea -> d_widget);
- long x1, x2, y1, y2;
- Graphics_WCtoDC (my selectionGraphics, my selx1, my sely1, & x1, & y1);
- Graphics_WCtoDC (my selectionGraphics, my selx2, my sely2, & x2, & y2);
- gtk_widget_queue_draw_area (GTK_WIDGET (my drawingArea -> d_widget), x1, y2, abs (x2 - x1), abs (y2 - y1));
- }
-}
-#endif
-
/* End of file Picture.cpp */
diff --git a/sys/Picture.h b/sys/Picture.h
index 3a097c4..80314ae 100644
--- a/sys/Picture.h
+++ b/sys/Picture.h
@@ -2,7 +2,7 @@
#define _Picture_h_
/* Picture.h
*
- * Copyright (C) 1992-2011,2012 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -137,7 +137,5 @@ void Picture_setSelection
void Picture_background (Picture me);
void Picture_foreground (Picture me);
-void Picture_selfExpose (Picture me);
-
/* End of file Picture.h */
#endif
diff --git a/sys/Ui.cpp b/sys/Ui.cpp
index c45b6e8..062ebab 100644
--- a/sys/Ui.cpp
+++ b/sys/Ui.cpp
@@ -385,6 +385,7 @@ void structUiForm :: v_destroy () {
for (int ifield = 1; ifield <= numberOfFields; ifield ++)
forget (field [ifield]);
if (d_dialogForm) {
+ trace ("invoking button title %ls", invokingButtonTitle);
GuiObject_destroy (d_dialogForm -> d_widget); // BUG: make sure this destroys the shell
}
Melder_free (invokingButtonTitle);
@@ -492,8 +493,9 @@ static void UiForm_okOrApply (I, GuiButton button, int hide) {
UiHistory_write_expandQuotes (field -> strings [field -> integerValue]);
UiHistory_write (L"\"");
} break; case UI_COLOUR: {
- UiHistory_write (L", ");
+ UiHistory_write (L", \"");
UiHistory_write (Graphics_Colour_name (field -> colourValue));
+ UiHistory_write (L"\"");
}
}
}
diff --git a/sys/UiPause.cpp b/sys/UiPause.cpp
index 3a418e0..133e9c1 100644
--- a/sys/UiPause.cpp
+++ b/sys/UiPause.cpp
@@ -156,7 +156,7 @@ int UiPause_end (int numberOfContinueButtons, int defaultContinueButton, int can
* Wait for the user to click Stop or Continue.
*/
#ifndef CONSOLE_APPLICATION
- { // scope
+ {// scope
autoMelderSaveDefaultDir saveDir;
thePauseForm_clicked = 0;
Melder_assert (theEventLoopDepth == 0);
diff --git a/sys/abcio.cpp b/sys/abcio.cpp
index c18a6e1..edf4daa 100644
--- a/sys/abcio.cpp
+++ b/sys/abcio.cpp
@@ -786,9 +786,10 @@ long bingeti4 (FILE *f) {
} else {
unsigned char bytes [4];
if (fread (bytes, sizeof (unsigned char), 4, f) != 4) readError (f, "four bytes.");
- return
- ((unsigned long) bytes [0] << 24) | ((unsigned long) bytes [1] << 16) |
- ((unsigned long) bytes [2] << 8) | (unsigned long) bytes [3]; // 32 or 64 bits
+ uint32_t externalValue =
+ ((uint32_t) bytes [0] << 24) | ((uint32_t) bytes [1] << 16) |
+ ((uint32_t) bytes [2] << 8) | (uint32_t) bytes [3];
+ return (long) (int32_t) externalValue; // first add signedness, then extend
}
} catch (MelderError) {
Melder_throw ("Signed long integer not read from 4 bytes in binary file.");
@@ -804,9 +805,10 @@ unsigned long bingetu4 (FILE *f) {
} else {
unsigned char bytes [4];
if (fread (bytes, sizeof (unsigned char), 4, f) != 4) readError (f, "four bytes.");
- return
- ((unsigned long) bytes [0] << 24) | ((unsigned long) bytes [1] << 16) |
- ((unsigned long) bytes [2] << 8) | (unsigned long) bytes [3]; // 32 or 64 bits
+ uint32_t externalValue =
+ ((uint32_t) bytes [0] << 24) | ((uint32_t) bytes [1] << 16) |
+ ((uint32_t) bytes [2] << 8) | (uint32_t) bytes [3];
+ return (unsigned long) externalValue;
}
} catch (MelderError) {
Melder_throw ("Unsigned long integer not read from 4 bytes in binary file.");
@@ -869,9 +871,9 @@ long bingeti4LE (FILE *f) {
} else {
unsigned char bytes [4];
if (fread (bytes, sizeof (unsigned char), 4, f) != 4) readError (f, "four bytes.");
- return
- ((unsigned long) bytes [3] << 24) | ((unsigned long) bytes [2] << 16) |
- ((unsigned long) bytes [1] << 8) | (unsigned long) bytes [0]; // 32 or 64 bits
+ uint32_t externalValue = ((uint32_t) bytes [3] << 24) | ((uint32_t) bytes [2] << 16) |
+ ((uint32_t) bytes [1] << 8) | (uint32_t) bytes [0];
+ return (long) (int32_t) externalValue; // first add signedness, then extend
}
} catch (MelderError) {
Melder_throw ("Signed long integer not read from 4 bytes in binary file.");
@@ -887,9 +889,9 @@ unsigned long bingetu4LE (FILE *f) {
} else {
unsigned char bytes [4];
if (fread (bytes, sizeof (unsigned char), 4, f) != 4) readError (f, "four bytes.");
- return
- ((unsigned long) bytes [3] << 24) | ((unsigned long) bytes [2] << 16) |
- ((unsigned long) bytes [1] << 8) | (unsigned long) bytes [0]; // 32 or 64 bits
+ uint32_t externalValue = ((uint32_t) bytes [3] << 24) | ((uint32_t) bytes [2] << 16) |
+ ((uint32_t) bytes [1] << 8) | (uint32_t) bytes [0];
+ return (unsigned long) externalValue;
}
} catch (MelderError) {
Melder_throw ("Unsigned long integer not read from 4 bytes in binary file.");
diff --git a/sys/machine.cpp b/sys/machine.cpp
index f25faae..e3b7886 100644
--- a/sys/machine.cpp
+++ b/sys/machine.cpp
@@ -1,6 +1,6 @@
/* machine.cpp
*
- * Copyright (C) 1992-2011,2012 Paul Boersma
+ * Copyright (C) 1992-2011,2012,2013 Paul Boersma
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -107,7 +107,7 @@ int Machine_getTextHeight (void) {
22, /* Mac */
20, /* Win32 */
25, /* Linux */
- 25 /* Cocoa */
+ 23 /* Cocoa */
};
return heights [lookAndFeel];
}
diff --git a/sys/melder.cpp b/sys/melder.cpp
index 04b9a83..80b1e57 100644
--- a/sys/melder.cpp
+++ b/sys/melder.cpp
@@ -1,6 +1,6 @@
/* melder.cpp
*
- * Copyright (C) 1992-2012 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
+ * Copyright (C) 1992-2012,2013 Paul Boersma, 2008 Stefan de Konink, 2010 Franz Brausse, 2013 Tom Naughton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -188,7 +188,17 @@ static bool waitWhileProgress (double progress, const wchar_t *message, GuiDialo
}
do { XtNextEvent ((XEvent *) & event); XtDispatchEvent ((XEvent *) & event); } while (event.what);
#else
- // Cocoa
+ NSEvent *nsEvent = [NSApp
+ nextEventMatchingMask: NSAnyEventMask
+ untilDate: [NSDate distantPast]
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES
+ ];
+ if (nsEvent) {
+ NSUInteger nsEventType = [nsEvent type];
+ if (nsEventType == NSKeyDown) NSBeep ();
+ [[nsEvent window] sendEvent: nsEvent];
+ }
#endif
#elif defined (_WIN32)
XEvent event;
@@ -247,6 +257,9 @@ static bool waitWhileProgress (double progress, const wchar_t *message, GuiDialo
trace ("the cancel button has been pressed");
return false; // don't continue
}
+ #elif cocoa
+ scale -> f_setValue (progress);
+ //[scale -> d_cocoaProgressBar displayIfNeeded];
#elif motif
scale -> f_setValue (progress);
XmUpdateDisplay (dia -> d_widget);
@@ -281,7 +294,7 @@ static void _Melder_dia_init (GuiDialog *dia, GuiProgressBar *scale, GuiLabel *l
*label2 = GuiLabel_createShown (*dia, 3, 403, 30, 30 + Gui_LABEL_HEIGHT, L"label2", 0);
trace ("creating the scale");
- *scale = GuiProgressBar_createShown (*dia, 3, 403, 70, 110, 0);
+ *scale = GuiProgressBar_createShown (*dia, 3, -3, 70, 110, 0);
trace ("creating the cancel button");
*cancelButton = GuiButton_createShown (*dia, 0, 400, 170, 170 + Gui_PUSHBUTTON_HEIGHT,
@@ -774,8 +787,8 @@ int Melder_assert_ (const char *condition, const char *fileName, int lineNumber)
#ifndef CONSOLE_APPLICATION
#if defined (macintosh)
-static void mac_message (int macAlertType, const wchar_t *messageW) {
- static UniChar messageU [4000];
+static void mac_message (NSAlertStyle macAlertType, const wchar_t *messageW) {
+ static unichar messageU [4000];
int messageLength = wcslen (messageW);
int j = 0;
for (int i = 0; i < messageLength && j <= 4000 - 2; i ++) {
@@ -788,18 +801,65 @@ static void mac_message (int macAlertType, const wchar_t *messageW) {
messageU [j ++] = 0xDC00 | (kar & 0x3FF);
}
}
+
+ /*
+ * Split up the message between header (will appear in bold) and rest.
+ * The split is done at the first line break, except if the first line ends in a colon,
+ * in which case the split is done at the second line break.
+ */
+ UniChar *lineBreak = & messageU [0];
+ for (; *lineBreak != '\0'; lineBreak ++) {
+ if (*lineBreak == '\n') {
+ break;
+ }
+ }
+ if (*lineBreak == '\n' && lineBreak - messageU > 0 && lineBreak [-1] == ':') {
+ for (lineBreak ++; *lineBreak != '\0'; lineBreak ++) {
+ if (*lineBreak == '\n') {
+ break;
+ }
+ }
+ }
#if useCarbon
DialogRef dialog;
CFStringRef messageCF = CFStringCreateWithCharacters (NULL, messageU, j);
CreateStandardAlert (macAlertType, messageCF, NULL, NULL, & dialog);
CFRelease (messageCF);
RunStandardAlert (dialog, NULL, NULL);
+ #elif fhgfdghdggfkdsgfXXX
+ NSString *header = NULL, *rest = NULL;
+ header = [[NSString alloc] initWithCharacters: messageU length: lineBreak - messageU]; // note: init can change the object pointer!
+ if (lineBreak - messageU != j) {
+ rest = [[NSString alloc] initWithCharacters: lineBreak + 1 length: j - 1 - (lineBreak - messageU)];
+ }
+ NSRunAlertPanel (header, rest, NULL, NULL, NULL);
+ [header release];
+ if (rest) [rest release];
#else
- CFStringRef messageCF = CFStringCreateWithCharacters (NULL, messageU, j);
- CFOptionFlags cfRes;
- CFUserNotificationDisplayAlert(0, macAlertType, NULL, NULL, NULL,
- CFSTR("Error"), messageCF, CFSTR("OK"), NULL, NULL, &cfRes);
- CFRelease (messageCF);
+ /*
+ * Create an alert dialog with an icon that is appropriate for the level.
+ */
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setAlertStyle: macAlertType];
+ /*
+ * Add the header in bold.
+ */
+ NSString *header = [[NSString alloc] initWithCharacters: messageU length: lineBreak - messageU]; // note: init can change the object pointer!
+ [alert setMessageText: header];
+ [header release];
+ /*
+ * Add the rest of the message in small type.
+ */
+ if (lineBreak - messageU != j) {
+ NSString *rest = [[NSString alloc] initWithCharacters: lineBreak + 1 length: j - 1 - (lineBreak - messageU)];
+ [alert setInformativeText: rest];
+ [rest release];
+ }
+ /*
+ * Display the alert dialog and synchronously wait for the user to click OK.
+ */
+ [alert runModal];
+ [alert release];
#endif
}
#endif
@@ -816,14 +876,14 @@ static void gui_fatal (const wchar_t *message) {
gtk_widget_destroy (GTK_WIDGET (dialog));
#elif defined (macintosh)
#if useCarbon
- mac_message (kAlertStopAlert, message);
+ mac_message (NSCriticalAlertStyle, message);
SysError (11);
#else
- mac_message (kCFUserNotificationStopAlertLevel, message);
+ mac_message (NSCriticalAlertStyle, message);
SysError (11);
#endif
#elif defined (_WIN32)
- MessageBox (NULL, message, L"Fatal error", MB_OK | MB_TOPMOST);
+ MessageBox (NULL, message, L"Fatal error", MB_OK | MB_TOPMOST | MB_ICONSTOP);
#endif
}
@@ -835,20 +895,20 @@ static void gui_error (const wchar_t *message) {
#if gtk
trace ("create dialog");
GuiObject dialog = gtk_message_dialog_new (GTK_WINDOW (Melder_topShell -> d_gtkWindow), GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", Melder_peekWcsToUtf8 (message));
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", Melder_peekWcsToUtf8 (message));
trace ("run dialog");
gtk_dialog_run (GTK_DIALOG (dialog));
trace ("destroy dialog");
gtk_widget_destroy (GTK_WIDGET (dialog));
#elif defined (macintosh)
#if useCarbon
- mac_message (kAlertStopAlert, message);
+ mac_message (NSWarningAlertStyle, message);
XmUpdateDisplay (0);
#else
- mac_message (kCFUserNotificationStopAlertLevel, message);
+ mac_message (NSWarningAlertStyle, message);
#endif
#elif defined (_WIN32)
- MessageBox (NULL, message, L"Message", MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION); // or (HWND) XtWindow ((GuiObject) Melder_topShell)
+ MessageBox (NULL, message, L"Message", MB_OK | MB_TOPMOST | MB_ICONWARNING); // or (HWND) XtWindow ((GuiObject) Melder_topShell)
#endif
if (memoryIsLow) {
theMessageFund = (char *) malloc (theMessageFund_SIZE);
@@ -860,10 +920,10 @@ static void gui_error (const wchar_t *message) {
gtk_widget_destroy (GTK_WIDGET (dialog));
#elif defined (macintosh)
#if useCarbon
- mac_message (kAlertStopAlert, L"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
+ mac_message (NSCriticalAlertStyle, L"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
XmUpdateDisplay (0);
#else
- mac_message (kCFUserNotificationStopAlertLevel, L"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
+ mac_message (NSCriticalAlertStyle, L"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.");
#endif
#elif defined (_WIN32)
MessageBox (NULL, L"Praat is very low on memory.\nSave your work and quit Praat.\nIf you don't do that, Praat may crash.", L"Message", MB_OK);
@@ -875,18 +935,18 @@ static void gui_error (const wchar_t *message) {
static void gui_warning (const wchar_t *message) {
#if gtk
GuiObject dialog = gtk_message_dialog_new (GTK_WINDOW (Melder_topShell -> d_gtkWindow), GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", Melder_peekWcsToUtf8 (message));
+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", Melder_peekWcsToUtf8 (message));
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (GTK_WIDGET (dialog));
#elif defined (macintosh)
#if useCarbon
- mac_message (kAlertNoteAlert, message);
+ mac_message (NSInformationalAlertStyle, message);
XmUpdateDisplay (0);
#else
- mac_message (kCFUserNotificationStopAlertLevel, message);
+ mac_message (NSInformationalAlertStyle, message);
#endif
#elif defined (_WIN32)
- MessageBox (NULL, message, L"Warning", MB_OK | MB_TOPMOST);
+ MessageBox (NULL, message, L"Warning", MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
#endif
}
diff --git a/sys/melder.h b/sys/melder.h
index 28a6953..9b93b61 100644
--- a/sys/melder.h
+++ b/sys/melder.h
@@ -1018,6 +1018,13 @@ struct autoMelderProgressOff {
struct autoMelderString : MelderString {
autoMelderString () { length = 0; bufferSize = 0; string = NULL; }
~autoMelderString () { Melder_free (string); }
+ wchar_t * transfer () {
+ wchar_t *tmp = string;
+ string = NULL;
+ length = 0;
+ bufferSize = 0;
+ return tmp;
+ }
};
struct autoMelderReadText {
diff --git a/sys/melder_audiofiles.cpp b/sys/melder_audiofiles.cpp
index d5bd09e..66ed421 100644
--- a/sys/melder_audiofiles.cpp
+++ b/sys/melder_audiofiles.cpp
@@ -933,7 +933,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
} else { // optimize
long numberOfBytes = numberOfChannels * numberOfSamples * numberOfBytesPerSamplePerChannel;
unsigned char *bytes = (unsigned char *) & buffer [numberOfChannels] [numberOfSamples] + sizeof (double) - numberOfBytes;
- if (fread (bytes, 1, numberOfBytes, f) < numberOfBytes) throw MelderError (); // read 24-bit data into last three-eigths of buffer
+ if (fread (bytes, 1, numberOfBytes, f) < numberOfBytes) throw MelderError (); // read 24-bit data into last three-eighths of buffer
if (numberOfChannels == 1) {
for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
unsigned char byte1 = * bytes ++, byte2 = * bytes ++, byte3 = * bytes ++;
@@ -969,7 +969,7 @@ void Melder_readAudioToFloat (FILE *f, int numberOfChannels, int encoding, doubl
} else { // optimize
long numberOfBytes = numberOfChannels * numberOfSamples * numberOfBytesPerSamplePerChannel;
unsigned char *bytes = (unsigned char *) & buffer [numberOfChannels] [numberOfSamples] + sizeof (double) - numberOfBytes;
- if (fread (bytes, 1, numberOfBytes, f) < numberOfBytes) throw MelderError (); // read 24-bit data into last three-eights of buffer
+ if (fread (bytes, 1, numberOfBytes, f) < numberOfBytes) throw MelderError (); // read 24-bit data into last three-eighths of buffer
if (numberOfChannels == 1) {
for (long isamp = 1; isamp <= numberOfSamples; isamp ++) {
unsigned char byte1 = * bytes ++, byte2 = * bytes ++, byte3 = * bytes ++;
diff --git a/sys/motifEmulator.cpp b/sys/motifEmulator.cpp
index 313152c..22b0c99 100644
--- a/sys/motifEmulator.cpp
+++ b/sys/motifEmulator.cpp
@@ -4816,11 +4816,11 @@ void GuiMainLoop () {
theUserMessageCallbackW = userMessageCallback;
}
#endif
-#endif
-
void Gui_setOpenDocumentCallback (void (*openDocumentCallback) (MelderFile file)) {
theOpenDocumentCallback = openDocumentCallback;
}
+#endif
+
void Gui_setQuitApplicationCallback (int (*quitApplicationCallback) (void)) {
theQuitApplicationCallback = quitApplicationCallback;
}
diff --git a/sys/praat.cpp b/sys/praat.cpp
index 23414e3..4ad108e 100644
--- a/sys/praat.cpp
+++ b/sys/praat.cpp
@@ -502,8 +502,9 @@ static void gui_cb_list (void *void_me, GuiListEvent event) {
long readableClassId = ((Thing) theCurrentPraatObjects -> list [IOBJECT]. object) -> classInfo -> sequentialUniqueIdOfReadableClass;
theCurrentPraatObjects -> numberOfSelected [readableClassId] ++;
Melder_assert (theCurrentPraatObjects -> numberOfSelected [readableClassId] > 0);
- UiHistory_write (first ? L"\nselect " : L"\nplus ");
- UiHistory_write (FULL_NAME);
+ UiHistory_write (first ? L"\nselectObject (\"" : L"\nplusObject (\"");
+ UiHistory_write_expandQuotes (FULL_NAME);
+ UiHistory_write (L"\")");
first = FALSE;
theCurrentPraatObjects -> totalSelection += 1;
}
@@ -863,9 +864,29 @@ void praat_dontUsePictureWindow (void) { praatP.dontUsePictureWindow = TRUE; }
/********** INITIALIZATION OF THE PRAAT SHELL **********/
#if defined (UNIX)
+ static void cb_sigusr1 (int signum) {
+ Melder_assert (signum == SIGUSR1);
+ #if 0
+ gboolean retval;
+ g_signal_emit_by_name (GTK_OBJECT (theCurrentPraatApplication -> topShell -> d_gtkWindow), "client-event", NULL, & retval);
+ #else
+ GdkEventClient gevent;
+ gevent. type = GDK_CLIENT_EVENT;
+ gevent. window = GTK_WIDGET (theCurrentPraatApplication -> topShell -> d_gtkWindow) -> window;
+ gevent. send_event = 1;
+ gevent. message_type = gdk_atom_intern_static_string ("SENDPRAAT");
+ gevent. data_format = 8;
+ // Melder_casual ("event put");
+ gdk_event_put ((GdkEvent *) & gevent);
+ #endif
+ }
+#endif
+
+#if defined (UNIX)
static gboolean cb_userMessage (GtkWidget widget, GdkEventClient *event, gpointer user_data) {
(void) widget;
(void) user_data;
+ //Melder_casual ("client event called");
autofile f;
try {
f.reset (Melder_fopen (& messageFile, "r"));
@@ -873,10 +894,10 @@ void praat_dontUsePictureWindow (void) { praatP.dontUsePictureWindow = TRUE; }
Melder_clearError ();
return true; // OK
}
- long pid;
+ long pid = 0;
int narg = fscanf (f, "#%ld", & pid);
f.close (& messageFile);
- { // scope
+ {// scope
autoPraatBackground background;
try {
praat_executeScriptFromFile (& messageFile, NULL);
@@ -885,7 +906,7 @@ void praat_dontUsePictureWindow (void) { praatP.dontUsePictureWindow = TRUE; }
Melder_flushError (NULL);
}
}
- if (narg) kill (pid, SIGUSR2);
+ if (narg && pid) kill (pid, SIGUSR2);
return true;
}
#elif defined (_WIN32)
@@ -1254,7 +1275,7 @@ void praat_init (const char *title, unsigned int argc, char **argv) {
#endif
#if ! defined (CONSOLE_APPLICATION) && ! defined (macintosh)
trace ("initializing the Gui late");
- MelderGui_create (theCurrentPraatApplication -> topShell); /* Mac: done this earlier. */
+ MelderGui_create (theCurrentPraatApplication -> topShell); // Mac: done this earlier
#endif
Melder_setHelpProc (helpProc);
}
@@ -1442,7 +1463,7 @@ void praat_run (void) {
/* Each line separately: every error should be ignored.
*/
praatP.phase = praat_READING_BUTTONS;
- { // scope
+ {// scope
autostring buttons;
try {
buttons.reset (MelderFile_readText (& buttonsFile));
@@ -1477,6 +1498,7 @@ void praat_run (void) {
trace ("install GTK key snooper");
trace ("locale is %s", setlocale (LC_ALL, NULL));
g_signal_connect (G_OBJECT (theCurrentPraatApplication -> topShell -> d_gtkWindow), "client-event", G_CALLBACK (cb_userMessage), NULL);
+ signal (SIGUSR1, cb_sigusr1);
gtk_key_snooper_install (theKeySnooper, 0);
trace ("start the GTK event loop");
trace ("locale is %s", setlocale (LC_ALL, NULL));
diff --git a/sys/praat_actions.cpp b/sys/praat_actions.cpp
index 99bfbbb..d0850a2 100644
--- a/sys/praat_actions.cpp
+++ b/sys/praat_actions.cpp
@@ -32,6 +32,7 @@ static struct structPraat_Command *theActions;
static GuiMenu praat_writeMenu;
static GuiMenuItem praat_writeMenuSeparator;
static GuiForm praat_form;
+static bool actionsInvisible = false;
static void fixSelectionSpecification (ClassInfo *class1, int *n1, ClassInfo *class2, int *n2, ClassInfo *class3, int *n3) {
/*
@@ -176,15 +177,19 @@ void praat_addAction4 (ClassInfo class1, int n1, ClassInfo class2, int n2, Class
static void deleteDynamicMenu (void) {
if (praatP.phase != praat_HANDLING_EVENTS) return;
+ if (actionsInvisible) return;
static long numberOfDeletions;
trace ("deletion #%ld", ++ numberOfDeletions);
for (int i = 1; i <= theNumberOfActions; i ++) {
if (theActions [i]. button) {
- #if gtk
+ trace ("trying to destroy action %d of %d: %ls", i, (int) theNumberOfActions, theActions [i]. title);
+ #if gtk || cocoa
if (theActions [i]. button -> d_parent == praat_form) {
- GuiObject_destroy (theActions [i]. button -> d_widget); // a label or a push button or a cascade button
+ trace ("destroy a label or a push button or a cascade button");
+ GuiObject_destroy (theActions [i]. button -> d_widget);
} else if (praat_writeMenu && theActions [i]. button -> d_parent == praat_writeMenu) {
- GuiObject_destroy (theActions [i]. button -> d_widget); // a Save menu item
+ trace ("destroying Save menu item");
+ GuiObject_destroy (theActions [i]. button -> d_widget);
}
#elif motif
if (theActions [i]. button -> classInfo == classGuiButton && theActions [i]. button -> d_widget -> subMenuId) { // a cascade button (not a direct child of the form)?
@@ -199,8 +204,9 @@ static void deleteDynamicMenu (void) {
}
}
if (praat_writeMenu) {
- #if gtk
+ #if gtk || cocoa
if (praat_writeMenuSeparator) {
+ trace ("destroy the Save menu separator");
GuiObject_destroy (praat_writeMenuSeparator -> d_widget);
}
//praat_writeMenu -> f_empty ();
@@ -211,6 +217,7 @@ static void deleteDynamicMenu (void) {
#endif
praat_writeMenuSeparator = NULL;
}
+ actionsInvisible = true;
}
static void updateDynamicMenu (void) {
@@ -611,6 +618,7 @@ void praat_actions_show (void) {
/* Create a new column of buttons in the dynamic menu. */
if (! theCurrentPraatApplication -> batch && ! Melder_backgrounding) {
+ actionsInvisible = false;
GuiMenu currentSubmenu1 = NULL, currentSubmenu2 = NULL;
int writeMenuGoingToSeparate = FALSE;
int y = Machine_getMenuBarHeight () + 10;
diff --git a/sys/praat_objectMenus.cpp b/sys/praat_objectMenus.cpp
index 4baceee..bf96979 100644
--- a/sys/praat_objectMenus.cpp
+++ b/sys/praat_objectMenus.cpp
@@ -104,11 +104,14 @@ END
/********** The fixed menus. **********/
-static GuiMenu praatMenu, newMenu, readMenu, goodiesMenu, preferencesMenu, technicalMenu, applicationHelpMenu, helpMenu;
+static GuiMenu praatMenu, editMenu, newMenu, readMenu, goodiesMenu, preferencesMenu, technicalMenu, applicationHelpMenu, helpMenu;
GuiMenu praat_objects_resolveMenu (const wchar_t *menu) {
return
wcsequ (menu, L"Praat") || wcsequ (menu, L"Control") ? praatMenu :
+ #if cocoa
+ wcsequ (menu, L"Edit") ? editMenu :
+ #endif
wcsequ (menu, L"New") || wcsequ (menu, L"Create") ? newMenu :
wcsequ (menu, L"Open") || wcsequ (menu, L"Read") ? readMenu :
wcsequ (menu, L"Help") ? helpMenu :
@@ -546,6 +549,18 @@ static void cb_openDocument (MelderFile file) {
}
}
+#if cocoa
+DIRECT (praat_cut)
+ [[[NSApp keyWindow] fieldEditor: YES forObject: nil] cut: nil];
+END
+DIRECT (praat_copy)
+ [[[NSApp keyWindow] fieldEditor: YES forObject: nil] copy: nil];
+END
+DIRECT (praat_paste)
+ [[[NSApp keyWindow] fieldEditor: YES forObject: nil] pasteAsPlainText: nil];
+END
+#endif
+
void praat_addMenus (GuiWindow window) {
Melder_setSearchProc (searchProc);
@@ -557,6 +572,9 @@ void praat_addMenus (GuiWindow window) {
if (! theCurrentPraatApplication -> batch) {
#ifdef macintosh
praatMenu = GuiMenu_createInWindow (NULL, L"\024", 0);
+ #if cocoa
+ editMenu = GuiMenu_createInWindow (NULL, L"Edit", 0);
+ #endif
#else
praatMenu = GuiMenu_createInWindow (window, L"Praat", 0);
#endif
@@ -572,6 +590,11 @@ void praat_addMenus (GuiWindow window) {
MelderString_append (& itemTitle_about, L"About ", Melder_peekUtf8ToWcs (praatP.title), L"...");
#ifdef macintosh
praat_addMenuCommand (L"Objects", L"Praat", itemTitle_about.string, 0, praat_UNHIDABLE, DO_About);
+ #if cocoa
+ praat_addMenuCommand (L"Objects", L"Edit", L"Cut", 0, 'X', DO_praat_cut);
+ praat_addMenuCommand (L"Objects", L"Edit", L"Copy", 0, 'C', DO_praat_copy);
+ praat_addMenuCommand (L"Objects", L"Edit", L"Paste", 0, 'V', DO_praat_paste);
+ #endif
#endif
#ifdef UNIX
praat_addMenuCommand (L"Objects", L"Praat", itemTitle_about.string, 0, praat_UNHIDABLE, DO_About);
diff --git a/sys/praat_picture.cpp b/sys/praat_picture.cpp
index 2eb0b56..b82c3cb 100644
--- a/sys/praat_picture.cpp
+++ b/sys/praat_picture.cpp
@@ -140,7 +140,7 @@ static void updateViewportMenu (void) {
DIRECT (MouseSelectsInnerViewport)
if (theCurrentPraatPicture != & theForegroundPraatPicture)
Melder_throw ("Mouse commands are not available inside pictures.");
- { // scope
+ {// scope
autoPraatPicture picture;
Picture_setMouseSelectsInnerViewport (praat_picture, praat_mouseSelectsInnerViewport = true);
}
@@ -150,7 +150,7 @@ END
DIRECT (MouseSelectsOuterViewport)
if (theCurrentPraatPicture != & theForegroundPraatPicture)
Melder_throw ("Mouse commands are not available inside pictures.");
- { // scope
+ {// scope
autoPraatPicture picture;
Picture_setMouseSelectsInnerViewport (praat_picture, praat_mouseSelectsInnerViewport = false);
}
@@ -1395,6 +1395,8 @@ void praat_picture_open (void) {
if (theCurrentPraatPicture == & theForegroundPraatPicture && ! theCurrentPraatApplication -> batch) {
#if gtk
gtk_window_present (GTK_WINDOW (dialog -> d_gtkWindow));
+ #elif cocoa
+ dialog -> f_show ();
#elif motif
XtMapWidget (dialog -> d_xmShell);
XMapRaised (XtDisplay (dialog -> d_xmShell), XtWindow (dialog -> d_xmShell));
@@ -1425,12 +1427,6 @@ void praat_picture_close (void) {
if (theCurrentPraatPicture != & theForegroundPraatPicture) return;
if (! theCurrentPraatApplication -> batch) {
Picture_highlight (praat_picture);
- #if gtk
- // TODO: Tijdelijke fix; dit exposed de selectie, maar voor bijvoorbeeld 'text' die buiten
- // de selectie valt is dit geen optie. Het mooiste zou zijn als na praat_picture_close
- // bekend zou zijn wat de 'dirty' regio is van het scherm. Om vervolgens alleen dat te exposen
- //Picture_selfExpose (praat_picture);
- #endif
}
}
diff --git a/sys/praat_script.cpp b/sys/praat_script.cpp
index 91e22d6..37873d4 100644
--- a/sys/praat_script.cpp
+++ b/sys/praat_script.cpp
@@ -490,7 +490,7 @@ static void secondPassThroughScript (UiForm sendingForm, int narg, Stackel args,
static void firstPassThroughScript (MelderFile file) {
try {
autostring text = MelderFile_readText (file);
- { // scope
+ {// scope
autoMelderFileSetDefaultDir dir (file);
Melder_includeIncludeFiles (& text);
}
diff --git a/sys/praat_version.h b/sys/praat_version.h
index 27b5ede..8bb1b38 100644
--- a/sys/praat_version.h
+++ b/sys/praat_version.h
@@ -1,5 +1,5 @@
-#define PRAAT_VERSION_STR 5.3.46
-#define PRAAT_VERSION_NUM 5346
+#define PRAAT_VERSION_STR 5.3.56
+#define PRAAT_VERSION_NUM 5356
#define PRAAT_YEAR 2013
-#define PRAAT_MONTH April
-#define PRAAT_DAY 21
+#define PRAAT_MONTH September
+#define PRAAT_DAY 15
diff --git a/sys/sendpraat.c b/sys/sendpraat.c
index bb96d64..5a254fd 100644
--- a/sys/sendpraat.c
+++ b/sys/sendpraat.c
@@ -1,6 +1,6 @@
/* sendpraat.c */
/* by Paul Boersma */
-/* 19 March 2013 */
+/* 25 April 2013 */
/*
* The sendpraat subroutine (Unix with GTK; Windows; Macintosh) sends a message
@@ -180,7 +180,7 @@ char *sendpraat (void *display, const char *programName, long timeOut, const cha
*/
sprintf (pidFileName, "%s/.%s-dir/pid", home, programName);
if ((pidFile = fopen (pidFileName, "r")) == NULL) {
- sprintf (errorMessage, "Program %s not running (or a version older than 3.6).", programName);
+ sprintf (errorMessage, "Program %s not running.", programName);
return errorMessage;
}
if (fscanf (pidFile, "%ld%ld", & pid, & wid) < 1) {
@@ -233,9 +233,9 @@ char *sendpraat (void *display, const char *programName, long timeOut, const cha
g_type_init ();
int displaySupplied = display != NULL;
if (! displaySupplied) {
- display = gdk_display_open (":0.0"); /* GdkDisplay* */
+ display = gdk_display_open (getenv ("DISPLAY")); /* GdkDisplay* */
if (display == NULL) {
- sprintf (errorMessage, "Cannot open display :0.0.");
+ sprintf (errorMessage, "Cannot open display %s", getenv ("DISPLAY"));
return errorMessage;
}
}
@@ -402,7 +402,7 @@ wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, co
*/
sprintf (pidFileName, "%s/.%ls-dir/pid", home, programName);
if ((pidFile = fopen (pidFileName, "r")) == NULL) {
- swprintf (errorMessageW, 1000, L"Program %ls not running (or a version older than 3.6).", programName);
+ swprintf (errorMessageW, 1000, L"Program %ls not running.", programName);
return errorMessageW;
}
if (fscanf (pidFile, "%ld%ld", & pid, & wid) < 1) {
@@ -455,9 +455,9 @@ wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, co
int displaySupplied = display != NULL;
g_type_init ();
if (! displaySupplied) {
- display = gdk_display_open (":0.0"); /* GdkDisplay* */
+ display = gdk_display_open (getenv ("DISPLAY")); /* GdkDisplay* */
if (display == NULL) {
- swprintf (errorMessageW, 1000, L"Cannot open display :0.0.");
+ swprintf (errorMessageW, 1000, L"Cannot open display %s", getenv ("DISPLAY"));
return errorMessageW;
}
}
@@ -532,16 +532,15 @@ wchar_t *sendpraatW (void *display, const wchar_t *programName, long timeOut, co
}
/*
- * To compile sendpraat as a stand-alone program:
- * temporarily change the following line to "#if 1" instead of "#if 0":
+ * To compile sendpraat as a stand-alone program, use the -DSTAND_ALONE option to the C compiler:
*/
-#if 0
+#ifdef STAND_ALONE
/*
* To compile on MacOS X:
-cc -o sendpraat -framework CoreServices -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers sendpraat.c -Dmacintosh -DuseCarbon=1
+cc -o sendpraat -DSTAND_ALONE -framework CoreServices -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers sendpraat.c -Dmacintosh -DuseCarbon=1
*
* To compile on Linux:
-cc -std=gnu99 -o sendpraat -DUNIX `pkg-config --cflags --libs gtk+-2.0` sendpraat.c
+cc -std=gnu99 -o sendpraat -DSTAND_ALONE -DUNIX `pkg-config --cflags --libs gtk+-2.0` sendpraat.c
*/
int main (int argc, char **argv) {
int iarg, line, length = 0;
@@ -597,7 +596,7 @@ int main (int argc, char **argv) {
printf ("\n");
#if win
printf (" sendpraat praat \"execute C:\\MyDocuments\\MyScript.praat\"\n");
- #elif mac
+ #else
printf (" sendpraat praat \"execute ~/MyResearch/MyProject/MyScript.praat\"\n");
#endif
printf (" Causes the program \"praat\" to execute a script.\n");
diff --git a/test/code.praat b/test/code.praat
index 54f0912..235f6d5 100644
--- a/test/code.praat
+++ b/test/code.praat
@@ -12,4 +12,4 @@ assert not index (code$, "'0' }") ; 2012-08-07
code$ < ../external/espeak/speak_lib.cpp
assert not index (code$, "setlocale") ; 2012-10-01
-printline OK
\ No newline at end of file
+printline OK...
\ No newline at end of file
diff --git a/test/fon/soundFiles.praat b/test/fon/soundFiles.praat
index 3c585ae..25f786d 100644
--- a/test/fon/soundFiles.praat
+++ b/test/fon/soundFiles.praat
@@ -49,7 +49,7 @@ procedure test32 .type$ .extension$ .duration
sound2 = Read from file... kanweg.'.extension$'
t = stopwatch
energy2 = Get energy in air
- assert "'energy1:12'" = "'energy2:12'"
+ assert "'energy1:12'" = "'energy2:12'" ; '.type$' '.extension$' '.duration'
plus sound
Remove
deleteFile ("kanweg." + .extension$)
diff --git a/test/runAllTests.praat b/test/runAllTests.praat
index ae777eb..3313255 100644
--- a/test/runAllTests.praat
+++ b/test/runAllTests.praat
@@ -1,7 +1,7 @@
# Praat script runAlltests.praat
-# Paul Boersma, 16 March 2011
+# Paul Boersma, 6 May 2013
#
-# This script runs all Praat scripts in its subdirectories, except itself.
+# This script runs all Praat scripts in its subdirectories.
directories = Create Strings as directory list... directories .
numberOfDirectories = Get number of strings
diff --git a/test/sys/graphics.praat b/test/sys/graphics.praat
index 9bcda27..e10615a 100644
Binary files a/test/sys/graphics.praat and b/test/sys/graphics.praat differ
diff --git a/test/sys/procedures2.praat b/test/sys/procedures2.praat
new file mode 100644
index 0000000..4b7973b
--- /dev/null
+++ b/test/sys/procedures2.praat
@@ -0,0 +1,10 @@
+;@doe (33,"ho,p"",""kkk", 5)
+ at do2 (66, "GH")
+
+procedure doe (.a, .b$, .c, .d$)
+ writeInfoLine ("hallo", .a, .b$, doe.c, .d$)
+endproc
+
+procedure do2 ()
+ appendInfoLine ("hoi")
+endproc
\ No newline at end of file
diff --git a/test/sys/progress.praat b/test/sys/progress.praat
new file mode 100644
index 0000000..0c20998
Binary files /dev/null and b/test/sys/progress.praat differ
diff --git a/test/sys/script2.praat b/test/sys/script2.praat
new file mode 100644
index 0000000..aabb046
Binary files /dev/null and b/test/sys/script2.praat differ
diff --git a/test/test.txt b/test/test.txt
new file mode 100644
index 0000000..5c93674
--- /dev/null
+++ b/test/test.txt
@@ -0,0 +1,17 @@
+writeInfo()
+#String function works with Chinese characters in Linux (Ubuntu)
+fileName$="02 你好大家好"
+a$=right$(fileName$,2)
+printline 'a$'
+
+#Regular Expression doesn't work with Chinese characters, but works with English in Linux (Ubuntu)
+length=length(fileName$)
+a=rindex_regex (fileName$, "\d")
+printline a='a'
+
+b$="02 Next time"
+b=rindex_regex (b$, "\d")
+printline b='b'
+
+#output:家好,a=8,b=2
+#correct output should be a and b are both of the value 2
--
Alioth's /git/debian-med/git-commit-notice on /srv/git.debian.org/git/debian-med/praat.git
More information about the debian-med-commit
mailing list