diff --git a/Makefile.am b/Makefile.am
index 3db91104..8e6e12ae 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -159,6 +159,7 @@ src_libespeak_ng_la_SOURCES = \
src/libespeak-ng/phoneme.c \
src/libespeak-ng/phonemelist.c \
src/libespeak-ng/setlengths.c \
+ src/libespeak-ng/soundicon.c \
src/libespeak-ng/spect.c \
src/libespeak-ng/speech.c \
src/libespeak-ng/ssml.c \
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 8a6a2332..8c6a8ca3 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -28,6 +28,7 @@ ESPEAK_SOURCES := \
src/libespeak-ng/phonemelist.c \
src/libespeak-ng/readclause.c \
src/libespeak-ng/setlengths.c \
+ src/libespeak-ng/soundicon.c \
src/libespeak-ng/spect.c \
src/libespeak-ng/speech.c \
src/libespeak-ng/ssml.c \
diff --git a/src/libespeak-ng/readclause.c b/src/libespeak-ng/readclause.c
index ff4bd945..2640f39d 100644
--- a/src/libespeak-ng/readclause.c
+++ b/src/libespeak-ng/readclause.c
@@ -41,10 +41,10 @@
#include "dictionary.h" // for LookupDictList, DecodePhonemes, Set...
#include "error.h" // for create_file_error_context
#include "phoneme.h" // for phonSWITCH
+#include "soundicon.h" // for LookupSoundIcon
#include "speech.h" // for GetFileLength, LookupMnem, PATHSEP
#include "ssml.h" // for SSML_STACK, ProcessSsmlTag, N_PARAM...
#include "synthdata.h" // for SelectPhonemeTable
-#include "synthesize.h" // for SOUND_ICON, soundicon_tab, samplerate
#include "translate.h" // for Translator, utf8_out, CLAUSE_OPTION...
#include "voice.h" // for voice, voice_t, current_voice_selected
@@ -296,143 +296,6 @@ int Read4Bytes(FILE *f)
return acc;
}
-static espeak_ng_STATUS LoadSoundFile(const char *fname, int index, espeak_ng_ERROR_CONTEXT *context)
-{
- FILE *f;
- char *p;
- int *ip;
- int length;
- char fname_temp[100];
- char fname2[sizeof(path_home)+13+40];
-
- if (fname == NULL) {
- // filename is already in the table
- fname = soundicon_tab[index].filename;
- }
-
- if (fname == NULL)
- return EINVAL;
-
- if (fname[0] != '/') {
- // a relative path, look in espeak-ng-data/soundicons
- sprintf(fname2, "%s%csoundicons%c%s", path_home, PATHSEP, PATHSEP, fname);
- fname = fname2;
- }
-
- f = NULL;
- if ((f = fopen(fname, "rb")) != NULL) {
- int ix;
- int fd_temp;
- int header[3];
- char command[sizeof(fname2)+sizeof(fname2)+40];
-
- if (fseek(f, 20, SEEK_SET) == -1) {
- int error = errno;
- fclose(f);
- return create_file_error_context(context, error, fname);
- }
-
- for (ix = 0; ix < 3; ix++)
- header[ix] = Read4Bytes(f);
-
- // if the sound file is not mono, 16 bit signed, at the correct sample rate, then convert it
- if ((header[0] != 0x10001) || (header[1] != samplerate) || (header[2] != samplerate*2)) {
- fclose(f);
- f = NULL;
-
-#ifdef HAVE_MKSTEMP
- strcpy(fname_temp, "/tmp/espeakXXXXXX");
- if ((fd_temp = mkstemp(fname_temp)) >= 0)
- close(fd_temp);
-#else
- strcpy(fname_temp, tmpnam(NULL));
-#endif
-
- sprintf(command, "sox \"%s\" -r %d -c1 -b 16 -t wav %s\n", fname, samplerate, fname_temp);
- if (system(command) == 0)
- fname = fname_temp;
- }
- }
-
- if (f == NULL) {
- f = fopen(fname, "rb");
- if (f == NULL)
- return create_file_error_context(context, errno, fname);
- }
-
- length = GetFileLength(fname);
- if (length < 0) { // length == -errno
- fclose(f);
- return create_file_error_context(context, -length, fname);
- }
- if (fseek(f, 0, SEEK_SET) == -1) {
- int error = errno;
- fclose(f);
- return create_file_error_context(context, error, fname);
- }
- if ((p = (char *)realloc(soundicon_tab[index].data, length)) == NULL) {
- fclose(f);
- return ENOMEM;
- }
- if (fread(p, 1, length, f) != length) {
- int error = errno;
- fclose(f);
- remove(fname_temp);
- free(p);
- return create_file_error_context(context, error, fname);
- }
- fclose(f);
- remove(fname_temp);
-
- ip = (int *)(&p[40]);
- soundicon_tab[index].length = (*ip) / 2; // length in samples
- soundicon_tab[index].data = p;
- return ENS_OK;
-}
-
-static int LookupSoundicon(int c)
-{
- // Find the sound icon number for a punctuation character
- int ix;
-
- for (ix = N_SOUNDICON_SLOTS; ix < n_soundicon_tab; ix++) {
- if (soundicon_tab[ix].name == c) {
- if (soundicon_tab[ix].length == 0) {
- if (LoadSoundFile(NULL, ix, NULL) != ENS_OK)
- return -1; // sound file is not available
- }
- return ix;
- }
- }
- return -1;
-}
-
-int LoadSoundFile2(const char *fname)
-{
- // Load a sound file into one of the reserved slots in the sound icon table
- // (if it'snot already loaded)
-
- int ix;
- static int slot = -1;
-
- for (ix = 0; ix < n_soundicon_tab; ix++) {
- if (((soundicon_tab[ix].filename != NULL) && strcmp(fname, soundicon_tab[ix].filename) == 0))
- return ix; // already loaded
- }
-
- // load the file into the next slot
- slot++;
- if (slot >= N_SOUNDICON_SLOTS)
- slot = 0;
-
- if (LoadSoundFile(fname, slot, NULL) != ENS_OK)
- return -1;
-
- soundicon_tab[slot].filename = (char *)realloc(soundicon_tab[ix].filename, strlen(fname)+1);
- strcpy(soundicon_tab[slot].filename, fname);
- return slot;
-}
-
static int AnnouncePunctuation(Translator *tr, int c1, int *c2_ptr, char *output, int *bufix, int end_clause)
{
// announce punctuation names
diff --git a/src/libespeak-ng/readclause.h b/src/libespeak-ng/readclause.h
index 4eba7756..bdcf15f9 100644
--- a/src/libespeak-ng/readclause.h
+++ b/src/libespeak-ng/readclause.h
@@ -42,7 +42,6 @@ int towlower2(unsigned int c, Translator *translator); // Supports Turkish I
int Eof(void);
const char *WordToString2(unsigned int word);
int Read4Bytes(FILE *f);
-int LoadSoundFile2(const char *fname);
int AddNameData(const char *name,
int wide);
int ReadClause(Translator *tr,
diff --git a/src/libespeak-ng/soundicon.c b/src/libespeak-ng/soundicon.c
new file mode 100644
index 00000000..fbf61a62
--- /dev/null
+++ b/src/libespeak-ng/soundicon.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2005 to 2015 by Jonathan Duddington
+ * email: jonsd@users.sourceforge.net
+ * Copyright (C) 2015-2017 Reece H. Dunn
+ * Copyright (C) 2021 Juho Hiltunen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see: .
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "soundicon.h"
+#include "error.h" // for create_file_error_context
+#include "readclause.h" // for Read4Bytes
+#include "speech.h" // for path_home, GetFileLength, PATHSEP
+#include "synthesize.h" // for samplerate
+
+int n_soundicon_tab = N_SOUNDICON_SLOTS;
+SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
+
+
+static espeak_ng_STATUS LoadSoundFile(const char *fname, int index, espeak_ng_ERROR_CONTEXT *context)
+{
+ FILE *f;
+ char *p;
+ int *ip;
+ int length;
+ char fname_temp[100];
+ char fname2[sizeof(path_home)+13+40];
+
+ if (fname == NULL) {
+ // filename is already in the table
+ fname = soundicon_tab[index].filename;
+ }
+
+ if (fname == NULL)
+ return EINVAL;
+
+ if (fname[0] != '/') {
+ // a relative path, look in espeak-ng-data/soundicons
+ sprintf(fname2, "%s%csoundicons%c%s", path_home, PATHSEP, PATHSEP, fname);
+ fname = fname2;
+ }
+
+ f = NULL;
+ if ((f = fopen(fname, "rb")) != NULL) {
+ int ix;
+ int fd_temp;
+ int header[3];
+ char command[sizeof(fname2)+sizeof(fname2)+40];
+
+ if (fseek(f, 20, SEEK_SET) == -1) {
+ int error = errno;
+ fclose(f);
+ return create_file_error_context(context, error, fname);
+ }
+
+ for (ix = 0; ix < 3; ix++)
+ header[ix] = Read4Bytes(f);
+
+ // if the sound file is not mono, 16 bit signed, at the correct sample rate, then convert it
+ if ((header[0] != 0x10001) || (header[1] != samplerate) || (header[2] != samplerate*2)) {
+ fclose(f);
+ f = NULL;
+
+#ifdef HAVE_MKSTEMP
+ strcpy(fname_temp, "/tmp/espeakXXXXXX");
+ if ((fd_temp = mkstemp(fname_temp)) >= 0)
+ close(fd_temp);
+#else
+ strcpy(fname_temp, tmpnam(NULL));
+#endif
+
+ sprintf(command, "sox \"%s\" -r %d -c1 -b 16 -t wav %s\n", fname, samplerate, fname_temp);
+ if (system(command) == 0)
+ fname = fname_temp;
+ }
+ }
+
+ if (f == NULL) {
+ f = fopen(fname, "rb");
+ if (f == NULL)
+ return create_file_error_context(context, errno, fname);
+ }
+
+ length = GetFileLength(fname);
+ if (length < 0) { // length == -errno
+ fclose(f);
+ return create_file_error_context(context, -length, fname);
+ }
+ if (fseek(f, 0, SEEK_SET) == -1) {
+ int error = errno;
+ fclose(f);
+ return create_file_error_context(context, error, fname);
+ }
+ if ((p = (char *)realloc(soundicon_tab[index].data, length)) == NULL) {
+ fclose(f);
+ return ENOMEM;
+ }
+ if (fread(p, 1, length, f) != length) {
+ int error = errno;
+ fclose(f);
+ remove(fname_temp);
+ free(p);
+ return create_file_error_context(context, error, fname);
+ }
+ fclose(f);
+ remove(fname_temp);
+
+ ip = (int *)(&p[40]);
+ soundicon_tab[index].length = (*ip) / 2; // length in samples
+ soundicon_tab[index].data = p;
+ return ENS_OK;
+}
+
+int LookupSoundicon(int c)
+{
+ // Find the sound icon number for a punctuation character
+ int ix;
+
+ for (ix = N_SOUNDICON_SLOTS; ix < n_soundicon_tab; ix++) {
+ if (soundicon_tab[ix].name == c) {
+ if (soundicon_tab[ix].length == 0) {
+ if (LoadSoundFile(NULL, ix, NULL) != ENS_OK)
+ return -1; // sound file is not available
+ }
+ return ix;
+ }
+ }
+ return -1;
+}
+
+int LoadSoundFile2(const char *fname)
+{
+ // Load a sound file into one of the reserved slots in the sound icon table
+ // (if it'snot already loaded)
+
+ int ix;
+ static int slot = -1;
+
+ for (ix = 0; ix < n_soundicon_tab; ix++) {
+ if (((soundicon_tab[ix].filename != NULL) && strcmp(fname, soundicon_tab[ix].filename) == 0))
+ return ix; // already loaded
+ }
+
+ // load the file into the next slot
+ slot++;
+ if (slot >= N_SOUNDICON_SLOTS)
+ slot = 0;
+
+ if (LoadSoundFile(fname, slot, NULL) != ENS_OK)
+ return -1;
+
+ soundicon_tab[slot].filename = (char *)realloc(soundicon_tab[ix].filename, strlen(fname)+1);
+ strcpy(soundicon_tab[slot].filename, fname);
+ return slot;
+}
diff --git a/src/libespeak-ng/soundicon.h b/src/libespeak-ng/soundicon.h
new file mode 100644
index 00000000..81c54827
--- /dev/null
+++ b/src/libespeak-ng/soundicon.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005 to 2014 by Jonathan Duddington
+ * email: jonsd@users.sourceforge.net
+ * Copyright (C) 2015-2017 Reece H. Dunn
+ * Copyright (C) 2021 Juho Hiltunen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see: .
+ */
+
+#ifndef ESPEAK_NG_SOUNDICON_H
+#define ESPEAK_NG_SOUNDICON_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int LookupSoundicon(int c);
+int LoadSoundFile2(const char *fname);
+
+typedef struct {
+ int name;
+ int length;
+ char *data;
+ char *filename;
+} SOUND_ICON;
+
+#define N_SOUNDICON_TAB 80 // total entries in soundicon_tab
+#define N_SOUNDICON_SLOTS 4 // number of slots reserved for dynamic loading of audio files
+
+extern int n_soundicon_tab;
+extern SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libespeak-ng/ssml.c b/src/libespeak-ng/ssml.c
index ce2232ec..3398af20 100644
--- a/src/libespeak-ng/ssml.c
+++ b/src/libespeak-ng/ssml.c
@@ -43,6 +43,7 @@
#include "dictionary.h" // for strncpy0
#include "mnemonics.h" // for LookupMnemName, MNEM_TAB,
#include "readclause.h" // for PARAM_STACK, param_stack, AddNameData
+#include "soundicon.h" // for LoadSoundFile2
#include "synthesize.h" // for SPEED_FACTORS, speed
#include "translate.h" // for CTRL_EMBEDDED, IsDigit09, utf8_out
#include "voice.h" // for SelectVoice, SelectVoiceByName
diff --git a/src/libespeak-ng/synthdata.c b/src/libespeak-ng/synthdata.c
index 0f802b9c..013b9896 100644
--- a/src/libespeak-ng/synthdata.c
+++ b/src/libespeak-ng/synthdata.c
@@ -36,6 +36,7 @@
#include "phoneme.h" // for PHONEME_TAB, PHONEME_TAB_LIST
#include "speech.h" // for path_home, GetFileLength, PATHSEP
#include "mbrola.h" // for mbrola_name
+#include "soundicon.h" // for N_SOUNDICON_SLOTS, soundicon_tab
#include "synthesize.h" // for PHONEME_LIST, frameref_t, PHONE...
#include "translate.h" // for Translator, LANGUAGE_OPTIONS
#include "voice.h" // for ReadTonePoints, tone_points, voice
diff --git a/src/libespeak-ng/synthesize.c b/src/libespeak-ng/synthesize.c
index dde10b6a..90d2e965 100644
--- a/src/libespeak-ng/synthesize.c
+++ b/src/libespeak-ng/synthesize.c
@@ -38,6 +38,7 @@
#include "mbrola.h" // for MbrolaGenerate, mbrola_name
#include "phoneme.h" // for PHONEME_TAB, phVOWEL, phLIQUID, phN...
#include "setlengths.h" // for CalcLengths
+#include "soundicon.h" // for soundicon_tab, n_soundicon
#include "synthdata.h" // for InterpretPhoneme, GetEnvelope, Inte...
#include "translate.h" // for translator, LANGUAGE_OPTIONS, Trans...
#include "voice.h" // for voice_t, voice, LoadVoiceVariant
@@ -66,9 +67,6 @@ static int syllable_centre;
static voice_t *new_voice = NULL;
-int n_soundicon_tab = N_SOUNDICON_SLOTS;
-SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
-
#define RMS_GLOTTAL1 35 // vowel before glottal stop
#define RMS_START 28 // 28
#define VOWEL_FRONT_LENGTH 50
diff --git a/src/libespeak-ng/synthesize.h b/src/libespeak-ng/synthesize.h
index f6a7b0e4..e12ae803 100644
--- a/src/libespeak-ng/synthesize.h
+++ b/src/libespeak-ng/synthesize.h
@@ -334,13 +334,6 @@ typedef struct {
#define i_StressLevel 0x800
-typedef struct {
- int name;
- int length;
- char *data;
- char *filename;
-} SOUND_ICON;
-
typedef struct {
int pause_factor;
int clause_pause_factor;
@@ -479,11 +472,6 @@ extern espeak_EVENT *event_list;
extern t_espeak_callback *synth_callback;
extern const int version_phdata;
-#define N_SOUNDICON_TAB 80 // total entries in soundicon_tab
-#define N_SOUNDICON_SLOTS 4 // number of slots reserved for dynamic loading of audio files
-extern int n_soundicon_tab;
-extern SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
-
void DoEmbedded(int *embix, int sourceix);
void DoMarker(int type, int char_posn, int length, int value);
void DoPhonemeMarker(int type, int char_posn, int length, char *name);