eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

soundicon.c 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (C) 2005 to 2015 by Jonathan Duddington
  3. * email: [email protected]
  4. * Copyright (C) 2015-2017 Reece H. Dunn
  5. * Copyright (C) 2021 Juho Hiltunen
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, see: <http://www.gnu.org/licenses/>.
  19. */
  20. #include "config.h"
  21. #include <ctype.h>
  22. #include <errno.h>
  23. #include <locale.h>
  24. #include <math.h>
  25. #include <stdint.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <espeak-ng/espeak_ng.h>
  31. #include <espeak-ng/speak_lib.h>
  32. #include <espeak-ng/encoding.h>
  33. #include <ucd/ucd.h>
  34. #include "soundicon.h"
  35. #include "common.h" // for GetFileLength
  36. #include "error.h" // for create_file_error_context
  37. #include "readclause.h" // for Read4Bytes
  38. #include "speech.h" // for path_home, PATHSEP
  39. #include "synthesize.h" // for samplerate
  40. int n_soundicon_tab = 0;
  41. SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
  42. static espeak_ng_STATUS LoadSoundFile(const char *fname, int index, espeak_ng_ERROR_CONTEXT *context)
  43. {
  44. FILE *f;
  45. unsigned char *p;
  46. int length;
  47. char fname_temp[100];
  48. char fname2[sizeof(path_home)+13+40];
  49. if (fname == NULL) {
  50. // filename is already in the table
  51. fname = soundicon_tab[index].filename;
  52. }
  53. if (fname == NULL)
  54. return EINVAL;
  55. if (fname[0] != '/') {
  56. // a relative path, look in espeak-ng-data/soundicons
  57. sprintf(fname2, "%s%csoundicons%c%s", path_home, PATHSEP, PATHSEP, fname);
  58. fname = fname2;
  59. }
  60. fname_temp[0] = 0;
  61. f = NULL;
  62. if ((f = fopen(fname, "rb")) != NULL) {
  63. int ix;
  64. int fd_temp;
  65. int header[3];
  66. char command[sizeof(fname2)+sizeof(fname2)+40];
  67. if (fseek(f, 20, SEEK_SET) == -1) {
  68. int error = errno;
  69. fclose(f);
  70. return create_file_error_context(context, error, fname);
  71. }
  72. for (ix = 0; ix < 3; ix++)
  73. header[ix] = Read4Bytes(f);
  74. // if the sound file is not mono, 16 bit signed, at the correct sample rate, then convert it
  75. if ((header[0] != 0x10001) || (header[1] != samplerate) || (header[2] != samplerate*2)) {
  76. fclose(f);
  77. f = NULL;
  78. #ifdef HAVE_MKSTEMP
  79. strcpy(fname_temp, "/tmp/espeakXXXXXX");
  80. if ((fd_temp = mkstemp(fname_temp)) >= 0)
  81. close(fd_temp);
  82. #else
  83. strcpy(fname_temp, tmpnam(NULL));
  84. #endif
  85. sprintf(command, "sox \"%s\" -r %d -c1 -b 16 -t wav %s\n", fname, samplerate, fname_temp);
  86. if (system(command) == 0)
  87. fname = fname_temp;
  88. }
  89. }
  90. if (f == NULL) {
  91. f = fopen(fname, "rb");
  92. if (f == NULL)
  93. return create_file_error_context(context, errno, fname);
  94. }
  95. length = GetFileLength(fname);
  96. if (length < 0) { // length == -errno
  97. fclose(f);
  98. return create_file_error_context(context, -length, fname);
  99. }
  100. if (fseek(f, 0, SEEK_SET) == -1) {
  101. int error = errno;
  102. fclose(f);
  103. return create_file_error_context(context, error, fname);
  104. }
  105. if ((p = realloc(soundicon_tab[index].data, length)) == NULL) {
  106. fclose(f);
  107. return ENOMEM;
  108. }
  109. if (fread(p, 1, length, f) != length) {
  110. int error = errno;
  111. fclose(f);
  112. if (fname_temp[0])
  113. remove(fname_temp);
  114. free(p);
  115. return create_file_error_context(context, error, fname);
  116. }
  117. fclose(f);
  118. if (fname_temp[0])
  119. remove(fname_temp);
  120. length = p[40] | (p[41] << 8) | (p[42] << 16) | (p[43] << 24);
  121. soundicon_tab[index].length = length / 2; // length in samples
  122. soundicon_tab[index].data = (char *) p;
  123. return ENS_OK;
  124. }
  125. int LookupSoundicon(int c)
  126. {
  127. // Find the sound icon number for a punctuation character and load the audio file if it's not yet loaded
  128. int ix;
  129. for (ix = 0; ix < n_soundicon_tab; ix++) {
  130. if (soundicon_tab[ix].name == c) {
  131. if (soundicon_tab[ix].length == 0) { // not yet loaded, load now
  132. if (LoadSoundFile(NULL, ix, NULL) != ENS_OK) {
  133. return -1; // sound file is not available
  134. }
  135. }
  136. return ix;
  137. }
  138. }
  139. return -1;
  140. }
  141. int LoadSoundFile2(const char *fname)
  142. {
  143. // Load a sound file into the sound icon table and memory
  144. // (if it's not already loaded)
  145. // returns -1 on error or the index of loaded file on success
  146. int ix;
  147. for (ix = 0; ix < n_soundicon_tab; ix++) {
  148. if (((soundicon_tab[ix].filename != NULL) && strcmp(fname, soundicon_tab[ix].filename) == 0)) {
  149. // the file information is found. If length = 0 it needs to be loaded to memory
  150. if (soundicon_tab[ix].length == 0) {
  151. if (LoadSoundFile(NULL, ix, NULL) != ENS_OK)
  152. return -1; // sound file is not available
  153. }
  154. return ix; // sound file already loaded to memory
  155. }
  156. }
  157. // load the file into the current slot and increase index
  158. if (LoadSoundFile(fname, n_soundicon_tab, NULL) != ENS_OK)
  159. return -1;
  160. soundicon_tab[n_soundicon_tab].filename = (char *)realloc(soundicon_tab[n_soundicon_tab].filename, strlen(fname)+1);
  161. strcpy(soundicon_tab[n_soundicon_tab].filename, fname);
  162. n_soundicon_tab++;
  163. return n_soundicon_tab - 1;
  164. }