/*
* 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 "common.h" // for GetFileLength
#include "error.h" // for create_file_error_context
#include "speech.h" // for path_home, PATHSEP
#include "synthesize.h" // for samplerate
int n_soundicon_tab = 0;
SOUND_ICON soundicon_tab[N_SOUNDICON_TAB];
static espeak_ng_STATUS LoadSoundFile(const char *fname, int index, espeak_ng_ERROR_CONTEXT *context)
{
FILE *f;
unsigned char *p;
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;
}
fname_temp[0] = 0;
f = NULL;
if ((f = fopen(fname, "rb")) != NULL) {
int ix;
int header[3];
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;
#if HAVE_MKSTEMP
strcpy(fname_temp, "/tmp/espeakXXXXXX");
int fd_temp;
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 = realloc(soundicon_tab[index].data, length)) == NULL) {
fclose(f);
return ENOMEM;
}
if (fread(p, 1, length, f) != length) {
int error = errno;
fclose(f);
if (fname_temp[0])
remove(fname_temp);
free(p);
return create_file_error_context(context, error, fname);
}
fclose(f);
if (fname_temp[0])
remove(fname_temp);
length = p[40] | (p[41] << 8) | (p[42] << 16) | (p[43] << 24);
soundicon_tab[index].length = length / 2; // length in samples
soundicon_tab[index].data = (char *) p;
return ENS_OK;
}
int LookupSoundicon(int c)
{
// Find the sound icon number for a punctuation character and load the audio file if it's not yet loaded
int ix;
for (ix = 0; ix < n_soundicon_tab; ix++) {
if (soundicon_tab[ix].name == c) {
if (soundicon_tab[ix].length == 0) { // not yet loaded, load now
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 the sound icon table and memory
// (if it's not already loaded)
// returns -1 on error or the index of loaded file on success
int ix;
for (ix = 0; ix < n_soundicon_tab; ix++) {
if (((soundicon_tab[ix].filename != NULL) && strcmp(fname, soundicon_tab[ix].filename) == 0)) {
// the file information is found. If length = 0 it needs to be loaded to memory
if (soundicon_tab[ix].length == 0) {
if (LoadSoundFile(NULL, ix, NULL) != ENS_OK)
return -1; // sound file is not available
}
return ix; // sound file already loaded to memory
}
}
// load the file into the current slot and increase index
if (LoadSoundFile(fname, n_soundicon_tab, NULL) != ENS_OK)
return -1;
soundicon_tab[n_soundicon_tab].filename = (char *)realloc(soundicon_tab[n_soundicon_tab].filename, strlen(fname)+1);
strcpy(soundicon_tab[n_soundicon_tab].filename, fname);
n_soundicon_tab++;
return n_soundicon_tab - 1;
}