Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,26 @@ chmod +x autogen.sh
make
make install

Notes about cxxpiper support
============================
Notes about piper support
=========================

The cxxpiper module uses the Piper synthesis
https://github.com/rhasspy/piper/
The piper module uses the Piper neural TTS engine
https://github.com/OHF-Voice/piper1-gpl

Upstream piper however does not provide an API that can really be used nicely,
so the build is quite convoluted. The following should be working:
Speech Dispatcher links against the `libpiper` C shared library (and `librubberband`).
To build and install `libpiper` from source:

wget https://github.com/rhasspy/piper-phonemize/releases/download/2023.11.14-4/piper-phonemize_linux_x86_64.tar.gz
sudo tar -C /opt -xvf piper-phonemize_linux_x86_64.tar.gz
wget https://github.com/rhasspy/piper/archive/refs/tags/2023.11.14-2.tar.gz
sudo tar -C /opt -xvf 2023.11.14-2.tar.gz
CXXFLAGS=-I/opt/piper_phonemize/include LDFLAGS=-L/opt/piper_phonemize/lib ./configure --with-piper=/opt/piper-2023.11.14-2
make
make install
$ git clone https://github.com/OHF-Voice/piper1-gpl.git
$ cd piper1-gpl/libpiper
$ cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
$ cmake --build build -j$(nproc)
$ sudo cmake --install build

Then configure Speech Dispatcher with:
$ ./configure --with-piper

(If libpiper is installed in a non-standard prefix like /opt/piper, use:
$ ./configure --with-piper=/opt/piper)

Continue building Speech Dispatcher
===================================
Expand Down
4 changes: 2 additions & 2 deletions config/modules/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ dist_moduleconforig_DATA += kali.conf
endif

if piper_support
dist_moduleconf_DATA += cxxpiper.conf
dist_moduleconforig_DATA += cxxpiper.conf
dist_moduleconf_DATA += piper.conf
dist_moduleconforig_DATA += piper.conf
endif

if ibmtts_support
Expand Down
75 changes: 0 additions & 75 deletions config/modules/cxxpiper.conf

This file was deleted.

56 changes: 56 additions & 0 deletions config/modules/piper.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#
# Configuration for piper Speech Dispatcher output module.
#

# Debugging level (0 = disabled, 1 = errors only, 5 = full debug)
Debug 0

# -- Model Configuration --
#
# ModelPath is required. On Arch Linux (e.g. using the piper-voices-en-us package from AUR),
# voices are installed to /usr/share/piper-voices/<lang>/<locale>/<voice>/<quality>/.
#
# en_US-lessac-medium is the recommended standard default voice.
ModelPath "/usr/share/piper-voices/en/en_US/lessac/medium/en_US-lessac-medium.onnx"

# ConfigPath (optional):
# Path to the voice's JSON configuration file. If omitted, piper automatically
# looks for <ModelPath>.json.
# ConfigPath "/usr/share/piper-voices/en/en_US/lessac/medium/en_US-lessac-medium.onnx.json"

# -- Multi-Speaker Voice Selection (Optional) --
#
# For single-speaker models (like lessac), a single voice named after the model stem is exposed.
# For multi-speaker models (e.g., libritts_r, vctk, thorsten_emotional), each speaker defined in the
# model's "speaker_id_map" is exposed as an individual voice.
#
# Listing available speaker names:
# 1. Using the Speech Dispatcher CLI:
# spd-say -o piper -L
# 2. Inspecting the model's JSON configuration file directly:
# jq '.speaker_id_map | keys' /path/to/model.onnx.json
#
# DefaultVoice (optional):
# Sets the initial speaker for multi-speaker models using a speaker name from speaker_id_map.
# DefaultVoice "8419"
#
# AddVoice (optional):
# Maps standard Speech Dispatcher voice types (MALE1, FEMALE1, etc.) to specific speakers
# within a language code.
#
# Examples for multi-speaker models:
# AddVoice "en_US" "MALE1" "8419"
# AddVoice "en_US" "FEMALE1" "4137"
# AddVoice "de_DE" "MALE1" "neutral"
# AddVoice "de_DE" "MALE2" "amused"

