Fixes: #1547 - Implement building and testing with cmake - Download libsonic from repository (when enabled and not available as system library), ref: #650 - Migrate android native build to cmake - Migrate CI to cmake - Add windows CI TODO (might be done in separate PR): - Building as [cmake external project](https://cmake.org/cmake/help/latest/module/ExternalProject.html) - Building for package managers (deb, rpm, ...) - Strip out `vcproj` - _to be discussed_ - Strip out `autotools` after next release - Update build documentation for `cmake`master
@@ -16,18 +16,16 @@ jobs: | |||
config: [debug, release] | |||
include: | |||
- config: debug | |||
target: assembleDebug | |||
apkname: espeak-debug.apk | |||
- config: release | |||
target: assembleRelease | |||
apkname: espeak-release-unsigned.apk | |||
name: Build ${{ matrix.config }} APK | |||
steps: | |||
- uses: actions/checkout@v3 | |||
- name: autoconf | |||
run: ./autogen.sh ; chmod -x INSTALL m4/*.m4 | |||
- name: configure | |||
run: ./configure --with-gradle=$(pwd)/android/gradlew | |||
- name: make | |||
run: make apk-${{ matrix.config }} | |||
run: cd android ; ./gradlew ${{ matrix.target }} | |||
- name: upload | |||
uses: actions/upload-artifact@v3 | |||
with: |
@@ -70,7 +70,7 @@ jobs: | |||
- sanitizer: "memory" | |||
configenv: "CC=clang CXX=clang++" | |||
sanitizer_cflags: "-fsanitize=memory -fsanitize-memory-track-origins=2" | |||
config: "--without-pcaudiolib --without-sonic" | |||
config: "-DUSE_LIBPCAUDIO:BOOL=OFF -DUSE_LIBSONIC:BOOL=OFF" | |||
sanitize_env: "MSAN_OPTIONS=exitcode=42" | |||
- sanitizer: "thread" | |||
@@ -81,7 +81,7 @@ jobs: | |||
sanitize_env: "UBSAN_OPTIONS=halt_on_error=1" | |||
- sanitizer: "valgrind" | |||
sanitize_env: 'VALGRIND="libtool --mode=execute valgrind --track-origins=yes --leak-check=full --error-exitcode=1"' | |||
sanitize_env: 'VALGRIND="valgrind --track-origins=yes --leak-check=full --error-exitcode=1"' | |||
exclude: | |||
- os: macos | |||
@@ -183,7 +183,7 @@ jobs: | |||
sudo apt-get install ronn kramdown python3 | |||
- name: apt-arch-deps | |||
if: matrix.os == 'ubuntu' && matrix.cross == 'no' | |||
run: "sudo apt-get install libtool-bin valgrind g++-12-multilib linux-libc-dev:${{ matrix.arch }} libpcaudio-dev:${{ matrix.arch }} libsonic-dev:${{ matrix.arch }} libstdc++-12-dev:${{ matrix.arch }} libc6-dbg:${{ matrix.arch }}" | |||
run: "sudo apt-get install cmake valgrind g++-12-multilib linux-libc-dev:${{ matrix.arch }} libpcaudio-dev:${{ matrix.arch }} libsonic-dev:${{ matrix.arch }} libstdc++-12-dev:${{ matrix.arch }} libc6-dbg:${{ matrix.arch }}" | |||
- name: apt-cross-deps | |||
if: matrix.cross == 'yes' | |||
run: sudo apt-get install qemu-user g++-12-${{ matrix.arch }}-${{ matrix.sys }} | |||
@@ -194,8 +194,7 @@ jobs: | |||
# MacOS - dependencies | |||
- name: brew-deps | |||
if: matrix.os == 'macos' | |||
run: brew install libtool automake ronn OJFord/homebrew-formulae/kramdown && | |||
brew install --HEAD anarchivist/espeak-ng/waywardgeek-sonic | |||
run: brew install cmake ronn OJFord/homebrew-formulae/kramdown | |||
- name: brew-compile-deps | |||
if: matrix.os == 'macos' && matrix.compiler == 'gcc' | |||
run: brew install gcc@12 | |||
@@ -204,11 +203,6 @@ jobs: | |||
- uses: actions/checkout@v3 | |||
# Configure | |||
- name: autoconf | |||
run: | | |||
./autogen.sh | |||
chmod -x INSTALL m4/*.m4 | |||
- name: configure | |||
run: | | |||
[ 'x${{ matrix.compiler }}' = 'xgcc' ] && export CC="${{ matrix.ccarch }}-${{ matrix.sys }}-gcc-12" | |||
@@ -218,19 +212,21 @@ jobs: | |||
[ 'x${{ matrix.cross }}' = 'xyes' ] && export LD="${{ matrix.ccarch }}-${{ matrix.sys }}-ld" | |||
export CFLAGS="-g -Og -fno-omit-frame-pointer ${{ matrix.compiler_flags }} ${{ matrix.sanitizer_cflags }} ${{ matrix.archcflags }}" | |||
export CXXFLAGS="-g -Og -fno-omit-frame-pointer ${{ matrix.compiler_flags }} ${{ matrix.sanitizer_cflags }} ${{ matrix.archcflags }}" | |||
./configure --host=${{ matrix.arch }}-${{ matrix.sys }} ${{ matrix.config }} | |||
cmake -Bbuild ${{ matrix.config }} -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} -DUSE_ASYNC:BOOL=OFF | |||
- name: config-failed-upload | |||
if: ${{ failure() }} | |||
uses: actions/upload-artifact@v3 | |||
with: | |||
name: config-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.compiler }}-${{ matrix.sanitizer }}.log | |||
path: config.log | |||
name: cmake-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.compiler }}-${{ matrix.sanitizer }}-builddir | |||
path: build | |||
# Build and test | |||
- name: make-binary | |||
run: make src/speak-ng src/espeak-ng | |||
run: cmake --build build --target espeak-ng | |||
- name: make-data | |||
run: ${{ matrix.sanitize_env }} ${{ matrix.runenv }} make all-am | |||
run: ${{ matrix.sanitize_env }} ${{ matrix.runenv }} cmake --build build --target data | |||
- name: test | |||
run: ${{ matrix.sanitize_env }} ${{ matrix.runenv }} make check | |||
run: | | |||
${{ matrix.sanitize_env }} ${{ matrix.runenv }} cmake --build build --target tests | |||
${{ matrix.sanitize_env }} ${{ matrix.runenv }} ctest --test-dir build -Ttest -j1 --output-on-failure |
@@ -8,7 +8,7 @@ on: | |||
branches: [ master ] | |||
env: | |||
deps: libpcaudio-dev libsonic-dev ronn kramdown python3 | |||
deps: cmake libpcaudio-dev libsonic-dev ronn kramdown python3 | |||
jobs: | |||
@@ -37,10 +37,8 @@ jobs: | |||
if: matrix.arch == 'x86-32' | |||
- name: dependencies | |||
run: sudo apt-get update && sudo apt-get install ${{ env.deps }} reprotest ${{ matrix.archdeps }} | |||
- name: autoconf | |||
run: ./autogen.sh ; chmod -x INSTALL m4/*.m4 | |||
- name: run | |||
run: reprotest 'CFLAGS="${{ matrix.archconfigflags }}" CXXFLAGS="${{ matrix.archconfigflags }}" ./configure --without-gradle && make clean && make && make check && touch success' success | |||
run: reprotest 'CFLAGS="${{ matrix.archconfigflags }}" CXXFLAGS="${{ matrix.archconfigflags }}" rm -rf build && cmake -Bbuild -DUSE_ASYNC:BOOL=OFF && cmake --build build && ctest --test-dir build -Ttest -j1 --output-on-failure && touch success' success | |||
distcheck: | |||
@@ -50,21 +48,21 @@ jobs: | |||
- uses: actions/checkout@v3 | |||
- name: dependencies | |||
run: sudo apt-get update && sudo apt-get install ${{ env.deps }} | |||
- name: autoconf | |||
run: ./autogen.sh ; chmod -x INSTALL m4/*.m4 | |||
- name: configure | |||
run: ./configure | |||
run: cmake -Bbuild -DUSE_ASYNC:BOOL=OFF | |||
- name: make | |||
run: make | |||
run: cmake --build build | |||
- name: make check | |||
run: make check | |||
- name: make dist | |||
run: make dist | |||
run: ctest --test-dir build -Ttest -j1 --output-on-failure | |||
- name: make package_source | |||
run: cmake --build build --target package_source | |||
- name: unpack | |||
run: mkdir unpack && tar -C unpack -xf *.tar.gz | |||
run: mkdir unpack && tar -C unpack -xf build/espeak-ng-*-Source.tar.bz2 | |||
- name: re-configure | |||
run: cd unpack/espeak-ng-* && ./configure | |||
run: cd unpack/espeak-ng-* && cmake -Bbuild -DUSE_ASYNC:BOOL=OFF | |||
- name: re-make | |||
run: cd unpack/espeak-ng-* && make | |||
run: cd unpack/espeak-ng-* && cmake --build build | |||
- name: re-make check | |||
run: cd unpack/espeak-ng-* && make check | |||
run: cd unpack/espeak-ng-* && ctest --test-dir build -Ttest -j1 --output-on-failure |
@@ -0,0 +1,21 @@ | |||
name: Windows | |||
on: | |||
workflow_dispatch: | |||
push: | |||
branches: [ master ] | |||
pull_request: | |||
branches: [ master ] | |||
jobs: | |||
build: | |||
runs-on: windows-latest | |||
name: build | |||
steps: | |||
- uses: actions/checkout@v3 | |||
- name: configure | |||
run: cmake -Bbuild -DUSE_ASYNC:BOOL=OFF | |||
- name: make | |||
run: cmake --build build | |||
- name: make check | |||
run: ctest --test-dir build -Ttest -C Debug -j1 --output-on-failure |
@@ -0,0 +1,31 @@ | |||
cmake_minimum_required(VERSION 3.8) | |||
project(espeak-ng | |||
VERSION 1.52.0.1 | |||
DESCRIPTION "open source speech synthesizer that supports more than hundred languages and accents" | |||
HOMEPAGE_URL "https://github.com/espeak-ng/espeak-ng" | |||
) | |||
include(CTest) | |||
include(cmake/deps.cmake) | |||
include(cmake/config.cmake) | |||
add_subdirectory(src) | |||
include(cmake/data.cmake) | |||
include(cmake/package.cmake) | |||
include(CPack) | |||
include(CTest) | |||
add_subdirectory(tests) | |||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF) | |||
message(STATUS "Configuration:") | |||
message(STATUS " shared: ${BUILD_SHARED_LIBS}") | |||
message(STATUS " mbrola: ${USE_MBROLA} (${MBROLA_BIN})") | |||
message(STATUS " libsonic: ${USE_LIBSONIC} (${SONIC_LIB} ${SONIC_INC})") | |||
message(STATUS " libpcaudio: ${USE_LIBPCAUDIO} (${PCAUDIO_LIB} ${PCAUDIO_INC})") | |||
message(STATUS " klatt: ${USE_KLATT}") | |||
message(STATUS " speech-player: ${USE_SPEECHPLAYER}") | |||
message(STATUS " async: ${USE_ASYNC}") |
@@ -25,6 +25,49 @@ dependencies { | |||
androidTestImplementation 'org.hamcrest:hamcrest-all:1.3' | |||
} | |||
android { | |||
compileSdk 33 | |||
ndkVersion "25.1.8937393" | |||
namespace "com.reecedunn.espeak" | |||
defaultConfig { | |||
minSdk 19 | |||
targetSdk 33 | |||
versionCode 22 | |||
versionName "1.52-dev" | |||
externalNativeBuild { | |||
cmake { | |||
arguments "-DUSE_ASYNC:BOOL=OFF", "-DUSE_MBROLA:BOOL=OFF" | |||
targets "ttsespeak", "espeak-data" | |||
} | |||
} | |||
} | |||
externalNativeBuild { | |||
cmake { | |||
path "jni/CMakeLists.txt" | |||
version "3.22.1" | |||
} | |||
} | |||
sourceSets { | |||
main { | |||
manifest.srcFile 'AndroidManifest.xml' | |||
java.srcDirs = ['src'] | |||
res.srcDirs = ['res'] | |||
} | |||
androidTest.setRoot('eSpeakTests') | |||
androidTest { | |||
java.srcDirs = ['eSpeakTests/src'] | |||
} | |||
} | |||
lint { | |||
abortOnError false | |||
} | |||
} | |||
tasks.register('checkData') { | |||
doFirst { | |||
assert file("../espeak-ng-data/en_dict").exists() | |||
@@ -37,13 +80,12 @@ tasks.register('checkData') { | |||
} | |||
tasks.register('createDataArchive', Zip) { | |||
dependsOn tasks.checkData | |||
preserveFileTimestamps = false | |||
reproducibleFileOrder = true | |||
archiveFileName = "espeakdata.zip" | |||
destinationDirectory = file("res/raw") | |||
from("../espeak-ng-data/") { | |||
from("build/generated/espeak-ng-data/") { | |||
into "espeak-ng-data" | |||
} | |||
} | |||
@@ -61,40 +103,10 @@ tasks.register('createDataVersion', Copy) { | |||
rename { return 'espeakdata_version' } | |||
into file("./res/raw") | |||
} | |||
preBuild.dependsOn createDataVersion | |||
android { | |||
compileSdk 33 | |||
ndkVersion "25.1.8937393" | |||
namespace "com.reecedunn.espeak" | |||
defaultConfig { | |||
minSdk 19 | |||
targetSdk 30 | |||
versionCode 22 | |||
versionName "1.52-dev" | |||
} | |||
externalNativeBuild { | |||
ndkBuild { | |||
path "jni/Android.mk" | |||
} | |||
} | |||
sourceSets { | |||
main { | |||
manifest.srcFile 'AndroidManifest.xml' | |||
java.srcDirs = ['src'] | |||
res.srcDirs = ['res'] | |||
} | |||
androidTest.setRoot('eSpeakTests') | |||
androidTest { | |||
java.srcDirs = ['eSpeakTests/src'] | |||
} | |||
} | |||
lint { | |||
abortOnError false | |||
} | |||
project.afterEvaluate { | |||
tasks.checkData.dependsOn(externalNativeBuildDebug) | |||
tasks.createDataArchive.dependsOn(externalNativeBuildDebug) | |||
javaPreCompileDebug.dependsOn(tasks.createDataVersion) | |||
javaPreCompileRelease.dependsOn(tasks.createDataVersion) | |||
} |
@@ -1,83 +0,0 @@ | |||
LOCAL_PATH:= $(call my-dir) | |||
include $(CLEAR_VARS) | |||
#LOCAL_CFLAGS = -std=c11 # speechplayer is c++ code | |||
# ucd-tools wide-character compatibility support: | |||
UCDTOOLS_SRC_PATH := ../../src/ucd-tools/src | |||
UCDTOOLS_SRC_FILES := \ | |||
$(subst $(LOCAL_PATH)/$(UCDTOOLS_SRC_PATH),$(UCDTOOLS_SRC_PATH),$(wildcard $(LOCAL_PATH)/$(UCDTOOLS_SRC_PATH)/*.c*)) | |||
LOCAL_SRC_FILES += $(UCDTOOLS_SRC_FILES) | |||
SPEECHPLAYER_SRC_FILES := \ | |||
../../src/speechPlayer/src/frame.cpp \ | |||
../../src/speechPlayer/src/speechPlayer.cpp \ | |||
../../src/speechPlayer/src/speechWaveGenerator.cpp | |||
LOCAL_SRC_FILES += $(SPEECHPLAYER_SRC_FILES) | |||
ESPEAK_SOURCES := \ | |||
src/libespeak-ng/common.c \ | |||
src/libespeak-ng/compiledata.c \ | |||
src/libespeak-ng/compiledict.c \ | |||
src/libespeak-ng/compilembrola.c \ | |||
src/libespeak-ng/dictionary.c \ | |||
src/libespeak-ng/encoding.c \ | |||
src/libespeak-ng/error.c \ | |||
src/libespeak-ng/espeak_api.c \ | |||
src/libespeak-ng/ieee80.c \ | |||
src/libespeak-ng/intonation.c \ | |||
src/libespeak-ng/klatt.c \ | |||
src/libespeak-ng/langopts.c \ | |||
src/libespeak-ng/mnemonics.c \ | |||
src/libespeak-ng/numbers.c \ | |||
src/libespeak-ng/phoneme.c \ | |||
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/sPlayer.c \ | |||
src/libespeak-ng/ssml.c \ | |||
src/libespeak-ng/synthdata.c \ | |||
src/libespeak-ng/synthesize.c \ | |||
src/libespeak-ng/synth_mbrola.c \ | |||
src/libespeak-ng/translate.c \ | |||
src/libespeak-ng/translateword.c \ | |||
src/libespeak-ng/tr_languages.c \ | |||
src/libespeak-ng/voices.c \ | |||
src/libespeak-ng/wavegen.c | |||
ESPEAK_SRC_PATH := ../../src | |||
ESPEAK_SRC_FILES := \ | |||
$(subst src/,$(ESPEAK_SRC_PATH)/,$(ESPEAK_SOURCES)) | |||
LOCAL_CFLAGS += -DINCLUDE_KLATT -DINCLUDE_SPEECHPLAYER -DINCLUDE_SONIC -DHAVE_ENDIAN_H | |||
LOCAL_SRC_FILES += \ | |||
$(filter-out $(BLACKLIST_SRC_FILES),$(ESPEAK_SRC_FILES)) | |||
# JNI | |||
LOCAL_SRC_FILES += \ | |||
$(subst $(LOCAL_PATH)/jni,jni,$(wildcard $(LOCAL_PATH)/jni/*.c)) | |||
# Common | |||
LOCAL_C_INCLUDES += \ | |||
$(LOCAL_PATH)/include \ | |||
$(LOCAL_PATH)/$(UCDTOOLS_SRC_PATH)/include \ | |||
$(LOCAL_PATH)/../../src/speechPlayer/include \ | |||
$(LOCAL_PATH)/$(ESPEAK_SRC_PATH)/include \ | |||
$(LOCAL_PATH)/$(ESPEAK_SRC_PATH)/include/compat | |||
LOCAL_LDLIBS := \ | |||
-llog | |||
LOCAL_MODULE := libttsespeak | |||
LOCAL_MODULE_TAGS := optional | |||
LOCAL_PRELINK_MODULE := false | |||
include $(BUILD_SHARED_LIBRARY) |
@@ -0,0 +1,26 @@ | |||
cmake_minimum_required(VERSION 3.8) | |||
project(espeak-android) | |||
add_subdirectory(../../ espeakng) | |||
add_custom_target( | |||
espeak-data | |||
COMMAND ${CMAKE_COMMAND} -B${CMAKE_CURRENT_BINARY_DIR}/../espeak-data ${CMAKE_CURRENT_SOURCE_DIR}/../../ | |||
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/../espeak-data --target data | |||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/../espeak-data/espeak-ng-data ${CMAKE_SOURCE_DIR}/../build/generated/espeak-ng-data | |||
) | |||
message(STATUS "Data: ${CMAKE_CURRENT_SOURCE_DIR}") | |||
find_library(A_LOG log) | |||
add_library(ttsespeak SHARED | |||
jni/eSpeakService.c | |||
) | |||
target_include_directories(ttsespeak PRIVATE | |||
include | |||
) | |||
target_link_libraries(ttsespeak PRIVATE | |||
espeak-ng ${A_LOG} | |||
) |
@@ -26,6 +26,7 @@ | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <stdbool.h> | |||
#include <string.h> | |||
#include <jni.h> | |||
#include <espeak/speak_lib.h> |
@@ -0,0 +1,14 @@ | |||
include(CheckSymbolExists) | |||
check_symbol_exists(mkstemp "stdlib.h" HAVE_MKSTEMP) | |||
option(USE_MBROLA "Use mbrola for speech synthesis" ${HAVE_MBROLA}) | |||
option(USE_LIBSONIC "Use libsonit for faster speech rates" ${HAVE_LIBSONIC}) | |||
option(USE_LIBPCAUDIO "Use libPcAudio for sound output" ${HAVE_LIBPCAUDIO}) | |||
option(USE_KLATT "Use klatt for speech synthesis" ON) | |||
option(USE_SPEECHPLAYER "Use speech-player for speech synthesis" ON) | |||
if (HAVE_PTHREAD) | |||
option(USE_ASYNC "Support asynchronous speech synthesis" ON) | |||
else() | |||
set(USE_ASYNC OFF) | |||
endif() |
@@ -0,0 +1,168 @@ | |||
list(APPEND _dict_compile_list | |||
af am an ar as az | |||
ba be bg bn bpy bs | |||
ca chr cmn cs cv cy | |||
da de | |||
el en eo es et eu | |||
fa fi fr | |||
ga gd gn grc gu | |||
hak haw he hi hr ht hu hy | |||
ia id io is it | |||
ja jbo | |||
ka kk kl kn kok ko ku ky | |||
la lb lfn lt lv | |||
mi mk ml mr ms mto mt my | |||
nci ne nl nog no | |||
om or | |||
pap pa piqd pl pt py | |||
qdb quc qu qya | |||
ro ru | |||
sd shn si sjn sk sl smj sq sr sv sw | |||
ta te th tk tn tr tt | |||
ug uk ur uz | |||
vi | |||
yue | |||
) | |||
list(APPEND _mbrola_lang_list | |||
af1 ar1 ar2 | |||
ca cmn cr1 cs | |||
de2 de4 de6 de8 | |||
ee1 en1 es es3 es4 | |||
fr | |||
gr1 gr2 grc-de6 | |||
he hn1 hu1 | |||
ic1 id1 in ir1 it1 it3 | |||
jp | |||
la1 lt | |||
ma1 mx1 mx2 | |||
nl nz1 | |||
pl1 pt1 ptbr ptbr4 | |||
ro1 | |||
sv sv2 | |||
tl1 tr1 | |||
us us3 | |||
vz | |||
) | |||
set(DATA_DIST_ROOT ${CMAKE_CURRENT_BINARY_DIR}) | |||
set(DATA_DIST_DIR ${DATA_DIST_ROOT}/espeak-ng-data) | |||
set(PHONEME_TMP_DIR ${DATA_DIST_ROOT}/phsource) | |||
set(DICT_TMP_DIR ${DATA_DIST_ROOT}/dictsource) | |||
set(DATA_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/espeak-ng-data) | |||
set(PHONEME_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/phsource) | |||
set(DICT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dictsource) | |||
file(MAKE_DIRECTORY "${DATA_DIST_DIR}") | |||
file(MAKE_DIRECTORY "${DICT_TMP_DIR}") | |||
file(COPY "${DATA_SRC_DIR}/lang" DESTINATION "${DATA_DIST_DIR}") | |||
file(COPY "${DATA_SRC_DIR}/voices/!v" DESTINATION "${DATA_DIST_DIR}/voices") | |||
file(COPY "${PHONEME_SRC_DIR}" DESTINATION "${DATA_DIST_ROOT}") | |||
set(ESPEAK_RUN_ENV ${CMAKE_COMMAND} -E env "ESPEAK_DATA_PATH=${DATA_DIST_ROOT}") | |||
set(ESPEAK_RUN_CMD ${ESPEAK_RUN_ENV} $ENV{VALGRIND} "$<TARGET_FILE:espeak-ng-bin>") | |||
add_custom_command( | |||
OUTPUT "${DATA_DIST_DIR}/intonations" | |||
COMMAND ${ESPEAK_RUN_CMD} --compile-intonations | |||
WORKING_DIRECTORY "${PHONEME_SRC_DIR}" | |||
COMMENT "Compile intonations" | |||
DEPENDS | |||
"$<TARGET_FILE:espeak-ng-bin>" | |||
"${PHONEME_SRC_DIR}/intonation" | |||
) | |||
set(_phon_deps "") | |||
function(check_phon_deps _file) | |||
set(_file "${PHONEME_SRC_DIR}/${_file}") | |||
list(APPEND _phon_deps "${_file}") | |||
file(STRINGS "${_file}" _phon_incs REGEX "include .+") | |||
list(TRANSFORM _phon_incs REPLACE "^[ \t]*include[ \t]+" "") | |||
foreach(_inc ${_phon_incs}) | |||
check_phon_deps(${_inc}) | |||
endforeach(_inc) | |||
set(_phon_deps ${_phon_deps} PARENT_SCOPE) | |||
endfunction(check_phon_deps) | |||
check_phon_deps("phonemes") | |||
add_custom_command( | |||
OUTPUT | |||
"${DATA_DIST_DIR}/phondata" | |||
"${DATA_DIST_DIR}/phondata-manifest" | |||
"${DATA_DIST_DIR}/phonindex" | |||
"${DATA_DIST_DIR}/phontab" | |||
COMMAND ${ESPEAK_RUN_CMD} --compile-phonemes | |||
WORKING_DIRECTORY "${PHONEME_SRC_DIR}" | |||
COMMENT "Compile phonemes" | |||
DEPENDS | |||
"$<TARGET_FILE:espeak-ng-bin>" | |||
${_phon_deps} | |||
) | |||
list(APPEND _dict_targets) | |||
list(APPEND _mbr_targets) | |||
foreach(_dict_name ${_dict_compile_list}) | |||
set(_dict_target "${DATA_DIST_DIR}/${_dict_name}_dict") | |||
set(_dict_deps "") | |||
list(APPEND _dict_targets ${_dict_target}) | |||
list(APPEND _dict_deps | |||
"${DICT_SRC_DIR}/${_dict_name}_rules" | |||
"${DICT_SRC_DIR}/${_dict_name}_list" | |||
) | |||
if(EXISTS "${DICT_SRC_DIR}/extra/${_dict_name}_listx") | |||
option(EXTRA_${_dict_name} "Compile extra ${_dict_name} dictionary" ON) | |||
if(EXTRA_${_dict_name}) | |||
list(APPEND _dict_deps "${DICT_SRC_DIR}/extra/${_dict_name}_listx") | |||
else() | |||
file(REMOVE "${DICT_TMP_DIR}/${_dict_name}_listx") | |||
endif() | |||
elseif(EXISTS "${DICT_SRC_DIR}/${_dict_name}_listx") | |||
list(APPEND _dict_deps "${DICT_SRC_DIR}/${_dict_name}_listx") | |||
endif() | |||
if(EXISTS "${DICT_SRC_DIR}/${_dict_name}_emoji") | |||
list(APPEND _dict_deps "${DICT_SRC_DIR}/${_dict_name}_emoji") | |||
endif() | |||
add_custom_command( | |||
OUTPUT "${_dict_target}" | |||
COMMAND ${CMAKE_COMMAND} -E copy ${_dict_deps} "${DICT_TMP_DIR}/" | |||
COMMAND ${ESPEAK_RUN_CMD} --compile=${_dict_name} | |||
WORKING_DIRECTORY "${DICT_TMP_DIR}" | |||
DEPENDS | |||
"$<TARGET_FILE:espeak-ng-bin>" | |||
"${DATA_DIST_DIR}/phondata" | |||
"${DATA_DIST_DIR}/intonations" | |||
${_dict_deps} | |||
) | |||
endforeach() | |||
if (HAVE_MBROLA AND USE_MBROLA) | |||
file(COPY "${DATA_SRC_DIR}/voices/mb" DESTINATION "${DATA_DIST_DIR}/voices") | |||
file(MAKE_DIRECTORY "${DATA_DIST_DIR}/mbrola_ph") | |||
foreach(_mbl ${_mbrola_lang_list}) | |||
set(_mbl_src "${PHONEME_SRC_DIR}/mbrola/${_mbl}") | |||
set(_mbl_out "${DATA_DIST_DIR}/mbrola_ph/${_mbl}_phtrans") | |||
list(APPEND _mbr_targets ${_mbl_out}) | |||
add_custom_command( | |||
OUTPUT "${_mbl_out}" | |||
COMMAND ${ESPEAK_RUN_CMD} --compile-mbrola="${_mbl_src}" | |||
DEPENDS "$<TARGET_FILE:espeak-ng-bin>" "${_mbl_src}" | |||
) | |||
endforeach(_mbl) | |||
endif() | |||
add_custom_target( | |||
data ALL | |||
DEPENDS | |||
"${DATA_DIST_DIR}/intonations" | |||
"${DATA_DIST_DIR}/phondata" | |||
${_dict_targets} | |||
${_mbr_targets} | |||
) | |||
install(DIRECTORY ${DATA_DIST_DIR} DESTINATION share) |
@@ -0,0 +1,33 @@ | |||
find_library(SONIC_LIB sonic) | |||
find_path(SONIC_INC "sonic.h") | |||
find_library(PCAUDIO_LIB pcaudio) | |||
find_path(PCAUDIO_INC "pcaudiolib/audio.h") | |||
find_library(PTHREAD_LIB pthread) | |||
find_program(MBROLA_BIN mbrola) | |||
include(FetchContent) | |||
if (PTHREAD_LIB) | |||
set(HAVE_PTHREAD ON) | |||
endif(PTHREAD_LIB) | |||
if (MBROLA_BIN) | |||
set(HAVE_MBROLA ON) | |||
endif(MBROLA_BIN) | |||
if (SONIC_LIB AND SONIC_INC) | |||
set(HAVE_LIBSONIC ON) | |||
else() | |||
FetchContent_Declare(sonic-git | |||
GIT_REPOSITORY https://github.com/waywardgeek/sonic.git | |||
GIT_TAG fbf75c3d6d846bad3bb3d456cbc5d07d9fd8c104 | |||
) | |||
FetchContent_MakeAvailable(sonic-git) | |||
FetchContent_GetProperties(sonic-git) | |||
add_library(sonic OBJECT ${sonic-git_SOURCE_DIR}/sonic.c) | |||
target_include_directories(sonic PUBLIC ${sonic-git_SOURCE_DIR}) | |||
set(HAVE_LIBSONIC ON) | |||
set(SONIC_LIB sonic) | |||
set(SONIC_INC ${sonic-git_SOURCE_DIR}) | |||
endif() | |||
if (PCAUDIO_LIB AND PCAUDIO_INC) | |||
set(HAVE_LIBPCAUDIO ON) | |||
endif() |
@@ -0,0 +1,17 @@ | |||
list(APPEND CPACK_SOURCE_IGNORE_FILES | |||
/\.git/ | |||
/\.gitignore | |||
/\.github/ | |||
/\.tx/ | |||
/\.travis.yml | |||
/_layouts/ | |||
/android/ | |||
/build/ | |||
/chromium_extension/ | |||
/data/ | |||
/docs/ | |||
/emscripten/ | |||
/fastlane/ | |||
/tools/ | |||
/vim/ | |||
) |
@@ -0,0 +1,25 @@ | |||
add_library(espeak-include INTERFACE) | |||
target_include_directories(espeak-include INTERFACE include include/compat) | |||
add_subdirectory(ucd-tools) | |||
add_subdirectory(speechPlayer) | |||
add_subdirectory(libespeak-ng) | |||
add_executable(espeak-ng-bin espeak-ng.c) | |||
set_target_properties(espeak-ng-bin PROPERTIES OUTPUT_NAME espeak-ng) | |||
target_link_libraries( | |||
espeak-ng-bin PRIVATE espeak-ng espeak-ng-config | |||
) | |||
if (MSVC) | |||
target_sources(espeak-ng-bin PRIVATE compat/getopt.c) | |||
endif() | |||
if (NOT WIN32) | |||
add_custom_target( | |||
speak-ng ALL | |||
${CMAKE_COMMAND} -E create_symlink espeak-ng ${CMAKE_CURRENT_BINARY_DIR}/speak-ng | |||
COMMENT "Link espeak-ng to speak-ng" | |||
DEPENDS espeak-ng-bin | |||
) | |||
endif() | |||
install(TARGETS espeak-ng-bin) | |||
install(DIRECTORY include/espeak include/espeak-ng TYPE INCLUDE) |
@@ -0,0 +1,105 @@ | |||
set(ESPEAK_CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}/include) | |||
set(ESPEAK_CONFIG_H ${ESPEAK_CONFIG_DIR}/config.h) | |||
configure_file(config.h.in ${ESPEAK_CONFIG_H}) | |||
add_library(espeak-ng-config INTERFACE) | |||
target_include_directories(espeak-ng-config INTERFACE ${ESPEAK_CONFIG_DIR}) | |||
add_library(espeak-ng | |||
common.c | |||
mnemonics.c | |||
error.c | |||
ieee80.c | |||
compiledata.c | |||
compiledict.c | |||
dictionary.c | |||
encoding.c | |||
intonation.c | |||
langopts.c | |||
numbers.c | |||
phoneme.c | |||
phonemelist.c | |||
readclause.c | |||
setlengths.c | |||
soundicon.c | |||
spect.c | |||
ssml.c | |||
synthdata.c | |||
synthesize.c | |||
tr_languages.c | |||
translate.c | |||
translateword.c | |||
voices.c | |||
wavegen.c | |||
speech.c | |||
espeak_api.c | |||
) | |||
if (NOT MSVC) | |||
target_compile_options(espeak-ng PRIVATE | |||
"-fPIC" | |||
"-fvisibility=hidden" | |||
"-fno-exceptions" | |||
"-fwrapv" | |||
"-pedantic" | |||
"-Wunused-parameter" | |||
"-Wunused" | |||
"-Wuninitialized" | |||
"-Wreturn-type" | |||
"-Wmissing-prototypes" | |||
"-Wint-conversion" | |||
"-Wimplicit" | |||
) | |||
endif() | |||
target_compile_definitions(espeak-ng PRIVATE "LIBESPEAK_NG_EXPORT=1") | |||
if (NOT BUILD_SHARED_LIBS) | |||
target_compile_definitions(espeak-ng INTERFACE "LIBESPEAK_NG_EXPORT=1") | |||
endif() | |||
if (USE_ASYNC) | |||
target_sources(espeak-ng PRIVATE | |||
event.c | |||
fifo.c | |||
espeak_command.c | |||
) | |||
endif(USE_ASYNC) | |||
if (USE_MBROLA) | |||
target_sources(espeak-ng PRIVATE | |||
mbrowrap.c | |||
compilembrola.c | |||
synth_mbrola.c | |||
) | |||
endif(USE_MBROLA) | |||
if (USE_KLATT) | |||
target_sources(espeak-ng PRIVATE klatt.c) | |||
endif(USE_KLATT) | |||
if (USE_SPEECHPLAYER) | |||
target_sources(espeak-ng PRIVATE sPlayer.c) | |||
target_link_libraries(espeak-ng PRIVATE speechPlayer) | |||
endif(USE_SPEECHPLAYER) | |||
if (HAVE_LIBSONIC AND USE_LIBSONIC) | |||
target_link_libraries(espeak-ng PRIVATE ${SONIC_LIB}) | |||
target_include_directories(espeak-ng PRIVATE ${SONIC_INC}) | |||
endif() | |||
if (HAVE_LIBPCAUDIO AND USE_LIBPCAUDIO) | |||
target_link_libraries(espeak-ng PRIVATE ${PCAUDIO_LIB}) | |||
target_include_directories(espeak-ng PRIVATE ${PCAUDIO_INC}) | |||
endif() | |||
target_link_libraries(espeak-ng PRIVATE espeak-ng-config ucd) | |||
if (NOT MSVC) | |||
target_link_libraries(espeak-ng PRIVATE m) | |||
endif() | |||
target_link_libraries(espeak-ng PUBLIC espeak-include) | |||
install(TARGETS espeak-ng LIBRARY) |
@@ -0,0 +1,10 @@ | |||
#cmakedefine01 HAVE_MKSTEMP | |||
#cmakedefine01 USE_ASYNC | |||
#cmakedefine01 USE_KLATT | |||
#cmakedefine01 USE_LIBPCAUDIO | |||
#cmakedefine01 USE_LIBSONIC | |||
#cmakedefine01 USE_MBROLA | |||
#cmakedefine01 USE_SPEECHPLAYER | |||
#define PACKAGE_VERSION "${PROJECT_VERSION}" |
@@ -0,0 +1,10 @@ | |||
add_library(speechPlayer STATIC | |||
src/frame.cpp | |||
src/speechPlayer.cpp | |||
src/speechWaveGenerator.cpp | |||
) | |||
target_include_directories(speechPlayer PUBLIC include) | |||
if(NOT MSVC) | |||
target_compile_options(speechPlayer PRIVATE "-fPIC") | |||
endif() | |||
install(TARGETS speechPlayer ARCHIVE) |
@@ -0,0 +1,10 @@ | |||
add_library(ucd STATIC | |||
src/case.c | |||
src/categories.c | |||
src/ctype.c | |||
src/proplist.c | |||
src/scripts.c | |||
src/tostring.c | |||
) | |||
target_include_directories(ucd PUBLIC src/include) | |||
install(TARGETS ucd ARCHIVE) |
@@ -0,0 +1,73 @@ | |||
include(CTest) | |||
list(APPEND _binary_tests) | |||
macro(compiled_test _test_name) | |||
add_executable(test_${_test_name} | |||
$<TARGET_OBJECTS:espeak-ng> | |||
${_test_name}.c | |||
) | |||
target_link_libraries(test_${_test_name} PRIVATE | |||
$<TARGET_PROPERTY:espeak-ng,LINK_LIBRARIES> | |||
) | |||
target_include_directories( | |||
test_${_test_name} PRIVATE | |||
$<TARGET_PROPERTY:espeak-ng,SOURCE_DIR> | |||
$<TARGET_PROPERTY:espeak-ng,SOURCE_DIR>/include/compat | |||
$<TARGET_PROPERTY:espeak-ng,INTERFACE_INCLUDE_DIRECTORIES> | |||
$<TARGET_PROPERTY:espeak-ng-config,INTERFACE_INCLUDE_DIRECTORIES> | |||
) | |||
add_dependencies(test_${_test_name} data) | |||
add_test( | |||
NAME ${_test_name} | |||
COMMAND ${ESPEAK_RUN_ENV} $<TARGET_FILE:test_${_test_name}> | |||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.. | |||
) | |||
list(APPEND _binary_tests test_${_test_name}) | |||
endmacro(compiled_test) | |||
find_program(SHELL bash) | |||
macro(shell_test _test_name) | |||
add_test( | |||
NAME ${_test_name} | |||
COMMAND ${ESPEAK_RUN_ENV} ESPEAK_BIN=$<TARGET_FILE:espeak-ng-bin> ${SHELL} ${CMAKE_CURRENT_SOURCE_DIR}/${_test_name}.test | |||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.. | |||
) | |||
endmacro(shell_test) | |||
compiled_test(api) | |||
compiled_test(encoding) | |||
compiled_test(ieee80) | |||
compiled_test(readclause) | |||
if (SHELL AND UNIX) | |||
shell_test(bom) | |||
shell_test(non-executable-files-with-executable-bit) | |||
shell_test(cmd_options) | |||
shell_test(dictionary) | |||
shell_test(language-numbers-cardinal) | |||
shell_test(language-numbers-ordinal) | |||
shell_test(language-phonemes) | |||
shell_test(language-pronunciation) | |||
shell_test(language-replace) | |||
shell_test(ssml) | |||
shell_test(translate) | |||
shell_test(variants) | |||
shell_test(voices) | |||
# shell_test(windows-data) | |||
# shell_test(windows-installer) | |||
if (USE_KLATT) | |||
shell_test(klatt) | |||
endif() | |||
if (USE_MBROLA) | |||
shell_test(mbrola) | |||
endif() | |||
endif() | |||
add_custom_target(tests DEPENDS ${_binary_tests}) |
@@ -8,7 +8,8 @@ echo -n "testing for Byte Order Marks in source files ... " | |||
# TODO checking for other encodings (e.g. UTF-16, UTF-32, UTF-7) needs more elaborate search, | |||
# otherwise it shows many false positives | |||
grep -ErlI $'\xEF\xBB\xBF' * | tee tests/bom.check >/dev/null # UTF-8 | |||
cd $(dirname $0)/.. | |||
grep -ErlI $'\xEF\xBB\xBF' * | grep -v '^build/' | tee tests/bom.check >/dev/null # UTF-8 | |||
if [ -s tests/bom.check ] ; then | |||
echo "found:" | |||
@@ -19,4 +20,3 @@ else | |||
echo "none found" | |||
true | |||
fi | |||
@@ -8,7 +8,7 @@ is_hash | |||
# read column 5 (File) of espeak-ng --voices, skip the directory | |||
echo "checking if all supported languages have phoneme tests ..." | |||
for lang in $(ESPEAK_DATA_PATH=`pwd` LD_LIBRARY_PATH=src:${LD_LIBRARY_PATH} src/espeak-ng --voices | awk '{print $5}' | cut -d "/" -f 2-2 | tail -n+2); | |||
do if ! grep -q "test_phwav $lang" tests/language-phonemes.test | |||
do if ! grep -q "test_phwav $lang" $0 | |||
then | |||
echo "$lang missing a phoneme test in tests/language-phonemes.test"; | |||
exit 1; |
@@ -2,8 +2,10 @@ | |||
echo -n "testing files for executable bits that shouldn't be executable ... " | |||
cd $(dirname $0)/.. | |||
find * -executable -type f | \ | |||
grep -vE "compile|config\.(guess|status|sub)|configure|depcomp|install-sh|libtool|missing" | # Ignore autotools output \ | |||
grep -vE "build" | # Ignore cmake output \ | |||
grep -vE ".*\.test|tests/common|src(/\.libs)?/(e?speak-ng|.*\.so\..*)|src/\.libs/lt-espeak-ng|android" | # Ignore built programs and libraries \ | |||
grep -vE ".*\.sh|tools/emoji" | # Ignore helper scripts \ | |||
grep -vE "src/ucd-tools/tools/(.*\.py|mkencodingtable)" | # Ignore ucd-tools helper scripts \ | |||
@@ -21,4 +23,3 @@ else | |||
echo "none found" | |||
true | |||
fi | |||
@@ -36,8 +36,8 @@ test_ssml() { | |||
diff expected.txt actual.txt || exit 1 | |||
} | |||
for i in `ls tests/ssml/*.ssml` ; do test_ssml $i; done | |||
for i in `ls tests/ssml/*.ssml2` ; do test_ssml $i punct; done | |||
for i in `dirname $0`/ssml/*.ssml ; do test_ssml $i; done | |||
for i in `dirname $0`/ssml/*.ssml2 ; do test_ssml $i punct; done | |||
test_ssml_audio "<prosody>" 88fccb35536158f25f4ae44a03fb005fef95c99b "<speak><prosody rate=\"x-slow\" pitch=\"low\"> Slow and low </prosody><prosody rate=\"x-fast\" pitch=\"x-high\"> Fast and high.</prosody></speak>" | |||
# #410 is a bug in SSML. Sentence termination causes prosody stack to misfunction. |