pax_global_header00006660000000000000000000000064136427257560014533gustar00rootroot0000000000000052 comment=e742e34e8589dee12705c5d5c7d4d0a22ec929b1 mbrola-3.3+dfsg/000077500000000000000000000000001364272575600135735ustar00rootroot00000000000000mbrola-3.3+dfsg/.gitignore000066400000000000000000000001341364272575600155610ustar00rootroot00000000000000# Binaries Bin/* # Eclipse settings .cproject .project .settings/* # Temporary files *.swp mbrola-3.3+dfsg/Database/000077500000000000000000000000001364272575600152775ustar00rootroot00000000000000mbrola-3.3+dfsg/Database/database.c000066400000000000000000000520771364272575600172220ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: database.c * Time-stamp: <01/09/26 16:45:04 mbrola> * Purpose: diphone database management * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/02/96 : Created. Put here everything concerning the speech database * * 02/02/97 : Replacement diphones enabled (T. Dutoit) * * 08/09/97 : New format -> phonemes are written as Zstring (old limit in * size was 2 char/phoneme) * New policy for silence definition * * 20/10/97 : Database information = Zstrings at the end of the dba * * 05/11/97 : BACON info for 2.05c * * 25/02/98 : Database formats cleaning * drop old compatibility checks with 2.02 and so on * Escape sequence in database_info for non printable information * archiving the database construction parameters * * 03/03/98 : Non posix platforms can't realloc on a NULL pointer * * 23/06/98 : Polymorphic databases ! * A cloning mechanism for multi-instanciation databases * * 28/08/98 : in my way to C/ANSI, dropped the 'const' definition * (that would require extern variables :-( * Thus "const FrameType VOICING_MASK=2;" * becomes "#define VOICING_MASK 2" * * 20/03/00 : keep tracks of the longest diphone in the database to * remove static limits from mbrola engine * * Detects when opening directories .... it's a FAQ because error * message was not clear, adding a Database extension like ".dba" * should do * * Rom databases included (database can be FILE* or int16* depending on * the database mode) * * 25% extra space in the hashtable enhances search * * Pitchmark in memory are kept compressed (4 in on byte) */ #include "common.h" #include "little_big.h" #include "database.h" #include "database_old.h" #ifdef BACON #include "database_bacon.h" #endif #ifdef CEBAB #include "database_cebab.h" #endif #ifndef ROMDATABASE_PURE /* * THE FOLLOWING FUNCTIONS ARE USED FOR DATABASES ON FILE !!!! */ /* Table of database constructors */ init_DatabaseFunction init_tab[ ]= { init_DatabaseOld, /* type 0 */ init_DatabaseBasic, /* type 1 */ # ifdef BACON init_DatabaseBacon, /* type 2 */ # else init_DatabaseBasic, #endif #ifdef CEBAB init_DatabaseCebab, /* type 3 */ # else init_DatabaseBasic, # endif }; #define NB_DATABASE_TYPE (sizeof(init_tab)/sizeof(init_DatabaseFunction)) #define void_(x) if (x) {} char* ReadDatabaseZstring(FILE* database) /* * Read a zstring in the database (allocate the memory) */ { int c; char* PhoneName=NULL; int index=0; do { c=fgetc(database); /* End of file means end of string :-) */ if (c==EOF) c=0; index+=1; if(PhoneName != NULL) PhoneName=(char *) MBR_realloc(PhoneName,index); else PhoneName=(char *) MBR_malloc(index); PhoneName[index-1]= (char) c; } while (c!=0); return PhoneName; } bool ReadDatabaseInfo(Database* dba) /* * Extract textual information from the database if any */ { /* go to the 'end' of the file and read the information */ fseek(database(dba),RawOffset(dba)+SizeRaw(dba),SEEK_SET); while (!feof(database(dba))) { PhonemeName str= ReadDatabaseZstring( database(dba) ); append_ZStringList( info(dba), str ); MBR_free(str); } return True; } /* * Three parts of the Database header */ bool ReadDatabaseHeader(Database* dba) /* * Reads the diphone database header , and initialize variables */ { FILE* database; uint16 OldSizeMrk; /* TO DO: Destroy when it becomes outdated !! */ int i; debug_message1("Read Header\n"); /* * Load the diphone database */ if ((database=fopen(dbaname(dba),"rb"))==NULL) { fatal_message(ERROR_DBNOTFOUND,"FATAL ERROR : cannot find file %s !\n",dbaname(dba)); return False; } dba->database = (void*) database; /* Sanity check -> big endian waiting on the corner */ i= fread(&Magic(dba),1,6,database); /* Reads "MBROLA" */ if (i==0) { fatal_message(ERROR_DBWRONGVERSION, "Database format error\n" "%s is an empty file (could be a directory)\n" ,dbaname(dba)); } if ( (i != 6) || (strncmp("MBROLA",(char *)Magic(dba),6)) || (Magic(dba)[0] != MAGIC_HEADER)) { fatal_message(ERROR_DBWRONGVERSION, "Binary number format error\n" "You are probably using a version of %s incompatible\n" "with your machine architecture.\n" "Get the right one from the MBROLA project homepage :\n" " " WWW_ADDRESS "\n" ,dbaname(dba)); return False; } for (i=0;i<5;i++) Version(dba)[i]= (char) fgetc(database); Version(dba)[5]='\0'; readl_int16(&nb_diphone(dba),database); /* * Version hack due to limited representation to keep compatibility * between formats TO DO : Remove when outdated ! */ readl_uint16(&OldSizeMrk,database); if (OldSizeMrk==0) { /* Sign of the new format !!! */ readl_int32(&SizeMrk(dba),database); } else { /* old format */ SizeMrk(dba)= OldSizeMrk; } readl_int32(&SizeRaw(dba), database); readl_int16(&Freq(dba), database); void_(fread(&MBRPeriod(dba), sizeof(MBRPeriod(dba)), 1, database)); void_(fread(&Coding(dba), sizeof(Coding(dba)), 1, database)); if (strcmp( Version(dba), SYNTH_VERSION) > 0 ) { fatal_message(ERROR_DBWRONGARCHITECTURE, "This program is not compatible with your database\n" "Get the last version of mbrola at www address :\n" " " WWW_ADDRESS "\n"); return False; } if ( MBRPeriod(dba) > 400 ) { warning_message(ERROR_PERIODTOOLONG, "Warning: Period %i is really long\n", MBRPeriod(dba)); } if (strcmp("2.05",Version(dba))>0) { /* Oh my, we're older than 2.05, let's call the compatibility driver! */ Coding(dba)=0; } debug_message2("VERSION %s\n", Version(dba)); debug_message2("nb_diphone %i\n",nb_diphone(dba)); debug_message2("SizeMrk %i\n",SizeMrk(dba)); debug_message2("SizeRaw %i\n",SizeRaw(dba)); debug_message2("Freq %i\n",Freq(dba)); debug_message2("MBRPeriod %i\n",MBRPeriod(dba)); debug_message2("Coding %i\n",Coding(dba)); return True; } bool ReadDatabaseIndex(Database* dba) /* * Read the index table of diphones, and put them in the hash table */ { FILE* database=database(dba); int error=False; int i; int32 indice_pm=0; /* cumulated pos in pitch mark vector */ int32 indice_wav=0; /* cumulated pos in the waveform dba */ uint8 nb_wframe; /* Physical number of frame */ PhonemeName new_left; PhonemeName new_right; int16 new_halfseg; uint8 new_nb_frame; int32 new_pos_pm; int32 new_pos_wave; /* initialize hash table: add extra 25% to enhance performances */ diphone_table(dba)=init_HashTab( nb_diphone(dba) + nb_diphone(dba)/4); /* Insert diphones one by one in the hash table */ for(i=0; (indice_pm!=SizeMrk(dba))&&(i max_frame(dba)) { max_frame(dba)=nb_wframe; } } /* dutoit 02/02/97 * Check if we've reached the end of the diphone table * The rest are replacement diphones, they don't correspond * to new samples, but duplicate existing diphones */ for( ; i depend on database Coding */ void close_DatabaseBasic(Database* dba) /* * Release the memory for a raw database */ { debug_message2("close_DatabaseBasic : %i\n", Coding(dba)); if ( info(dba) ) close_ZStringList( info(dba) ); /* close ReadDatabaseInfo */ close_HashTab( diphone_table(dba) ); /* close ReadDatabaseIndex */ if (pmrk(dba)) MBR_free(pmrk(dba)); /* close ReadDatabasePitchMark */ if (database(dba)) fclose(database(dba)); /* close ReadDatabaseHeader */ if (dbaname(dba)) MBR_free(dbaname(dba)); /* file name */ if (sil_phon(dba)) MBR_free(sil_phon(dba)); /* silence phoneme, string */ MBR_free(dba); debug_message1("done close_DatabaseBasic\n"); } Database* init_DatabaseBasic(Database* dba) /* * Basic version, read raw waves = Check there's no coding * Returning NULL means error */ { debug_message1("init_DatabaseBasic\n"); /* init virtuals */ dba->getdiphone_Database= getdiphone_DatabaseBasic; dba->close_Database= close_DatabaseBasic; /* A basic dba contains RAW waveforms */ if ( Coding(dba) != DIPHONE_RAW ) { dba->close_Database(dba); fatal_message( ERROR_BINNUMBERFORMAT, "This program can't decode your database\n" "Get the last version of mbrola at www address :\n" " " WWW_ADDRESS "\n"); return NULL; } if ( ! ReadDatabaseIndex(dba) || ! ReadDatabasePitchMark(dba) || ! ReadDatabaseInfo(dba) ) { dba->close_Database(dba); return NULL; } debug_message1("done init_DatabaseBasic\n"); return dba; } Database* init_Database(char* dbaname) /* Generic initialization, calls the appropriate constructor * Returning NULL means fatal error (check LastErr) */ { Database* mydba; debug_message1("init_Database\n"); mydba= (Database*) MBR_malloc(sizeof(Database)); /* First initialize the name, and give 0 values for error handling and * premature exit */ dbaname(mydba)= MBR_strdup(dbaname); mydba->database= NULL; sil_phon(mydba)= NULL; max_frame(mydba)= 0; pmrk(mydba)= NULL; diphone_table(mydba)= NULL; mydba->close_Database= close_DatabaseBasic; /* will be changed depending on the dba type */ info(mydba)= init_ZStringList(); if (! ReadDatabaseHeader(mydba) ) { mydba->close_Database(mydba); return NULL; } if ( Coding(mydba) > NB_DATABASE_TYPE ) { mydba->close_Database(mydba); fatal_message( ERROR_BINNUMBERFORMAT, "This program can't decode your database\n" "Get the last version of mbrola at www address :\n" " " WWW_ADDRESS "\n"); return NULL; } debug_message1("virtual init_Database\n"); /* Yes it is that simple !! Watch your step */ return init_tab[Coding(mydba)](mydba); } Database* init_rename_Database(char* dbaname, ZStringList* rename, ZStringList* clone) /* * A variant of init_Database allowing phoneme renaming on the fly * * rename and clone can be NULL to indicate there's nothing to change * * Renaming is a ONCE consuming operation (the database is changed * at loading) -> it involves a complete reconstruction of the hash table * but nothing else at run-time */ { Database* mydba= init_Database(dbaname); PhonemeName new_sil= NULL; debug_message1("init_rename_Database\n"); /* Standard initialization failed ? */ if (!mydba) return NULL; /* Test if renaming apply on the silence diphone */ if (rename) new_sil= find_rename_ZStringList(rename, sil_phon(mydba)); if (new_sil) { MBR_free(sil_phon(mydba)); sil_phon(mydba)=MBR_strdup(new_sil); } if (rename) diphone_table(mydba)= diphone_rename_HashTab( diphone_table(mydba), rename); if (clone) diphone_table(mydba)= diphone_clone_HashTab( diphone_table(mydba), clone); debug_message1("done Init_rename_Database\n"); return mydba; } #endif /* ROMDATABASE_PURE .... next function can be used in both worlds */ int getDatabaseInfo(Database* dba, char* msg, int size, int index) /* * Retrieve the ith info message, NULL means get the size */ { int return_size=0; /* Default error flag */ if ( (index < size_ZStringList(info(dba))) && (index >= 0) ) { /* request the size of an information message */ if (msg==NULL) return_size= strlen( decode_ZStringList( info(dba), index) ) + 1; else { /* request the message itself */ strncpy(msg, decode_ZStringList( info(dba), index), size); msg[size-1]= 0; /* append 0 for security if msg is > size */ return_size= strlen(msg); /* effective size */ /* * Non printable information archiving the database construction * parameters */ if (msg[0] == (char) INFO_ESCAPE) msg[0]= 0; } } return return_size; } bool getdiphone_DatabaseBasic(Database* dba, DiphoneSynthesis *diph) /* * Basic loading of the diphone specified by diph. Stores the samples * Return False in case of error */ { debug_message2("getDiphone_DatabaseBasic : %i \n", Coding(dba)); debug_message3(" diphone : %s-%s ", name_Phone(LeftPhone(diph)), name_Phone(RightPhone(diph))); if (! init_common_Database(dba,diph)) return False; debug_message3(" Nbframe : %d, add : %ld ", nb_frame_diphone(diph), pos_wave_diphone(diph)); #ifdef ROMDATABASE_INIT if ( Coding(dba)& ROM_MASK) { /* * We're in ROM, it's as simple as that */ buffer(diph)= (int16*) rom_wave_ptr(dba) + pos_wave_diphone(diph); } else #endif /* ROMDATABASE_INIT */ { /* * We're on file */ #ifndef ROMDATABASE_PURE fseek(database(dba), pos_wave_diphone(diph) * sizeof(int16) + RawOffset(dba), SEEK_SET); /* Sanity check */ if ( tot_frame(diph) > max_frame(dba) ) { fatal_message(ERROR_PHOLENGTH, "PANIC: phone %s-%s -> %i frames > Max=%i\n", name_Phone(LeftPhone(diph)), name_Phone(RightPhone(diph)), tot_frame(diph), max_frame(dba)); return False; } if ( readl_int16buffer( buffer(diph), tot_frame(diph)*MBRPeriod(dba), database(dba)) != (unsigned) tot_frame(diph)*MBRPeriod(dba) ) { fatal_message(ERROR_PHOREADING, "PANIC when reading phone %s-%s\n", name_Phone(LeftPhone(diph)), name_Phone(RightPhone(diph))); return False; } #endif /* ROMDATABASE_PURE */ } debug_message1("done getdiphone_DatabaseBasic\n"); return True; } void init_real_frame(DiphoneSynthesis *diph) /* * Make the link between logical and physical frames */ { int pred_type; /* Type ( Voiced/ Unvoiced ) of the previous frame */ uint8 i; /* physical number of frames of the diphone */ /* Stride thru the pitch marks to spot Unvoiced-Voiced transitions */ tot_frame(diph)=1; real_frame(diph)[0]=1; pred_type=V_REG; for(i=1; i<= nb_frame_diphone(diph) ; tot_frame(diph)++,i++) { /* Check for extra frame at the end of an unvoiced sequence */ if ( !(pred_type & VOICING_MASK ) && ( pmrk_DiphoneSynthesis(diph, i) & VOICING_MASK )) { tot_frame(diph)++; } real_frame(diph)[i]=tot_frame(diph); pred_type=pmrk_DiphoneSynthesis(diph, i); } tot_frame(diph)--; /* If the last is unvoiced, bonus frame !!! */ if (! (pred_type & VOICING_MASK )) tot_frame(diph)++; } bool init_common_Database(Database* dba, DiphoneSynthesis *diph) /* * Common initialization shared among all database types */ { /* Search the diphone index in the database */ int i= search_HashTab(diphone_table(dba), name_Phone(LeftPhone(diph)), name_Phone(RightPhone(diph))); if (i==NONE) return False; Descriptor(diph)= content(diphone_table(dba),i); /* Substract 1 as index will go from 1 to N (instead of 0..N-1) */ diph->p_pmrk= & (pmrk(dba)[ diph->Descriptor->pos_pm / 4 ]); diph->p_pmrk_offset= diph->Descriptor->pos_pm % 4; /* link between physical and logical frames */ init_real_frame(diph); return True; } #ifdef MULTI_CHANNEL static void close_DatabaseCopy(Database* dba) /* * Close a database created with the copyconstructor */ { debug_message1("close_DatabaseCopy\n"); #ifdef ROMDATABASE_INIT if ( Coding(dba) & ROM_MASK ) { /* Nothing to close if it's a ROM database */ } else #endif /* ROMDATABASE_INIT */ { #ifndef ROMDATABASE_PURE if ( database(dba) ) fclose( database(dba) ); #endif } /* don't release anything else as it may be shared ! */ MBR_free(dba); } Database* copyconstructor_Database(Database* old_dba) /* Creates a copy of a diphone database so that many synthesis engine * can use the same database at the same time (duplicate the file handler * and connect a dumb "close_Database" * * Highly recommended with multichannel mbrola, unless you can guaranty * mutually exclusive access to the getdiphone function */ { Database* mydba; debug_message1("copyconstructor_Database\n"); mydba= (Database*) MBR_malloc(sizeof(Database)); /* clone ! */ *mydba= *old_dba; /* Closing should not release shared object */ mydba->close_Database= close_DatabaseCopy; /* duplicate the file handler ... if any */ #ifdef ROMDATABASE_INIT if ( Coding(mydba)&ROM_MASK ) { /* Nothing to duplicate if it's a ROM database */ } else #endif { #ifndef ROMDATABASE_PURE if (( mydba->database= (void*) fopen(dbaname(mydba),"rb")) == NULL) { mydba->close_Database(mydba); fatal_message(ERROR_DBNOTFOUND, "FATAL ERROR : cannot find file %s !\n", dbaname(mydba)); return NULL; } #endif } return mydba; } #endif /* MULTI_CHANNEL MODE */ mbrola-3.3+dfsg/Database/database.h000066400000000000000000000202301364272575600172110ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: database.h * Time-stamp: <2000-04-07 16:48:29 pagel> * Purpose: diphone database management * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/02/96 : Created. Put here everything concerning the speech database * * 02/02/97 : Replacement diphones enabled (T. Dutoit) * * 08/09/97 : New format -> phonemes are written as Zstring (old limit in * size was 2 char/phoneme) * New policy for silence definition * * 20/10/97 : Database information = Zstrings at the end of the dba * * 05/11/97 : BACON info for 2.05c * * 25/02/98 : Database formats cleaning * drop old compatibility checks with 2.02 and so on * Escape sequence in database_info for non printable information * archiving the database construction parameters * * 03/03/98 : Non posix platforms can't realloc on a NULL pointer * * 23/06/98 : Polymorphic databases ! * A cloning mechanism for multi-instanciation databases * * 28/08/98 : in my way to C/ANSI, dropped the 'const' definition * (that would require extern variables :-( * Thus "const FrameType VOICING_MASK=2;" * becomes "#define VOICING_MASK 2" * * 20/03/00 : keep tracks of the longest diphone in the database to * remove static limits from mbrola engine * * Detects when opening directories .... it's a FAQ because error * message was not clear, adding a Database extension like ".dba" * should do * * Rom databases included (database can be FILE* or int16* depending on * the database mode) * * 25% extra space in the hashtable enhances search */ #ifndef _DATABASE_H #define _DATABASE_H #include "audio.h" #include "diphone.h" #include "hash_tab.h" #define DIPHONE_RAW 1 /* The diphone wave database is raw */ #define ROM_MASK 128 /* The Coding tag of the database indicate if it's in ROM */ #define INFO_ESCAPE 0xFF /* Escape code in database informations (prevents from displaying) */ /* * Frame types in the MBR analysed database */ typedef uint8 FrameType; #define VOICING_MASK 2 /* Voiced/Unvoiced mask */ #define TRANSIT_MASK 1 /* Stationary/Transitory mask */ #define NV_REG 0 /* unvoiced stable state */ #define NV_TRA TRANSIT_MASK /* unvoiced transient */ #define V_REG VOICING_MASK /* voiced stable state */ #define V_TRA (VOICING_MASK | TRANSIT_MASK) /* voiced transient */ /* * Main type */ typedef struct Database Database; typedef bool (*getdiphone_DatabaseFunction)(Database* dba, DiphoneSynthesis *diph); typedef void (*close_DatabaseFunction)(Database* dba); typedef Database* (*init_DatabaseFunction)(Database* dba); struct Database { /* Polymorphic structure, depends on Coding */ void* self; /* Virtual function for diphone wave loading */ getdiphone_DatabaseFunction getdiphone_Database; /* Virtual function to release the memory */ close_DatabaseFunction close_Database; uint8 Coding; /* Type of coding DIPHONE_RAW, or BACON */ int16 Freq; /* Sampling frequency of the database */ uint8 MBRPeriod; /* Period of the MBR analysis */ int16 nb_diphone; /* Number of diphones in the database */ int32 SizeMrk; /* Size of the pitchmark part */ FrameType *pmrk; /* The whole pitch marks database */ int32 SizeRaw; /* Size of the wave part */ int32 RawOffset; /* Offset for raw samples in database */ uint8 max_frame; /* Maximum number of frames encountered for a diphone in the dba */ int16 max_samples; /* Size of the diphone buffer= 0 means let me manage it myself */ int32 Magic[2]; /* Magic header of the database */ char Version[6]; /* Version of the database */ PhonemeName sil_phon; /* Silence symbol in the database */ HashTab *diphone_table; /* Diphone index table */ ZStringList* info; /* information strings */ char *dbaname; /* name of the diphone file */ void *database; /* diphone wave file or base pointer to wave data, depending on dba type */ }; /* Convenient macros */ #define dbaname(PDatabase) PDatabase->dbaname /* Those 2 macros access the same field */ #define rom_wave_ptr(PDatabase) (PDatabase->database) #define database(PDatabase) ((FILE*)PDatabase->database) #define nb_diphone(PDatabase) PDatabase->nb_diphone #define RawOffset(PDatabase) PDatabase->RawOffset #define Coding(PDatabase) PDatabase->Coding #define Freq(PDatabase) PDatabase->Freq #define MBRPeriod(PDatabase) PDatabase->MBRPeriod #define SizeMrk(PDatabase) PDatabase->SizeMrk #define SizeRaw(PDatabase) PDatabase->SizeRaw #define max_frame(PDatabase) PDatabase->max_frame #define max_samples(PDatabase) PDatabase->max_samples #define Magic(PDatabase) PDatabase->Magic #define Version(PDatabase) PDatabase->Version #define sil_phon(PDatabase) PDatabase->sil_phon #define info(PDatabase) PDatabase->info #define pmrk(PDatabase) PDatabase->pmrk #define diphone_table(PDatabase) PDatabase->diphone_table #ifndef ROMDATABASE_PURE /* * Functions relying on FILE based databases */ /* * Three parts of the Database header */ bool ReadDatabaseHeader(Database* dba); /* Reads the diphone database header , and initialize variables */ bool ReadDatabaseIndex(Database* dba); /* * Read the index table of diphones, and put them in the hash table */ bool ReadDatabasePitchMark(Database* dba); /* Load pitch markers (Voiced/Unvoiced, Transitory/Stationnary) */ bool ReadDatabaseInfo(Database* dba); /* * Extract textual information from the database if any */ /* * Initialisation and loading of Diphones -> depend on database Coding * Returning NULL means fail (check LastError) */ Database* init_DatabaseBasic(Database* dba); /* * Basic version, read raw waves = Check there's no coding * Returning NULL means error */ void close_DatabaseBasic(Database* dba); /* Release the memory allocated for the in-house BACON decoder */ Database* init_Database(char* dbaname); /* Generic initialization, calls the appropriate constructor * Returning NULL means fail (check LastError) */ Database* init_rename_Database(char* dbaname, ZStringList* rename, ZStringList* clone); /* * A variant of init_Database allowing phoneme renaming on the fly * Returning NULL means fail (check LastError) * * rename and clone can be NULL to indicate there's nothing to change * * Renaming is a ONCE consuming operation (the database is changed * at loading) -> it involves a complete reconstruction of the hash table * but nothing else at run-time */ #endif /* ROMDATABASE_PURE */ #ifdef MULTICHANNEL_MODE Database* copyconstructor_Database(Database* dba); /* Creates a copy of a diphone database so that many synthesis engine * can use the same database at the same time (duplicate the file handler) * * Returning NULL means fail (check LastError) * * Highly recommended with multichannel mbrola, unless you can guaranty * mutually exclusive access to the getdiphone function */ #endif /* * Available to everybody */ int getDatabaseInfo(Database* dba, char* msg, int size, int index); /* * Retrieve the ith info message, NULL means get the size */ bool init_common_Database(Database* dba, DiphoneSynthesis *diph); /* * Common initialization shared among all database types */ bool getdiphone_DatabaseBasic(Database* dba, DiphoneSynthesis *ds); /* * Basic loading of the diphone specified by diph. Stores the samples * Return False in case of error */ #endif mbrola-3.3+dfsg/Database/database_old.c000066400000000000000000000210721364272575600200470ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: database_old.c * Time-stamp: <00/03/30 01:37:55 pagel> * * Purpose: Decode raw formats before 2.05 release, here for compatibility purpose * Use pretty much RAW functions * * Author: Vincent Pagel * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * History: * * 25/06/98 : Created from 2.06 code * 20/03/00 : Add support for max_frame parsing + new hash table scheme */ #include "database.h" #define void_(x) if (x) {} #ifndef ROMDATABASE_PURE /********************************************************* * OLD TYPES: Better lock it up and throw away the key * *********************************************************/ /* * Structure of the diphone database (as stored in file) * Used before 2.02a */ typedef struct { char left[2],right[2]; /* Name of the diphone */ int32 pos_wave; /* position in SPEECH_FILE */ int16 halfseg; /* position of center of diphone */ uint16 pos_pm; /* index in PITCHMARK_FILE */ uint8 nb_frame; /* Number of pitch markers */ char dummy[3]; /* Alignment on multiple of 4 */ } DiphoneEvenOlderFile; /* * Structure of the diphone database (as stored in file) * Used from release 2.02a to release 2.05 * * Since 2.05 there is no more struct related to the * index datas, we just read the info sequentially */ typedef struct { char left[2],right[2]; /* Name of the diphone */ int16 halfseg; /* position of center of diphone */ uint8 nb_frame; /* Number of pitch markers */ uint8 nb_wframe; /* index in PITCHMARK_FILE */ } DiphoneOldFile; /* Specifies a diphone that is the copy of another one */ typedef struct { char left[2],right[2]; /* Name of the diphone */ char leftr[2],rightr[2]; /* Name of the replacement diphone */ } DiphoneReplace; /******************************************************* * OLD FUNCTIONS: don't even ruin your eyesight on it * *******************************************************/ Database* init_DatabaseOld(Database* dba) /* * Initializes the old ones! */ { int i; int32 indice_pm=0; int32 indice_wav=0; bool even_older; /* Allocate one more byte for the trailing 0 */ PhonemeName left_cell= (char *) MBR_malloc(3); PhonemeName right_cell= (char *) MBR_malloc(3); int16 halfseg_cell; int32 pos_wave_cell; int32 pos_pm_cell; uint8 nb_frame_cell; debug_message2("Old compatibility mode : %i\n",Coding(dba)); warning_message(WARNING_UPGRADE,"Think of upgrading your database!\n"); /* Except some oddities for ReadDatabaseIndex and PitchMark, once it's * loaded it works like RAW databases */ dba->getdiphone_Database= getdiphone_DatabaseBasic; dba->close_Database= close_DatabaseBasic; /* Check version < 2.02 or 2.02 <= version < 2.05 */ if (strcmp("2.02",Version(dba))>0) { nb_diphone(dba)= (int16) (nb_diphone(dba) / sizeof(DiphoneEvenOlderFile)); even_older=True; } else /* From 2.02 to 2.05 */ { /* New format allow more diphone in a database than previously */ even_older=False; } /* * Read the index table of diphones, and put them in the hash table */ diphone_table(dba)=init_HashTab(nb_diphone(dba)); /* initialize hash table */ /* Insert diphones one by one in the hash table */ for(i=0; (indice_pm!=SizeMrk(dba)) && (i>8) | ((one_oldfcell.pos_wave>>24)&0xFF)); one_oldfcell.pos_pm = ( ((one_oldfcell.pos_pm&0xFF00) >>8) | ((one_oldfcell.pos_pm&0xFF) <<8)); #endif strncpy( left_cell , one_oldfcell.left,2); strncpy( right_cell , one_oldfcell.right,2); nb_frame_cell= one_oldfcell.nb_frame; halfseg_cell= one_oldfcell.halfseg; pos_wave_cell= one_oldfcell.pos_wave; pos_pm_cell= one_oldfcell.pos_pm; } else { /* Renaissance 8 bytes structures */ DiphoneOldFile one_fcell; /* Cell on file */ void_(fread(&one_fcell,sizeof(one_fcell),1,database(dba))); strncpy( left_cell, one_fcell.left,2); strncpy( right_cell, one_fcell.right,2); nb_frame_cell= one_fcell.nb_frame; halfseg_cell= one_fcell.halfseg; pos_pm_cell= indice_pm; indice_pm+=one_fcell.nb_frame; pos_wave_cell= indice_wav; indice_wav+= (long) one_fcell.nb_wframe* (long) MBRPeriod(dba); } /* add a trailing 0 to the name */ left_cell[2]= 0; right_cell[2]= 0; /* One world, one vision, one diphone database (the PC one) -> swap */ #ifdef BIG_ENDIAN halfseg_cell= ( (( halfseg_cell & 0xFF00) >>8) | (( halfseg_cell & 0xFF) <<8)); #endif debug_message8("%i Diph %s-%s nbframe=%i poswav=%i pospm=%i halfseg=%i\n", i, left_cell, right_cell, nb_frame_cell, pos_wave_cell, pos_pm_cell, halfseg_cell); add_HashTab(diphone_table(dba), left_cell, right_cell, pos_wave_cell, halfseg_cell, pos_pm_cell, nb_frame_cell); /* Keep a record of the longest diphone (to allocate oversized temporary buffer) */ if (nb_frame_cell*1.5 > max_frame(dba)) { max_frame(dba)=nb_frame_cell*1.5; } } /* The last diphone of the database is _-_ */ sil_phon(dba)= MBR_strdup(left_cell); debug_message2("Init silence with %s\n", left_cell); /* dutoit 02/02/97 * Check if we've reached the end of the diphone table * The rest are replacement diphones, they don't correspond * to new samples, but duplicate existing diphones */ for( ; i * Purpose: Decode raw formats before 2.05 release, here for compatibility purpose * Use pretty much RAW functions * Author: Vincent Pagel * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * History: * * 25/06/98 : Created from 2.06 code chunks */ #ifndef _DATABASE_OLD_H #define _DATABASE_OLD_H Database* init_DatabaseOld(Database* dba); /* * Initializes the old ones! */ #endif mbrola-3.3+dfsg/Database/diphone_info.c000066400000000000000000000037301364272575600201070ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: diphoneinfo.c * Purpose: diphone descriptor * Authors: Vincent Pagel & Alain Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 09/04/98 : Created. A diphone descriptor intended for a hash_table * * 09/09/98 : DiphoneInfo now includes memory allocation and dereference * * 03/03/00 : Use PhonemeCode instead of PhonemeName to get a flat structure * no more memory memory allocation needed */ #include "diphone_info.h" #include "mbralloc.h" int32 hash_DiphoneInfo(const char* left_string, const char* right_string) /* * Hashing function for the research of the diphone name in diphone_table */ { int32 mult; int i,shift; /* nb_empty=433 nb_collision=309 * 504 alone and rest is 742 / 309 = 2.401294 for one hash code * * On 1000 phoneme (Levai.pho) average 1.546953 comparison to find the key * Systematic search for diphones gives average 1.5955 path * * Adding extra 25% space in the hash table leads to 1.427 comparisons * to find the key */ shift=0; mult=0; for(i=0;left_string[i]!=0;i++) { mult+= left_string[i] << shift; shift=(shift+8)%32; } for(i=0;right_string[i]!=0;i++) { mult+= right_string[i] << shift ; shift=(shift+8)%32; } return(mult); } mbrola-3.3+dfsg/Database/diphone_info.h000066400000000000000000000041441364272575600201140ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: diphoneinfo.c * Time-stamp: <00/03/29 23:38:54 pagel> * Purpose: diphone descriptor * Authors: Vincent Pagel & Alain Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 09/04/98 : Created. A diphone descriptor intended for a hash_table * * 09/09/98 : DiphoneInfo now includes memory allocation and dereference * * 03/03/00 : Use PhonemeCode instead of PhonemeName to get a flat structure * no more memory memory allocation needed */ #ifndef DIPHONE_INFO_H #define DIPHONE_INFO_H #include "common.h" /* * Structure of the diphone database (as stored in memory) */ typedef struct { /* Name of the diphone */ PhonemeCode left; PhonemeCode right; int32 pos_wave; /* position in SPEECH_FILE */ int16 halfseg; /* position of center of diphone */ int32 pos_pm; /* index in PITCHMARK_FILE */ uint8 nb_frame; /* Number of pitch markers */ } DiphoneInfo; /* Convenience macros */ #define left(diphoneinfo) (diphoneinfo).left #define right(diphoneinfo) (diphoneinfo).right #define pos_wave(diphoneinfo) (diphoneinfo).pos_wave #define halfseg(diphoneinfo) (diphoneinfo).halfseg #define pos_pm(diphoneinfo) (diphoneinfo).pos_pm #define nb_frame(diphoneinfo) (diphoneinfo).nb_frame int32 hash_DiphoneInfo(const char* left, const char* right); /* * Hashing function for the research of the diphone name in diphone_table */ #endif mbrola-3.3+dfsg/Database/hash_tab.c000066400000000000000000000342421364272575600172210ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: hash_table.c * Time-stamp: <00/03/30 00:17:20 pagel> * Purpose: coalescent hashing table * Author: Vincent Pagel and Alain Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/02/96 : Created. Implement a coalescent hashing of the diphone database * * 29/01/97 : Generalization to phoneme names longer than 2 chars * * 01/09/97 : Alain Ruelle adds close_hash to release the memory * * 17/03/00 : VP adds an auxiliary phoneme encoding table (for ROM databases) * the policy is that maintaining Phoneme names with char* for a ROM * frozen hash structure is foolish, while maintaining an index in a * phoneme table is sensible (ROM image of the hashtable can be frozen * since it doesn't contain any "pointers" - without mentionning that * pointers on phoneme names were desesperately redundants). The cost * of that change is: when initializing a database it takes a sequential * or dichotomic search in the auxiliary table to translate phoneme * names (sequential at the moment as number of phonemes are generally * small). * * Ultimately may be that some of you wish to even completely remove * char* phonemes and use uint8 instead and spare the "malloc" "free" * dance on phoneme names during Parser input. Yes phoneme names is a * convention we can do without .... except for human readability and * debugging. Another advantage of PhonemeCode everywhere would be * that the hash_table would be reduced to computing x*N+y access in a * matrix!! * * 29/03/00: VP adds memory alignment for ROM databases */ #include #include "common.h" #include "database.h" #include "mbrola.h" #include "diphone_info.h" #include "hash_tab.h" #if defined(ROMDATABASE_STORE) || defined(ROMDATABASE_INIT) #include "rom_handling.h" #endif HashTab* init_HashTab(int16 nb_item) /* Initialize an empty hash_table */ { int i; HashTab *result; result= (HashTab *) MBR_malloc(sizeof(HashTab)); nb_item(result)= nb_item; result->hash_tab= (HashInfo *) MBR_malloc(nb_item*sizeof(HashInfo)); /* Mark all the cells as unoccupied */ for(i=0; itot_nb_coup=0; result->tot_coup=0; #endif return(result); } void close_HashTab(HashTab *hash_tab) /* Empty and release the hash_table ~ruelle */ { if (hash_tab) { if (auxiliary_tab(hash_tab)) close_ZStringList(auxiliary_tab(hash_tab)); if (hash_tab->hash_tab) MBR_free(hash_tab->hash_tab); MBR_free(hash_tab); } } int16 mix(int32 index, int16 nb_diphone) /* * Homogeneization to avoid performance drops depending on nb_diphone * if we had computed mult % nb_diphone */ { double temp; temp= index * 0.6180339887; /* (sqrt(5)-1)/2 */ temp-= floor(temp); temp*= nb_diphone; return( (int16) temp); } void add_HashTab(HashTab *hash_tab, PhonemeName new_left, PhonemeName new_right, int32 new_pos_wave, int16 new_halfseg, int32 new_pos_pm, uint8 new_nb_frame ) /* Add a new reference in the diphone table */ { DiphoneInfo* one_cell; int16 first_free; int16 hash_value= mix( hash_DiphoneInfo(new_left, new_right), nb_item(hash_tab)); int16 chosen; /* The primary choice is free? */ if (hit(hash_tab,hash_value)==EMPTY) { chosen= hash_value; next_one(hash_tab, chosen)=NONE; #ifdef DEBUG_HASH debug_message2("primary choice FREE %i\n",hash_value); #endif } else { #ifdef DEBUG_HASH debug_message3("-> %i hits at %i\n",hit(hash_tab,hash_value),hash_value); #endif first_free=first_free(hash_tab); /* First free cell in the hash table */ for( ; hit(hash_tab,first_free)!=EMPTY ; first_free--); /* put the cell in the linked list */ chosen=first_free; next_one(hash_tab,chosen)= next_one(hash_tab,hash_value); next_one(hash_tab,hash_value)=chosen; /* Cumulate hits */ hit(hash_tab,hash_value)++; first_free--; /* It's now occupied */ first_free(hash_tab)=first_free; } /* Put effective data in the chosen cell */ hit(hash_tab,chosen)=1; one_cell= content(hash_tab, chosen); pos_wave(*one_cell)=new_pos_wave; pos_pm(*one_cell)=new_pos_pm; halfseg(*one_cell)=new_halfseg; nb_frame(*one_cell)=new_nb_frame; left(*one_cell)= encode_ZStringList(auxiliary_tab(hash_tab), new_left); right(*one_cell)= encode_ZStringList(auxiliary_tab(hash_tab), new_right); } bool equalkey_HashTab(const HashTab* ht, int16 hash_value, const PhonemeName left, const PhonemeName right) /* * True if the keys for hashing are equal */ { return ( (strcmp( auxiliary_tab_val(ht, left(*content(ht,hash_value))) , left) == 0) && (strcmp( auxiliary_tab_val(ht, right(*content(ht,hash_value))), right) == 0) ); } int16 search_HashTab(const HashTab *hash_tab,const PhonemeName left,const PhonemeName right) /* * Return the reference number of a diphone in the diphone database * Hash table search -> return NONE=-1 if the value is not present */ { #ifdef DEBUG_HASH int nb_coup=1; #endif int16 hash_value=mix( hash_DiphoneInfo(left,right), nb_item(hash_tab)); /* The primary choice doesn't exist */ if (hit(hash_tab,hash_value)==EMPTY) hash_value=NONE; while ((hash_value!=NONE) && (!equalkey_HashTab( hash_tab, hash_value, left, right))) { #ifdef DEBUG_HASH nb_coup++; #endif hash_value= next_one(hash_tab,hash_value); } #ifdef DEBUG_HASH hash_tab->tot_nb_coup+= nb_coup; hash_tab->tot_coup++; debug_message3(" NBTRIES=%i AVERAGE=%f\n", nb_coup, (float) hash_tab->tot_nb_coup/(float)hash_tab->tot_coup); #endif return(hash_value); } int16 searchdiph_HashTab(const HashTab *hash_tab, DiphoneInfo* di) /* * Return the reference number of a diphone in the diphone database * Hash table search -> return NONE=-1 if the value is not present */ { return search_HashTab(hash_tab, auxiliary_tab_val(hash_tab, left(*di)), auxiliary_tab_val(hash_tab, right(*di))); } HashTab *diphone_rename_HashTab(HashTab *hash_tab, ZStringList* rename) /* * Rename all occurences of diphones containing the phoneme X to phone Y * in the hash table according to rename which contains X-Y pairs * * WARNING 1: it costs some CPU and memory moves .... * * WARNING 2: This operation fundamentaly change the rank of elements * in the hash table, so * * FORGET ALL YOUR POINTER TO ELEMENTS OF THE TABLE */ { int i; PhonemeName new_name; HashTab *hash_temp; /* a new hash table to reorder the renamed elements */ /* no renaming at all, avoid a painfull life to the hash table */ if ( (!rename) || (size_ZStringList(rename) == 0)) return hash_tab; /* old and new tables have the same size */ hash_temp=init_HashTab( nb_item(hash_tab) ); /* Take one by one, rename and add to the new table */ for(i=0; i e.g. if * t is cloned to t_h, then for t-t diphone we must generate * t_h-t t-t_h but also t_h-t_h */ if (cloneLeftRight==2) { nb_new_diphone++; debug_message5("Clone %s into %s for (%s)-(%s)\n", XPhone, YPhone, auxiliary_tab_val(hash_tab, left(di)) , auxiliary_tab_val(hash_tab, right(di))); } } } debug_message2("Clone %i new targets\n", nb_new_diphone ); /* The new one is bigger by nb_new_diphone */ hash_temp=init_HashTab( (int16) (nb_item(hash_tab) + nb_new_diphone) ); /* 2nd pass: take one by one and introduce in the new table */ for(i=0; itot_nb_coup=0; hash_tab->tot_coup=0; } #endif /*************************** * DEALS WITH ROM DATABASES ***************************/ #ifdef ROMDATABASE_STORE void file_flush_ROM_HashTab( HashTab* tab, FILE* rom_file) /* Dump the hash table in a ROM image */ { file_flush_ROM_align16( rom_file ); file_flush_ROM_int16( nb_item(tab), rom_file); file_flush_ROM_int16( first_free(tab), rom_file); file_flush_ROM_array( tab->hash_tab, sizeof(HashInfo), nb_item(tab), rom_file); file_flush_ROM_ZStringList( auxiliary_tab(tab), rom_file); } #endif #ifdef ROMDATABASE_INIT HashTab* init_ROM_HashTab(void** input_ptr) /* * Initialize the hash table from a ROM image */ { HashTab *my_ht; my_ht= (HashTab *) MBR_malloc(sizeof(HashTab)); ptr_ROM_align16(*input_ptr); *input_ptr= read_ROM_int16( &nb_item(my_ht), *input_ptr); *input_ptr= read_ROM_int16( &first_free(my_ht), *input_ptr); *input_ptr= read_ROM_array( (void*) &my_ht->hash_tab, sizeof(HashInfo), nb_item(my_ht), *input_ptr); auxiliary_tab(my_ht)= init_ROM_ZStringList(input_ptr); return my_ht; } void close_ROM_HashTab(HashTab *hash_tab) /* * Close the ROM image (fewer malloc than in regular one) */ { close_ROM_ZStringList( auxiliary_tab(hash_tab) ); MBR_free(hash_tab); } #endif mbrola-3.3+dfsg/Database/hash_tab.h000066400000000000000000000126511364272575600172260ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: hash_table.h * Time-stamp: <00/03/29 23:48:28 pagel> * Purpose: coalescent hashing table * Authors: Vincent Pagel and Alain Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/02/96 : Created. Implement a coalescent hashing of the diphone database * * 29/01/97 : Generalization to phoneme names longer than 2 chars * * 01/09/97 : Alain Ruelle adds close_hash to release the memory * * 17/03/00 : VP adds an auxiliary phoneme encoding table (for ROM databases) * the policy is that maintaining Phoneme names with char* for a ROM * frozen hash structure is foolish, while maintaining an index in a * phoneme table is sensible (ROM image of the hashtable can be frozen * since it doesn't contain any "pointers" - without mentionning that * pointers on phoneme names were desesperately redundants). The cost * of that change is: when initializing a database it takes a sequential * or dichotomic search in the auxiliary table to translate phoneme * names (sequential at the moment as number of phonemes are generally * small). * * Ultimately may be that some of you wish to even completely remove * char* phonemes and use uint8 instead and spare the "malloc" "free" * dance on phoneme names during Parser input. Yes phoneme names is a * convention we can do without .... except for human readability and * debugging. Another advantage of PhonemeCode everywhere would be * that the hash_table would be reduced to computing x*N+y access in a * matrix!! */ #ifndef _HASH_TAB_H #define _HASH_TAB_H #include "diphone_info.h" #include "zstring_list.h" /* Return when the index is not found in the hash table */ #define NONE -1 /* Used to mark a hash cell as empty */ #define EMPTY 255 /* Wrapper structure */ typedef struct { DiphoneInfo content; /* Hashing information */ uint8 hit; /* survey value for number of collisions */ int16 next_one; /* link to the next database cell */ } HashInfo; /* The whole diphone database */ typedef struct { ZStringList * auxiliary_tab; /* Table of phoneme names */ HashInfo *hash_tab; /* Hashing information */ int16 nb_item; /* Number of elements in hash_tab */ int16 first_free; /* First position free from the end of the table */ #ifdef DEBUG_HASH int16 tot_nb_coup; int16 tot_coup; #endif } HashTab; /* Convenient macros */ #define nb_item(Tab) Tab->nb_item #define first_free(Tab) Tab->first_free #define next_one(Tab,Index) Tab->hash_tab[Index].next_one #define hit(Tab,Index) Tab->hash_tab[Index].hit #define content(Tab,Index) (&(Tab->hash_tab[Index].content)) #define auxiliary_tab(Tab) (Tab->auxiliary_tab) #define auxiliary_tab_val(Tab,Index) ( decode_ZStringList(auxiliary_tab(Tab), Index) ) HashTab *init_HashTab(int16 nb_item); /* Initialize a void hash_table */ void close_HashTab(HashTab *hash_tab); /* Empty and release the hash_table */ int16 searchdiph_HashTab(const HashTab *hash_tab, DiphoneInfo* one_cell); /* * Return the reference number of a diphone in the diphone database * Hash table search -> return NONE=-1 if the value is not present */ int16 search_HashTab(const HashTab *hash_tab,const PhonemeName left, const PhonemeName right); /* * Return the reference number of a diphone in the diphone database * Hash table search -> return NONE=-1 if the value is not present */ void add_HashTab(HashTab *hash_tab, PhonemeName new_left, PhonemeName new_right, int32 new_pos_wave, int16 new_halfseg, int32 new_pos_pm, uint8 new_nb_frame ); /* Add a new reference in the diphone table */ HashTab* diphone_rename_HashTab(HashTab* hash_tab, ZStringList* rename); /* * Rename all occurences of diphones containing the phoneme X to phone Y * in the hash table according to rename which contains X-Y pairs * * WARNING 1: it costs some CPU and memory moves .... * * WARNING 2: This operation fundamentaly change the rank of elements * in the hash table, so * * FORGET ALL YOUR POINTER TO ELEMENTS OF THE TABLE */ HashTab* diphone_clone_HashTab(HashTab* hash_tab, ZStringList* clone); /* Make a copy of all occurences of diphones containing the phoneme * X to phoneme Y according to the clone list which contains X-Y pairs * * The clone list contains only ONE occurence of each phoneme */ #ifdef DEBUG_HASH void tuning_HashTab(HashTab *hash_tab); /* Function for debug and tuning purpose */ #endif #ifdef ROMDATABASE_STORE void file_flush_ROM_HashTab( HashTab* tab, FILE* rom_file); /* Dump the hash table in a ROM image */ #endif #ifdef ROMDATABASE_INIT HashTab* init_ROM_HashTab(void** input_ptr); /* * Initialize the hash table from a ROM image */ void close_ROM_HashTab(HashTab *hash_tab); /* * Close the ROM image (fewer malloc that in regular one) */ #endif #endif mbrola-3.3+dfsg/Database/little_big.c000066400000000000000000000057171364272575600175730ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: little_big.c * Purpose: IO little_endian aware * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 09/04/98 : Created from older audio.c * Put here input output function depending on the little endian or * big endian format */ #include "little_big.h" #define void_(x) if (x) {} /* * Read and write operations with/without byte swapping */ void write_int16(int16 value, FILE *output_file) { fwrite(&value,sizeof(int16), 1, output_file); } void write_int32(int32 value, FILE *output_file) { fwrite(&value,sizeof(int32), 1, output_file); } void write_int16_swapped(int16 value, FILE *output_file) { value= (int16) ( ((value & 0xFF00) >>8) | ((value & 0xFF) <<8) ); fwrite(&value,sizeof(int16), 1, output_file); } void write_int32_swapped(int32 value, FILE *output_file) { value=(((value&0xFF)<<24) | \ ((value&0xFF00)<<8) | \ ((value&0xFF0000)>>8) | \ ((value>>24)&0xFF)); fwrite(&value,sizeof(int32), 1, output_file); } void read_int16(int16 *value, FILE *output_file) { void_(fread(value,sizeof(int16), 1, output_file)); } void read_uint16(uint16 *value, FILE *output_file) { void_(fread(value,sizeof(uint16), 1, output_file)); } size_t read_int16buffer(int16 *ptr, size_t nitems, FILE *stream) { return fread(ptr,sizeof(int16),nitems,stream); } void read_int32(int32 *value, FILE *output_file) { void_(fread(value,sizeof(int32), 1, output_file)); } void read_int16_swapped(int16 *value, FILE *output_file) { void_(fread(value,sizeof(int16), 1, output_file)); *value= (int16) ( ((*value & 0xFF00) >> 8) | ((*value & 0xFF) << 8) ); } size_t read_int16buffer_swapped(int16 *ptr, size_t nitems, FILE *stream) { size_t nb_read=fread(ptr,sizeof(int16),nitems,stream); swab( (char*) ptr, (char*) ptr, sizeof(int16)*nb_read); return(nb_read); } void read_uint16_swapped(uint16 *value, FILE *output_file) { void_(fread(value,sizeof(uint16), 1, output_file)); *value= (int16) (((*value & 0xFF00) >> 8) | ((*value & 0xFF) << 8)); } void read_int32_swapped(int32 *value, FILE *output_file) { void_(fread(value,sizeof(int32), 1, output_file)); *value=(((*value&0xFF)<<24) | \ ((*value&0xFF00)<<8) | \ ((*value&0xFF0000)>>8) | \ ((*value>>24)&0xFF)); } mbrola-3.3+dfsg/Database/little_big.h000066400000000000000000000062021364272575600175660ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: little_big.h * Time-stamp: <2000-03-28 17:55:41 pagel> * Purpose: IO little_endian aware * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 09/04/98: Created from older audio.h */ #ifndef _LITTLE_BIG_H #define _LITTLE_BIG_H #include "common.h" /* * Check that architecture is defined and define reading and writing operations * depending on it ( deals with byte swapping) */ #ifdef LITTLE_ENDIAN #define MAGIC_HEADER 0x4f52424d #define readl_int32(X,Y) read_int32(X,Y) #define readl_int16(X,Y) read_int16(X,Y) #define readl_int16buffer(X,Y,Z) read_int16buffer(X,Y,Z) #define readl_uint16(X,Y) read_uint16(X,Y) #define readb_int32(X,Y) read_int32_swapped(X,Y) #define readb_int16(X,Y) read_int16_swapped(X,Y) #define readb_uint16(X,Y) read_uint16_swapped(X,Y) #define writel_int32(X,Y) write_int32(X,Y) #define writel_int16(X,Y) write_int16(X,Y) #define writeb_int32(X,Y) write_int32_swapped(X,Y) #define writeb_int16(X,Y) write_int16_swapped(X,Y) #else #ifdef BIG_ENDIAN #define MAGIC_HEADER 0x4d42524f #define readl_int32(X,Y) read_int32_swapped(X,Y) #define readl_int16(X,Y) read_int16_swapped(X,Y) #define readl_int16buffer(X,Y,Z) read_int16buffer_swapped(X,Y,Z) #define readl_uint16(X,Y) read_uint16_swapped(X,Y) #define readb_int32(X,Y) read_int32(X,Y) #define readb_int16(X,Y) read_int16(X,Y) #define readb_uint16(X,Y) read_uint16(X,Y) #define writel_int32(X,Y) write_int32_swapped(X,Y) #define writel_int16(X,Y) write_int16_swapped(X,Y) #define writeb_int32(X,Y) write_int32(X,Y) #define writeb_int16(X,Y) write_int16(X,Y) #else #error "You should define BIG_ENDIAN (sun,hp,next..) or LITTLE_ENDIAN (pc,vax)" #endif #endif /* * Read and write operations with/without byte swapping */ void write_int16(int16 value, FILE *output_file); void write_int32(int32 value, FILE *output_file); void write_int16_swapped(int16 value, FILE *output_file); void write_int32_swapped(int32 value, FILE *output_file); void read_int16(int16 *value, FILE *output_file); size_t read_int16buffer(int16 *ptr, size_t nitems, FILE *stream); void read_uint16(uint16 *value, FILE *output_file); void read_int32(int32 *value, FILE *output_file); void read_int16_swapped(int16 *value, FILE *output_file); size_t read_int16buffer_swapped(int16 *ptr, size_t nitems, FILE *stream); void read_uint16_swapped(uint16 *value, FILE *output_file); void read_int32_swapped(int32 *value, FILE *output_file); #endif mbrola-3.3+dfsg/Database/rom_database.c000066400000000000000000000244461364272575600200760ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: rom_database.c * Time-stamp: <01/09/26 16:32:17 mbrola> * Purpose: diphone database management (from ROM dumps) * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 24/03/00 : Created. * * 29/03/00 : Memory alignment issue ... On a SUN reading int32 * requires multiple of 4, int16 requires a multiple of 2... * Otherwise BUS error. Anyway alignment is good for everybody and * adds very little dummy chars. */ #include "rom_handling.h" #include "rom_database.h" #include "little_big.h" #ifdef BACON #include "database_bacon.h" #endif #ifdef CEBAB #include "database_cebab.h" #endif #ifdef ROMDATABASE_INIT /*********************************************** * ROM constructor depends on the database type ***********************************************/ /* Table of database constructors */ init_DatabaseFunction init_ROM_tab[ ]= { init_ROM_DatabaseBasic, /* type 0 , was DatabaseOld -> exactly the same as RAW dba */ init_ROM_DatabaseBasic, /* type 1 */ #ifdef BACON init_ROM_DatabaseBacon, /* type 2 */ #else init_ROM_DatabaseBasic, #endif #ifdef CEBAB init_ROM_DatabaseCebab, /* type 3 */ #else init_ROM_DatabaseBasic, #endif }; #define NB_ROM_DATABASE_TYPE (sizeof(init_ROM_tab)/sizeof(init_DatabaseFunction)) #endif /* ROMDATABASE_INIT */ #ifdef ROMDATABASE_STORE /************************************************************* * Storing method of a ROM image depends on the database type *************************************************************/ /* Table of database constructors */ typedef void (*file_flush_ROM_DatabaseFunction)(Database* dba, FILE* rom_file); file_flush_ROM_DatabaseFunction file_flush_ROM_tab[ ]= { file_flush_ROM_DatabaseBasic, /* type 0 , was DatabaseOld */ file_flush_ROM_DatabaseBasic, /* type 1 */ #ifdef BACON file_flush_ROM_DatabaseBacon, /* type 2 */ #else file_flush_ROM_DatabaseBasic, #endif #ifdef CEBAB file_flush_ROM_DatabaseCebab, /* type 3 */ #else file_flush_ROM_DatabaseBasic, #endif }; void file_flush_ROM_header(Database* dba, FILE* rom_file) /* * Dump the core of a database structure into a ROM image * This part is generally common, whatever encoding method */ { int32 round_size; /* Rest of the header */ file_flush_ROM_uint8( MBRPeriod(dba), rom_file); /* Then magically, we're aligned on 32 ! */ file_flush_ROM_align32(rom_file); /* ... but sanity anyway */ file_flush_ROM_int16( Freq(dba), rom_file); file_flush_ROM_int16( nb_diphone(dba), rom_file); file_flush_ROM_int32( SizeMrk(dba), rom_file); file_flush_ROM_int32( SizeRaw(dba), rom_file); file_flush_ROM_int32( RawOffset(dba), rom_file); /* The diphone hash table (auto-align) */ file_flush_ROM_HashTab( diphone_table(dba), rom_file); /* Database information */ file_flush_ROM_ZStringList( info(dba), rom_file); /* * The rest is not aligned but we dont't care */ /* pitch marks */ round_size= (SizeMrk(dba)+3)/4; /* round to upper value */ file_flush_ROM_array( pmrk(dba), sizeof(FrameType), round_size, rom_file); file_flush_ROM_uint8( max_frame(dba), rom_file); /* Silence phoneme */ file_flush_ROM_Zstring( sil_phon(dba), rom_file); } void file_flush_ROM_DatabaseBasic(Database* dba, FILE* rom_file) /* Nothing much to do with a RAW database */ { long pos_read; /* The common part */ file_flush_ROM_header(dba, rom_file); /* Align with the forthcoming samples */ file_flush_ROM_align16(rom_file); /* Read and write the whole WAVE chunk */ fseek(database(dba), RawOffset(dba), SEEK_SET); pos_read= RawOffset(dba); while ( (!feof(database(dba))) && (pos_read < RawOffset(dba)+SizeRaw(dba))) { int16 buffer[255]; /* Respect endianness when reading codebook indexes */ int nb_read= readl_int16buffer( buffer, 255, database(dba)); fwrite(buffer, sizeof(int16), nb_read, rom_file); pos_read+=nb_read; } } void file_flush_ROM_Database(Database* dba, char* out_name) /* Dump the database structure into a ROM image */ { FILE* rom_file= fopen(out_name, "wb"); if (rom_file==NULL) { fatal_message(ERROR_DBNOTFOUND,"FATAL ERROR : cannot save to file %s !\n",out_name); } /* The name of the database... useless, only kept for information purpose */ file_flush_ROM_Zstring( dbaname(dba), rom_file); /* Write "MBROLA" "2.069" */ file_flush_ROM_align32(rom_file); file_flush_ROM_array( Magic(dba), sizeof(int32), 2, rom_file); file_flush_ROM_array( Version(dba), sizeof(char), 6, rom_file); /* The database code name include a ROM tag */ file_flush_ROM_uint8( Coding(dba) | ROM_MASK , rom_file); file_flush_ROM_tab[ Coding(dba) ](dba, rom_file); fclose(rom_file); } #endif /* ROMDATABASE_STORE */ #ifdef ROMDATABASE_INIT void close_ROM_DatabaseBasic(Database* dba) /* * Nothing much to desallocate or close when you're in ROM */ { /* fewer desalloc in Database Information */ if ( info(dba) ) close_ROM_ZStringList( info(dba) ); /* close upper structures of the hash table */ if (diphone_table(dba)) close_ROM_HashTab( diphone_table(dba) ); /* No pitch marks, no file, no silence phoneme */ /* The structure itself */ MBR_free(dba); } void init_ROM_header(Database* my_dba) /* Collective function for different coding types */ { int32 round_size; void* input_ptr= rom_wave_ptr(my_dba); input_ptr= read_ROM_uint8( &MBRPeriod(my_dba), input_ptr); /* Then magically, we're aligned on 32 ! */ ptr_ROM_align32(input_ptr); /* sanity */ input_ptr= read_ROM_int16( &Freq(my_dba), input_ptr); input_ptr= read_ROM_int16( &nb_diphone(my_dba), input_ptr); input_ptr= read_ROM_int32( &SizeMrk(my_dba), input_ptr); input_ptr= read_ROM_int32( &SizeRaw(my_dba), input_ptr); input_ptr= read_ROM_int32( &RawOffset(my_dba), input_ptr); /* The diphone hash table (autoalign) */ diphone_table(my_dba)= init_ROM_HashTab( &input_ptr); /* Database information */ info(my_dba)= init_ROM_ZStringList( &input_ptr ); /* * The rest is not aligned but we dont't care */ /* Compressed pitch marks (2bits/mark) */ round_size= (SizeMrk(my_dba)+3)/4; /* round to upper value */ input_ptr= read_ROM_array( (void*) &pmrk(my_dba), sizeof(FrameType), round_size, input_ptr); input_ptr= read_ROM_uint8( &max_frame(my_dba), input_ptr); /* Silence phoneme */ input_ptr= read_ROM_Zstring(& sil_phon(my_dba), input_ptr); /* Pointer to the start of the waves in ROM */ rom_wave_ptr(my_dba)= input_ptr; /* Size of the buffer that will be allocated in Diphonesynthesis */ max_samples(my_dba)= MBRPeriod(my_dba) * max_frame(my_dba); } Database* init_ROM_DatabaseBasic(Database* dba) /* * Basic version, simply init a pointer on wave forms = Check there's no coding * Returning NULL means error */ { debug_message1("init_ROM_DatabaseBasic\n"); /* init virtuals */ dba->getdiphone_Database= getdiphone_DatabaseBasic; dba->close_Database= close_ROM_DatabaseBasic; /* A basic dba contains RAW waveforms */ if ( (Coding(dba) & (ROM_MASK-1)) != DIPHONE_RAW ) { dba->close_Database(dba); fatal_message( ERROR_BINNUMBERFORMAT, "PANIC: This program can't decode your database %i\n",Coding(dba)); return NULL; } init_ROM_header(dba); /* * Size of the buffer that will be allocated in Diphonesynthesis * is null as ROM_DatabaseBasic returns pointer on buffers in ROM */ max_samples(dba)= 0; /* Align for INT16 audio samples */ ptr_ROM_align16( rom_wave_ptr(dba) ); debug_message1("done init_ROM_DatabaseBasic\n"); return(dba); } Database* init_ROM_Database(void* input_ptr) /* * Initialize a database from a ROM image * Returning NULL means fatal error (check LastErr) */ { int i; Database* my_dba; debug_message1("init_ROM_Database\n"); my_dba= (Database*) MBR_malloc(sizeof(Database)); my_dba->database= NULL; sil_phon(my_dba)= NULL; info(my_dba)= NULL; max_frame(my_dba)= 0; pmrk(my_dba)= NULL; diphone_table(my_dba)= NULL; /* will be changed later on, depending on the dba type, it's here for premature exists */ my_dba->close_Database= close_ROM_DatabaseBasic; /* The name of the database... useless, only kept for information purpose */ input_ptr= read_ROM_Zstring( &dbaname(my_dba), input_ptr); /* Read "MBROLA" */ ptr_ROM_align32(input_ptr); input_ptr= read_ROM_int32( &Magic(my_dba)[0], input_ptr); input_ptr= read_ROM_int32( &Magic(my_dba)[1], input_ptr); if ( (strncmp("MBROLA",(char *)Magic(my_dba),6)) || (Magic(my_dba)[0] != MAGIC_HEADER)) { fatal_message(ERROR_DBWRONGVERSION, "PANIC: Binary number format error\n" "You are probably using a version of %s incompatible\n" "with your machine architecture.\n" ,dbaname(my_dba)); return NULL; } /* Read version number "2.01" */ for(i=0;i<6;i++) input_ptr= read_ROM_uint8( (uint8*) &(Version(my_dba)[i]), input_ptr); if (strcmp(Version(my_dba),SYNTH_VERSION)>0) { fatal_message(ERROR_DBWRONGARCHITECTURE, "PANIC: Can't cope with databases coming from the future\n"); return NULL; } input_ptr= read_ROM_uint8( &Coding(my_dba), input_ptr); /* Remove ROM bit and check we have the decoder */ if ( (Coding(my_dba)& (ROM_MASK-1)) > NB_ROM_DATABASE_TYPE ) { my_dba->close_Database(my_dba); fatal_message( ERROR_BINNUMBERFORMAT, "PANIC: This program can't decode your database code %i\n", Coding(my_dba)); return NULL; } debug_message1("virtual init_ROM_Database\n"); /* Yes it is that simple !! Watch your step */ rom_wave_ptr(my_dba)=input_ptr; return init_ROM_tab[ Coding(my_dba)& (ROM_MASK-1) ](my_dba); } #endif mbrola-3.3+dfsg/Database/rom_database.h000066400000000000000000000043411364272575600200730ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: rom_database.h * Time-stamp: <00/03/29 23:57:41 pagel> * Purpose: diphone database management (from ROM dumps) * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 24/03/00 : Created. * * 29/03/00 : Memory alignment issue ... On a SUN reading int32 * requires multiple of 4, int16 requires a multiple of 2... * Otherwise BUS error. Anyway alignment is good for everybody and * adds very little dummy chars. */ #ifndef _ROM_DATABASE_H #define _ROM_DATABASE_H #include "database.h" #ifdef ROMDATABASE_STORE void file_flush_ROM_Database(Database* dba, char* out_name); /* Dump the database structure into a ROM image */ void file_flush_ROM_header(Database* dba, FILE* rom_file); /* * Dump the core of a database structure into a ROM image * This part is generally common, whatever encoding method */ void file_flush_ROM_DatabaseBasic(Database* dba, FILE* rom_file); /* Nothing much to do with a RAW database */ #endif #ifdef ROMDATABASE_INIT void close_ROM_DatabaseBasic(Database* dba); /* * Nothing much to desallocate or close when you're in ROM */ void init_ROM_header(Database* my_dba); /* Collective function for different coding types */ Database* init_ROM_DatabaseBasic(Database* dba); /* * Basic version, simply init a pointer on wave forms = Check there's no coding * Returning NULL means error */ Database* init_ROM_Database(void* input_ptr); /* * Initialize a database from a ROM image (polymorphic result) */ #endif #endif mbrola-3.3+dfsg/Database/rom_handling.c000066400000000000000000000075151364272575600201140ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: rom_handling.c * Time-stamp: <00/03/29 22:56:46 pagel> * Purpose: basic initialization from ROM * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 23/03/00 : Created. */ #include "rom_handling.h" #ifdef ROMDATABASE_INIT void* read_ROM_uint8(uint8* val, void* input_ptr) /* initialize val from input_ptr, return next position */ { *val= * ((uint8 *) input_ptr); return (void*) ((size_t)input_ptr + sizeof(uint8)); } void* read_ROM_int16(int16* val, void* input_ptr) /* initialize val from input_ptr, return next position */ { *val= * ((int16 *) input_ptr); return (void*) ((size_t) input_ptr + sizeof(int16)); } void* read_ROM_int32( int32* val, void* input_ptr ) /* initialize val from input_ptr, return next position */ { *val= *((int32 *) input_ptr); return (void*) ((size_t)input_ptr + sizeof(int32)); } void* read_ROM_array(void** any, int size_item, int nb_item, void* input_ptr ) /* * initialize an array containing elements of size 'size_elements' * from a ROM image starting at input_ptr */ { *any= input_ptr; return (void*) ((size_t)input_ptr + size_item*nb_item); } void* read_ROM_Zstring(char** val, void* input_ptr) /* initialize val from input_ptr, return next position */ { char* zstring= (char*) input_ptr; *val= zstring; while ( *zstring != (char) 0 ) zstring++; /* next one */ zstring++; return (void*) zstring; } #endif /* ROMDATABASE_INIT */ /*********************************************************** * Serie of functions used to flush a memory image to a file * for later ROM usage ***********************************************************/ #ifdef ROMDATABASE_STORE void file_flush_ROM_uint8(uint8 val, FILE* output) /* initialize val from input_ptr, return next position */ { fwrite( &val, sizeof(uint8), 1, output); } void file_flush_ROM_int16(int16 val, FILE* output) /* initialize val from input_ptr, return next position */ { fwrite( &val, sizeof(int16), 1, output); } void file_flush_ROM_int32(int32 val, FILE* output) /* initialize val from input_ptr, return next position */ { fwrite( &val, sizeof(int32), 1, output); } void file_flush_ROM_array(void* any, int size_item, int nb_item, FILE* output) /* initialize an array containing elements of size 'size_elements' * from a ROM image starting at input_ptr */ { fwrite(any, size_item, nb_item, output); } void file_flush_ROM_Zstring(char* val, FILE* output) /* initialize val from input_ptr, return next position */ { fprintf(output,"%s",val); fputc(0,output); } /************************************************* * Those functions align ROM file dumps on multiple of 2 (int16) or of 4 (int32) * -> compulsory for to avoid BUS_SIG some processors * -> access more efficient for other CPU */ void file_flush_ROM_align16(FILE*output) { long file_pos= ftell(output); /* Odd position */ if ( file_pos & 0x1 ) fputc( 0x00, output); } void file_flush_ROM_align32(FILE*output) { long file_pos= ftell(output); int i= (4 - (file_pos & 0x3))%4; /* Not a multiple of 4 -> dummy fillers */ while (i--) fputc( 0x00, output); } #endif /* ROMDATABASE_STORE */ mbrola-3.3+dfsg/Database/rom_handling.h000066400000000000000000000071021364272575600201110ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: rom_handling.h * Time-stamp: <2000-03-29 22:08:40 pagel> * Purpose: basic initialization from ROM * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 23/03/00 : Created. */ #ifndef ROM_HANDLING_H #define ROM_HANDLING_H #include "common.h" /*********************************************************** * Serie of functions used to retrieve values from a ROM image * for ROM database initialization ***********************************************************/ #ifdef ROMDATABASE_INIT void* read_ROM_uint8(uint8* val, void* input_ptr); /* initialize val from input_ptr, return next position */ void* read_ROM_int16(int16* val, void* input_ptr); /* initialize val from input_ptr, return next position */ void* read_ROM_int32(int32* val, void* input_ptr); /* initialize val from input_ptr, return next position */ void* read_ROM_array(void** any, int size_item, int nb_item, void* input_ptr); /* initialize an array containing elements of size 'size_elements' * from a ROM image starting at input_ptr */ void* read_ROM_Zstring(char** val, void* input_ptr); /* initialize val from input_ptr, return next position */ /********************************* * Those macros align pointers on multiple of 2 (int16) or of 4 (int32) * -> compulsory for to avoid BUS_SIG some processors * -> access more efficient for other CPU */ #define ptr_ROM_align(X,ROUND) {X= (void*) ((((size_t) X)+ROUND-1) & ~(ROUND-1));} #define ptr_ROM_align16(X) ptr_ROM_align(X,2) #define ptr_ROM_align32(X) ptr_ROM_align(X,4) #endif /* ROMDATABASE_INIT */ /*********************************************************** * Serie of functions used to flush a memory image to a file * for later ROM usage ***********************************************************/ /* Don't use macro to allow type checking :-> */ #ifdef ROMDATABASE_STORE void file_flush_ROM_uint8(uint8 val, FILE* output); /* initialize val from input_ptr, return next position */ void file_flush_ROM_int16(int16 val, FILE* output); /* initialize val from input_ptr, return next position */ void file_flush_ROM_int32(int32 val, FILE* output); /* initialize val from input_ptr, return next position */ void file_flush_ROM_array(void* any, int size_item, int nb_item, FILE* output); /* initialize an array containing elements of size 'size_elements' * from a ROM image starting at input_ptr */ void file_flush_ROM_Zstring(char* val, FILE* output); /* initialize val from input_ptr, return next position */ /************************************************* * Those functions align ROM file dumps on multiple of 2 (int16) or of 4 (int32) * -> compulsory for to avoid BUS_SIG some processors * -> access more efficient for other CPU */ void file_flush_ROM_align16(FILE*output); void file_flush_ROM_align32(FILE*output); #endif /* ROMDATABASE_STORE */ #endif /* ROM_HANLDING_H */ mbrola-3.3+dfsg/Database/zstring_list.c000066400000000000000000000144031364272575600202000ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: zstring_list.c * Purpose: list of zstring (can be used for renaming phoneme pairs) * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <01/09/26 16:51:08 mbrola> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/08/98 : Created as rename_list * 9/09/98 : leak in close_RenameList * 20/03/00 : Can be used for list of phonemes as well (phoneme encoding) * Adds support to ROM dump and initialization * 26/9/01 : the type of PhonemeCode was really too small */ #include #include "zstring_list.h" #include "mbralloc.h" #include "vp_error.h" #if defined(ROMDATABASE_STORE) || defined(ROMDATABASE_INIT) #include "rom_handling.h" #endif ZStringList* init_ZStringList() /* Basic constructor, initialize to empty list */ { ZStringList* my_zl= (ZStringList*) MBR_malloc(sizeof(ZStringList)); nb_elem(my_zl)=0; nb_available(my_zl)= PACKET_ALLOCATION; /* must be EVEN */ zlist(my_zl)= (PhonemeName *) MBR_malloc( sizeof(PhonemeName) * nb_available(my_zl)); return my_zl; } void close_ZStringList(ZStringList* zl) /* Release the memory */ { int i; for(i=0; i= nb_available(zl)) { /* sanity check */ if (nb_available(zl)+PACKET_ALLOCATION > MAX_PHONEME_NUMBER) { fatal_message(ERROR_TOOMANYPHONEMES,"Too many phonemes in the dba %i!\n",nb_elem(zl)); } nb_available(zl)+= PACKET_ALLOCATION; zlist(zl)= (PhonemeName*) MBR_realloc( zlist(zl), sizeof(PhonemeName) * nb_available(zl) ); } code= nb_elem(zl); zlist(zl)[ nb_elem(zl)++ ]= MBR_strdup(str); return code; } PhonemeCode encode_ZStringList(ZStringList* zl, PhonemeName str) /* finds the translation of 'str' (if not available add a new code) */ { PhonemeCode code= find_ZStringList(zl,str); if (code == PHONEME_FAIL) { code= append_ZStringList(zl, str); } return code; } PhonemeName decode_ZStringList(ZStringList* zl, PhonemeCode code) /* back to the string from the code, the compiler should expand it as a macro */ { return( zlist(zl)[code] ); } /********************************** * DEDICATED TO PHONEME RENAMING **********************************/ bool append_rename_ZStringList(ZStringList* zl, PhonemeName old_name, PhonemeName new_name, bool multi) /* Add a new renaming pair to the list * If multi is True, it's a multiset * * Return False if the key was allready present (if it's not multiset) */ { PhonemeName renamed; if ( (!multi) && ((renamed=find_rename_ZStringList(zl,old_name)) != NULL)) { warning_message(ERROR_RENAMING, "Can't map %s to %s. Already mapped to %s\n", old_name, new_name, renamed); return False; } append_ZStringList(zl, old_name); append_ZStringList(zl, new_name); return True; } bool parse_ZStringList(ZStringList* my_zl, PhonemeName rename_string, bool multi) /* * Parsing the renaming pairs from a string * Returning False means wrong initializer (check LastErr) * * multi= True means multiset. If False, introducing a renaming pair with * the same key is an error (returns False) */ { PhonemeName name1; PhonemeName name2; name1= strtok( rename_string, " \n"); name2= strtok( NULL, " \n"); while ( (name1!= NULL) && (name2!= NULL)) { if (! append_rename_ZStringList(my_zl,name1,name2,multi)) return False; /* fatal with append */ name1= strtok(NULL, " \n"); name2= strtok(NULL, " \n"); } if (name1 != NULL) { warning_message(ERROR_RENAMING,"Wrong renaming list at %s\n",name1); return False; } return True; } PhonemeName find_rename_ZStringList(ZStringList* zl, PhonemeName name) /* * find the name in the table and return its translation * or return NULL */ { int i; for(i=0; i * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/08/98 : Created as rename_list * 9/09/98 : leak in close_RenameList * 20/03/00 : Can be used for list of phonemes as well (phoneme encoding) * Adds support to ROM dump and initialization */ #ifndef _ZSTRING_LIST_H #define _ZSTRING_LIST_H #include "common.h" typedef struct { uint16 nb_elem; uint16 nb_available; PhonemeName* zlist; } ZStringList; #define nb_elem(zl) (zl->nb_elem) #define nb_available(zl) (zl->nb_available) #define zlist(zl) (zl->zlist) /* To avoid too much realloc when growing the list, allocate by packets. This number should be even for renaming pairs */ #define PACKET_ALLOCATION 6 /* Return code when research fails */ #define PHONEME_FAIL ((PhonemeCode) -1 ) ZStringList* init_ZStringList(); /* Basic constructor, initialize to empty list */ void close_ZStringList(ZStringList* zl); /* Release the memory */ PhonemeCode append_ZStringList(ZStringList* zl, PhonemeName str); /* Add a new string a returns its code */ PhonemeCode encode_ZStringList(ZStringList* zl, PhonemeName str); /* finds the translation of 'str' (if not available add a new code) */ PhonemeName decode_ZStringList(ZStringList* zl, PhonemeCode code); /* back to the string from the code, the compiler should expand it as a macro */ int size_ZStringList(ZStringList* zl); /* return the size of the renaming list */ /********************************** * DEDICATED TO PHONEME RENAMING **********************************/ bool append_rename_ZStringList(ZStringList* zl, PhonemeName old_name, PhonemeName new_name, bool multi); /* Add a new renaming pair to the list * If multi is True, it's a multiset * * Return False if the key was allready present (if it's not multiset) */ bool parse_ZStringList(ZStringList* my_zl, PhonemeName rename_string, bool multi); /* * Parsing the renaming pairs from a string * Returning False means wrong initializer (check LastErr) * * multi= True means multiset. If False, introducing a renaming pair with * the same key is an error (returns False) */ PhonemeName find_rename_ZStringList(ZStringList* zl, PhonemeName str); /* finds the translation of 'str'. returns PHONEME_FAIL if not found */ #ifdef ROMDATABASE_STORE void file_flush_ROM_ZStringList(ZStringList* zl, FILE* rom_file); /* Dump the hash table in a ROM image */ #endif #ifdef ROMDATABASE_INIT ZStringList* init_ROM_ZStringList(void** input_ptr); /* * Initialize the hash table from a ROM image */ void close_ROM_ZStringList(ZStringList* zl); /* * Close the ROM image (fewer mallocs than in the regular one) */ #endif #endif mbrola-3.3+dfsg/Documentation/000077500000000000000000000000001364272575600164045ustar00rootroot00000000000000mbrola-3.3+dfsg/Documentation/HISTORY.txt000066400000000000000000000562171364272575600203210ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: HISTORY.txt * Purpose: History of the Mbrola Speech Synthesizer * Authors: Mbrola Team * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculté Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * HISTORY: * * 15/06/95 : created * * 26/06/95 : modified and adapted to Sun by V. Pagel * * 08/08/95 : checked for PC/DOS and modified accordingly * dummy chars in database struct; fopen("t or b"); prototypes * * 22/08/95 : correction of OLA : energy correction only applies to frame * * 05/09/95 : pagelization of the style ! thank you, Vince. * * 11/09/95 : fixed a bug in intermediate pitch interpolation (Curtime increment) * fixed a bug in last sound flushing (put a silence) * fixed a bug in Concat -> need the number of 1st ola frame * for cur_diph * * 13/09/95 : No pitch modification on NV frames. * * 14/09/95 : Added ';' for comments in command file, and # for flushing * fixed horrible bug with non weigthed smoothing window * * 18/09/95 : fixed bug in Concat : validity test for begin and end. * * 19/09/95 : length1 and length2 in samples instead of millisec * Add time_crumbs mechanism to balance slow drifting in * phoneme durations -> keeps total duration close to original * * 12/10/95 : Free copy and use for non commercial apps. V1.00 * Dummy instructions added for protection of rights. * 20 pitchpatternpoints, 1000 synthesis OLA frames per phoneme (10 sec) * Max 250 successive phonemes with no prosodic info (25sec) * * 13/10/95 : 1.0a optimization in OLA ( previously wrote sample by sample) * * 16/10/95 : DEBUG defined; fixed stupid bug in Initialize. * * 18/10/95 : 1.0c now accepts database location as command line parameter. * * 24/10/95 : 1.01 One and only one data file per voice/language * * 06/11/95 : GetPitch if V (previously also if NV_TRA) * A lot of new debug info (DEBUG2) * Hamming weighting window (was triangle) * Check next (original) diphone for concatenation length * VREG VREG... VREG VTRA => VTRA smoothed, too * F0 limits=f(database) * Added cur_diph->d.RightPhone = PhoneTable[0]; after call to * FillCommandBuffer ! * Correction of diphone length=f(really synthesized data) * Lenanal in MatchProsody : nb_frames*MBRPeriod (was nb_frames+1) * Magic checking of database format * 1.02 : TimeRatio and FreqRatio * * 10/11/95 : 1.02a Last bug with Lenanal and nb_frames*MBRPeriod * Replace RealLastSample with last_time_crumb to avoid * sample counter overflow. * Architecture panic test. * * 21/02/96 : 1.03a DEBUG3 added for compatibility with the BACON coded database * Many output audio file formats added ( RIFFwav, au, aiff, raw ) * Now skips empty lines (caused bugs on PC when file ends with CR) * * 22/02/96 : 1.03b Get rid of little endian or big endian databases thanks * to BIG_ENDIAN or LITTLE_ENDIAN -> we choose to keep the FR1-PC * database to give a little advantage to powerless PCs !!! * * 27/02/96 : 1.03c Reintroduce changes made in lost branch 1.02b * It concerns the "odd" variable to reverse one unvoiced frame out * of 2 to avoid the perception of a 133Hz signal in unvoiced phones * * Concat : limitframe cheks for real phoneme border within diphone * * 28/02/96 : 1.04a Ad hoc order 2 BACON DECODER included in a separate file * -> load_diphone function... This required to read each diphone * once, i.e. fusion of access (Concat & MBRola) through buffer * which is now a field of Diphone_Synth * LoadDiphone is now a pointer to Basic_LoadDiphone or to * Bacon_LoadDiphone depending on the Coding scheme * * DEBUG3 is out for the moment ! * * 29/02/96 : 1.04b THE BIG SPLITTING -> the whole thing in now spreaded in * many files to increase readability. * Make thing ready for hash tables !!!! * * 01/03/96 : 1.04c Smart acces to the diphone reference ( hash tables ) * instead of sequential search -> we get an average 1.595506 * strncmp by diphone search !!!!! (still better than 600) * -> the Diphone base structure was modified to add linked list * mechanism of hash table, I used the old "int8 dummy[3]" * space for this ! * * 04/03/96 : 1.04d synth1 and synth2 become pointers cause PCs don't have * enough space in data segment ( 64Ko ). * HBK = Horrible Bug Killing in Concat -> when the left diphone * is _-_ last_frame is negative * Bug in hash_table -> introduce EMPTY=-1 and NONE=255 * Can now use uppercase and lowercase symbols for phones -> correct * a bug in LowerCase which did not add trailing 0 * * 14/03/96 : 2.00a The name of the whole project is changed in MBROLA to * avoid confusion with CNET's Psola-td * * 18/03/96 : 2.00b string.h is now in common.h to compile on Linux, a bug with * (* char) Magic which is not aligned on a 4* address * * 28/03/96 : 2.00b -> Cancel the 1.04d modif to read uppercase and lower * case phones, as we now use SAMPA alphabet, and the case of * the symbol is discriminant * * 13/05/96 : 2.00c Better coder in database_bacon.c * * 07/06/96 : 2.00d Panic Checking for _-_ diphone in the database * Add a mechanism to change Time and frequency ratios in the .pho * file ( comment line beginning with T=0.8 or F=1.2 ) * Filenames were shortened to 8 char for MSDOP :-\ * Another MSDOP checking for empty lines -> if we listen to the * Borland C Scanf, an empty line has one char: the carriage return! * * 25/06/96 : 2.01a HBK with interp_length which caused core dumps or * clics in the signal (negative frequency shift !) * FIRST_PITCH becomes First_Pitch which account for MBRPeriod of * the diphone database. * * 04/07/96 : 2.01b Eliminate some dumb smoothing attempt for unvoiced frames, * in the ola routine. In Concat eliminate useless smoothw computed * on unvoiced frames -> Faster and more secure * * 16/07/96 : 2.01c Complete repackaging of the tables constants -> more * sensible values, and and tests to check we're not out of the * limits. * * 31/07/96 : 2.01d Introduce automatic detection of little endian with * __i386__ , fflush with # symbol, sample rate is writen in the * audio file header (except for AIFF for the moment due to 80bit * IEEE representation) * * 12/09/96 : 2.01e Check for saturation when we make the conversion to * integers. * * Correct a typo with smooth() and smoothw(), no related bug. * * Get rid of the pitch limitation (No /2 or *2 limits) * -> this implied a special case for extra low pitch (more than * div 2 with 0 filling of the output. More rational memove as * well as ola bufer sizes!!! * * F0 and POS become float (more precisions for F0 since new limits * allow singing and that it requires a more precise pitch * * 18/09/96 : 2.02a Change the format of the database.... Skim a few bytes * from place to place in the header -> 16 bytes become 8 byte in * the diphone structure. V/UV decisions becomes a bitstream * * 26/09/96 : 2.02b Because the german database is huge (12Mo) and its pitch * is high (200Hz), there's an overflow on pos_pm signed short * A temporary fix before I imagine something better consist in * declaring uint16 (unsigned int16) for pitch mark referencing * * 05/12/96 : 2.02c Typechecking for unsigned int lead to a separated * function readl_uint16 -> more compatibility with compilers * * VolumeRatio is now a new parameter in the command line * * Coding scheme compatible with 2.02b in database_bacon (split * the old InitDatabase into 3 functions for modularity * * 12/12/96 : 2.02d * Pack what concern phonemes in readpho.c * Pack what concern mbrola synthesis itself in mbrola.c * Synth.c contain a main program for standalone compilation * Library.c contains Read/Write functions in a DLL like style * * Modify the behavior of NextDiphone so that it adds trailing silence * when EOF or when Flush. It implies there is no special case for last * diphone synthesis. It is used in library.c, a Read/Write approach to * mbrola synthesizer -> many variables of mbrola.c where defined global * for the purpose of externaly control the process * * 29/01/97: 2.03a * Diphone names can be longer than 2 characters (it's now a Zstring). To * avoid a new diphone database format (the current one explicitely limits the * size to 2 chars) we introduce the RENAME command which allows to * dynamically rename a phoneme into another. This scheme may also be used to * transform a non SAMPA alphabet into mbrola compatible version. * * To do so we have parametrized the functions of the hash_table type, and * added a 'dirty' flag, as RENAMING implies "delete" and "add" -> of course * with coalescent hashing the performance would dramatically drop if we * indivually modify the phonemes, thus after a renaming session, we * completely compute the hash_table again. * * 02/02/97: 2.03b * database.c has been modified by Thierry Dutoit to allow diphone duplication * without changing the format of our database -> diphone duplications are * indicated at the end of the Main Index (detected when the Pitchmark * position reach the end of the pitchmark table). For example the diphone * a-ch can be easily declared as a-t. * * readpho.c modified to allow pitchpairs surrounded by ()s * * We try to include a standard VisualC++ make file directory * * 6/02/97 : 2.03c * * synth.c : since the order on the command line has been changed, many * people unintentionally destroy their .pho files writing the wav on it. * -> we go back to the older format "mbrola dba file_in* file_out" * * diphone.h : maximum diphone size is raised from 8000 samples to 10000 * because of the german database * readpho.c : %2s is removed since now phoneme names can be longer than 2 * chars * a_line is too short to allow MAXNPITCHPATTERNPOINTS in it ! * Allocate 4 char instead of 3 for Silence and Flush (alastair Sinton) * Tweaking with EOF and FLUSH in case of library compilation mode * * library.c : include defines for the Windows DLL * * hash_tab.c : after a renaming, must update cur_diph and prev_diph * reference in the hash_tab * * 20/02/97: 2.03d Put a clear difference between comment and commands in * pho files. Comment= ; Command= ;; * * 26/03/97: 2.03e Sanity check when replacing diphones * -> check the target of the replacement exist * * 29/05/97: 2.03f Pseudo C++ to benefit from the Catch/Throw mechanism in the * DLL and LIBRARY version. * * Changes the behavior of readpho -> we wait for a pitch point to * treat the lines... It's a tradeoff: either we don't alow this, * then we can't warranty that asynchronious read/write will respect * the right pitch curve, either we behave this way, and a pitch * point is COMPULSORY before any sound breaks out. * * Use fake C++ lists -> the big jump to STL is planned for 2.04 * * Gives a politically correct memory freeing scheme (prepare for C++ * and satisfy PC users !). * * 02/07/97: 2.04a New approach to get the last diphone (supposedly _-_) of * the dba. * * Error.{cpp,h} become vp_error because of name conflict on Visual * not such a clever thing to use "test" "error" "windows" names :-) * * In Readpho.cpp correct a strange bug with PitchFactor ! * * No jump to STL lists for the moment (no time) * * Pitchmarks now use 32 bit, thanks to the database from French * Britany -> hack in the database header to keep compatibility with * previous databases. * * 15/07/97: 2.04b A. Ruelle changes the windows DLL interface to Winapi * calling standard and adds Last_MBR_Error2 for Visual Basic. * Vincent Pagel: a bug with circular buffer and "unsigned int" in * library.cpp * readpho.cpp -> EOF/FLUSH management in the DLL/LIBRARY version * (eof means wait for new data to be available). In the standalone * version EOF on a regular file means add a trailing _ and exit. * * 21/08/97: 2.04c in ReadDatabasePitchmark, unsigned int for Borland C++ * * database_bacon was not in accordance with database concerning * replacement diphones (changed in 2.04a) * * 07/10/97: 2.05a New database format :-) the limitation of 2 chars per * phoneme is too hard to cope with -> * database_bacon.cpp, database.h and database.cpp changed * * reapho.cpp: Target frequency to get cartoon voices as proposed by * Arthur Dirksen * * library.cpp: Add GetVersion_MBR for the DLL to be aware of the * release number of the synth, and getFreq_MBR for the client * to change the sampling rate of the soundcard properly with * voice characteristic modification * * readpho.cpp: new sanity check -> verify that the target of the copy * is not overriden. It unveils a bug in hash_search * * hash_tab.cpp: hash_search stupidly supposes that the primary hit is * never empty :-p * * * library.h: Alain Ruelle removes LastErrorStr2 * * 20/10/1997 : 2.05b For my 27th birthday, add database information at * the end of the dba in the form of Zstrings (phoneme set, copyright * informations) -> database.cpp * * synth.cpp : switch -i to get dba information * * library.h : Retrievable with getInfo_MBR * * common.h : freeNull -> bug ! The macro is not surrounded by {} * * mbrola.cpp: incredible bug in the smoothing algorithm... Can't * understand how it escaped unoticed for 2 years :-0 Maxnconcat * is limited to 6 frames (just the opposite in the previous one) * And we check we don't explore frames out of scope with nb_begin * and nb_end * * 05/11/97 2.05c : * make this version compatible with BACON coded databases :-) * * 01/12/97 2.05d : * New -e flag and E=ON | OFF directive to ignore missing diphones * * 05/12/97 2.06a : * Using a hamming window instead of a hanning window was such a bad * idea for the american english database. * * 21/01/98 2.06b : * Sort of database_display information in debug mode -> replace the * old dedicated program * Integration of the directory VisualDll for the compilation of a DLL * under Microsoft Visual C++ 5.0 * * Most of all a full documentation now included in the DOCUMENTATION * directory, and more comments in the code * * 02/02/98 2.06c : * readtype_MBR function to directly read audio data in LIN16, MULAW * and other convenient formats. Internally we keep floats for the * moment to represent the ola buffer. * * 25/02/98 3.00a : * database_cebab.cpp : A new database type DIPHONE_CEBAB compressed * for Internet users. * database.cpp: A lot of cleaning in the list of available dba formats * only 2.05 or later are compatible * * 24/06/98 3.01a : alpha release. Mbrola has drifted toward object * oriented style (constructor, destructor and a "this" pointer for * each function). As a consequence one can instanciate as many * synthesis channel (Mbrola object) as he wishes with one or more * database. It uses polymorphism to implement the diversity of * connections with Diphone Databases (Database object), and with the * provider of Phonemes (Parser object). Polymorphism implies * indirections tables to find the right method. * * Main Objects: * * Parser -> phoneme provider ( init, reset, close, nextphone ) * Database -> a diphone database ( init, reset, close, getdiphone) * Mbrola -> it's a synthesizer engine that runs with Database and * Parser * * As usually 2 modes to use Mbrola: * * 1) Standalone (an exe file that takes a .pho and produces a * .wav, the main iteration takes place on input) * * 2) Library or DLL version, where the main iteration takes place * on audio output buffers, at the cost of a small system overhead * * The library has 2 mode: MULTICHANNEL, and MONOCHANNEL. The second * is here for the sake of compatibility with previous mbrola DLLs, it * instanciate a DLL able to build one Mbrola object with one * Database. The first category on the other hand is able to build as * many Mbrola, with as many Databases and Parser as you wish. * * Of course those modification imply a complete revamping of all the * sources. The main changes are in readpho.cpp that has been splitted * into a Fifo and Parser object ( see the Parser directory ). It's * heavily based on abstract types: parser.h. IMPORTANT : the * instanciation of parser.h can be user defined (as long as it returns * Phone objects). * * 26/06/98 3.01b : the beta one. Database.cpp is now splitted into * databaseBasic (raw), databaseBacon (commercial scheme), * databaseCebab (WWW scheme), and quite important databaseOld which * is a rebirth of formats older than 2.05 (too many users complained * about compatibility loss in 3.00a) * * From a user's point of view, there is a change in the behavior of * FLUSH -> the size of the audio buffer is now precisely the one * requested (no need to include a dummy "_ 0" phoneme. Corrected a * bug on the limit of pitch point interpolations. * * Added a constellation of get*Mbrola set*Mbrola to change * parameters at runtime. * * Modify init_Mbrola slightly (don't give the parser from the start, * since it can be plugged and unplugged as one wish). * * This version is purified ! * * 01/08/98 3.01c : * All .cpp files become .c file, and compile with 'cc' * * Visual C++ DLL works again * Visual C++ Standalone project * * remove when possible #ifdef on BIG_ENDIAN -> * introduce readl_int16buffer ( little_big.cpp ) * * move the 2 iterations ( LIBRARY and STANDALONE ) into mbrola.cpp * * use of uint8 instead of int8 for unsigned operations * * the vocal tract ratio is plugged again * * Phoneme renaming and cloning mechanism * * 01/09/98 3.01d : * * make a clean package with all the 3.01c features. Demo1.c to * show the use of the one_channel mode, and demo2.c for the * multi-channel mode. * * 09/09/98 3.01e : The big deal * * A new make file allowing checking and purifying -> the "check" target * allows to compare a test set against previous standard output. * The panacea is "make PURE=purify check" to verify that no memory leak * was introduced. * * Replacement for C++ Catch/Throw. Database returns error code, as well * as the engine (no longjump because of multichannel mode -> would have * urged us to include a [env] structure in all our objects or as a parameter * to the different functions)... a return code is cheap compared to that. * * Forget old limitations with appendf0_Phone, can as many pitch points as * you feel like the PitchPoint table is resized * * (Nearly) forget old limitations with append_PhoneBuff, if there * are too many phonemes without pitch, we force a default * pitch. This is not really unkind as the limit is 250 phonemes. * * Solidify the code of destructors for premature exit in Database*, * DiphoneSynthesis and Mbrola * * Interface modified -> reset_MBR now returns True/False value * (since everybody now returns error code, got to catch it) * * Bug with fatal_message -> enlarge the buffer (too small for the largest * message) * * CODE IS PURIFIED (at last we have the license !). Memory leak corrected * on cloning. Unallocted free memory corrected with close_MBR and reset_MBR * by adding reset_DiphoneSynthesis * * Hopefully OneChannel mode is ready for WWW distrib as a DLL * * Provide DLL_USE for Visual C++ * * Write a "de la mort" documentation with Word97 * * 05/10/98 3.01f : add initSized_Phone to avoid multiple realloc on each * appendf0 (generally the number of pitch points is known from the start) * * 20/10/98 3.01g : Mainly for people using Festival, give the possibility * to move the command line parameters into an initialization file compatible * with .set files. Had to modify rename_list to allow the parsing of renaming * script (loose compatibility with previous ;;RENAME command), and to allow * initialization of Flush from the command line (init_PhoneBuffer). * * Correctly implement flush_MBR for people using renaming. * * 10/06/99 3.01h: * Wrong definition for signal handling * Return value of Bacon getdiphone_DatabaseFunction * Pb with Concat and 0ms phonemes on PC (division by 0) * Laurent Hubaut detects bug with zero_padding (non decremented) * Laurent Hubaut and Susanne Eismann detect bug with non zeroed ola_win * Remove all "exit" statements in the library version, except in MBRMALLOC * Default parser now add a 0ms silence before each silence to avoid spreading * of small noises in front of EXTRA long silences. * * 29/03/00 3.02a: FUNCTIONAL TEST IS NOT THE SAME AS 3.01h DUE TO SMOOTHING * * 1) New feature: diphone sizes and period size are not limited anymore * this will let you define new databases at 22050Hz and male voices at * 100Hz if you feel like to (see Engine/diphone.h) * * 2) Bug in smoothing: don't smooth anything with extra short frames (0ms) * (Engine/mbrola.c) * * 3) Back in time with pitchmarks: they are kept compressed (2 bits / mark) even * when downloaded in memory (stingy ROM usage) * * 4) Revolution in the Database directory due to arrival of ROM * databases. Those ones are simply memory dumps of a database at work, * once a Database* object is initialized, functionalities are exactly * the same as regular databases. Works for RAW, BACON and CEBAB * * To do this, had to remove many indirections in Hashtable, and add * rom_database.c + rom_handling.c source files. * * Modified the standalone version to add -w and -W options: * ./synth -W fr1 creates a fr1.rom image of the database. * * for debugging purpose: * ./synth -w fr1 test.pho test.wav * it download fr1.rom image and synthesize the test. * * Added a ROMDATABASE_PURE mode: lets you work with Mbrola without FILE* * * 26/09/01 3.02b: small bug correction -> a strong limit on the number * of phonemes (256) prevents us from using diphones * * Ansi-ness of the code -> problem with the typecast on an lvalue with * the database(dba) operation * * TODO: * May optimize FlushFile for Library mode to avoid 2 moves on samples at * the price of a medium size audio buffer. */ mbrola-3.3+dfsg/Documentation/LATEX/000077500000000000000000000000001364272575600172615ustar00rootroot00000000000000mbrola-3.3+dfsg/Documentation/LATEX/doc2.lyx000066400000000000000000001621251364272575600206550ustar00rootroot00000000000000#This file was created by Fri Apr 7 06:29:47 2000 #LyX 0.12 (C) 1995-1998 Matthias Ettrich and the LyX Team \lyxformat 2.15 \textclass article \language default \inputencoding latin1 \fontscheme default \graphics default \paperfontsize default \spacing single \papersize a4paper \paperpackage a4 \use_geometry 0 \use_amsmath 0 \paperorientation portrait \secnumdepth 3 \tocdepth 3 \paragraph_separation indent \defskip medskip \quotes_language english \quotes_times 2 \papercolumns 1 \papersides 1 \paperpagestyle default \layout Title MBROLA \layout Date (Multi-Band Resynthesis OverLap Add) \layout Date System documentation \layout Date Edition 7.0 - Mbrola release 3.02 \layout Date March 12th, 2000 \layout Standard \protected_separator \layout Quote "It would be a considerable invention indeed, that of a machine able to mimic speech, with its sounds and articulations. I think it is not impossible." Leonhard Euler (1761) \layout Quote \protected_separator \layout Right Address by Vincent Pagel and Thierry Dutoit \newline \layout Standard \protected_separator \layout Standard \begin_inset LatexCommand \tableofcontents \end_inset \layout Standard \protected_separator \layout Section MBROLA Sources General condition of use \layout Standard The source code of MBROLA may only be used to produce the object code sold by your company. It is confidential and should remain safely locked, as well as its documentatio n. \layout Section A brief description of MBROLA \layout Standard MBROLA v3.01 is a speech synthesizer based on the concatenation of diphones. One synthesis channel takes a list of phonemes as input, together with prosodic information (duration of phonemes and a piecewise linear description of pitch), and produces speech samples on 16 bits (linear), at the sampling frequency of the diphone database. It is therefore \noun on not \noun toggle a Text-To-Speech synthesizer, since it does not accept raw text as input. \layout Standard It is distributed as a ZIP file whose name respect the format \emph on "mbrXXXX.zip" \emph toggle where \emph on XXXX \emph toggle represent the version number (e.g. \emph on \latex latex "mbr3.01e.zip" \emph toggle \latex default ). \newline \layout Standard It may be compiled in 3 modes depending on which stream drives the process: \layout Itemize Driven by the input phonetic file: it is compiled as a standalone program named "synth" which outputs audio in a file or a pipe. This mode is a good choice under Unix platforms for end-user applications. In the following we call this mode \series bold " \emph on standalone mode \series default \emph toggle ". \layout Itemize Driven by the audio output: compiled as a library, which outputs audio data into buffers of the size, requested by the main program. This allows you to easily include MBROLA inside your TTS application without temporary file mechanisms. In the following we call this mode " \series bold \emph on library mode \series default \emph toggle ". \layout Itemize Same as above, included in a DLL for Windows95-98/NT (which is of course the preferred mode for Windows platforms). In the following we call this mode " \series bold \emph on DLL mode \series default \emph toggle ". \layout Standard While using \emph on library \emph toggle or \emph on DLL \emph toggle mode, we now differentiate one channel and multi channel mbrola. In the first mode, one database is associated to one and only one synthesis channel, which generally fits for end-user applications. In the second mode, one can run many synthesis channel instantiations with one or more Database instances and many phonetic input streams. This second solution is adapted to multi channel telecom TTS applications. \layout Standard \protected_separator \layout Standard In all those compilation modes MBROLA requires a language/voice database to run properly. For your internal use (i.e. non-commercial) you can test the voices made available on the MBROLA project homepage: \layout Standard \protected_separator \layout Standard http://tcts.fpms.ac.be/synthesis \layout Standard \protected_separator \layout Standard Refer to your contract to check your rights for commercial exploitation of the different Diphone Databases. \layout Standard \protected_separator \layout Section Distribution \layout Standard Since release 3.01, Mbrola has been transformed into pure ANSI/C code, and object like programming with a strong encapsulation of data (strong because we have respected the fences we put!). One file in the distribution is generally equivalent to one object (pointer on struct). You can find an exhaustive description in the programmer's section 6. \layout Standard This distribution of MBROLA contains the following files: \layout Description Makefile: Unix makefile for Gnu Make (gmake command) \layout Description \protected_separator \layout Description DOCUMENTATION/Programmer/documentation302: this document \layout Description DOCUMENTATION/Programmer/HISTORY.txt: history of revisions \layout Description DOCUMENTATION/User/readme.txt: standalone version manual \layout Description \protected_separator \layout Description Database: handling of different database formats \layout Description Database/database.c: functions to read diphones in the speech database \layout Description Database/database.h \layout Description Database/database_bacon.c: functions to read compressed diphone databases \layout Description Database/database_bacon.h \layout Description Database/database_old.c: functions to read diphone databases older than 2.06 \layout Description Database/database_old.h \layout Description \protected_separator \layout Description Database/diphone_info.c: description of the diphone structures \layout Description Database/diphone_info.h \layout Description \protected_separator \layout Description Database/hash_tab.c: hash table of DiphoneInfo (access to the diphone database) \layout Description Database/hash_tab.h \layout Description \protected_separator \layout Description Database/little_big.c: handles the little and big endian numeric conversions \layout Description Database/little_big.h \layout Description \protected_separator \layout Description Database/rename_list.c: list of phoneme pairs (used for renaming and cloning) \layout Description Database/rename_list.h \layout Description \protected_separator \layout Description Parser: functions to read phonemes in the input stream \layout Description Parser/fifo.c: First In First Out with chars \layout Description Parser/fifo.h \layout Description Parser/input.h: define abstract input stream \layout Description Parser/input_fifo.c: \series bold i \series default nstantiation of input.h with Fifo \layout Description Parser/input_fifo.h \layout Description Parser/input_file.c: instantiation of input.h with File \layout Description Parser/input_file.h \layout Description Parser/parser.h: define abstract phoneme parser \layout Description Parser/parser_input.c: instantiation of parser.h with Input \layout Description Parser/parser_input.h \layout Description Parser/phonbuff.c: handle a phoneme buffer for pitch interpolation \layout Description Parser/phonbuff.h \layout Description Parser/phone.c: phoneme type \layout Description Parser/phone.h \layout Description \protected_separator \layout Description Engine: Mbrola synthesis engine \layout Description Engine/diphone.c: diphone with info for synthesis \layout Description Engine/diphone.h \layout Description Engine/mbrola.c: mbrola algorithm (Ola, Smoothing...) \layout Description Engine/mbrola.h \layout Description \protected_separator \layout Description Misc: Miscellaneous functions basically unrelated to synthesis \layout Description Misc/audio.c: audio output and audio file header (au, wav, aiff, raw) \layout Description Misc/audio.h \layout Description Misc/common.c: useful little functions (uppercase, swab...) \layout Description Misc/common.h \layout Description Misc/g711.c: G711 audio coding (ALAW and MULAW) \layout Description Misc/g711.h \layout Description Misc/incdll.h: external definitions used outside of the Mbrola package \layout Description Misc/mbralloc.c: memory allocators are here and ONLY here \layout Description Misc/mbralloc.h \layout Description Misc/vp_error.c: deals with fatal error and warnings \layout Description Misc/vp_error.h: macros for debugging purposes \layout Description \protected_separator \layout Description Standalone: Standalone compilation front-end \layout Description Standalone/Posix \layout Description Standalone/Posix/getopt.c: provided for non-POSIX Unixes \layout Description Standalone/Posix/getopt.h \layout Description Standalone/synth.c: front-end for the compilation in the standalone mode. Main() \layout Description Standalone/synth.h \layout Description LibOneChannel: library providing one MBROLA synthesis channel \layout Description LibOneChannel/demo1.c: small demonstration program running with the library \layout Description LibOneChannel/demo1b.c: small demo showing error handling with the library \layout Description LibOneChannel/onechannel.c: library providing one mbrola channel at a time \layout Description LibOneChannel/onechannel.h \layout Description LibOneChannel/lib1.c: wrapper file to build the library lib1.c (mono channel) \layout Description \protected_separator \layout Description LibMultiChannel: library for multi MBROLA synthesis channel for telecom \layout Description LibMultiChannel/multichannel.c: many synthesis channel from one dba \layout Description LibMultiChannel/multichannel.h \layout Description LibMultiChannel/demo2.c: demo using lib2 \layout Description LibMultiChannel/lib2.c: wrapper file to build the library lib2.c (multi channel) \layout Description \protected_separator \layout Description VisualC++: compilation projects for Microsoft Visual C++ \layout Description VisualC++/DLL: Visual C++ project to build the DLL \layout Description VisualC++/DLL_USE: sample program using the DLL \layout Description VisualC++/Standalone: Visual C++ project to build a standalone binary \layout Description \protected_separator \layout Description Bin: directory containing the output of the compilation with Make under Unix architectures. \layout Section Installation and Tests \protected_separator \layout Subsection On Unix \layout Standard You must first unzip the distribution file mbrXXXX.zip where XXXX stand for the version number: \layout Description unzip mbrXXXX.zip \layout Description Mbrola can be compiled with the 'gmake' (gnu make) command on the following platforms: \layout Itemize SUN Sparc 5/S5R4 (Solaris2.4) \layout Itemize HPUX9.0 and HPUX10.0 \layout Itemize VAX/VMS V6.2 (V5.5-2 won't work) \layout Itemize DECALPHA(AXP)/VMS 6.2 \layout Itemize AlphaStation 200 4/233 \layout Itemize AlphaStation 200 4/166 \layout Itemize IBM RS6000 Aix 4.12 \layout Itemize PC/LINUX 1.2.11 \layout Itemize PCPentium120/Solaris2.4 \layout Itemize OS/2 \layout Itemize BeBox \layout Itemize QNX OS \layout Standard Though, as Mbrola is written in standard ANSI/C, we also support POSIX compliant UNIX Platforms. Please send acknowledgment when Mbrola works on a machine/system not listed here. Before you compile anything you must define some symbols depending on the architecture you're working with: \layout Description LITTLE_ENDIAN ® 80x86 based platforms \layout Description BIG_ENDIAN ® motorola or HP based platforms \layout Description VMS ® VAX/VMS stations \layout Description DOS ® PC80x86 with Dos or Windows \layout Description SUN4 ® old Sun4 stations (not Posix compliant) \layout Description DEBUG ® Huge debugging flag \layout Description DEBUG_HASH ® Runs the database and print info about the hash table management (used to tune the memory management of the database) \layout Description According to the compilation mode you wish, you can comment or uncomment following lines of Makefile : \layout Quote #CFLAGS += -DDEBUG \layout Quote #CFLAGS += -DDEBUG_HASH \layout Quote #CFLAGS += -DLITTLE_ENDIAN \layout Quote CFLAGS += -DBIG_ENDIAN \layout Standard You can add any definitions to the CFLAGS (compilation flags) variable of the Makefile, as in the following example: \layout Description optimized compilation on a Sun Station : \layout Quote CFLAGS= -Wall -DBIG_ENDIAN -O6 \layout Description debug mode on a VAX/VMS : \layout Quote CFLAGS= -Wall -DLITTLE_ENDIAN -DVMS -g -DDEBUG \layout Standard By default the compiler is set with CC = gcc ; though on many platforms cc may also work. As the hardware manufacturer generally provides cc, it is preferred when possible since the object code performance can be higher by an order of magnitude. You can type : \layout Description "make" or "make all" to generate the 'synth' binary (standalone mode). \layout Description "make clean" removes the entire object files and binaries. \layout Description "make lib1" compiles lib1.c in the library mode (one channel synth) \layout Description "make demo1" builds a demo exemplifying the use of lib1 \layout Description "make lib2" compiles lib1.c in the library mode (multi channel synth) \layout Description "make demo2" builds a demo exemplifying the use of lib2 \layout Description "make tags" to build Emacs popular tags (helps finding your way through the code with ESC-. ). SUN Workshop uses an internal btags program for that purpose. \layout Standard The intermediate object code goes into a Bin directory that is created on the occasion. \layout Subsection On PCs/Dos \layout Standard On PC/Dos platforms, use "pkunzip synthXXXX.zip" to restore the files (don't forget to restore the embedded paths in the archive). Mbrola can be compiled with Microsoft Visual C++ (4 .0 or higher), or Borland C++ (4 .5 or higher), on the following platforms: \layout Itemize PC486/DOS6 (but other PC/DOS should do, too) \layout Itemize PC486/Windows 3.1 \layout Itemize PC486/Windows 95 \layout Itemize PC-Pentium/Windows 98 \layout Itemize PC-Pentium/Windows NT \layout Standard Always check that in your project the following preprocessor directives are defined: LITTLE_ENDIAN and DOS. A project to build such a release with Visual C++ is provided under VisualC++/S tandalone. \layout Subsection On PC/Windows \layout Standard First proceed like for the PC/DOS platforms. Once synthXXXX is installed you can start building a DLL in the VisualC++ \backslash DLL directory. MbrolaDll.dsw is a Microsoft VisualC++ 5.0 project file to build a DLL. In any project you make to build a DLL with Mbrola don't forget to define the DLL, LITTLE_ENDIAN, DOS preprocessor definitions. \layout Standard The Mbrola source files and a wrapper DLL interface is included in the project, it should compile smoothly. In case you have to build a new project from scratch remember that you should include only file from either LibOneChannel/ or LibMultiChannel/. Never include files from Standalone/, as this directory is only relevant for a standalone mode (see section above for an exe binary). \layout Standard Several compilation modes are available, the "Win32 Bacon Static" is a good one to start with (Bacon compression scheme is included, DLL are statically linked). \layout Standard In the directory VisualC++/DLL_USE , little sample programs are given that use the Mbrola DLL. \layout Subsubsection Black magic \layout Standard There is a strange bug in Visual C++ 5.0, when you compile the project you sometime get: \layout Quote Linking... \layout Quote nafxcw.lib(dllmodul.cbj) : error LNK2005: _DllMain@12 already defined in LIBCMT.lib (dllmain.cbj) \layout Quote nafxcw.lib(afxmem.cbj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.cbj) \layout Quote nafxcw.lib(afxmem.cbj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.cbj) \layout Quote nafxcw.lib(dllmodul.cbj) : warning LNK4006: _DllMain@12 already defined in LIBCMT.lib(dllmain.cbj); second definition ignored \layout Quote nafxcw.lib(afxmem.cbj) : warning LNK4006: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.cbj); second definition ignored \layout Quote nafxcw.lib(afxmem.cbj) : warning LNK4006: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.cbj); second definition ignored \layout Quote Creating library MbrolaDl/Mbrola.lib and object MbrolaDl/Mbrola.exp \layout Quote Output \backslash Release_Static \backslash Mbrola.dll : fatal error LNK1169: one or more multiply defined symbols found \layout Quote Error executing link.exe. \layout Quote Mbrola.dll - 4 error(s), 7 warning(s) \layout Standard Solution: remove one file from the project and include it again in the list of source files, and build the project again. The problem vanishes. \layout Subsection Using the standalone binary \layout Standard You are now ready to test the program. First try: "synth" to get an information screen about the copyright. Then, for a help screen on how to use the standalone version of the software, try : \layout Quotation synth -h \layout Standard You get a help screen like the following: \layout Quotation > USAGE: ./synth [COMMAND LINE OPTIONS] database pho_file+ output_file \layout Quotation > \layout Quotation >A - instead of pho_file or output_file means stdin or stdout \layout Quotation >Extension of output_file ( raw, au, wav, aiff ) tells the wanted audio format \layout Quotation > \layout Quotation > Options can be any of the following: \layout Quotation > -i = display the database information if any \layout Quotation > -e = IGNORE fatal errors on unknown diphone \layout Quotation > -c CC = set COMMENT char (escape sequence in pho files) \layout Quotation > -F FC = set FLUSH command name \layout Quotation > -v VR = VOLUME ratio, float ratio applied to ouput samples \layout Quotation > -f FR = FREQ ratio, float ratio applied to pitch points \layout Quotation > -t TR = TIME ratio, float ratio applied to phone durations \layout Quotation > -l VF = VOICE freq, target freq for voice quality \layout Quotation > -R RL = Phoneme RENAME list of the form a A b B ... \layout Quotation > -C CL = Phoneme CLONE list of the form a A b B ... \layout Quotation > \layout Quotation > -I IF = Initialization file containing one command per line \layout Quotation > CLONE, RENAME, VOICE, TIME, FREQ, VOLUME, FLUSH, \layout Quotation > COMMENT, and IGNORE are available \layout Standard Now in order to go further, you need to get a version of an MBROLA language/voic e database from the MBROLA project homepage. Let us assume you have copied the FR1 database and referred to the accompanying fr1.txt file for its installation. Then try: \layout Quotation synth fr1/fr1 fr1/TEST/bonjour.pho bonjour.wav \layout Standard it uses the format: \layout Quotation synth diphone_database command_file1 command_file2 ... output_file \layout Standard and creates a sound file for the word 'bonjour' (Hello! in French) \layout Standard \protected_separator \layout Standard Basically the output file is composed of signed integer numbers on 16 bits, corresponding to samples at the sampling frequency of the MBROLA voice/language database (16 kHz for the diphone database supplied by the authors of MBROLA : Fr1). MBROLA can produce different audio file formats: .au, .wav, .aiff, .aif, and .raw files depending on the ouput_file extension. If the extension is not recognized, the format is RAW (no header). We recommend .wav for Windows, and .au for Unix platforms. To display information about the phoneme set used by the database, type: \layout Quotation synth -i fr1/fr1 \layout Standard It displays the phonetic alphabet as well as copyright information about the database. \layout Standard \protected_separator \layout Standard Option -e makes Mbrola ignore wrong or missing diphone sequences (replaced by silence) which can be quite useful when debugging your TTS. Equivalent to "IGNORE" directive in the initialization file (N.B replace the obsolete ;;E=OFF , unsupported in .pho file). \layout Subsubsection Changing the pitch \layout Standard Optional parameters let you shorten or lengthen synthetic speech and transpose it by providing optional time and frequency ratios: \layout Quotation synth -t 1.2 -f 0.8 -v 0.7 fr1/fr1 TEST/bonjour.pho bonjour.wav \layout Standard or its equivalent in the initialization file: \layout Quotation TIME 1.2 \layout Quotation FREQ 0.8 \layout Standard for instance, will result in a RIFF Wav file bonjour.wav 1.2 times longer than the previous one (slower rate), and containing speech in which all fundamental frequency values have been multiplied by 0.8 (sounds lower). You can also set the values of these coefficients directly in a .pho file by adding special escape sequence like : \layout Quotation ;; F=0.8 \layout Quotation ;; T=1.2 \layout Standard You can change the voice characteristics with the -l parameter. If the sampling rate of your database is 16000, indicating -l 18000 allows you to shorten the vocal tract by a ratio 16/18 (children voice, or women voice depending on the voice you're working on). With -l 10000,you can lengthen the vocal tract by a ratio 18/10 (namely the voice of a Troll). The same command in an initialization file becomes "VOICE 10000". \layout Standard \protected_separator \layout Standard Option \series bold -v \series default gives a VolumeRatio that multiplies each output sample. In the example below, each sample is multiplied by 0.7 (the loudness goes down). Warning: setting VolumeRatio too high generates saturation. \layout Quotation synth -v 0.7 fr1/fr1 TEST/bonjour.pho bonjour.wav \layout Standard or add the line \series bold "VOLUME 0.7" \series default in an initialization file \layout Standard \protected_separator \layout Standard The \series bold -c \series default option lets you specify which symbol will be used as an escape sequence for comments and commands in .pho files. The default value is the semi-colon ';', but you may want to change this if your phonetic alphabet use this symbol, like in: \layout Quotation synth -c ! fr1/fr1 TEST/test1.pho test2.pho test.wav \layout Standard equivalent to " \series bold COMMENT ! \series default " in an initialization file \layout Standard \protected_separator \layout Standard The \series bold -F \series default option lets you specify which symbol will be used to Flush the audio output. The default value is \series bold # \series default , you may want to change the symbol like in: \layout Quotation mbrola -F FLUSH_COMMAND fr1/fr1 test.pho test.wav \layout Standard equivalent to " \series bold FLUSH FLUSH_COMMAND \series default " in the initialization file. \layout Subsubsection Using Pipes \layout Standard A - instead of command_file or output_file means stdin or stdout. On multitasking machines, it is easy to run the synthesizer in real time to obtain audio output from the audio device, by using pipes. \layout Subsubsection Renaming and Cloning phonemes \layout Standard It may happen that the language-processing module connected to MBROLA doesn't use the same phonemic alphabet as the voice used. The Renaming and Cloning mechanisms help you to quickly solve such problems (without adding extra CPU load). The only limitation about phoneme names is that they can't contain blank characters. \layout Standard \protected_separator \layout Standard If, for instance, phoneme a in the mbrola voice you use is called my_a in your alphabet, and phoneme b is called my_b, then the following command solves the problem: \layout Quotation synth -R "a my_a b my_b" fr1/fr1 test.pho test.wav \layout Standard You can give as many renaming pairs as you want. Circular definition is not a problem. E.g. " \series bold a b b c \series default " will rename original \emph on [a] \emph toggle into [b] and original \emph on [b] \emph toggle into \emph on [c] \emph toggle independently \emph on ([a] \emph toggle won't be renamed to \emph on [c] \emph toggle ). \layout Standard \protected_separator \layout Standard LIMITATION: you can't rename a phoneme into another that already exists. \layout Standard \protected_separator \layout Standard The cloning mechanism does exactly the same thing, though the old phoneme still exists after renaming. This is useful if you have 2 allophones in your alphabet, but the Mbrola voice only provides one. \layout Standard \protected_separator \layout Standard Imagine for instance, that you make the distinction between the voiced [r] and its unvoiced counterpart [r0] and that you are using a syllabic version [r=]. If as a first approximation using [r] for both is OK, then you may use an Mbrola voice that only provides one version of [r] by running: \layout Quotation synth -C "r r0 r r=" fr1/fr1 test.pho test.wav \layout Standard which tells the synthesizer that [r0] and [r=] should be both synthesized as [r]. You can write a long cloning list of phoneme pairs to fit your needs. \layout Standard \protected_separator \layout Standard Renaming and cloning eats CPU since the complete diphone hash table has to be rebuilt, but once the renaming or cloning has occurred there is absolutel y NO RELATED PERFORMANCE DROP. So using this feature is more efficient than a pre-processor is, though a simple phoneme mapping cannot always solve incompatibilities. \layout Standard \protected_separator \layout Standard Before renaming anything as \series bold # \series default , check section 5.1.2 \layout Standard \protected_separator \layout Standard When one has long cloning and renaming lists, you can conveniently write them into an initialization file according to the following format: \layout Quotation RENAME a my_a \layout Quotation RENAME b my_b \layout Quotation CLONE r r0 \layout Quotation CLONE r r= \layout Standard The obsolete " \series bold ;; RENAME a my_a \series default " can't be used in .pho file anymore, but is correctly parsed in initialization files. Note to EN1 and MRPA users: the consequence of the change above is that you must change the previous call format " \emph on mbrola en1 en1mrpa... \emph toggle " into " \emph on mbrola -I en1mrpa en1 ... \emph toggle ". \layout Subsection Machine dependant hints for best using Mbrola \layout Standard \layout Subsubsection On MSDOS \layout Standard \layout Standard With the standalone version, generating wav files is easier: \layout Standard \layout Quotation synth fr1/fr1 TEST/bonjour.pho bonjour.wav \layout Standard \layout Standard Then you can play the RIFF Wav file with your favorite DOS or Windows sound utility. On OS/2 pipes may be used just like below. \layout Subsubsection On modern Unix systems such as Solaris or HPUX or Linux \layout Standard Type: \layout Quotation synth fr1 bonjour.pho -.au | audioplay \layout Standard where audioplay is your audio file player (* the name vary with the platform, e.g. splayer for HPUX *). \layout Standard If your audioplayer has problems with sun .AU files, try with .wav or .raw. Never use .wav format when you pipe the output (mbrola can't rewind the file to write the audio size in the header). Wav format was not developed for Unix (on the contrary Au format let you specify in the header "we're on a pipe, read until end of file"). \layout Standard \protected_separator \layout Standard NOTE FOR LINUX: you can use the GPL rawplay program provided at \layout Quotation ftp://tcts.fpms.ac.be/pub/mbrola/pclinux/ \layout Subsubsection On Sun4 ( old audio interface ) \layout Standard Those machines are now quite old and only provide a mulaw 8Khz output. A hack is: \layout Quotation synth fr1 input.pho - | sox -t raw -sw -r 16000 - -t raw -Ub -r 8000 - > /dev/audio \layout Standard Provided you have the public domain sox utility developed by Ircam, you should hear \emph on 'bonjour' \emph toggle without the need to create intermediate files. Note that we strongly recommend that you DON'T use SOX, since its resampling method (linear interpolation) will permanently damage the sound. \layout Standard Other solution: The UTILITY.ZIP file available from the MBROLA homepage provides RAW2SUN that does this conversion. \layout Subsubsection On VAX or AXP workstations \layout Standard To make it easier for users to find MBROLA, you should add the following command to your system startup procedure: \layout Quotation $ DEFINE/SYSTEM/EXEC MBROLA_DIR disk:[dir] \layout Standard where "disk:[dir]" is the name of the directory you created for the MBROLA_DIR files. You could also add the following command to your system login command procedure : \layout Quotation $ MBROLA :== $MBROLA_DIR:MBROLA.EXE \layout Quotation $ RAW2SUN :== $MBROLA_DIR:RAW2SUN.EXE \layout Standard to use the decsound device: \layout Quotation $ MCR DECSOUND - volume 40 -play sound.au \layout Standard See also the MBR_OLA.COM batch file in the UTILITY.ZIP file available from the MBROLA Homepage if you cannot play 16 bits sound files on your machine. \layout Subsection Default Parser Manual \layout Standard The default parser is the parser that was provided before release 3.01. Implicitly it means that you can replace it with your own one, thanks to the setParser_MBR function. Basically the work of the parser is to return to Mbrola a phoneme with a length, and its pitch points. \layout Standard \protected_separator \layout Standard We provide a default parser that allows you to give optional pitch points, the intonation curve being linearly interpolated between those points. \layout Subsubsection Input file format \layout Standard Example of a command line : \layout Quotation synth fr1/fr1 bonjour.pho bonjour.wav \layout Standard For example the phonetic input file bonjour.pho simply contains : \layout Quotation ; \series bold Bonjour \layout Quotation _ \series bold 51 25 114 \layout Quotation b \series bold 62 \layout Quotation o~ \series bold 127 48 170.42 \layout Quotation Z \series bold 110 53.5 116 \layout Quotation u \series bold 211 \layout Quotation R \series bold 150 50 91 \layout Quotation _ \series bold 91 \layout Standard This shows the format of the input data required by MBROLA. Each line contains a phoneme name, a duration (in ms), and a series (possibly none) of pitch pattern points composed of two float numbers each: the position of the pitch pattern point within the phoneme (in % of its total duration), and the pitch value (in Hz) at this position. \layout Standard \protected_separator \layout Standard Hence, the second line of bonjour.pho : \layout Quotation _ 51 25 114 \layout Standard tells the synthesizer to produce a silence of 51 ms, and to put a pitch pattern point of 114 Hz at 25% of 51 ms. Pitch pattern points define a piecewise linear pitch curve. Notice that the pitch pattern they define is continuous, since the program automatically drops pitch information when synthesizing unvoiced phones. \layout Standard \protected_separator \layout Standard Blank characters or tabs separate the data on each line. Comments can optionally be introduced in command files, starting with a semi-colon \series bold ';' \series default . This default can be overrun with the \series bold -c \series default option of the command line. \layout Standard \protected_separator \layout Standard Another special escape sequence \series bold ';;' \series default allow the user to introduce commands in the middle of .pho files as described below. This escape sequence is also affected by the \series bold -c \series default option. \layout Subsubsection Changing the Frequency Ratio or Time Ratio \layout Standard A command escape sequence containing a line like \series bold "T=x.x" \series default modifies the time ratio to \series bold x.x \series default , the same result is obtained on the fundamental frequency by replacing T with F, like in: \layout Quotation ;; T = 1.2 \layout Quotation ;;F=0.8 \layout Subsubsection Flush the output stream \layout Standard Note, finally, that the synthesizer outputs chunks of synthetic speech determine d as sections of the piecewise linear pitch curve. Phones inside a section of this curve are synthesized in one go. The last one of each chunk, however, cannot be properly synthesized while the next phone is not known (since the program uses diphones as base speech units). When using mbrola with pipes, this may be a problem. Imagine, for instance, that mbrola is used to create a pipe-based speaking clock on a HP: \layout Quotation speaking_clock | mbrola fr1 - -.au | splayer \layout Standard which tells the time, say, every 30 seconds. The last phone of each time announcement will only be synthesized when the next announcement starts. To bypass this problem, mbrola accepts a special command phone, which flushes the synthesis buffer : " \series bold # \series default " \layout Standard This default character can be replaced by another symbol thanks to the command: \layout Quotation ;; FLUSH new_flush_symbol \layout Standard Another important issue with piping under UNIX, is the possibility to prematurel y end the audio output, if for example the user presses the stop button of your application. Since release 3.01, Mbrola handles signals. \layout Standard \protected_separator \layout Standard If in the previous example the user wants to interrupt the speaking clock message, the application just needs to send the USR1 signal. You can send such a signal from the console with: \layout Quotation kill -16 mbrola_process_number \layout Standard Once mbrola catches the signal, it reads its input stream until it gets EOF or a FLUSH command (hence, surrounding sections with flush is a good habit). \layout Subsubsection Limitations of MBROLA \layout Standard There is no more limitation on the number of pitch points one can assign to a phoneme, or on the number of phonemes without pitch points. There is no more limitation on extra low pitch (sometime used to produce vocal fry). \layout Standard Phonemes can be synthesized with a maximum duration that depends on the fundamental frequency with which they are produced. The higher the frequency, the lower the duration. For a frequency of 133 Hz, the maximum duration is 7.5 sec. For a frequency of 66.5 Hz, is 5 sec. For a frequency of 266 Hz, is 3.75 sec. \layout Section Programmer's Manual \layout Standard First, we describe in this section the object oriented philosophy used since release 3.01. \layout Subsection Philosophy and architecture \layout Standard Actually nothing (or nearly nothing) prevents us to program in standard C/ANSI with an object like convention which authorize: \layout Enumerate "weak" encapsulation \layout Enumerate Inheritance \layout Enumerate Polymorphism \layout Subsection Encapsulation of Object's attributes \layout Standard Let's exemplify the programming conventions with the char Fifo found in Parser/fifo.h. First we define a structure describing a Fifo. \layout Quotation typedef struct \layout Quotation { \layout Quotation char* charbuff; \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator /* circular buffer for phonetic input */ \layout Quotation int buffer_pos; \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator /* Current position */ \layout Quotation int buffer_end; \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator /* Last available phoneme */ \layout Quotation int buffer_size; \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator /* number of chars in Phobuffer */ \layout Quotation } Fifo; \layout Standard To make distinction between public and private data, the convention is to never directly access the features of a Fifo out of its fifo.c implementation file. To reach this goal we exclusively access members through function-like macros. \layout Quotation #define charbuff(ff) ff->charbuff \layout Quotation #define buffer_pos(ff) ff->buffer_pos \layout Quotation #define buffer_end(ff) ff->buffer_end \layout Quotation #define buffer_size(ff) ff->buffer_size \layout Standard It allows the following: \layout Quotation Fifo* my_fifo; \layout Quotation .. \layout Quotation int length= buffer_size(my_fifo); \layout Standard The programmer should not cheat to discover whether buffer_size is a function or a macro, thus encapsulating the data and making them independent of the Fifo's real implementation (modulo a complete recompiling). C is not C++ and your compiler won't be able to carry out strong type checking just as with inline functions, that's the reason why attributes don't respect the full convention below (according to our conventions we should have use the name buffer_size_Fifo() ). \layout Standard The methods always respect the format: functionname_ObjectName just like below and take a pointer on the object as a first argument. Methods beginning with init are always constructor, and those beginning with close are destructors: \layout Quotation Fifo* init_Fifo(int size); \layout Quotation /* \layout Quotation \protected_separator \protected_separator * Constructor with size of the buffer \layout Quotation \protected_separator \protected_separator */ \layout Quotation void close_Fifo(Fifo* ff); \layout Quotation /* \layout Quotation \protected_separator \protected_separator * Release the memory \layout Quotation \protected_separator \protected_separator */ \layout Quotation void reset_Fifo(Fifo* ff); \layout Quotation /* \layout Quotation \protected_separator \protected_separator * Forget previously entered data in the circular buffer \layout Quotation \protected_separator \protected_separator */ \layout Quotation int write_Fifo(Fifo* ff, char *buffer_in); \layout Quotation /* \layout Quotation \protected_separator \protected_separator * Write a string of phoneme in the input buffer \layout Quotation \protected_separator \protected_separator * Return the number of chars actually written \layout Quotation \protected_separator \protected_separator */ \layout Quotation int readline_Fifo(Fifo* ff, char *line, int size); \layout Quotation /* \layout Quotation \protected_separator \protected_separator * Read a line from the input stream in a circular buffer \layout Quotation \protected_separator \protected_separator * Return 0 if there's nothing to read \layout Quotation \protected_separator \protected_separator */ \layout Subsubsection Inheritance and Polymorphism \layout Standard Inheritance alone can always be simulated through the is_a_client_of relation, the most interesting case being polymorphism. Polymorphism is interesting for multiple format database handling, and live input parser definition inside of the synthesizer. \layout Standard \protected_separator \layout Standard The abstract type below specifies an Input object providing the methods close, reset and readline . \layout Quotation typedef struct Input Input; \layout Quotation typedef int (*readline_InputFunction)(Input* in, char *line, int size); \layout Quotation typedef void (*close_InputFunction)(Input* in); \layout Quotation typedef void (*reset_InputFunction)(Input* in); \layout Quotation struct Input \layout Quotation { \layout Quotation void* self; \layout Quotation readline_InputFunction readline_Input; \layout Quotation close_InputFunction close_Input; \layout Quotation close_InputFunction reset_Input; \layout Quotation }; \layout Standard This type can be derived into Input_File (the input stream is a file) or Input_Fifo (the input stream comes from a Fifo as described above). The part of the object corresponding to the features overloaded on the basic Input type is stored in the self part. \layout Quotation #include "input.h" \layout Quotation #include "fifo.h" \layout Quotation static int readline_InputFifo(Input* in, char *line, int size) \layout Quotation { return( readline_Fifo((Fifo*) in->self,line,size) ); } \layout Quotation static void reset_InputFifo(Input* in) \layout Quotation { reset_Fifo((Fifo*) in->self); } \layout Quotation static void close_InputFifo(Input* in) \layout Quotation { MBR_free(in); } \layout Quotation Input* init_InputFifo(Fifo* my_fifo) \layout Quotation { \layout Quotation Input* self= (Input*) MBR_malloc( sizeof(Input) ); \layout Quotation self->self= (void*) my_fifo; \layout Quotation self->readline_Input= readline_InputFifo; \layout Quotation self->close_Input= close_InputFifo; \layout Quotation self->reset_Input= reset_InputFifo; \layout Quotation return self; \layout Quotation } \layout Subsubsection Inheritance and cross-reference graph \layout Standard The Database, Input and Parser objects contain deferred (=virtual) methods and thus allow polymorphism. \layout Section Application Programming Interface \layout Standard The explanations given in the previous section are particularly useful to the user who wants to design ad-hoc parsers. Though one can keep on working with the default parser. \layout Subsection One channel mode \layout Standard You can build a demo by running " \series bold make demo1 \series default " under Unix, or simply build the library with "make lib1". With Windows and Visual C++ the DLL project builds an equivalent of lib1, and numerous examples are provided in the DLL_USE directory. The complete one channel mode interface is given section 7.24. Let's exemplify the use below: \layout Standard \protected_separator \layout Standard First, initialize the engine with a diphone database. All the functions in the API return an error code. A negative value means there was a flaw during the process, in case of error, an explicit error message can be obtained from \series bold lastErrorStr_MBR \series default (). \layout Quotation err_code= init_MBR("h:/mbrola/database/fr1" ); \layout Quotation if (err_code<0) \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator handle_error(); \layout Standard If the default parser is plugged, one can use the regular syntax in write_MBR to send phonemes to the engine: \layout Quotation if ( ( write_MBR("_ 51 \backslash n b 62 \backslash n") < 0) || \layout Quotation ( write_MBR("o~ 127 50 170 \backslash n Z 110 \backslash n") <0) || \layout Quotation ( WriteSpeechFile(output)<0) || \layout Quotation ( write_MBR("u 211 100 200 \backslash n R 150 \backslash n_ 9 \backslash n# \backslash n") < 0) || \layout Quotation ( WriteSpeechFile(output)<0) ) \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator handle_error(); \layout Quotation close_MBR(); \layout Standard Each time one calls \series bold init_MBR \series default (), one should call a pending \series bold close_MBR \series default () to release allocated memory. Once \series bold close_MBR \series default () is called, one can call init_MBR() for a brand new database. If one wish to work with the same database but forget previously entered phonemes, then use \series bold reset_MBR \series default (). \layout Standard \protected_separator \layout Standard Let's describe how \series bold WriteSpeechFile \series default works: \layout Quotation int WriteSpeechFile(FILE *output) \layout Quotation { \layout Quotation int i; \layout Quotation while ( (i=readtype_MBR(buffer, 16000, LIN16)) == 16000) \layout Quotation \protected_separator \protected_separator fwrite(buffer, 2, i, output); \layout Quotation if (i>0) \layout Quotation { /* write last chunk */ \layout Quotation \protected_separator \protected_separator fwrite(buffer,size,i,output); \layout Quotation \protected_separator \protected_separator return 0; \layout Quotation } \layout Quotation else \layout Quotation \protected_separator \protected_separator return i; /* return an error code */ \layout Quotation } \layout Standard It reads sample buffers from the engine until it can't get any more ( \series bold readtype_MBR \series default returns 0), or an error occurs. Readtype can return 0 for two reasons: either a flush has been encountered, either we don't have enough data in the default parser, as it needs a look ahead to interpolate pitch values. This is the case after \series bold write_MBR \series default ("o~ 127 50 170 \backslash n Z 110 \backslash n"), synthesis on the /Z/ can't be carried out until we get the pitch point on "u 211 100 200". This way asynchronous read/write operations are allowed. \layout Standard \protected_separator \layout Standard The small error handling function simply does: \layout Quotation void handle_error() \layout Quotation { \layout Quotation \protected_separator \protected_separator char err[255]; \layout Quotation \protected_separator \protected_separator lastErrorStr_MBR(err,sizeof(err)); \layout Quotation \protected_separator \protected_separator printf("Code %i \backslash n%s \backslash n", lastError_MBR(), err); \layout Quotation \protected_separator \protected_separator exit(-1); \layout Quotation } \layout Standard At any time, one can use the get_* and set_* functions to modify internal parameters of the synthesizer. \layout Standard \protected_separator \layout Standard Important note about the vocal tract length capabilities: one can modify the size of the speaker's throat with \series bold setFreq_MBR \series default . The lower this frequency, the deeper the voice. This very simple method takes advantage of the playback sampling rate to shift the formants up and down, just like when changing the speed of a tape player. Thus, to be effective, any call to \series bold setFreq_MBR \series default must be accompanied with a call to the audio hardware setting the requested playback sample rate. Otherwise the speed and pitch will sound odd. \layout Subsubsection Multi channel mode \layout Standard One can build a demo by running " \series bold make demo2 \series default " under Unix, or simply build the library with " \series bold make lib2 \series default ". The complete multi channel mode interface is given section 7.25. \layout Standard \protected_separator \layout Standard It looks strangely close to the one channel mode, except that one passes a pointer to a synthesizer structure for every function. Another point is that it doesn't hide any more the parser's details to the user. Thus if one wants to use the default parser, one has to effectively build it. \layout Standard \protected_separator \layout Standard The following code build 3 independent default phoneme parsers: \layout Quotation /* Input Fifo with a buffer of 100 chars */ \layout Quotation fifo1= init_Fifo(100); \layout Quotation fifo2= init_Fifo(100); \layout Quotation fifo3= init_Fifo(100); \layout Quotation \protected_separator \layout Quotation /* Input stream of the synthesizer */ \layout Quotation input1= init_InputFifo(fifo1); \layout Quotation input2= init_InputFifo(fifo2); \layout Quotation input3= init_InputFifo(fifo3); \layout Quotation /* Plug the fifos on the default parsers */ \layout Quotation parser1= init_ParserInput(input1,"_",120.0,";",1.0,1.0); \layout Quotation parser2= init_ParserInput(input2,"_",120.0,";",1.0,1.0); \layout Quotation parser3= init_ParserInput(input3,"_",120.0,";",1.0,1.0); \layout Standard To use one's own parser, see the next section. Once this is done, as many databases as synthesis channels must be opened (let's say 3 channels in this example). \layout Quotation Database* main_dba= init_DatabaseMBR2(argv[1],NULL,NULL); \layout Quotation if (!main_dba) \layout Quotation \protected_separator \protected_separator \protected_separator handle_error(True); \layout Standard Of course opening 3 or more times the same database would spoil a lot of memory since many internal structures could be shared. Instead of using \series bold init_DatabaseMBR2 \series default one can clone an already opened database: \layout Quotation Database* clone_dba1= copyconstructor_DatabaseMBR2(main_dba); \layout Quotation Database* clone_dba2= copyconstructor_DatabaseMBR2(main_dba); \layout Quotation Database* clone_dba3= copyconstructor_DatabaseMBR2(main_dba); \layout Standard Cloned database just behave like regular Database, i.e. their destructor must be called before leaving. Once we have a Parser input and a Database, we can open a synthesis channel: \layout Quotation Mbrola* channel1= init_MBR2(clone_dba1,parser1); \layout Quotation Mbrola* channel2= init_MBR2(clone_dba2,parser2); \layout Quotation Mbrola* channel3= init_MBR2(clone_dba3,parser3); \layout Standard In this particular example, one can write phonemes in the parser, and read samples from the synthesis engine with instructions such as: \layout Quotation write_Fifo(fifo1,"_ 51 \backslash n b 62 \backslash n o~ 100 \backslash n Z 120") \layout Quotation while ((i=readtype_MBR2(channel1, buffer, 16000, LIN16))==16000) \layout Quotation \protected_separator \protected_separator \protected_separator fwrite(buffer,size,i,output); \layout Standard Of course the call to write_Fifo is completely dependent of the fact that this example uses the default phoneme parser. In this particular case, the polymorphic object Parser, which was passed to the constructor of channel, reads its input data from Fifo1. \layout Subsubsection Designing and plugging your own parser \layout Standard The user can write his own implementation of a Parser, as long as it follows the definition of Parser/parser.h. The file parser_simple.c below gives an example of a parser that reads phonetic inputs with the format: Phoneme Duration Pitch_At_0% Pitch_At_100%. \layout Standard \protected_separator \layout Standard In practice this example does not take into account that the Engine synthesize diphones. As the word states, a diphone is made of two phonemes, thus one must know both parts of the diphones to utter it. Thus each phoneme file being used with parser_simple must end with two silences: the first one reveal 1st half of the last phoneme, and the second one reveal the second half (a complete example is provided in VisualC++/DLL_USE /mbrola/parser_simple.cpp). Many people forget to include the second silence as the result sounds correct without. Though, the total length of the synthetic message won't agree with the requested one. \layout Quotation /* \layout Quotation * FPMs-TCTS SOFTWARE LIBRARY \layout Quotation * \layout Quotation * File: parser_simple.c \layout Quotation * Purpose: parse a simple "pho file" (demonstration of the mbrola DLL) \layout Quotation * Instanciation of parser.h \layout Quotation * \layout Quotation * Author: Vincent Pagel \layout Quotation * Email : mbrola@tcts.fpms.ac.be \layout Quotation * \layout Quotation * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) \layout Quotation * \layout Quotation * 18/09/98 : Created \layout Quotation */ \layout Quotation \protected_separator \layout Quotation #include \layout Quotation #include "mbrola.h" \layout Quotation #include "parser_simple.h" \layout Quotation \protected_separator \layout Quotation static void reset_ParserSimple(Parser* parse) \layout Quotation { \layout Quotation /* nothing to do */ \layout Quotation fseek( (File*) parse->self,0,SEEK_SET); \layout Quotation } \layout Quotation \protected_separator \layout Quotation static StatePhone nextphone_ParserSimple(Parser* parse, LPPHONE* ph) \layout Quotation { \layout Quotation \protected_separator \protected_separator char phoneme[255]; /* phoneme name */ \layout Quotation \protected_separator \protected_separator float length; /* length in milliseconds */ \layout Quotation \protected_separator \protected_separator float pitch0; /* pitch at 0% */ \layout Quotation \protected_separator \protected_separator float pitch100; /* pitch at 100% */ \layout Quotation \protected_separator \layout Quotation \protected_separator \protected_separator if ( fscanf( (FILE*)parse->self," %s %f %f %f ",phoneme,&length,&pitch0,&pitch10 0 ) ==4 ) \layout Quotation \protected_separator \protected_separator { \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator *ph= init_Phone(phoneme,length); \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator appendf0_Phone(*ph, 0.0 , pitch0); \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator appendf0_Phone(*ph, 100.0, pitch100); \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator return PHO_OK; \layout Quotation \protected_separator \protected_separator } \layout Quotation else \layout Quotation \protected_separator \protected_separator { \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator return PHO_EOF; \layout Quotation \protected_separator \protected_separator } \layout Quotation } \layout Quotation \protected_separator \layout Quotation static void close_ParserSimple(Parser* parse) \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator /* Destructor */ \layout Quotation { \layout Quotation \protected_separator \protected_separator fclose( (FILE*) parse->self); \layout Quotation \protected_separator \protected_separator free(parse); \layout Quotation } \layout Quotation \protected_separator \layout Quotation Parser* init_ParserSimple(char* input_name) \layout Quotation /* \layout Quotation \protected_separator \protected_separator * Constructor of the parser. Parse a text file of the form \layout Quotation \protected_separator \protected_separator * PHONEME LENGTH PITCH_AT_BEGINNING PITCH_AT_END \layout Quotation \protected_separator \protected_separator */ \layout Quotation { \layout Quotation \protected_separator \protected_separator FILE* input; \layout Quotation \protected_separator \protected_separator Parser* parse; \layout Quotation \protected_separator \layout Quotation \protected_separator \protected_separator /* open the text file */ \layout Quotation \protected_separator \protected_separator input=fopen(input_name,"rt"); \layout Quotation \protected_separator \layout Quotation \protected_separator \protected_separator if (!input) \layout Quotation \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator \protected_separator return NULL; \layout Quotation \protected_separator \layout Quotation \protected_separator \protected_separator parse= (Parser*) MBR_alloc( sizeof( struct Parser) ); \layout Quotation \protected_separator \protected_separator parse->reset_Parser= reset_ParserSimple; \layout Quotation \protected_separator \protected_separator parse->close_Parser= close_ParserSimple; \layout Quotation \protected_separator \protected_separator parse->nextphone_Parser= nextphone_ParserSimple; \layout Quotation \protected_separator \protected_separator parse->self= (void*) input; \layout Quotation \protected_separator \protected_separator return(parse); \layout Quotation } \layout Subsection Mbrola architecture \layout Standard In following chapters the exported functions and variables of all the source files in the project are described. After the file descriptions, a symbol index is provided to allow fast localizat ion of any function, variable or define. \the_end mbrola-3.3+dfsg/Documentation/rom_documentation.txt000066400000000000000000000061241364272575600226760ustar00rootroot00000000000000Release 3.02a This is a short introduction to ROM databases (this section will be moved in the full documentation): Mbrola now offers a way to initialize database from a ROM dump. Previously, initialization was: Database* init_Database(char* dbaname); /* Generic initialization, calls the appropriate constructor * Returning NULL means fail (check LastError) */ One had to provide a file name, and the header of the database was indicating the type of the database ( Raw, Bacon compressed, Cebab compressed and other types to come). The new mechanism is: Database* init_ROM_Database(void* input_ptr); /* * Initialize a database from a ROM image */ Where one provides as an input a pointer to a ROM map. Mbrola internal structures were heavily modified so that most of database information are actually kept in ROM and not copied in RAM through mallocs. To build those ROM images from different types of databases, one must use the standalone version of MBROLA with the new -W option: mbrola -W fr1 Launching this command line generates a fr1.rom dump in a file. You can then embed this dump in the resources of your mbrola instance. If you need renaming or cloning, you can freeze it in the ROM database once for all (renaming cannot of course be called on a ROM image). For example you can call the command: mbrola -R "a b c d" -C "b i" fr1 It will download fr1, rename a into b, and c into d, clone b into i and THEN dump memory image into fr1.rom For debugging purposes, the standalone "mbrola" program can use a ROM dump instead of a regular database file, it is indicated through the new -w option: mbrola -w fr1 TEST/bonjour.pho output.wav This command initializes the mbrola engine with the fr1.rom dump (it mallocs a memory copy of fr1.rom and then call init_ROM_Database on it) Once the programmer has built a new Database object (either from a file, either from a memory map) Mbrola's functionality remain the same, thus refer to the standard manual. ---------------------------------------------------------------- Building the code: To be able to save ROM images from regular diphone databases you must define compilers symbol ROMDATABASE_STORE, see the line in the Makefile: CFLAGS += -DROMDATABASE_STORE To be able to initialize a Database from a ROM image, you must define compilers symbol ROMDATABASE_INIT, see the line in the makefile: # Uncomment if you wish to use init_ROM_Database(ROM_pointer) CFLAGS += -DROMDATABASE_INIT If you work with a Visual C++ project, you must include the C files: Database/rom_handling.c Database/rom_database.c IF YOU ARE ON A "ROM ONLY" PLATFORM AND WANT FILE* TO DISAPPEAR FROM THE SOURCE CODE: CFLAGS += -DROMDATABASE_PURE ------------------------------------------------------ WARNINGS: please note than endianess should be the same on the embedded system and on the system where you build the .rom image (see BIG_ENDIAN LITTLE_ENDIAN). In other word if the target system is a LITTLE_ENDIAN platform use a PC, if the system is a BIG_ENDIAN platform use a Macintosh or a SUN. The same remark is valid for FLOAT as well in case of compressed databases mbrola-3.3+dfsg/Engine/000077500000000000000000000000001364272575600150005ustar00rootroot00000000000000mbrola-3.3+dfsg/Engine/diphone.c000066400000000000000000000076141364272575600166020ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: diphone.c * Time-stamp: <00/03/30 01:29:26 pagel> * Purpose: Phone and diphone objects * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 15/06/98 : Created. Phones, Diphones, ... * 09/09/98 : reset_DiphoneSynthesis function * 24/03/00 : no more limits on period size -> * pass frame size during construction */ #include "diphone.h" DiphoneSynthesis* init_DiphoneSynthesis(int mbr_period, int max_pm, int max_samples) /* Alloc memory, working and audio buffers for synthesis */ { DiphoneSynthesis* self; self= (DiphoneSynthesis *) MBR_malloc(sizeof(DiphoneSynthesis)); LeftPhone(self)=NULL; RightPhone(self)=NULL; smoothw(self)= (int16*) MBR_malloc(sizeof(int16) * 2*mbr_period); real_frame(self)= (uint8*) MBR_malloc(sizeof(uint8) * max_pm); /* For ROM RAW databases, no need to alloc a buffer */ if (max_samples) buffer(self)= (int16*) MBR_malloc(sizeof(int16) * max_samples); buffer_alloced(self)= (max_samples!=0); return(self); } void reset_DiphoneSynthesis(DiphoneSynthesis* ds) /* * Forget the diphone in progress */ { ds->Descriptor=NULL; if (LeftPhone(ds)) { close_Phone( LeftPhone(ds) ); LeftPhone(ds)=NULL; } if (RightPhone(ds)) { close_Phone( RightPhone(ds) ); RightPhone(ds)= NULL; } } void close_DiphoneSynthesis(DiphoneSynthesis* ds) /* Release memory and phone */ { reset_DiphoneSynthesis(ds); if (smoothw(ds)) MBR_free( smoothw(ds) ); if ( buffer_alloced(ds) && buffer(ds) ) MBR_free( buffer(ds) ); if (real_frame(ds)) MBR_free( real_frame(ds) ); MBR_free(ds); } int GetPitchPeriod(DiphoneSynthesis *dp, int cur_sample,int Freq) /* * Returns the pitch period (in samples) at position cur_sample * of dp by linear interpolation between pitch pattern points. */ { int i; Phone *work_phone; float phon_time; /* Time from the begining of the phoneme */ float curtime= cur_sample*1000.0f/(float)Freq; /* Time in ms */ float return_val; debug_message2("GetPitch %f\n", curtime); /* Left part of the diphone */ if (cur_sample < Length1(dp)) { work_phone=LeftPhone(dp); phon_time= curtime + length_Phone(LeftPhone(dp)) - Length1(dp)/(Freq/1000); /* Too far */ if (phon_time >= length_Phone(LeftPhone(dp))) { Phone *phon=LeftPhone(dp); return (int) ((float)Freq/freq_Pitch(tail_PitchPattern(phon))); } } else /* Right part of the diphone */ { work_phone=RightPhone(dp); phon_time= curtime - Length1(dp)/(Freq/1000) ; } if (phon_time<0.0f) phon_time=0.0f; i=0; while ( (i < work_phone->NPitchPatternPoints) && (phon_time >= work_phone->PitchPattern[i].pos)) i++; if (i>=work_phone->NPitchPatternPoints) return_val= freq_Pitch(tail_PitchPattern(work_phone)); else /* Linear interpolation of pitch value */ return_val= work_phone->PitchPattern[i-1].freq + (work_phone->PitchPattern[i].freq - work_phone->PitchPattern[i-1].freq) /(work_phone->PitchPattern[i].pos - work_phone->PitchPattern[i-1].pos) * (phon_time - work_phone->PitchPattern[i-1].pos); debug_message1("done GetPitch\n"); return( (int)((float)Freq / return_val) ); } mbrola-3.3+dfsg/Engine/diphone.h000066400000000000000000000076611364272575600166110ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: diphone.c * Time-stamp: <2000-04-07 16:55:15 pagel> * Purpose: Phone and diphone objects * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 15/06/98 : Created. Phones, Diphones, ... * 09/09/98 : reset_DiphoneSynthesis function * 24/03/00 : no more limits on period size -> pass frame size during construction */ #ifndef _DIPHONE_H #define _DIPHONE_H #include "phone.h" #include "diphone_info.h" /* * PITCH MARKED DIPHONE DATABASE, CONSTANTS */ #define NBRE_PM_MAX 2000 /* Max nbr of frames in a synth. segment*/ /* * STRUCTURES representing diphone sequences to synthesize */ /* * A DiphoneSynthesis is a Diphone equiped with information necessary to * synthesize it */ typedef struct { /* A Diphone is made of 2 phonemes */ Phone *LeftPhone; /* First phoneme */ Phone *RightPhone;/* Second phoneme */ int Length1; /* Length of first half-phoneme in samples */ int Length2; /* Length of second half-phoneme in samples */ DiphoneInfo* Descriptor; /* Descriptor in the diphone database */ uint8 *p_pmrk; /* Point to the beginning of the pm 1..N interval */ uint8 p_pmrk_offset; /* offset in the 4 bit compressed structure */ int16 *smoothw; /* Difference vector between 2 ola frames (2 mbr_period) */ bool smooth; /* True if Smoothw has a value */ int16* buffer; /* To read or uncompress audio data */ bool buffer_alloced; /* True if pointer above was malloc'ed */ uint8 *real_frame; /* for skiping V - NV transition */ uint8 tot_frame; /* physical number of frames of the diphone */ int nb_pm; /* Number of pitch markers to synthesize */ } DiphoneSynthesis; /* * Convenient macros to access Diphone_synth structures */ #define halfseg_diphone(X) X->Descriptor->halfseg #define nb_frame_diphone(X) X->Descriptor->nb_frame #define pos_wave_diphone(X) X->Descriptor->pos_wave #define left_diphone(MB,X) auxiliary_tab_val( diphone_table(diph_dba(MB)) , X->Descriptor->left) #define right_diphone(MB,X) auxiliary_tab_val( diphone_table(diph_dba(MB)) , X->Descriptor->right) #define Descriptor(X) (X->Descriptor) #define Length1(X) X->Length1 #define Length2(X) X->Length2 #define LeftPhone(X) (X->LeftPhone) #define RightPhone(X) (X->RightPhone) #define nb_pm(X) X->nb_pm #define smoothw(X) X->smoothw #define smooth(X) X->smooth #define buffer(X) X->buffer #define buffer_alloced(X) X->buffer_alloced #define real_frame(X) X->real_frame #define physical_frame_type(X) X->physical_frame_type #define tot_frame(X) X->tot_frame /* At the moment it's a macro */ #define pmrk_DiphoneSynthesis(DP,INDEX) ((DP->p_pmrk[ ( (INDEX-1)+DP->p_pmrk_offset)/ 4 ] >> ( 2*( ((INDEX-1) + DP->p_pmrk_offset)%4))) & 0x3) DiphoneSynthesis* init_DiphoneSynthesis(int mbr_period, int max_pm, int max_sample); /* Alloc memory, working and audio buffers for synthesis */ void reset_DiphoneSynthesis(DiphoneSynthesis* ds); /* * Forget the diphone in progress */ void close_DiphoneSynthesis(DiphoneSynthesis* ds); /* Release memory and phone */ int GetPitchPeriod(DiphoneSynthesis *dp, int cur_sample,int Freq); /* * Returns the pitch period (in samples) at position cur_sample * of dp by linear interpolation between pitch pattern points. */ #endif mbrola-3.3+dfsg/Engine/mbrola.c000066400000000000000000000754321364272575600164330ustar00rootroot00000000000000/* * File: mbrola.c * Purpose: Diphone-based MBROLA speech synthesizer. * Authors: Thierry Dutoit and Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <00/04/11 13:59:18 pagel> * * FPMs-TCTS SOFTWARE LIBRARY * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * This file contains an implementation or Belgian patent BE09600524 * and US Patent Nr. 5,987,413 * * 10/01/97 : Created. * * 22/10/97 : incredible bug with maxnconcat * * 17/06/98 : Mbrola is now pseudo object code with a This pointer * * 31/08/98 : init ola_win to 0 for PCs * bug for 0ms long phonemes * * 04/09/98 : return error code on every floor (to replace catch/throw) * * 08/09/98 : correct double memory free in case of reset_Mbrola * correct leftPhone and rightPhone affectation order for cur_diph * to avoid memory leak in case of premature ending * * 18/05/99 : decrement zero_padding() and add a condition not to overlap * with phonemes having 0ms length * * 10/06/99 : ola_win is zeroed in reset_Mbrola instead of init_Mbrola * (clean buffer in case of playback interruption) * * 05/09/99 : boundcheck on "first" in Concat * * 28/03/00 : Rom databases, malloc'ed diphone buffers * Test in Concat for degenerated case "0ms long phonemes" */ #include #include "common.h" #include "diphone.h" #include "database.h" #include "audio.h" #include "hash_tab.h" #include "parser.h" #include "mbrola.h" void init_Hanning(float* table,int size,float ratio) /* * Initialize the Hanning weighting window * Ratio is used for volume control (Volume is embedded in hanning to * spare a multiplication later ...) */ { int i; for (i=0; i it will give a first value for prev_diph when we make the first * NextDiphone call so that cur_diph= _-FirstPhon with lenght1=0 * and prev_diph= _-_ with length2=0 * * return False in case of error */ { int i; debug_message1("reset_Mbrola\n"); /* Free residual phonemes * Right phoneme of prev_diph, and Left phoneme of cur_diph are shared. * So to avoid double desallocation, scratch one */ reset_DiphoneSynthesis(cur_diph(mb)); RightPhone(prev_diph(mb))=NULL; reset_DiphoneSynthesis(prev_diph(mb)); /* Set dummy cur_diphone with empty value */ LeftPhone(cur_diph(mb)) = init_Phone( sil_phon(diph_dba(mb)), 0.0); RightPhone(cur_diph(mb)) = init_Phone( sil_phon(diph_dba(mb)), 0.0); if (!diph_dba(mb)->getdiphone_Database( diph_dba(mb), cur_diph(mb) )) { fatal_message( ERROR_DBNOSILENCE, "_-_ PANIC with %s!\n", sil_phon(diph_dba(mb))); return False; } /* Indicate we don't generate anything with the first _-_ diphone */ nb_pm(cur_diph(mb))=1; /* The ola window is null from the start */ for (i=0; i< 2*MBRPeriod(diph_dba(mb)); i++) ola_win(mb)[i]=0.0f; #ifdef LIBRARY /* Indicate that the first call to read_MBR must trigger an initialization */ first_call(mb)=True; #endif debug_message1("done reset_Mbrola\n"); return True; } StatePhone NextDiphone(Mbrola* mb) /* * Reads a phone from the phonetic command buffer and prepares the next * diphone to synthesize ( prev_diph ) * Return value may be: PHO_EOF,PHO_FLUSH,PHO_OK, PHO_ERROR */ { int len_left, len_right, tot_len; float wanted_len; int len_anal; /* Number of sample in last segment analysed */ Phone* my_phone; StatePhone state; DiphoneSynthesis *temp; debug_message1("NextDiphone\n"); if ((state=parser(mb)->nextphone_Parser(parser(mb),&my_phone))!=PHO_OK) { debug_message1("done NextDiphone PHO_NOT_OK\n"); return(state); } /* length and freq modified if the vocal tract length is not 1.0 */ applyRatio_Phone(my_phone,VoiceRatio(mb)); /* Prev_diph has been used ... release LeftPhone * don't RightPhone, as reference on it is still active in cur_diph */ if (LeftPhone(prev_diph(mb))) { close_Phone(LeftPhone(prev_diph(mb))); /* once used, release the phoneme */ LeftPhone(prev_diph(mb))=NULL; } /* Shift the diphone being worked on */ /* prev_diph is the one that will be synthesized */ temp=prev_diph(mb); prev_diph(mb)=cur_diph(mb); cur_diph(mb)=temp; /* Initialize minimal info of the new cur_diph */ RightPhone(cur_diph(mb))= my_phone; LeftPhone(cur_diph(mb)) = RightPhone(prev_diph(mb)); /* Reuse common part ! */ /* * Load the diphone from the database !! */ if ( ! diph_dba(mb)->getdiphone_Database( diph_dba(mb), cur_diph(mb)) ) { bool success= False; /* then ... we failed */ /* Try to arrange a solution for the missing diphone */ if (no_error(mb)) { PhonemeName temp_left= name_Phone( LeftPhone( cur_diph(mb))); PhonemeName temp_right= name_Phone( RightPhone( cur_diph(mb))); warning_message(ERROR_UNKNOWNSEGMENT, "Warning: %s-%s unknown, replaced with _-_\n", name_Phone(LeftPhone( cur_diph(mb))), name_Phone(RightPhone( cur_diph(mb)))); /* Momentary replacement with _-_ */ name_Phone( LeftPhone( cur_diph(mb)))= sil_phon( diph_dba(mb)); name_Phone( RightPhone( cur_diph(mb)))= sil_phon(diph_dba(mb)); success= diph_dba(mb)->getdiphone_Database( diph_dba(mb), cur_diph(mb)); /* Restore situation */ name_Phone( LeftPhone( cur_diph(mb)))= temp_left; name_Phone( RightPhone( cur_diph(mb)))= temp_right; } if (!success) { fatal_message(ERROR_UNKNOWNSEGMENT, "Fatal error: Unknown recovery for %s-%s segment\n", name_Phone(LeftPhone(cur_diph(mb))), name_Phone(RightPhone(cur_diph(mb)))); return PHO_ERROR; } } /* * Computation of length of 2nd part of prev_diph and of 1st part of current * one : current phoneme gives current diphone => impose length of 2nd * part of previous and of 1st part of current one proportionally to their * relative importance in the database. * Ex : phoneme sequence = A B C. When synthesizer receives C, B-C is * scheduled, and the length of B in A-B and B-C are derived. Synthesis of * A-B can then start. */ len_anal = ( nb_frame_diphone(prev_diph(mb)) ) * MBRPeriod(diph_dba(mb)); len_left= len_anal - halfseg_diphone(prev_diph(mb)); len_right= halfseg_diphone(cur_diph(mb)) ; tot_len=len_left+len_right; wanted_len= length_Phone( LeftPhone(cur_diph(mb)) ); Length2(prev_diph(mb))= (int) (wanted_len * (float)len_left * (float)Freq(diph_dba(mb)) / 1000.0f / (float)tot_len) ; Length1(cur_diph(mb)) = (int) (wanted_len * (float) Freq(diph_dba(mb)) / 1000.0f - Length2(prev_diph(mb))) ; debug_message3("done NextDiphone PHO_OK -> %s-%s\n", name_Phone(RightPhone(prev_diph(mb))), name_Phone(my_phone)); return(PHO_OK); } bool MatchProsody(Mbrola* mb) /* * Selects Duplication or Elimination for each analysis OLA frames of * the diphone we must synthesize (prev_diph). Selected frames must fit * with wanted pitch pattern and phonemes duration of prev_diph * * Return False in case of error */ { int nb_frame; /* Nbr of pitch markers in the database segment*/ float theta1; /* Time warping coefficients */ float theta2=0.0f; float beta=0.0f; int halfseg; /* Index (in samples) of center of diphone */ int cur_sample; /* sample offset in synthesis window */ int t; /* time in analysis window */ int limit; /* sample where to stop */ int i; int k; /* dummy variable !!! */ int len_anal; /* Number of sample in last segment analysed */ int start; int old_len1; /* Length1 in samples before adjustment */ debug_message1("MatchProsody\n"); /* Modify the length of the 2nd part of a phone if the end of its 1st part does not correspond to its theoretical value */ start=(int) ( length_Phone(LeftPhone(prev_diph(mb))) - Length1(prev_diph(mb)) / (Freq(diph_dba(mb))*1000.0f)); old_len1=Length1(prev_diph(mb)); if (old_len1>0) { Length1(prev_diph(mb))+= last_time_crumb(mb) ; /* redraw pitch curve with new length */ for (i=0; i< NPitchPatternPoints(LeftPhone(prev_diph(mb))) ;i++) if (PitchPattern(LeftPhone(prev_diph(mb)))[i].pos > start) { PitchPattern(LeftPhone(prev_diph(mb)))[i].pos= start+ (PitchPattern(LeftPhone(prev_diph(mb)))[i].pos - start) * Length1(prev_diph(mb))/old_len1; } } nb_frame = nb_frame_diphone(prev_diph(mb)); halfseg = halfseg_diphone(prev_diph(mb)); len_anal = nb_frame * MBRPeriod(diph_dba(mb)); theta1 = ((float) Length1(prev_diph(mb))) / (float) halfseg; if (len_anal-halfseg!=0) { theta2 = ((float) Length2(prev_diph(mb))) / (float) (len_anal-halfseg); beta = (float) Length1(prev_diph(mb)) - (theta2*halfseg); } /* * Assign to each synthesis frame the corresponding one in segment analysis */ frame_number(mb)[0]=1; frame_pos(mb)[0]=0; k=1; /* first window pos (sample) */ debug_message3("matchpro %i= %i\n",nb_frame, pmrk_DiphoneSynthesis( prev_diph(mb), 1)); if ( pmrk_DiphoneSynthesis( prev_diph(mb), 1) & VOICING_MASK ) { cur_sample = GetPitchPeriod(prev_diph(mb), 0, Freq(diph_dba(mb))); } else { cur_sample = MBRPeriod(diph_dba(mb)); } t= MBRPeriod(diph_dba(mb)); /* stride through analysis frames */ for(i=1; i<=nb_frame ;i++) { if (t <= halfseg) /* Left phone */ limit = (int) (t*theta1); else /* Right phone */ limit = (int) (t*theta2 + beta); /* Stride through synthesis windows */ while (cur_sample <= limit) { frame_number(mb)[k]=i; /* NB : first frame number = 1 */ frame_pos(mb)[k]= cur_sample; k++; debug_message3("match %i= %i\n", i, pmrk_DiphoneSynthesis( prev_diph(mb), i)); if (pmrk_DiphoneSynthesis( prev_diph(mb), i) & VOICING_MASK ) { cur_sample += GetPitchPeriod(prev_diph(mb),cur_sample,Freq(diph_dba(mb))); } else { cur_sample += MBRPeriod(diph_dba(mb)); } if (k>=NBRE_PM_MAX) { fatal_message( ERROR_PITCHTOOHIGH, "%s-%s Concat : PANIC, check your pitch :-)\n", name_Phone(LeftPhone(prev_diph(mb))), name_Phone(RightPhone(prev_diph(mb)))); return False; } } t=t+MBRPeriod(diph_dba(mb)); } frame_number(mb)[k]=0; /* End tag */ nb_pm(prev_diph(mb)) = k-1; /* Number of pitchmarks for synthesis */ /* total length that should have been synthesized -last effective sample */ last_time_crumb(mb)+= (old_len1+Length2(prev_diph(mb))) - frame_pos(mb)[k-1] ; debug_message1("done MatchProsody\n"); return True; } void Concat(Mbrola* mb) /* * This is a unique feature of MBROLA. * Smoothes diphones around their concatenation point by making the left * part fade into the right one and conversely. This is possible because * MBROLA frames have the same length everywhere. * * output : nb_begin, nb_end -> number of stable voiced frames to be used * for interpolation at the end of Leftphone(prev_diph(mb)) and the beginning * of RightPhone(prev_diph(mb)). */ { int c; int begin, end; /* Nbr of voiced frames at begining and end of prev_diph(mb)*/ int first,last; /* Number of the first frame */ int last_frame, first_frame; /* offset in sample for the last and first */ /* frame of concatenation point */ int16 *buff_left; /* speech buffer on left of junction */ int16 *buff_right; /* speech buffer on right of junction */ int i,j; int cur_sample; /* sample offset in synthesis window */ int maxnconcat; int limitframe; debug_message1("Concat\n"); /* We compute the first Olaed frame for cur_diph -> we can't do * Matchprosody on it yet since we lack pitch points... * But at least we have a pitch point at 0 for cur_diph */ cur_sample = GetPitchPeriod(cur_diph(mb), 0, Freq(diph_dba(mb))); if (Length1(cur_diph(mb))!=0) { float theta= ((float) Length1(cur_diph(mb))) / halfseg_diphone(cur_diph(mb)); /* Use CEIL as first belongs to [1..N] */ first= (int) ceil((double)cur_sample / MBRPeriod(diph_dba(mb)) / theta); } else { first=0; /* 0 length phonemes */ } if (first > frame_number(mb)[ nb_pm(cur_diph(mb)) ]) { first= frame_number(mb)[ nb_pm(cur_diph(mb)) ]; } last= frame_number(mb)[nb_pm(prev_diph(mb))]; if ( (first!=0) && /* Degenerated case= phoneme with 0ms length */ (pmrk_DiphoneSynthesis( prev_diph(mb), last ) & VOICING_MASK) && (pmrk_DiphoneSynthesis( cur_diph(mb), first ) & VOICING_MASK)) { /* Difference vector beetween LAST and FIRST Voiced frame */ smooth(cur_diph(mb))=True; /* buffer goes from 0 to NB_SAMPLE while real_frame goes from 1 to N */ last_frame = MBRPeriod(diph_dba(mb)) * ( real_frame(prev_diph(mb))[last] -1 ); buff_left= &buffer(prev_diph(mb))[last_frame]; first_frame = MBRPeriod(diph_dba(mb)) * (real_frame(cur_diph(mb))[first] -1 ); buff_right= &buffer(cur_diph(mb))[first_frame]; /* For the first half, no problem */ for(i=0;i6) maxnconcat=6; begin=1; while ((pmrk_DiphoneSynthesis(prev_diph(mb), frame_number(mb)[begin]) == V_REG) && (frame_number(mb)[begin] <= limitframe) && (begin < maxnconcat)) begin++; /* if VREG VREG ... VREG VTRA : smooth VTRA too */ if ( ( begin>1 ) && ( pmrk_DiphoneSynthesis(prev_diph(mb),frame_number(mb)[begin]) == V_TRA) && ( frame_number(mb)[begin] <= limitframe) && ( begin < maxnconcat)) begin++; nb_begin(mb) = begin -1; /* Check previous value of nb_end */ if (nb_begin(mb) > nb_end(mb)) nb_begin(mb)=nb_end(mb); debug_message2("nb_begin %i \n", nb_begin(mb)); end=1; c=nb_pm(prev_diph(mb))+1; while ((pmrk_DiphoneSynthesis(prev_diph(mb),frame_number(mb)[c-end]) == V_REG) && (frame_number(mb)[c-end] > limitframe) && (end < maxnconcat)) end++; /* if VTRA VREG VREG ... VREG : smooth VTRA too */ if ((end > 1) && (pmrk_DiphoneSynthesis(prev_diph(mb),frame_number(mb)[c-end]) == V_TRA) && (frame_number(mb)[c-end] > limitframe) && (end < maxnconcat)) end++; nb_end(mb) = end - 1; /* simplification: just check 1st frame of cur_diph, if not * voiced, no interpolation at end of prev_diph(mb) */ if (pmrk_DiphoneSynthesis(cur_diph(mb), 1) != V_REG) nb_end(mb)=0; debug_message2("end %i ", nb_end(mb)); debug_message1("done Concat\n"); } void FlushFile(Mbrola* mb, int shift, int shift_zero) /* * Flush on file what's computed */ { int k; for (k=0;k 32765) { saturation(mb)=True; ola_integer(mb)[k]=32765; } else if (ola_win(mb)[k] < -32765) { saturation(mb)=True; ola_integer(mb)[k]=-32765; } else ola_integer(mb)[k]= (int16) ola_win(mb)[k]; } /* Amount that has been flushed */ buffer_shift(mb)=shift; /* Zero padding ! */ zero_padding(mb)= shift_zero; #ifndef LIBRARY audio_length(mb)+= write_int16s(ola_integer(mb), shift, output_file); /* Fill the gap between 2 frames for extra low pitch */ /* No lower limit, but write MBRPeriod buffer each time */ if (shift_zero>0) { int shift_mod; /* Modulo for shift zero */ int written; if (shift_zero>2*MBRPeriod(diph_dba(mb))) shift_mod=2*MBRPeriod(diph_dba(mb)); else shift_mod=shift_zero; for (k=0; k2*MBRPeriod(diph_dba(mb))) { written= write_int16s(ola_integer(mb), 2*MBRPeriod(diph_dba(mb)), output_file); buffer_shift(mb)+=written; audio_length(mb)+=written; shift_zero-=written; } written= write_int16s(ola_integer(mb),shift_zero, output_file); audio_length(mb)+=written; buffer_shift(mb)+=written; } #endif } void OverLapAdd(Mbrola* mb, int frame) /* * OLA routine */ { int k; float correction; /* Energy correction factor */ int end_window, add_window; int lim_smooth; /* Beyond this limit -> left smoothing */ float tmp; FrameType type; /* Frame type */ int shift_zero; /* Noman's land between 2 ola filled with 0 */ int shift; /* Shift between pulses */ debug_message1("OverLapAdd\n"); shift = frame_pos(mb)[frame]-frame_pos(mb)[frame-1]; if ((correction = (float)shift/(float)MBRPeriod(diph_dba(mb)))>=1) correction=1.0f; /* Keep nothing of previous frames as there's no overlap */ shift_zero= shift - 2*MBRPeriod(diph_dba(mb)); if (shift_zero>0) shift= 2*MBRPeriod(diph_dba(mb)); end_window = 2*MBRPeriod(diph_dba(mb)) - shift; add_window =MBRPeriod(diph_dba(mb)) * (real_frame(prev_diph(mb))[frame_number(mb)[frame]]-1); lim_smooth = nb_pm(prev_diph(mb))-nb_end(mb); /* Flush on file what's flushable */ FlushFile(mb,shift,shift_zero); if (saturation(mb)) { warning_message(WARNING_SATURATION, "Saturation on %s-%s\n", name_Phone(LeftPhone(prev_diph(mb))), name_Phone(RightPhone(prev_diph(mb)))); saturation(mb)=False; } /* !! SHIFTING CAN BE REMOVED IN CASE OF STATIC OUTPUT BUFFER !! */ /* shift the ola window and completion with 0 */ memmove(&ola_win(mb)[0], &ola_win(mb)[shift], end_window*sizeof(ola_win(mb)[0])); for(k=end_window; k<2*MBRPeriod(diph_dba(mb)) ; k++) ola_win(mb)[k]=0.0f; /* Two kinds of OLA depending if the frame is unvoiced */ type= pmrk_DiphoneSynthesis(prev_diph(mb), frame_number(mb)[frame] ); debug_message5("Frame type=%i Number=%i Real=%i Smooth=%i\n", type, frame_number(mb)[frame], real_frame(prev_diph(mb))[frame_number(mb)[frame]], smooth(prev_diph(mb))); if (! (type & VOICING_MASK)) { /* UNVOICED FRAME => PLAY BACK */ if ( (frame<=nb_begin(mb))|| (frame>lim_smooth)) warning_message(ERROR_SMOOTHING,"Smooth Panic! Stay cool"); /* Check if we're duplicating an unvoiced frame */ if ( odd(mb) && (frame_number(mb)[frame] == frame_number(mb)[frame-1])) { /* reverse every second duplicated UV frame */ add_window=add_window+2*MBRPeriod(diph_dba(mb))-1; for (k=0; k< 2*MBRPeriod(diph_dba(mb)) ; k++) { tmp = weight(mb)[k] * (float) buffer(prev_diph(mb))[add_window - k]; /* Energy correction */ tmp *= correction; ola_win(mb)[k] += tmp; } } else /* Don't reverse the unvoiced frame */ { for (k=0; k< 2*MBRPeriod(diph_dba(mb)) ; k++) { tmp = weight(mb)[k] * (float) buffer(prev_diph(mb))[add_window + k]; /* Energy correction */ tmp *= correction; ola_win(mb)[k] += tmp; } } } else { /* Meeep meeep, you're entering a restrictead area, helmet is * recommended if you don't have rights to exploit Belgian * patent BE09600524 or US Patent Nr. 5,987,413 * * Voiced frame -> autoloop ! MBROLA unique feature !! * Many case depending on smoothing or not */ if ((frame<=nb_begin(mb)) && smooth(prev_diph(mb)) && smoothing(mb) ) /* Left smoothing */ { float smooth_left = (float)(nb_begin(mb)-frame+1) / (2*(float)nb_begin(mb)); for (k=0; klim_smooth) && smooth(cur_diph(mb)) && smoothing(mb) ) /* Right smoothing */ { float smooth_right= (float)(nb_end(mb)-(nb_pm(prev_diph(mb))-frame)) /(2*(float)nb_end(mb)); for (k=0; k0) { /* Zero padding between 2 Ola frames for extra low pitch */ if (zero_padding(mb)>0) { int nb_generated; if ( zero_padding(mb) > to_go) nb_generated= to_go; else nb_generated= zero_padding(mb); /* decrement in case the requested buffer is very small */ zero_padding(mb)-= nb_generated; buffer_out= zero_convert( buffer_out,nb_generated, sample_type ); if (!buffer_out) return lasterr_code; to_go -= nb_generated; } /* Available frames from previous OLA */ if (to_go > (buffer_shift(mb)-eaten(mb))) nb_move= buffer_shift(mb)-eaten(mb); else nb_move= to_go; buffer_out= move_convert( buffer_out, &ola_integer(mb)[eaten(mb)], nb_move, sample_type ); if (!buffer_out) return lasterr_code; to_go-= nb_move; eaten(mb)+= nb_move; if (to_go<=0) break; /* Still some frames available in the same diphone ? */ if (frame_counter(mb) flush and continue */ debug_message1("Synthesis\n"); /* * Put something in the pipe, and initialization of junk diphone cur_diph * that will be prev_diph at time of Concat -> needed for "buff_left" */ NextDiphone(mb); /* standalone mode */ #ifndef SIGNAL while ((stream_state=NextDiphone(mb)) == PHO_OK) oneshot_Mbrola(mb); #else while ( ((stream_state=NextDiphone(mb)) == PHO_OK) && !must_flush ) oneshot_Mbrola(mb); /* Reset signal */ if (must_flush) { /* Eat remaining phones before a flush */ while (stream_state == PHO_OK) { stream_state= NextDiphone(mb); } warning_message(1,"Input Flush Signal\n"); must_flush=False; /* reset until next call ! */ } #endif debug_message1("done Synthesis\n"); return(stream_state); } #endif mbrola-3.3+dfsg/Engine/mbrola.h000066400000000000000000000161101364272575600164240ustar00rootroot00000000000000/* * File: mbrola.h * Time-stamp: <00/04/11 13:13:16 pagel> * Purpose: Diphone-based MBROLA speech synthesizer. * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * FPMs-TCTS SOFTWARE LIBRARY * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #ifndef _MBROLA_H #define _MBROLA_H #include "diphone.h" #include "database.h" #include "parser.h" #ifndef LIBRARY #include "synth.h" #endif typedef struct { Database* diph_dba; /* A synth engine is linked to a database */ Parser* parser; /* Phonemic command stream */ /* * prev_diph points to the previous diphone synthesis structure * and cur_diph points to the current one. The reason is that to * synthesize the previous diphone we need information on the next * one. While progressing to the next diphone, prev_diph memory is * resetted the pointers are swapped between cur and prev diphones */ DiphoneSynthesis *prev_diph, *cur_diph; /* Last_time_crumb balances slow time drifting in match_proso. time_crumb is * the difference in samples between the length really synthesized and * theoretical one */ int last_time_crumb; float FirstPitch; /* default first F0 Value (fetched in the database) */ int32 audio_length; /* File size, used for file formats other than RAW */ int frame_number[NBRE_PM_MAX]; /* for match_prosody */ int frame_pos[NBRE_PM_MAX]; /* frame position for match_prosody */ int nb_begin; int nb_end; /* number of voiced frames at the begin and end the segment */ bool saturation; /* Saturation in ola_integer */ float *ola_win; /* OLA buffer */ int16 *ola_integer; /* OLA buffer for file output */ float *weight; /* Hanning weighting window */ float volume_ratio; /* 1.0 is default */ /* * The following variables are part of the structure for library mode * but could be local for standalone mode */ bool odd; /* flip-flop for reversing 1 out of 2 unvoiced OLA frame */ int frame_counter; /* frame being OLAdded */ int buffer_shift; /* Shift between 2 Ola = available for output */ int zero_padding; /* 0's between 2 Ola = available for output */ bool smoothing; /* True if the smoothing algorithm is on */ bool no_error; /* True to ignore missing diphones */ uint16 VoiceFreq; /* Freq of the audio output (vocal tract length) */ float VoiceRatio; /* Freq ratio of the audio output */ #ifdef LIBRARY bool first_call; /* True if it's the first call to Read_MBR */ int eaten; /* Samples allready consumed in ola_integer */ #endif } Mbrola; /* Convenience macros */ #define diph_dba(mb) mb->diph_dba #define parser(mb) mb->parser #define prev_diph(mb) mb->prev_diph #define cur_diph(mb) mb->cur_diph #define last_time_crumb(mb) mb->last_time_crumb #define FirstPitch(mb) mb->FirstPitch #define audio_length(mb) mb->audio_length #define frame_number(mb) mb->frame_number #define frame_pos(mb) mb->frame_pos #define nb_begin(mb) mb->nb_begin #define nb_end(mb) mb->nb_end #define saturation(mb) mb->saturation #define ola_win(mb) mb->ola_win #define ola_integer(mb) mb->ola_integer #define weight(mb) mb->weight #define volume_ratio(mb) mb->volume_ratio #define odd(mb) mb->odd #define frame_counter(mb) mb->frame_counter #define buffer_shift(mb) mb->buffer_shift #define zero_padding(mb) mb->zero_padding #define smoothing(mb) mb->smoothing #define no_error(mb) mb->no_error #define VoiceRatio(pt) (pt->VoiceRatio) #define VoiceFreq(pt) (pt->VoiceFreq) #define first_call(pt) (pt->first_call) #define eaten(pt) (pt->eaten) void set_voicefreq_Mbrola(Mbrola* mb, uint16 OutFreq); /* Change the Output Freq and VoiceRatio to change the vocal tract */ uint16 get_voicefreq_Mbrola(Mbrola* mb); /* Get output Frequency */ void set_smoothing_Mbrola(Mbrola* mb, bool smoothing); /* Spectral smoothing or not */ bool get_smoothing_Mbrola(Mbrola* mb); /* Spectral smoothing or not */ void set_no_error_Mbrola(Mbrola* mb, bool no_error); /* Tolerance to missing diphones */ bool get_no_error_Mbrola(Mbrola* mb); /* Spectral smoothing or not */ void set_volume_ratio_Mbrola(Mbrola* mb, float volume_ratio); /* Overall volume */ float get_volume_ratio_Mbrola(Mbrola* mb); /* Overall volume */ void set_parser_Mbrola(Mbrola* mb, Parser* parser); /* drop the current parser for a new one */ Mbrola* init_Mbrola(Database* dba); /* * Connect the database to the synthesis engine, then initialize internal * variables. Connect the phonemic command stream later with set_parser_Mbrola */ void close_Mbrola(Mbrola* mb); /* close related features and free the memory ! */ bool reset_Mbrola(Mbrola* mb); /* * Gives initial values to current_diphone (not synthesized anyway) * -> it will give a first value for prev_diph when we make the first * NextDiphone call so that cur_diph= _-FirstPhon with lenght1=0 * and prev_diph= _-_ with length2=0 * * return False in case of error */ StatePhone NextDiphone(Mbrola* mb); /* * Reads a phone from the phonetic command buffer and prepares the next * diphone to synthesize ( prev_diph ) * Return value may be: PHO_EOF, PHO_FLUSH, PHO_OK, PHO_ERROR */ bool MatchProsody(Mbrola* mb); /* * Selects Duplication or Elimination for each analysis OLA frames of * the diphone we must synthesize (prev_diph). Selected frames must fit * with wanted pitch pattern and phonemes duration of prev_diph * * Return False in case of error */ void Concat(Mbrola* mb); /* * This is a unique feature of MBROLA. * Smoothes diphones around their concatenation point by making the left * part fade into the right one and conversely. This is possible because * MBROLA frames have the same length everywhere plus phase trick. * * output : nb_begin, nb_end -> number of stable voiced frames to be used * for interpolation at the end of Leftphone(prev_diph) and the beginning * of RightPhone(prev_diph). */ void OverLapAdd(Mbrola* mb, int frame); /* * OLA routine */ #ifdef LIBRARY /* LIBRARY mode: synthesis driven by the output */ int readtype_Mbrola(Mbrola* mb, void *buffer_out, int nb_wanted, AudioType sample_type); /* * Reads nb_wanted samples in an audio buffer * Returns the effective number of samples read */ #else /* STANDALONE MODE: Synthesis driven by the input */ StatePhone Synthesis(Mbrola* mb); /* * Main loop: performs MBROLA synthesis of all diphones * Returns a value indicating the reasons of the break * (a flush request, a end of file, end of phone sequence) */ #endif #endif mbrola-3.3+dfsg/LICENSE000066400000000000000000001033331364272575600146030ustar00rootroot00000000000000 GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . mbrola-3.3+dfsg/LibMultiChannel/000077500000000000000000000000001364272575600166055ustar00rootroot00000000000000mbrola-3.3+dfsg/LibMultiChannel/demo2.c000066400000000000000000000136021364272575600177610ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * Time-stamp: <1998-10-21 16:19:14 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * File: demo2.c * Purpose: demo of multiple channel synthesis * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * 01/09/98: Created */ #include #include #include "common.h" #include "parser.h" /* Those includes depend on the parser you are using */ #include "input_fifo.h" #include "parser_input.h" #include "input_fifo.h" /* end of default parser include */ #include "multichannel.h" #include "mbrola.h" short buffer[16000]; #define True 1 #define False 0 void handle_error(int Fatal) { char err[255]; lastErrorStr_MBR2(err,sizeof(err)); printf("Code %i\n%s\n", lastError_MBR2(), err); if (Fatal) exit(-1); } int WriteSpeechFile(Mbrola* mb,FILE *output, AudioType type, char size) /* Read audio while available (out of input data or flush */ { int i; while ((i=readtype_MBR2(mb,buffer,16000,type))==16000) fwrite(buffer,size,i,output); if (i>0) { fwrite(buffer,size,i,output); return 0; } else { return i; } } int main(int argc, char **argv) { /* Audio output file for each channel */ FILE *output1; FILE *output2; FILE *output3; /* The diphone database */ Database* main_dba; /* the main instance */ Database* clone_dba1; /* secondary instances for different channels */ Database* clone_dba2; Database* clone_dba3; /* Parser providing the phonemic input to the engine */ Parser* parser1; Parser* parser2; Parser* parser3; /* Fifo associated with each Input */ Fifo* fifo1; Fifo* fifo2; Fifo* fifo3; /* Input associated with each parser */ Input* input1; Input* input2; Input* input3; /* One synthesis engine for each channel */ Mbrola* channel1; Mbrola* channel2; Mbrola* channel3; if (argc!=2) { printf("synthlib ../fr1\n"); return 1; } /* open the dba with no renaming */ main_dba= init_DatabaseMBR2(argv[1],NULL,NULL); if (!main_dba) handle_error(True); output1=fopen("res1.ulaw","wb"); output2=fopen("res2.raw","wb"); output3=fopen("res3.lin8","wb"); /* * The section of code below depends on your implementation * of the phoneme parser. We use here the Mbrola default * parser, but you could use your own (* as long as it * follows the generic parser.h interface *) */ /* Input Fifo with a buffer of 100 chars */ fifo1= init_Fifo(100); fifo2= init_Fifo(100); fifo3= init_Fifo(100); /* Input stream of the synthesizer */ input1= init_InputFifo(fifo1); input2= init_InputFifo(fifo2); input3= init_InputFifo(fifo3); /* Plug the fifos on the default parsers */ parser1= init_ParserInput(input1,"_",120.0,1.0,1.0,";",NULL); parser2= init_ParserInput(input2,"_",120.0,1.0,1.0,";",NULL); parser3= init_ParserInput(input3,"_",120.0,1.0,1.0,";",NULL); /* * End of parser dependent part */ /* * Build the databases for each channel, the database handler * occupies little memory */ clone_dba1= copyconstructor_DatabaseMBR2(main_dba); clone_dba2= copyconstructor_DatabaseMBR2(main_dba); clone_dba3= copyconstructor_DatabaseMBR2(main_dba); if (!clone_dba1 || !clone_dba2 || !clone_dba3) handle_error(True); /* * Plug everything in the different engines, they all use * the same physical database */ channel1= init_MBR2(clone_dba1,parser1); channel2= init_MBR2(clone_dba2,parser2); channel3= init_MBR2(clone_dba3,parser3); if (!channel1 || !channel2 || !channel3) handle_error(True); /* * Send the data to synthesize */ /* write_Fifo(fifo1,";; F=0.2\n"); */ if ((write_Fifo(fifo1,"_ 51 \n b 62 \n")<0) || (write_Fifo(fifo1,"o~ 127 50 170 \n Z 110\n")<0) || (WriteSpeechFile(channel1,output1,ULAW,1)<0) || (write_Fifo(fifo1,"u 211 100 200\n R 150 \n_ 9\n#\n")<0)|| (WriteSpeechFile(channel1,output1,ULAW,1))) handle_error(False); if ((write_Fifo(fifo2,"_ 51 \n b 62 \n")<0) || (write_Fifo(fifo2,"o~ 127 50 170 \n Z 110\n")<0) || (WriteSpeechFile(channel2,output2,LIN16,2)<0) || (write_Fifo(fifo2,"u 211 100 200\n R 150 \n_ 9\n#\n")<0) || (WriteSpeechFile(channel2,output2,LIN16,2)<0)) handle_error(False); if ((write_Fifo(fifo3,"_ 51 \n b 62 \n")<0) || (write_Fifo(fifo3,"o~ 127 50 170 \n Z 110\n")<0) || (WriteSpeechFile(channel3,output3,LIN8,1)<0) || (write_Fifo(fifo3,"u 211 100 200\n R 150 \n_ 9\n#\n")<0) || (WriteSpeechFile(channel3,output3,LIN8,1)<0)) handle_error(False); /* * It's over, release the memory */ close_MBR2(channel1); fclose(output1); close_MBR2(channel2); fclose(output2); close_MBR2(channel3); fclose(output3); /* Close the database */ close_DatabaseMBR2(clone_dba1); close_DatabaseMBR2(clone_dba2); close_DatabaseMBR2(clone_dba3); /* The main instance MUST'nt be closed before any of its clone */ close_DatabaseMBR2(main_dba); /* Close polymorhpic parser */ close_ParserMBR2(parser1); close_ParserMBR2(parser2); close_ParserMBR2(parser3); /* * The code below is dependent on the parser implementation */ input1->close_Input(input1); input2->close_Input(input2); input3->close_Input(input3); close_Fifo(fifo1); close_Fifo(fifo2); close_Fifo(fifo3); /* * End of parser dependent code */ return(0); } mbrola-3.3+dfsg/LibMultiChannel/lib2.c000066400000000000000000000045731364272575600176120ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * Copyright (c) 95 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * File: lib2.c * Purpose: Wrapper to build a all-in-one library version of the * multi-channel mode * * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * 2/09/98: Created * Used to hide mbrola file structure from the outside when distributing * lib */ #define MULTI_CHANNEL #define LIBRARY #include "../Misc/common.h" #include "../Misc/vp_error.h" #include "../Misc/mbralloc.h" #include "../Engine/diphone.h" #include "../Engine/mbrola.h" #include "../Database/database.h" #include "../Database/database_old.h" #include "../Misc/audio.h" #include "../Parser/parser.h" #include "../Parser/input_fifo.h" #include "../Parser/parser_input.h" #include "../Database/hash_tab.h" #include "../LibMultiChannel/multichannel.h" #include "../Misc/mbralloc.c" #include "../Database/little_big.c" #include "../Misc/common.c" #include "../Parser/phone.c" #include "../Engine/diphone.c" #include "../Misc/g711.c" #include "../Misc/audio.c" #include "../Engine/mbrola.c" #include "../Database/diphone_info.c" #include "../Database/database_old.c" #include "../Database/database.c" #include "../Database/zstring_list.c" #include "../Parser/phonbuff.c" #include "../Parser/fifo.c" #include "../Parser/parser_input.c" #include "../Parser/input_fifo.c" #include "../Database/hash_tab.c" #include "../LibMultiChannel/multichannel.c" #include "../Misc/vp_error.c" #ifdef BACON #include "../Database/database_bacon.c" #endif #ifdef CEBAB #include "../Database/database_cebab.c" #endif #if defined(ROMDATABASE_STORE) || defined(ROMDATABASE_INIT) #include "../Database/rom_database.c" #include "../Database/rom_handling.c" #endif mbrola-3.3+dfsg/LibMultiChannel/multichannel.c000066400000000000000000000133361364272575600214420ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * Time-stamp: <2000-03-28 18:03:07 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * File: multichannel.c * Purpose: instanciation of multiple channel from one dba * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * 22/06/98: Created * 23/08/98: Correction in close_MBR2 (bug detected by Susan Eisman) * Change function names for consistence * * 03/09/98: close_MBR2 don't have to close the database and parser... * export the kit init/close_Database for the DLL client * * 09/09/98: 3.01d -> reset_MBR2 now returns a success value * first_call(mb) goes back to where it belongs (Mbrola) * and correct a bug with init/reset_MBR2 * 20/10/98: 3.01g -> pass flush symbol. Avoid the variable "rename" due to * exisiting functions in libraries */ #include "common.h" #include "diphone.h" #include "audio.h" #include "mbrola.h" #include "database.h" #include "input_fifo.h" #include "input_file.h" #include "incdll.h" Database* DLL_EXPORT init_DatabaseMBR2(char* dbaname, char* rename_string, char* clone_string) /* * Give the name of the file containing the database, and parameters to * rename of clone phoneme names * * NULL on rename or clone means no modification to the database */ { ZStringList* rename_list=NULL; /* phoneme renaming */ ZStringList* clone_list=NULL; /* phoneme cloning */ if (rename_string) { rename_list= init_ZStringList(); parse_ZStringList(rename_list, rename_string, False); } if (clone_string) { clone_list= init_ZStringList(); parse_ZStringList(clone_list, clone_string, True); } return init_rename_Database(dbaname, rename_list, clone_list); } Database* DLL_EXPORT copyconstructor_DatabaseMBR2(Database* dba) /* Creates a copy of a diphone database so that many synthesis engine * can use the same database at the same time (duplicate the file handler) * * Highly recommended with multichannel mbrola, unless you can guaranty * mutually exclusive access to the getdiphone function */ { return copyconstructor_Database(dba); } void DLL_EXPORT close_DatabaseMBR2(Database* dba) /* * Release the memory of the polymorphic type */ { dba->close_Database(dba); /* virtual destructor */ } void DLL_EXPORT close_ParserMBR2(Parser* pars) /* * Release the memory of the polymorphic type */ { pars->close_Parser(pars); } Mbrola* DLL_EXPORT init_MBR2(Database* db, Parser* parse) /* * Kick start the engine. Returning NULL means error */ { Mbrola* mb; mb= init_Mbrola(db); if (mb) set_parser_Mbrola(mb, parse); return(mb); } void DLL_EXPORT close_MBR2(Mbrola* mb) /* Free everything */ { close_Mbrola(mb); /* Close the engine */ } int DLL_EXPORT reset_MBR2(Mbrola* mb) /* * Reset the pho buffer with residual commands -> used as a kind of * "panic" flush when a sentence is interrupted either with the stop * button, or in case of error * Return false in case of failure */ { if (!reset_Mbrola(mb)) return False; parser(mb)->reset_Parser(parser(mb)); return True; } int DLL_EXPORT readtype_MBR2(Mbrola* mb, void *buffer_out, int nb_wanted, AudioType sample_type) /* * Reads nb_wanted samples in an audio buffer * Returns the effective number of samples read */ { return readtype_Mbrola(mb, buffer_out, nb_wanted, sample_type); } int DLL_EXPORT getDatabaseInfo_MBR2(Mbrola* mb,char *msg,int nb_wanted,int index) /* Retrieve the ith info message, NULL means get the size */ { return(getDatabaseInfo(diph_dba(mb), msg, nb_wanted, index)); } void DLL_EXPORT setFreq_MBR2(Mbrola* mb,int freq) /* Set the freq and voice ratio */ { set_voicefreq_Mbrola(mb,freq); } int DLL_EXPORT getFreq_MBR2(Mbrola* mb) /* Return the output frequency */ { return(VoiceFreq(mb)); } void DLL_EXPORT setNoError_MBR2(Mbrola* mb, int no_error) /* Tolerance to missing diphones */ { set_no_error_Mbrola(mb, no_error); } int DLL_EXPORT getNoError_MBR2(Mbrola* mb) /* Spectral smoothing or not */ { return get_no_error_Mbrola(mb); } void DLL_EXPORT setVolumeRatio_MBR2(Mbrola* mb, float volume_ratio) /* Overall volume */ { set_volume_ratio_Mbrola(mb, volume_ratio); } float DLL_EXPORT getVolumeRatio_MBR2(Mbrola* mb) /* Overall volume */ { return get_volume_ratio_Mbrola(mb); } void DLL_EXPORT setParser_MBR2(Mbrola* mb, Parser* parser) /* drop the current parser for a new one */ { set_parser_Mbrola(mb, parser); } int DLL_EXPORT lastError_MBR2() /* Return the last error code */ { return lasterr_code; } int DLL_EXPORT lastErrorStr_MBR2(char *buffer_err,int nb_wanted) /* Return the last error message available */ { int length=strlen(errbuffer)+1; if (length. * * File: multichannel.h * Purpose: multichannel Mbrola synthesis * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * 22/06/98: Created. Replace old library.c * One should either use multichannel or onechannel front end * depending on end-user or telecom applications */ #ifndef _MULTICHANNEL_H #define _MULTICHANNEL_H #include "database.h" #include "mbrola.h" #include "parser.h" Database* DLL_EXPORT init_DatabaseMBR2(char* dbaname, char* rename, char* clone); /* * Give the name of the file containing the database, and parameters to * rename of clone phoneme names * * NULL on rename or clone means no modification to the database */ Database* DLL_EXPORT copyconstructor_DatabaseMBR2(Database* dba); /* Creates a copy of a diphone database so that many synthesis engine * can use the same database at the same time (duplicate the file handler) * * Highly recommended with multichannel mbrola, unless you can guaranty * mutually exclusive access to the getdiphone function */ void DLL_EXPORT close_DatabaseMBR2(Database* dba); /* Release the memory */ void DLL_EXPORT close_ParserMBR2(Parser* pars); /* * Release the memory of the polymorphic type */ Mbrola* DLL_EXPORT init_MBR2(Database* db, Parser* parse); /* Kick start the engine. Returning NULL means error */ void DLL_EXPORT close_MBR2(Mbrola* mb); /* Free everything */ int DLL_EXPORT reset_MBR2(Mbrola* mb); /* * Reset the pho buffer with residual commands -> used as a kind of * "panic" flush when a sentence is interrupted either with the stop * button, or in case of error * Return false in case of failure */ int DLL_EXPORT readtype_MBR2(Mbrola* mb, void *buffer_out, int nb_wanted, AudioType sample_type); /* * Reads nb_wanted samples in an audio buffer * Returns the effective number of samples read */ int DLL_EXPORT getDatabaseInfo_MBR2(Mbrola* mb,char *msg,int nb_wanted,int index); /* Retrieve the ith info message, NULL means get the size */ void DLL_EXPORT setFreq_MBR2(Mbrola* mb,int freq); /* Set the freq and voice ratio */ int DLL_EXPORT getFreq_MBR2(Mbrola* mb); /* Return the output frequency */ void DLL_EXPORT setSmoothing_MBR2(Mbrola* mb, int smoothing); /* Spectral smoothing or not */ int DLL_EXPORT getSmoothing_MBR2(Mbrola* mb); /* Spectral smoothing or not */ void DLL_EXPORT setNoError_MBR2(Mbrola* mb, int no_error); /* Tolerance to missing diphones */ int DLL_EXPORT get_no_error_MBR2(Mbrola* mb); /* Spectral smoothing or not */ void DLL_EXPORT set_volume_ratio_MBR2(Mbrola* mb, float volume_ratio); /* Overall volume */ float DLL_EXPORT get_volume_ratio_MBR2(Mbrola* mb); /* Overall volume */ void DLL_EXPORT set_parser_MBR2(Mbrola* mb, Parser* parser); /* drop the current parser for a new one */ int DLL_EXPORT lastError_MBR2(); /* Return the last error code */ int DLL_EXPORT lastErrorStr_MBR2(char *buffer_err,int nb_wanted); /* Return the last error message available */ void DLL_EXPORT reset_error_MBR2(); /* Clear the Mbrola error buffer */ int DLL_EXPORT getVersion_MBR2(char *msg,int nb_wanted); /* Return the release number, e.g. "2.05a" */ #endif mbrola-3.3+dfsg/LibOneChannel/000077500000000000000000000000001364272575600162345ustar00rootroot00000000000000mbrola-3.3+dfsg/LibOneChannel/demo1.c000066400000000000000000000041461364272575600174120ustar00rootroot00000000000000/* * Time-stamp: <1999-06-11 16:35:14 pagel> * * FPMs-TCTS SOFTWARE LIBRARY * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * File: demo1.c * Purpose: demo of multiple channel synthesis * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * 01/09/98: Created again */ #include #include #include "common.h" #include "parser_export.h" #include "onechannel.h" #include "incdll.h" short buffer[16000]; void handle_error() { char err[255]; lastErrorStr_MBR(err,sizeof(err)); printf("Code %i\n%s\n", lastError_MBR(), err); exit(-1); } int WriteSpeechFile(FILE *output, AudioType type, char size) { int i; while ((i=readtype_MBR(buffer,16000,type))==16000) fwrite(buffer,size,i,output); if (i>0) { fwrite(buffer,size,i,output); return 0; } else return i; } int main(int argc, char **argv) { FILE *output; if (argc!=2) { printf("%s ../fr1\n",argv[0]); return 1; } if ( init_MBR(argv[1])<0 ) handle_error(); output=fopen("res.ulaw","wb"); /* write_MBR(";; F=0.2\n"); */ if ( (write_MBR("_ 51 \n b 62 \n") < 0) || (write_MBR("o~ 127 50 170 \n Z 110\n") <0) || (WriteSpeechFile(output,LIN16,2)<0) || (write_MBR("u 211 100 200\n R 150 \n_ 9\n#\n") < 0) || (WriteSpeechFile(output,LIN16,2)<0)) handle_error(); close_MBR(); fclose(output); return(0); } /* 51+ 62+ 127+ 110+ 211+ 150+ 9= 720, should be 720*16*2=23040 samples */ mbrola-3.3+dfsg/LibOneChannel/demo1b.c000066400000000000000000000047651364272575600175630ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * File: demo1.c * Purpose: demo of multiple channel synthesis * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * 01/09/98: Created again */ #include #include #include "parser.h" #include "onechannel.h" #include "mbrola.h" short buffer[16000]; #define True 1 #define False 0 void handle_error(int Fatal) { char err[255]; lastErrorStr_MBR(err,sizeof(err)); printf("Code %i\n%s\n", lastError_MBR(), err); if (Fatal) exit(-1); } int WriteSpeechFile(FILE *output, AudioType type, char size) { int i; while ((i=readtype_MBR(buffer,16000,type))==16000) fwrite(buffer,size,i,output); if (i>0) { fwrite(buffer,size,i,output); return 0; } else { return i; } } int main(int argc, char **argv) { FILE *output; if (argc!=2) { printf("%s ../fr1\n",argv[0]); return 1; } if (init_MBR(argv[1])<0) handle_error(True); output=fopen("res.ulaw","wb"); /* write_MBR(";; F=0.2\n"); */ if ( (write_MBR("_ 51 \n b 62 \n")<0) || (write_MBR("o~ 127 50 170 \n Z 110\n")<0) || (WriteSpeechFile(output,LIN16,2)<0)) handle_error(True); /* Generate unknown diphone error */ if ( (write_MBR("UNKNOWN_PHON 211 100 200\n R 150 \n_ 9\n#\n")<0) || (WriteSpeechFile(output,LIN16,2)<0)) handle_error(False); /* Try to recover */ if ( (reset_MBR()<0) || (write_MBR("_ 51 \n b 62 \n")<0) || (write_MBR("o~ 127 50 170 \n Z 110\n")<0) || (write_MBR("u 211 100 200\n R 150 \n_ 9\n")<0) || (flush_MBR()<0) || (WriteSpeechFile(output,LIN16,2)<0)) handle_error(True); close_MBR(); fclose(output); return(0); } /* 51+ 62+ 127+ 110+ 211+ 150+ 9= 720, should be 720*16*2=23040 samples */ mbrola-3.3+dfsg/LibOneChannel/lib1.c000066400000000000000000000050251364272575600172310ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: wrapper.c * Time-stamp: <2000-03-28 18:02:19 pagel> * Purpose: Wrapper to build a all-in-one library version of the * one-channel mode * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 10/01/97: Created * Used to hide mbrola file structure from the outside when distributing * lib * * 27/03/99: Romdatabases */ #undef MULTI_CHANNEL #define LIBRARY #include "../Misc/common.h" #include "../Misc/vp_error.h" #include "../Misc/mbralloc.h" #include "../Misc/incdll.h" #include "../Parser/phone.h" #include "../Database/diphone_info.h" #include "../Engine/diphone.h" #include "../Engine/mbrola.h" #include "../Database/database.h" #include "../Database/database_old.h" #include "../Misc/audio.h" #include "../Parser/parser.h" #include "../Parser/parser_input.h" #include "../Database/hash_tab.h" #include "../LibOneChannel/onechannel.h" #include "../Misc/mbralloc.c" #include "../Database/little_big.c" #include "../Misc/common.c" #include "../Parser/phone.c" #include "../Engine/diphone.c" #include "../Misc/g711.c" #include "../Misc/audio.c" #include "../Engine/mbrola.c" #include "../Database/diphone_info.c" #include "../Database/database_old.c" #include "../Database/database.c" #include "../Database/zstring_list.c" #include "../Parser/phonbuff.c" #include "../Parser/fifo.c" #include "../Parser/parser_input.c" #include "../Parser/input_fifo.c" #include "../Parser/input_file.c" #include "../Database/hash_tab.c" #include "../LibOneChannel/onechannel.c" #include "../Misc/vp_error.c" #ifdef BACON #include "../Database/database_bacon.c" #endif #ifdef CEBAB #include "../Database/database_cebab.c" #endif #if defined(ROMDATABASE_STORE) || defined(ROMDATABASE_INIT) #include "../Database/rom_database.c" #include "../Database/rom_handling.c" #endif mbrola-3.3+dfsg/LibOneChannel/onechannel.c000066400000000000000000000176221364272575600205220ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: onechannel.c * Purpose: A one channel Mbrola Synthesizer * Authors: Pagel Vincent * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <2000-03-28 18:01:26 pagel> * * Copyright (c) 95 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 10/01/97: Created -> library compilation mode * No main function but a Read/Write scheme * * 10/06/97: close_MBR to release the memory on PCs ! * Change the behavior of write_MBR so that it doesn't attempt to write * partial strings * * 26/06/97: Changes by A. Ruelle -> * LastErrorStr2_MBR added for using the windows dll with other * languages than C (ex: Visual Basic). * Removing __declspec(dllexport), and replacing it by the macro * DLL_EXPORT which is set to WINAPI. With this calling convention * other languages than C can call function of the dll. * * 18/09/97: LastErrorStr2 wins against LastErrorStr... (A. Ruelle) * * 15/10/97: 2.05a -> getFreq_MBR, getVersion_MBR for the Win DLL * * 20/10/97: 2.05b -> getDbaInfo * * 30/01/98: 2.06c -> support Mlaw coding and other Alaw or LIN8 samples. * * 17/06/98: 3.01a -> support extra low pitch ( zero padding ) * support the object-like ANSI/C scheme * keep compatibility with the previous DLL * * 23/08/98: 3.01c -> support a bunch of get/set functions * initialization with copy and clone * * 09/09/98: 3.01d -> reset_MBR now returns a success value * first_call goes back to where it belongs (Mbrola) * and correct a bug with init/reset_MBR * * 20/10/98: 3.01f -> flush_MBR corrected for renaming. */ #include "common.h" #include "diphone.h" #include "mbrola.h" #include "database.h" #include "parser_input.h" #include "zstring_list.h" #include "onechannel.h" /* * Globals: main objects of the channel one */ Fifo* my_fifo; /* the char fifo for the input stream */ Input* my_input; /* the fifo input stream for the parser */ Parser* my_parse; /* the parser */ Database* my_dba; /* the database */ Mbrola* my_brole; /* the engine */ int DLL_EXPORT init_rename_MBR(char *dbaname,char* rename_string,char* clone_string) /* * Reads the diphone database * Rename and clone the list parsed from the parameter strings * * 0 if ok, error code otherwise */ { float my_pitch; float freq_ratio=1.0; float time_ratio=1.0; char* comment_symbol=";"; ZStringList* rename_list=NULL; /* phoneme renaming */ ZStringList* clone_list=NULL; /* phoneme cloning */ #ifdef DEBUG /* Log file for the DLL */ freopen("mbrola.log","wt",stderr); #endif if (rename_string) { rename_list= init_ZStringList(); parse_ZStringList(rename_list, rename_string, False); if (!rename_list) return lastError_MBR(); } if (clone_string) { clone_list= init_ZStringList(); parse_ZStringList(clone_list, clone_string, True); if (!clone_list) return lastError_MBR(); } my_dba= init_rename_Database(dbaname,rename_list,clone_list); if (my_dba==NULL) return lastError_MBR(); /* not usefull after initialization */ if (rename_list) close_ZStringList(rename_list); if (clone_list) close_ZStringList(clone_list); my_pitch= (float)Freq(my_dba) / (float)MBRPeriod(my_dba); my_fifo= init_Fifo(FIFO_SIZE); my_input= init_InputFifo(my_fifo); my_parse= init_ParserInput(my_input, sil_phon(my_dba), my_pitch, time_ratio, freq_ratio, comment_symbol, NULL ); my_brole= init_Mbrola(my_dba); set_parser_Mbrola(my_brole,my_parse); return 0; } int DLL_EXPORT init_MBR(char *dbaname) /* * Reads the diphone database * 0 if ok, error code otherwise */ { return init_rename_MBR(dbaname,NULL,NULL); } void DLL_EXPORT close_MBR(void) /* Free all the allocated memory */ { close_Mbrola(my_brole); my_parse->close_Parser(my_parse); /* ... the parser */ close_InputFifo(my_input); close_Fifo(my_fifo); my_dba->close_Database(my_dba); /* ... the database */ } int DLL_EXPORT reset_MBR() /* * Reset the pho buffer with residual commands -> may be used as a kind of * "panic" flush when a sentence is interrupted * * Return 0 if fail */ { if (!reset_Mbrola(my_brole)) return False; my_parse->reset_Parser(my_parse); return True; } int DLL_EXPORT readtype_MBR(void *buffer_out, int nb_wanted, AudioType sample_type) /* * Reads nb_wanted samples in an audio buffer * Returns the effective number of samples read * or negative error code */ { return readtype_Mbrola(my_brole,buffer_out,nb_wanted,sample_type); } int DLL_EXPORT read_MBR(void *buffer_out, int nb_wanted) /* * Reads nb_wanted samples in an audio buffer * Returns the effective number of samples read or * negative error code */ { return readtype_Mbrola(my_brole,buffer_out,nb_wanted,LIN16); } int DLL_EXPORT write_MBR(char *buffer_in) /* Write in the handmade fifo ! */ { return write_Fifo(my_fifo,buffer_in) ; } int DLL_EXPORT flush_MBR() /* * Write a flush command in the stream (0 means fail). Used by client * applications in case the flush symbol has been renamed */ { /* Got to break encapsulation here :-/ */ PhoneBuff* pb= (PhoneBuff*) my_parse->self; /* my_parse comes from init_ParserInput */ char* flush_symbol= flush_symbol(pb); if (flush_symbol) { /* Sorry for the quick hack :-( */ int length= strlen(flush_symbol); char *local= MBR_strdup(flush_symbol); int code; /* because of sprintf(flush_symbol,"%s%%n",flush); */ local[length-2]=0; strcat(local,"\n"); code=write_MBR(local); MBR_free(local); return(code); } return(0); } int DLL_EXPORT getDatabaseInfo_MBR(char *msg,int nb_wanted,int index) /* Retrieve the ith info message, NULL means get the size */ { return getDatabaseInfo(diph_dba(my_brole), msg, nb_wanted, index); } void DLL_EXPORT setFreq_MBR(int freq) /* Set the freq and voice ratio (change the voice tone) */ { set_voicefreq_Mbrola(my_brole,freq); } int DLL_EXPORT getFreq_MBR() /* Return the output frequency (to update soundcard) */ { return VoiceFreq(my_brole); } void DLL_EXPORT setNoError_MBR(int no_error) /* Tolerance to missing diphones */ { set_no_error_Mbrola(my_brole, no_error); } int DLL_EXPORT getNoError_MBR() /* Spectral smoothing or not */ { return get_no_error_Mbrola(my_brole); } void DLL_EXPORT setVolumeRatio_MBR(float volume_ratio) /* Overall volume */ { set_volume_ratio_Mbrola(my_brole, volume_ratio); } float DLL_EXPORT getVolumeRatio_MBR() /* Overall volume */ { return get_volume_ratio_Mbrola(my_brole); } void DLL_EXPORT setParser_MBR(Parser* parser) /* drop the current parser for a new one */ { set_parser_Mbrola(my_brole, parser); } int DLL_EXPORT lastError_MBR() /* Return the last error code */ { return lasterr_code; } int DLL_EXPORT lastErrorStr_MBR(char *buffer_err,int nb_wanted) /* Return the last error message available */ { int length=strlen(errbuffer)+1; if (length. * * File: onechannel.h * Purpose: Diphone-based MBROLA speech synthesizer. * One synthesis channel per database * * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * 10/01/97: Created -> library compilation mode * No main function but a Read/Write scheme */ #ifndef _ONECHANNEL_H #define _ONECHANNEL_H int DLL_EXPORT init_MBR(char *dbaname); /* * Reads the diphone database * 0 if ok, error code otherwise */ int DLL_EXPORT init_rename_MBR(char *dbaname,char* rename,char* clone); /* * Reads the diphone database * Rename and clone the list parsed from the parameter strings * * 0 if ok, error code otherwise */ void DLL_EXPORT close_MBR(void); /* Free all the allocated memory */ int DLL_EXPORT reset_MBR(); /* * Reset the pho buffer with residual commands -> may be used as a kind of * "panic" flush when a sentence is interrupted * 0 means fail */ int DLL_EXPORT readtype_MBR(void *buffer_out, int nb_wanted, AudioType sample_type); /* * Read nb_wanted samples in an audio buffer * return the effective number of samples read * or the negative error code we catch * * The sample_type may be LIN16, LIN8, ULAW, ALAW */ int DLL_EXPORT read_MBR(void *buffer_out, int nb_wanted); /* * Read nb_wanted samples in an audio buffer * return the effective number of samples read * or the negative error code we catch * * Kept for compatibility */ int DLL_EXPORT write_MBR(char *buffer_in); /* * Write a string of phoneme in the input buffer * Return the number of chars actually written * 0 mean not enough space in the buffer */ int DLL_EXPORT flush_MBR(); /* * Write a flush command in the stream (0 means fail). Used by client * applications in case the flush symbol has been renamed */ int DLL_EXPORT getDatabaseInfo_MBR(char *msg,int nb_wanted,int index); /* Retrieve the ith info message, NULL means get the size */ void DLL_EXPORT setFreq_MBR(int freq); /* Set the freq and voice ratio */ int DLL_EXPORT getFreq_MBR(); /* Return the output frequency */ void DLL_EXPORT setNoError_MBR(int no_error); /* Tolerance to missing diphones */ int DLL_EXPORT getNoError_MBR(); /* Spectral smoothing or not */ void DLL_EXPORT setVolumeRatio_MBR(float volume_ratio); /* Overall volume */ float DLL_EXPORT getVolumeRatio_MBR(); /* Overall volume */ void DLL_EXPORT setParser_MBR(Parser* parser); /* drop the current parser for a new one */ int DLL_EXPORT lastError_MBR(); /* Return the last error code */ int DLL_EXPORT lastErrorStr_MBR(char *buffer_err,int nb_wanted); /* Return the last error message available */ void DLL_EXPORT resetError_MBR(); /* Clear the Mbrola error buffer */ int DLL_EXPORT getVersion_MBR(char *msg,int nb_wanted); /* Return the release number, e.g. "2.05a" */ #endif mbrola-3.3+dfsg/Makefile000066400000000000000000000423621364272575600152420ustar00rootroot00000000000000# BEGIN_COMM <- flags parenthesize what goes in the commercial Makefile (awk strips) # BEGIN_WWW <- flags parenthesize what goes in the Web Makefile (stripped by awk below) # Mbrola Speech Synthesize Makefile ( tune the #define and type "make" ) VERSION=3.3 # To test strict C ANSI compliance CC = gcc -ansi -pedantic LIB= -lm # This allow you to write commands like "make PURE=purify demo1" # or "make PURE=quantify lib2" CCPURE = $(PURE) $(CC) ######################## # Machine specific #define, uncomment as needed # If your OS is not here, may be it provides some __linux or __sunos # that are used in Misc/common.h If compiling fails see that file #CFLAGS += -DTARGET_OS_DOS #CFLAGS += -DTARGET_OS_SUN4 #CFLAGS += -DTARGET_OS_VMS #CFLAGS += -DTARGET_OS_MAC # See below for BEOS # CFLAGS += -DTARGET_OS_BEOS # If endianess of your machine is not automatically detected in Misc/common.h # you should manually specify here CFLAGS += -DLITTLE_ENDIAN #CFLAGS += -DBIG_ENDIAN ####################### # GENERAL FLAGS FOR GCC # Optimized code CFLAGS += -O6 # Debug mode with gdb #CFLAGS += -g # Print MANY debug information on stdout #CFLAGS += -DDEBUG # For testing hash_table performances #CFLAGS += -DDEBUG_HASH #Include directories CFLAGS += -IParser -IStandalone -IMisc -ILibOneChannel -ILibMultiChannel -IEngine -IDatabase # Flags for GCC CFLAGS += -Wall # CFLAGS += -fhandle-exceptions # Flags for OS/2 #CFLAGS += -Zmts -D__ST_MT_ERRNO -Zexe -Zomf -Zsys #CFLAGS += -Zmtd -D__ST_MT_ERRNO -Zexe -Zomf # BeOs 3.2 # -w all is too sensible on prototype # CC = cc -w all # -w on make some warning # CC = cc -w on # LIB = # BeOS 4.x # LIB = -lbe -lroot # CFLAGS += -O1 # or CFLAGS += -O3 COMMONSRCS = Engine/mbrola.c Engine/diphone.c Parser/phone.c Parser/parser_input.c Parser/input_file.c Parser/phonbuff.c Misc/audio.c Misc/vp_error.c Misc/mbralloc.c Misc/common.c Database/database.c Database/database_old.c Database/diphone_info.c Database/little_big.c Database/hash_tab.c Database/zstring_list.c COMMONCHDRS = Engine/mbrola.h Engine/diphone.h Parser/phone.h Parser/parser.h Parser/input_file.h Parser/input.h Parser/phonbuff.h Misc/incdll.h Misc/audio.h Misc/vp_error.h Misc/mbralloc.h Misc/common.h Database/database.h Database/database_old.h Database/diphone_info.h Database/little_big.h Database/hash_tab.h Database/phoname_list.h # END_WWW # LibOneChannel or LibMultiChannel #CFLAGS += -DLIBRARY # DLL is a library with exported symbols #CFLAGS += -DDLL ###################################################### # ROM SECTION # # Uncomment if you want a pure rom access, that is NO FILE AT ALL # Note that this mode is incompatible with ROMDATABASE_STORE as it # requires files for this operation ! # CFLAGS += -DROMDATABASE_PURE # Uncomment if you wish to save .rom images from regular diphone databases CFLAGS += -DROMDATABASE_STORE # Uncomment if you wish to use init_ROM_Database(ROM_pointer) CFLAGS += -DROMDATABASE_INIT # Uncomment to cope with ROMDATABASE_STORE or ROMDATABASE_INIT COMMONSRCS += Database/rom_handling.c Database/rom_database.c ###################################################### # DATABASE COMPRESSION SECTION # # END_COMM # BEGIN_WWW # Signal handling of the standalone version (Unix platforms) CFLAGS += -DSIGNAL # Add external cflags CFLAGS += $(EXT_CFLAGS) # BEGIN_COMM BINSRCS = Standalone/synth.c $(COMMONSRCS) BINHDRS = Standalone/synth.h $(COMMONHDRS) LIBSRCS = Misc/g711.c Parser/input_fifo.c Parser/fifo.c $(COMMONSRCS) LIBHDRS = Misc/g711.h Parser/input_fifo.h Parser/fifo.h $(COMMONHDRS) MBRDIR = ./Bin BINDIR = ./Bin/Standalone LIBDIR = ./Bin/LibOneChannel BINOBJS = $(BINSRCS:%.c=Bin/Standalone/%.o) PROJ = mbrola $(PROJ): install_dir $(BINOBJS) $(CCPURE) $(CFLAGS) -o $(MBRDIR)/$(PROJ) $(BINOBJS) $(LIB) clean: \rm -f $(MBRDIR)/$(PROJ) $(PROJ).a core demo* TAGS $(BIN)/lib*.o $(BINOBJS) \rm -rf VisualC++/DLL/output VisualC++/DLL/mbroladl VisualC++/DLL/mbroladll.ncb VisualC++/DLL/mbroladll.opt VisualC++/DLL/*.plg .sb \rm -rf VisualC++/Standalone/output VisualC++/Standalone/mbroladl VisualC++/Standalone/mbrola.ncb VisualC++/Standalone/mbrola.opt VisualC++/Standalone/*.plg .sb \rm -rf delexsend$(VERSION) send$(VERSION) mbr$(VERSION) \rm -rf doc.txt spotless: clean net \rm -rf Bin tags: etags */*{c,h} net: \rm -f *~ */*~ $(BINDIR)/%.o: %.c $(CCPURE) $(CFLAGS) -o $@ -c $< # to create the compilation directory, if necessary install_dir: if [ ! -d Bin/Standalone ]; then \ mkdir Bin ; mkdir Bin/LibOneChannel; mkdir Bin/LibMultiChannel ; mkdir Bin/Standalone ; mkdir Bin/Standalone/Standalone ; mkdir Bin/Standalone/Parser ; mkdir Bin/Standalone/Engine ; mkdir Bin/Standalone/Database ; mkdir Bin/Standalone/Misc; \ fi lib1 : LibOneChannel/lib1.c $(CCPURE) $(CFLAGS) -o Bin/LibOneChannel/lib1.o -c LibOneChannel/lib1.c demo1: install_dir lib1 LibOneChannel/demo1.c $(CCPURE) $(CFLAGS) -c -o Bin/LibOneChannel/demo1.o LibOneChannel/demo1.c $(CCPURE) $(CFLAGS) -o demo1 Bin/LibOneChannel/demo1.o Bin/LibOneChannel/lib1.o $(LIB) # END_WWW demo1b: install_dir lib1 LibOneChannel/demo1b.c $(CCPURE) $(CFLAGS) -c -o Bin/LibOneChannel/demo1b.o LibOneChannel/demo1b.c $(CCPURE) $(CFLAGS) -o demo1b Bin/LibOneChannel/demo1b.o Bin/LibOneChannel/lib1.o $(LIB) lib2 : LibMultiChannel/lib2.c $(CCPURE) $(CFLAGS) -o Bin/LibMultiChannel/lib2.o -c LibMultiChannel/lib2.c demo2: install_dir lib2 LibMultiChannel/demo2.c $(CCPURE) $(CFLAGS) -c -o Bin/LibMultiChannel/demo2.o LibMultiChannel/demo2.c $(CCPURE) $(CFLAGS) -o demo2 Bin/LibMultiChannel/demo2.o Bin/LibMultiChannel/lib2.o $(LIB) # END_COMM # Check the integrity of the new Mbrola version by comparing the output # to previous standard output. Worry if you see the "Binary files differ" # message checkold: demo1 demo2 synth @ echo "" @ echo "" @ echo "Check the integrity of the new Mbrola version" # the code below generates errors -> dedicated to checks with Purify -@./demo1 UTILITY_TCTS -@./demo2 UTILITY_TCTS -@./demo1 UTILITY_TCTS/vincee1 -@./demo2 UTILITY_TCTS/vincee1 -@./demo1 UTILITY_TCTS/us1.cebab -@./demo2 UTILITY_TCTS/us1.cebab # The code below successfully synthesize ./synth UTILITY_TCTS/fr1 UTILITY_TCTS/bonjour.pho resbon1.wav ./synth -R "on o~ j Z" -C "ou u r R" UTILITY_TCTS/vincee1 UTILITY_TCTS/bonjour.pho resbon2.wav ./demo1 UTILITY_TCTS/fr1 ./demo2 UTILITY_TCTS/fr1 ./synth UTILITY_TCTS/us1.cebab UTILITY_TCTS/alice.pho resalis.au @ echo "" @ echo "" @ echo "Worry if you see the Binary files differ message" diff res.ulaw UTILITY_TCTS/$(OSTYPE) diff resbon1.wav UTILITY_TCTS/$(OSTYPE) diff resbon2.wav UTILITY_TCTS/$(OSTYPE) diff resalis.au UTILITY_TCTS/$(OSTYPE) diff res1.ulaw UTILITY_TCTS/$(OSTYPE) diff res2.raw UTILITY_TCTS/$(OSTYPE) diff res3.lin8 UTILITY_TCTS/$(OSTYPE) check: checkold # Generate ROM images ./synth -W UTILITY_TCTS/fr1 ./synth -W UTILITY_TCTS/us1.cebab ./synth -w UTILITY_TCTS/fr1 UTILITY_TCTS/bonjour.pho resbon1rom.wav ./synth -w UTILITY_TCTS/us1.cebab UTILITY_TCTS/alice.pho resalisrom.au diff resbon1rom.wav resbon1.wav diff resalisrom.au resalis.au \rm -f res* UTILITY_TCTS/fr1.rom UTILITY_TCTS/us1.cebab.rom # Put the right version number in common.h version: @ mv Misc/common.h Misc/common.h~ @ sed 's/SYNTH_VERSION.*/SYNTH_VERSION \"$(VERSION)\"/' < Misc/common.h~ > Misc/common.h; # Internet delexicalized version ( Unix standalone mode ) delex: version spotless mkdir delexsend$(VERSION) ; cd delexsend$(VERSION) ; mkdir Database Engine Misc Parser Standalone LibOneChannel ; echo "Version $(VERSION) `date`" > readme.txt; cat ../DOCUMENTATION/User/readme.txt >> readme.txt ; cp ../00readme_* . ; cp -r ../Standalone/Posix Standalone/Posix ; cp ../Misc/incdll.h Misc ; ../UTILITY_TCTS/source_delexicalize.pl Database/database.c Database/database.h Database/database_cebab.c Database/database_cebab.h Database/database_old.c Database/database_old.h Database/diphone_info.c Database/diphone_info.h Database/hash_tab.c Database/hash_tab.h Database/little_big.c Database/little_big.h Database/zstring_list.c Database/zstring_list.h Engine/diphone.c Engine/diphone.h Engine/mbrola.c Engine/mbrola.h Misc/audio.c Misc/audio.h Misc/common.c Misc/common.h Misc/g711.c Misc/g711.h Misc/mbralloc.c Misc/mbralloc.h Misc/vp_error.c Misc/vp_error.h Parser/fifo.c Parser/fifo.h Parser/input.h Parser/input_fifo.c Parser/input_fifo.h Parser/input_file.c Parser/input_file.h Parser/parser.h Parser/parser_input.c Parser/parser_input.h Parser/phonbuff.c Parser/phonbuff.h Parser/phone.c Parser/phone.h Standalone/synth.c Standalone/synth.h LibOneChannel/onechannel.c ; cp ../LibOneChannel/onechannel.h ../LibOneChannel/lib1.c ../LibOneChannel/demo1.c LibOneChannel ; awk '/# BEGIN_WWW/,/# END_WWW/' < ../Makefile | sed 's/.*_COMM.*//' |sed 's/.*_WWW.*//' > Makefile big: delex cd delexsend$(VERSION) ; cp ../Misc/incdll.h . ; cp ../LibOneChannel/onechannel.h . ; cp ../Parser/parser.h . ; cp ../Parser/phone_export.h phone.h ; cat Misc/common.h Misc/vp_error.h Misc/mbralloc.h Misc/incdll.h Parser/phone.h Database/diphone_info.h Engine/diphone.h Parser/parser.h Misc/g711.h Misc/audio.h Database/zstring_list.h Database/hash_tab.h Database/little_big.h Database/database.h Database/database_cebab.h Engine/mbrola.h Database/database_old.h Parser/input.h Parser/fifo.h Parser/phonbuff.h Parser/parser_input.h Parser/input_fifo.h LibOneChannel/onechannel.h Misc/mbralloc.c Database/little_big.c Misc/common.c Parser/phone.c Engine/diphone.c Misc/g711.c Misc/audio.c Engine/mbrola.c Database/diphone_info.c Database/database_old.c Database/database.c Database/zstring_list.c Parser/phonbuff.c Parser/fifo.c Parser/input_fifo.c Parser/parser_input.c Database/hash_tab.c LibOneChannel/onechannel.c Misc/vp_error.c Database/database_cebab.c | sed 's/#include ".*//g' > mbrola_lib.c ; \rm -rf Database Engine Misc Parser Standalone LibOneChannel # Internet public version (no ROM, no DEBUG and no MULTI_CHANNEL) send: version spotless mkdir send$(VERSION) ; cd send$(VERSION) ; cp ../00readme_* . ; mkdir Database Engine Misc Parser Standalone LibOneChannel ; echo "Version $(VERSION) `date`" > readme.txt; cat ../DOCUMENTATION/User/readme.txt >> readme.txt ; cp -r ../Standalone/Posix Standalone/Posix ; ../UTILITY_TCTS/source_clean_public.pl Database/database.c Database/database.h Database/database_cebab.c Database/database_cebab.h Database/database_old.c Database/database_old.h Database/diphone_info.c Database/diphone_info.h Database/hash_tab.c Database/hash_tab.h Database/little_big.c Database/little_big.h Database/zstring_list.c Database/zstring_list.h Engine/diphone.c Engine/diphone.h Engine/mbrola.c Engine/mbrola.h Misc/audio.c Misc/audio.h Misc/common.c Misc/common.h Misc/g711.c Misc/g711.h Misc/mbralloc.c Misc/mbralloc.h Misc/vp_error.c Misc/vp_error.h Parser/fifo.c Parser/fifo.h Parser/input.h Parser/input_fifo.c Parser/input_fifo.h Parser/input_file.c Parser/input_file.h Parser/parser.h Parser/parser_input.c Parser/parser_input.h Parser/phonbuff.c Parser/phonbuff.h Parser/phone.c Parser/phone.h Standalone/synth.c Standalone/synth.h LibOneChannel/onechannel.c LibOneChannel/onechannel.h LibOneChannel/lib1.c LibOneChannel/demo1.c Misc/incdll.h ; awk '/# BEGIN_WWW/,/# END_WWW/' < ../Makefile | sed 's/.*_COMM.*//' |sed 's/.*_WWW.*//' > Makefile # Commercial Version com: version spotless mkdir mbr$(VERSION) ; cd mbr$(VERSION) ; cp -r ../Database . ; cp -r ../Engine . ; cp -r ../LibMultiChannel . ;cp -r ../LibOneChannel . ;cp -r ../Misc . ;cp -r ../Parser . ;cp -r ../Standalone . ;cp -r ../VisualC++ . ;cp -r ../DOCUMENTATION . ; echo "Version $(VERSION) `date`" > DOCUMENTATION/User/readme.txt; cat ../DOCUMENTATION/User/readme.txt >> DOCUMENTATION/User/readme.txt ; \rm -f Database/database_cebab.* ; awk '/# BEGIN_COMM/,/# END_COMM/' < ../Makefile | sed 's/.*_COMM.*//' | sed 's/.*_WWW.*//'> Makefile ; sed 's/RELEASE/$(VERSION)/g' < ../00readme.txt > 00readme.txt sauve: spotless cd ..; gtar cvfz SAUVE/synth$(VERSION).tgz synth$(VERSION)/ doc: echo "File: Misc/common.h" >> doc.txt cat Misc/common.h >> doc.txt # echo "File: Misc/common.c" >> doc.txt # cat Misc/common.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Misc/incdll.h" >> doc.txt cat Misc/incdll.h >> doc.txt echo "File: Misc/mbralloc.h" >> doc.txt cat Misc/mbralloc.h >> doc.txt # echo "File: Misc/mbralloc.c" >> doc.txt # cat Misc/mbralloc.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Misc/vp_error.h" >> doc.txt cat Misc/vp_error.h >> doc.txt # echo "File: Misc/vp_error.c" >> doc.txt # cat Misc/vp_error.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Misc/audio.h" >> doc.txt cat Misc/audio.h >> doc.txt # echo "File: Misc/audio.c" >> doc.txt # cat Misc/audio.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/database.h" >> doc.txt cat Database/database.h >> doc.txt echo "File: Database/database.c " >> doc.txt # cat Database/database.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/rom_database.h" >> doc.txt cat Database/rom_database.h >> doc.txt echo "File: Database/rom_database.c " >> doc.txt # cat Database/rom_database.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/rom_handling.h" >> doc.txt cat Database/rom_handling.h >> doc.txt echo "File: Database/rom_handling.c " >> doc.txt # cat Database/rom_handling.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: atabase/database_bacon.h" >> doc.txt cat Database/database_bacon.h >> doc.txt # echo "File: Database/database_bacon.c" >> doc.txt # cat Database/database_bacon.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/database_old.h" >> doc.txt cat Database/database_old.h >> doc.txt # echo "File: Database/database_old.c" >> doc.txt # cat Database/database_old.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/diphone_info.h" >> doc.txt cat Database/diphone_info.h >> doc.txt # echo "File: Database/diphone_info.c" >> doc.txt # cat Database/diphone_info.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/hash_tab.h" >> doc.txt cat Database/hash_tab.h >> doc.txt # echo "File: Database/hash_tab.c" >> doc.txt # cat Database/hash_tab.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/little_big.h" >> doc.txt cat Database/little_big.h >> doc.txt # echo "File: Database/little_big.c" >> doc.txt # cat Database/little_big.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Database/zstring_list.h" >> doc.txt cat Database/zstring_list.h >> doc.txt # echo "File: Database/zstring_list.c" >> doc.txt # cat Database/zstring_list.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Engine/diphone.h" >> doc.txt cat Engine/diphone.h >> doc.txt # echo "File: Engine/diphone.c" >> doc.txt # cat Engine/diphone.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Engine/mbrola.h" >> doc.txt cat Engine/mbrola.h >> doc.txt # echo "File: Engine/mbrola.c" >> doc.txt # cat Engine/mbrola.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Parser/fifo.h" >> doc.txt cat Parser/fifo.h >> doc.txt # echo "File: Parser/fifo.c" >> doc.txt # cat Parser/fifo.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Parser/input.h" >> doc.txt cat Parser/input.h >> doc.txt echo "File: Parser/input_fifo.h" >> doc.txt cat Parser/input_fifo.h >> doc.txt # echo "File: Parser/input_fifo.c" >> doc.txt # cat Parser/input_fifo.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Parser/input_file.h" >> doc.txt cat Parser/input_file.h >> doc.txt # echo "File: Parser/input_file.c" >> doc.txt # cat Parser/input_file.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Parser/parser.h" >> doc.txt cat Parser/parser.h >> doc.txt echo "File: Parser/parser_input.h" >> doc.txt cat Parser/parser_input.h >> doc.txt # echo "File: Parser/parser_input.c" >> doc.txt # cat Parser/parser_input.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Parser/phonbuff.h" >> doc.txt cat Parser/phonbuff.h >> doc.txt # echo "File: Parser/phonbuff.c" >> doc.txt # cat Parser/phonbuff.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Parser/phone.h" >> doc.txt cat Parser/phone.h >> doc.txt # echo "File: Parser/phone.c" >> doc.txt # cat Parser/phone.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: Standalone/synth.h" >> doc.txt cat Standalone/synth.h >> doc.txt # echo "File: Standalone/synth.c" >> doc.txt # cat Standalone/synth.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: LibOneChannel/onechannel.h" >> doc.txt cat LibOneChannel/onechannel.h >> doc.txt # echo "File: LibOneChannel/onechannel.c" >> doc.txt # cat LibOneChannel/onechannel.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt echo "File: LibMultiChannel/multichannel.h" >> doc.txt cat LibMultiChannel/multichannel.h >> doc.txt # echo "File: LibMultiChannel/multichannel.c" >> doc.txt # cat LibMultiChannel/multichannel.c| awk '/{/ { nb++; } { if (nb == 0) print; } /}/ { nb--; }' >> doc.txt mbrola-3.3+dfsg/Misc/000077500000000000000000000000001364272575600144665ustar00rootroot00000000000000mbrola-3.3+dfsg/Misc/audio.c000066400000000000000000000203711364272575600157360ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: audio_file.c * Purpose: audio files * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/02/96 : Created. Put here input output function depending on the * little endian or big endian format * Also audio_file header writing and file format extraction * 09/04/98 : split to little_big * * 17/06/98 : linear16to8 corrected (gave alaw result ) * */ #include "common.h" #include "audio.h" #include "little_big.h" #include "g711.h" /* True if the format of the current output needs byte swapping */ bool audio_swapped; #ifdef LIBRARY int16* conv_LIN16fromLIN16( int16 *out, int16 *in, int nb_move) /* linear 16bits to linear16 :-) simply move */ { memmove((int16 *) out , (int16 *) in , nb_move*2); return( &out[nb_move] ); } int8 linear2lin8(int16 lin) /* linear16tolinear8 */ { return( 128 + (lin >> 8)); } int8* conv_LIN8fromLIN16( int8 *out, int16 *in, int nb_move) /* linear 16bits to linear8 */ { int i; for(i=0; ill) && !strcmp(lower_case+l-ll, format_list[i])) break; } MBR_free(lower_case); if (format_list[i] == NULL) /* no format means RAW */ return(RAW_FORMAT); return((WaveType)i); } mbrola-3.3+dfsg/Misc/audio.h000066400000000000000000000043611364272575600157440ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: audio_file.h * Time-stamp: <2000-03-28 17:53:49 pagel> * Purpose: audio files * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #ifndef _AUDIO_H #define _AUDIO_H #include "common.h" /* * Audio file format */ typedef enum { RAW_FORMAT=0, /* same as intern computation format: 16 bits linear */ WAV_FORMAT , AU_FORMAT , AIF_FORMAT , AIFF_FORMAT } WaveType; int write_int16s(int16 *buffer,int count,FILE *file); /* Write a buffer of int16 */ void write_header(WaveType file_format, int32 audio_length, uint16 samp_rate, FILE *output_file); /* Write the header corresponding to the output audio format */ WaveType find_file_format(char *name); /* Find the file format corresponding to the name's extension * raw=none wav=RIFF au=Sun Audio aif or aiff=Macintosh */ /* * Sample type conversion routines for read_MBR */ #ifdef LIBRARY void* zero_convert(void* buffer_out, int nb_move, AudioType sample_type); /* * Output zeros in a buffer according to the sample_type * Return the next position after the end of the buffer * * Returning NULL means fatal error */ void* move_convert(void* buffer_out,int16* buffer_in,int nb_move, AudioType sample_type); /* * Move audio samples and convert them at the same time * Return the shifted pointer in buffer_out * * linear 16bits to linear16 :-) simply move * linear 16bits to linear8 * linear 16bits to mulaw * linear 16bits to alaw * * Returning NULL means fatal error */ #endif #endif mbrola-3.3+dfsg/Misc/common.c000066400000000000000000000025451364272575600161300ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: common.c * Time-stamp: <00/03/29 14:36:29 pagel> * Purpose: common defines and utilities * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 29/02/96 : Created. Put here all little usefull functions * and symbols common to the different sources. * */ #include "common.h" #if defined(TARGET_OS_VMS) || defined(TARGET_OS_BEOS) || defined(TARGET_OS_MAC) void swab( const char *from, char *to, int nbytes) /* A quick definition of SWAB for VAX-VMS */ { int i; char tmp; for (i=0; i * Purpose: common utilities and defines * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /****************** * Definitions * ******************/ #ifndef _COMMON_H #define _COMMON_H #include #include #include #include /* The Dll version is based on the library one -> export DLL functions */ #ifdef DLL # include "windows.h" # define LIBRARY # define DLL_EXPORT WINAPI #else # define DLL_EXPORT #endif /* * Sanity check on compilation mode! */ #if defined(ROMDATABASE_PURE) && defined(ROMDATABASE_STORE) # error "ROMDATABASE_PURE and ROMDATABASE_STORE are incompatible" #endif #if defined(ROMDATABASE_PURE) && !defined(ROMDATABASE_INIT) # error "ROMDATABASE_PURE without ROMDATABASE_INIT: hey pal, are you going to work?" #endif /* * On VMS, '-' can't be used as a file name, use '_' instead * Also use a hand-made version of swab */ #ifdef TARGET_OS_VMS #define OPENRT "r" #define PIPESYMB "_" #else #define OPENRT "rt" #define PIPESYMB "-" #endif /* For beboxes and Mac use a hand-made version of swab */ #if defined(TARGET_OS_VMS) || defined(TARGET_OS_BEOS) || defined(TARGET_OS_MAC) || defined(__STRICT_ANSI__) void swab( const char *from, char *to, int nbytes); #endif #if defined(__GLIBC__) #include #undef BIG_ENDIAN #undef LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN # define LITTLE_ENDIAN #else # define BIG_ENDIAN #endif #else /* Intel based machine ? */ #if defined(__i386) || defined(_M_X86) || defined(TARGET_OS_VMS) #undef BIG_ENDIAN #undef LITTLE_ENDIAN # define LITTLE_ENDIAN #endif /* Endianess __sparc for SUN */ #if defined(__powerpc__) || defined(__sparc) #undef BIG_ENDIAN #undef LITTLE_ENDIAN #define BIG_ENDIAN #endif #ifdef __powerpc__ #include /* Make sure we see the definitions */ #endif #endif /* memmove is not defined on SUN4, but memcpy will do */ #ifdef TARGET_OS_SUN4 #define memmove memcpy #endif #ifndef TARGET_OS_DOS #include #else /* swab for Windows */ #define swab(X,Y,Z) _swab(X,Y,Z) #endif #include "mbralloc.h" #include "vp_error.h" #include "incdll.h" /* Release number (automatically changed by "make version") */ #define SYNTH_VERSION "3.02b" #define WWW_ADDRESS "http://tcts.fpms.ac.be/synthesis" /* General trace */ /* #define DEBUG */ /* Trace of the hash table -> this debug make the program stop and * and print the access statistics in the hash table (may help to * check and tune access time on new databases) */ /* #define DEBUG_HASH */ /* * True and False should be used instead of integer values */ /* Argh ! Depends on the compiler! Comment it if yours is not C/ANSI */ #define bool int #define False 0 #define True 1 /* * The Flush pseudo phoneme is used to force the flushing of the audio output * when one uses pipes or library mode. */ #define FLUSH "#" /* * First character of a comment line in the phonetic input */ #define COMMENT ";" /* If the OS is able to catch signals ( well I mean Unix platforms ) */ #ifdef SIGNAL #include extern volatile sig_atomic_t must_flush; /* To catch the users signal (means flush the input) */ #endif /* * ARCHITECTURE DEPENDENT !!! * These definitions should be imposed so that int8, int16 and int32 * always refer to 8, 16 and 32 bits integer * * WARNING int16 and int32 are signed, uint16 and uint8 are NOT signed */ #define uint8 unsigned char #define int8 char #define int16 short #define uint16 unsigned short #define int32 int /* The name as a string */ typedef char* PhonemeName; /* Phoneme name encoded according to auxiliary table */ typedef uint16 PhonemeCode; #define MAX_PHONEME_NUMBER 65000 #endif mbrola-3.3+dfsg/Misc/g711.c000066400000000000000000000163741364272575600153240ustar00rootroot00000000000000/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #include "common.h" /* * g711.c * * u-law, A-law and linear PCM conversions. */ #define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ #define QUANT_MASK (0xf) /* Quantization field mask. */ #define NSEGS (8) /* Number of A-law segments. */ #define SEG_SHIFT (4) /* Left shift for segment number. */ #define SEG_MASK (0x70) /* Segment field mask. */ static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; /* copy from CCITT G.711 specifications */ unsigned char _u2a[128] = { /* u- to A-law conversions */ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 29, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128}; unsigned char _a2u[128] = { /* A- to u-law conversions */ 1, 3, 5, 7, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}; static int search(int val,short *table,int size) { int i; for (i = 0; i < size; i++) { if (val <= *table++) return (i); } return (size); } /* * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law * * linear2alaw() accepts an 16-bit integer and encodes it as A-law data. * * Linear Input Code Compressed Code * ------------------------ --------------- * 0000000wxyza 000wxyz * 0000001wxyza 001wxyz * 000001wxyzab 010wxyz * 00001wxyzabc 011wxyz * 0001wxyzabcd 100wxyz * 001wxyzabcde 101wxyz * 01wxyzabcdef 110wxyz * 1wxyzabcdefg 111wxyz * * For further information see John C. Bellamy's Digital Telephony, 1982, * John Wiley & Sons, pps 98-111 and 472-476. */ unsigned char linear2alaw(int pcm_val) /* 2's complement (16-bit range) */ { int mask; int seg; unsigned char aval; if (pcm_val >= 0) { mask = 0xD5; /* sign (7th) bit = 1 */ } else { mask = 0x55; /* sign bit = 0 */ pcm_val = -pcm_val - 8; } /* Convert the scaled magnitude to segment number. */ seg = search(pcm_val, seg_end, 8); /* Combine the sign, segment, and quantization bits. */ if (seg >= 8) /* out of range, return maximum value. */ return (uint8) (0x7F ^ mask); else { aval = (uint8) (seg << SEG_SHIFT); if (seg < 2) aval |= (pcm_val >> 4) & QUANT_MASK; else aval |= (pcm_val >> (seg + 3)) & QUANT_MASK; return (uint8)(aval ^ mask); } } /* * alaw2linear() - Convert an A-law value to 16-bit linear PCM * */ int alaw2linear(unsigned char a_val) { int t; int seg; a_val ^= 0x55; t = (a_val & QUANT_MASK) << 4; seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; switch (seg) { case 0: t += 8; break; case 1: t += 0x108; break; default: t += 0x108; t <<= seg - 1; } return ((a_val & SIGN_BIT) ? t : -t); } #define BIAS (0x84) /* Bias for linear code. */ /* * linear2ulaw() - Convert a linear PCM value to u-law * * In order to simplify the encoding process, the original linear magnitude * is biased by adding 33 which shifts the encoding range from (0 - 8158) to * (33 - 8191). The result can be seen in the following encoding table: * * Biased Linear Input Code Compressed Code * ------------------------ --------------- * 00000001wxyza 000wxyz * 0000001wxyzab 001wxyz * 000001wxyzabc 010wxyz * 00001wxyzabcd 011wxyz * 0001wxyzabcde 100wxyz * 001wxyzabcdef 101wxyz * 01wxyzabcdefg 110wxyz * 1wxyzabcdefgh 111wxyz * * Each biased linear code has a leading 1 which identifies the segment * number. The value of the segment number is equal to 7 minus the number * of leading 0's. The quantization interval is directly available as the * four bits wxyz. * The trailing bits (a - h) are ignored. * * Ordinarily the complement of the resulting code word is used for * transmission, and so the code word is complemented before it is returned. * * For further information see John C. Bellamy's Digital Telephony, 1982, * John Wiley & Sons, pps 98-111 and 472-476. */ unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */ { int mask; int seg; unsigned char uval; /* Get the sign and the magnitude of the value. */ if (pcm_val < 0) { pcm_val = BIAS - pcm_val; mask = 0x7F; } else { pcm_val += BIAS; mask = 0xFF; } /* Convert the scaled magnitude to segment number. */ seg = search(pcm_val, seg_end, 8); /* * Combine the sign, segment, quantization bits; * and complement the code word. */ if (seg >= 8) /* out of range, return maximum value. */ return (uint8)(0x7F ^ mask); else { uval = (uint8) ((seg << 4) | ((pcm_val >> (seg + 3)) & 0xF)); return (uint8)(uval ^ mask); } } /* * ulaw2linear() - Convert a u-law value to 16-bit linear PCM * * First, a biased linear code is derived from the code word. An unbiased * output can then be obtained by subtracting 33 from the biased code. * * Note that this function expects to be passed the complement of the * original code word. This is in keeping with ISDN conventions. */ int ulaw2linear(unsigned char u_val) { int t; /* Complement to obtain normal u-law value. */ u_val = (uint8) ~u_val; /* * Extract and bias the quantization bits. Then * shift up by the segment number and subtract out the bias. */ t = ((u_val & QUANT_MASK) << 3) + BIAS; t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); } /* A-law to u-law conversion */ unsigned char alaw2ulaw(unsigned char aval) { aval &= 0xff; return (uint8) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : (0x7F ^ _a2u[aval ^ 0x55])); } /* u-law to A-law conversion */ unsigned char ulaw2alaw(unsigned char uval) { uval &= 0xff; return (uint8) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : (0x55 ^ (_u2a[0x7F ^ uval] - 1))); } mbrola-3.3+dfsg/Misc/g711.h000066400000000000000000000024031364272575600153150ustar00rootroot00000000000000/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* * linear2alaw() - Convert a 16-bit linear PCM to an A-law value */ unsigned char linear2alaw(int pcm_val); /* * linear2ulaw() - Convert a 16-bit linear PCM to an Mu-law value */ unsigned char linear2ulaw(int pcm_val); mbrola-3.3+dfsg/Misc/incdll.h000066400000000000000000000025411364272575600161060ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: incdll.h * Purpose: symbols needed outside of the mbrola sources * namely to compile the wrapper DLL * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef INCDLL_H #define INCDLL_H /* * Type of samples we can output with read_MBR */ typedef enum { LIN16=0, /* same as intern computation format: 16 bits linear */ LIN8, /* unsigned linear 8 bits, worse than telephone */ ULAW, /* MU law -> 8bits, telephone. Roughly equ. to 12bits */ ALAW /* A law -> 8bits, equivallent to mulaw */ } AudioType; #endif mbrola-3.3+dfsg/Misc/mbralloc.c000066400000000000000000000034501364272575600164270ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: mbralloc.c * Time-stamp: <2001-09-26 17:32:04 pagel> * Purpose: memory allocation and freeing * Authors: Vincent Pagel and Alain Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 09/04/98: Created * Gather all allocation scheme here for people who wish to replace * it later with their own memory manager... at the moment nothing * really fancy * * FreeNull created by Alain Ruelle becomes MBR_free * * 01/09/98: we don't have the catch/throw mechanism any more, so the * fatal_error handling becomes really brutal with exit(1) */ #include "common.h" #include "vp_error.h" void *MBR_malloc(size_t size) /* * Check there's enough memory for the pointer */ { void *tmp=malloc(size); if (tmp==NULL) { fatal_message(ERROR_MEMORYOUT,"FATAL: out of memory\n"); exit(1); /* Don't have any replacement solution */ } return(tmp); } char *MBR_strdup( const char *str) /* standard strdup would use standard malloc */ { char *newstr = (char *) MBR_malloc(strlen(str)+1); strcpy(newstr,str); return(newstr); } mbrola-3.3+dfsg/Misc/mbralloc.h000066400000000000000000000030571364272575600164370ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: mbralloc.h * Time-stamp: <2000-03-28 17:53:02 pagel> * Purpose: memory allocation and freeing * Author: Vincent Pagel and Alain Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 09/04/98: Created * Gather all allocation scheme here for people who wish to replace it * later with their own memory manager * Alain Ruelle's FreeNull becomes MBR_free */ #ifndef _MBRALLOC_H #define _MBRALLOC_H #include #include #define MBR_free(X) {free(X);X=NULL;} /* free a memory block and set the pointer to NULL */ #define MBR_realloc(X,Y) realloc(X,Y) /* dummy reallocation for the moment */ void *MBR_malloc(size_t size); /* * Check there's enough memory for the pointer */ char *MBR_strdup( const char *str); /* standard strdup would use standard malloc */ #endif mbrola-3.3+dfsg/Misc/parser_export.h000066400000000000000000000040131364272575600175320ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: parser_fifo.c * Purpose: polymorphic type to parse a "pho file" * Time-stamp: <2000-03-06 12:32:30 pagel> * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 18/06/98 : Created */ #ifndef _PARSER_H #define _PARSER_H #include "phone_export.h" /* Return values of the nextphone function */ typedef enum { PHO_OK, PHO_EOF, PHO_FLUSH, PHO_ERROR } StatePhone; /* Polymorphic type */ typedef struct Parser Parser; typedef void (*reset_ParserFunction)(Parser* ps); typedef void (*close_ParserFunction)(Parser* ps); typedef StatePhone (*nextphone_ParserFunction)(Parser* ps,Phone** ph); /* * Generic parser : * reset: forget remaining data in the buffer (when the user STOP synthesis for example * * close: release the memory * * nextphone: return the next Phoneme from input. * * PRECONDITION: this phoneme MUST have a pitch point at 0 and 100% * * THE CALLER IS IN CHARGE OF CALLING close_Phone ON THE PHONES HE GETS * WITH nextphone */ struct Parser { void* self; /* Polymorphic on the real type */ reset_ParserFunction reset_Parser; /* virtual func */ close_ParserFunction close_Parser; /* virtual func */ nextphone_ParserFunction nextphone_Parser; /* virtual func */ }; #endif mbrola-3.3+dfsg/Misc/vp_error.c000066400000000000000000000060551364272575600164760ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: vp_error.c * Time-stamp: <2000-03-28 17:58:44 pagel> * Purpose: Errors management and debugging messages * Authors: V. Pagel and A. Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 10/06/96 : Created by VP. Don't be fool and don't rename it as "error.c" * unless you wish to introduce some confusion under UNIX platform with built * in error modules. Put here all little usefull functions to manage errors, * depending on the mode: LIBRARY, or CONSOLE (means stderr output or buffering * of the messages) * * Error messages as defined by A Ruelle * * 26/06/98: Back to C/ANSI. An inline is not possible any more for the usefull * debug_message... consequence the call is still here in the * generated code in non debug mode. This I do not wish -> MACROs * with size dependent names :-( */ #include "common.h" #include "vp_error.h" /* buffer cumulating error messages when in lib or dll mode */ char errbuffer[300]; int lasterr_code; /* Code of the last error */ void fatal_message(const int code, const char *format, /* args */ ...) /* * Uses the format of a printf function * throw an exception when in library mode, or abort the program */ { va_list ap; va_start(ap,format); lasterr_code=code; #ifdef LIBRARY vsprintf(errbuffer, format, ap); va_end(ap); #else vfprintf(stderr, format, ap); va_end(ap); exit(code); /* in standalone mode... brutal */ #endif } void warning_message(const int code, const char *format, /* args */ ...) /* * Uses the format of a printf function * Just print a warning in the error buffer */ { va_list ap; va_start(ap,format); lasterr_code=code; #ifdef LIBRARY vsprintf(errbuffer, format, ap); va_end(ap); #else vfprintf(stderr, format, ap); va_end(ap); #endif } #ifdef DEBUG void debug_message(char const *format, /* args */ ...) /* * Uses the format of a printf function * Previously was inline for C++, but no solution in ANSI C * We don't want that the Debug message generate any code in the release * version of Mbrola -> this is the reason for the inline declaration as * when we're not debugging the macro is empty, and no code is generated */ { va_list ap; va_start(ap,format); vfprintf(stderr, format, ap); va_end(ap); fflush(stderr); /* critical if the program crashes */ } #endif mbrola-3.3+dfsg/Misc/vp_error.h000066400000000000000000000102701364272575600164750ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: vp_error.h * Time-stamp: <01/09/26 16:39:44 mbrola> * Purpose: Errors management with debugging messages * Authors: V. Pagel and A. Ruelle * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 10/06/96 : Created by VP. Don't be fool and don't rename it as "error.c" * unless you wish to introduce some confusion under UNIX platform with built * in error modules. Put here all little usefull functions to manage errors, * depending on the mode: LIBRARY, or CONSOLE (means stderr output or buffering * of the messages) * * Error messages as defined by A Ruelle * * 26/06/98: Back to C/ANSI. An inline is not possible any more for the usefull * debug_message... consequence the call is still here in the * generated code in non debug mode. This I do not wish -> MACROs * with size dependent names ! */ #ifndef _VP_ERROR_H #define _VP_ERROR_H #include #include /* * For the DLL and LIBRARY mode, Error codes returned */ #define ERROR_MEMORYOUT -1 #define ERROR_UNKNOWNCOMMAND -2 #define ERROR_SYNTAXERROR -3 #define ERROR_COMMANDLINE -4 #define ERROR_OUTFILE -5 #define ERROR_RENAMING -6 #define ERROR_NEXTDIPHONE -7 #define ERROR_PRGWRONGVERSION -10 #define ERROR_TOOMANYPITCH -20 #define ERROR_TOOMANYPHOWOPITCH -21 #define ERROR_PITCHTOOHIGH -22 #define ERROR_PHOLENGTH -30 #define ERROR_PHOREADING -31 #define ERROR_DBNOTFOUND -40 #define ERROR_DBWRONGVERSION -41 #define ERROR_DBWRONGARCHITECTURE -42 #define ERROR_DBNOSILENCE -43 #define ERROR_INFOSTRING -44 #define ERROR_BINNUMBERFORMAT -60 #define ERROR_PERIODTOOLONG -61 #define ERROR_SMOOTHING -62 #define ERROR_UNKNOWNSEGMENT -63 #define ERROR_CANTDUPLICATESEGMENT -64 #define ERROR_TOOMANYPHONEMES -65 #define ERROR_BOOK -70 #define ERROR_CODE -71 #define WARNING_UPGRADE -80 #define WARNING_SATURATION -81 /* buffer cumulating error messages when in lib or dll mode */ extern char errbuffer[]; extern int lasterr_code; /* Code of the last error */ void fatal_message(const int code, const char *format, /* args */ ...); /* * Uses the format of a printf function * throw an exception when in library mode, or abort the program */ void warning_message(const int code, const char *format, /* args */ ...); /* * Uses the format of a printf function * Just print a warning in the error buffer */ #ifdef DEBUG void debug_message(char const *format, /* args */ ...); /* What's below is kind of ugly. When we're in C++ it can be replaced * by an inline debug_message function * * unavoidable if I don't want code to be generated in the release */ #define debug_message1(A) debug_message(A) #define debug_message2(A,B) debug_message(A,B) #define debug_message3(A,B,C) debug_message(A,B,C) #define debug_message4(A,B,C,D) debug_message(A,B,C,D) #define debug_message5(A,B,C,D,E) debug_message(A,B,C,D,E) #define debug_message6(A,B,C,D,E,F) debug_message(A,B,C,D,E,F) #define debug_message7(A,B,C,D,E,F,G) debug_message(A,B,C,D,E,F,G) #define debug_message8(A,B,C,D,E,F,G,H) debug_message(A,B,C,D,E,F,G,H) #else /* don't generate anything */ #define debug_message1(A) #define debug_message2(A,B) #define debug_message3(A,B,C) #define debug_message4(A,B,C,D) #define debug_message5(A,B,C,D,E) #define debug_message6(A,B,C,D,E,F) #define debug_message7(A,B,C,D,E,F,G) #define debug_message8(A,B,C,D,E,F,G,H) #endif #endif mbrola-3.3+dfsg/Parser/000077500000000000000000000000001364272575600150275ustar00rootroot00000000000000mbrola-3.3+dfsg/Parser/fifo.c000066400000000000000000000046771364272575600161340ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: fifo.c * Purpose: a char fifo * * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 18/06/98 : Created */ #include "fifo.h" #include "common.h" int readline_Fifo(Fifo* ff, char *line, int size) /* * Read a line from the circular input buffer * Return 0 if there's nothing to read */ { int i=0; char last=0; while ( (i= available) return(0); while (buffer_in[i]!=0) { /* Check overflow */ if (buffer_end(ff)==buffer_pos(ff)-1) return(i); charbuff(ff)[buffer_end(ff)]=buffer_in[i]; i++; buffer_end(ff)++; /* Circular buffer */ if (buffer_end(ff)==buffer_size(ff)) buffer_end(ff)=0; } return(i); } void reset_Fifo(Fifo* ff) /* * Forget previously entered data in the circular buffer */ { buffer_pos(ff)=0; buffer_end(ff)=0; } void close_Fifo(Fifo* ff) /* * Close the door before leaving */ { MBR_free(charbuff(ff)); MBR_free(ff); } Fifo* init_Fifo(int size) /* * Constructor with size of the buffer */ { Fifo* self=(Fifo*) MBR_malloc( sizeof(Fifo) ); charbuff(self)= (char*) MBR_malloc(size); buffer_size(self)=size; reset_Fifo(self); return(self); } mbrola-3.3+dfsg/Parser/fifo.h000066400000000000000000000036511364272575600161300ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: fifo.h * Purpose: a char fifo * * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 18/06/98 : Created */ #ifndef FIFO_H #define FIFO_H /* Size of the standard phonetic input buffer */ #define FIFO_SIZE 8192 #define LINE_FEED 0x0a typedef struct { char* charbuff; /* circular buffer for phonetic input */ int buffer_pos; /* Current position */ int buffer_end; /* Last available phoneme */ int buffer_size; /* number of chars in Phobuffer */ } Fifo; #define charbuff(ff) ff->charbuff #define buffer_pos(ff) ff->buffer_pos #define buffer_end(ff) ff->buffer_end #define buffer_size(ff) ff->buffer_size int readline_Fifo(Fifo* ff, char *line, int size); /* * Read a line from the input stream in a circular buffer * Return 0 if there's nothing to read */ int write_Fifo(Fifo* ff, char *buffer_in); /* * Write a string of phoneme in the input buffer * Return the number of chars actually written */ void reset_Fifo(Fifo* ff); /* * Forget previously entered data in the circular buffer */ void close_Fifo(Fifo* ff); /* * Release the memory */ Fifo* init_Fifo(int size); /* * Constructor with size of the buffer */ #endif mbrola-3.3+dfsg/Parser/input.h000066400000000000000000000024411364272575600163400ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: input.h * Purpose: polymorphic type for input stream * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 22/06/98 : Created */ #ifndef _INPUT_H #define _INPUT_H typedef struct Input Input; typedef long (*readline_InputFunction)(Input* in, char *line, int size); typedef void (*close_InputFunction)(Input* in); typedef void (*reset_InputFunction)(Input* in); struct Input { void* self; readline_InputFunction readline_Input; close_InputFunction close_Input; close_InputFunction reset_Input; }; #endif mbrola-3.3+dfsg/Parser/input_fifo.c000066400000000000000000000031331364272575600173350ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: input_fifo.c * Purpose: input stream from a fifo (instanciation of input.h) * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 22/06/98 : Created */ #include "fifo.h" #include "input.h" #include "common.h" /* TODO TODO Alleviate the writing directly call with self for all functions, except Close */ static int readline_InputFifo(Input* in, char *line, int size) { return( readline_Fifo((Fifo*) in->self,line,size) ); } static void reset_InputFifo(Input* in) { reset_Fifo((Fifo*) in->self); } static void close_InputFifo(Input* in) { MBR_free(in); } Input* init_InputFifo(Fifo* my_fifo) { Input* self= (Input*) MBR_malloc( sizeof(Input) ); self->self= (void*) my_fifo; self->readline_Input= readline_InputFifo; self->close_Input= close_InputFifo; self->reset_Input= reset_InputFifo; return self; } mbrola-3.3+dfsg/Parser/input_fifo.h000066400000000000000000000020761364272575600173470ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: input_file.h * Purpose: input stream from a fifo (instanciation of input.h) * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 22/06/98 : Created */ #ifndef _INPUT_FIFO_H #define _INPUT_FIFO_H #include "input.h" #include "fifo.h" Input* init_InputFifo(Fifo* my_fifo); #endif mbrola-3.3+dfsg/Parser/input_file.c000066400000000000000000000031471364272575600173360ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: input_file.c * Purpose: input stream from a file (instanciation of input.h) * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 22/06/98 : Created */ #include "mbralloc.h" #include "input_file.h" /* TODO TODO Alleviate the writing directly call with self for all functions, except Close */ static long readline_InputFile(Input* in, char *line, int size) { return( (long) fgets(line, size, (FILE*)in->self)); } static void reset_InputFile(Input* in) /* nothing to reset a file ! */ { } static void close_InputFile(Input* in) /* nothing to close */ { MBR_free(in); } Input* init_InputFile(FILE* my_file ) { Input* self= (Input*) MBR_malloc( sizeof(Input) ); self->self= (void*) my_file; self->readline_Input= readline_InputFile; self->close_Input= close_InputFile; self->reset_Input= reset_InputFile; return self; } mbrola-3.3+dfsg/Parser/input_file.h000066400000000000000000000020541364272575600173370ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: input_file.h * Purpose: input stream from a file handler * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 22/06/98 : Created */ #ifndef _INPUT_FILE_H #define _INPUT_FILE_H #include #include "input.h" Input* init_InputFile(FILE* my_file ); #endif mbrola-3.3+dfsg/Parser/parser.h000066400000000000000000000037311364272575600165000ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: parser_fifo.c * Purpose: polymorphic type to parse a "pho file" * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 18/06/98 : Created */ #ifndef _PARSER_H #define _PARSER_H #include "phone.h" /* Return values of the nextphone function */ typedef enum { PHO_OK, PHO_EOF, PHO_FLUSH, PHO_ERROR } StatePhone; /* Polymorphic type */ typedef struct Parser Parser; typedef void (*reset_ParserFunction)(Parser* ps); typedef void (*close_ParserFunction)(Parser* ps); typedef StatePhone (*nextphone_ParserFunction)(Parser* ps,Phone** ph); /* * Generic parser : * reset: forget remaining data in the buffer (when the user STOP synthesis for example * * close: release the memory * * nextphone: return the next Phoneme from input. * * PRECONDITION: this phoneme MUST have a pitch point at 0 and 100% * * THE CALLER IS IN CHARGE OF CALLING close_Phone ON THE PHONES HE GETS * WITH nextphone */ struct Parser { void* self; /* Polymorphic on the real type */ reset_ParserFunction reset_Parser; /* virtual func */ close_ParserFunction close_Parser; /* virtual func */ nextphone_ParserFunction nextphone_Parser; /* virtual func */ }; #endif mbrola-3.3+dfsg/Parser/parser_input.c000066400000000000000000000041321364272575600177060ustar00rootroot00000000000000/* FPMs-TCTS SOFTWARE LIBRARY * * File: parser_input.c * Purpose: parse a "pho file" from a polymorphic input stream * Instanciation of parser.h * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <2000-03-28 17:58:06 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 18/06/98 : Created * 21/10/98 : Initialize flush */ #include "parser_input.h" #include "phonbuff.h" /* TODO TODO Alleviate the writing directly call with self for all functions, except Close */ static void close_ParserInput(Parser* self) { close_PhoneBuff((PhoneBuff*)self->self); MBR_free(self); } static void reset_ParserInput(Parser* self) { reset_PhoneBuff( (PhoneBuff*) self->self); } static StatePhone nextphone_ParserInput(Parser* self,Phone** ph) { return(next_PhoneBuff((PhoneBuff*)self->self, ph)); } Parser* init_ParserInput(Input* my_input, char* silence, float pitch, float time_ratio, float freq_ratio, char* comment, char* flush) /* * Constructor of the parser. Need to know initial default pitch, and * initial default phoneme as well */ { Parser* self= (Parser*) MBR_malloc( sizeof(Parser)); self->reset_Parser= reset_ParserInput; self->close_Parser= close_ParserInput; self->nextphone_Parser= nextphone_ParserInput; self->self= (void*) init_PhoneBuff(my_input, silence, pitch, time_ratio, freq_ratio, comment, flush); return(self); } mbrola-3.3+dfsg/Parser/parser_input.h000066400000000000000000000025771364272575600177260ustar00rootroot00000000000000/* FPMs-TCTS SOFTWARE LIBRARY * * File: parser_input.h * Purpose: parse a "pho file" from a polymorphic input stream * Instanciation of parser.h * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <1998-10-21 16:16:34 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 18/06/98 : Created * 21/10/98 : Initialize flush */ #ifndef PARSER_INPUT_H #define PARSER_INPUT_H #include "parser.h" #include "input.h" Parser* init_ParserInput(Input* my_input, char* silence, float pitch, float time_ratio, float freq_ratio, char* comment, char* flush); /* * Constructor of the parser. Need to know initial default pitch, and * initial default phoneme as well */ #endif mbrola-3.3+dfsg/Parser/phonbuff.c000066400000000000000000000334171364272575600170120ustar00rootroot00000000000000/* FPMs-TCTS SOFTWARE LIBRARY * * File: phonbuff.c * Purpose: Table of phonemes to implement a simple .pho parser * Buffer of phonemes for pitch interpolation * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <00/03/29 14:36:10 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 11/06/98 : Created from readpho.c * Warning -> this is a sample program of what a parser could * be, feel free to implement your own parser (as long as it * follows the requirements of parser.h) * * 15/09/98 : In case there's too many phonemes without pitch points, we * compulsorily add a value with default_pitch (avoid fatal_message) */ #include "common.h" #include "diphone.h" #include "database.h" #include "hash_tab.h" #include "mbrola.h" #include "parser.h" #include "phonbuff.h" void init_FlushSymbol(PhoneBuff* pt, char *flush) /* * Build a new sscanf target to spot the flush symbol */ { /* Null means put a default value if there is none */ if (flush==NULL) flush=FLUSH; if (flush_symbol(pt)!=NULL) MBR_free(flush_symbol(pt)); flush_symbol(pt)= (char *) MBR_malloc( strlen(flush) + 3); sprintf(flush_symbol(pt),"%s%%n",flush); } void init_CommentSymbol(PhoneBuff* pt, char *comment) /* * Build a new sscanf target to spot the comment symbol */ { /* Null means put a default value if there is none */ if (comment==NULL) comment=COMMENT; if (comment_symbol(pt)!=NULL) free(comment_symbol(pt)); comment_symbol(pt)= (char *) MBR_malloc( strlen(comment) + 3); sprintf(comment_symbol(pt),"%s%%n",comment); } void initdummy_PhoneBuff(PhoneBuff* pt) { Phone* my_phone; /* silence with dummy length, and 1 pitch point at 0% equal * to FirstPitch for interpolation */ my_phone=init_Phone(default_phon(pt), 0.0f); appendf0_Phone(my_phone, 0.0f, default_pitch(pt)); pt->Buff[0]=my_phone; CurPhone(pt)=0; /* Forces FillCommandBuffer to read new data and */ NPhones(pt)=0; /* consider PhoneBuff[0] as the previous phone */ state_pho(pt)=PHO_OK; /* Reset ReadPho internal flag */ Closed(pt)=False; } void free_residue_PhoneBuff(PhoneBuff *pt) /* free allocated strings in the phonetable */ { int i; /* In charge of freeing what have not been passed to the synthesizer */ for(i=CurPhone(pt); ireset_Input(input(pt)); } PhoneBuff* init_PhoneBuff(Input* my_input, char* default_phon, float default_pitch, float time_ratio, float freq_ratio, char* comment, char* flush) /* * Phonetab Constructor */ { PhoneBuff* self= (PhoneBuff*) MBR_malloc( sizeof(PhoneBuff)); input(self)=my_input; /* polymorphic input stream */ default_pitch(self)=default_pitch; default_phon(self)=default_phon; TimeRatio(self)=time_ratio; FreqRatio(self)=freq_ratio; initdummy_PhoneBuff(self); flush_symbol(self)=NULL; comment_symbol(self)=NULL; init_FlushSymbol(self,flush); init_CommentSymbol(self,comment); return(self); } void shift_PhoneBuff(PhoneBuff *pt) /* * Reset the phonetable to an empty value */ { /* PhoneBuff[0] filled with last phone of previous fill */ head_PhoneBuff(pt)=tail_PhoneBuff(pt); /* The first pitch point will have index 1 */ /* Leaves the first position free for 0% pitch point */ CurPhone(pt)=0; NPhones(pt)=0; Closed(pt)=False; } void append_PhoneBuff(PhoneBuff *pt,char *name,float length) /* * Append a new phone at the end of the table * if too many phones without pitch information, add a pitch point with * default pitch */ { Phone *my_phone; NPhones(pt)++; my_phone= init_Phone(name,length); tail_PhoneBuff(pt)= my_phone; /* Dummy point for later 0% value */ appendf0_Phone(tail_PhoneBuff(pt), 0.0f, 0.0f); /* Test overflow ... I consider this is not fatal any more, just add a compulsory pitch point */ if (NPhones(pt)==MAXNPHONESINONESHOT-2) { warning_message(ERROR_TOOMANYPHOWOPITCH, "Too many phones without pitch information at '%s'\n",name); /* Energic measures to force a pitch point */ appendf0_Phone(my_phone, 0.0, default_pitch(pt)); } } void interpolatef0_PhoneBuff(PhoneBuff *pt) /* * Interpolate 0% and 100% value for each phone of the table */ { int i; float CurPos; float a, b; /* Interpolation parameters */ float InterpLength=0.0f; /* Sum the lengths without the borders */ for(i=1; iPitchPattern[0].pos= 0.0f; val_PhoneBuff(pt,NPhones(pt))->PitchPattern[0].freq= a*CurPos + b; /* Add 100% pitch point to the 1st phoneme */ appendf0_Phone(head_PhoneBuff(pt), 100.0, freq_Pitch(head_PitchPattern(val_PhoneBuff(pt,1)))); } /* Interpolated, until next sequence ! */ Closed(pt)=True; } StatePhone ReadLine(PhoneBuff* pt, char *line, int size) /* * Skip empty lines * Skip comment line ( begins with a ; ) * Detect # which means end of chunk ( equivallent to eof ) * Return value may be: PHO_EOF,PHO_FLUSH,PHO_OK */ { unsigned int comment, stream_flush; int leading_blank; float fvalue; char *rest; debug_message1("ReadLine\n"); do { /* * InputLine depends on what is connected to photab * according to compilation mode */ if (! input(pt)->readline_Input( input(pt), line, size) ) return(PHO_EOF); debug_message2("line: %s\n", line); comment=0; stream_flush=0; leading_blank=0; sscanf(line," %n",&leading_blank); rest= &line[leading_blank]; sscanf(rest, comment_symbol(pt), &comment); sscanf(rest, flush_symbol(pt), &stream_flush); if (stream_flush) return(PHO_FLUSH); if (comment) { int command; /* Check if this is a true comment ; or a command ;; */ rest= &rest[comment]; command=0; sscanf(rest,comment_symbol(pt), &command); if (command) { /* Test ";; T=1.2" <- Time ratio */ /* Test ";; F=0.8" <- Frequency ratio */ /* Test ";; FLUSH ###" <- Flush symbol renaming */ char new_name[100]; rest=&rest[comment]; if (sscanf(rest," T = %f",&fvalue)==1) TimeRatio(pt)=fvalue; else if (sscanf(rest," F = %f",&fvalue)==1) FreqRatio(pt)=fvalue; else if (sscanf(rest," FLUSH %s",new_name)==1) { /* New Flush symbol */ init_FlushSymbol(pt,new_name); } } else { /* A true meaningless comment :-) */ } } } #if defined(TARGET_OS_DOS) || defined(__EMX__) while (comment || (leading_blank==strlen(line)) || (leading_blank==strlen(line)-1)); #else while (comment || (leading_blank==strlen(line))); #endif debug_message1("done ReadLine\n"); return(PHO_OK); } StatePhone FillCommandBuffer(PhoneBuff *pt) /* * Reads phonemes from the input file and put it in a buffer for pitch * interpolation. * Return value may be: PHO_EOF, PHO_FLUSH, PHO_OK * * Input file format is line with format : Phoneme Length (pos freq)* * Phone = phoneme name * Length= phoneme length in ms * pos = position (in % of total phone duration) of a pitch pattern point * freq = F0 (Hz) value of that pitch pattern point */ { char name[255]; float length; float pos, f0; int j,k; int position,new_pos; /* string index of pitch-pair being processed */ int val; /* Result of sscanf -> detection of syntax errors */ StatePhone state_line; /* Return value */ char a_line[1024]; /* An input line in the command file */ debug_message1("FillCommandBuffer\n"); /* Order of the phoneme */ j=1; do /* Analyze lines we have pitchpoints */ { state_line=ReadLine(pt, a_line, sizeof(a_line)); /* Incidents during reading */ #ifdef LIBRARY /* In LIBRARY or DLL mode */ if (state_line==PHO_FLUSH) #else /* in file mode -> eof on a file means FLUSH */ if ( (state_line==PHO_FLUSH) || (state_line==PHO_EOF)) #endif { /* If we have to flush, add 3 trailing silences */ /* the 1st one will help reveal the last phoneme ! */ append_PhoneBuff(pt, default_phon(pt),0); /* The 2nd will be issued */ append_PhoneBuff(pt, default_phon(pt),0); /* * The 3rd one won't even issued with nextphone_Parser, but * compulsory to provide F0 interpolation value */ append_PhoneBuff(pt, default_phon(pt),0); appendf0_Phone(tail_PhoneBuff(pt),0.0f,default_pitch(pt)*FreqRatio(pt)); break; } else if (state_line==PHO_EOF) { /* If EOF, then simply return the state as is for later completion */ return(PHO_EOF); } /* Retrieves PHONEME_NAME LENGTH_IN_MS */ val=sscanf(a_line,"%s %f%n",name,&length,&position); /* it's a silence add an anti spreading 0ms silence */ if (strcmp(name, default_phon(pt))==0) { append_PhoneBuff(pt, default_phon(pt),0); } /* A New phoneme */ append_PhoneBuff(pt, name, length*TimeRatio(pt)); if (val!=2) /* Check syntax */ { fatal_message(ERROR_SYNTAXERROR,"Fatal error in line:%s\n",a_line); return PHO_ERROR; } /* * Read pairs of POSITION PITCH_VALUE till the end of a_line * Eventually the pairs can be surrounded with () * WARNING:if the first condition is checked, the second call to sscanf * is dropped */ k=1; while ( (sscanf(&a_line[position]," ( %f , %f ) %n", &pos, &f0, &new_pos)==2) || (sscanf(&a_line[position]," %f %f%n", &pos, &f0, &new_pos)==2)) { f0*=FreqRatio(pt); appendf0_Phone(tail_PhoneBuff(pt),pos,f0); k++; position+=new_pos; } /* Check for residual characters in the line */ if (sscanf(&a_line[position],"%*s")!=-1) { fatal_message(ERROR_UNKNOWNCOMMAND, "Fatal error in line:%s\n" "At the pitch pair:%s????\n", a_line,&a_line[position]); return PHO_ERROR; } j++; } while ( NPitchPatternPoints(tail_PhoneBuff(pt)) == 1 ); /* We have a serie of phonemes with coherent pitch points, * interpolate them, and close the sequence */ interpolatef0_PhoneBuff(pt); #ifdef DEBUG { int jj; debug_message1("READLINE:\n"); for(jj=0;jj<=NPhones(pt);jj++) { int kk; debug_message2("Phoneme:%s ", name_Phone(val_PhoneBuff(pt,jj))); for(kk=0; kk< NPitchPatternPoints(pt->Buff[jj]) ; kk++) debug_message3("(%f %f) ", pos_Pitch(val_PitchPattern(pt->Buff[jj],kk)), freq_Pitch(val_PitchPattern(pt->Buff[jj],kk))); debug_message1("\n"); } } debug_message1("done FillCommandBuffer\n"); #endif return(state_line); } StatePhone next_PhoneBuff(PhoneBuff *pt, Phone** ph) /* * Reads a phone from the phonetic command buffer and prepares the next * diphone to synthesize ( prev_diph ) * Return value may be: PHO_EOF,PHO_FLUSH,PHO_OK * * NB : Uses only phones from 1 to ... NPhones-1 in the buffer. * Phone 0 = memory from previous buffer. */ { debug_message1("NextDiphone\n"); if ((CurPhone(pt)==NPhones(pt)) || (!Closed(pt))) { /* Must read buffer ahead */ /* Shift the phonetable if new data needed */ if (CurPhone(pt)==NPhones(pt)) shift_PhoneBuff(pt); /* * Test if the previous call to FillCommandBuffer had resulted in * FLUSH or EOF. EOF is possible only with the non-library version */ if ( (state_pho(pt)==PHO_FLUSH) || (state_pho(pt)==PHO_EOF)) { StatePhone temp=state_pho(pt); state_pho(pt)=PHO_OK; /* reset */ return(temp); } /* Read new phoneme serie */ state_pho(pt)=FillCommandBuffer(pt); /* Premature exit */ if (state_pho(pt)==PHO_ERROR) return PHO_ERROR; /* The pitch sequence is not complete */ if (!Closed(pt)) { state_pho(pt)=PHO_OK; /* reset for further readings */ return(PHO_EOF); } } *ph= val_PhoneBuff(pt,CurPhone(pt)) ; CurPhone(pt)++; debug_message1("done NextDiphone\n"); return(PHO_OK); } mbrola-3.3+dfsg/Parser/phonbuff.h000066400000000000000000000104121364272575600170050ustar00rootroot00000000000000/* FPMs-TCTS SOFTWARE LIBRARY * * File: phonbuff.c * Purpose: Table of phonemes to implement a simple .pho parser * Buffer of phonemes for pitch interpolation * Author: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <1998-10-21 16:14:51 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 11/06/98 : Created from readpho.c * Warning -> this is a sample program of what a parser could * be, feel free to implement your own parser (as long as it * follows the requirements of parser.h) * * 20/10/98 : initialize flush from constructor */ #ifndef _PHONEBUFF_H #define _PHONEBUFF_H #include "diphone.h" #include "input.h" #include "parser.h" #define MAXNPHONESINONESHOT 250 /* Max nbr of phonemes without F0 pattern*/ /* A phonetic command buffer and its pitch points */ typedef struct { Input* input; /* Polymorphic input stream */ Phone* Buff[MAXNPHONESINONESHOT];/* Phonetic command buffer */ int NPhones; /* Nbr of phones in the phonetic command buffer */ int CurPhone; /* Index of current phone in the command buffer */ StatePhone state_pho; /* State of the last phoneme serie: EOF FLUSH OK */ bool Closed; /* True if the sequence is closed by a pitch point */ /* * Silence is a special phoneme used for initialization (the first diphone * in the stream is always SILENCE-SILENCE. Also used for termination */ char *default_phon; float default_pitch; /* first pitch point of the sequence */ char *comment_symbol; /* user defined escape char */ char *flush_symbol; /* user defined flush command */ float TimeRatio; /* Ratio for the durations of the phones */ float FreqRatio; /* Ratio for the pitch applied to the phones */ } PhoneBuff; /* Convenient macro to access Phonetable */ #define input(X) (X->input) #define CurPho(X) (X->Buff[X->CurPhone]) #define NPhones(X) X->NPhones #define CurPhone(X) X->CurPhone #define Buff(X) X->Buff #define val_PhoneBuff(pt,i) (pt->Buff[i]) #define state_pho(pt) (pt->state_pho) #define Closed(pt) (pt->Closed) #define default_phon(pt) (pt->default_phon) #define default_pitch(pt) (pt->default_pitch) #define comment_symbol(pt) (pt->comment_symbol) #define flush_symbol(pt) (pt->flush_symbol) #define TimeRatio(pt) (pt->TimeRatio) #define FreqRatio(pt) (pt->FreqRatio) /* * Last phone of the list */ #define tail_PhoneBuff(pt) (val_PhoneBuff(pt,NPhones(pt))) /* * First phone of the list */ #define head_PhoneBuff(pt) (val_PhoneBuff(pt,0)) PhoneBuff* init_PhoneBuff(Input* my_input, char* default_phon,float default_pitch, float time_ratio, float freq_ratio,char* comment, char* flush); /* * Constructor, needs a phoneme and pitch for default allocation (begin * and end of synthesis) */ void close_PhoneBuff(PhoneBuff *pt); /* free allocated strings in the phonetable */ void reset_PhoneBuff(PhoneBuff *pt); /* Before a synthesis sequence initialize the loop with a silence */ StatePhone next_PhoneBuff(PhoneBuff *pt,Phone** ph); /* * Reads a phone from the phonetic command buffer and prepares the next * diphone to synthesize ( prev_diph ) * Return value may be: PHO_EOF,PHO_FLUSH,PHO_OK, PHO_ERROR * * NB : Uses only phones from 1 to ... NPhones-1 in the buffer. * Phone 0 = memory from previous buffer. */ void init_FlushSymbol(PhoneBuff *pt, char *flush); /* * Build a new sscanf target to spot the flush symbol */ void init_CommentSymbol(PhoneBuff *pt, char *comment); /* * Build a new sscanf target to spot the comment symbol */ void init_SilenceSymbol(PhoneBuff *pt, char *silence); /* * Build a new sscanf target to spot the comment symbol */ #endif mbrola-3.3+dfsg/Parser/phone.c000066400000000000000000000066751364272575600163220ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: phone.c * Purpose: Phone objects * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <2000-03-28 17:57:46 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 23/06/98 : Created from diphone.c * The functions are exported to the DLL in the case of a * user defined Parser (the parser must return phonemes). * * 28/08/98 : added applyRatio_Phone to modify length and freq according * to a vocal tract ratio. It ends here because the Vocal Tract ratio * is not the business of the Parser (so the variable does leave the * Engine section). * * 15/09/98 : appendf0_Phone now enlarge the pitch point table if it's * too small (no more "fatal_error"). */ #include "phone.h" Phone* DLL_EXPORT initSized_Phone(char* name, float length, int nb_pitch) /* * Initialize a phoneme with its name and length in milliseconds * Indicate the planned number of pitch points ( added with appendf0) */ { Phone* self= (Phone*) MBR_malloc(sizeof(Phone)); name_Phone(self)=MBR_strdup(name); length_Phone(self)=length; reset_Phone(self); /* allocate the pitch slots */ pp_available(self)= nb_pitch; self->PitchPattern= (PitchPatternPoint*) MBR_malloc( sizeof(PitchPatternPoint) * pp_available(self)); return(self); } Phone* DLL_EXPORT init_Phone(char* name, float length) /* * Initialize a phoneme with its name and length in milliseconds * 2 pitch points is the default (one at 0 one at 100) */ { return initSized_Phone(name,length,2); } void DLL_EXPORT reset_Phone(Phone *ph) /* Reset the pitch pattern list of a phoneme */ { ph->NPitchPatternPoints=0; } void DLL_EXPORT close_Phone(Phone *ph) /* * Release the name in the string */ { if (name_Phone(ph)) MBR_free(name_Phone(ph)); MBR_free( PitchPattern(ph) ); MBR_free(ph); } void DLL_EXPORT appendf0_Phone(Phone *ph, float pos, float f0) /* * Append a pitch point to a phoneme ( position in % and f0 in Hertz ) * resize the pitch point vector if too small */ { int index_f0= NPitchPatternPoints(ph); /* Enlarge the pitch point vector ? */ if (index_f0 == (pp_available(ph)-1)) { pp_available(ph)+=2; PitchPattern(ph)= (PitchPatternPoint*) MBR_realloc( PitchPattern(ph), sizeof(PitchPatternPoint) * pp_available(ph)); } pos_Pitch( val_PitchPattern(ph,index_f0))= pos/100.0f * length_Phone(ph); freq_Pitch( val_PitchPattern(ph,index_f0))= f0; NPitchPatternPoints(ph)++; } void applyRatio_Phone(Phone* ph, float ratio) /* length and freq modified if the vocal tract length is not 1.0 */ { int i; /* need to change anything ? */ if (ratio==1.0) return; length_Phone(ph)*= ratio; for(i=0; i< ph->NPitchPatternPoints; i++) { ph->PitchPattern[i].pos *= ratio; ph->PitchPattern[i].freq /= ratio; } } mbrola-3.3+dfsg/Parser/phone.h000066400000000000000000000065361364272575600163230ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: phone.cpp * Purpose: Phone objects * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <2000-03-28 17:50:14 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 23/06/98 : Created from diphone.cpp * The functions are exported to the DLL in the case of a * user defined Parser (the parser must return phonemes). */ #ifndef _PHONE_H #define _PHONE_H #include "common.h" /* * STRUCTURES representing phones and diphone sequences to synthesize */ /* Pitch pattern point attached to a Phoneme */ typedef struct { float pos; /* relative position within phone in milliseconds */ float freq; /* frequency (Hz)*/ } PitchPatternPoint; #define pos_Pitch(X) X->pos #define freq_Pitch(X) X->freq /* A Phoneme and its pitch points */ typedef struct { char *name; /* Name of the phone */ float length; /* phoneme length in ms */ int NPitchPatternPoints; /* Nbr of pattern points */ int pp_available; /* number of allocatables pitch points */ PitchPatternPoint* PitchPattern; /* PitchPattern[0] gives F0 at 0% of the duration of a phone, and the last pattern point (PitchPattern[NPitchPatternPoints-1]) gives F0 at 100% ( reserve 2 slots for 0% and 100% during interpolation ) */ } Phone; /* Convenient macro to access Phone structure */ #define tail_PitchPattern(X) (&(X->PitchPattern[X->NPitchPatternPoints-1])) #define head_PitchPattern(X) (&(X->PitchPattern[0])) #define val_PitchPattern(X,i) (&(X->PitchPattern[i])) #define length_Phone(X) (X->length) #define name_Phone(X) (X->name) #define NPitchPatternPoints(X) (X->NPitchPatternPoints) #define pp_available(X) (X->pp_available) #define PitchPattern(X) (X->PitchPattern) Phone* DLL_EXPORT initSized_Phone(char* name, float length, int nb_pitch); /* * Initialize a phoneme with its name and length in milliseconds * Indicate the planned number of pitch points ( added with appendf0) */ Phone* DLL_EXPORT init_Phone(char* name, float length); /* * Initialize a phoneme with its name and length in milliseconds * 2 pitch points is the default (one at 0 one at 100) */ void DLL_EXPORT reset_Phone(Phone *ph); /* Reset the pitch pattern list of a phoneme */ void DLL_EXPORT close_Phone(Phone *ph); /* * Release the name in the string */ void DLL_EXPORT appendf0_Phone(Phone *ph, float pos, float f0); /* * Append a pitch point to a phoneme ( position in % and f0 in Hertz ) * resize the pitch point vector if too small */ void applyRatio_Phone(Phone* ph, float ratio); /* * length and freq modified if the vocal tract length is not 1.0 * internal use only */ #endif mbrola-3.3+dfsg/Parser/phone_export.h000066400000000000000000000035601364272575600177160ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: phone_export.cpp * Purpose: Phone objects, exported interface * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <1999-06-11 17:30:19 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 11/06/99 : Created phone.h * Function exported in the library in the case of a * user defined Parser (the parser must return phonemes). */ #ifndef _PHONE_H #define _PHONE_H /* Dummy structure */ typedef void Phone; Phone* initSized_Phone(char* name, float length, int nb_pitch); /* * Initialize a phoneme with its name and length in milliseconds * Indicate the planned number of pitch points ( added with appendf0) */ Phone* init_Phone(char* name, float length); /* * Initialize a phoneme with its name and length in milliseconds * 2 pitch points is the default (one at 0 one at 100) */ void reset_Phone(Phone *ph); /* Reset the pitch pattern list of a phoneme */ void close_Phone(Phone *ph); /* * Release the name in the string */ void appendf0_Phone(Phone *ph, float pos, float f0); /* * Append a pitch point to a phoneme ( position in % and f0 in Hertz ) * resize the pitch point vector if too small */ #endif mbrola-3.3+dfsg/README.md000066400000000000000000000373111364272575600150570ustar00rootroot00000000000000# Welcome to MBROLA project __Table of contents__ - [A brief description of MBROLA](#a-brief-description-of-mbrola) - [Compilation](#compilation) - [Execution](#execution) - [Using Pipes](#using-pipes) - [Renaming and Cloning phonemes](#renaming-and-cloning-phonemes) - [On MSDOS/Windows](#on-msdoswindows) - [On modern Linux](#on-modern-linux) - [On Sun4 or with machines with an old audio interface](#on-sun4-or-with-machines-with-an-old-audio-interface) - [On VAX or AXP workstations](#on-vax-or-axp-workstations) - [Format of input and output files - Limitations](#format-of-input-and-output-files---limitations) - [Phoneme commands](#phoneme-commands) - [Changing the Freq Ratio or Time Ratio](#changing-the-freq-ratio-or-time-ratio) - [Flush the output stream](#flush-the-output-stream) - [Limitations of the program](#limitations-of-the-program) - [BUGS](#bugs) - [Feedback](#feedback) - [License](#license) # A brief description of MBROLA MBROLA is a speech synthesizer based on the concatenation of diphones. It takes a list of phonemes as input, together with prosodic information (duration of phonemes and a piecewise linear description of pitch), and produces speech samples on 16 bits (linear), at the sampling frequency of the diphone database. Please look at [MBROLA-voices](https://github.com/numediart/MBROLA-voices) project homepage to get the voices. You may also develop your own voices using the [MBROLATOR](https://github.com/numediart/MBROLATOR). It is therefore NOT a Text-To-Speech (TTS) synthesizer, since it does not accept raw text as input. In order to obtain a full TTS system, you need to use this synthesizer in combination with a text processing system that produces phonetic and prosodic commands. The synthesizer uses a synthesis method known itself as MBROLA. See more at [development history](Documentation/HISTORY.txt). # Compilation You need C compiler and libraries to compile the project. On Debian-based Linux you need to install following packages: ``` sudo apt-get install make gcc ``` To compile your own binary, execute command: ``` make ``` To clean project, execute command: ``` make clean ``` Look for [makefile details](README_Makefile.md), if compilation is not successful. More documentation for developers is located in [Documentation](Documentation) folder of the project. # Execution First try: ``` mbrola ``` from `Bin` folder of the project to see the terms and conditions on the use of this software. Then try: ``` mbrola -h ``` to get some help on how to use the software, e.g.: ``` USAGE: mbrola [COMMAND LINE OPTIONS] database pho_file+ output_file A - instead of pho_file or output_file means stdin or stdout Extension of output_file ( raw, au, wav, aiff ) tells the wanted audio format Options can be any of the following: -i = display the database information if any -e = IGNORE fatal errors on unknown diphone -c CC = set COMMENT char (escape sequence in pho files) -F FC = set FLUSH command name -v VR = VOLUME ratio, float ratio applied to ouput samples -f FR = FREQ ratio, float ratio applied to pitch points -t TR = TIME ratio, float ratio applied to phone durations -l VF = VOICE freq, target freq for voice quality -R RL = Phoneme RENAME list of the form a A b B ... -C CL = Phoneme CLONE list of the form a A b B ... -I IF = Initialization file containing one command per line CLONE, RENAME, VOICE, TIME, FREQ, VOLUME, FLUSH, COMMENT, and IGNORE are available -W = store the datbase in ROM format -w = the database in a ROM dump -d = Show list of diphones in the database ``` Now in order to go further, you need to get a version of an MBROLA language/voice database from the [MBROLA-voices](https://github.com/numediart/MBROLA-voices) page or create one using the [MBROLATOR] (https://github.com/numediart/MBROLATOR). Let us assume you have copied the FR1 database and referred to the accompanying fr1.txt file for its installation. Then try e.g.: `mbrola fr1/fr1 fr1/TEST/bonjour.pho bonjour.wav` it uses the format: `mbrola diphone_database command_file1 command_file2 ... output_file` and creates a sound file for the word 'bonjour'. Basically the output file is composed of signed integer numbers on 16 bits, corresponding to samples at the sampling frequency of the MBROLA voice/language database (16 kHz for the diphone database supplied by the author of MBROLA : Fr1). MBROLA can produce different audio file formats: .au, .wav, .aiff, .aif, and .raw files depending on the ouput_file extension. If the extension is not recognized, the format is RAW (no header). We recommand .wav for Windows, and .au for Unix platforms. To display information about the phoneme set used by the database, type: ``` mbrola -i fr1/fr1 ``` It displays the phonetic alphabet as well as copyright information about the database. Option `-e` makes Mbrola ignore wrong or missing diphone sequences (replaced by silence) which can be quite useful when debugging your TTS. Equivallent to "IGNORE" directive in the initialization file (N.B replace the obsolete ;;E=OFF , unsupported in .pho file). Optional parameters let you shorten or lengthen synthetic speech and transpose it by providing optional time and frequency ratios: ``` mbrola -t 1.2 -f 0.8 fr1/fr1 TEST/bonjour.pho bonjour.wav ``` or its equivalent in the initialization file: ``` TIME 1.2 FREQ 0.8 ``` for instance, will result in a RIFF Wav file bonjour.wav 1.2 times longer than the previous one (slower rate), and containing speech in which all fundamental frequency values have been multiplied by 0.8 (sounds lower). You can also set the values of these coefficients directly in a .pho file by adding special escape sequences like : ``` ;; F=0.8 ;; T=1.2 ``` You can change the voice characteristics with the -l parameter. If the sampling rate of your database is 16000, indicating -l 18000 allows you to shorten the vocal tract by a ratio of 16/18 (children voice, or women voice depending on the voice you're working on). With -l 10000, you can lengthen the vocal tract by a ratio of 16/10 (namely the voice of a Troll). The same command in an initialization file becomes "VOICE 10000". Option `-v` specifies a VolumeRatio which multiplies each output sample. In the example below, each sample is multipliead by 0.7 (the loudness goes down). Warning: setting VolumeRatio too high generates saturation. ``` mbrola -v 0.7 fr1/fr1 TEST/bonjour.pho bonjour.wav ``` or add `VOLUME 0.7` in an initialization file The `-c` option lets you specify which symbol will be used as an escape sequence for comments and commands in .pho files. The default value is the semi-colon `;`, but you may want to change this if your phonetic alphabet uses this symbol, like in: ``` mbrola -c ! fr1/fr1 TEST/test1.pho test2.pho test.wav ``` equivalent to "COMMENT !" in an initialization file The `-F` option lets you specify which symbol will be used to Flush the audio output. The default value is #, you may want to change the symbol like in: ``` mbrola -F FLUSH_COMMAND fr1/fr1 test.pho test.wav ``` equivalent to "FLUSH FLUSH_COMMAND" in the initialization file. ## Using Pipes A - instead of command_file or output_file means stdin or stdout. On multitasking machines, it is easy to run the synthesizer in real time to obtain audio output from the audio device, by using pipes. ## Renaming and Cloning phonemes It may happen that the language processing module connected to MBROLA doesn't use the same phonemic alphabet as the voice used. The Renaming and Cloning mechanisms help you to quickly solve such problems (without adding extra CPU load). The only limitation about phoneme names is that they can't contain blank characters. If, for instance, phoneme "a" in the mbrola voice you use is called "my_a" in your alphabet, and phoneme "b" is called "my_b", then the following command solves the problem: ``` mbrola -R "a my_a b my_b" fr1/fr1 test.pho test.wav ``` You can give as many renaming pairs as you want. Circular definition are not a problem -> "a b b c" will rename original [a] into [b] and original [b] into [c] independantly ([a] won't be renamed to [c]). LIMITATION: you can't rename a phoneme into another that already exists. The cloning mechanism does exactly the same thing, though the old phoneme still exists after renaming. This is usefull if you have 2 allophones in your alphabet, but the Mbrola voice only provides one. Imagine for instance, that you make the disctinction between the voiced [r] and its unvoiced counterpart [r0] and that you are using a syllabic version [r=]. If as a first approximation using [r] for both is OK, then you may use an Mbrola voice that only provides one version of [r] by running: ``` mbrola -C "r r0 r r=" fr1/fr1 test.pho test.wav ``` which tells the synthesizer that [r0] and [r=] should be both synthesized as [r]. You can write a long cloning list of phoneme pairs to fit your needs. Renaming and cloning eats CPU since the complete diphone hash table has to be rebuilt, but once the renaming or cloning has occurred there is absolutely NO RELATED PERFORMANCE DROP. So using this feature is more efficient than a pre-processor, though incompatibilities cannot always be solved by a simple phoneme mapping. Before renaming anything as #, check paragraph 5.4 When you have long cloning and renaming lists, you can conveniently write them into an initialization file according to the following format: ``` RENAME a my_a RENAME b my_b CLONE r r0 CLONE r r= ``` The obsolete `;; RENAME a my_a` can't be used in .pho file anymore, but is correctly parsed in initialization files. Note to Festival and EN1 users: the consequence of the change above is that you must change the previous call format `mbrola en1 en1mrpa ...` into `mbrola -I en1mrpa en1 ...`. BELOW ARE A NUMBER OF MACHINE DEPENDANT HINTS FOR BEST USING MBROLA ## On MSDOS/Windows Type: ``` mbrola fr1/fr1 TEST/bonjour.pho bonjour.wav ``` Then you can play the RIFF Wav file with windows sound utility or pipes may be used just like below. ## On modern Linux ``` mbrola fr1/fr1 TEST/bonjour.pho -.au | aplay ``` where `aplay` is your audio file player (`aplay` for ALSA `paplay` for PulseAudio). If your audioplayer has problems with sun .AU files, try with .raw Never use .wav format when you pipe the ouput (mbrola can't rewind the file to write the audio size in the header). Wav format was not developped for Unix (on the contrary Au format let you specify in the header "we're on a pipe, read until end of file"). ## On Sun4 or with machines with an old audio interface Those machines are now quite old and only provide a mulaw 8Khz output. A hack is: ``` mbrola fr1/fr1 input.pho - | sox -t raw -sw -r 16000 - -t raw -Ub -r 8000 - > /dev/audio ``` (providing you have the public domain sox utility developed by Ircam). You should hear 'bonjour' without the need to create intermediate files. Note that we strongly recommend that you DON'T use SOX, since its resampling method (linear interpolation) will permanently damage the sound. ## On VAX or AXP workstations To make it easier for users to find MBROLA, you should add the following command to your system startup procedure: ``` $ DEFINE/SYSTEM/EXEC MBROLA_DIR disk:[dir] where "disk:[dir]" is the name of the directory you created for the MBROLA_DIR files. You could also add the following command to your system login command procedure: $ MBROLA :== $MBROLA_DIR:MBROLA.EXE $ RAW2SUN :== $MBROLA_DIR:RAW2SUN.EXE to use the decsound device: $ MCR DECSOUND - volume 40 -play sound.au ``` See also the MBR_OLA.COM batch file in the UTILITY.ZIP file available from the MBROLA Homepage if you cannot play 16 bits sound files on your machine. # Format of input and output files - Limitations ## Phoneme commands The input file bonjour.pho in the above example simply contains : ``` ; bonjour _ 51 25 114 b 62 o~ 127 48 170.42 Z 110 53.5 116 u 211 R 150 50 91 _ 91 ``` This shows the format of the input data required by MBROLA. Each line contains a phoneme name, a duration (in ms), and a series (possibly none) of pitch targets composed of two float numbers each : the position of the pitch target within the phoneme (in % of its total duration), and the pitch value (in Hz) at this position. In order to increase readability, it is also possible to enclose pitch target in parentheses. Hence, the first line of bonjour.pho could be written : ``` _ 51 (25,114) ``` it tells the synthesizer to produce a silence of 51 ms, and to put a pitch target of 114 Hz at 25% of 51 ms. Pitch targets define a piecewise linear pitch curve. Notice that the intonation curve they define is continuous, since the program automatically drops pitch information when synthesizing unvoiced phones. The data on each line is separated by blank characters or tabs. Comments can optionally be introduced in command files, starting with a semi-colon `;`. This default can be overrun with the `-c` option of the command line. Another special escape sequence `;;` allows the user to introduce commands in the middle of .pho files as described below. This escape sequence is also affected by the -c option. ## Changing the Freq Ratio or Time Ratio A command escape sequence containing a line like "T=xx" modifies the time ratio to xx, the same result is obtained on the fundamental frequency by replacing T with F, like in: ``` ;; T = 1.2 ;;F=0.8 ``` ## Flush the output stream Note, finally, that the synthesizer outputs chunks of synthetic speech determined as sections of the piecewise linear pitch curve. Phones inside a section of this curve are synthesized in one go. The last phone of each chunk, however, cannot be properly synthesized while the next phone is not known (since the program uses diphones as base speech units). When using mbrola with pipes, this may be a problem. Imagine, for instance, that mbrola is used to create a pipe-based speaking clock on an HP: ``` speaking_clock | mbrola - -.au | splayer ``` which tells the time, say, every 30 seconds. The last phone of each time announcement will only be synthesized when the next announcement starts. To bypass this problem, mbrola accepts a special command phone, which flushes the synthesis buffer : "#" This default character can be replaced by another symbol thanks to the command: ``` ;; FLUSH new_flush_symbol ``` Another important issue with piping under UNIX, is the possibility to prematurely end the audio output, if for example the user presses the stop button of your application. Since release 3.01, Mbrola handles signals. If in the previous example the user wants to interrupt the speaking clock message, the application just needs to send the USR1 signal. You can send such a signal from the console with: ``` kill -SIGUSR1 mbrola_process_number ``` Once mbrola catches the signal, it reads its input stream until it gets EOF or a FLUSH command (hence, surrounding sections with flush is a good habit). # Limitations of the program Phones can be synthesized with a maximum duration which depends on the fundamental frequency with which they are produced. The higher the frequency, the lower the duration. For a frequency of 133 Hz, the maximum duration is 7.5 sec. For a frequency of 66.5 Hz, it is 15 sec. For a frequency of 266 Hz, it is 3.75 sec. # Feedback Report bugs to [MBROLA Issues](https://github.com/numediart/MBROLA/issues) page on GitHub. Look at and subscribe to [MBROLA mailing list](https://groups.io/g/mbrola) to view and discuss other related topics. # License This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License](LICENSE) for more details. mbrola-3.3+dfsg/README_Makefile.md000066400000000000000000000013511364272575600166470ustar00rootroot00000000000000IMPORTANT: most of machine dependant moves are kept in Misc/common.h Please check the following #defines, some of which can be set in the Makefile depending on your OS you must define: TARGET_OS_MAC TARGET_OS_DOS TARGET_OS_SUN4 TARGET_OS_VMS TARGET_OS_BEOS If your system is not listed above, then it may be handled directly with: __i386 __powerpc__ __sparc If not, then you have to manually define one of those: LITTLE_ENDIAN or BIG_ENDIAN If you are able to handle signals, then #define SIGNAL (able to reset the mbrola engine on the fly with SIG_USR1). If you want to build the library mode instead of Standalone then `#define LIBRARY` If you want to build a Windows DLL, then `#define DLL` mbrola-3.3+dfsg/Standalone/000077500000000000000000000000001364272575600156635ustar00rootroot00000000000000mbrola-3.3+dfsg/Standalone/Posix/000077500000000000000000000000001364272575600167655ustar00rootroot00000000000000mbrola-3.3+dfsg/Standalone/Posix/getopt.c000066400000000000000000000551361364272575600204450ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2, 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #ifdef HAVE_CONFIG_H #if defined (emacs) || defined (CONFIG_BROKETS) /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because it found this file in $srcdir). */ #include #else #include "config.h" #endif #endif #ifndef __STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #endif /* GNU C library. */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ char *getenv (); static char * my_index (const char *str,int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ #ifndef __STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); #endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (char **argv) { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ static const char * _getopt_initialize (const char *optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind = 1; nextchar = NULL; /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } /* else if (getenv("POSIXLY_CORRECT") != NULL) * ordering = REQUIRE_ORDER; */ else ordering = PERMUTE; return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ #if NLS #include "nl_types.h" #endif int _getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind,int long_only) { optarg = NULL; #if NLS libc_nls_init(); #endif if (optind == 0) optstring = _getopt_initialize (optstring); if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound=0; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if (nameend - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptAmbiguous, "%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); #else fprintf (stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[optind]); #endif nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptNoArgumentsAllowed1, "%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); #else fprintf (stderr, "%s: option `--%s' doesn't allow an argument\n", argv[0], pfound->name); #endif else /* +option or -option */ #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptNoArgumentsAllowed2, "%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); #else fprintf (stderr, "%s: option `%c%s' doesn't allow an argument\n", argv[0], argv[optind - 1][0], pfound->name); #endif } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptRequiresArgument1, "%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); #else fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); #endif nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptUnrecognized1, "%s: unrecognized option `--%s'\n"), argv[0], nextchar); #else fprintf (stderr, "%s: unrecognized option `--%s'\n", argv[0], nextchar); #endif else /* +option or -option */ #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptUnrecognized2, "%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); #else fprintf (stderr, "%s: unrecognized option `%c%s'\n", argv[0], argv[optind][0], nextchar); #endif } nextchar = (char *) ""; optind++; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { /* 1003.2 specifies the format of this message. */ #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptIllegal, "%s: illegal option -- %c\n"), argv[0], c); #else fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); #endif } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ #if NLS fprintf (stderr, catgets(_libc_cat, GetoptSet, GetoptRequiresArgument2, "%s: option requires an argument -- %c\n"), argv[0], c); #else fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ mbrola-3.3+dfsg/Standalone/Posix/getopt.h000066400000000000000000000106331364272575600204430ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if __STDC__ #if defined(__GNU_LIBRARY__) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* not __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* not __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ mbrola-3.3+dfsg/Standalone/synth.c000066400000000000000000000377721364272575600172140ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: synth.c * Purpose: Main function of the MBROLA speech synthesizer. * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * Time-stamp: <00/03/30 03:30:20 pagel> * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * 10/01/97: Created as well as library.c to offer 2 compilation modes. * front end with a main() function. * * 20/10/97: flag to get the database textual information * * 11/06/98: new object oriented scheme * * 28/08/98: phoneme renaming * * 11/09/98: reset signal handling * * 20/10/98: phoneme renaming in a file for compatibility (Festival) * * 27/03/00: Rom databases dumping + initialization from ROM image for * debugging purposes */ #include "common.h" #include "zstring_list.h" #include #define void_(x) if (x) {} #if defined(__GLIBC__) #include #else #if defined(TARGET_OS_DOS) || defined(TARGET_OS_SUN4) || defined (__STRICT_ANSI__) #include #include "Posix/getopt.c" #endif #if defined(__linux__) || defined(__EMX__) #include #endif #endif #include "common.h" #include "database.h" #include "diphone.h" #include "mbrola.h" #include "audio.h" #include "input_file.h" #include "parser_input.h" #include "synth.h" #if defined(ROMDATABASE_INIT) || defined(ROMDATABASE_STORE) #include "rom_database.h" #endif /* * In standalone mode, input and ouput through files */ FILE *output_file; /* Audio output file (can be stdout) */ /* main objects */ Database* my_dba; Mbrola* my_brole; Parser* my_parse; /* Globals initialized from Initialization file, or from command line */ float freq_ratio=1.0; float time_ratio=1.0; float volume_ratio=1.0; bool smoothing=True; bool no_error=False; /* True if phoneme error resistant */ char* comment_symbol=NULL; /* init from command line */ char* flush_symbol=NULL; /* init from rename file */ float my_pitch; /* default pitch value */ uint16 voice_len=0; /* Voice sampling rate */ ZStringList* rename_list; /* phoneme renaming */ ZStringList* clone_list; /* phoneme cloning */ #ifdef SIGNAL /* * Global modified by the signal handler * -> indicate to flush what's being played * used as "reset play" in programs like emacs speak */ volatile sig_atomic_t must_flush=False; void reset_handler(int signum) /* To catch the users signal (means flush the input) */ { warning_message(1,"Got a reset signal !\n"); must_flush=True; signal (signum, reset_handler); /* rearm */ } #endif /* Different functions dedicated to global initializations */ void set_comment_symbol(char* sym) { /* Avoid overlapping */ if (comment_symbol) MBR_free(comment_symbol); comment_symbol= MBR_strdup(sym); } void set_flush_symbol(char* sym) { /* Avoid overlapping */ if (flush_symbol) MBR_free(flush_symbol); flush_symbol= MBR_strdup(sym); } void set_volume_ratio(char* val) { if ((volume_ratio=(float) atof(val))<=0.0f) { printf("Error in the format of the volume ratio : %s\n",val); exit(1); } } void set_freq_ratio(char* val) { if ((freq_ratio=(float) atof(val))<=0.0f) { printf("Error in the format of the frequency ratio : %s\n",val); exit(1); } } void set_time_ratio(char* val) { if ((time_ratio=(float) atof(val))<=0.0f) { printf("Error in the format of the time ratio : %s\n",val); exit(1); } } void set_voice_len(char* val) { if ((voice_len= (int16) atoi(val))<=0) { fprintf(stderr,"Error in the format of the Voice ratio : %s\n",val); exit(1); } if ( (voice_len<1000) || (voice_len>48000)) { fprintf(stderr,"The Voice ratio is a sampling frequency : %s\n",val); exit(1); } } void parse_init_file(char* rename_file_name) /* Parse a file mapping phonemes onto other with ;;RENAME a A ... */ { FILE* rename_file= fopen(rename_file_name,OPENRT); char buffer[255]; char source[255]; char dest[255]; if (rename_file==NULL) fatal_message(ERROR_DBNOTFOUND,"Error with %s renaming file !\n",rename_file_name); /* Read a line with quite a loose syntax ... */ while (fgets(buffer,sizeof(buffer),rename_file)) { char* pos; /* position of the command start, ignoring whatever preceedes */ debug_message2("LINE: %s\n",buffer); /* skip whatever comment char in the header */ if ( (pos= strstr(buffer,"RENAME")) != NULL) { sscanf(pos,"RENAME %s %s",source,dest); debug_message3("rename %s to %s\n",source,dest); append_rename_ZStringList(rename_list, source, dest, True); } else if ( (pos= strstr(buffer,"CLONE")) != NULL) { sscanf(pos,"CLONE %s %s",source,dest); debug_message3("clone %s %s\n",source,dest); append_rename_ZStringList(clone_list, source, dest, False); } else if ( (pos= strstr(buffer,"FLUSH")) != NULL) { sscanf(pos,"FLUSH %s",source); debug_message2("flush %s\n",source); set_flush_symbol(source); } else if ( (pos= strstr(buffer,"COMMENT")) != NULL) { sscanf(pos,"COMMENT %s",source); debug_message2("comment %s\n",source); set_comment_symbol(source); } else if ( (pos= strstr(buffer,"TIME")) != NULL) { sscanf(pos,"TIME %s",source); debug_message2("time %s\n",source); set_time_ratio(source); } else if ( (pos= strstr(buffer,"FREQ")) != NULL) { sscanf(pos,"FREQ %s",source); debug_message2("freq %s\n",source); set_freq_ratio(source); } else if ( (pos= strstr(buffer,"VOLUME")) != NULL) { sscanf(pos,"VOLUME %s",source); debug_message2("volume %s\n",source); set_volume_ratio(source); } else if ( (pos= strstr(buffer,"VOICE")) != NULL) { sscanf(pos,"VOICE %s",source); debug_message2("voice %s\n",source); set_voice_len(source); } else if ( (pos= strstr(buffer,"IGNORE")) != NULL) { debug_message1("ignore\n"); no_error=True; } } } void process_one_file(Mbrola* mb, char *file_name) /* * Send one file on the output */ { FILE *command_file; /* File providing the phonetic input (can be stdin) */ int stream_eof; /* To make the difference between flush and eof */ Input* my_input; /* to build the new parser */ Parser* my_parse; /* A - as input file means STDIN */ if (!strcmp(file_name,PIPESYMB)) command_file=stdin; else if ((command_file=fopen(file_name,OPENRT)) == NULL) fatal_message(ERROR_DBNOTFOUND,"Error with %s input file !\n",file_name); /* * HERE WE GOOOOOOoooo * Loop and flush until the end of pho file is reached */ my_input= init_InputFile(command_file); my_parse= init_ParserInput(my_input, sil_phon(my_dba), my_pitch, time_ratio, freq_ratio, comment_symbol, flush_symbol); set_parser_Mbrola(mb,my_parse); do { reset_Mbrola(mb); stream_eof=Synthesis(mb); fflush(output_file); } while (stream_eof!=PHO_EOF); my_parse->close_Parser(my_parse); /* close the parser */ my_input->close_Input(my_input); /* and the input stream */ if (command_file!=stdin) fclose(command_file); } /* * Function name says all ! */ int main(int argc, char **argv) { WaveType file_format; /* File format for the audio output */ int argpos; int c; bool info=False; /* True if textual information requested */ #ifdef ROMDATABASE_STORE bool romdatabase_store= False; /* True if we build a ROM dump */ #endif #ifdef ROMDATABASE_INIT void *romdatabase_pointer=NULL; /* Pointer to a ROM dump: used for debugging */ bool romdatabase_init= False; /* True if the dba is a ROM dump */ #endif rename_list= init_ZStringList(); /* phoneme renaming */ clone_list= init_ZStringList(); /* phoneme cloning */ #ifdef SIGNAL /* * Plug the reset signal handler (but don't overide parent's Signal Ignore */ if (signal (SIGUSR1, reset_handler) == SIG_IGN) signal (SIGUSR1, SIG_IGN); #endif /* Paranoid test ! */ if ((sizeof(uint8)!=1) || (sizeof(int16)!=2) || ( sizeof(int32)!=4)) fatal_message(ERROR_DBWRONGARCHITECTURE,"Architecture PANIC!\n"); if (argc==1) { printf( "\n" " MBROLA " SYNTH_VERSION " - speech synthesizer\n" " Author : Thierry Dutoit with help of AC/DC adaptator Vincent Pagel\n" " Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) - T.Dutoit\n" " Email mbrola@tcts.fpms.ac.be to freely subscribe as a user\n" " This software may not be sold or incorporated into any product\n" " which is sold without prior permission from the author.\n"); printf( " When no charge is made, this software may be copied and distributed\n" " freely, provided that the accompanying readme.txt file is copied and\n" " distributed with it.\n" " Permission is granted to use this software for synthesizing speech\n" " with and only with the voice and language databases made available\n" " by the author from the mbrola project www homepage :\n" " " WWW_ADDRESS "\n" " All other rights reserved.\n"); printf( " THIS SOFTWARE CARRIES NO WARRANTY, EXPRESSED OR IMPLIED. THE USER\n" " ASSUMES ALL RISKS, KNOWN OR UNKNOWN, DIRECT OR INDIRECT, WHICH INVOLVE\n" " THIS SOFTWARE IN ANY WAY. IN PARTICULAR, THE AUTHOR DOES NOT TAKE ANY\n" " COMMITMENT IN VIEW OF ANY POSSIBLE THIRD PARTY RIGHTS.\n\n" " U.S. Patent Number 5,987,413\n" "\n" " For help type : mbrola -h\n" "\n"); return 0; } /* Read the switches */ while ((c=getopt(argc, argv, "+v:t:f:l:c:F:R:C:I:shiewW"))>0) switch(c) { case 'i': info=True; break; case 'e': no_error=True; break; case 'c': set_comment_symbol(optarg); break; case 'F': set_flush_symbol(optarg); break; case 'v': set_volume_ratio(optarg); break; case 'f': set_freq_ratio(optarg); break; case 't': set_time_ratio(optarg); break; case 'l': set_voice_len(optarg); break; case 'C': parse_ZStringList(clone_list, optarg, True); break; case 'R': parse_ZStringList(rename_list, optarg, False); break; case 'I': parse_init_file(optarg); break; case 's': smoothing=False; break; case 'h': printf("\n" " USAGE: %s [COMMAND LINE OPTIONS] database pho_file+ output_file\n" "\n" "A " PIPESYMB " instead of pho_file or output_file means stdin or stdout\n" "Extension of output_file ( raw, au, wav, aiff ) tells the wanted audio format\n" "\nOptions can be any of the following:\n" "-i = display the database information if any\n" "-e = IGNORE fatal errors on unknown diphone\n" "-c CC = set COMMENT char (escape sequence in pho files)\n" "-F FC = set FLUSH command name\n" "-v VR = VOLUME ratio, float ratio applied to ouput samples\n", argv[0]); printf("-f FR = FREQ ratio, float ratio applied to pitch points\n" "-t TR = TIME ratio, float ratio applied to phone durations\n" "-l VF = VOICE freq, target freq for voice quality\n" "-R RL = Phoneme RENAME list of the form ""a A b B ...""\n" "-C CL = Phoneme CLONE list of the form ""a A b B ...""\n\n" "-I IF = Initialization file containing one command per line\n" " CLONE, RENAME, VOICE, TIME, FREQ, VOLUME, FLUSH, COMMENT,\n" " and IGNORE are available\n" #ifdef ROMDATABASE_STORE "-W = store the datbase in ROM format\n" #endif #ifdef ROMDATABASE_INIT "-w = the database in a ROM dump\n" #endif "\n"); return 0; #ifdef ROMDATABASE_STORE case 'W': romdatabase_store=True; break; #endif #ifdef ROMDATABASE_INIT case 'w': romdatabase_init=True; break; #endif default: printf("Error, option %c not recognized, try -h for help\n",c); return 1; } argpos=optind; if (argpos >= argc) fatal_message(ERROR_COMMANDLINE, "Not enough arguments, try -h for help\n"); #ifdef ROMDATABASE_INIT if (romdatabase_init) { long rom_size; FILE* rom_file; char out_name[1024]; sprintf( out_name, "%s.rom", argv[argpos] ); /* Open the ROM image for simulation */ rom_file= fopen(out_name,"rb"); if (rom_file==NULL) fatal_message(ERROR_DBNOTFOUND,"Unable to read %s!\n",out_name); fseek(rom_file,0,SEEK_END); rom_size=ftell(rom_file); rewind(rom_file); /* Allocate the big ROM area and read data in it */ romdatabase_pointer= MBR_malloc(rom_size); void_(fread(romdatabase_pointer, 1, rom_size, rom_file )); fclose(rom_file); my_dba= init_ROM_Database(romdatabase_pointer); } else /* else normal initialization */ #endif { #ifndef ROMDATABASE_PURE /* initialize the database with rename and clone */ my_dba= init_rename_Database(argv[argpos], rename_list, clone_list); #endif } if (!my_dba) { fatal_message(ERROR_COMMANDLINE, "All database initializations failed\n"); } /* not usefull anymore */ if (rename_list) close_ZStringList(rename_list); if (clone_list) close_ZStringList(clone_list); #ifdef ROMDATABASE_STORE if (romdatabase_store) { char out_name[1024]; sprintf( out_name, "%s.rom", dbaname(my_dba) ); /* Dump a copy of the database into a file to get a ROM image */ file_flush_ROM_Database( my_dba, out_name); fprintf(stderr, "ROM image saved in %s\n", out_name); } #endif /* ROMDATABASE_STORE */ /* do not connect any parser yet */ my_pitch= (float)Freq(my_dba) / (float)MBRPeriod(my_dba); my_brole= init_Mbrola(my_dba); set_volume_ratio_Mbrola(my_brole,volume_ratio); set_smoothing_Mbrola(my_brole,smoothing); set_no_error_Mbrola(my_brole,no_error); if (voice_len!=0) set_voicefreq_Mbrola(my_brole,voice_len); if (info) { /* Information requested */ char *local; int size; int index=0; size=getDatabaseInfo(my_dba,NULL,0,index); while (size!=0) { local=(char *) MBR_malloc(size); getDatabaseInfo(my_dba,local,size,index); printf("\n%s\n",local); MBR_free(local); index+=1; size=getDatabaseInfo(my_dba,NULL,0,index); } } if (argpos+2 >= argc) { /* Not fatal so that we close everything before leaping */ warning_message(ERROR_COMMANDLINE, "Not enough arguments, try -h for help\n"); } else { /* A - as output file means STDOUT -> may be followed by a format switch */ if (!strncmp(argv[argc-1],PIPESYMB,1)) output_file=stdout; else if ((output_file=fopen(argv[argc-1],"wb")) == NULL) fatal_message(ERROR_OUTFILE,"Error with %s output file !\n",argv[argc-1]); /* * The stream header ( length is unknown at this time ) */ file_format=find_file_format(argv[argc-1]); write_header(file_format, audio_length(my_brole), get_voicefreq_Mbrola(my_brole), output_file); /* Process the files one by one */ argpos++; while (argposclose_Database(my_dba); /* ... the database */ if (flush_symbol) MBR_free(flush_symbol); if (comment_symbol) MBR_free(comment_symbol); #ifdef ROMDATABASE_INIT if (romdatabase_init) { MBR_free(romdatabase_pointer); } #endif return 0; } mbrola-3.3+dfsg/Standalone/synth.h000066400000000000000000000024001364272575600171750ustar00rootroot00000000000000/* * FPMs-TCTS SOFTWARE LIBRARY * * File: synth.h * Purpose: Main function of the MBROLA speech synthesizer. * Authors: Vincent Pagel * Email : mbrola@tcts.fpms.ac.be * * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab) * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef _SYNTH_H #define _SYNTH_H #include "common.h" /* * In standalone mode, input and ouput through files */ extern FILE *command_file; /* File providing the phonetic input (can be stdin) */ extern FILE *output_file; /* Audio output file (can be stdout) */ /* used in standalone compilation mode */ extern int main(int argc, char **argv); #endif