# -- Sound Icons --
# Folder containing sound icon audio files (path must end with a trailing slash '/').
SoundIconFolder "/usr/share/sounds/sound-icons/"

# -- ESpeak NG Data Directory --
# Path to the espeak-ng-data directory used by Piper for phonemization.
# On Arch Linux, this is installed by the 'espeak-ng' package to /usr/share/espeak-ng-data/.
ESpeakNGDataDirPath "/usr/share/espeak-ng-data/"

# End of piper.conf
1 change: 1 addition & 0 deletions config/speechd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ SymbolsPreprocFile "orca-math.dic"
#AddModule "baratinoo" "sd_baratinoo" "baratinoo.conf"
#AddModule "rhvoice" "sd_rhvoice" "rhvoice.conf"
#AddModule "voxin" "sd_voxin" "voxin.conf"
#AddModule "piper" "sd_piper" "piper.conf"

# The output module testing doesn't actually connect to anything. It
# outputs the requested commands to standard output and reads
Expand Down
99 changes: 44 additions & 55 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -427,70 +427,59 @@ AS_IF([test $with_kali != no], [output_modules="${output_modules} kali"])

# check for piper support
AC_ARG_WITH([piper],
[AS_HELP_STRING([--with-piper=/path], [include Piper support])],
[AS_HELP_STRING([--with-piper[[=yes|no|check|/path]]], [include Piper TTS support])],
[],
[with_piper=no])
AS_IF([test $with_espeak = yes -a $with_piper != no], [
# We currently need various headers of piper
PIPER_SRC_DIR="$with_piper/src/cpp"
[with_piper=check])

AS_IF([test "$with_piper" != "no"], [
PIPER_CFLAGS=""
PIPER_LIBS=""
AS_IF([test "$with_piper" != "yes" -a "$with_piper" != "check"], [
PIPER_CFLAGS="-I$with_piper/include"
PIPER_LIBS="-L$with_piper/lib -lpiper"
])
OLDCXXFLAGS="$CXXFLAGS"
OLDLDFLAGS="$LDFLAGS"
CXXFLAGS="$CXXFLAGS -I$PIPER_SRC_DIR"

AS_IF([test $with_piper != no],
[PKG_CHECK_MODULES([ONNXRUNTIME], [libonnxruntime], [
CXXFLAGS="$CXXFLAGS $ONNXRUNTIME_CFLAGS"
LDFLAGS="$LDFLAGS $ONNXRUNTIME_LIBS"
], [AC_CHECK_LIB([onnxruntime], [OrtGetApiBase],
[ONNXRUNTIME_LIBS="-lonnxruntime"],
[with_piper=no])
])])

AS_IF([test $with_piper != no],
[PKG_CHECK_MODULES([RUBBERBAND], [rubberband], [
CXXFLAGS="$CXXFLAGS $RUBBERBAND_CFLAGS"
LDFLAGS="$LDFLAGS $RUBBERBAND_LIBS"
], [with_piper=no])])
OLDLIBS="$LIBS"
CXXFLAGS="$CXXFLAGS $PIPER_CFLAGS"
LDFLAGS="$LDFLAGS $PIPER_LIBS"

AC_LANG_PUSH(C++)
AS_IF([test $with_piper != no],
[AC_CHECK_LIB([piper_phonemize], [_ZN5piper19DEFAULT_PHONEME_MAPB5cxx11E],
[:],
[with_piper=no])])

AS_IF([test $with_piper != no],
[AC_CHECK_HEADER([json.hpp],
[],
[with_piper=no])])
AS_IF([test $with_piper != no],
[AC_CHECK_HEADER([piper.hpp],
[],
[with_piper=no])])
AS_IF([test $with_piper != no],
[AC_CHECK_HEADER([utf8.h],
[],
[with_piper=no])])
AS_IF([test $with_piper != no],
[AC_CHECK_HEADER([wavfile.hpp],
[],
[with_piper=no])])

AS_IF([test $with_piper != no],
# We need espeak with https://github.com/espeak-ng/espeak-ng/pull/2127 applied
[AC_CHECK_LIB([espeak-ng], [espeak_TextToPhonemesWithTerminator],
[:],
[with_piper=no],
[$ESPEAK_NG_LIBS])])

# Check for piper.h header
AC_CHECK_HEADER([piper.h], [have_piper_h=yes], [have_piper_h=no])
# Check for libpiper library
AC_CHECK_LIB([piper], [piper_create], [have_libpiper=yes], [have_libpiper=no])
# Check for nlohmann json
AC_CHECK_HEADER([nlohmann/json.hpp], [have_json_h=yes], [
AC_CHECK_HEADER([json.hpp], [have_json_h=yes], [have_json_h=no])
])
AC_LANG_POP(C++)

CXXFLAGS="$OLDCXXFLAGS"
LDFLAGS="$OLDLDFLAGS"
LIBS="$OLDLIBS"

AS_IF([test "$have_piper_h" = "yes" -a "$have_libpiper" = "yes" -a "$have_json_h" = "yes"], [
PKG_CHECK_MODULES([RUBBERBAND], [rubberband], [
AS_IF([test -z "$PIPER_LIBS"], [PIPER_LIBS="-lpiper"])
with_piper=yes
], [
AS_IF([test "$with_piper" = "yes"], [
AC_MSG_FAILURE([rubberband is required for piper])
])
with_piper=no
])
], [
AS_IF([test "$with_piper" = "yes"], [
AC_MSG_FAILURE([libpiper (piper.h, libpiper, and json.hpp) is not available])
])
with_piper=no
])
])
AM_CONDITIONAL([piper_support], [test $with_piper != no])
AS_IF([test $with_piper != no], [output_modules="${output_modules} cxxpiper"])
AC_SUBST([PIPER_SRC_DIR])
AC_SUBST([ONNXRUNTIME_CFLAGS])
AC_SUBST([ONNXRUNTIME_LIBS])
AM_CONDITIONAL([piper_support], [test "$with_piper" = "yes"])
AS_IF([test "$with_piper" = "yes"], [output_modules="${output_modules} piper"])
AC_SUBST([PIPER_CFLAGS])
AC_SUBST([PIPER_LIBS])
AC_SUBST([RUBBERBAND_CFLAGS])
AC_SUBST([RUBBERBAND_LIBS])

Expand Down
14 changes: 6 additions & 8 deletions src/modules/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,14 @@ endif
endif

#
# cxxpiper
# piper
#
if piper_support
modulebin_PROGRAMS += sd_cxxpiper
sd_cxxpiper_SOURCES = cxxpiper.cpp module_utils_addvoice.c module_utils_play.c $(common_SOURCES)
sd_cxxpiper_CPPFLAGS = -I$(PIPER_SRC_DIR) $(ONNXRUNTIME_CFLAGS) $(RUBBERBAND_CFLAGS) $(AM_CPPFLAGS)
sd_cxxpiper_LDADD = $(top_builddir)/src/common/libcommon.la \
-lpiper_phonemize \
$(ONNXRUNTIME_LIBS) \
-lespeak-ng \
modulebin_PROGRAMS += sd_piper
sd_piper_SOURCES = piper.cpp module_utils_addvoice.c module_utils_play.c $(common_SOURCES)
sd_piper_CPPFLAGS = $(PIPER_CFLAGS) $(RUBBERBAND_CFLAGS) $(AM_CPPFLAGS)
sd_piper_LDADD = $(top_builddir)/src/common/libcommon.la \
$(PIPER_LIBS) \
$(RUBBERBAND_LIBS) \
$(SNDFILE_LIBS) \
$(common_LDADD)
Expand Down
Loading
Loading