speech-dispatcher-0.9.1/0000755000175000017500000000000013465234514012124 500000000000000speech-dispatcher-0.9.1/.version0000644000175000017500000000000613465234514013526 000000000000000.9.1 speech-dispatcher-0.9.1/.tarball-version0000644000175000017500000000000613465234514015145 000000000000000.9.1 speech-dispatcher-0.9.1/doc/0000755000175000017500000000000013465234514012671 500000000000000speech-dispatcher-0.9.1/doc/speech-dispatcher-cs.info0000644000175000017500000023372213465234513017474 00000000000000This is speech-dispatcher-cs.info, produced by makeinfo version 6.5 from speech-dispatcher-cs.texi. INFO-DIR-SECTION Sound INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * Speech Dispatcher cs: (speechd-cs). Speech Dispatcher (in Czech). END-INFO-DIR-ENTRY  File: speech-dispatcher-cs.info, Node: Top, Next: Úvod, Prev: (dir), Up: (dir) Tento manuál se vzathuje ke Speech Dispatcher, verze 0.9.1. Jedná se však pouze o uživatelskou část dokumentace a upozorňujeme, že tento překlad již není aktuální! Poskytujeme jej s tím, že možná bude užitečný a to zejména v sekcích, které popisují obecné koncepty a myšlenky projektu, a to těm, kteří si nemohou přečíst anglickou dokumentaci. Nikdo by nicméně neměl spoléhat na technické detaily zde uvedené, protože mnoho věcí je již dnes jinak. Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s. Dáváme povolení kopírovat, distribuovat a/nebo modifikovate tento dokument pod podmínkami GNU Free Documentation License, Verze 1.2 nebo jakékoliv novější verze vydané Free Software Foundation; bez jakýchkoliv Invariant Sections (neměnných sekcí), bez Front-Cover Texts (texty na přední straně obálky) a bez Back-Cover Texts (texty na zadní straně obálky). Kopie této licence je přiložena v sekci nazvané ,,GNU Free Documentation License". * Menu: * Úvod:: Co to je Speech Dispatcher * Uživatelská dokumentace:: Používání, konfigurace * GNU General Public License:: Podmínky kopírování Speech Dispatcher * GNU Free Documentation License:: Podmínky kopírování tohoto manuálu * Index of Concepts::  File: speech-dispatcher-cs.info, Node: Úvod, Next: Uživatelská dokumentace, Prev: Top, Up: Top 1 Úvod ****** * Menu: * Motivace:: Proč Speech Dispatcher? * Základní design:: Jak to pracuje? * Přehled základních rysů:: Co všechno umí? * Současný stav:: Jaký je současný stav?  File: speech-dispatcher-cs.info, Node: Motivace, Next: Základní design, Prev: Úvod, Up: Úvod 1.1 Motivace ============ Projekt Speech Dispatcher se snaží poskytnout na zařízení nezávislou vrstvu pro řečovou syntézu. Měl by poskytovat jednoduché rozhraní pro klientské aplikace (aplikace, které chtějí mluvit), stejně jako pro ovladače konkrétních zařízení (různé řečové syntetizéry). Vysoce kvalitní řečová syntéza je tu již dlouho a nyní je použitelná i pro běžné uživatele na jejich domácích počítačích. Občas to přichází jako nutnost, občas je to jen dobrá vlastnost, aby některé programy poskytovaly řečový výstup. Pro syntézu hlasu je tu široké pole využití od výukového software až po specializované systémy, jako jsou například nemocnice či laboratoře. Pro zrakově postižené uživatele je to jedna ze dvou základních cest, jak získat výstup z počítače (tou druhou je Braillský řádek). Existují různé řečové syntetizéry s různými schopnostmi. Některé z nich jsou hardwarové, některé softwarové. Některé jsou svobodným software a jsou volně dostupné na internetu. Programátoři to mají opravdu těžké, když chtějí své programy rozmluvit, protože potřebují nejprve najít nějaký vhodný syntetizér (dlouhé hodiny experimentování a tak dále) a potom jej potřebují nějak zprovoznit s jejich programem. Často musí psát pro tyto programy či hardwarová zařízení vlastní ovladače a dělají to znovu a znovu. Snadno si lze představit, že se to celé zhroutí když nevinný uživatel spustí dva programy najednou. Kdyby přesto nastartovaly oba, budou křičet jeden přes druhého. Tím je pro programátory velmi obtížné implementovat do svých programů podporu řečové syntézy (pro nevidomé uživatele, nebo prostě pro lepší uživatelské rozhraní) a je to jeden z důvodů, proč pořád ještě plně nevyužíváme toho, co řečová syntéza nabízí. V ideálním světě by programátoři mohli pro řečovou syntézu používat podobné příkazy, jako to dělají pro textový výstup na obrazovku (printf, puts, ...). V ideálním světě by existovalo nějaké speech_printf(), které by se staralo o to, aby byla zpráva přemluvena ve správný čas bez přerušování ostatních. Programátor by se tak nemusel starat o to, jak je přesně komunikace s řečovým syntetizérem implementována. V ideálním světě by byl v každé GNU/Linuxové distribuci nějaký řečový syntetizér a nějaké rozhraní starající se o aplikace, které chtějí mluvit, dovolující uživatelům nastavit si parametry řeči a poskytující nějaké jednoduché rozhraní (jako speech_printf()) pomocí nějaké sdílené knihovny pro programátory. Bude to jěště dlouhá cesta než se nám podaří dosáhnout tohoto stavu věcí, ale se Speech Dispatcherem děláme první krůčky...  File: speech-dispatcher-cs.info, Node: Základní design, Next: Přehled základních rysů, Prev: Motivace, Up: Úvod 1.2 Základní design =================== V komunikaci mezi všemi různými aplikacemi a syntetizéry je obrovský nepořádek. Proto jsme chtěli, aby byl Speech Dispatcher vrstva oddělující aplikace a syntetizéry tak, aby se aplikace nemusely starat o syntetizéry a syntetizéry se nemusely starat o interakci s aplikacemi. Rozhodli jsme se implementovat Speech Dispatcher jako server, který přijímá od aplikací příkazy přes protokol nazvaný 'SSIP', zpracovává je a, pokud je to nutné, zavolá příslušnou funkci daného výstupního modulu, který pak komunikuje s některým z různých syntetizátorů. Každý klient (aplikace, která chce mluvit) otevře socketové spojení na Speech Dispatcher a volá funkce jako say(), stop(), pause() poskytované knihovnou implementující tento protokol. Tato sdílená knihovna je stále na straně klienta a posílá Speech Dispatcheru SSIP příkazy přes otevřený socket. Když příkazy dorazí do Dispatchera, ten je zpracuje, přečte text, který by měl být přeříkán a vloží jej do fronty podle jeho priority. Potom se rozhodne kdy, s jakými parametry (nastavovanými klientským programem i uživatelem) a na jakém syntetizéru zprávu nechá přemluvit. Tyto požadavky na mluvení jsou pak zpracovávány výstupními moduly (pluginy) pro různé hardwarové a softwarové syntetizéry a přeříkány nahlas. [image src="figures/architecture.png" alt="Architektura Speech Dispatchera" text=" applications protocol output modules interface Speech Dispatcher core synthesizers .-----------------------. |Emacspeak| :s l: < > | Speech Dispatcher | :m : |Apollo| :h i: | - configuration | :o : |Festival| |Speakup| :a b: | - synchronization | :d A: |Flite| :r r: | - sound icons | :u P: . |User center| :e a:

| - history | :l I: . . :d r: < > | - punctuation, ... | :e : . . : y: < > | [||| priority queues] | : : . . : : < > | | : : . `-----------------------'"] Detailní popis programování klientů i serveru je k dispozici v anglickém manuálu.  File: speech-dispatcher-cs.info, Node: Přehled základních rysů, Next: Současný stav, Prev: Základní design, Up: Úvod 1.3 Přehled základních rysů =========================== Speech Dispatcher z pohledu uživatele: * snadná konfigurace různých mluvících aplikací, centrální správa * možnost volně rozhodovat, jaká aplikace bude mluvit s jakým syntetizérem * méně času věnovaného konfiguraci a ladění různých aplikací využívajících syntézu * historie zpráv pro zrakově postižené uživatele Speech Dispatcher z pohledu programátora aplikace: * snadná cesta, jak aplikaci rozmluvit * jednotné rozhraní k různým syntetizérům * synchronizace zpráv na vyšší úrovni (kategorizace pomocí priorit) * možnost nemuset se starat o konfiguraci parametrů hlasu  File: speech-dispatcher-cs.info, Node: Současný stav, Prev: Přehled základních rysů, Up: Úvod 1.4 Současný stav ================= TODO:  File: speech-dispatcher-cs.info, Node: Uživatelská dokumentace, Next: GNU General Public License, Prev: Úvod, Up: Top 2 Uživatelská dokumentace ************************* * Menu: * Základní funkce:: Detailnější popis všech základních funkcí * Spouštění:: Volby příkazové řádky * Konfigurace:: Jak zkonfigurovat Speech Dispatcher  File: speech-dispatcher-cs.info, Node: Základní funkce, Next: Spouštění, Prev: Uživatelská dokumentace, Up: Uživatelská dokumentace 2.1 Základní funkce =================== V této sekci je detailnější popis základních funkcí Speech Dispatcheru. * Menu: * Model priorit zpráv:: Zpracování současně příchozích zpráv * Historie zpráv:: Ukládání zpráv pro pozdější nahlédnutí * Více výstupních modulů:: Interakce s různými syntetizéry * Autentifikace uživatelů:: Autentifikace pro přístup k historii  File: speech-dispatcher-cs.info, Node: Model priorit zpráv, Next: Historie zpráv, Prev: Základní funkce, Up: Základní funkce 2.1.1 Model priorit zpráv ------------------------- Speech Dispatcher nemůže syntetizovat všechny zprávy, které do něj přichází z prostého důvodu, že zprávy přicházejí obyčejně rychleji, než je syntetický hlas dokáže číst. Na obrazovce monitoru je v porovnání s jednokanálovým řečovým výstupem relativně hodně místa. Z toho důvodu používáme systém několika priorit zaměřených na různé typy zpráv. Myšlenka je taková, že úlohou programátora klientské aplikace bude pouze určit pro každou zprávu určitou prioritu odpovídající typu dané zprávy. Veškerá synchronizace a přepínání mezi těmito zprávami (které mohou pocházet od různých klientů) potom bude zajištěno aplikováním určitých pravidel ve Speech Dispatcheru. * Menu: * Typy priorit:: * Diagram priorit:: * Příklady využití priorit::  File: speech-dispatcher-cs.info, Node: Typy priorit, Next: Diagram priorit, Prev: Model priorit zpráv, Up: Model priorit zpráv 2.1.1.1 Priority Categories ........................... Speech Dispatcher poskytuje systém pěti priorit. Každá zpráva obsahuje buď explicitní informaci o prioritě, nebo jí je přiřazena výchozí priorita. Prosím podívejte se také na přiložený diagram (dole). Priorita 'important' .................... Tato zpráva bude přeříkána okamžitě, jak dorazí do serveru. Není nikdy přerušena. Když server obdrží současně několik různých zpráv této priority, ty jsou uloženy a přeříkány v pořadí, ve kterém přišly. Když přijde nová zpráva priority 'important' a zrovna se říká nějaká jiná zpráva, tato jiná zpráva je zahozena. Další zprávy nižších priorit jsou buď pozdrženy (priorita 'message' a 'text') než již nečekají na přeříkání žádné zprávy priority 'important', nebo jsou zahozeny (priority 'notification' a 'progress'). Tyto zprávy by měly být tak krátké, jak je to jen možné, a měly by být používány pouze zřídka, protože blokují výstup všech ostatních zpráv. Priorita 'message' .................. Tato zpráva bude přeříkána, pokud již ve frontě nečeká žádná jiná zpráva priority 'important' nebo 'message'. V opačném případě je tato zpráva pozdržena dokud nebudou všechny přeříkány. To znamená, že priorita 'message' nezastavuje sama sebe. Když ve frontě čekají zprávy priorit 'notification' nebo 'progress' nebo 'text' když přijde zpráva priority 'message', jsou zahozeny. Priorita 'text' ............... Tato zpráva bude přeříkána, když ve frontě nečeká žádná zpráva priority 'important' nebo 'message'. Pokud čeká, tato nová zpráva je pozdržena dokud nebudou předchozí zprávy přeříkány. Priorita text přerqušuje sama sebe. To znamená, že když přijde několik zpráv priority text, ty nejsou přeříkány v pořadí, ve kterém přišly, ale bude vyřčena pouze poslední z nich a ostatní jsou přerušeny a zahozeny. Pokud jsou ve frontě zprávy priorit 'notification' nebo 'progress' nebo se právě přeříkávají, jsou zahozeny. Priorita 'notification' ....................... Toto je zpráva nízké priority. Pokud ve frontě čekají zprávy priorit 'important', 'messages', 'text' nebo 'progress' nebo jsou právě přeříkávány, tato nová zpráva priority 'notification' je zrušena. Tato priorita přerušuje sama sebe, takže když přijde najednou více zpráv s prioritou 'notification', přeříká se pouze poslední z nich. Priority 'progress' ................... Toto je speciální priorita pro zprávy, které přicházejí krátce po sobě a nesou informaci o nějaké probíhající činnosti (např. 'Dokončeno 45%'). Kdyby nové zprávy přerušovaly ostatní (viz. priorita Notification), uživatel by nemusel slyšet ani jednu zprávu do konce. Tato priorita se chová stejně jako 'notification' s výjimkou dvou věcí. * Zprávy této priority nepřerušují jedna druhou. Místo toho, pokud je zrovna přeříkávána jiná zpráva této priority, nově příchozí zpráva je zahozena. * Speech Dispatcher se snaží detekovat poslední zprávu v sérii příchozích zpráv a zaručit její přeříkání (pro uživatele je důležité slyšet zprávu 'Completed 100%', aby věděl, že proces již skončil). Vždy, když ve frontě již nečeká žádná nová zpráva této priority a poslední příchozí zpráva ještě nebyla přeříkána, je její přeříkání vynuceno s prioritou 'message'.  File: speech-dispatcher-cs.info, Node: Diagram priorit, Next: Příklady využití priorit, Prev: Typy priorit, Up: Model priorit zpráv 2.1.1.2 Diagram priorit ....................... [image src="figures/priorities.png" alt="Speech Dispatcher architecture" text=" ___________ | IMPORTANT | `-----------' . / \\ / |p| \\ . . . . . . . |r| . . . . . . . . . . message ----> |i| <---- text . . . |o| . . . progress ----> |r| <---- notification . . . |i| . . . . |t| . . . . . . . . . |y| . . . . . . . . . doesn't interrupt interrupts itself itself "]  File: speech-dispatcher-cs.info, Node: Příklady využití priorit, Prev: Diagram priorit, Up: Model priorit zpráv 2.1.1.3 Příklady využití priorit ................................ Příklady použití priority 'important' jsou: * chybové hlášky * velmi důležité zprávy * ... Příklady použití priority 'message' jsou: * běžné zprávy programu * varování * ... Příklady použití priority 'text' jsou: * text, na kterém uživatel pracuje * předčítaný text * položky menu * ... Příklady použití priority 'notification' jsou: * méně důležité informace * písmenka při vkládání * run-time nápověda * ... Příklady použití priority 'progress' jsou: * "dokončeno 15%", "dokončeno 16%", "dokončeno 17%" * "Načítám zvuky", "Načítám grafiku", "Načítám ai", ...  File: speech-dispatcher-cs.info, Node: Historie zpráv, Next: Více výstupních modulů, Prev: Model priorit zpráv, Up: Základní funkce 2.1.2 Historie zpráv -------------------- Pro nevidomé a zrakově postižené je dobrou vlastností, pokud mají možnost nějakým jednoduchým klientem procházet historii vyslovených zpráv. Některé méně důležité zprávy jsou přijmuty Speech Dispatcherem bez toho, aby byly přeříkány, protože jsou potlačeny důležitějšími informacemi. To je nedělitelná vlastnost každého řečového rozhraní, protože není možné podat v řečovém výstupu tolik informací, kolik se jich vejde na obrazovku. To je jeden z hlavních důvodů, proč je výhodné udržovat historii přijatých zpráv, aby se mohl uživatel podívat, zda mu neušlo něco důležitého. * Menu: * Přístupová práva:: Přístupová práva k historii zpráv  File: speech-dispatcher-cs.info, Node: Přístupová práva, Prev: Historie zpráv, Up: Historie zpráv 2.1.2.1 Access Rights ..................... Aby bylo ochráněno soukromí uživatelů, Speech Dispatcher omezuje přístup k historii na určitou podmnožinu přijatých zpráv. Platí následující pravidla: * Všechny zprávy přijaté od určitého klientského spojení jsou tomuto spojení přístupny i v historii. * Všechny zprávy odeslané určitým uživatelem jsou tomuto uživateli přístupny i v historii. * Všechny zprávy zaslané uživatelem 'speechd' jsou přístupny všem uživatelům na daném systému, pod kterým běží Speech Dispatcher ve skupině 'speechd'. * Žádné další zprávy nejsou přístupné. Dvě zprávy jsou považovány za identické jestliže jejich spojení pocházejí z toho samého počítače, uživatelská jména jsou stejná a jejich identita může být ověřena, jak je popsáno v *note Autentifikace uživatelů::. Pokud nemůže být uživatelova identita ověřena, tento uživatel je považován za jiného než všichni připojení nebo dříve připojení uživatelé.  File: speech-dispatcher-cs.info, Node: Více výstupních modulů, Next: Autentifikace uživatelů, Prev: Historie zpráv, Up: Základní funkce 2.1.3 Více výstupních modulů ---------------------------- Speech Dispatcher podporuje souběžné používání více výstupních modulů. Pokud tyto moduly poskytují dobrou synchronizaci, lze je při čtení zpráv kombinovat. Pokud např. modul1 mluví anglicky a česky, zatímco modul2 mluví pouze německy, tak pokud přijde nějaká zpráva v němčině, použije se modul2, zatímco pro ostatní jazyky se použije modul1. Na druhé straně jazyk není jediným kritériem pro takové rozhodnutí. Přesná pravidla pro výběr výstupího modulu mohou být ovlivněna v konfiguračním souboru 'speechd.conf'.  File: speech-dispatcher-cs.info, Node: Autentifikace uživatelů, Prev: Více výstupních modulů, Up: Základní funkce 2.1.4 Autentifikace uživatelů ----------------------------- NOTE: Na implementaci této vlastnosti se pracuje, ale současná verze ji nepodporuje. Speech Dispatcher neposkytuje žádný explicitní autentifikační mechanismus. K ověření identity uživatlů používáme Identification Protocol definovaný v RFC 1413. V konfiguraci je možné specifikovat mapování uživatelů. To umožňuje jednat s určitými uživateli jako s jedním a přidělit jim stejná práva (např. procházet jejich *note Historie zpráv::).  File: speech-dispatcher-cs.info, Node: Spouštění, Next: Konfigurace, Prev: Základní funkce, Up: Uživatelská dokumentace 2.2 Invoking ============ 2.2.1 Potřebná privilegia ------------------------- Speech Dispatcher může být obecně spouštěn pod obyčejným uživatelem. Snažili jsme se jej zabezpečit, jak jen to bylo možné, ale nejsme odborníky na počítačovou bezpečnost a kód může obsahovat nebezpečné chyby. Nedoporučujeme jej spouštět jako root nebo pod jiným vysoce privilegovaným uživatelem. Jediná omezení jsou tyto: * Speech Dispatcher vytváří PID file standardně ve '/var/run/speech-dispatcher.pid', takže '/var/run/' musí být danému uživateli přístupné k zápisu. To může být změněno nastavením volby 'pidpath' při volání skriptu './configure' při kompilaci. * Když je zapnuto logování, výchozí cesta, kam Speech Dispatcher zapisuje svůj log, je '/var/log/speech-dispatcher.log'. To ale může být kdykoliv přenastaveno v hlavním konfiguračním souboru. 2.2.2 Volby příkazové řádky --------------------------- Speech Dispatcher může být spuštěn s těmito volbami: 'speech-dispatcher [-{d|s}] [-l {1|2|3|4|5}] [-p=port] | [-v] | [-h]' '-d or --run-daemon' Spustí program jako démona (běží v pozadí, odpojí se od terminálu, atd.) Toto je výchozí chování. '-s or --run-single' Spustí program jako běžnou aplikaci běžící na popředí. '-l level or --log-level=level' Vybere požadovaný logovací úroveň. Logovací úroveň je číslo mezi 0 a 5 (0 znamená neloguj nic, 5 znamená zapisuj téměř vše včetně zpracovávaného textu.) Standardní je 3. *Note Úrovně logování::. Logovací úroveň 5 by neměla být používána k jiným účelům, než pro hledání chyb a to pouze krátkodobě. Logy, které produkuje mohou narůst do obrovské velikosti a obsahují text čtený uživateli nezávisle na různých přístupových právech, jak platí pro historii. Spouštět server s touto úrovní logování tedy může snadno vést k narušení soukromí. '-p or --port' Zadá port, na kterém by měl server čekat na klienty. Výchozí je 6560. '-v or --version' Vypíše informace o verzi Speech Dispatchera. Také oznámí základní informace o copyrightu. '-h or --help' Vypíše nápovědu o volbách příkazové řádky, upozornění o copyrightu a emailovou adresu pro zasílání oznámení o chybách.  File: speech-dispatcher-cs.info, Node: Konfigurace, Prev: Spouštění, Up: Uživatelská dokumentace 2.3 konfigurace =============== Speech Dispatcher může být konfigurován na několika různých úrovních. Jedna z nich je nastavování globálních parametrů přes serverový konfigurační soubor. Je zde i podpora pro konfiguraci specifickou pro určité klienty. Některé aplikace mají vlastní mechanismus nastavování voleb souvisejících s řečovou syntézou. Pro detaily o těchto nastaveních se prosím podívejte do dokumentace daného programu. Následující kapitoly se zabývají pouze konfigurací na straně serveru přes konfigurační soubor. * Menu: * Syntaxe konfiguračního souboru:: * Volby v konfiguraci:: * Nastavení výstupních modulů:: * Úrovně logování::  File: speech-dispatcher-cs.info, Node: Syntaxe konfiguračního souboru, Next: Volby v konfiguraci, Prev: Konfigurace, Up: Konfigurace 2.3.1 Syntaxe konfiguračního souboru ------------------------------------ Pro načítání configurace založené na textových souborech používáme knihovnu DotConf, takže bude syntaxe nejspíš mnoha uživatelům povědomá. Každá z řetězcových konstant, pokud není uvedeno jinak, by měla být zakódována v UTF-8. Jména voleb nepoužívají jiné znaky než standardní ASCII sadu omezenou na znaky ('a', 'b', ...), pomlčky ('-') a podtržítka '_'. Komentáře a dočasně neaktivní volby začínají znakem '#'. Pokud chcete takovu volbu zapnout, stačí smazat znak komentáře a nastavit volbu na požadovanou hodnotu. # toto je komentar # InactiveOption "tato volba je zatim vypla komentarem" Řetězce jsou uzavřeny v uvozovkách. LogFile "/var/log/speech-dispatcher.log" Čísla jsou zapsána bez uvozovek. Port 6560 Přepínače používají On (zapnuto) a Off (vypnuto). Debug Off  File: speech-dispatcher-cs.info, Node: Volby v konfiguraci, Next: Nastavení výstupních modulů, Prev: Syntaxe konfiguračního souboru, Up: Konfigurace 2.3.2 Configuration options --------------------------- Všechny dostupné volby jsou zdokumentovány přímo v konfiguračním souboru a jsou k nim uvedeny i příklady. Většina voleb je nastavena na výchozí hodnotu a zakomentována. Pokud je chcete změnit, postačí modifikovat jejich hodnotu a smazat symbol komentáře '#'.  File: speech-dispatcher-cs.info, Node: Nastavení výstupních modulů, Next: Úrovně logování, Prev: Volby v konfiguraci, Up: Konfigurace 2.3.3 Output Modules Configuration ---------------------------------- Každý uživatel by si měl zapnout ve své konfiguraci alespoň jeden výstupní modul, pokud chce, aby Speech Dispatcher produkoval nějaký zvukový výstup. Když není načten žádný výstupní modul, Speech Dispatcher sice nastartuje, bude komunikovat s klienty a logovat zprávy do historie, ale nebude produkovat žádný zvuk. Každý výstupní modul je třeba do Speech Dispatchera natáhnout jednou řádkou "AddModule" v 'etc/speechd.conf'. Navíc, každý výstupní modul má přiřazen vlastní konfigurační soubor. * Menu: * Natahování modulů ve speechd.conf:: * Konfigurační soubory výstupních modulů:: * Konfigurace generického výstupního modulu::  File: speech-dispatcher-cs.info, Node: Natahování modulů ve speechd.conf, Next: Konfigurační soubory výstupních modulů, Prev: Nastavení výstupních modulů, Up: Nastavení výstupních modulů 2.3.3.1 Natahování modulů ve speechd.conf ......................................... Každý modul, který by se měl spustit při startu Speech Dispatchera, musí být natažen příkazem 'AddModule' v konfiguraci. Všimněte si, že lze natáhnout jeden binární modul vícekrát s různými konfiguračními soubory a pod jinými jmény. To je užitečné hlavně pro natahování generických výstupních modulů. *Note Konfigurace generického výstupního modulu::. AddModule "MODULE_NAME" "MODULE_BINARY" "MODULE_CONFIG" MODULE_NAME je jméno daného výstupního modulu. MODULE_BINARY je jméno binárního spustitelného souboru tohoto výstupního modulu. To může být buď cesta absolutní nebo relativní k 'bin/speechd-modules/'. MODULE_CONFIG je soubor s konfigurací pro tento konkrétní výstupní modul. Cesta může být absolutní i relativní k 'etc/speech-dispatcher/modules/'. Tento parametr je volitelný (není třeba jej uvádět).  File: speech-dispatcher-cs.info, Node: Konfigurační soubory výstupních modulů, Next: Konfigurace generického výstupního modulu, Prev: Natahování modulů ve speechd.conf, Up: Nastavení výstupních modulů 2.3.3.2 Konfigurační soubory výstupních modulů .............................................. Každý výstupní modul je odlišný a proto má odlišné volby v konfiguraci. Prosím prostudujte si komentáře v daném konfiguračním souboru. Zde je popsáno pouze několik voleb, které jsou pro některé výstupní moduly společné. 'AddVoice "LANGUAGE" "SYMBOLICNAME" "NAME"' Každý výstupní modul poskytuje nějaké hlasy a někdy dokonce podporuje různé jazyky. Z toho důvodu byl zaveden společný mechanismus, kterým můžou být tyto hlasy definovány v konfiguraci. Žádný modul ovšem není povinen tuto volbu používat. Některé syntetizátory, např. Festival, podporují symbolická jména SSIP přímo, takže konfigurace konkrétních hlasů se provádí v syntetizátoru samotném. Každému definovanému hlasu odpovídá přesně jedna řádka 'AddVoice'. LANGUAGE je ISO kód jazyka tohoto hlasu (en, cs, de, ...) SYMBOLICNAME je symbolické jméno, pod kterým chcete, aby byl tento hlas dostupný. *Note Standardní hlasy::, pro seznam symbolických jmen, která můžete použít. NAME je jméno specifické pro daný výstupní modul. Prosím podívejte se na komentáře v příslušném konfiguračním souboru v sekci AddModule pro detailnější informace. Např. definice, kterou v součastnosti používáme pro Epos (generic) vypadá takto: AddVoice "cs" "male1" "kadlec" AddVoice "sk" "male1" "bob" 'ModuleDelimiters "DELIMITERS", ModuleMaxChunkLength LENGTH' Často se výstupní modul nesnaží vysyntetizovat celý příchozí text najednou, ale místo toho jej nejprve rozřeže na menší kousky (věty, části vět) a ty potom postupně odesílá na syntézu. Tento přístup, využívaný některými výstupními moduly, je mnohem rychlejší, ale na druhé straně zase limituje schopnost syntetizéru poskytnout dobrou intonaci. Z toho důvodu máte obyčejně možnost zkonfigurovat si na jakých znacích (DELIMITERS) by se měl text rozdělit na menší části (pokud jsou následovány nějakým whitespace znakem). Druhá volba (LENGTH) udává, po kolika znacích by se měl text násilně rozdělit, pokud nebyl nalezen žádný delimiter. Pokud tato dvě pravidla zpřísníte, dostanete lepší rychlost, ale vzdáte se určité části kvality intonace. Takže například pro pomalejší počítače doporučujeme do DELIMITERS vložit i čárku (,), aby byl text rozdělen i na částech věty, zatímco na rychlejších počítačích je lepší tam čárku nedávat, takže do syntetizéru vždy dorazí celá souvětí. To samé platí o 'MaxChunkLength'. Pro rychlejší počítače je lepší nastavit větší hodnotu. Například výchozí hodnoty ve výstupním modulu pro Festival jsou: FestivalMaxChunkLength 300 FestivalDelimiters ".?!;,:" Výstupní modul se může také rozhodnout dělit věty na delimiters pouze pokud ty jsou následovány mezerou. Takže například "file123.tmp" by rozděleno nebylo, ale věta "The horse raced around the fence, that was lately painted green, fell." by rozdělena byla (to je mimochodem velmi zajímavá věta).  File: speech-dispatcher-cs.info, Node: Konfigurace generického výstupního modulu, Prev: Konfigurační soubory výstupních modulů, Up: Nastavení výstupních modulů 2.3.3.3 Konfigurace generického výstupního modulu ................................................. Generický výstupní modul uživatelům dovoluje jednoduše si napsat vlastní jednoduchý výstupní modul pro syntetizéry, které mají rozhraní ve formě jednoduchého řádkového klienta, pouze modifikací konfiguračního souboru. Tímto způsobem nemusí psát žádný specifický kód v C a uživatelé si mohou přidávat podporu pro výstupní zařízení i když neumí programovat. *Note AddModule::. Klíčová část každého generického výstupního modulu je definice řetězce, který se má spouštět. -- Konfigurace generického modulu: GenericExecuteSynth "EXECUTION_STRING" 'execution_string' je příkaz, který by měl být zavolán v shellu, když je potřeba něco říct. Ve skutečnosti to může být více jak jeden příkaz, dohromady zřetězené operátorem '&&'. Když bude výstupní modul chtít přeříkávání zprávy zastavit, zašle těmto procesům signál KILL, takže je důležité, aby použité příkazy po obdržení KILL okamžitě přestaly mluvit. (Na většině GNU/Linuxových systémů má tuto vlastnost utilita 'play') V 'execution_string' můžete využít těchto proměnných, které budou nahrazeny pořadovanými hodnotami, než bude příkaz vykonán. * '$DATA' Text, který by měl být přeříkán. Znaky řetězce, které by nějak interferovali se zpracováním v bashi budou automaticky nahrazeny odpovídajícími escape sekvencemi. Asi bude ale nutné uvést kolem této proměnné uvozovky (např. takto: '\"$DATA\"'). * '$LANG' Identifikační řetězec jazyka (ten je definován pomocí GenericLanguage). * '$VOICE' Identifikační řetězec hlasu (ten je definován pomocí AddVoice). * '$PITCH' Požadovaná výška hlasu (desetinné číslo definované v GenericPitchAdd a v GenericPitchMultiply) * '$RATE' Požadovaná rychlost hlasu (desetinné číslo definované v GenericRateAdd a v GenericRateMultiply) Tady je příklad z 'etc/speech-dispatcher/modules/epos-generic.conf' GenericExecuteSynth \ "epos-say -o --language $LANG --voice $VOICE --init_f $PITCH --init_t $RATE \ \"$DATA\" | sed -e s+unknown.*$++ >/tmp/epos-said.wav && play /tmp/epos-said.wav >/dev/null" -- Konfigurace generického modulu: AddVoice "LANGUAGE" "SYMBOLICNAME" "NAME" *Note AddVoice::. -- Konfigurace generického modulu: GenericLanguage "iso-code" "string-subst" Definuje, jaký řetězec 'string-subst' by měl být nahrazen za '$LANG' pro daný 'iso-code' ISO kód jazyka. Opět příklad z Epos generic: GenericLanguage "en" "english" GenericLanguage "cs" "czech" GenericLanguage "sk" "slovak" -- Konfigurace generického modulu: GenericRateAdd NUM -- Konfigurace generického modulu: GenericRateMultiply NUM -- Konfigurace generického modulu: GenericPitchAdd NUM -- Konfigurace generického modulu: GenericPitchMultiply NUM Tyto parametry nastavují konverzi pro výpočet rychlosti a výšky. ('$RATE' a '$PITCH'). Výsledná rychlost (nebo výška) je dána následujícím vzorcem: (speechd_rate * GenericRateMultiply) + GenericRateAdd kde speechd_rate je hodnota mezi -100 (nejnižší) a +100 (nejvyšší). Je třeba definovat nějakou rozumnou konverzi pro daný syntetizér. (Hodnoty v GenericNěcoMultiply jsou vynásobeny stem, protože stávající verze DotConfu nepodporuje desetinná čísla. Můžete tedy psát 0.85 jako 85 atd.)  File: speech-dispatcher-cs.info, Node: Úrovně logování, Prev: Nastavení výstupních modulů, Up: Konfigurace 2.3.4 Úrovně logování --------------------- Ve Speech Dispatcheru je 6 různých úrovní logování. 0 znamená žádné logování, zatímco 5 znamená vypisovat téměř všechny dostupné informace. * Úroveň 0 * Žádné informace * Úroveň 1 * Informace o startu a vypínání. * Úroveň 2 * Informace o chybách, které nastaly. * Alokace a uvolňování zdrojů při startu a při exitu. * Úroveň 3 * Informace o přijímání/odepírání/zavírání klientských spojení. * Informace o neplatných SSIP příkazech od klientů. * Úroveň 4 * Je vypisován každý přijatý příkaz * Informace o zpracovávání vstupu * Informace o ukládání zpráv do front * Informace o fungování historie, zvukových ikon, atd. facilities. * Informace o práci vlákna speak() * Úroveň 5 (Ta slouží pouze pro ladící účely a může vypisovat opravdu *mnoho* dat. Používejte opatrně.) * Všechna obdržená data jsou vypisována (zprávy od klientů) * Ladící informace. Appendix A Standardní hlasy *************************** 'MALE1' 'MALE2' 'MALE3' 'FEMALE1' 'FEMALE2' 'FEMALE3' 'CHILD_MALE' 'CHILD_FEMALE' Skutečná dostupnost těchto hlasů není zaručena, ale příkaz 'SET SELF VOICE' musí akceptovat jakýkoliv z nich. Pokud není daný hlas dostupný, je mapován na jiný hlas výstupním modulem.  File: speech-dispatcher-cs.info, Node: GNU General Public License, Next: GNU Free Documentation License, Prev: Uživatelská dokumentace, Up: Top Appendix B GNU General Public License ************************************* Version 2, June 1991 Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble ======== The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 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 this service 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. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION =============================================================== 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS Appendix: 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. Copyright (C) YYYY NAME OF AUTHOR This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) YEAR NAME OF AUTHOR Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than 'show w' and 'show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. SIGNATURE OF TY COON, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.  File: speech-dispatcher-cs.info, Node: GNU Free Documentation License, Next: Index of Concepts, Prev: GNU General Public License, Up: Top Appendix C GNU Free Documentation License ***************************************** Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See . Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. C.1 ADDENDUM: How to use this License for your documents ======================================================== To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (C) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.  File: speech-dispatcher-cs.info, Node: Index of Concepts, Prev: GNU Free Documentation License, Up: Top Index of Concepts ***************** [index] * Menu: * access rights: Přístupová práva. (line 6) * AddVoice: Konfigurace generického výstupního modulu. (line 49) * Design: Základní design. (line 6) * FDL, GNU Free Documentation License: GNU Free Documentation License. (line 7) * Filosofie: Motivace. (line 6) * GenericExecuteSynth: Konfigurace generického výstupního modulu. (line 16) * GenericLanguage: Konfigurace generického výstupního modulu. (line 53) * GenericPitchAdd: Konfigurace generického výstupního modulu. (line 66) * GenericPitchMultiply: Konfigurace generického výstupního modulu. (line 67) * GenericRateAdd: Konfigurace generického výstupního modulu. (line 64) * GenericRateMultiply: Konfigurace generického výstupního modulu. (line 65) * GPL, GNU General Public License: GNU General Public License. (line 7) * history: Historie zpráv. (line 6) * Hlavní myšlenky, Motivace: Motivace. (line 6) * identd: Autentifikace uživatelů. (line 6) * Identification Protocol: Autentifikace uživatelů. (line 6) * konfigurace: Konfigurace. (line 6) * mapování uživatlů: Autentifikace uživatelů. (line 13) * Ostatní programy: Současný stav. (line 6) * Priorita important: Typy priorit. (line 15) * Priorita message: Typy priorit. (line 32) * Priorita notification: Typy priorit. (line 57) * Priorita text: Typy priorit. (line 42) * priority: Model priorit zpráv. (line 6) * RFC 1413: Autentifikace uživatelů. (line 6) * speechd skupina: Přístupová práva. (line 16) * speechd uživatel: Přístupová práva. (line 16) * syntetizátory: Více výstupních modulů. (line 6) * Syntetizéry: Současný stav. (line 6) * tail recursion: Index of Concepts. (line 6) * výstupní modul: Více výstupních modulů. (line 6)  Tag Table: Node: Top266 Node: Úvod1622 Node: Motivace1956 Node: Základní design4651 Node: Přehled základních rysů7023 Node: Současný stav7815 Node: Uživatelská dokumentace7959 Node: Základní funkce8343 Node: Model priorit zpráv8879 Node: Typy priorit9809 Node: Diagram priorit13229 Node: Příklady využití priorit14153 Node: Historie zpráv14969 Node: Přístupová práva15810 Node: Více výstupních modulů16888 Node: Autentifikace uživatelů17608 Node: Spouštění18233 Node: Konfigurace20618 Node: Syntaxe konfiguračního souboru21380 Node: Volby v konfiguraci22415 Node: Nastavení výstupních modulů22890 Node: Natahování modulů ve speechd.conf23740 Ref: AddModule24019 Node: Konfigurační soubory výstupních modulů24853 Ref: AddVoice25422 Node: Konfigurace generického výstupního modulu28266 Node: Úrovně logování31984 Ref: Standardní hlasy33193 Node: GNU General Public License33465 Node: GNU Free Documentation License52766 Node: Index of Concepts75229  End Tag Table  Local Variables: coding: iso-8859-2 End: speech-dispatcher-0.9.1/doc/spd-say.info0000644000175000017500000001350613465234513015052 00000000000000This is spd-say.info, produced by makeinfo version 6.5 from spd-say.texi. INFO-DIR-SECTION Sound START-INFO-DIR-ENTRY * Say for Speech Dispatcher: (spd-say). Say. END-INFO-DIR-ENTRY  File: spd-say.info, Node: Top, Prev: (dir), Up: (dir) This manual documents Say for Speech Dispatcher, version 0.4. Copyright (C) 2001, 2002, 2003, 2006 Brailcom, o.p.s. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". 1 General ********* 'spd-say' is a very simple client for Speech Dispatcher that takes some text from the command line and some simple parameters and passes them to Speech Dispatcher for synthesis. The resulting synthesized speech is then played on your speakers. It can also be used for stopping and cancelling speech on Speech Dispatcher. Usage: 'spd-say [options] ["some text"]' '-r or --rate' Set the rate of the speech (between -100 and +100, default see below). '-p or --pitch' Set the pitch of the speech (between -100 and +100, default see below). '-R or --pitch-range' Set the pitch range of the speech (between -100 and +100, default see below). '-i or --volume' Set the volume (intensity) of the speech (between -100 and +100, default see below). '-o or --output-module' Set the output module. Default see below. '-O or --list-output-modules' List the output modules that are available with the current server. '-I or --sound-icon' Play the sound icon. '-l or --language' Set the language. The parameter is an iso language code, like 'en' or 'cs'. Default see below. '-t or --voice-type' Set the preferred voice type (male1, male2, male3, female1, female2, female3, child_male, child_female). '-L or --list-synthesis-voices' List the "synthesis voices" supported by an output module. If no -o option is supplied, -L displays the synthesis voices provided by the default output module. Otherwise, it displays the synthesis voices provided by the chosen module. '-y or --synthesis-voice' Set the synthesis voice. The synthesis voice is an attribute of the chosen synthesizer. Most users will probably not wish to set it, but this setting is provided for completeness. '-m or --punctuation-mode' Set the punctuation mode (none, some, all). Default see below. '-s or --spelling' Spell the message. '-x or --ssml' Set SSML mode on (default: off). The text contains SSML markup. '-e or --pipe-mode' Set pipe mode on (default: off). Reads text from stdin, writes to stdout, and also sends to Speech Dispatcher. '-w or --wait' Wait till the end of speaking the message. In this mode, spd-say returns only after the message is fully spoken on the speakers or after it gets discarded. '-S or --stop' Stop the previous message in Speech Dispatcher (regardless of the client who sent it and it's priority) before saying the specified message. If no message is specified, it just performs the stop function. '-C or --cancel' Similar to '-S', but it stops (cancels) all the messages in all the queues in Speech Dispatcher. Use this for total stop of speech. '-v or --version' Print version and copyright info. '-h or --help' Print a short help message. Defaults for rate, pitch, and volume are determined by 'DefaultRate', 'DefaultPitch', and 'DefaultVolume' settings in the 'speechd.conf' file. Factory defaults are 0, 0, and 100 respectively. The default language code is determined by the 'DefaultLanguage' setting in the 'speechd.conf' file. Factory default is 'en' (English). The default output module is determined by the 'LanguageDefaultModule' setting in the 'speechd.conf' file. Factory default is 'flite'. The default punctuation mode is determined by the 'DefaultPunctuationMode' setting in the 'speechd.conf' file. Factory default is 'none'. 2 Pipe Mode *********** In pipe mode (option '--pipe-mode' or '-e'), spd-say reads text from stdin, writes to stdout, and also sends the text to Speech Dispatcher. Example: $ cat README | spd-say -e If a line begins with the characters _!-!_, the line is sent to Speech Dispatcher as a SSIP command. Example: $ spd-say --pipe-mode The quality of mercy is not strained. !-!SET SELF VOICE FEMALE1 It droppeth as the gentle rain from heaven Upon the place beneath: it is twice blest; !-!SET SELF RATE 50 It blesseth him that gives and him that takes. ^D Note that each line of input is individually sent to Speech Dispatcher, therefore in the example above, the word _heaven_ is taken as the end of a sentence. It should be possible to use other text filtering utilities, such as 'tr' or 'fmt' to compensate. For example, the following command would clean up most cases: $ cat INSTALL | fmt -u -w 1500 | spd-say -e If the text itself contains _!-!_, just make sure it is not at the start of the line to prevent it from being interpreted as a SSIP command. The following sed command will do the job: $ cat myfile | sed -e 's/^!-!/ !-!/g' - | spd-say -e The input is sent to Speech Dispatcher as fast as it will accept and queue it. To wait for each line to be spoken, use the '--wait' or '-w' option. Example: $ spd-say --pipe-mode -w This line is spoken and processing waits for speaking to finish before this line is sent to Speech Dispatcher. ^D You can abort a long speech narative with the '--cancel' or '-C' option. $ spd-say -C  Tag Table: Node: Top190  End Tag Table speech-dispatcher-0.9.1/doc/speech-dispatcher.info0000644000175000017500000065575713465234513017111 00000000000000This is speech-dispatcher.info, produced by makeinfo version 6.5 from speech-dispatcher.texi. INFO-DIR-SECTION Sound INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * Speech Dispatcher: (speech-dispatcher). Speech Dispatcher. END-INFO-DIR-ENTRY  File: speech-dispatcher.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) This manual documents Speech Dispatcher, version 0.9.1. Copyright (C) 2001, 2002, 2003, 2006 Brailcom, o.p.s. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License." You can also (at your option) distribute this manual under the GNU General Public License: Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled "GNU General Public License" * Menu: * Introduction:: What is Speech Dispatcher. * User's Documentation:: Usage, Configuration... * Technical Specifications:: * Client Programming:: Documentation for application developers. * Server Programming:: Documentation for project contributors. * Download and Contact:: How to get Speech Dispatcher and how to contact us * Reporting Bugs:: How to report a bug * How You Can Help:: What is needed * Appendices:: * GNU General Public License:: Copying conditions for Speech Dispatcher * GNU Free Documentation License:: Copying conditions for this manual * Index of Concepts::  File: speech-dispatcher.info, Node: Introduction, Next: User's Documentation, Prev: Top, Up: Top 1 Introduction ************** * Menu: * Motivation:: Why Speech Dispatcher? * Basic Design:: How does it work? * Features Overview:: What are the assets? * Current State:: What is done?  File: speech-dispatcher.info, Node: Motivation, Next: Basic Design, Prev: Introduction, Up: Introduction 1.1 Motivation ============== Speech Dispatcher is a device independent layer for speech synthesis that provides a common easy to use interface for both client applications (programs that want to speak) and for software synthesizers (programs actually able to convert text to speech). High quality speech synthesis is now commonly available both as propriatary and Free Software solutions. It has a wide field of possible uses from educational software to specialized systems, e.g. in hospitals or laboratories. It is also a key compensation tool for the visually impaired users. For them, it is one of the two possible ways of getting output from a computer (the second one being a Braille display). The various speech synthesizers are quite different, both in their interfaces and capabilities. Thus a general common interface is needed so that the client application programmers have an easy way to use software speech synthesis and don't have to care about peculiar details of the various synthesizers. The absence of such a common and standardized interface and thus the difficulty for programmers to use software speech synthesis has been a major reason why the potential of speech synthesis technology is still not fully expoited. Ideally, there would be little distinction for applications whether they output messages on the screen or via speech. Speech Dispatcher can be compared to what a GUI toolkit is for the graphical interface. Not only does it provide an easy to use interface, some kind of theming and configuration mechanisms, but also it takes care of some of the issues inherent with this particular mode of output, such as the need for speech message serialization and interaction with the audio subsystem.  File: speech-dispatcher.info, Node: Basic Design, Next: Features Overview, Prev: Motivation, Up: Introduction 1.2 Design ========== Current Design ============== The communication between all applications and synthesizers, when implemented directly, is a mess. For this purpose, we wanted Speech Dispatcher to be a layer separating applications and synthesizers so that applications wouldn't have to care about synthesizers and synthesizers wouldn't have to care about interaction with applications. We decided we would implement Speech Dispatcher as a server receiving commands from applications over a protocol called 'SSIP', parsing them if needed, and calling the appropriate functions of output modules communicating with the different synthesizers. These output modules are implemented as plug-ins, so that the user can just load a new module if he wants to use a new synthesizer. Each client (application that wants to speak) opens a socket connection to Speech Dispatcher and calls functions like say(), stop(), and pause() provided by a library implementing the protocol. This shared library is still on the client side and sends Speech Dispatcher SSIP commands over the socket. When the messages arrive at Speech Dispatcher, it parses them, reads the text that should be said and puts it in one of several queues according to the priority of the message and other criteria. It then decides when, with which parameters (set up by the client and the user), and on which synthesizer it will say the message. These requests are handled by the output plug-ins (output modules) for different hardware and software synthesizers and then said aloud. [image src="figures/architecture.png" alt="Speech Dispatcher architecture" text=" applications protocol output modules interface Speech Dispatcher core synthesizers .-----------------------. |Emacspeak| :s l: < > | Speech Dispatcher | :m : |Apollo| :h i: | - configuration | :o : |Festival| |Speakup| :a b: | - synchronization | :d A: |Flite| :r r: | - sound icons | :u P: . |User center| :e a:

| - history | :l I: . . :d r: < > | - punctuation, ... | :e : . . : y: < > | [||| priority queues] | : : . . : : < > | | : : . `-----------------------'"] See also the detailed description *note Client Programming:: interfaces, and *note Server Programming:: documentation. Future Design ============= Speech Dispatcher currently mixes two important features: common low-level interface to multiple speech synthesizers and message management (including priorities and history). This became even more evident when we started thinking about handling messages intended for output on braille devices. Such messages of course need to be synchronized with speech messages and there is little reason why the accessibility tools should send the same message twice for these two different kinds of output used by blind people (often simultaneously). Outside the world of accessibility, applications also want to either have full control over the sound (bypass prioritisation) or to only retrieve the synthesized data, but not play them immediatelly. We want to eventually split Speech Dispatcher into two independent components: one providing a low-level interface to speech synthesis drivers, which we now call TTS API Provider and is already largely implemented in the Free(b)Soft project, and the second doing message managemenet, called Message Dispatcher. This will allow Message Dispatcher to also output on Braille as well as to use the TTS API Provider separately. From implementation point of view, an opportunity for new design based on our previous experiences allowed us to remove several bottlenecks for speed (responsiveness), ease of use and ease of implementation of extensions (particularly output modules for new synthesizers). From the architecture point of view and possibilities for new developments, we are entirely convinced that both the new design in general and the inner design of the new components is much better. While a good API and its implementation for Braille are already existent in the form of BrlAPI, the API for speech is now under developement. Please see another architecture diagram showing how we imagine Message Dispatcher in the future. [image src="figures/architecture-future.png" alt="Speech Dispatcher architecture"] References:  File: speech-dispatcher.info, Node: Features Overview, Next: Current State, Prev: Basic Design, Up: Introduction 1.3 Features Overview ===================== Speech Dispatcher from user's point of view: * ability to freely combine applications with your favorite synthesizer * message synchronization and coordination * less time devoted to configuration of applications Speech Dispatcher from application programmers's point of view: * easy way to make your applications speak * common interface to different synthesizers * higher level synchronization of messages (priorities) * no need to take care about configuration of voice(s)  File: speech-dispatcher.info, Node: Current State, Prev: Features Overview, Up: Introduction 1.4 Current State ================= In this version, most of the features of Speech Dispatcher are implemented and we believe it is now useful for applications as a device independent Text-to-Speech layer and an accessibility message coordination layer. Currently, one of the most advanced applications that works with Speech Dispatcher is 'speechd-el'. This is a client for Emacs, targeted primarily for blind people. It is similar to Emacspeak, however the two take a bit different approach and serve different user needs. You can find speechd-el on . speechd-el provides speech output when using nearly any GNU/Linux text interface, like editing text, reading email, browsing the web, etc. Orca, the primary screen reader for the Gnome Desktop, supports Speech Dispatcher directly since its version 2.19.0. See for more information. We also provide a shared C library, a Python library, a Java, Guile and a Common Lisp libraries that implement the SSIP functions of Speech Dispatcher in higher level interfaces. Writing client applications in these languages should be quite easy. On the synthesis side, there is good support for Festival, eSpeak, Flite, Cicero, IBM TTS, MBROLA, Epos, Dectalk software, Cepstral Swift and others. See *Note Supported Modules::. We decided not to interface the simple hardware speech devices as they don't support synchronization and therefore cause serious problems when handling multiple messages. Also they are not extensible, they are usually expensive and often hard to support. Today's computers are fast enough to perform software speech synthesis and Festival is a great example.  File: speech-dispatcher.info, Node: User's Documentation, Next: Technical Specifications, Prev: Introduction, Up: Top 2 User's Documentation ********************** * Menu: * Installation:: How to get it installed in the best way. * Running:: The different ways to start it. * Troubleshooting:: What to do if something doesn't work... * Configuration:: How to configure Speech Dispatcher. * Tools:: What tools come with Speech Dispatcher. * Synthesis Output Modules:: Drivers for different synthesizers. * Security:: Security mechanisms and restrictions.  File: speech-dispatcher.info, Node: Installation, Next: Running, Prev: User's Documentation, Up: User's Documentation 2.1 Installation ================ This part only deals with the general aspects of installing Speech Dispatcher. If you are compiling from source code (distribution tarball or git), please refer to the file 'INSTALL' in your source tree. 2.1.1 The requirements ---------------------- You will need these components to run Speech Dispatcher: * glib 2.0 () * libdotconf 1.3 () * pthreads We recommend to also install these packages: * Festival () * festival-freebsoft-utils 0.3+ () * Sound icons library () 2.1.2 Recommended installation procedure ---------------------------------------- * Install your software synthesizer Although we highly recommend to use Festival for its excellent extensibility, good quality voices, good responsiveness and best support in Speech Dispatcher, you might want to start with eSpeak, a lightweight multi-lingual feature-complete synthesizer, to get all the key components working and perhaps only then switch to Festival. Installation of eSpeak should be easier and the default configuration of Speech Dispatcher is set up for eSpeak for this reason. You can of course also start with Epos or any other supported synthesizer. * Make sure your synthesizer works There is usually a way to test if the installation of your speech synthesizer works. For eSpeak run 'espeak "test"', for Flite run 'flite -t "Hello!"' and hear the speech. For Festival run 'festival' and type in (SayText "Hello!") (quit) * Install Speech Dispatcher Install the packages for Speech Dispatcher from your distribution or download the source tarball (or git) from and follow the instructions in the file 'INSTALL' in the source tree. * Configure Speech Dispatcher You can skip this step in most cases. If you however want to setup your own configuration of the Dispatchers default values, the easiest way to do so is through the 'spd-conf' configuration script. It will guide you through the basic configuration. It will also subsequently perform some diagnostics tests and offer some limited help with troubleshooting. Just execute spd-conf under an ordinary user or system user like 'speech-dispatcher' depending on whether you like to setup Speech Dispatcher as user or system service respectively. You might also want to explore the offered options or run some of its subsystems manually, type 'spd-conf -h' for help. If you do not want to use this script, it doesn't work in your case or it doesn't provide enough configuration flexibility, please continue as described below and/or in *Note Running Under Ordinary Users::. * Test Speech Dispatcher The simplest way to test Speech Dispatcher is through 'spd-conf -d' or through the 'spd-say' tool. Example: spd-conf -d spd-say "Hello!" spd-say -l cs -r 90 "Ahoj" If you don't hear anything, please *Note Troubleshooting::. 2.1.3 How to use eSpeak NG or eSpeak with MBROLA ------------------------------------------------ Please follow the guidelines at (resp. ) for installing eSpeak NG (resp. eSpeak) with a set of MBROLA voices that you want to use. Check the 'modules/espeak-ng-mbrola-generic.conf' (resp. 'modules/espeak-mbrola-generic.conf') configuration files for the 'AddVoice' lines. If a line for any of the voices you have installed (and it is supported by your version of eSpeak NG (resp. eSpeak), e.g. 'ls /usr/share/espeak-ng-data/voices/mb/mb-*' (resp. 'ls /usr/share/espeak-data/voices/mb/mb-*')) is not contained here, please add it. Check if 'GenericExecuteString' contains the correct name of your mbrola binary and correct path to its voice database. Restart speech-dispatcher and in your client, select 'espeak-ng-mbrola-generic' (resp. 'espeak-mbrola-generic') as your output module, or test it with the following command spd-say -o espeak-ng-mbrola-generic -l cs Testing (resp. spd-say -o espeak-mbrola-generic -l cs Testing )  File: speech-dispatcher.info, Node: Running, Next: Troubleshooting, Prev: Installation, Up: User's Documentation 2.2 Running =========== Speech Dispatcher is normally executed on a per-user basis. This provides more flexibility in user configuration, access rights and is essential in any environment where multiple people use the computer at the same time. It used to be possible to run Speech Dispatcher as a system service under a special user (and still is, with some limitations), but this mode of execution is strongly discouraged. * Menu: * Running Under Ordinary Users:: * Running in a Custom Setup:: * Setting Communication Method::  File: speech-dispatcher.info, Node: Running Under Ordinary Users, Next: Running in a Custom Setup, Prev: Running, Up: Running 2.2.1 Running Under Ordinary Users ---------------------------------- No special provisions need to be done to run Speech Dispatcher under the current user. The Speech Dispatcher process will use (or create) a '~/.cache/speech-dispatcher/' directory for its purposes (logging, pidfile). Optionally, a user can place his own configuration file in '~/.config/speech-dispatcher/speechd.conf' and it will be automatically loaded by Speech Dispatcher. The preferred way to do so is via the 'spd-conf' configuration command. If this user configuration file is not found, Speech Dispatcher will simply use the system wide configuration file (e.g. in '/etc/speech-dispatcher/speechd.conf'). # speech-dispatcher # spd-say test  File: speech-dispatcher.info, Node: Running in a Custom Setup, Next: Setting Communication Method, Prev: Running Under Ordinary Users, Up: Running 2.2.2 Running in a Custom Setup ------------------------------- Speech Dispatcher can be run in any other setup of executing users, port numbers and system paths as well. The path to configuration, pidfile and logfiles can be specified separately via compilation flags, configuration file options or command line options in this ascending order of their priority. This way can also be used to start Speech Dispatcher as a system wide service from /etc/init.d/ , although this approach is now discouraged.  File: speech-dispatcher.info, Node: Setting Communication Method, Prev: Running in a Custom Setup, Up: Running 2.2.3 Setting Communication Method ---------------------------------- Currently, two different methods are supported for communication between the server and its clients. For local communication, it's preferred to use _Unix sockets_, where the communication takes place over a Unix socket with its driving file located by default in the user's runtime directory as 'XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock'. In this way, there can be no conflict between different user sessions using different Speech Dispatchers in the same system. By default, permissions are set in such a way, that only the same user who started the server can access it, and communication is hidden to all other users. The other supported mechanism is _Inet sockets_. The server will thus run on a given port, which can be made accessible either localy or to other machines on the network as well. This is very useful in a network setup. Be however aware that while using Inet sockets, both parties (server and clients) must first agree on the communication port number to use, which can create a lot of confusion in a setup where multiple instances of the server serve multiple different users. Also, since there is currently no authentication mechanism, during Inet socket communication, the server will make no distinction between the different users connecting to it. The default port is 6560 as set in the server configuration. Client applications will respect the _SPEECHD_ADDRESS_ environment variable. The method (''unix_socket'' or ''inet_socket'') is optionally followed by it's parameters separated by a colon. For an exact description, please *Note Address specification::. An example of launching Speech Dispatcher using unix_sockets for communication on a non-standard destination and subsequently using spd-say to speak a message: killall -u `whoami` speech-dispatcher speech-dispatcher -c unix_socket -S /tmp/my.sock SPEECHD_ADDRESS=unix_socket:/tmp/my.sock spd-say "test"  File: speech-dispatcher.info, Node: Troubleshooting, Next: Configuration, Prev: Running, Up: User's Documentation 2.3 Troubleshooting =================== If you are experiencing problems when running Speech Dispatcher, please: * Use 'spd-conf' to run diagnostics: spd-conf -d * Check the appropriate logfile in '~/.cache/speech-dispatcher/log/speech-dispatcher.log' for user Speech Dispatcher or in '/var/log/speech-dispatcher/speech-dispatcher.log'. Look for lines containing the string 'ERROR' and their surrounding contents. If you hear no speech, restart Speech Dispatcher and look near the end of the log file - before any attempts for synthesis of any message. Usually, if something goes wrong with the initialization of the output modules, a textual description of the problem and a suggested solution can be found in the log file. * If this doesn't reveal the problem, please run spd-conf -D Which will genereate a very detailed logfile archive which you can examine yourself or send to us with a request for help. * You can also try to say some message directly through the utility 'spd-say'. Example: spd-say "Hello, does it work?" spd-say --language=cs --rate=20 "Everything ok?" * Check if your configuration files (speechd.conf, modules/*.conf) are correct (some uninstalled synthesizer specified as the default, wrong values for default voice parameters etc.) * There is a know problem in some versions of Festival. Please make sure that Festival server_access_list configuration variable and your /etc/hosts.conf are set properly. server_access_list must contain the symbolic name of your machine and this name must be defined in /etc/hosts.conf and point to your IP address. You can test if this is set correctly by trying to connect to the port Festival server is running on via an ordinary telnet (by default like this: 'telnet localhost 1314'). If you are not rejected, it works.  File: speech-dispatcher.info, Node: Configuration, Next: Tools, Prev: Troubleshooting, Up: User's Documentation 2.4 Configuration ================= Speech Dispatcher can be configured on several different levels. You can configure the global settings through the server configuration file, which can be placed either in the Speech Dispatcher default configuration system path like /etc/speech-dispatcher/ or in your home directory in '~/.config/speech-dispatcher/'. There is also support for per-client configuration, this is, specifying different default values for different client applications. Furthermore, applications often come with their own means of configuring speech related settings. Please see the documentation of your application for details about application specific configuration. * Menu: * Configuration file syntax:: Basic rules. * Configuration options:: What to configure. * Audio Output Configuration:: How to switch to ALSA, Pulse... * Client Specific Configuration:: Specific default values for applications. * Output Modules Configuration:: Adding and customizing output modules. * Log Levels:: Description of log levels.  File: speech-dispatcher.info, Node: Configuration file syntax, Next: Configuration options, Prev: Configuration, Up: Configuration 2.4.1 Configuration file syntax ------------------------------- We use the DotConf library to read a permanent text-file based configuration, so the syntax might be familiar to many users. Each of the string constants, if not otherwise stated differently, should be encoded in UTF-8. The option names use only the standard ASCII charset restricted to upper- and lowercase characters ('a', 'b'), dashes ('-') and underscores '_'. Comments and temporarily inactive options begin with '#'. If such an option should be turned on, just remove the comment character and set it to the desired value. # this is a comment # InactiveOption "this option is turned off" Strings are enclosed in doublequotes. LogFile "/var/log/speech-dispatcher.log" Numbers are written without any quotes. Port 6560 Boolean values use On (for true) and Off (for false). Debug Off  File: speech-dispatcher.info, Node: Configuration options, Next: Audio Output Configuration, Prev: Configuration file syntax, Up: Configuration 2.4.2 Configuration options --------------------------- All available options are documented directly in the file and examples are provided. Most of the options are set to their default value and commented out. If you want to change them, just change the value and remove the comment symbol '#'.  File: speech-dispatcher.info, Node: Audio Output Configuration, Next: Client Specific Configuration, Prev: Configuration options, Up: Configuration 2.4.3 Audio Output Configuration -------------------------------- Audio output method (ALSA, Pulse etc.) can be configured centrally from the main configuration file 'speechd.conf'. The option 'AudioOutputMethod' selects the desired audio method and further options labeled as 'AudioALSA...' or 'AudioPulse...' provide a more detailed configuration of the given audio output method. It is possible to use a list of preferred audio output methods, in which case each output module attempts to use the first availble in the given order. The example below prefers Pulse Audio, but will use ALSA if unable to connect to Pulse: AudioOutputMethod "pulse,alsa" Please note however that some more simple output modules or synthesizers, like the generic output module, do not respect these settings and use their own means of audio output which can't be influenced this way. On the other hand, the fallback dummy output module tries to use any available means of audio output to deliver its error message.  File: speech-dispatcher.info, Node: Client Specific Configuration, Next: Output Modules Configuration, Prev: Audio Output Configuration, Up: Configuration 2.4.4 Client Specific Configuration ----------------------------------- It is possible to automatically set different default values of speech parameters (e.g. rate, volume, punctuation, default voice...) for different applications that connect to Speech Dispatcher. This is especially useful for simple applications that have no parameter setting capabilities themselves or they don't support a parameter setting you wish to change (e.g. language). Using the commands 'BeginClient "IDENTIFICATION"' and 'EndClient' it is possible to open and close a section of parameter settings that only affects those client applications that identify themselves to Speech Dispatcher under the specific identification code which is matched against the string 'IDENTIFICATION'. It is possible to use wildcards ('*' matches any number of characters and '?' matches exactly one character) in the string 'IDENTIFICATION'. The identification code normally consists of 3 parts: 'user:application:connection'. 'user' is the username of the one who started the application, 'application' is the name of the application (usually the name of the binary for it) and 'connection' is a name for the connection (one application might use more connections for different purposes). An example is provided in '/etc/speech-dispatcher/speechd.conf' (see the line 'Include "clients/emacs.conf"' and '/etc/speech-dispatcher/clients/emacs.conf'.  File: speech-dispatcher.info, Node: Output Modules Configuration, Next: Log Levels, Prev: Client Specific Configuration, Up: Configuration 2.4.5 Output Modules Configuration ---------------------------------- Each user should turn on at least one output module in his configuration, if he wants Speech Dispatcher to produce any sound output. If no output module is loaded, Speech Dispatcher will start, log messages into history and communicate with clients, but no sound is produced. Each output module has an "AddModule" line in 'speech-dispatcher/speechd.conf'. Additionally, each output module can have its own configuration file. The audio output is handled by the output modules themselves, so this can be switched in their own configuration files under 'etc/speech-dispatcher/modules/'. * Menu: * Loading Modules in speechd.conf:: * Configuration files of output modules:: * Configuration of the Generic Output Module::  File: speech-dispatcher.info, Node: Loading Modules in speechd.conf, Next: Configuration files of output modules, Prev: Output Modules Configuration, Up: Output Modules Configuration 2.4.5.1 Loading Modules in speechd.conf ....................................... Each module that should be run when Speech Dispatcher starts must be loaded by the 'AddModule' command in the configuration. Note that you can load one binary module multiple times under different names with different configurations. This is especially useful for loading the generic output module. *Note Configuration of the Generic Output Module::. AddModule "MODULE_NAME" "MODULE_BINARY" "MODULE_CONFIG" MODULE_NAME is the name of the output module. MODULE_BINARY is the name of the binary executable of this output module. It can be either absolute or relative to 'bin/speechd-modules/'. MODULE_CONFIG is the file where the configuration for this output module is stored. It can be either absolute or relative to 'etc/speech-dispatcher/modules/'. This parameter is optional.  File: speech-dispatcher.info, Node: Configuration files of output modules, Next: Configuration of the Generic Output Module, Prev: Loading Modules in speechd.conf, Up: Output Modules Configuration 2.4.5.2 Configuration Files of Output Modules ............................................. Each output module is different and therefore has different configuration options. Please look at the comments in its configuration file for a detailed description. However, there are several options which are common for some output modules. Here is a short overview of them. * AddVoice "LANGUAGE" "SYMBOLICNAME" "NAME" Each output module provides some voices and sometimes it even supports different languages. For this reason, there is a common mechanism for specifying these in the configuration, although no module is obligated to use it. Some synthesizers, e.g. Festival, support the SSIP symbolic names directly, so the particular configuration of these voices is done in the synthesizer itself. For each voice, there is exactly one 'AddVoice' line. LANGUAGE is the ISO language code of the language of this voice. SYMBOLICNAME is a symbolic name under which you wish this voice to be available. See *note Standard Voices: (ssip)Top. for the list of names you can use. NAME is a name specific for the given output module. Please see the comments in the configuration file under the appropriate AddModule section for more info. For example our current definition of voices for Epos (file '/etc/speech-dispatcher/modules/generic-epos.conf' looks like this: AddVoice "cs" "male1" "kadlec" AddVoice "sk" "male1" "bob" * ModuleDelimiters "DELIMITERS", ModuleMaxChunkLength LENGTH Normally, the output module doesn't try to synthesize all incoming text at once, but instead it cuts it into smaller chunks (sentences, parts of sentences) and then synthesizes them one by one. This second approach, used by some output modules, is much faster, however it limits the ability of the output module to provide good intonation. NOTE: The Festival module does not use ModuleDelimiters and ModuleMaxChunkLength. For this reason, you can configure at which characters (DELIMITERS) the text should be cut into smaller blocks or after how many characters (LENGTH) it should be cut, if there is no DELIMITER found. Making the two rules more strict, you will get better speed but give away some quality of intonation. So for example for slower computers, we recommend to include comma (,) in DELIMITERS so that sentences are cut into phrases, while for faster computers, it's preferable not to include comma and synthesize the whole compound sentence. The same applies to 'MaxChunkLength', it's better to set higher values for faster computers. For example, curently the default for Flite is FestivalMaxChunkLength 500 FestivalDelimiters ".?!;" The output module may also decide to cut sentences on delimiters only if they are followed by a space. This way for example "file123.tmp" would not be cut in two parts, but "The horse raced around the fence, that was lately painted green, fell." would be. (This is an interesting sentence, by the way.)  File: speech-dispatcher.info, Node: Configuration of the Generic Output Module, Prev: Configuration files of output modules, Up: Output Modules Configuration 2.4.5.3 Configuration files of the Generic Output Module ........................................................ The generic output module allows you to easily write your own output module for synthesizers that have a simple command line interface by modifying the configuration file. This way, users can add support for their device even if they don't know how to program. *Note AddModule::. The core part of a generic output module is the command execution line. -- Generic Module Configuration: GenericExecuteSynth "EXECUTION_STRING" 'execution_string' is the command that should be executed in a shell when it's desired to say something. In fact, it can be multiple commands concatenated by the '&&' operator. To stop saying the message, the output module will send a KILL signal to the process group, so it's important that it immediately stops speaking after the processes are killed. (On most GNU/Linux system, the 'play' utility has this property). In the execution string, you can use the following variables, which will be substituted by the desired values before executing the command. * '$DATA' The text data that should be said. The string's characters that would interfere with bash processing are already escaped. However, it may be necessary to put double quotes around it (like this: '\"$DATA\"'). * '$LANG' The language identification string (it's defined by GenericLanguage). * '$VOICE' The voice identification string (it's defined by AddVoice). * '$PITCH' The desired pitch (a float number defined in GenericPitchAdd and GenericPitchMultiply). * '$PITCH_RANGE' The desired pitch range (a float number defined in GenericPitchRangeAdd and GenericPitchRangeMultiply). * '$RATE' The desired rate or speed (a float number defined in GenericRateAdd and GenericRateMultiply) Here is an example from 'etc/speech-dispatcher/modules/epos-generic.conf' GenericExecuteSynth \ "epos-say -o --language $LANG --voice $VOICE --init_f $PITCH --init_t $RATE \ \"$DATA\" | sed -e s+unknown.*$++ >/tmp/epos-said.wav && play /tmp/epos-said.wav >/dev/null" -- GenericModuleConfiguration: AddVoice "LANGUAGE" "SYMBOLICNAME" "NAME" *Note AddVoice::. -- GenericModuleConfiguration: GenericLanguage "iso-code" "string-subst" Defines which string 'string-subst' should be substituted for '$LANG' given an 'iso-code' language code. Another example from Epos generic: GenericLanguage "en" "english" GenericLanguage "cs" "czech" GenericLanguage "sk" "slovak" -- GenericModuleConfiguration: GenericRateAdd NUM -- GenericModuleConfiguration: GenericRateMultiply NUM -- GenericModuleConfiguration: GenericPitchAdd NUM -- GenericModuleConfiguration: GenericPitchMultiply NUM -- GenericModuleConfiguration: GenericPitchRangeAdd NUM -- GenericModuleConfiguration: GenericPitchRangeMultiply NUM These parameters set rate and pitch conversion to compute the value of '$RATE', '$PITCH' and '$PITCH_RANGE'. The resulting rate (or pitch) is calculated using the following formula: (speechd_rate * GenericRateMultiply) + GenericRateAdd where speechd_rate is a value between -100 (lowest) and +100 (highest) Some meaningful conversion for the specific text-to-speech system used must by defined. (The values in GenericSthMultiply are multiplied by 100 because DotConf currently doesn't support floats. So you can write 0.85 as 85 and so on.)  File: speech-dispatcher.info, Node: Log Levels, Prev: Output Modules Configuration, Up: Configuration 2.4.6 Log Levels ---------------- There are 6 different verbosity levels of Speech Dispatcher logging. 0 means no logging, while 5 means that nearly all the information about Speech Dispatcher's operation is logged. * Level 0 * No information. * Level 1 * Information about loading and exiting. * Level 2 * Information about errors that occurred. * Allocating and freeing resources on start and exit. * Level 3 * Information about accepting/rejecting/closing clients' connections. * Information about invalid client commands. * Level 4 * Every received command is output. * Information preceding the command output. * Information about queueing/allocating messages. * Information about the history, sound icons and other facilities. * Information about the work of the speak() thread. * Level 5 (This is only for debugging purposes and will output *a lot* of data. Use with caution.) * Received data (messages etc.) is output. * Debugging information.  File: speech-dispatcher.info, Node: Tools, Next: Synthesis Output Modules, Prev: Configuration, Up: User's Documentation 2.5 Tools ========= Several small tools are distributed together with Speech Dispatcher. 'spd-say' is a small client that allows you to send messages to Speech Dispatcher in an easy way and have them spoken, or cancel speech from other applications. * Menu: * spd-say:: Say a given text or cancel messages in Dispatcher. * spd-conf:: Configuration, diagnostics and troubleshooting tool * spd-send:: Direct SSIP communication from command line.  File: speech-dispatcher.info, Node: spd-say, Next: spd-conf, Prev: Tools, Up: Tools 2.5.1 spd-say ------------- spd-say is documented in its own manual. *Note (spd-say)Top::.  File: speech-dispatcher.info, Node: spd-conf, Next: spd-send, Prev: spd-say, Up: Tools 2.5.2 spd-conf -------------- spd-conf is a tool for creating basic configuration, initial setup of some basic settings (output module, audio method), diagnostics and automated debugging with a possibility to send the debugging output to the developers with a request for help. The available command options are self-documented through 'spd-say -h'. In any working mode, the tool asks the user about future actions and preferred configuration of the basic options. Most useful ways of execution are: * 'spd-conf' Create new configuration and setup basic settings according to user answers. Run diagnostics and if some problems occur, run debugging and offer to send a request for help to the developers. * 'spd-conf -d' Run diagnostics of problems. * 'spd-conf -D' Run debugging and offer to send a request for help to the developers.  File: speech-dispatcher.info, Node: spd-send, Prev: spd-conf, Up: Tools 2.5.3 spd-send -------------- spd-send is a small client/server application that allows you to establish a connection to Speech Dispatcher and then use a simple command line tool to send and receive SSIP protocol communication. Please see 'src/c/clients/spd-say/README' in the Speech Dispatcher's source tree for more information.  File: speech-dispatcher.info, Node: Synthesis Output Modules, Next: Security, Prev: Tools, Up: User's Documentation 2.6 Synthesis Output Modules ============================ Speech Dispatcher supports concurrent use of multiple output modules. If the output modules provide good synchronization, you can combine them when reading messages. For example if module1 can speak English and Czech while module2 speaks only German, the idea is that if there is some message in German, module2 is used, while module1 is used for the other languages. However the language is not the only criteria for the decision. The rules for selection of an output module can be influenced through the configuration file 'speech-dispatcher/speechd.conf'. * Menu: * Provided Functionality:: Some synthesizers don't support the full set of SSIP features.  File: speech-dispatcher.info, Node: Provided Functionality, Prev: Synthesis Output Modules, Up: Synthesis Output Modules 2.6.1 Provided functionality ---------------------------- Please note that some output modules don't support the full Speech Dispatcher functionality (e.g. spelling mode, sound icons). If there is no easy way around the missing functionality, we don't try to emulate it in some complicated way and rather try to encourage the developers of that particular synthesizer to add that functionality. We are actively working on adding the missing parts to Festival, so Festival supports nearly all of the features of Speech Dispatcher and we encourage you to use it. Much progress has also been done with eSpeak. * Menu: * Supported Modules::  File: speech-dispatcher.info, Node: Supported Modules, Prev: Provided Functionality, Up: Provided Functionality 2.6.1.1 Supported Modules ......................... * Festival Festival is a free software multi-language Text-to-Speech synthesis system that is very flexible and extensible using the Scheme scripting language. Currently, it supports high quality synthesis for several languages, and on today's computers it runs reasonably fast. If you are not sure which one to use and your language is supported by Festival, we advise you to use it. See . * eSpeak eSpeak is a newer very lightweight free software engine with a broad range of supported languages and a good quality of voice at high rates. See . * Flite Flite (Festival Light) is a lightweight free software TTS synthesizer intended to run on systems with limited resources. At this time, it has only one English voice and porting voices from Festival looks rather difficult. With the caching mechanism provided by Speech Dispatcher, Festival is faster than Flite in most situations. See . * Generic The Generic module can be used with any synthesizer that can be managed by a simple command line application. *Note Configuration of the Generic Output Module::, for more details about how to use it. However, it provides only very rudimentary support of speaking. * Pico The SVOX Pico engine is a software speech synthesizer for German, English (GB and US), Spanish, French and Italian. SVOX produces clear and distinct speech output made possible by the use of Hidden Markov Model (HMM) algorithms. See . Pico documentation can be found at It includes three manuals: - SVOX_Pico_Lingware.pdf - SVOX_Pico_Manual.pdf - SVOX_Pico_architecture_and_design.pdf  File: speech-dispatcher.info, Node: Security, Prev: Synthesis Output Modules, Up: User's Documentation 2.7 Security ============ Speech Dispatcher doesn't implement any special authentication mechanisms but uses the standard system mechanisms to regulate access. If the default 'unix_socket' communication mechanism is used, only the user who starts the server can connect to it due to imposed restrictions on the unix socket file permissions. In case of the 'inet_socket' communication mechanism, where clients connect to Speech Dispatcher on a specified port, theoretically everyone could connect to it. The access is by default restricted only for connections originating on the same machine, which can be changed via the LocalhostAccessOnly option in the server configuration file. In such a case, the user is reponsible to set appropriate security restrictions on the access to the given port on his machine from the outside network using a firewall or similar mechanism.  File: speech-dispatcher.info, Node: Technical Specifications, Next: Client Programming, Prev: User's Documentation, Up: Top 3 Technical Specifications ************************** * Menu: * Communication mechanisms:: * Address specification:: * Actions performed on startup:: * Accepted signals::  File: speech-dispatcher.info, Node: Communication mechanisms, Next: Address specification, Prev: Technical Specifications, Up: Technical Specifications 3.1 Communication mechanisms ============================ Speech Dispatcher supports two communicatino mechanisms: UNIX-style and Inet sockets, which are refered as 'unix-socket' and 'inet-socket' respectively. The communication mechanism is decided on startup and cannot be changed at runtime. Unix sockets are now the default and preferred variant for local communication, Inet sockets are necessary for communication over network. The mechanism for the decision of which method to use is as follows in this order of precedence: command-line option, configuration option, the default value 'unix-socket'. _Unix sockets_ are associated with a file in the filesystem. By default, this file is placed in the user's runtime directory (as determined by the value of the XDG_RUNTIME_DIR environment variable and the system configuration for the given user). It's default name is constructed as 'XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock'. The access permissions for this file are set to 600 so that it's restricted to read/write by the current user. As such, access is handled properly and there are no conflicts between the different instances of Speech Dispatcher run by the different users. Client applications and libraries are supposed to independently replicate the process of construction of the socket path and connect to it, thus establishing a common communication channel in the default setup. It should be however possible in the client libraries and is possible in the server, to define a custom file as a socket name if needed. Client libraries should respect the SPEECHD_ADDRESS environment variable. _Inet sockets_ are based on communication over a given port on the given host, two variables which must be previously agreed between the server and client before a connection can be established. The only implicit security restriction is the server configuration option which can allow or disallow access from machines other than localhost. By convention, the clients should use host and port given by one of the following sources in the following order of precedence: its own configuration, value of the SPEECHD_ADDRESS environment variable and the default pair (localhost, 6560). *Note Setting Communication Method::.  File: speech-dispatcher.info, Node: Address specification, Next: Actions performed on startup, Prev: Communication mechanisms, Up: Technical Specifications 3.2 Address specification ========================= Speech Dispatcher provies several methods of communication and can be used both locally and over network. *Note Communication mechanisms::. Client applications and interface libraries need to recognize an address, which specifies how and where to contact the appropriate server. Address specification consits from the method and one or more of its parameters, each item separated by a colon: method:parameter1:parameter2 The method is either 'unix_socket' or 'inet_socket'. Parameters are optional. If not used in the address line, their default value will be used. Two forms are currently recognized: unix_socket:full/path/to/socket inet_socket:host_ip:port Examples of valid address lines are: unix_socket unix_socket:/tmp/test.sock inet_socket inet_socket:192.168.0.34 inet_socket:192.168.0.34:6563 Clients implement different mechanisms how the user can set the address. Clients should respect the SPEECHD_ADDRESS environment variable *Note Setting Communication Method::, unless the user ovverrides its value by settins in the client application itself. Clients should fallback to the default address, if neither the environment variable or their specific configuration is set. The default communication address currently is: unix_socket:/$XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock where '~' stands for the path to the users home directory.  File: speech-dispatcher.info, Node: Actions performed on startup, Next: Accepted signals, Prev: Address specification, Up: Technical Specifications 3.3 Actions performed on startup ================================ What follows is an overview of the actions the server takes on startup in this order: * Initialize logging stage 1 Set loglevel to 1 and log destination to stderr (logfile is not ready yet). * Parse command line options Read preferred communication method, destinations for logfile and pidfile * Establish the '~/.config/speech-dispatcher/' and '~/.cache/speech-dispatcher/' directories If pid and conf paths were not given as command line options, the server will place them in '~/.config/speech-dispatcher/' and '~/.cache/speech-dispatcher/' by default. If they are not specified AND the current user doesn't have a system home directory, the server will fail startup. The configuration file is pointed to '~/.config/speech-dispatcher/speechd.conf' if it exists, otherwise to '/etc/speech-dispatcher/speechd.conf' or a similar system location according to compile options. One of these files must exists, otherwise Speech Dispatcher will not know where to find its output modules. * Create pid file Check the pid file in the determined location. If an instance of the server is already running, log an error message and exit with error code 1, otherwise create and lock a new pid file. * Check for autospawning enabled If the server is started with -spawn, check whether autospawn is not disabled in the configuration (DisableAutoSpawn config option in speechd.conf). If it is disabled, log an error message and exit with error code 1. * Install signal handlers * Create unix or inet sockets and start listening * Initialize Speech Dispatcher Read the configuration files, setup some lateral threads, start and initialize output modules. Reinitialize logging (stage 2) into the final logfile destination (as determined by the command line option, the configuration option and the default location in this order of precedence). After this step, Speech Dispatcher is ready to accept new connections. * Daemonize the process Fork the process, disconnect from standard input and outputs, disconnect from parent process etc. as prescribed by the POSIX standards. * Initialize the speaking lateral thread Initialize the second main thread which will process the speech request from the queues and pass them onto the Speech Dispatcher modules. * Start accepting new connections from clients Start listening for new connections from clients and processing them in a loop.  File: speech-dispatcher.info, Node: Accepted signals, Prev: Actions performed on startup, Up: Technical Specifications 3.4 Accepted signals ==================== * SIGINT Terminate the server * SIGHUP Reload configuration from config files but do not restart modules * SIGUSR1 Reload dead output modules (modules which were previously working but crashed during runtime and marked as dead) * SIGPIPE Ignored  File: speech-dispatcher.info, Node: Client Programming, Next: Server Programming, Prev: Technical Specifications, Up: Top 4 Client Programming ******************** Clients communicate with Speech Dispatcher via the Speech Synthesis Internet Protocol (SSIP) *Note (ssip)Top::. The protocol is the actual interface to Speech Dispatcher. Usually you don't need to use SSIP directly. You can use one of the supplied libraries, which wrap the SSIP interface. This is the recommended way of communicating with Speech Dispatcher. We try so support as many programming environments as possible. This manual (except SSIP) contains documentation for the C and Python libraries, however there are also other libraries developed as external projects. Please contact us for information about current external client libraries. * Menu: * C API:: Shared library for C/C++ * Python API:: Python module. * Guile API:: * Common Lisp API:: * Autospawning:: How server is started from clients  File: speech-dispatcher.info, Node: C API, Next: Python API, Prev: Client Programming, Up: Client Programming 4.1 C API ========= * Menu: * Initializing and Terminating in C:: * Speech Synthesis Commands in C:: * Speech output control commands in C:: * Characters and Keys in C:: * Sound Icons in C:: * Parameter Setting Commands in C:: * Other Functions in C:: * Information Retrieval Commands in C:: * Event Notification and Index Marking in C:: * History Commands in C:: * Direct SSIP Communication in C::  File: speech-dispatcher.info, Node: Initializing and Terminating in C, Next: Speech Synthesis Commands in C, Prev: C API, Up: C API 4.1.1 Initializing and Terminating ---------------------------------- -- C API function: SPDConnection* spd_open(char* client_name, char* connection_name, char* user_name, SPDConnectionMode connection_mode) Opens a new connection to Speech Dispatcher and returns a socket file descriptor you will use to communicate with Speech Dispatcher. The socket file descriptor is a parameter used in all the other functions. It now uses local communication via inet sockets. See 'spd_open2' for more details. The three parameters 'client_name', 'connection_name' and 'username' are there only for informational and navigational purposes, they don't affect any settings or behavior of any functions. The authentication mechanism has nothing to do with 'username'. These parameters are important for the user when he wants to set some parameters for a given session, when he wants to browse through history, etc. The parameter 'connection_mode' specifies how this connection should be handled internally and if event notifications and index marking capabilities will be available. 'client_name' is the name of the client that opens the connection. Normally, it should be the name of the executable, for example "lynx", "emacs", "bash", or "gcc". It can be left as NULL. 'connection_name' determines the particular use of that connection. If you use only one connection in your program, this should be set to "main" (passing a NULL pointer has the same effect). If you use two or more connections in your program, their 'client_name's should be the same, but 'connection_name's should differ. For example: "buffer", "command_line", "text", "menu". 'username' should be set to the name of the user. Normally, you should get this string from the system. If set to NULL, libspeechd will try to determine it automatically by g_get_user_name(). 'connection_mode' has two possible values: 'SPD_MODE_SINGLE' and 'SPD_MODE_THREADED'. If the parameter is set to 'SPD_MODE_THREADED', then 'spd_open()' will open an additional thread in your program which will handle asynchronous SSIP replies and will allow you to use callbacks for event notifications and index marking, allowing you to keep track of the progress of speaking the messages. However, you must be aware that your program is now multi-threaded and care must be taken when using/handling signals. If 'SPD_MODE_SINGLE' is chosen, the library won't execute any additional threads and SSIP will run only as a synchronous protocol, therefore event notifications and index marking won't be available. It returns a newly allocated SPDConnection* structure on success, or 'NULL' on error. Each connection you open should be closed by spd_close() before the end of the program, so that the associated connection descriptor is closed, threads are terminated and memory is freed. -- C API function: SPDConnection* spd_open2(char* client_name, char* connection_name, char* user_name, SPDConnectionMode connection_mode, SPDConnectionMethod method, int autospawn) Opens a new connection to Speech Dispatcher and returns a socket file descriptor. This function is the same as 'spd_open' except that it gives more control of the communication method and autospawn functionality as described below. 'method' is either 'SPD_METHOD_UNIX_SOCKET' or 'SPD_METHOD_INET_SOCKET'. By default, unix socket communication should be preferred, but inet sockets are necessary for cross-network communication. 'autospawn' is a boolean flag specifying whether the function should try to autospawn (autostart) the Speech Dispatcher server process if it is not running already. This is set to 1 by default, so this function should normally not fail even if the server is not yet running. -- C API function: void spd_close(SPDConnection *connection) Closes a Speech Dispatcher socket connection, terminates associated threads (if necessary) and frees the memory allocated by spd_open(). You should close every connection before the end of your program. 'connection' is the SPDConnection connection obtained by spd_open().  File: speech-dispatcher.info, Node: Speech Synthesis Commands in C, Next: Speech output control commands in C, Prev: Initializing and Terminating in C, Up: C API 4.1.2 Speech Synthesis Commands ------------------------------- -- Variable: C API type SPDPriority 'SPDPriority' is an enum type that represents the possible priorities that can be assigned to a message. typedef enum{ SPD_IMPORTANT = 1, SPD_MESSAGE = 2, SPD_TEXT = 3, SPD_NOTIFICATION = 4, SPD_PROGRESS = 5 }SPDPriority; *Note Message Priority Model: (ssip)Top. -- C API function: int spd_say(SPDConnection* connection, SPDPriority priority, char* text); Sends a message to Speech Dispatcher. If this message isn't blocked by some message of higher priority and this CONNECTION isn't paused, it will be synthesized directly on one of the output devices. Otherwise, the message will be discarded or delayed according to its priority. 'connection' is the SPDConnection* connection created by spd_open(). 'priority' is the desired priority for this message. *Note Message Priority Model: (ssip)Top. 'text' is a null terminated string containing text you want sent to synthesis. It must be encoded in UTF-8. Note that this doesn't have to be what you will finally hear. It can be affected by different settings, such as spelling, punctuation, text substitution etc. It returns a positive unique message identification number on success, -1 otherwise. This message identification number can be saved and used for the purpose of event notification callbacks or history handling. -- C API function: int spd_sayf(SPDConnection* connection, SPDPriority priority, char* format, ...); Similar to 'spd_say()', simulates the behavior of printf(). 'format' is a string containing text and formatting of the parameters, such as "%d", "%s" etc. It must be encoded in UTF-8. '...' is an arbitrary number of arguments. All other parameters are the same as for spd_say(). For example: spd_sayf(conn, SPD_TEXT, "Hello %s, how are you?", username); spd_sayf(conn, SPD_IMPORTANT, "Fatal error on [%s:%d]", filename, line); But be careful with unicode! For example this doesn't work: spd_sayf(conn, SPD_NOTIFY, ``Pressed key is %c.'', key); Why? Because you are supposing that key is a char, but that will fail with languages using multibyte charsets. The proper solution is: spd_sayf(conn, SPD_NOTIFY, ``Pressed key is %s'', key); where key is an encoded string. It returns a positive unique message identification number on success, -1 otherwise. This message identification number can be saved and used for the purpose of event notification callbacks or history handling.  File: speech-dispatcher.info, Node: Speech output control commands in C, Next: Characters and Keys in C, Prev: Speech Synthesis Commands in C, Up: C API 4.1.3 Speech Output Control Commands ------------------------------------ Stop Commands ............. -- C API function: int spd_stop(SPDConnection* connection); Stops the message currently being spoken on a given connection. If there is no message being spoken, does nothing. (It doesn't touch the messages waiting in queues). This is intended for stops executed by the user, not for automatic stops (because automatically you can't control how many messages are still waiting in queues on the server). 'connection' is the SPDConnection* connection created by spd_open(). It returns 0 on success, -1 otherwise. -- C API function: int spd_stop_all(SPDConnection* connection); The same as spd_stop(), but it stops every message being said, without distinguishing where it came from. It returns 0 on success, -1 if some of the stops failed. -- C API function: int spd_stop_uid(SPDConnection* connection, int target_uid); The same as spd_stop() except that it stops a client client different from the calling one. You must specify this client in 'target_uid'. 'target_uid' is the unique ID of the connection you want to execute stop() on. It can be obtained from spd_history_get_client_list(). *Note History Commands in C::. It returns 0 on success, -1 otherwise. Cancel Commands ............... -- C API function: int spd_cancel(SPDConnection* connection); Stops the currently spoken message from this connection (if there is any) and discards all the queued messages from this connection. This is probably what you want to do, when you call spd_cancel() automatically in your program. -- C API function: int spd_cancel_all(SPDConnection* connection); The same as spd_cancel(), but it cancels every message without distinguishing where it came from. It returns 0 on success, -1 if some of the stops failed. -- C API function: int spd_cancel_uid(SPDConnection* connection, int target_uid); The same as spd_cancel() except that it executes cancel for some other client than the calling one. You must specify this client in 'target_uid'. 'target_uid' is the unique ID of the connection you want to execute cancel() on. It can be obtained from spd_history_get_client_list(). *Note History Commands in C::. It returns 0 on success, -1 otherwise. Pause Commands .............. -- C API function: int spd_pause(SPDConnection* connection); Pauses all messages received from the given connection. No messages except for priority 'notification' and 'progress' are thrown away, they are all waiting in a separate queue for resume(). Upon resume(), the message that was being said at the moment pause() was received will be continued from the place where it was paused. It returns immediately. However, that doesn't mean that the speech output will stop immediately. Instead, it can continue speaking the message for a while until a place where the position in the text can be determined exactly is reached. This is necessary to be able to provide 'resume' without gaps and overlapping. When pause is on for the given client, all newly received messages are also queued and waiting for resume(). It returns 0 on success, -1 if something failed. -- C API function: int spd_pause_all(SPDConnection* connection); The same as spd_pause(), but it pauses every message, without distinguishing where it came from. It returns 0 on success, -1 if some of the pauses failed. -- C API function: int spd_pause_uid(SPDConnection* connection, int target_uid); The same as spd_pause() except that it executes pause for a client different from the calling one. You must specify the client in 'target_uid'. 'target_uid' is the unique ID of the connection you want to pause. It can be obtained from spd_history_get_client_list(). *Note History Commands in C::. It returns 0 on success, -1 otherwise. Resume Commands ............... -- C API function: int spd_resume(SPDConnection* connection); Resumes all paused messages from the given connection. The rest of the message that was being said at the moment pause() was received will be said and all the other messages are queued for synthesis again. 'connection' is the SPDConnection* connection created by spd_open(). It returns 0 on success, -1 otherwise. -- C API function: int spd_resume_all(SPDConnection* connection); The same as spd_resume(), but it resumes every paused message, without distinguishing where it came from. It returns 0 on success, -1 if some of the pauses failed. -- C API function: int spd_resume_uid(SPDConnection* connection, int target_uid); The same as spd_resume() except that it executes resume for a client different from the calling one. You must specify the client in 'target_uid'. 'target_uid' is the unique ID of the connection you want to resume. It can be obtained from spd_history_get_client_list(). *Note History Commands in C::. It returns 0 on success, -1 otherwise.  File: speech-dispatcher.info, Node: Characters and Keys in C, Next: Sound Icons in C, Prev: Speech output control commands in C, Up: C API 4.1.4 Characters and Keys ------------------------- -- C API function: int spd_char(SPDConnection* connection, SPDPriority priority, char* character); Says a character according to user settings for characters. For example, this can be used for speaking letters under the cursor. 'connection' is the SPDConnection* connection created by spd_open(). 'priority' is the desired priority for this message. *Note Message Priority Model: (ssip)Top. 'character' is a NULL terminated string of chars containing one UTF-8 character. If it contains more characters, only the first one is processed. It returns 0 on success, -1 otherwise. -- C API function: int spd_wchar(SPDConnection* connection, SPDPriority priority, wchar_t wcharacter); The same as spd_char(), but it takes a wchar_t variable as its argument. It returns 0 on success, -1 otherwise. -- C API function: int spd_key(SPDConnection* connection, SPDPriority priority, char* key_name); Says a key according to user settings for keys. 'connection' is the SPDConnection* connection created by spd_open(). 'priority' is the desired priority for this message. *Note Message Priority Model: (ssip)Top. 'key_name' is the name of the key in a special format. *Note Speech Synthesis and Sound Output Commands: (ssip)Top, (KEY, the corresponding SSIP command) for description of the format of 'key_name' It returns 0 on success, -1 otherwise.  File: speech-dispatcher.info, Node: Sound Icons in C, Next: Parameter Setting Commands in C, Prev: Characters and Keys in C, Up: C API 4.1.5 Sound Icons ----------------- -- C API function: int spd_sound_icon(SPDConnection* connection, SPDPriority priority, char* icon_name); Sends a sound icon ICON_NAME. These are symbolic names that are mapped to a sound or to a text string (in the particular language) according to Speech Dispatcher tables and user settings. Each program can also define its own icons. 'connection' is the SPDConnection* connection created by spd_open(). 'priority' is the desired priority for this message. *Note Message Priority Model: (ssip)Top. 'icon_name' is the name of the icon. It can't contain spaces, instead use underscores ('_'). Icon names starting with an underscore are considered internal and shouldn't be used.  File: speech-dispatcher.info, Node: Parameter Setting Commands in C, Next: Other Functions in C, Prev: Sound Icons in C, Up: C API 4.1.6 Parameter Settings Commands --------------------------------- The following parameter setting commands are available. For configuration and history clients there are also functions for setting the value for some other connection and for all connections. They are listed separately below. Please see *note Parameter Setting Commands: (ssip)Top. for a general description of what they mean. -- C API function: int spd_set_data_mode(SPDConnection *connection, SPDDataMode mode) Set Speech Dispatcher data mode. Currently, plain text and SSML are supported. SSML is especially useful if you want to use index marks or include changes of voice parameters in the text. 'mode' is the requested data mode: 'SPD_DATA_TEXT' or 'SPD_DATA_SSML'. -- C API function: int spd_set_language(SPDConnection* connection, char* language); Sets the language that should be used for synthesis. 'connection' is the SPDConnection* connection created by spd_open(). 'language' is the language code as defined in RFC 1766 ("cs", "en", ...). -- C API function: int spd_set_output_module(SPDConnection* connection, char* output_module); Sets the output module that should be used for synthesis. The parameter of this command should always be entered by the user in some way and not hardcoded anywhere in the code as the available synthesizers and their registration names may vary from machine to machine. 'connection' is the SPDConnection* connection created by spd_open(). 'output_module' is the output module name under which the module was loaded into Speech Dispatcher in its configuration ("flite", "festival", "epos-generic"... ) -- C API function: char* spd_get_output_module(SPDConnection* connection); Gets the current output module in use for synthesis. 'connection' is the SPDConnection* connection created by spd_open(). It returns the output module name under which the module was loaded into Speech Dispatcher in its configuration ("flite", "festival", "espeak"... ) -- C API function: int spd_set_punctuation(SPDConnection* connection, SPDPunctuation type); Set punctuation mode to the given value. 'all' means speak all punctuation characters, 'none' menas speak no punctuation characters, 'some' means speak only punctuation characters given in the server configuration or defined by the client's last spd_set_punctuation_important(). 'connection' is the SPDConnection* connection created by spd_open(). 'type' is one of the following values: 'SPD_PUNCT_ALL', 'SPD_PUNCT_NONE', 'SPD_PUNCT_SOME'. It returns 0 on success, -1 otherwise. -- C API function: int spd_set_spelling(SPDConnection* connection, SPDSpelling type); Switches spelling mode on and off. If set to on, all incoming messages from this particular connection will be processed according to appropriate spelling tables (see spd_set_spelling_table()). 'connection' is the SPDConnection* connection created by spd_open(). 'type' is one of the following values: 'SPD_SPELL_ON', 'SPD_SPELL_OFF'. -- C API function: int spd_set_voice_type(SPDConnection* connection, SPDVoiceType voice); Set a preferred symbolic voice. 'connection' is the SPDConnection* connection created by spd_open(). 'voice' is one of the following values: 'SPD_MALE1', 'SPD_MALE2', 'SPD_MALE3', 'SPD_FEMALE1', 'SPD_FEMALE2', 'SPD_FEMALE3', 'SPD_CHILD_MALE', 'SPD_CHILD_FEMALE'. -- C API function: int spd_set_synthesis_voice(SPDConnection* connection, char* voice_name); Set the speech synthesizer voice to use. Please note that synthesis voices are an attribute of the synthesizer, so this setting only takes effect until the output module in use is changed (via 'spd_set_output_module()' or via 'spd_set_language'). 'connection' is the SPDConnection* connection created by spd_open(). 'voice_name' is any of the voice name values retrieved by *Note spd_list_synthesis_voices::. -- C API function: int spd_set_voice_rate(SPDConnection* connection, int rate); Set voice speaking rate. 'connection' is the SPDConnection* connection created by spd_open(). 'rate' is a number between -100 and +100 which means the slowest and the fastest speech rate respectively. -- C API function: int spd_get_voice_rate(SPDConnection* connection); Get voice speaking rate. 'connection' is the SPDConnection* connection created by spd_open(). It returns the current voice rate. -- C API function: int spd_set_voice_pitch(SPDConnection* connection, int pitch); Set voice pitch. 'connection' is the SPDConnection* connection created by spd_open(). 'pitch' is a number between -100 and +100, which means the lowest and the highest pitch respectively. -- C API function: int spd_get_voice_pitch(SPDConnection* connection); Get voice pitch. 'connection' is the SPDConnection* connection created by spd_open(). It returns the current voice pitch. -- C API function: int spd_set_voice_pitch_range(SPDConnection* connection, int pitch_range); Set voice pitch range. 'connection' is the SPDConnection* connection created by spd_open(). 'pitch_range' is a number between -100 and +100, which means the lowest and the highest pitch range respectively. -- C API function: int spd_set_volume(SPDConnection* connection, int volume); Set the volume of the voice and sounds produced by Speech Dispatcher's output modules. 'connection' is the SPDConnection* connection created by spd_open(). 'volume' is a number between -100 and +100 which means the lowest and the loudest voice respectively. -- C API function: int spd_get_volume(SPDConnection* connection); Get the volume of the voice and sounds produced by Speech Dispatcher's output modules. 'connection' is the SPDConnection* connection created by spd_open(). It returns the current volume.  File: speech-dispatcher.info, Node: Other Functions in C, Next: Information Retrieval Commands in C, Prev: Parameter Setting Commands in C, Up: C API 4.1.7 Other Functions ---------------------  File: speech-dispatcher.info, Node: Information Retrieval Commands in C, Next: Event Notification and Index Marking in C, Prev: Other Functions in C, Up: C API 4.1.8 Information Retrieval Commands ------------------------------------ -- C API function: char** spd_list_modules(SPDConnection* connection) Returns a null-terminated array of identification names of the available output modules. You can subsequently set the desired output module with *Note spd_set_output_module::. In case of error, the return value is a NULL pointer. 'connection' is the SPDConnection* connection created by spd_open(). -- C API function: char** spd_list_voices(SPDConnection* connection) Returns a null-terminated array of identification names of the symbolic voices. You can subsequently set the desired voice with *Note spd_set_voice_type::. Please note that this is a fixed list independent of the synthesizer in use. The given voices can be mapped to specific synthesizer voices according to user wish or may, for example, all be mapped to the same voice. To choose directly from the raw list of voices as implemented in the synthesizer, *Note spd_list_synthesis_voices::. In case of error, the return value is a NULL pointer. 'connection' is the SPDConnection* connection created by spd_open(). -- C API function: char** spd_list_synthesis_voices(SPDConnection* connection) Returns a null-terminated array of identification names of 'SPDVoice*' structures describing the available voices as given by the synthesizer. You can subsequently set the desired voice with 'spd_set_synthesis_voice()'. typedef struct{ char *name; /* Name of the voice (id) */ char *language; /* 2-letter ISO language code */ char *variant; /* a not-well defined string describing dialect etc. */ }SPDVoice; Please note that the list returned is specific to each synthesizer in use (so when you switch to another output module, you must also retrieve a new list). If you want instead to use symbolic voice names which are independent of the synthesizer in use, *Note spd_list_voices::. In case of error, the return value is a NULL pointer. 'connection' is the SPDConnection* connection created by spd_open().  File: speech-dispatcher.info, Node: Event Notification and Index Marking in C, Next: History Commands in C, Prev: Information Retrieval Commands in C, Up: C API 4.1.9 Event Notification and Index Marking in C ----------------------------------------------- When the SSIP connection is run in asynchronous mode, it is possible to register callbacks for all the SSIP event notifications and index mark notifications, as defined in *note (ssip)Message Event Notification and Index Marking:: -- Variable: C API type SPDNotification 'SPDNotification' is an enum type that represents the possible base notification types that can be assigned to a message. typedef enum{ SPD_BEGIN = 1, SPD_END = 2, SPD_INDEX_MARKS = 4, SPD_CANCEL = 8, SPD_PAUSE = 16, SPD_RESUME = 32 }SPDNotification; There are currently two types of callbacks in the C API. -- Variable: C API type SPDCallback 'void (*SPDCallback)(size_t msg_id, size_t client_id, SPDNotificationType state);' This one is used for notifications about the events: 'BEGIN', 'END', 'PAUSE' and 'RESUME'. When the callback is called, it provides three parameters for the event. 'msg_id' unique identification number of the message the notification is about. 'client_id' specifies the unique identification number of the client who sent the message. This is usually the same connection as the connection which registered this callback, and therefore uninteresting. However, in some special cases it might be useful to register this callback for other SSIP connections, or register the same callback for several connections originating from the same application. 'state' is the 'SPD_Notification' type of this notification. *Note SPDNotification::. -- Variable: C API type SPDCallbackIM 'void (*SPDCallbackIM)(size_t msg_id, size_t client_id, SPDNotificationType state, char *index_mark);' 'SPDCallbackIM' is used for notifications about index marks that have been reached in the message. (A way to specify index marks is e.g. through the SSML element in ssml mode.) The syntax and meaning of these parameters are the same as for *note SPDCallback:: except for the additional parameter 'index_mark'. 'index_mark' is a NULL terminated string associated with the index mark. Please note that this string is specified by client application and therefore it needn't be unique. One or more callbacks can be supplied for a given 'SPDConnection*' connection by assigning the values of pointers to the appropriate functions to the following connection members: SPDCallback callback_begin; SPDCallback callback_end; SPDCallback callback_cancel; SPDCallback callback_pause; SPDCallback callback_resume; SPDCallbackIM callback_im; There are three settings commands which will turn notifications on and off for the current SSIP connection and cause the callbacks to be called when the event is registered by Speech Dispatcher. -- C API function: int spd_set_notification_on(SPDConnection* connection, SPDNotification notification); -- C API function: int spd_set_notification_off(SPDConnection* connection, SPDNotification notification); -- C API function: int spd_set_notification(SPDConnection* connection, SPDNotification notification, const char* state); These functions will set the notification specified by the parameter 'notification' on or off (or to the given value) respectively. Note that it is only safe to call these functions after the appropriate callback functions have been set in the 'SPDCallback' structure. Doing otherwise is not considered an error, but the application might miss some events due to callback functions not being executed (e.g. the client might receive an 'END' event without receiving the corresponding 'BEGIN' event in advance. 'connection' is the SPDConnection* connection created by spd_open(). 'notification' is the requested type of notifications that should be reported by SSIP. *Note SPDNotification::. Note that also '|' combinations are possible, as illustrated in the example below. 'state' must be either the string "on" or "off", for switching the given notification on or off. The following example shows how to use callbacks for the simple purpose of playing a message and waiting until its end. (Please note that checks of return values in this example as well as other code not directly related to index marking, have been removed for the purpose of clarity.) #include sem_t semaphore; /* Callback for Speech Dispatcher notifications */ void end_of_speech(size_t msg_id, size_t client_id, SPDNotificationType type) { /* We don't check msg_id here since we will only send one message. */ /* Callbacks are running in a separate thread, so let the (sleeping) main thread know about the event and wake it up. */ sem_post(&semaphore); } int main(int argc, char **argv) { SPDConnection *conn; sem_init(&semaphore, 0, 0); /* Open Speech Dispatcher connection in THREADED mode. */ conn = spd_open("say","main", NULL, SPD_MODE_THREADED); /* Set callback handler for 'end' and 'cancel' events. */ conn->callback_end = con->callback_cancel = end_of_speech; /* Ask Speech Dispatcher to notify us about these events. */ spd_set_notification_on(conn, SPD_END); spd_set_notification_on(conn, SPD_CANCEL); /* Say our message. */ spd_sayf(conn, SPD_MESSAGE, (char*) argv[1]); /* Wait for 'end' or 'cancel' of the sent message. By SSIP specifications, we are guaranteed to get one of these two eventually. */ sem_wait(&semaphore); return 0; }  File: speech-dispatcher.info, Node: History Commands in C, Next: Direct SSIP Communication in C, Prev: Event Notification and Index Marking in C, Up: C API 4.1.10 History Commands -----------------------  File: speech-dispatcher.info, Node: Direct SSIP Communication in C, Prev: History Commands in C, Up: C API 4.1.11 Direct SSIP Communication in C ------------------------------------- It might happen that you want to use some SSIP function that is not available through a library or you may want to use an available function in a different manner. (If you think there is something missing in a library or you have some useful comment on the available functions, please let us know.) For this purpose, there are a few functions that will allow you to send arbitrary SSIP commands on your connection and read the replies. -- C API function: int spd_execute_command(SPDConnection* connection, char *command); You can send an arbitrary SSIP command specified in the parameter 'command'. If the command is successful, the function returns a 0. If there is no such command or the command failed for some reason, it returns -1. 'connection' is the SPDConnection* connection created by spd_open(). 'command' is a null terminated string containing a full SSIP command without the terminating sequence '\r\n'. For example: spd_execute_command(fd, "SET SELF RATE 60"); spd_execute_command(fd, "SOUND_ICON bell"); It's not possible to use this function for compound commands like 'SPEAK' where you are receiving more than one reply. If this is your case, please see 'spd_send_data()'. -- C API function: char* spd_send_data(SPDConnection* connection, const char *message, int wfr); You can send an arbitrary SSIP string specified in the parameter 'message' and, if specified, wait for the reply. The string can be any SSIP command, but it can also be textual data or a command parameter. If 'wfr' (wait for reply) is set to SPD_WAIT_REPLY, you will receive the reply string as the return value. If wfr is set to SPD_NO_REPLY, the return value is a NULL pointer. If wfr is set to SPD_WAIT_REPLY, you should always free the returned string. 'connection' is the SPDConnection* connection created by spd_open(). 'message' is a null terminated string containing a full SSIP string. If this is a complete SSIP command, it must include the full terminating sequence '\r\n'. 'wfr' is either SPD_WAIT_REPLY (integer value of 1) or SPD_NO_REPLY (0). This specifies if you expect to get a reply on the sent data according to SSIP. For example, if you are sending ordinary text inside a 'SPEAK' command, you don't expect to get a reply, but you expect a reply after sending the final sequence '\r\n.\r\n'. For example (simplified by not checking and freeing the returned strings): spd_send_data(conn, "SPEAK", SPD_WAIT_REPLY); spd_send_data(conn, "Hello world!\n", SPD_NO_REPLY); spd_send_data(conn, "How are you today?!", SPD_NO_REPLY); spd_send_data(conn, "\r\n.\r\n.", SPD_WAIT_REPLY);  File: speech-dispatcher.info, Node: Python API, Next: Guile API, Prev: C API, Up: Client Programming 4.2 Python API ============== There is a full Python API available in 'src/python/speechd/' in the source tree. Please see the Python docstrings for full reference about the available objects and methods. Simple Python client: import speechd client = speechd.SSIPClient('test') client.set_output_module('festival') client.set_language('en') client.set_punctuation(speechd.PunctuationMode.SOME) client.speak("Hello World!") client.close() The Python API respects the environment variables SPEECHD_ADDRESS it the communication address is not specified explicitly (see 'SSIPClient' constructor arguments). Implementation of callbacks within the Python API tries to hide the low level details of SSIP callback handling and provide a convenient Pythonic interface. You just pass a callable object (function) to the 'speak()' method and this function will be called whenever an event occurs for the corresponding message. Callback example: import speechd, time called = [] client = speechd.SSIPClient('callback-test') client.speak("Hi!", callback=lambda cb_type: called.append(cb_type)) time.sleep(2) # Wait for the events to happen. print "Called callbacks:", called client.close() Real-world callback functions will most often need some sort of context information to be able to distinguish for which message the callback was called. This can be simply done in Python. The following example uses the actual message text as the context information within the callback function. Callback context example: import speechd, time class CallbackExample(object): def __init__(self): self._client = speechd.SSIPClient('callback-test') def speak(self, text): def callback(callback_type): if callback_type == speechd.CallbackType.BEGIN: print "Speech started:", text elif callback_type == speechd.CallbackType.END: print "Speech completed:", text elif callback_type == speechd.CallbackType.CANCEL: print "Speech interupted:", text self._client.speak(text, callback=callback, event_types=(speechd.CallbackType.BEGIN, speechd.CallbackType.CANCEL, speechd.CallbackType.END)) def go(self): self.speak("Hi!") self.speak("How are you?") time.sleep(4) # Wait for the events to happen. self._client.close() CallbackExample().go() _Important notice:_ The callback is called in Speech Dispatcher listener thread. No subsequent Speech Dispatcher interaction is allowed from within the callback invocation. If you need to do something more complicated, do it in another thread to prevent deadlocks in SSIP communication.  File: speech-dispatcher.info, Node: Guile API, Next: Common Lisp API, Prev: Python API, Up: Client Programming 4.3 Guile API ============= The Guile API can be found 'src/guile/' in the source tree, however it's still considered to be at the experimental stage. Please read 'src/guile/README'.  File: speech-dispatcher.info, Node: Common Lisp API, Next: Autospawning, Prev: Guile API, Up: Client Programming 4.4 Common Lisp API =================== The Common Lisp API can be found 'src/cl/' in the source tree, however it's still considered to be at the experimental stage. Please read 'src/cl/README'.  File: speech-dispatcher.info, Node: Autospawning, Prev: Common Lisp API, Up: Client Programming 4.5 Autospawning ================ It is suggested that client libraries offer an autospawn functionality to automatically start the server process when connecting locally and if it is not already running. E.g. if the client application starts and Speech Dispatcher is not running already, the client will start Speech Dispatcher. The library API should provide a possibility to turn this functionality off, but we suggest to set the default behavior to autospawn. Autospawn is performed by executing Speech Dispatcher with the -spawn parameter under the same user and permissions as the client process: speech-dispatcher --spawn With the '--spawn' parameter, the process will start and return with an exit code of 0 only if a) it is not already running (pidfile check) b) the server doesn't have autospawn disabled in its configuration c) no other error preventing the start occurs. Otherwise, Speech Dispatcher is not started and the error code of 1 is returned. The client library should redirect its stdout and stderr outputs either to nowhere or to its logging system. It should subsequently completely detach from the newly spawned process. Due to a bug in Speech Dispatcher, it is currently necessary to include a wait statement after the autospawn for about 0.5 seconds before attempting a connection. Please see how autospawn is implemented in the C API and in the Python API for an example.  File: speech-dispatcher.info, Node: Server Programming, Next: Download and Contact, Prev: Client Programming, Up: Top 5 Server Programming ******************** * Menu: * Server Core:: Internal structure and functionality overview. * Output Modules:: Plugins for various speech synthesizers.  File: speech-dispatcher.info, Node: Server Core, Next: Output Modules, Prev: Server Programming, Up: Server Programming 5.1 Server Core =============== The main documentation for the server core is the code itself. This section is only a general introduction intended to give you some basic information and hints where to look for things. If you are going to make some modifications in the server core, we will be happy if you get in touch with us on . The server core is composed of two main parts, each of them implemented in a separate thread. The _server part_ handles the communication with clients and, with the desired configuration options, stores the messages in the priority queue. The _speaking part_ takes care of communicating with the output modules, pulls messages out of the priority queue at the correct time and sends them to the appropriate synthesizer. Synchronization between these two parts is done by thread mutexes. Additionally, synchronization of the speaking part from both sides (server part, output modules) is done via a SYSV/IPC semaphore. Server part ----------- After switching to the daemon mode (if required), it reads configuration files and initializes the speaking part. Then it opens the socket and waits for incoming data. This is implemented mainly in 'src/server/speechd.c' and 'src/server/server.c'. There are three types of events: new client connects to speechd, old client disconnects, or a client sends some data. In the third case, the data is passed to the 'parse()' function defined in 'src/server/parse.c'. If the incoming data is a new message, it's stored in a queue according to its priority. If it is SSIP commands, it's handled by the appropriate handlers. Handling of the 'SET' family of commands can be found in 'src/server/set.c' and 'HISTORY' commands are processed in 'src/server/history.c'. All reply messages of SSIP are defined in 'src/server/msg.h'. Speaking part ------------- This thread, the function 'speak()' defined in 'src/server/speaking.c', is created from the server part process shortly after initialization. Then it enters an infinite loop and waits on a SYSV/IPC semaphore until one of the following actions happen: * The server adds a new message to the queue of messages waiting to be said. * The currently active output module signals that the message that was being spoken is done. * Pause or resume is requested. After handling the rest of the priority interaction (like actions needed to repeat the last priority progress message) it decides which action should be performed. Usually it's picking up a message from the queue and sending it to the desired output module (synthesizer), but sometimes it's handling the pause or resume requests, and sometimes it's doing nothing. As said before, this is the part of Speech Dispatcher that talks to the output modules. It does so by using the output interface defined in 'src/server/output.c'.  File: speech-dispatcher.info, Node: Output Modules, Prev: Server Core, Up: Server Programming 5.2 Output Modules ================== * Menu: * Basic Structure:: The definition of an output module. * Communication Protocol for Output Modules:: * How to Write New Output Module:: How to include support for new synthesizers * The Skeleton of an Output Module:: * Output Module Functions:: * Module Utils Functions and Macros:: * Index Marks in Output Modules::  File: speech-dispatcher.info, Node: Basic Structure, Next: Communication Protocol for Output Modules, Prev: Output Modules, Up: Output Modules 5.2.1 Basic Structure --------------------- Speech Dispatcher output modules are independent applications that, using a simple common communication protocol, read commands from standard input and then output replies on standard output, communicating the requests to the particular software or hardware synthesizer. Everything the output module writes on standard output or reads from standard input should conform to the specifications of the communication protocol. Additionally, standard error output is used for logging of the modules. Output module binaries are usually located in 'bin/speechd-modules/' and are loaded automatically when Speech Dispatcher starts, according to configuration. Their standard input/output/error output is redirected to a pipe to Speech Dispatcher and this way both sides can communicate. When the modules start, they are passed the name of a configuration file that should be used for this particular output module. Each output module is started by Speech Dispatcher as: my_module "configfile" where 'configfile' is the full path to the desired configuration file that the output module should parse.  File: speech-dispatcher.info, Node: Communication Protocol for Output Modules, Next: How to Write New Output Module, Prev: Basic Structure, Up: Output Modules 5.2.2 Communication Protocol for Output Modules ----------------------------------------------- The protocol by which the output modules communicate on standard input/output is based on *note SSIP: (ssip)Top, although it is highly simplified and a little bit modified for the different purpose here. Another difference is that event notification is obligatory in modules communication, while in SSIP, this is an optional feature. This is because Speech Dispatcher has to know all the events happening in the output modules for the purpose of synchronization of various messages. Since it's very similar to SSIP, *note General Rules: (ssip)Top, for a general description of what the protocol looks like. One of the exceptions is that since the output modules communicate on standard input/output, we use only 'LF' as the line separator. The return values are: * 2xx OK * 3xx CLIENT ERROR or BAD SYNTAX or INVALID VALUE * 4xx OUTPUT MODULE ERROR or INTERNAL ERROR * 700 EVENT INDEX MARK * 701 EVENT BEGIN * 702 EVENT END * 703 EVENT STOP * 704 EVENT PAUSE 'SPEAK' Start receiving a text message in the SSML format and synthesize it. After sending a reply to the command, output module waits for the text of the message. The text can spread over any number of lines and is finished by an end of line marker followed by the line containing the single character '.' (dot). Thus the complete character sequence closing the input text is 'LF . LF'. If any line within the sent text contains only a dot, an extra dot should be prepended before it. During reception of the text message, output module doesn't send a response to the particular lines sent. The response line is sent only immediately after the 'SPEAK' command and after receiving the closing dot line. This doesn't provide any means of synchronization, instead, event notification is used for this purpose. There is no explicit upper limit on the size of the text. If the 'SPEAK' command is received while the output module is already speaking, it is considered an error. Example: SPEAK 202 OK SEND DATA Hello, GNU! . 200 OK SPEAKING After receiving the full text (or the first part of it), the output module is supposed to start synthesizing it and take care of delivering it to an audio device. When (or just before) the first synthesized samples are delivered to the audio and start playing, the output module must send the 'BEGIN' event over the communication socket to Speech Dispatcher, *Note Events notification and index marking::. After the audio stops playing, the event 'STOP', 'PAUSE' or 'END' must be delivered to Speech Dispatcher. Additionally, if supported by the given synthesizer, the output module can issue events associated with the included SSML index marks when they are reached in the audio output. 'CHAR' Synthesize a character. If the synthesizer supports a different behavior for the event of "character", this should be used. It works like the command 'SPEAK' above, except that the argument has to be exactly one line long. It contains the UTF-8 form of exactly one character. 'KEY' Synthesize a key name. If the synthesizer supports a different behavior for the event of "key name", this should be used. It works like the command 'SPEAK' above, except that the argument has to be exactly one line long. *Note SSIP KEY: (ssip)Top, for the description of the allowed arguments. 'SOUND_ICON' Produce a sound icon. According to the configuration of the particular synthesizer, this can produce either a sound (e.g. .wav) or synthesize some text. It works like the command 'SPEAK' above, except that the argument has to be exactly one line long. It contains the symbolic name of the icon that should be said. *Note SSIP SOUND_ICON: (ssip)Top, for more detailed description of the sound icons mechanism. 'STOP' Immediately stop speaking on the output device and cancel synthesizing the current message so that the output module is prepared to receive a new message. If there is currently no message being synthesized, it is not considered an error to call 'STOP' anyway. This command is asynchronous. The output module is not supposed to send any reply (not even error reply). It should return immediately, although stopping the synthesizer may require a little bit more time. The module must issue one of the events 'STOPPED' or 'END' when the module is finally stopped. 'END' is issued when the playing stopped by itself before the module could terminate it or if the architecture of the output module doesn't allow it to decide, otherwise 'STOPPED' should be used. STOP 'PAUSE' Stop speaking the current message at a place where we can exactly determine the position (preferably after a '__spd_' index mark). This doesn't have to be immediate and can be delayed even for a few seconds. (Knowing the position exactly is important so that we can later continue the message without gaps or overlapping.) It doesn't do anything else (like storing the message etc.). This command is asynchronous. The output module is not supposed to send any reply (not even error reply). For example: PAUSE 'SET' Set one of several speech parameters for the future messages. Each of the parameters is written on a single line in the form name=value where 'value' can be either a number or a string, depending upon the name of the parameter. The 'SET' environment is terminated by a dot on a single line. Thus the complete character sequence closing the input text is 'LF . LF' During reception of the settings, output module doesn't send any response to the particular lines sent. The response line is sent only immediately after the 'SET' command and after receiving the closing dot line. The available parameters that accept numerical values are 'rate', 'pitch' and 'pitch_range'. The available parameters that accept string values are 'punctuation_mode', 'spelling_mode', 'cap_let_recogn', 'voice', and 'language'. The arguments are the same as for the corresponding SSIP commands, except that they are written with small letters. *Note Parameter Setting Commands: (ssip)Top. The conversion between these string values and the corresponding C enum variables can be easily done using 'src/common/fdsetconv.c'. Not all of these parameters must be set and the value of the string arguments can also be 'NULL'. If some of the parameters aren't set, the output module should use its default. It's not necessary to set these parameters on the synthesizer right away, instead, it can be postponed until some message to be spoken arrives. Here is an example: SET 203 OK RECEIVING SETTINGS rate=20 pitch=-10 pitch_range=50 punctuation_mode=all spelling_mode=on punctuation_some=NULL . 203 OK SETTINGS RECEIVED 'AUDIO' Audio has exactly the same structure as 'SET', but is transmitted only once immediatelly after 'INIT' to transmit the requested audio parameters and tell the output module to open the audio device. 'QUIT' Terminates the output module. It should send the response, deallocate all the resources, close all descriptors, terminate all child processes etc. Then the output module should exit itself. QUIT 210 OK QUIT 5.2.2.1 Events notification and index marking ............................................. Each output module must take care of sending asynchronous notifications whenever the synthesizer (or the module) starts or stops output audio on the speakers. Additionally, whenever possible, the output module should report back to Speech Dispatcher index marks found in the incoming SSML text whenever they are reached while speaking. See SSML specifications for more details about the 'mark' element Event and index mark notifications are reported by simply writing them to the standard output. An event notification must never get in between synchronous commands (those which require a reply) and their reply. Before Speech Dispatcher sends any new requests (like 'SET', 'SPEAK' etc.) it waits for the previous request to be terminated by the output module by signalling 'STOP', 'END' or 'PAUSE' index marks. So the only thing the output module must ensure in order to satisfy this requirement is that it doesn't send any index marks until it acknowledges the receival of the new message via '200 OK SPEAKING'. It must also ensure that index marks written to the pipe are well ordered - of course it doesn't make any sense and it is an error to send any index marks after 'STOP', 'END' or 'PAUSE' is sent. 'BEGIN' This event must be issued whenever the module starts to speak the given message. If this is not possible, it can issue it when it starts to synthesize the message or when it receives the message. It is prepended by the code '701' and takes the form 701 BEGIN 'END' This event must be issued whenever the module terminates speaking the given message because it reached its end. If this is not possible, it can issue this event when it is ready to receive a new message after speaking the previous message. Each 'END' must always be preceeded (possibly not directly) by a 'BEGIN'. It is prepended by the code '702' and takes the form 702 END 'STOP' This event should be issued whenever the module terminates speaking the given message without reaching its end (as a consequence of receiving the STOP command or because of some error) not because of a 'PAUSE' command. When the synthesizer in use doesn't allow the module to decide, the event 'END' can be used instead. Each 'STOP' must always be preceeded (possibly not directly) by a 'BEGIN'. It is prepended by the code '703' and takes the form 703 STOP 'PAUSE' This event should be issued whenever the module terminates speaking the given message without reaching its end because of receiving the 'PAUSE' command. Each 'PAUSE' must always be preceeded (possibly not directly) by a 'BEGIN'. It is prepended by the code '704' and takes the form 704 PAUSE 'INDEX MARK' This event should be issued by the output module (if supported) whenever an index mark (SSML tag '') is passed while speaking a message. It is preceeded by the code '700' and takes the form 700-name 700 INDEX MARK where 'name' is the value of the SSML attribute 'name' in the tag ''.  File: speech-dispatcher.info, Node: How to Write New Output Module, Next: The Skeleton of an Output Module, Prev: Communication Protocol for Output Modules, Up: Output Modules 5.2.3 How to Write New Output Module ------------------------------------ If you want to write your own output module, there are basically two ways to do it. Either you can program it all yourself, which is fine as long as you stick to the definition of an output module and its communication protocol, or you can use our 'module_*.c' tools. If you use these tools, you will only have to write the core functions like module_speak() and module_stop etc. and you will not have to worry about the communication protocol and other formal things that are common for all modules. Here is how you can do it using the provided tools. We will recommend here a basic structure of the code for an output module you should follow, although it's perfectly ok to establish your own if you have reasons to do so, if all the necessary functions and data are defined somewhere in the file. For this purpose, we will use examples from the output module for Flite (Festival Lite), so it's recommended to keep looking at 'flite.c' for reference. A few rules you should respect: * The 'module_*.c' files should be included at the specified place and in the specified order, because they include directly some pieces of the code and won't work in other places. * If one or more new threads are used in the output module, they must block all signals. * On module_close(), all lateral threads and processes should be terminated, all memory freed. Don't assume module_close() is always called before exit() and the sources will be freed automatically. * We will be happy if all the copyrights are assigned to Brailcom, o.p.s. in order for us to be in a better legal position against possible intruders.  File: speech-dispatcher.info, Node: The Skeleton of an Output Module, Next: Output Module Functions, Prev: How to Write New Output Module, Up: Output Modules 5.2.4 The Skeleton of an Output Module -------------------------------------- Each output module should include 'module_utils.h' where the SPDMsgSettings structure is defined to be able to handle the different speech synthesis settings. This file also provides tools which help with writing output modules and making the code simpler. #include "module_utils.h" If your plugin needs the audio tools (if you take care of the output to the soundcard instead of the synthesizer), you also have to include 'spd_audio.h' #include "spd_audio.h" The definition of macros 'MODULE_NAME' and 'MODULE_VERSION' should follow: #define MODULE_NAME "flite" #define MODULE_VERSION "0.1" If you want to use the 'DBG(message)' macro from 'module_utils.c' to print out debugging messages, you should insert these two lines. (Please don't use printf for debugging, this doesn't work with multiple processes!) (You will later have to actually start debugging in 'module_init()') DECLARE_DEBUG(); You don't have to define the prototypes of the core functions like module_speak() and module_stop(), these are already defined in 'module_utils.h' Optionally, if your output module requires some special configuration, apart from defining voices and configuring debugging (they are handled differently, see below), you can declare the requested option here. It will expand into a dotconf callback and declaration of the variable. (You will later have to actually register these options for Speech Dispatcher in 'module_load()') There are currently 4 types of possible configuration options: * 'MOD_OPTION_1_INT(name); /* Set up `int name' */' * 'MOD_OPTION_1_STR(name); /* Set up `char* name' */' * 'MOD_OPTION_2(name); /* Set up `char *name[2]' */' * 'MOD_OPTION_{2,3}_HT(name); /* Set up a hash table */' *Note Output Modules Configuration::. For example Flite uses 2 options: MOD_OPTION_1_INT(FliteMaxChunkLength); MOD_OPTION_1_STR(FliteDelimiters); Every output module is started in 2 phases: _loading_ and _initialization_. The goal of loading is to initialize empty structures for storing settings and declare the DotConf callbacks for parsing configuration files. In the second phase, initialization, all the configuration has been read and the output module can accomplish the rest (check if the synthesizer works, set up threads etc.). You should start with the definition of 'module_load()'. int module_load(void) { Then you should initialize the settings tables. These are defined in 'module_utils.h' and will be used to store the settings received by the 'SET' command. INIT_SETTINGS_TABLES(); Also, define the configuration callbacks for debugging if you use the 'DBG()' macro. REGISTER_DEBUG(); Now you can finally register the options for the configuration file parsing. Just use these macros: * MOD_OPTION_1_INT_REG(name, default); /* for integer parameters */ * MOD_OPTION_1_STR_REG(name, default); /* for string parameters */ * MOD_OPTION_MORE_REG(name); /* for an array of strings */ * MOD_OPTION_HT_REG(name); /* for hash tables */ Again, an example from Flite: MOD_OPTION_1_INT_REG(FliteMaxChunkLength, 300); MOD_OPTION_1_STR_REG(FliteDelimiters, "."); If you want to enable the mechanism for setting voices through AddVoice, use this function (for an example see 'generic.c'): Example from Festival: module_register_settings_voices(); *Note Output Modules Configuration::. If everything went correctly, the function should return 0, otherwise -1. return 0; } The second phase of starting an output module is handled by: int module_init(void) { If you use the DBG() macro, you should init debugging on the start of this function. From that moment on, you can use DBG(). Apart from that, the body of this function is entirely up to you. You should do all the necessary initialization of the particular synthesizer. All declared configuration variables and configuration hash tables, together with the definition of voices, are filled with their values (either default or read from configuration), so you can use them already. INIT_DEBUG(); DBG("FliteMaxChunkLength = %d\n", FliteMaxChunkLength); DBG("FliteDelimiters = %s\n", FliteDelimiters); This function should return 0 if the module was initialized successfully, or -1 if some failure was encountered. In this case, you should clean up everything, cancel threads, deallocate memory etc.; no more functions of this output module will be touched (except for other tries to load and initialize the module). Example from Flite: /* Init flite and register a new voice */ flite_init(); flite_voice = register_cmu_us_kal(); if (flite_voice == NULL){ DBG("Couldn't register the basic kal voice.\n"); return -1; } [...] The third part is opening the audio. This is commanded by the 'AUDIO' protocol command. If the synthesizer is able to retrieve audio data, it is desirable to open the 'spd_audio' output according to the requested parameters and then use this method for audio output. Audio initialization can be done as follows: int module_audio_init(char **status_info){ DBG("Opening audio"); return module_audio_init_spd(status_info); } If it is impossible to retrieve audio from the synthesizer and the synthesizer itself is used for playback, than the module must still contain this function, but it should just return 0 and do nothing. Now you have to define all the synthesis control functions 'module_speak', 'module_stop' etc. See *note Output Module Functions::. At the end, this simple include provides the main() function and all the functionality related to being an output module of Speech Dispatcher (parsing argv[] parameters, communicating on stdin/stdout, ...). It's recommended to study this file carefully and try to understand what exactly it does, as it will be part of the source code of your output module. #include "module_main.c" If it doesn't work, it's most likely not your fault. Complain! This manual is not complete and the instructions in this sections aren't either. Get in touch with us and together we can figure out what's wrong, fix it and then warn others in this manual.  File: speech-dispatcher.info, Node: Output Module Functions, Next: Module Utils Functions and Macros, Prev: The Skeleton of an Output Module, Up: Output Modules 5.2.5 Output Module Functions ----------------------------- -- Output Module Functions: int module_speak (char *data, size_t bytes, EMessageType msgtype) This is the function where the actual speech output is produced. It is called every time Speech Dispatcher decides to send a message to synthesis. The data of length BYTES are passed in a NULL terminated string DATA. The argument MSGTYPE defines what type of message it is (different types should be handled differently, if the synthesizer supports it). Each output module should take care of setting the output device to the parameters from msg_settings (defined in module_utils.h) (See SPDMsgSettings in 'module_utils.h'). However, it is not an error if some of these values are ignored. At least rate, pitch and language should be set correctly. Speed and pitch are values between -100 and 100 included. 0 is the default value that represents normal speech flow. So -100 is the slowest (or lowest) and +100 is the fastest (or highest) speech. The language parameter is given as a null-terminated string containing the name of the language according to RFC 1766 (en, cs, fr, ...). If the requested language is not supported by this synthesizer, it's ok to abort and return 0, because that's an error in user settings. An easy way to set the parameters is using the UPDATE_PARAMETER() and UPDATE_STRING_PARAMETER() macros. *Note Module Utils Functions and Macros::. Example from festival: UPDATE_STRING_PARAMETER(language, festival_set_language); UPDATE_PARAMETER(voice, festival_set_voice); UPDATE_PARAMETER(rate, festival_set_rate); UPDATE_PARAMETER(pitch, festival_set_pitch); UPDATE_PARAMETER(punctuation_mode, festival_set_punctuation_mode); UPDATE_PARAMETER(cap_let_recogn, festival_set_cap_let_recogn); This function should return 0 if it fails and 1 if the delivery to the synthesizer is successful. It should return immediately, because otherwise, it would block stopping, priority handling and other important things in Speech Dispatcher. If there is a need to stay longer, you should create a separate thread or process. This is for example the case of some software synthesizers which use a blocking function (eg. spd_audio_play) or hardware devices that have to send data to output modules at some particular speed. Note that if you use threads for this purpose, you have to set them to ignore all signals. The simplest way to do this is to call 'set_speaking_thread_parameters()' which is defined in module_utils.c. Call it at the beginning of the thread code. -- Output module function: int module_stop (void) This function should stop the synthesis of the currently spoken message immediately and throw away the rest of the message. This function should return immediately. Speech Dispatcher will not send another command until module_report_event_stop() is called. Note that you cannot call module_report_event_stop() from within the call to module_stop(). The best thing to do is emit the stop event from another thread. It should return 0 on success, -1 otherwise. -- Output module function: size_t module_pause (void) This function should stop speaking on the synthesizer (or sending data to soundcard) just after sending an '__spd_' index mark so that Speech Dispatcher knows the position of stop. The pause can wait for a short time until an index mark is reached. However, if it's not possible to determine the exact position, this function should have the same effect as 'module_stop'. This function should return immediately. Speech Dispatcher will not send another command until module_report_event_pause() is called. Note that you cannot call module_report_event_pause() from within the call to module_pause(). The best thing to do is emit the pause event from another thread. For some software synthesizers, the desired effect can be archieved in this way: When 'module_speak()' is called, you execute a separate process and pass it the requested message. This process cuts the message into sentences and then runs in a loop and sends the pieces to synthesis. If a signal arrives from 'module_pause()', you set a flag and stop the loop at the point where next piece of text would be synthesized. It's not an error if this function is called when the device is not speaking. In this case, it should return 0. Note there is no module_resume() function. The semantics of 'module_pause()' is the same as 'module_stop()' except that your module should stop after reaching a '__spd_' index mark. Just like 'module_stop()', it should discard the rest of the message after pausing. On the next 'module_speak()' call, Speech Dispatcher will resend the rest of the message after the index mark.  File: speech-dispatcher.info, Node: Module Utils Functions and Macros, Next: Index Marks in Output Modules, Prev: Output Module Functions, Up: Output Modules 5.2.6 Module Utils Functions and Macros --------------------------------------- This section describes the various variables, functions and macros that are available in the 'module_utils.h' file. They are intended to make writing new output modules easier and allow the programmer to reuse existing pieces of code instead of writing everything from scratch. * Menu: * Initialization Macros and Functions:: * Generic Macros and Functions:: * Functions used by module_main.c:: * Functions for use when talking to synthesizer:: * Multi-process output modules:: * Memory Handling Functions::  File: speech-dispatcher.info, Node: Initialization Macros and Functions, Next: Generic Macros and Functions, Prev: Module Utils Functions and Macros, Up: Module Utils Functions and Macros 5.2.6.1 Initialization Macros and Functions ........................................... -- Module Utils macro: INIT_SETTINGS_TABLES () This macro initializes the settings tables where the parameters received with the 'SET' command are stored. You must call this macro if you want to use the 'UPDATE_PARAMETER()' and 'UPDATE_STRING_PARAMETER()' macros. It is intended to be called from inside a function just after the output module starts. 5.2.6.2 Debugging Macros ........................ -- Module Utils macro: DBG (format, ...) DBG() outputs a debugging message, if the 'Debug' option in module's configuration is set, to the file specified in configuration ad 'DebugFile'. The parameter syntax is the same as for the printf() function. In fact, it calls printf() internally. -- Module Utils macro: FATAL (text) Outputs a message specified as 'text' and calls exit() with the value EXIT_FAILURE. This terminates the whole output module without trying to kill the child processes or freeing other resources other than those that will be freed by the system. It is intended to be used after some severe error has occurred.  File: speech-dispatcher.info, Node: Generic Macros and Functions, Next: Functions used by module_main.c, Prev: Initialization Macros and Functions, Up: Module Utils Functions and Macros 5.2.6.3 Generic Macros and Functions .................................... -- Module Utils macro: UPDATE_PARAMETER (param, setter) Tests if the integer or enum parameter specified in 'param' (e.g. rate, pitch, cap_let_recogn, ...) changed since the last time when the 'setter' function was called. If it changed, it calls the function 'setter' with the new value. (The new value is stored in the msg_settings structure that is created by module_utils.h, which you normally don't have to care about.) The function 'setter' should be defined as: void setter_name(type value); Please look at the 'SET' command in the communication protocol for the list of all available parameters. *note Communication Protocol for Output Modules::. An example from Festival output module: static void festival_set_rate(signed int rate) { assert(rate >= -100 && rate <= +100); festivalSetRate(festival_info, rate); } [...] int module_speak(char *data, size_t bytes, EMessageType msgtype) { [...] UPDATE_PARAMETER(rate, festival_set_rate); UPDATE_PARAMETER(pitch, festival_set_pitch); [...] } -- Module Utils macro: UPDATE_STRING_PARAMETER (param, setter) The same as 'UPDATE_PARAMETER' except that it works for parameters with a string value.  File: speech-dispatcher.info, Node: Functions used by module_main.c, Next: Functions for use when talking to synthesizer, Prev: Generic Macros and Functions, Up: Module Utils Functions and Macros 5.2.6.4 Functions used by 'module_main.c' ......................................... -- Module Utils function: char* do_speak(void) Takes care of communication after the 'SPEAK' command was received. Calls 'module_speak()' when the full text is received. It returns a response according to the communication protocol. -- Module Utils function: char* do_stop(void) Calls the 'module_stop()' function of the particular output module. It returns a response according to the communication protocol. -- Module Utils function: char* do_pause(void) Calls the 'module_pause()' function of the particular output module. It returns a response according to the communication protocol and the value returned by 'module_pause()'. -- Module Utils function: char* do_set() Takes care of communication after the 'SET' command was received. Doesn't call any particular function of the output module, only sets the values in the settings tables. (You should then call the 'UPDATE_PARAMETER()' macro in module_speak() to actually set the synthesizer to these values.) It returns a response according to the communication protocol. -- Module Utils function: char* do_speaking() Calls the 'module_speaking()' function. It returns a response according to the communication protocol and the value returned by 'module_speaking()'. -- Module Utils function: void do_quit() Prints the farewell message to the standard output, according to the protocol. Then it calls 'module_close()'.  File: speech-dispatcher.info, Node: Functions for use when talking to synthesizer, Next: Multi-process output modules, Prev: Functions used by module_main.c, Up: Module Utils Functions and Macros 5.2.6.5 Functions for use when talking to synthesizer ..................................................... -- Module Utils function: static int module_get_message_part ( const char* message, char* part, unsigned int *pos, size_t maxlen, const char* dividers) Gets a part of the 'message' according to the specified 'dividers'. It scans the text in 'message' from the byte specified by '*pos' and looks for one of the characters specified in 'dividers' followed by a whitespace character or the terminating NULL byte. If one of them is encountered, the read text is stored in 'part' and the number of bytes read is returned. If end of 'message' is reached, the return value is -1. 'message' is the text to process. It must be a NULL-terminated uni-byte string. 'part' is a pointer to the place where the output text should be stored. It must contain at least 'maxlen' bytes of space. 'maxlen' is the maximum number of bytes that should be written to 'part'. 'dividers' is a NULL-terminated uni-byte string containing the punctuation characters where the message should be divided into smaller parts (if they are followed by whitespace). After returning, 'pos' is the position where the function terminated in processing 'message'. -- Output module function: void module_report_index_mark(char *mark) -- Output module function: void module_report_event_*() The 'module_report_' functions serve for reporting event notifications and index marking events. You should use them whenever you get an event from the synthesizer which is defined in the output module communication protocol. Note that you cannot call these functions from within a call to module_speak(), module_stop(), or module_pause(). The best way to do this is to emit the events from another thread. -- Output module function: int module_close(void) This function is called when Speech Dispatcher terminates. The output module should terminate all threads and processes, free all resources, close all sockets etc. Never assume this function is called only when Speech Dispatcher terminates and exit(0) will do the work for you. It's perfectly ok for Speech Dispatcher to load, unload or reload output modules in the middle of its run.  File: speech-dispatcher.info, Node: Multi-process output modules, Next: Memory Handling Functions, Prev: Functions for use when talking to synthesizer, Up: Module Utils Functions and Macros 5.2.6.6 Multi-process output modules .................................... -- Module Utils function: size_t module_parent_wfork ( TModuleDoublePipe dpipe, const char* message, SPDMessageType msgtype, const size_t maxlen, const char* dividers, int *pause_requested) It simply sends the data to the child in smaller pieces and waits for confirmation with a single 'C' character on the pipe from child to parent. 'dpipe' is a parameter which contains the information necessary for communicating through pipes between the parent and the child and vice-versa. typedef struct{ int pc[2]; /* Parent to child pipe */ int cp[2]; /* Child to parent pipe */ }TModuleDoublePipe; 'message' is a pointer to a NULL-terminated string containing the message for synthesis. 'msgtype' is the type of the message for synthesis. 'maxlen' is the maximum number of bytes that should be transfered over the pipe. 'dividers' is a NULL-terminated string containing the punctuation characters at which this function should divide the message into smaller pieces. 'pause_requested' is a pointer to an integer flag, which is either 0 if no pause request is pending, or 1 if the function should terminate at a convenient place in the message because a pause is requested. In the beginning, it initializes the pipes and then it enters a simple cycle: 1. Reads a part of the message or an index mark using 'module_get_message_part()'. 2. Looks if there isn't a pending request for pause and handles it. 3. Sends the current part of the message to the child using 'module_parent_dp_write()'. 4. Waits until a single character 'C' comes from the other pipe using 'module_parent_dp_read()'. 5. Repeats the cycle or terminates, if there is no more data. -- Module Utils function: int module_parent_wait_continue(TModuleDoublePipe dpipe) Waits until the character 'C' (continue) is read from the pipe from child. This function is intended to be run from the parent. 'dpipe' is the double pipe used for communication between the child and parent. Returns 0 if the character was read or 1 if the pipe was broken before the character could be read. -- Module Utils function: void module_parent_dp_init (TModuleDoublePipe dpipe) Initializes pipes (dpipe) in the parent. Currently it only closes the unnecessary ends. -- Module Utils function: void module_child_dp_close (TModuleDoublePipe dpipe) Initializes pipes (dpipe) in the child. Currently it only closes the unnecessary ends. -- Module Utils function: void module_child_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes) Writes the specified number of 'bytes' from 'msg' to the pipe to the parent. This function is intended, as the prefix says, to be run from the child. Uses the pipes defined in 'dpipe'. -- Module Utils function: void module_parent_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes) Writes the specified number of 'bytes' from 'msg' into the pipe to the child. This function is intended, as the prefix says, to be run from the parent. Uses the pipes defined in 'dpipe'. -- Module Utils function: int module_child_dp_read(TModuleDoublePipe dpipe char *msg, size_t maxlen) Reads up to 'maxlen' bytes from the pipe from parent into the buffer 'msg'. This function is intended, as the prefix says, to be run from the child. Uses the pipes defined in 'dpipe'. -- Module Utils function: int module_parent_dp_read(TModuleDoublePipe dpipe, char *msg, size_t maxlen) Reads up to 'maxlen' bytes from the pipe from child into the buffer 'msg'. This function is intended, as the prefix says, to be run from the parent. Uses the pipes defined in 'dpipe'. -- Module Utils function: void module_sigblockall(void) Blocks all signals. This is intended to be run from the child processes and threads so that their signal handling won't interfere with the parent. -- Module Utils function: void module_sigunblockusr(sigset_t *some_signals) Use the set 'some_signals' to unblock SIGUSR1. -- Module Utils function: void module_sigblockusr(sigset_t *some_signals) Use the set 'some_signals' to block SIGUSR1.  File: speech-dispatcher.info, Node: Memory Handling Functions, Prev: Multi-process output modules, Up: Module Utils Functions and Macros 5.2.6.7 Memory Handling Functions ................................. -- Module Utils function: static void* xmalloc (size_t size) The same as the classical 'malloc()' except that it executes 'FATAL(``Not enough memory'')' on error. -- Module Utils function: static void* xrealloc (void *data, size_t size) The same as the classical 'realloc()' except that it also accepts 'NULL' as 'data'. In this case, it behaves as 'xmalloc'. -- Module Utils function: void xfree(void *data) The same as the classical 'free()' except that it checks if data isn't NULL before calling 'free()'.  File: speech-dispatcher.info, Node: Index Marks in Output Modules, Prev: Module Utils Functions and Macros, Up: Output Modules 5.2.7 Index Marks in Output Modules ----------------------------------- Output modules need to provide some kind of synchronization and they have to give Speech Dispatcher back some information about what part of the message is currently being said. On the other hand, output modules are not able to tell the exact position in the text because various conversions and message processing take place (sometimes punctuation and spelling substitution, the message needs to be recoded from multibyte to unibyte coding etc.) before the text reaches the synthesizer. For this reason, Speech Dispatcher places so-called index marks in the text it sends to its output modules. They have the form: 'id' is the identifier associated with each index mark. Within a 'module_speak()' message, each identifer is unique. It consists of the string '__spd_' and a counter number. Numbers begin from zero for each message. For example, the fourth index mark within a message looks like When an index mark is reached, its identifier should be stored so that the output module is able to tell Speech Dispatcher the identifier of the last index mark. Also, index marks are the best place to stop when the module is requested to pause (although it's ok to stop at some place close by and report the last index mark). Notice that index marks are in SSML format using the 'mark' tag.  File: speech-dispatcher.info, Node: Download and Contact, Next: Reporting Bugs, Prev: Server Programming, Up: Top 6 Download ********** You can download Speech Dispatcher's latest release source code from . There is also information on how to set up anonymous access to our git repository. However, you may prefer to download Speech Dispatcher in a binary package for your system. We don't distribute such packages ourselves. If you run Debian GNU/Linux, it should be in the central repository under the name 'speech-dispatcher' or 'speechd'. If you run an rpm-based distribution like RedHat, Mandrake or SuSE Linux, please try to look at . If you want to contact us, please look at or use the email .  File: speech-dispatcher.info, Node: Reporting Bugs, Next: How You Can Help, Prev: Download and Contact, Up: Top 7 Reporting Bugs **************** If you believe you found a bug in Speech Dispatcher, we will be very grateful if you let us know about it. Please do it by email on the address , but please don't send us messages larger than half a megabyte unless we ask you. To report a bug in a way that is useful for the developers is not as easy as it may seem. Here are some hints that you should follow in order to give us the best information so that we can find and fix the bug easily. First of all, please try to describe the problem as exactly as you can. We prefer raw data over speculations about where the problem may lie. Please try to explain in what situation the bug happens. Even if it's a general bug that happens in many situations, please try to describe at least one case in as much detail, as possible. Also, please specify the versions of programs that you use when the bug happens. This is not only Speech Dispatcher, but also the client application you use (speechd-el, say, etc.) and the synthesizer name and version. If you can reproduce the bug, please send us the log file also. This is very useful, because otherwise, we may not be able to reproduce the bug with our configuration and program versions that differ from yours. Configuration must be set to logging priority at least 4, but best 5, so that it's useful for debugging purposes. You can do so in 'etc/speech-dispatcher/speechd.conf' by modifying the variable 'LogLevel'. Also, you may want to modify the log destination with variable 'LogFile'. After modifying these options, please restart Speech Dispatcher and repeat the situation in which the bug happens. After it happened, please take the log and attach it to the bug report, preferably compressed using 'gzip'. But note, that when logging with level 5, all the data that come from Speech Dispatcher is also recorded, so make sure there is no sensitive information when you are reproducing the bug. Please make sure you switch back to priority 3 or lower logging, because priority 4 or 5 produces really huge logs. If you are a programmer and you find a bug that is reproducible in SSIP, you can send us the sequence of SSIP commands that lead to the bug (preferably from starting the connection). You can also try to reproduce the bug in a simple test-script under 'speech-dispatcher/src/tests' in the source tree. Please check 'speech-dispatcher/src/tests/README' and see the other tests scripts there for an example. When the bug is a SEGMENTATION FAULT, a backtrace from gdb is also valuable, but if you are not familiar with gdb, don't bother with that, we may ask you to do it later. Finally, you may also send us a guess of what you think happens in Speech Dispatcher that causes the bug, but this is usually not very helpful. If you are able to provide additional technical information instead, please do so.  File: speech-dispatcher.info, Node: How You Can Help, Next: Appendices, Prev: Reporting Bugs, Up: Top 8 How You Can Help ****************** If you want to contribute to the development of Speech Dispatcher, we will be very happy if you do so. Please contact us on . Here is a short, definitively not exhaustive, list of how you can help us and other users. * _Donate money:_ We are a non-profit organization and we can't work without funding. Brailcom, o.p.s. created Speech Dispatcher, speechd-el and also works on other projects to help blind and visually impaired users of computers. We build on Free Software and GNU/Linux, because we believe this is the right way. But it won't be possible when we have no money. * _Report bugs:_ Every user, even if he can't give us money and he is not a programmer, can help us very much by just using our software and telling us about the bugs and inconveniences he encounters. A good user community that reports bugs is a crucial part of development of a good Free Software package. We can't test our software under all circumstances and on all platforms, so each constructive bug report is highly appreciated. You can report bugs in Speech Dispatcher on . * _Write or modify an application to support synthesis:_ With Speech Dispatcher, we have provided an interface that allows applications easy access to speech synthesis. However powerful, it's no more than an interface, and it's useless on its own. Now it's time to write the particular client applications, or modify existing applications so that they can support speech synthesis. It is useful if the application needs a specific interface for blind people or if it wants to use speech synthesis for educational or other purposes. * _Develop new voices and language definitions for Festival:_ In the world of Free Software, currently Festival is the most promising interface for Text-to-Speech processing and speech synthesis. It's an extensible and highly configurable platform for developing synthetic voices. If there is a lack of synthetic voices or no voices at all for some language, we believe the wisest solution is to try to develop a voice in Festival. It's certainly not advisable to develop your own synthesizer if the goal is producing a quality voice system in a reasonable time. Festival developers provide nice documentation about how to develop a voice and a lot of tools that help doing this. We found that some language definitions can be constructed by canibalizing the already existing definitions and can be tuned later. As for the voice samples, one can temporarily use the MBROLA project voices. But please note that, although they are downloadable for free (as price), they are not Free Software and it would be wonderful if we could replace them by Free Software alternatives as soon as possible. See . * _Help us with this or other Free-b-Soft projects:_ Please look at to find information about our projects. There is a plenty of work to be done for the blind and visually impaired people to make their work with computers easier. * _Spread the word about Speech Dispatcher and Free Software:_ You can help us, and the whole community around Free Software, just by telling your friends about the amazing world of Free Software. It doesn't have to be just about Speech Dispatcher; you can tell them about other projects or about Free Software in general. Remember that Speech Dispatcher could only arise out of understanding of some people of the principles and ideas behind Free Software. And this is mostly the same for the rest of the Free Software world. See for more information about GNU/Linux and Free Software.  File: speech-dispatcher.info, Node: Appendices, Next: GNU General Public License, Prev: How You Can Help, Up: Top Appendix A Appendices *********************  File: speech-dispatcher.info, Node: GNU General Public License, Next: GNU Free Documentation License, Prev: Appendices, Up: Top Appendix B GNU General Public License ************************************* Version 2, June 1991 Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble ======== The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 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 this service 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. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION =============================================================== 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS Appendix: 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. Copyright (C) YYYY NAME OF AUTHOR This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) YEAR NAME OF AUTHOR Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than 'show w' and 'show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. SIGNATURE OF TY COON, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.  File: speech-dispatcher.info, Node: GNU Free Documentation License, Next: Index of Concepts, Prev: GNU General Public License, Up: Top Appendix C GNU Free Documentation License ***************************************** Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See . Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. C.1 ADDENDUM: How to use this License for your documents ======================================================== To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (C) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.  File: speech-dispatcher.info, Node: Index of Concepts, Prev: GNU Free Documentation License, Up: Top Index of Concepts ***************** [index] * Menu: * AddVoice: Configuration of the Generic Output Module. (line 49) * Basic ideas, Motivation: Motivation. (line 6) * C API type: Speech Synthesis Commands in C. (line 6) * C API type <1>: Event Notification and Index Marking in C. (line 11) * C API type <2>: Event Notification and Index Marking in C. (line 27) * C API type <3>: Event Notification and Index Marking in C. (line 49) * char*: Parameter Setting Commands in C. (line 51) * char* <1>: Direct SSIP Communication in C. (line 38) * char* <2>: Functions used by module_main.c. (line 6) * char* <3>: Functions used by module_main.c. (line 12) * char* <4>: Functions used by module_main.c. (line 17) * char* <5>: Functions used by module_main.c. (line 24) * char* <6>: Functions used by module_main.c. (line 33) * char**: Information Retrieval Commands in C. (line 6) * char** <1>: Information Retrieval Commands in C. (line 16) * char** <2>: Information Retrieval Commands in C. (line 34) * configuration: Configuration. (line 6) * DBG: Initialization Macros and Functions. (line 18) * DBG <1>: Initialization Macros and Functions. (line 19) * default values: Configuration. (line 6) * Design: Basic Design. (line 6) * different synthesizers: Synthesis Output Modules. (line 6) * do_pause: Functions used by module_main.c. (line 18) * do_quit: Functions used by module_main.c. (line 40) * do_set: Functions used by module_main.c. (line 25) * do_speak: Functions used by module_main.c. (line 7) * do_speaking: Functions used by module_main.c. (line 34) * do_stop: Functions used by module_main.c. (line 13) * FATAL: Initialization Macros and Functions. (line 24) * FATAL <1>: Initialization Macros and Functions. (line 25) * FDL, GNU Free Documentation License: GNU Free Documentation License. (line 7) * GenericExecuteSynth: Configuration of the Generic Output Module. (line 14) * GenericLanguage: Configuration of the Generic Output Module. (line 53) * GenericPitchAdd: Configuration of the Generic Output Module. (line 66) * GenericPitchMultiply: Configuration of the Generic Output Module. (line 67) * GenericPitchRangeAdd: Configuration of the Generic Output Module. (line 68) * GenericPitchRangeMultiply: Configuration of the Generic Output Module. (line 69) * GenericRateAdd: Configuration of the Generic Output Module. (line 64) * GenericRateMultiply: Configuration of the Generic Output Module. (line 65) * GPL, GNU General Public License: GNU General Public License. (line 7) * INIT_SETTINGS_TABLES: Initialization Macros and Functions. (line 6) * INIT_SETTINGS_TABLES <1>: Initialization Macros and Functions. (line 7) * int: Speech Synthesis Commands in C. (line 21) * int <1>: Speech Synthesis Commands in C. (line 47) * int <2>: Speech output control commands in C. (line 9) * int <3>: Speech output control commands in C. (line 23) * int <4>: Speech output control commands in C. (line 30) * int <5>: Speech output control commands in C. (line 46) * int <6>: Speech output control commands in C. (line 53) * int <7>: Speech output control commands in C. (line 60) * int <8>: Speech output control commands in C. (line 76) * int <9>: Speech output control commands in C. (line 96) * int <10>: Speech output control commands in C. (line 103) * int <11>: Speech output control commands in C. (line 119) * int <12>: Speech output control commands in C. (line 131) * int <13>: Speech output control commands in C. (line 138) * int <14>: Characters and Keys in C. (line 6) * int <15>: Characters and Keys in C. (line 24) * int <16>: Characters and Keys in C. (line 32) * int <17>: Sound Icons in C. (line 6) * int <18>: Parameter Setting Commands in C. (line 14) * int <19>: Parameter Setting Commands in C. (line 24) * int <20>: Parameter Setting Commands in C. (line 35) * int <21>: Parameter Setting Commands in C. (line 63) * int <22>: Parameter Setting Commands in C. (line 80) * int <23>: Parameter Setting Commands in C. (line 94) * int <24>: Parameter Setting Commands in C. (line 106) * int <25>: Parameter Setting Commands in C. (line 120) * int <26>: Parameter Setting Commands in C. (line 131) * int <27>: Parameter Setting Commands in C. (line 140) * int <28>: Parameter Setting Commands in C. (line 151) * int <29>: Parameter Setting Commands in C. (line 160) * int <30>: Parameter Setting Commands in C. (line 171) * int <31>: Parameter Setting Commands in C. (line 183) * int <32>: Event Notification and Index Marking in C. (line 80) * int <33>: Event Notification and Index Marking in C. (line 82) * int <34>: Event Notification and Index Marking in C. (line 84) * int <35>: Direct SSIP Communication in C. (line 14) * int <36>: Output Module Functions. (line 6) * int <37>: Functions for use when talking to synthesizer. (line 47) * int <38>: Multi-process output modules. (line 53) * int <39>: Multi-process output modules. (line 86) * int <40>: Multi-process output modules. (line 92) * int module_stop: Output Module Functions. (line 58) * int spd_pause(): Speech output control commands in C. (line 77) * int spd_resume(): Speech output control commands in C. (line 120) * module_child_dp_init: Multi-process output modules. (line 71) * module_child_dp_read: Multi-process output modules. (line 88) * module_child_dp_write: Multi-process output modules. (line 76) * module_close: Functions for use when talking to synthesizer. (line 48) * module_get_message_part: Functions for use when talking to synthesizer. (line 9) * module_parent_dp_init: Multi-process output modules. (line 66) * module_parent_dp_read: Multi-process output modules. (line 94) * module_parent_dp_write: Multi-process output modules. (line 82) * module_parent_wait_continue: Multi-process output modules. (line 55) * module_parent_wfork: Multi-process output modules. (line 9) * module_pause(): Output Module Functions. (line 72) * module_report_event_*: Functions for use when talking to synthesizer. (line 37) * module_report_index_mark: Functions for use when talking to synthesizer. (line 36) * module_sigblockall: Multi-process output modules. (line 99) * module_sigblockusr: Multi-process output modules. (line 109) * module_sigunblockusr: Multi-process output modules. (line 105) * module_speak(): Output Module Functions. (line 8) * module_stop(): Output Module Functions. (line 59) * Other programs: Current State. (line 6) * output module: Synthesis Output Modules. (line 6) * Philosophy: Motivation. (line 6) * size_t: Multi-process output modules. (line 6) * size_t module_pause: Output Module Functions. (line 71) * SPDCallback: Event Notification and Index Marking in C. (line 28) * SPDCallbackIM: Event Notification and Index Marking in C. (line 50) * SPDConnection*: Initializing and Terminating in C. (line 6) * SPDConnection* <1>: Initializing and Terminating in C. (line 62) * SPDNotification: Event Notification and Index Marking in C. (line 12) * SPDPriority: Speech Synthesis Commands in C. (line 7) * spd_cancel_all(): Speech output control commands in C. (line 54) * spd_cancel_uid(): Speech output control commands in C. (line 62) * spd_char(): Characters and Keys in C. (line 8) * spd_close(): Initializing and Terminating in C. (line 83) * spd_execute_command(): Direct SSIP Communication in C. (line 16) * spd_get_client_list(): History Commands in C. (line 6) * spd_get_message_list_fd(): History Commands in C. (line 5) * spd_get_output_module(): Parameter Setting Commands in C. (line 53) * spd_get_voice_pitch(): Parameter Setting Commands in C. (line 152) * spd_get_voice_rate(): Parameter Setting Commands in C. (line 132) * spd_get_volume(): Parameter Setting Commands in C. (line 184) * spd_history_select_client(): History Commands in C. (line 6) * spd_key(): Characters and Keys in C. (line 34) * spd_list_modules(): Information Retrieval Commands in C. (line 7) * spd_list_synthesis_voices(): Information Retrieval Commands in C. (line 36) * spd_list_voices(): Information Retrieval Commands in C. (line 17) * spd_open(): Initializing and Terminating in C. (line 9) * spd_open2(): Initializing and Terminating in C. (line 65) * spd_pause_all(): Speech output control commands in C. (line 97) * spd_pause_uid(): Speech output control commands in C. (line 105) * spd_resume_all(): Speech output control commands in C. (line 132) * spd_resume_uid(): Speech output control commands in C. (line 140) * spd_say(): Speech Synthesis Commands in C. (line 23) * spd_sayf(): Speech Synthesis Commands in C. (line 49) * spd_say_wchar(): Characters and Keys in C. (line 26) * spd_send_data(): Direct SSIP Communication in C. (line 40) * spd_set_data_mode(): Parameter Setting Commands in C. (line 16) * spd_set_language(): Parameter Setting Commands in C. (line 26) * spd_set_notification: Event Notification and Index Marking in C. (line 86) * spd_set_notification_off: Event Notification and Index Marking in C. (line 84) * spd_set_notification_on: Event Notification and Index Marking in C. (line 82) * spd_set_output_module(): Parameter Setting Commands in C. (line 37) * spd_set_punctuation(): Parameter Setting Commands in C. (line 65) * spd_set_spelling(): Parameter Setting Commands in C. (line 82) * spd_set_voice_pitch(): Parameter Setting Commands in C. (line 142) * spd_set_voice_pitch() <1>: Parameter Setting Commands in C. (line 162) * spd_set_voice_rate(): Parameter Setting Commands in C. (line 122) * spd_set_voice_type(): Parameter Setting Commands in C. (line 96) * spd_set_voice_type() <1>: Parameter Setting Commands in C. (line 108) * spd_set_volume(): Parameter Setting Commands in C. (line 173) * spd_sound_icon(): Sound Icons in C. (line 8) * spd_stop(): Speech output control commands in C. (line 10) * spd_stop_all(): Speech output control commands in C. (line 24) * spd_stop_uid(): Speech output control commands in C. (line 32) * static: Functions for use when talking to synthesizer. (line 6) * static <1>: Memory Handling Functions. (line 6) * static <2>: Memory Handling Functions. (line 10) * Synthesizers: Current State. (line 6) * tail recursion: Index of Concepts. (line 6) * UPDATE_PARAMETER: Generic Macros and Functions. (line 6) * UPDATE_PARAMETER <1>: Generic Macros and Functions. (line 7) * UPDATE_STRING_PARAMETER: Generic Macros and Functions. (line 40) * UPDATE_STRING_PARAMETER <1>: Generic Macros and Functions. (line 41) * void: Initializing and Terminating in C. (line 82) * void <1>: Functions used by module_main.c. (line 39) * void <2>: Functions for use when talking to synthesizer. (line 35) * void <3>: Functions for use when talking to synthesizer. (line 36) * void <4>: Multi-process output modules. (line 64) * void <5>: Multi-process output modules. (line 69) * void <6>: Multi-process output modules. (line 74) * void <7>: Multi-process output modules. (line 80) * void <8>: Multi-process output modules. (line 98) * void <9>: Multi-process output modules. (line 103) * void <10>: Multi-process output modules. (line 107) * void <11>: Memory Handling Functions. (line 15) * xfree: Memory Handling Functions. (line 16) * xmalloc: Memory Handling Functions. (line 7) * xrealloc: Memory Handling Functions. (line 12)  Tag Table: Node: Top255 Node: Introduction1983 Node: Motivation2332 Node: Basic Design4198 Node: Features Overview8953 Node: Current State9627 Node: User's Documentation11465 Node: Installation12134 Node: Running16802 Node: Running Under Ordinary Users17457 Node: Running in a Custom Setup18329 Node: Setting Communication Method18995 Node: Troubleshooting21122 Node: Configuration23234 Node: Configuration file syntax24428 Node: Configuration options25467 Node: Audio Output Configuration25918 Node: Client Specific Configuration27093 Node: Output Modules Configuration28687 Node: Loading Modules in speechd.conf29635 Ref: AddModule29906 Node: Configuration files of output modules30710 Ref: AddVoice31333 Node: Configuration of the Generic Output Module34173 Node: Log Levels38044 Node: Tools39262 Node: spd-say39896 Node: spd-conf40081 Node: spd-send41053 Node: Synthesis Output Modules41468 Node: Provided Functionality42318 Node: Supported Modules43090 Node: Security45234 Node: Technical Specifications46229 Node: Communication mechanisms46534 Node: Address specification48969 Node: Actions performed on startup50617 Node: Accepted signals53457 Node: Client Programming53916 Node: C API54963 Node: Initializing and Terminating in C55482 Node: Speech Synthesis Commands in C60040 Node: Speech output control commands in C63057 Node: Characters and Keys in C68531 Node: Sound Icons in C70234 Node: Parameter Setting Commands in C71167 Ref: spd_set_output_module72519 Ref: spd_get_output_module73161 Ref: spd_set_voice_type74682 Ref: spd_set_synthesis_voice75083 Node: Other Functions in C77614 Node: Information Retrieval Commands in C77816 Ref: spd_list_modules78129 Ref: spd_list_voices78533 Ref: spd_list_synthesis_voices79303 Node: Event Notification and Index Marking in C80241 Ref: SPDNotification80779 Ref: SPDCallback81245 Node: History Commands in C86388 Node: Direct SSIP Communication in C86600 Node: Python API89690 Node: Guile API92771 Node: Common Lisp API93075 Node: Autospawning93393 Node: Server Programming94931 Node: Server Core95261 Node: Output Modules98284 Node: Basic Structure98764 Node: Communication Protocol for Output Modules100076 Ref: Events notification and index marking108264 Node: How to Write New Output Module111450 Node: The Skeleton of an Output Module113381 Node: Output Module Functions120039 Node: Module Utils Functions and Macros125364 Node: Initialization Macros and Functions126122 Node: Generic Macros and Functions127529 Node: Functions used by module_main.c129134 Node: Functions for use when talking to synthesizer130915 Node: Multi-process output modules133517 Node: Memory Handling Functions138299 Node: Index Marks in Output Modules139068 Node: Download and Contact140642 Node: Reporting Bugs141485 Node: How You Can Help144528 Node: Appendices148660 Node: GNU General Public License148826 Node: GNU Free Documentation License168111 Node: Index of Concepts190571  End Tag Table speech-dispatcher-0.9.1/doc/ssip.info0000644000175000017500000032526513465234513014460 00000000000000This is ssip.info, produced by makeinfo version 6.5 from ssip.texi. INFO-DIR-SECTION Sound INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * SSIP: (ssip). Speech Synthesis Interface Protocol. END-INFO-DIR-ENTRY  File: ssip.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) This manual documents Speech Synthesis Interface Protocol, version 0.2. Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s., http://www.brailcom.cz . Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License." You can also (at your option) distribute this manual under the GNU General Public License: Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled "GNU General Public License" Please contact us on * Menu: * Introduction:: * Basic Terminology:: * General Rules:: * SSIP Commands:: * Return Codes:: * Appendices:: * GNU Free Documentation License:: * GNU General Public Licence::  File: ssip.info, Node: Introduction, Next: Basic Terminology, Prev: Top, Up: Top 1 Introduction ************** * Menu: * Purpose:: * Protocol Philosophy:: * Higher Level API::  File: ssip.info, Node: Purpose, Next: Protocol Philosophy, Prev: Introduction, Up: Introduction 1.1 Purpose =========== Speech Synthesis Interface Protocol is a device independent layer for speech synthesis, developed with the goal of making the usage of speech synthesis easier for application programmers. It takes care of most of the output-related tasks necessary to solve in speech enabled applications. What is a very high level GUI library to graphics, Speech Synthesis Interface Protocol is to speech synthesis. Up to now, the applications that wanted to implement speech output had to handle all the device dependent aspects of communication with different speech synthesizers themselves. Speech Synthesis Interface Protocol (SSIP) aims to provide a totally independent abstract set of commands by which different applications can talk to some central Speech Server installed on the system that than talks to the synthesizers themselves. This way, user applications don't have to care about the particular synthesizers available on the system and the synthesizers don't have to care about the installed user applications. SSIP is not only a device independent language for speech synthesis related requests, but also a mechanism to coordinate the interaction and conflicts between different clients' needs in a central place in the system. Through the priority system, the central Speech Server that implements SSIP can decide which messages are considered the most important at any particular time and say them, while possibly supressing others.  File: ssip.info, Node: Protocol Philosophy, Next: Higher Level API, Prev: Purpose, Up: Introduction 1.2 Protocol Philosophy ======================= Speech Synthesis Interface Protocol defines a reasonable subset of the different capabilities provided by the different synthesizers. It supports some basic events (message, key, character, ...) as well as changing the basic voice parameters (language, voice, rate, pitch, ...) or the more advanced ones (punctuation mode, spelling mode, ...). None of the commands or parameters of SSIP depends on the characteristics of the particular devices that are being used. For example when the client application wants to change the language for the next message, it only calls the appropriate SSIP command and it leaves the Speech Server to decide which synthesizer to use. SSIP was designed to allow multiple simultaneous connections to the server. A connection is identified by an identification string provided by the client application and an id number. Each connection with all its parameters is considered a closed space independent of the others, so that different clients can maintain different settings in their connections and then the Speech Server should take care of setting the right parameters on the synthesizer according to the origin of each request. One client can even establish several connections to maintain different contexts. SSIP also solves the issue when more than one client wants to speak at one time or when more messages come than it's possible to say. Each message has an assigned priority and according to this priority, when multiple messages come to the server, they are directly said, postponed or suppressed. It is important to understand the difference between SSIP and higher level protocols like SABLE, VoiceXML or SSML. Speech Synthesis Interface Protocol is not a markup language in which one would write a document. SSIP is rather the underlaying tool that the application would use to let you read and browse the documents encoded in either ordinary formats (like plain text, HTML, PDF) or the voice-enabled formats (SABLE, VoiceXML, SSML). These higher level protocols describe only how the document should be said, while SSIP is the means to actually do it on your system. In this manner, one of the supported formats of the messages you can send through SSIP is SSML.  File: ssip.info, Node: Higher Level API, Prev: Protocol Philosophy, Up: Introduction 1.3 Higher Level API ==================== SSIP is the basic interface protocol that is being used in the communication of a client with the central Speech Server on a system. However, in many cases it may be more convenient for application programmers not to use SSIP directly (having to care about open socket connections etc.) but rather use an interface wrapper written in the specific programming language they use. There is no obstacle in SSIP for this option, and in fact, this approach is highly encouraged. This way, application programmers should finally be able to use such simple functions as speech_open(), speech_printf() and speech_set_rate() in their programs. We believe this can make writing new speech enabled applications a lot easier and allow programmers to make more of them.  File: ssip.info, Node: Basic Terminology, Next: General Rules, Prev: Introduction, Up: Top 2 Basic Terminology ******************* * _Speech Synthesis Interface Protocol_ or _SSIP_ is the device-independent protocol described in this document through which client application can send their requests for speech synthesis to the Speech Server. * _Speech Server_ is the server application that implements Speech Synthesis Interface Protocol, as described in this document, and provides an interface for client applications. * _Client_ or _client application_ is every application that connects to Speech Server and talks to it through the Speech Synthesis Interface Protocol. In other words, this is the application that "wants to speak". * _Message_ is a chunk of text that a client sends to Speech Server to request saying something or play some sound. * _To cancel a message_ means to stop saying it and/or remove it from the queue of messages waiting to be said. However, it is not removed from the history, where it was stored after being received by Speech Server.  File: ssip.info, Node: General Rules, Next: SSIP Commands, Prev: Basic Terminology, Up: Top 3 General Rules *************** SSIP communicates with the clients through a defined set of text commands, in the usual manner for common Internet protocols. The characters sent through the Speech Synthesis Interface Protocol are encoded using the UTF-8 encoding. Each SSIP command, unless specified otherwise, consists of exactly one line. The line is sent in the following format: COMMAND ARG ... where COMMAND is a case insensitive command name and ARGs are its arguments separated by spaces. The command arguments which come from a defined set of values are case insensitive as well. The number of arguments is dependent on the particular command and there can be commands having no arguments. All lines of SSIP input and output must be ended with a pair of carriage return and line feed characters, in that order. When you connect to Speech Server, you should at least set your client name, through the 'SET SELF CLIENT_NAME' command (*note Parameter Setting Commands::). This is important to get a proper identification of your client -- to allow managing it from the control center application and to identify it in a message history browser. You might want to set other connection parameters as well. Look for more details in *note Parameter Setting Commands::. An SSIP connection is preferably closed by issuing the 'QUIT' command, see *note Other Commands::. SSIP is a synchronous protocol -- you send commands and only after a complete response from SSIP arrives back are you allowed to send the next command. Usually, the SSIP connection remains open during the whole run of the particular client application. If you close the connection and open it again, you must set all the previously set parameters again, SSIP doesn't store session parameters between connections. The protocol allows you to perform commands influencing other currently connected or previously connected clients. This allows you to write a control application managing or browsing all the messages received by the current Speech Server process. The mechanism is completely relaxed, there are no restrictions on managing some aspects of sound output for other users, however, there is a mechanism to prevent one user from seeing history messages of another user. Some of the commands (*note Speech Output Control Commands:: and *note Parameter Setting Commands::) take an argument in the form: { ID | all | self } where the value can be the 'id' of the connection the command should be performed on (a positive number), the string 'all' to act on all clients of this server or 'self' to act on the connection itself. Unless you are writing a special client for managing Speech Server or unless you have specific needs, you should only use the 'self' value for this argument. Not all parameter setting commands may receive all kinds of the first parameter defined above, for instance, some of them may receive only 'self'. SSIP replies have the following format: CCC-line 1 CCC-line 2 ... CCC-line N-1 DDD line N where N is a positive integer, and CCC and DDD are three-digit long numeric codes identifying the result of the command. The last line determines the overall result of the command. The result code is followed by an English message describing the result of the action in a human readable form.  File: ssip.info, Node: SSIP Commands, Next: Return Codes, Prev: General Rules, Up: Top 4 SSIP Commands *************** Commands recognized by SSIP can be divided into several groups: Speech synthesis and sound output commands, speech control commands, parameter setting commands, commands retrieving information about current client and server settings, commands handling the message history, and other commands. Each of these command groups is described in one of the following sections. In the command descriptions, the command is written together with its arguments. Optional arguments are enclosed by square brackets ('[' and ']'), alternatives are separated by the vertical rule ('|') and are grouped within braces ('{' and '}') or square brackets for mandatory or optional arguments respectively. Literal argument values are typeset in lowercase letters (they are case insensitive), and variable arguments are typeset LIKE THIS. Ellipsis denoted by three dots ('...') means repetition (zero or more times) of all the arguments within the current brackets. * Menu: * Speech Synthesis and Sound Output Commands:: * Speech Output Control Commands:: * Message Priority Commands:: * Blocks of Messages Commands:: * Parameter Setting Commands:: * Information Retrieval Commands:: * Message Events Notification and Index Marking:: * History Handling Commands:: * Other Commands::  File: ssip.info, Node: Speech Synthesis and Sound Output Commands, Next: Speech Output Control Commands, Prev: SSIP Commands, Up: SSIP Commands 4.1 Speech Synthesis and Sound Output ===================================== These commands invoke actual output to particular output device. The particular way how the message is handled depends on current speech parameter settings and user configuration. 'SPEAK' Start receiving a text message and synthesize it. After sending a reply to the command, Speech Server waits for the text of the message. The text can spread over any number of lines and is finished by an end of line marker followed by the line containing the single character '.' (dot). Thus the complete character sequence closing the input text is 'CR LF . CR LF'. If any line within the sent text starts with a dot, an extra dot is prepended before it. During reception of the text message, Speech Server doesn't send responses for the lines sent. The response line is sent only immediately after the 'SPEAK' command and after receiving the closing dot line. The content of the message can be either a plain text or a SSML (Speech Synthesis Markup Language) text. See 'SET SELF SSML_MODE'. There is no guarantee that the SSML markup will be respected, so the application shouldn't rely on them. The external parameters can still be set by the parameter setting commands. SSML is intended only for additional markup inside the message. In SSML mode, each message must begin with '' and end with ''. Speech Server can start speech synthesis as soon as a sufficient amount of the text arrives; it generally needn't (but may) wait until the end of data marker is received. There is no explicit upper limit on the size of the text, but the server administrator may set one in the configuration or the limit can be enforced by available system resources. If the limit is exceeded, the whole text is accepted, but the excess is ignored and an error response code is returned after processing the final dot line. The reply takes the form 225-msg_id 225 OK MESSAGE QUEUED where MSG_ID is a unique id assigned to this message in Speech Server. This is useful for the *note History Handling Commands:: commands as well as for *note Message Events Notification and Index Marking::. The 'SPEAK' command might be used for example in this way: SPEAK 230 OK RECEIVING DATA hi . 225-21 225 OK MESSAGE QUEUED 'CHAR CHAR' Speak letter CHAR. CHAR can be any character representable by the UTF-8 encoding. The only exception is the character space (' '); that can't be sent directly. In this case, a string 'space' must be sent instead. CHAR e CHAR \ CHAR space CHAR & This command is intended to be used for speaking single letters, e.g. when reading a character under cursor or when spelling words. 'KEY KEY-NAME' Speak key identified by KEY-NAME. The command is intended to be used for speaking keys pressed by the user. KEY-NAME is a case sensitive symbolic key name. It is composed of a key name, optionally prepended with one or more prefixes, each containing an auxiliary key name and the underscore character. Key name may contain any character excluding control characters (for example, the characters in the range 0 to 31 in the ASCII table, characters in the range 128 to 159 in the Latin-* tables and other "invisible" characters), spaces, underscores, and double quotes. The recognized key names are: * Any single UTF-8 character, excluding the exceptions defined above. * Any of the symbolic key names defined in *note Key Names::. Examples of valid key names: a A shift_a shift_A u' $ enter shift_kp-enter control_alt_delete control 'SOUND_ICON ICON-NAME' Send a sound identified by ICON-NAME to the audio output. ICON-NAME is a symbolic name of the given sound from the standard set listed in *note Standard Sound Icons::, or another name from the particular Speech Server sound icon configuration.  File: ssip.info, Node: Speech Output Control Commands, Next: Message Priority Commands, Prev: Speech Synthesis and Sound Output Commands, Up: SSIP Commands 4.2 Controlling Speech Output ============================= These commands can stop or resume speech or audio output. They all affect only the synthesis process and output to a sound device, they do not affect the message history. 'STOP { ID | all | self }' Immediately stop outputting the current message (whatever it is -- text, letter, key, or sound icon) from the identified client, if any is being output. If the command argument is 'self', the last message from the current client connection is stopped. If it is 'all', stop currently output message or messages from all the clients. Otherwise, argument ID must be given as a positive integer and the currently processed message from the client connection identified by ID is stopped; if there is none such, do nothing. 'CANCEL { ID | all | self }' This command is the same as 'STOP', with the exception that it stops as yet unspoken output messages as well. All currently queued messages are stored into the message history without being sent to the audio output device. 'PAUSE { ID | all | self }' Stop audio output immediately, but do not discard anything. All the currently speaking and currently or later queued messages are postponed and saved for later processing, until a corresponding 'RESUME' command is received. The meaning of the command arguments is the same as in the 'STOP' command. 'RESUME { ID | all | self }' Cancel the effect of the previously issued 'PAUSE' command. Note that messages of the priority "progress" and "notification" received during the pause are not output (but they remain stored in the message history). It is an error to send the 'RESUME' command when the output corresponding to the given argument is not paused by a previous invocation of the 'PAUSE' command. Such an error is signaled by a '4XX' return code. The meaning of the command arguments is the same as in the 'STOP' command.  File: ssip.info, Node: Message Priority Commands, Next: Blocks of Messages Commands, Prev: Speech Output Control Commands, Up: SSIP Commands 4.3 Priority Setting Commands ============================= A speech synthesizer can't synthesize everything that comes to it, for the simple reason that messages are often coming faster than a synthetic voice can say them. On the screen of a monitor, there is relatively a lot of space compared to one-channel speech synthesis output. For this reason, SSIP implements a system of several priorities targeted at different types of messages. The idea is that the task of the programmer of a client application is only to assign a meaningful priority to each message and all the synchronization and switching between the messages (that can be coming from different clients) is automatically handled by the Speech Server by applying certain rules based on the priorities. * Menu: * Priority Categories:: What are the available priorities. * Priority Diagram:: Schematic diagram of used priority model. * Priority Setting Commands:: * Examples of Using Priorities:: A few examples of using the priorities.  File: ssip.info, Node: Priority Categories, Next: Priority Diagram, Prev: Message Priority Commands, Up: Message Priority Commands 4.3.1 Priority Categories ------------------------- Speech Synthesis Interface Protocol provides a system of five priorities. Every message will either contain explicit priority information, or the default value will be used. Please see also the diagram below. Priority 'important' ==================== This message will be said immediately as it comes to server. It is never interrupted. When several concurrent messages of this priority are received by server, they are queued and said in the order they came. When a new message of level 'important' comes while a message of another priority is being spoken, the other message is canceled and the message with priority 'important' is said instead. Other messages of lower priorities are postponed (priority 'message' and 'text') until there are no messages of priority important waiting, or are canceled (priority 'notification' and 'progress'). These messages should be as short as possible and should rarely be used, because they block the output of all other messages. Priority 'message' ================== This message will be said when there is no message of priority 'important' or 'message' waiting in the queue. If there are, this message is postponed until those messages are spoken. This means that the priority 'message' doesn't interrupt itself. If there are messages of priority 'notification', 'progress' or 'text' waiting in the queue or being spoken when a message of priority 'message' comes, they are canceled. Priority 'text' =============== This message will be said when there is no message of priority 'important' or 'message' waiting in the queue. If there are, this message is postponed until the previous messages are spoken. The priority text interrupts itself. This means that if several messages of this priority are received, they are not said in the order they were received, but only the latest of them is said; others are canceled. If there are messages of priority 'notification' and 'progress' waiting in the queue or being spoken when a message of priority 'text' comes, they are canceled. Priority 'notification' ======================= This is a low priority message. If there are messages with priorities 'important', 'message', 'text' or 'progress' waiting in the queues or being spoken, this 'notification' message is canceled. This priority interrupts itself, so if more messages with priority 'notification' come at the same time, only the last of them is spoken. Priority 'progress' =================== This is a special priority for messages that are coming shortly one after each other and they carry the information about some work in progress (e.g. 'Completed 45%'). If new messages interrupted each other (see priority Notification), the user might not receive any complete message. This priority behaves the same as "notification" except for two things: * The messages of this priority don't interrupt each other, instead, a newly arriving message is canceled if another message is being spoken. * Speech Server tries to detect the last message of a series of messages (for instance, it's important for the user to hear the final 'Completed 100%' message to know the work has completed). Speech Server waits until there are no more messages of this priority waiting in queues and if the last of them wasn't spoken yet, it speaks it with the priority 'message'. This way, even if Speech Server is busy speaking messages of other priorities, we are still sure that the important messages at the end of the 'progress' sequences will be said.  File: ssip.info, Node: Priority Diagram, Next: Priority Setting Commands, Prev: Priority Categories, Up: Message Priority Commands 4.3.2 Priority Diagram ---------------------- [image src="figures/priorities.png" alt="Speech Synthesis Interface Protocol Priorities" text=" ___________ | IMPORTANT | `-----------' . / \\ / |p| \\ . . . . . . . |r| . . . . . . . . . . message ----> |i| <---- text . . . |o| . . . progress ----> |r| <---- notification . . . |i| . . . . |t| . . . . . . . . . |y| . . . . . . . . . doesn't interrupt interrupts itself itself "]  File: ssip.info, Node: Priority Setting Commands, Next: Examples of Using Priorities, Prev: Priority Diagram, Up: Message Priority Commands 4.3.3 Priority Setting Commands ------------------------------- When a priority is set for a given connection, all the newly arriving messages will be said with this priority until it is changed for a new value. * SET self PRIORITY P This command sets message priority to P. P must be one of the values 'important', 'text', 'message', 'notification', 'progress'. *Note Priority Categories::. Only 'self' is allowed as the 'target' argument.  File: ssip.info, Node: Examples of Using Priorities, Prev: Priority Setting Commands, Up: Message Priority Commands 4.3.4 Examples of Using Priorities ---------------------------------- Example uses for priority 'important' are: * error messages * very important messages * ... Example uses for priority 'message' are: * regular program messages * warnings * ... Example uses for priority 'text' are: * text the user is working on * menu items * ... Example uses for priority 'notification' are: * less important status information * letters when typing input * run-time help * ... Example uses for level 'progress' are: * "completed 15%", "completed 16%", "completed 17%" * "Loading sounds", "Loading graphics", "Loading ai", ...  File: ssip.info, Node: Blocks of Messages Commands, Next: Parameter Setting Commands, Prev: Message Priority Commands, Up: SSIP Commands 4.4 Blocks of Messages Commands =============================== Block commands allow the client to concatenate several messages to form one block that behaves as one message in the priority system and history. After opening the block, client can send a specified subset of the commands and the messages introduced by 'SPEAK' will be processed immediately, however there will be no priority interaction before closing the block. The *note Speech Output Control Commands:: also handle the whole block as one message. Take for example this message from an email client: > Hi, how are you? I'm fine. Thank you. The character '>' clearly marks who said which part. So it'd be nice to say the two lines with different voices, however, it'd be desirable to treat it all as one message with priority TEXT and have it put together in history, because in fact, it logically _is_ one message. 'BLOCK BEGIN' Opens a block of messages. There will be no priority interaction between the messages inside the block, the whole block will be treated as one message of the priority that was specified by previous 'SET' command. It can only be called outside of a block; nesting is not allowed. The allowed commands inside a block are: * 'SPEAK' * 'SOUND_ICON' * 'CHAR' * 'KEY' * 'SET SELF RATE' * 'SET SELF PITCH' * 'SET SELF VOLUME' * 'SET SELF VOICE' * 'SET SELF LANGUAGE' * 'SET SELF PUNCTUATION' * 'SET SELF CAP_LET_RECOGN' * 'QUIT' * 'BLOCK END' 'BLOCK END' Closes a block of messages, see 'BLOCK BEGIN'. It can be only called inside a block opened by 'BLOCK BEGIN'; nesting is not allowed. A more complete example of SSIP communication using BLOCKs. [...] SET SELF PRIORITY TEXT 202 OK PRIORITY SET BLOCK BEGIN 260 OK INSIDE BLOCK SET SELF VOICE MALE1 209 OK VOICE SET SPEAK 230 OK RECEIVING DATA The word 225 OK MESSAGE QUEUED SET SELF VOICE MALE2 209 OK VOICE SET SPEAK 230 OK RECEIVING DATA `Free' 225 OK MESSAGE QUEUED SET SELF VOICE MALE1 209 OK VOICE SET SPEAK 230 OK RECEIVING DATA in Free Software refers to freedom, not price. 225 OK MESSAGE QUEUED BLOCK END 261 OK OUTSIDE BLOCK  File: ssip.info, Node: Parameter Setting Commands, Next: Information Retrieval Commands, Prev: Blocks of Messages Commands, Up: SSIP Commands 4.5 Parameter Setting ===================== The 'SET' command sets various control parameters of the synthesized speech or server configuration. The parameter is always denoted by the second command argument. All the settings take effect on the connections specified in the first argument (*note General Rules::) and until the parameter setting is changed by another invocation of the appropriate 'SET' command or until the connection is closed. The voice property and TTS-processing settings can sometimes be without any real effect if the end synthesizer doesn't provide the required functionality. This is not considered an error in the implementation of SSIP. 'SET self CLIENT_NAME USER:CLIENT:COMPONENT' Set client's name. Client name consists of the user name, client (application) identification, and the identification of the component of the client (application). Each of the parts of the client name may contain only alphanumeric characters, dashes ('-') and underscores ('_'). For example, for a client called 'lynx' that creates an SSIP connection for its command processing, the name could be set in the following way: SET CLIENT_NAME joe:lynx:cmd_processing The client name is used in the server configuration settings, client listings and message history handling. All its three parts can be arbitrary, but it's important to define and follow rules for each application supporting Speech Synthesis Interface Protocol, so that a Speech Server user can configure all the aspects of the speech output easily. Usually, this command should be sent as the very first command when a new SSIP connection is established. The command may be sent only once within a single connection. Attempts to change the client's name once it's already set are answered with an error code. Only 'self' is allowed as the 'target' argument. 'SET all DEBUG {ON|OFF}' If set to 'ON', Speech Dispatcher will write all its debugging information (including output modules) with maximal verbosity into a debug directory which is reported by the server to the client in reply to this command. When subsequently set to 'OFF', Speech Dispatcher will stop writing out debugging information into this path and close all the appropriate logging files. The intended use for this functionality is on-line debugging from client application. If the user wants to report a problem, the client application will ask him/her for a place to generate the logs, to repeat the situation that he/she considers to be a bug, and then perhaps it will automatically pack the logs and offer to send them to the developers of Speech Dispatcher or another appropriate place where the contained information can be processed. Warning: This option results in a lot of data being written into the output logs and so should not be left on for an unnecessarily long time. SET all DEBUG ON 262-/home/hanke/.cache/speech-dispatcher/log/debug 262 OK DEBUGGING SET 'SET {all | self | ID } OUTPUT_MODULE MODULE' Set the output module to MODULE. This overrides the selection based on language. Only values returned by the 'LIST OUTPUT_MODULES' command are permitted. *Note list-output-modules::. SET self OUTPUT_MODULE espeak 216 OK OUTPUT MODULE SET 'GET OUTPUT_MODULE' Get the output module currently in use. This takes no parameters and simply returns the current output module. GET OUTPUT_MODULE 251-espeak 251 OK GET RETURNED 'SET { all | self | ID } LANGUAGE LANGUAGE-CODE' Set recommended language for this client according to LANGUAGE-CODE. LANGUAGE-CODE is the code of the language according to RFC 1766. For example, to set the preferred language to Czech, you send the following command: SET SELF LANGUAGE cs Please note, that switching a language may require switching a voice, so this command may actually override a previous call to 'SET VOICE' or 'SET SYNTHESIS_VOICE'. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultLanguage' setting in the 'speechd.conf' file. The factory default is 'en' (English). 'SET {self} SSML_MODE MODE' Set the mode of the text received in the message body sent by the 'SPEAK' command. This can be either a plain text, if 'mode' is set to 'off' or a SSML marked text, if 'mode' is set to 'on'. There is no guarantee that the SSML markup will be respected, so the application shouldn't rely on them. The external parameters can still be set by the parameter setting commands. SSML is intended only for additional markup inside the message. In SSML mode, each message must begin with '' and end with ''. For example a simple 'hello world' looks like this: SET SELF SSML_MODE on SPEAK Hello world! . 'SET { all | self | ID } PUNCTUATION { all | some | none }' Set punctuation mode to the given value. 'all' means speak all punctuation characters, 'none' means speak no punctuation characters, 'some' means speak only punctuation characters set in the synthesizer's configuration. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultPunctuationMode' setting in the 'speechd.conf' file. The factory default is 'none'. 'SET { all | self | ID } SPELLING { on | off }' Switch spelling on or off. If spelling is set to on, all the incoming messages will be said letter-by-letter, instead of speaking them as whole words. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultSpelling' setting in the 'speechd.conf' file. The factory default is 'off'. 'SET { all | self | ID } CAP_LET_RECOGN { none | spell | icon }' Set capital letters recognition mode. 'none' switches this feature off. 'spell' causes capital letters to be spelled in the speech using the table set as 'CAP_LET_RECOGN_TABLE'. With parameter 'icon', each capital letter will be preceeded by a sound icon (either sound or textual) specified by the user in his configuration. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultCapLetRecognition' setting in the 'speechd.conf' file. The factory default is 'none'. 'SET { all | self | ID } VOICE_TYPE NAME' Set the voice identified by NAME. NAME must be one of the voice identifiers returned by the command 'LIST VOICES' (*note Information Retrieval Commands::). There is a standard set of voice identifiers defined in *note Standard Voices::. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultVoiceType' setting in the 'speechd.conf' file. The factory default is 'MALE1'. 'GET VOICE_TYPE' Gets the current pre-defined voice. A list of voice identifiers can be obtained by the command 'LIST VOICES' (*note Information Retrieval Commands::). GET VOICE_TYPE 251-MALE1 251 OK GET RETURNED 'SET { all | self | ID } SYNTHESIS_VOICE NAME' Set the voice identified by NAME. NAME is a voice name recognized by the current synthesizer. It must be one of the names returned by the command 'LIST SYNTHESIS_VOICES' run for the appropriate synthesizer. (*note Information Retrieval Commands::). Please note, that switching to a particular voice may require switching a language, so this command may actually override a previous call to 'SET LANGUAGE'. 'SET { all | self | ID } RATE N' Set the rate of speech. N is an integer value within the range from -100 to 100, lower values meaning slower speech and higher values meaning faster speech. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultRate' setting in the 'speechd.conf' file. The factory default is 0. 'GET RATE' Get the current rate of speech value. GET RATE 251-10 251 OK GET RETURNED 'SET { all | self | ID } PITCH N' Set the pitch of speech. N is an integer value within the range from -100 to 100, lower values meaning lower pitch and higher values meaning higher pitch. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultPitch' setting in the 'speechd.conf' file. The factory default is 0. 'GET PITCH' Get the current pitch value. GET PITCH 251-10 251 OK GET RETURNED 'SET { all | self | ID } VOLUME N' Set the volume of speech. N is an integer value within the range from -100 to 100. lower values meaning lower volume and higher values meaning higher volume. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultVolume' setting in the 'speechd.conf' file. The factory default is 100. 'GET VOLUME' Get the current volume value. GET VOLUME 251-100 251 OK GET RETURNED 'SET { all | self | ID } PAUSE_CONTEXT N' Set the number of (more or less) sentences that should be repeated after a previously paused text is resumed. If there isn't enough text before the pause spot, the entire message is repeated. N is a positive integer value specifying the number of sentences to repeat. The default for the Speech Dispatcher implementation of SSIP is determined by the 'DefaultPauseContext' setting in the 'speechd.conf' file. The factory default is 0. 'SET { all | self | ID } HISTORY { on | off }' Enable ('on') or disable ('off') storing of received messages into history. This command is intended for use by message history browsers and usually should not be used by other kinds of clients.  File: ssip.info, Node: Information Retrieval Commands, Next: Message Events Notification and Index Marking, Prev: Parameter Setting Commands, Up: SSIP Commands 4.6 Retrieving Information ========================== The 'LIST' command serves for retrieving information that can be presented to the user for selection of the values to the 'SET' command. The information listed is selected according to the first argument of the 'LIST' command. 'LIST OUTPUT_MOUDLES' Lists the available output modules putting each module identification name one on a single line. Example: LIST OUTPUT_MODULES 250-festival 250-espeak 250 OK MODULE LIST SENT 'LIST VOICES' Lists the available symbolic voice names putting each voice name on a single line. These are symbolic names that are mapped to the real voices used in the synthesizer either automatically or via synthesizer or output module configuration. Example: LIST VOICES 249-MALE1 249-MALE2 249-MALE3 249-FEMALE1 249-FEMALE2 249-FEMALE3 249-CHILD_MALE 249-CHILD_FEMALE 249 OK VOICE LIST SENT 'LIST SYNTHESIS_VOICES' Lists the available voices for the current synthesizer in use. These names differ from those obtained by 'LIST VOICES' in that they are names of the real voices used inside the synthesizer. This feature should only be used to allow the user to choose the voice. All automatic switching of voices (unless user-configurable) should be done using the symbolic voice names which can be configured in the synthesizer. Each voice name is listed on a separate line together with its language code and dialect identification string separated by tabs. The dialect identification strings do not have well-defined meaning yet. If no dialect is specified by the synthesizer, the value 'none' is used. Example: LIST SYNTHESIS_VOICES 249-afrikaans af none 249-welsh-test cy none 249-german de none 249-greek_test el none 249-en-rhotic en r 249-lancashire en uk-north 249 OK VOICE LIST SENT  File: ssip.info, Node: Message Events Notification and Index Marking, Next: History Handling Commands, Prev: Information Retrieval Commands, Up: SSIP Commands 4.7 Message Events Notification and Index Marking ================================================= * Menu: * Why Events Notification:: * Types of Events:: * Events Notifications in SSIP:: * Switching Notifications On and Off::  File: ssip.info, Node: Why Events Notification, Next: Types of Events, Prev: Message Events Notification and Index Marking, Up: Message Events Notification and Index Marking 4.7.1 Why Events Notification ----------------------------- Applications can send messages to a Speech Server through the SSIP 'SPEAK' command. However, this command only puts the received message into a queue in Speech Server and returns immediately. The message then will or will not be said at some particular time according to its priority. Through Message Events Notification, the application is able to discover certain kind of events, including when the message started to be played on the speakers, when it terminated playing, when it was paused and resumed, or when it was interrupted/discarded. It is also possible to get notification when a certain place in the given text was reached while playing the synthesized text on the speakers - this capability, however, might or might not be supported by the end synthesizer and so client applications should not rely on it.  File: ssip.info, Node: Types of Events, Next: Events Notifications in SSIP, Prev: Why Events Notification, Up: Message Events Notification and Index Marking 4.7.2 Types of Events --------------------- SSIP recognizes several types of events. Each event is reported together with the unique identification of the message and client it is associated with. This is an overview of available events. For detailed SSIP syntax, please look below. 'BEGIN' This event means that the synthesizer just started to speak the message and the user is able to hear the speech on his/her speakers. Please note that not every message stored for speaking by the 'SPEAK' command will issue this event. It can issue the 'CANCEL' event instead. 'END' This event means that the synthesizer just terminated speaking the message (by reaching its end) and the user is no longer able to hear the speech on their speakers. Again, note that not every message that has already reported the 'BEGIN' event will necessarily get to the 'END' event. It might instead issue the 'CANCEL' or 'PAUSE' events. 'CANCEL' The 'CANCEL' event is reported when the message was canceled (either after 'BEGIN' during speaking or even before, when waiting in the queues) and will not be spoken anymore. 'PAUSE' The event 'PAUSE' means that the message that was being spoken was paused and no longer produces any sound on the speakers, but was not discarded and the rest of the message might be spoken again after the 'RESUME' command is sent. *Note Speech Output Control Commands::. This will be reported by the 'RESUME' event. 'PAUSE' is always preceded by the event 'BEGIN', and can be followed by either the event 'RESUME' or 'CANCEL'. 'RESUME' The event 'RESUME' means that a message that was paused while being spoken, just started to continue and again produces sound in the speakers. 'RESUME' is always preceeded by the event 'PAUSE', and can be followed by either the event 'END' or 'CANCEL'. 'INDEX_MARK' This event means that some previously specified place in the text (so-called index mark) was reached when speaking the synthesized message in the speakers. It is always accompanied by an additional parameter that indicates which place it is - the name of the index mark. Example (not in SSIP syntax): This SSML message Hello, how does it work? would issue the following sequence of events if it is not discarded or paused: BEGIN INDEX_MARK "mark1" END or this one if it gets paused after the first index mark and then later resumed. BEGIN INDEX_MARK "mark1" PAUSE RESUME END  File: ssip.info, Node: Events Notifications in SSIP, Next: Switching Notifications On and Off, Prev: Types of Events, Up: Message Events Notification and Index Marking 4.7.3 Events Notification in SSIP --------------------------------- Event notifications, if requested, are reported asynchronously in SSIP. This means that they are not sent as replies to any particular requests but can arrive anytime. However, notifications can't arrive in the time between when a SSIP command is sent by the client and its reply is sent back by the server. Each notification consists of a multi-line SSIP reply as defined in *note General Rules::, and includes at least two parameters: 'msg_id' and 'client_id'. 'msg_id' is the identification number of the message the event is related to, *note SPEAK:: while 'client_id' is the identification number of the client who sent the message. Some events may have additional parameters. 'INDEX_MARK' 700-msg_id 700-client_id 700-index_mark 700 END The event 'INDEX_MARK' carries a special parameter 'index_mark' which is a string of characters identifying the index mark, as specified by the client application (e.g. by the SSML tag . 'BEGIN' 701-msg_id 701-client_id 701 BEGIN 'END' 702-msg_id 702-client_id 702 END 'CANCEL' 703-msg_id 703-client_id 703 CANCELED 'PAUSE' 704-msg_id 704-client_id 704 PAUSED 'RESUME' 705-msg_id 705-client_id 705 RESUMED  File: ssip.info, Node: Switching Notifications On and Off, Prev: Events Notifications in SSIP, Up: Message Events Notification and Index Marking 4.7.4 Switching Notifications On and Off ---------------------------------------- The client application might or might not want to receive the notifications about events, or it might want to receive some but not others. SSIP allows clients to specify which notifications are to be used. The following commands for setting notifications on and off affect all the text messages (sent by the 'SPEAK' SSIP command) based on when the appropriate 'SPEAK' command was called. So if for example, you set all notifications on, send a message and then set all notifications off, you will receive all the available notifications for that message even though it might start speaking after the notifications are already turned off. 'SET SELF NOTIFICATION ALL { on | off }' Set all available event notifications to either "on" or "off" for for the messages that follow. *Note Types of Events::. 'SET SELF NOTIFICATION BEGIN { on | off }' 'SET SELF NOTIFICATION END { on | off }' Set the event notifications for 'BEGIN' or 'END' to either "on" or "off" for the messages that follow. *Note Types of Events::. 'SET SELF NOTIFICATION CANCEL { on | off }' Set the event notifications for 'CANCEL' to 'mode' where 'mode' is either "on" or "off" for switching the notifications on or off for the messages that follow. *Note Types of Events::. 'SET SELF NOTIFICATION PAUSE { on | off }' 'SET SELF NOTIFICATION RESUME { on | off }' Set the event notifications for 'PAUSE' or 'RESUME' to 'mode' where 'mode' is either "on" or "off" for switching the notifications on or off for the messages that follow. *Note Types of Events::. 'SET SELF NOTIFICATION INDEX_MARKS { on | off }' Set the event notifications for 'INDEX_MARK' to either "on" or "off" for switching the notifications on or off for the messages that follow. *Note Types of Events::.  File: ssip.info, Node: History Handling Commands, Next: Other Commands, Prev: Message Events Notification and Index Marking, Up: SSIP Commands 4.8 History Handling ==================== * Menu: * Purpose of Message History:: * Message History in SSIP::  File: ssip.info, Node: Purpose of Message History, Next: Message History in SSIP, Prev: History Handling Commands, Up: History Handling Commands 4.8.1 Purpose of Message History -------------------------------- It seems a good feature for the blind and visually impaired to provide the possibility to browse, through some simple client, the history of received and previously said messages. Some messages are even received by Speech Server without being said, because there will always be more space for information on the screen than speech output can possibly provide. For this reason, SSIP defines a set of commands that allow client applications to browse through the history of previously received messages saved on the server. The idea is that _each_ message received by the server should be accessible through the history and the user can search for it later by time, keywords or using other methods. On the other hand, this may cause security issues as several clients may connect to Speech Server and they might originate from different users. For this reason, only those messages that come from the same user should be accessible by default (if not overridden in server configuration).  File: ssip.info, Node: Message History in SSIP, Prev: Purpose of Message History, Up: History Handling Commands 4.8.2 Message History in SSIP ----------------------------- History is handled by the 'HISTORY' command. It can take many forms, described below, that allow browsing, retrieving and repeating stored messages. In each invocation of the 'HISTORY' command there is no difference between processing spoken or not spoken messages, all the received messages are processed. The implementation of these history commands in the Speech Dispatcher implementation of SSIP is still under way. If you want to use them, please contact us to see the current status. There is a "history cursor" pointing to some message in the history. You can move it across history messages and retrieve the message the cursor is pointing to, using the 'HISTORY CURSOR' set of command arguments described below. 'HISTORY GET CLIENT_LIST' List known client names, their identifiers and status. Each connection is listed on a separate line in the following format: ID NAME STATUS where ID is a client id that can be used in other history handling requests or in the speech output control commands (*note Speech Output Control Commands::), NAME is the client name as set through the 'SET SELF CLIENT_NAME' command, and STATUS is '1' for connected clients and '0' for disconnected clients. IDs are unique within a single run of Speech Server. Sample SSIP reply: 240-0 joe:speechd_client:main 0 240-1 joe:speechd_client:status 0 240-2 unknown:unknown:unknown 1 240 OK CLIENTS LIST SENT 'HISTORY GET CLIENT_ID' Return id of the client itself. The id is listed on a separate line in the following format: ID Example: 200-123 200 OK CLIENT ID SENT 'HISTORY GET CLIENT_MESSAGES { ID | all | self } START NUMBER' List identifiers of messages sent by the client identified by ID. If the special identifier 'all' is used, identifiers of messages sent by all clients are listed; if the special identifier 'self' is used, identifiers of messages sent by this client are listed. NUMBER of messages is listed, starting from the message numbered START. Both NUMBER and START must be positive integers. The first message is numbered 1, the second 2, etc. If the given range exceeds the range of available messages, no error is signaled and the given range is restricted to the available range of messages. Messages are sorted by the criterion used in the last client's invocation of the 'HISTORY SORT' command. If no 'HISTORY SET' has been invoked yet, the messages are sorted from the oldest to the newest, according to their time of arrival at Speech Server. Each message id is listed, together with other information, on a separate line, in the following format: ID CLIENT-ID CLIENT-NAME "TIME" PRIORITY "INTRO" CLIENT-ID is a numeric identifier of the client which sent the message, CLIENT-NAME is its name as set by the 'SET SELF CLIENT_NAME' command (*note Parameter Setting Commands::). TIME is the time of arrival of the message, in the fixed length 'YYYY-MM-DD HH:MM:SS' format. PRIORITY is the priority of the message, one of the values accepted by the 'SET SELF PRIORITY' command (*note Parameter Setting Commands::). INTRO is the introductory part of the message of a certain maximum length, see the 'HISTORY SET SHORT_MESSAGE_LENGTH' command. INTRO does not contain any double quotes nor the line feed character. All the message identifiers in the history, regardless of clients that issued them, are unique within a single run of Speech Server and remain unchanged. 'HISTORY GET LAST' List the id of the last message sent by the client. The id is listed on a separate line of the following format: ID If the client hasn't sent any message yet, return an error code. 'HISTORY GET MESSAGE ID' Return the text of the history message identified by ID. If ID doesn't refer to any message, return an error code instead. The text is sent as a multi-line message, with no escaping or special transformation. An example SSIP response to the command: 200-Hello, world! 200-How are you? 200 OK MESSAGE SENT 'HISTORY CURSOR GET' Get the id of the message the history cursor is pointing to. The id is listed on a separate line. Sample SSIP reply to this command: 243-42 243 OK CURSOR POSITION RETURNED 'HISTORY CURSOR SET { ID | all | self } { first | last | pos N }' Set the history cursor to the given position. The meaning of the first argument after 'SET' is the same as in the 'HISTORY GET CLIENT_MESSAGES' command. The argument 'first' asks to set the cursor on the first position and the argument 'last' asks to set the cursor on the last position of the history of the given client. If the argument 'pos' is used, the position is set to N, where N is a positive integer. It is an error if ID doesn't identify any client or if N doesn't point to any existing position in the history. As for the order and numbering of the messages in the history, the same rules apply as in 'HISTORY GET CLIENT_MESSAGES'. See above. 'HISTORY CURSOR { forward | backward }' Move the cursor one position 'forward', resp. 'backward', within the messages of the client specified in the last 'HISTORY CURSOR SET' command. If there is no next, resp. previous, message, don't move the cursor and return an error code. 'HISTORY SAY ID' Speak the message from history identified by ID. If ID doesn't refer to any message, return an error code instead. The message is spoken as it would be sent by its originating command ('SPEAK' or 'SOUND_ICON'), but the _current_ settings (priority, etc.) apply. 'HISTORY SORT { asc | desc } { time | user | client_name | priority | message_type }' Sort the messages in history according to the given criteria. If the second command argument is 'asc', sort in ascending order, if it is 'desc', sort in descending order. The third command argument specifies the message property to order by: 'time' Time of arrival of the message. 'user' User name. 'client_name' Client name, excluding user name. 'priority' Priority. 'message_type' Type of the message (text, sound icon, character, key), in the order specified in the Speech Server configuration or by the 'HISTORY SET MESSAGE_TYPE_ORDERING' command. The sorting is stable -- order of all the messages that are equal in the given ordering remains the same. The sorting is specific to the given client connection, other connections are unaffected by invocation of this command. 'HISTORY SET SHORT_MESSAGE_LENGTH LENGTH' Set the maximum length of short versions of history messages to LENGTH characters. LENGTH must be a non-negative integer. Short (truncated) versions of history messages are used e.g. in the answer to the 'HISTORY GET CLIENT_MESSAGES' format. 'HISTORY SET MESSAGE_TYPE_ORDERING "ORDERING"' Set the ordering of the message types, from the minimum to the maximum. ORDERING is a sequence of the following symbols, separated by spaces: 'text', 'sound_icon', 'char', 'key'. The symbols are case insensitive and each of them must be present in ORDERING exactly once. The specified ordering can be used by the 'HISTORY SORT' command. 'HISTORY SEARCH { ID | all | self } "CONDITION"' Return the list of history messages satisfying CONDITION. The command allows searching messages by given words. The output format is the same as the 'HISTORY GET CLIENT_MESSAGES' command. The meaning of the first argument after 'SEARCH' is the same as the 'HISTORY GET CLIENT_MESSAGES' command. CONDITION is constructed according to the following grammar rules: 'CONDITION :: WORD' Matches messages containing WORD. 'CONDITION :: ( ! CONDITION )' Negation of the given condition. 'CONDITION :: ( CONDITION [ & CONDITION ... ] )' Logical AND -- all the conditions must be satisfied. 'CONDITION :: ( CONDITION [ | CONDITION ... ] )' Logical OR -- at least one of the conditions must be satisfied. Spaces within the condition are insignificant and ignored. The following rules apply to WORDs: - WORD is a sequence of adjacent alphanumeric characters. - If WORD contains any upper-case letter, the search for the word is case sensitive, otherwise it's case insensitive. - WORD must match whole word, not only its substring. - WORD can contain the wild card characters '?', substituting any single alphanumeric character, and '*', substituting any number (incl. zero) of alphanumeric characters. Returned messages are sorted by the following rules: 1. The primary sorting is defined by the number of the satisfied subconditions on the top level of the given condition, from the highest (best matching messages first) to the lowest. This takes effect only if the given condition is the OR rule. 2. The criterion used in the last client's invocation of the 'HISTORY SORT' command. If no 'HISTORY SORT' has been invoked yet, the messages are sorted from the oldest to the newest, according to their time of arrival.  File: ssip.info, Node: Other Commands, Prev: History Handling Commands, Up: SSIP Commands 4.9 Other Commands ================== 'QUIT' Close the connection. 'HELP' Print a short list of all SSIP commands, as a multi-line message.  File: ssip.info, Node: Return Codes, Next: Appendices, Prev: SSIP Commands, Up: Top 5 Return Codes ************** Each line of the SSIP output starts with a three-digit numeric code of the form NXX where N determines the result group and XX denotes the finer classification of the result. SSIP defines the following result groups: 1XX Informative response -- general information about the protocol, help messages. 2XX Operation was completely successful. 3XX Server error, problem on the server side. 4XX Client error, invalid arguments or parameters received. 5XX Client error, invalid command syntax, unparseable input. 7XX Event notifications. See *Note Events Notifications in SSIP::. Result groups 1XX and 2XX correspond to successful actions, other groups to unsuccessful actions. Only the groups defined here may be returned in an SSIP connection. Currently, for return codes in the range '100'-'599', only the meaning of the first digit of the result code is defined. The last two digits are insignificant and can be of any value. Clients shouldn't rely on the unspecified digits in any way. However, the return codes in the range '700'-'800', reserved for events notification, are well defined in the appropriate section of SSIP documentation and client applications can rely on them. In the future, these return codes should be fixed so that clients can rely on them. * Menu: * Sample SSIP Dialog::  File: ssip.info, Node: Sample SSIP Dialog, Prev: Return Codes, Up: Return Codes 5.1 Example of an SSIP Dialog ============================= The following example illustrates a sample dialog with SSIP. The client connects to a Speech Server, sets all the common parameters, sends two text messages, displays the list of clients, instructs Speech Server to repeat the second message, and closes the connection. Lines starting with a numeric code are response lines of the server, other lines are the lines sent by the client. SET SELF CLIENT_NAME joe:vi:default 208 OK CLIENT NAME SET SET SELF PRIORITY MESSAGE 202 OK PRIORITY SET SPEAK 230 OK RECEIVING DATA Hello, I'm am SSIP communication example! How are you? . 225 OK MESSAGE QUEUED SPEAK 230 OK RECEIVING DATA Still there? . 225 OK MESSAGE QUEUED HISTORY GET CLIENT_LIST 240-1 jim:Emacs:default 0 240-2 jim:Emacs:default 0 240-3 unknown:unknown:unknown 0 240-4 jim:Emacs:default 1 240-5 joe:vi:default 1 240 OK CLIENTS LIST SENT HISTORY GET LAST 242-39 joe:vi:default 242 OK LAST MSG SENT HISTORY SAY 39 225 OK MESSAGE QUEUED QUIT 231 HAPPY HACKING  File: ssip.info, Node: Appendices, Next: GNU Free Documentation License, Prev: Return Codes, Up: Top Appendix A Appendices ********************* * Menu: * Key Names:: List of the symbolic key names. * Standard Sound Icons:: List of the standard sound icon names. * Standard Voices::  File: ssip.info, Node: Key Names, Next: Standard Sound Icons, Prev: Appendices, Up: Appendices A.1 Key Names ============= This appendix defines all the recognized symbolic key names. The names are case sensitive. Special Key Names ----------------- 'space' 'underscore' 'double-quote' Auxiliary Keys -------------- 'alt' 'control' 'hyper' 'meta' 'shift' 'super' Control Character Keys ---------------------- 'backspace' 'break' 'delete' 'down' 'end' 'enter' 'escape' 'f1' 'f2' 'f3' 'f4' 'f5' 'f6' 'f7' 'f8' 'f9' 'f10' 'f11' 'f12' 'f13' 'f14' 'f15' 'f16' 'f17' 'f18' 'f19' 'f20' 'f21' 'f22' 'f23' 'f24' 'home' 'insert' 'kp-*' 'kp-+' 'kp--' 'kp-.' 'kp-/' 'kp-0' 'kp-1' 'kp-2' 'kp-3' 'kp-4' 'kp-5' 'kp-6' 'kp-7' 'kp-8' 'kp-9' 'kp-enter' 'left' 'menu' 'next' 'num-lock' 'pause' 'print' 'prior' 'return' 'right' 'scroll-lock' 'space' 'tab' 'up' 'window'  File: ssip.info, Node: Standard Sound Icons, Next: Standard Voices, Prev: Key Names, Up: Appendices A.2 Standard Sound Icons ======================== There are none currently.  File: ssip.info, Node: Standard Voices, Prev: Standard Sound Icons, Up: Appendices A.3 Standard Voices =================== The following voice names are always present in the output of the 'LIST VOICES' command (*note Information Retrieval Commands::): 'MALE1' 'MALE2' 'MALE3' 'FEMALE1' 'FEMALE2' 'FEMALE3' 'CHILD_MALE' 'CHILD_FEMALE' The actual presence of any of these voices is not guaranteed. But the command 'SET VOICE' (*note Parameter Setting Commands::) must accept any of them. If the given voice is not available, it is mapped to another voice by the output module.  File: ssip.info, Node: GNU Free Documentation License, Next: GNU General Public Licence, Prev: Appendices, Up: Top Appendix B GNU Free Documentation License ***************************************** Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See . Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. B.1 ADDENDUM: How to use this License for your documents ======================================================== To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (C) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.  File: ssip.info, Node: GNU General Public Licence, Prev: GNU Free Documentation License, Up: Top Appendix C GNU General Public License ************************************* Version 2, June 1991 Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble ======== The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 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 this service 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. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION =============================================================== 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS Appendix: 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. Copyright (C) YYYY NAME OF AUTHOR This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) YEAR NAME OF AUTHOR Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than 'show w' and 'show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. SIGNATURE OF TY COON, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.  Tag Table: Node: Top221 Node: Introduction1541 Node: Purpose1727 Node: Protocol Philosophy3305 Node: Higher Level API5695 Node: Basic Terminology6596 Node: General Rules7755 Node: SSIP Commands11250 Node: Speech Synthesis and Sound Output Commands12648 Ref: SPEAK13066 Ref: SSIP KEY15832 Ref: SSIP SOUND_ICON16883 Node: Speech Output Control Commands17148 Node: Message Priority Commands19356 Node: Priority Categories20536 Node: Priority Diagram24314 Node: Priority Setting Commands25251 Node: Examples of Using Priorities25868 Node: Blocks of Messages Commands26673 Node: Parameter Setting Commands29213 Node: Information Retrieval Commands39584 Ref: list-output-modules40034 Node: Message Events Notification and Index Marking41862 Node: Why Events Notification42259 Node: Types of Events43326 Node: Events Notifications in SSIP46229 Node: Switching Notifications On and Off47855 Node: History Handling Commands49915 Node: Purpose of Message History50177 Node: Message History in SSIP51396 Node: Other Commands61279 Node: Return Codes61528 Node: Sample SSIP Dialog63013 Node: Appendices64271 Node: Key Names64589 Node: Standard Sound Icons65455 Node: Standard Voices65640 Node: GNU Free Documentation License66231 Node: GNU General Public Licence88671  End Tag Table speech-dispatcher-0.9.1/doc/figures/0000755000175000017500000000000013372573660014342 500000000000000speech-dispatcher-0.9.1/doc/figures/priorities.txt0000644000175000017500000000121011447133617017201 00000000000000 ___________ | IMPORTANT | `-----------' . / \ / |p| \ . . . . . . . |r| . . . . . . . . . . message ----> |i| <---- text . . . |o| . . . progress ----> |r| <---- notification . . . |i| . . . . |t| . . . . . . . . . |y| . . . . . . . . . doesn't interrupt interrupts itself itself speech-dispatcher-0.9.1/doc/figures/priorities.png0000644000175000017500000002740711447133617017166 00000000000000‰PNG  IHDR° ZJą>sBITŰáOŕ IDATxœíwxGúÇߕel0–…m\0ŕ\Ŕ-ŒŠ.”˜ Đ.r@w@|„đK …L -p H. 1B ˝—¸Ŕ›#4ƒąl\0ޞôűcŒNHŤŐŞíŽ4ďçááYíNyWZż;ówf­V ˆËąyóćˇŢzKl+ŚNşvíZą­@ؑ‰m‚ ˆT‹mâ@Ǝ›¸jÍ&ą­@ęHŮ´.ić;b[p-DA:Đ!"‚ԁA¤tˆ‚ u CDŠ"‚ HčAę@‡ˆ RfӎŸ‚á¸ZXę3;É]l­(•"[ˆ‚ u` ‘vô8ŘäA("b]Ÿş°Tkęžďzë_ÓÖ ˇnœĚ¸Öbu'-*Đ8EˇŔżRĉŔ.3Âýż|SÇŹgüŒŮ3ŚNrÂĎp.;Mbc]ˆ“‚-DÄ şś’A‹Ě ÉĆúQ?=kÉú“q´ š-与šoÁOÁčŸá_)âD` ą?>ÂŔјň#ĆX+Ź"~M÷;ą-u!N :DÄ9°ÝCaˇ1 v™*°¨/P śŠŔŽ0 :DÄţ°Ń꜑)­Đžc–ŽY P)"}°ËL;ÜA3úáxĆcÍŹÇŚŠĺS5ÇUîąf݀‰q!$ąŠ w_ĆąDŚNňŹq:Đ!"öÇlT3k#Ń.ƒČܕr„^;¨RÄš@‡H;–Ćîœ1•kŕNc…sąô^¸?ZW&âÔ CDěëÜtˆsƒ*‚ u` ąŘD\l!"‚ԁA¤tˆ‚ u CDŠ"‚ HčAęŔ°WćŰo6űÍfą­@§[ˆ‚ u0Z-ĆÓ"‚` AD:DA:Đ!"ŇĺŃŁGb›€Đ:DD˘üňË/óçĎŰ „.pP‘(}úôšvíÚýű÷Ĺ6ĄtˆˆDiذayyyAAŻŻŻŘś ´€]fDŠ\ştééÓ§Z­vŊbۂP:DDŠ,]ş”üë_˙ׄ*°ËŒH??żÇ€LĆTTTÖŤWOl‹*Ŕ""9ţřăâ ÝänvÆ b[„Đ:DDr,Y˛”žŠ6í"`˖-"„P:DDrěŮłşýšóč‰CŕęŐŤb[„Đ:DDZ=x Sg5áU™LVSSóĂ?ˆmBčią|ůr­xŐoŰŠ•\.o ëׯŰ.„ Đ!"҂ÄŮtŒ&‡Žę çϟÓ&„Đ!"˘şşúć͘đÎä̤żbŚ˘˘âôéÓ˘š†P:DDBlذAŁŃşťËűîNÎ4Tx5i8etˆˆ„ 6­ÚFčŸě7¤=zT“Ş@‡ˆHˆ+WŽŔ艃őONMĹĹĹŮŮŮ★P:DD*üđĂjľZ&“ž8H˙|“ŚžţJx° Ž""HlM‹ˆćršáî¸=úĆŔž}űD0 Ą tˆˆT ą5CG%_ššôČËËSŠTB›…Đ:DDœ>}ş˘˘‚a˜Ie|ľUt¸WðlŮ2ÁMC("" HTM“f ^Ź bťĆŔ?ţ(¨Ye CD$‰Ş!6ŹLúűH¸uëVeeĽpf!”ŸěěěââbxaĂĘ+}ăęy¸kľÚľk× hBčń!ń4žţĘ&M8’ľiß|ó@f!ôOÓŁO,w˛żL ׎]Óh4B˜…Đ:DDdT*U^^Lý§Éţ2áqýÝÜdjľzǎ‚˜†P:DDdH$WĂ­˘ĂšSĘd˛°¨?8tˆˆČHUc–×˙Ň._žěX›ZA‡ˆˆIeeĺ­[ˇŕYTY&NÁ0Leeĺ‘#GlB#č1Yťv­VŤ­çáţJß8>éë7đl +WŽt°i CDĄÄАíFy2pXO8yň¤ŁlB(""ćÚľk0öíĄüs‘…JKK˙ýď;Ę2„VĐ!"˘ącÇľZíć&>n˙\ýü} 99ŮaŚ!”‚ =ő'™Ě˛ç°Wż8pŕ€CĚB(""$zfŘŘţ–f|'é/ŸŸ˙đáCű›…P :DDŽ9RYYÉ0Ě[4ořK/zű4€ĽK—:Ŕ4„^Đ!"â°jŐ*h\ż§Ůşˇ€]ťvŮŮ,„nĐ!"âpâÄ xCc“fŒ€;w•ŮÓ,„nĐ!""đď˙ť´´žĹĐXAÂ+í=<ëiľÚŐŤWŰŐ4„jĐ!""@"fü}úY]HL§V°}űvť™…P:DDHÄ ‰žąšń“_€ëׯăňˆˆ˝@‡ˆÍÇóóóáYôŒŐ ŃŰMîV[[ťeËűX†P:DDhHʌˇÂ+üĽMĽ b:1täؙLŮşlܸŃaĆ"t+˙J{Ž4yÚËÄtČÓ^&˙X}âˆń --Í1–"ԁ”˛˛˛;wîŔŰ˙m61q‹şccŸ8nňë ĂTWW˙úëŻöľĄtˆˆ Ź^˝ZŤŐzxz$ô`ińYЧg˝ĐCHąś—† čA!Q2m;ždŻ˝ńg8}ú´˝ Dh""ćúőë0~ň0>éőűČDO4N3yÖX(++KOOˇ“™˝ CD„c˖-ľľľnrˇ!#űđIOtCňŐ€Żż20ŘpyDÄ CD„ƒÄÇDśjÁDÝ(3GšŢťŔáÇmˇĄtˆˆpř˜áă-X›ď$€‚‚‚{÷î١d„6Đ!"ą˙ţęęj†aĆOyĂlbý¨lł‰˙Ö̧‘7,Y˛Äv;šA‡ˆÄ_|Ą/†xzÖ3›X×Sćî,ëčŇł#ěŢ˝ŰF#ĘA‡ˆ‰Œ!Q2vgňĚ1p˙ţ}˛Ş‚X:DDŇÓÓÉJŽ$JĆîtŒŽßŔSŤŐâöˆ- CD„€,čěďëŻtPíc_€;w:¨|„Đ!"BpčĐ!xă ޜúdggŤŐjÇՂ¸6č‡sďŢ˝‚‚xă  ë)w—k4šM›69ŽÄľA‡ˆ8 ăÓČűOaÍř¤7X‘cID^j)))6‹P\lׇDĂtéёgzÝbˆÄ ňŒź€Ń]ů=+##Ă*3[ˆˆƒ)--˝˙>Lž5ĆŇźüă ŁßzM&“ŐÔÔ¤ŚŚZZ‚śGłrĺJ­V Ż&LdMŕ^O~ŻęźEevxaŕý;y ÖŽ];dČ‹ĘDŔ"âhŁ5sýěŮłöŻĄtˆˆcÉĘĘҚ`˙ţýś”<}útS%?}úÔ^ö#T]fD4†a=Ż?žL,RÄjĐ!"’Ý"čäŘącŢŢŢmŰś•Ë-~ÂóóóľZm@@Ă0xLŰ1čd—üüüźźźÚÚZ<ĆcSÚ7ćƍ<ŕ™ţŔŕ^OŽżŘŸM›§†¸oß>`&44třđá ,Řłgϝ;w4YŤ<== ˘˘Š:öđđ€˙9Äƍë^âŤT*‡ŚˇîŘßߟg˝ÖŮc\>÷yÇÝ96‹JĽ:}úôć͛˙ůĎ4( @.—7jÔ¨°°Ov­#˘VŤ 3ný)•ĘnÝşM›6퍯ž:ţ|YY™qĆĐĐĐŔŔ@ňG˘ÜźyóŔŔŔĘĘJÖóĆÇ$ IoœF˙źńąu6˜*‡ť.îô|Ę7uďüË7őÝZš†$Ď˙:ţţţ2™ŒlvĄܸqcťó/“híüˡ4˝uÇnnn|ęĺoţwb\>÷yÇÝWYYY˝ző …nĐŁşşúÖ­[7nܸqăĆőë×ÉAaaĄąÇIJJňőő5>/<+VŹ8p ťťűęŐŤłłłŻ\šňű￝}účŃŁÖ­[sxĂňňň?ţ>űě3 žPçϟÉÉÉÜsWÖ­[÷Ă?řřř,^źřöíŰDGB¨˘¸¸¸¸¸¸Î!ćää\ż~˝śśV\›)E6ÉKJJĘĘĘâHźjŐŞ‡vęÔiذav´˙ˆÜôíŰ7...??ÝşuŚŇ¤§§Ďš5 6nÜřꍯFFFVUUŮX/ât””””””Ô9Ą„„¨¨¨Ç‹k" …Ď!CŢ|óÍňňň1cưŽ<@aa!YüuѢEŚćáY‡Ľ q0oŢ<0ÝH,-->|xeeĺÔŠSßxăđđđˆˆűŢ â(•JĽRYçĂÂÂ"##qˆ€ÜÜÜââb//ŻUŤVľhŃ"==ýĂ?dMšxńââââž}űöěŮS`#ůC‰*•jíÚľĆWß~űí›7oĆÄÄ,[ś 233Ż_żŽ"…8Ä:‡xćĚ™ŹŹ,‰D!âRZZZRR˘Őj˝˝˝żýö[77ˇĽK—?~Ü Ů˝{÷ÖŹY#“É-Z$†™@”ÄĽK—’­Pu|ůĺ—ß˙=Ă0qqqîî}ăĆ Ô)5D„ĽRůôéÓęęęŸţYŁŃh4šqăĆé'›?~eeĺˆ#bbbÄ2•'}úô‰WŠTúJbFFÌ3€a˜uëÖőęŐëÁƒŃŃѨ!Ň jˆ; …BĄPܸq#66vɒ%nnn͚5ťwďޔ)StiŽ]ťśuëVww÷O?ýTDSůcĐH|ňäɈ#*++'Ož|ôčŃ&Mšœ8q"&&&885D:yNClٲedd¤Ă&áš˙ţ˘E‹şv횞žŢ˛eËS§N?~ÜŰŰűűďżßśmI3wîÜÚÚÚˇß~ťE‹ްA7ÄlŻáćŢ˝{'$$č”ÄżýíoŮŮŮmŰś]ąbE÷îÝÓÓÓűô铟ŸçΝaÆĄ˜N!DCüßâ˘ŐjóňňúöíK‘ &uꔿż?ëd8‰Cb`ҤIŁF2NŐ˛eË>}ú¨TŞ̙3ÇxU Ä%a‰CD ‘NŇŇŇ:tč°~ýúzőę-[śŹźźź´´T×6Ôáëëťe˲PŘÜšs …ĆÚi$śiÓĆÔ29999ű÷ď_´h‘L&[źxq=Ȟ҈kó\"ÎeŚFłdɒ¸¸¸ŹŹŹÖ­[_źxqć̙eee$Ń8}Ż^˝fΜŞ?âě\,X°ŕ—_~Š_ż>ëU‡Č0ĚűďżěŘąŚM›ž>}:&&ć×_ŘND`0‘vîݝ׍WŻŮłg×ÔÔLŸ>ýŇĽKmÚ´˝8DÖ\ .ܸqŁóÎĺčÖ­[hh¨ŠŤúqˆ]ştIOOďßżAAÁŔgϞÝgăŠćűᅬŽŽ>~üxppđţýűW­ZEö—€gqˆŚ2şťť÷îÝ[(3…&<<<22R‡čďďżwďŢŋťšš-Y˛¤{÷î÷îÝ×BÄA`"Ľ”––Ž7näȑEEEƒžrĺŠ.Ά››[RRbŹ!Ň@fffVV–~ű—a˜Ůłg?~źYłfgϞ‰‰Ůťw݈"5D9sćLŰśmˇmŰćĺĺľaÆÔÔT˛É”>ĽĽĽĽĽĽŹ˘Ëcj.sBBBzzú€  ”””TSS#Š…ˆƒxNCÄ8D—§ŚŚćĂ?ěŢ˝űüŃącÇ´´´ˇß~›5eHHˆ÷ŠŞv{†œnŽŠíÓTřĂ1—ŮĎĎoϞ=K–,‘ËĺK—.íŢ˝űÝťw3 q4ĎiˆńńńQQQł÷—!''§K—.Ÿ}ö|đÁgΜяI6€hˆâÎç%ťŠčţ ćÉv1Śîa˜¤¤¤'N4oŢüÜšs111{öěĆ0ÄѰhˆ8…Ó%Ů´iSťví.^źzěŘą ĽŽLA4D˛+“(ď-%˜OĚČČ0ťb\\\zzúŤŻžúřńăÁƒż÷Ţ{Ř}vPCt} †:iҤ˛˛˛1cĆdffvíÚŐl.ÝzˆX(5xއčëëť{÷îĽK—Ęĺňe˖uëÖMˇ_ÄÁ8DçĐĄCŃŃŃ?˙üłRŠÜącǡß~Kö3 w˘kĂ=D†af͚uňäÉĐĐĐóçĎÇÄÄěŢ˝[ qˆ.KeeĺŒ3ŮŮŮZ­6<<ܢ{gfÌńńń#GŽźxńbťvíRRR† â8;ťS\\ şę1ŃeHII™4iRzzşuŢPC´vO•Ν;§ĽĽ 2¤¨¨hʔ)8ôě\ ąŽ…HśŕÉĎĎoܸą¸f!6đŐW_ŮR‚BĄ k|QHxxxUU•ŐMăFíÚľkŢźyÆ ăŽmB¤†RŠ€:‡Ř˛eK???ÔČÍÍŰŃČĚĚ´ą†a>ůäťƒ ‰Ápý8Ä­[ˇ2ˆ“&MâţĆ0‘Î{§ŒCDŘA Q_CŹ_żžŘŻ0I0}útxNC$;4ş°†8rôřľ_nŰ ‘ŮśuÓ?Ţ5Ó<ę5Äęęj÷eŚç4ݰ0ÔjˆĆ<ČŻđxś€.mlܰúý$oÂ3 ąÎž9sFTc !‘8DQ°.qHbCźyóŚZ­ Ăo˛˛˛'OžˆľhśnމÍ6řčP˘ŁŁ++++**ƒdŚ a}díu•ë'㶊'‚kˆrť¨!R ‹†čÂqˆü!ކxý—°ŠcîĆŻqçČĚć#oČń‘?˘kˆ"QYYiÇć!pžĽL]2x)ż#͖ŒX ÎeścGŁďC ŕ~L9š–fëŐo˝Zj7˘kˆşae!Ǘ v,ű'ŕxřA0zTŹţqSĐĽ!Úˇ˝ĂáśŔČUą>ĘŹW }ÜľXjD×EY ‘ X"ŸŤ*‚8ˆç4ĜœœÚÚZ—Ôńds? ü;ÔĆmyôíőg#z˘ˆŠ!Úë†Ř…ç4D—ŸËlGX{+vďż˙ľÔkŔŽVŃ<—Ůž"7fV-q¨!˛Ł“Ť9ĆU ş˝`í´ÁUƒAm?ĂĄ˛ÚŔmOD×EÄž˘1Ď7>Š!:MĄKC䏊Źąâç[ŽÚe”Ć JKKŔŰۛfťkˆ’1Ç Ěř­ lę Ž2ŰZ4DWĹq jˆöŐ­xwň|ű˘´#¨!:%4  …›››š‡Bn@JŔšĚԂs™ŇŃq.3"¨!"젆ˆë!R-s™ ;ˇoŮš}‹ŘV8RĐ…ŸŁBŔšĚԂs™v¤ !, +Ś4Ä&őśZâǏ?~üxą­p&¤Ł! jˆÔ‚"ÂjˆúbEE…¸&!€qˆ;RĐĹ5DjÁ8D„˘!Šm…8`"ľĐ˘!"–" QŹ%QC¤Ôv¤ !Šľ$"Ć!R jˆ;¨!˘†H!¨!"젆ˆÍC ÁšĚ;RĐĹ5DjA aGô=UD5DjA a5DÔ)5D„š÷TA ‘Z0aG"˘đŤĂjˆƒ"ŽâĹ5DjA aG "™ ˘żü—0­EÔŠĹp=ÂԐĚzˆ˘t™QC¤–ç4ݰ0ԐŒ†( ¨!R jˆ,ŚVKő!˘†H!¨!"ěHAC ÔŠ…%QĽRůűű“3ĆoHIľ›8šr ĂXmŞ-÷hK˝bÁjł4ă…‘QC¤3s™ľZ­Á_‹3ţÁ#V  ‘ŒŤč RÔŠĹb ‘ŐEę_5HĎ˙Ş~[Ś$;wŐMe1k•ŮzM]ҝ'_ŻA>WSÚhłt4DáG™EŃYë˛ôąwşĆŠÔlśUCän?ň˙hě şĂ}qĆ^›FV{xZĹ]/ÇíëÜkvłW ü włÎfÔÖ­{ÔűbÓ\fă_N˙Ż‹űŞüOŠŽuVńü6¸ ˇ‹*Ęómë!ŠŢ4ևŞŢ ŤÍĆWc×Cä~¤ žb°ü†Ľé1M!Š?0łHDC jˆTőNŒ öˇăŘ8Dn‡ĹĄEş$Î垼Ł! dă)éŘąvKyNCźyóŚZ­ćÖ Ţ-ÜoV—'ź_B˝‚}ŹĂ/[ŽJuVĄ†čJqˆRóě|°˝i†s™ 4Dł|VeÁÔUăÜşůÓŐĽąb\ĹT˝ŚĐĎbJᶊŁ^ŽoCż4ăŒÜWYK6ţŽLĺ5e3jˆÎčDLá\˝‚(=Hóqˆf‹°şĽÍó’]ÚęvÉÂÓ*+.ŮŢ[ąąă¨!:5NÝ;ąŻUs™]ý6žEîŠ"b"ĺ˝㌬yÎevqŹ~ŒD×uTtŮĆg„¸qˆfŻş|ď„Őv÷TAŘ}=DăĹ[Ńő4DQ°şw""¸/3Ž4D(Řbą. !Jgq‚ú¸Ž†č\/"éƒ˘ăGC4ÄşUžnŢźyýúőÚÚZQMr=lO&5BBB”JĺÓ§Om)¤śśöâŋŤWŻŽŽŽśŽÝj7Bî%YUU%Luˆt()))))1‡čDX4+Ćž5rx:GÔ+ d=D+œřÝťw/\¸pţüů3gÎ\ž|šśśś_ż~ďžűŽ#Œä ˘˘âʕ+íۡˇbK —ŃąŰd)¸/3Â ąźźü÷ß?˙Œ$HJJ˛ĹëĆRęׯ?sćĚóçĎ+Š^˝zľmŰ6:::::şYłff=jˆVĂ3PFřxž¸‚†höË5;ßĆşé4<­â’2s™ľZí͛7uđʕ+jľZwŐÇÇ'!!ĄsçΡoßţúëŻ[ľjŐŁG[,ąşł<<œ8Gâ%CBB\o.3ÂŒC|ăś!k\ž“ú8‹0ĐwîÜ9eĘÝŐŕŕŕŘgtčĐĄAƒŮ÷ěŮsăƍ^xáő×_ˇÎýŹn$&'''&&fdděÚľËËË >|˜™™™™™yĺʕĚĚĚ7n\ťvíÚľkß}÷Éâĺĺ%—˝şyˆÝ&ë@ ŃĚ NýWa âäɓÓÓÓżúę+ww÷˗/ˇiӆ;{rr2̘1ĂęÇÉ.cĘ}űö‹‹;wîÜúőëNŤ7łIDATß{ď=NLL$ ŞŞŞţóŸ˙č\äĽK—ĘĘĘärůž}ű<<=00’Ú,ĎźŠn“ŕv9„âââââbşâů‡˛N\w™ßžă8Äzőęýřă!!!'OžüÇ?ţÁ‘wéŇĽ0eĘ)ŹĽ˜˜˜›ŸŸ˙ĺ—_r$SŤŐŁFRŠT‰‰‰ëÖ­Ł<‘<ůŚBh#IJÓî8Ä:‡őřńcqm˛ý_ĹÔ/¤˙› ˘ƒőíǚ—ť^ł&I…BAşúíÚľËÓÓsÝşu›6mb͘“““ššęéé9mÚ4Ǜɋyóć@rrryyšŠ4~řáŠS§š6múÍ7߄‡‡GDD8ÝOfG¨í6)•JĽRYç[ślét"ϟÇÔU‹2ę'ŕŽ×ٟ˜ÜÜÜââbă&^§NHSkÚ´içΝ3θ|ůrF3věŘ   ! ĺAbbbçΝ=z´~ýzÖű÷ď_˛d‰\.ßšsgăƍ333Ż_żîÔ˘Ľ`ˇ‰ŕăăăăăCľ†ˆ°RZZJŚ3_?~üđáĂŤŞŞ† f†­RŠśnÝ*“Éf͚%”Ľźŕh$ŢżܸqćÓO?íŇĽ dgg߸qĂéŢaú`ˇÉ:žÓsrrhĐ>„„„řřř°D¤¤¤ěŢ˝>|8tčP}­m͚5ŒŒŒÎVôëׯS§N=2PŐjőȑ# ”Jĺ¨QŁČI˜ËŒÝ&ëxNCLHHpF q …ÂxŠ2Ä}úŹYłĆĂĂ#%%eăƍťwďöňňúúëŻWŻ^ [śl)((ˆíÚľŤx†›¤˙ţ;vĚËË۰a9łoßžäädš\ţË/ż 8°°°đŐW_={öĺ˗iÓŃŮş͐žƒFŁ!ÓŇŇBCC I“&çϟ×%űîťď†qww˙íˇßZ´h?ţřŁE}:˙şöîÝ AAAĺĺĺwďŢőóó€Ď?˙\ŤŐj4š%K–¸ťť@ťvíŽ?Žťw„6PCD Ń×wîÜŮĽK—;wîÄĹĹ]ž|šsçÎşd#FŒ˜={vMM̀ţűß˙ślŮrȐ!âYm]#q͚5#GŽ,,,0`YŒ‡a˜¤¤¤cǎ5kÖ,--í•W^ŮłgŘö"Bƒ"ÂŃ5ÍěٳnjS^^>qâÄcǎ¤\°`Aż~ýČÄ̙3Ľ,š0 C&Žź˙ţűgϞmŢźůÖ­[őľÂ„„„´´4oooxíľ×ćĚ™Łżâň¸B"ârssoßž=|řp ˇf͚M›6ąĘj2™lǎáááţţţăǏŢT‹0`@‡4ťťűΝ;IŻY˙’’’Ĺ‹Ëd˛Ĺ‹÷ěŮS ŰË Â€qˆ;/^ěĐĄĂÁƒ>üÎ;ďp$V*•ŠŠŠsćĚ1^öFjč‰ .ŒgM“““3dȐŁG6mÚôÔŠS111ÖLDhœËŒ˜%55566öÖ­[ŃŃї.]ęŢ˝ťŮ,QQQ3gÎŔ6Ű8p`RRGč8‰CěŘącZZZbb˘JĽ0`ŔÜšsąűěň ąn”™,ƒ˜ŸŸ/î""ľľľóćÍ#˛šťťťJĽrtd”Ůj,ećI›6m"""*++ľZmmmí… ‰ŽÔ­[ˇÜÜ\ťW‡HňPĄ†ˆ|řp•Jžšše5D>ű2;vl̘1> Úž}{Ϟ=…ąq¨!ŇČ_|A‚Ťú÷ď_TT̆hˆeeeŰ&¸5DňňňzőęnnnóçĎŻ­­u´yˆă¨ó‹äjˆ.Oeeĺ›ož Ăź˙ţűř×kÔjľ. §WŻ^yyyb[„X jˆńŕÁƒĄC‡^¸pÁËË+%%eřđá‰QCä֍9räČŘącóňň‚ƒƒˇoßŢŁGÇYˆ8Ô]ŸsçÎ 6ěáÇ/źđBjjjtt4wzÔůhˆäĺĺ=úŘącnnnóć͛;wŽL&s‘ˆ#@ ‘ˆěŮł'ĎéÉMš4Q(‡h)jľúŁ>"~°wďޏ=˛ťyˆă nąŽ…_TTtöěY\Ěő(,,üä“O–/_ŽÍŤYż~ýÔŠSĹśÂůđőő-,,Ű ^(•J¨[ÍáěŮł˘ƒ8??żUŤVńO˘Ľ"âƒÎ!˘†ˆč ĄVCŒŽŽćĐߜ8eéŠuÂ[ĺŒ=nj¸&š”!bCLHHPŠTůůůDLDhFĄPČd2:›HD@¤óŢ)çš.s˖-ýüü첢VŤĹń5éăééYQQÁz‰ćD222Ä6@ 1Ś´´ź˝˝)l(Ą†H-ŽŐ†)(ŃŘĽ(ÄžTUV6 ¨Ď‘5D+âg5D„˘!Šm…8„‡‡WUUaóBĽ!"ÎÍbffŚ]ĘńS0PXŞ%äŘŕŞî$wƒóĆ%čę˛{ÉŚîËÔU§5D„ŒC´]C$~ĘOÁč‡ţąÎ[éű2}ôs4(Áž%dçžęě ąŽg”““ăÂű2ëżYŻęţYš×qˆU/„„„(•ʧOŸŠe€ˆ}™ŤŞŞěRšžËĐo-ęŸ4ëł ň\5啬(™ĂxKŻ:#d_fWĐÍžŹ8ŽÚ’×ÄŞ—¨!şpӘűEkŕš˝§‹ůD §Š €˘KĂíĹřw¨?:;RŃšĺgý4ŹWÉ%S ř”i*YýŘ@ŘćŸÝj› °fäţ&ů@y˘Fىˆˆ°Ë˝['ş?NúŁą†ČSŞ+ů5Ť‘Ę\fnůŮěGÖßX˙*˜xht—ŹČ FĎşŠěŹUXmłqiĆ*ś+߇hŻ8DłŁĚŚ^]üťŽ)--Ů8Ď1hÖŤNÍsqˆńńń"jˆ­!‹ź‰0°:eƒÔ l߆íß Ís™íŽ!˛ţ|~#ë$fK–ŹŽ-Ďiˆaaaţţţ¨!Z k×U˙ف˘átO—d‘Іč’8őťămCԗ‰ń0¸p×U,¤˘!rĂ-0ł"@‡šżU<_ŕ…He.łî]Ş?˜`1…Tć2{ łiř'°Z?ś1ŸQŤuqž­nD †ˆPjˆ;”Ç!rhˆ_o^˙őćőÂ[…Ŕsâ͛7Őjľ5DDxPCÄő)„hˆuېŘKC$[ŕą’…,Ëą…qˆ<đňňŘ6щŽŽŽŞŞĘĚĚôđđŰDPHŸç2#† †ˆPŃݖőö7™r 8Zˆ¨!âž*ÔRç퇈Ń)ŕpˆŢŢŢÔjˆőë×G ‘N‡Č0öou"BBó\fܗ™Z ç2ăž*f ÷eŚGiˆˆłƒ"jˆÔRç1с"jˆb¸˘óŘ2—™Î&ÎeŚÔvhÖ1‘ZPCDŘA 5Dją"â젆ˆ"…HkOD:Їˆ"ľŕž*;¨!"‚"Â"ľ †ˆ‚"jˆ"•=UЁ{Ş`óB¤˛§ "5PCD(5D„ŒCD ‘ZPCD A 5D A aăéźwĘA a5D„BPCDŘÁ8DÔŠ5DÄÔQC¤Ôvˆ†(śâ€"ľŕzˆ;¨!"‚"ÂĆ!˘†H-¨!"† †ˆ"… †ˆ°ƒ"6)ăvPCD(5D„ÔĂĂĂ ??Ÿa˜€€­V‹Ç”ƒVŤŐjľŮŮŮYYYjľZŤŐćĺĺĺĺĺ‘ó=ŇëŸçslK^SĺHÁ{݋#ňZZ>ëwK¤Ă'OžhéĂÓӓa"#€§§§VŤĹczŽŸÓ üüüš6mŞVŤkjjäryHHˆîX˙<Ÿc[ň’cľZíććŚ_ޏöđˇŮ6đÉkiůŹßm@@@YY™ý[_Î@`` xxxTUUzxxĂ0şc’Ćř<9&C1úÇÜéőËÔĎË]ŚŠrŹ;6.ӔÍÜvrWúyů'Öݗ-y˙i>“č ČMIENDŽB`‚speech-dispatcher-0.9.1/doc/figures/priorities.pdf0000644000175000017500000002624011447133617017145 00000000000000%PDF-1.3 %Ç쏢 6 0 obj <> stream xœÍUMS1 ˝űW¨$K aKţźvڎ^ÚäÖé Zh‡ ‡ţý>yJ€NRNL&öŹW’Ÿ¤÷´wä9ˇßfż\ť;wń9Ňő/č˙NKˆIeYH´%–H’4s+t˙Í}w_(eÎMč+˘\šŃ–~âźtQ9—”ŚĄ¨’ÄęYęî -ç& Ů4\čţÚiŐÄĽRlŃś“ç’HZጠě#čýśKäÓ'ĽPŠg‘ĚĽí<ŔI‡Ŕ>ŠZŮW\×`ěŸ@;Ŕh邯™Ep]œ°KwíˇéĹ ¨šçÚ+ç™ZAcŃšőÉä؀†n4ŸhČÂ)“ĆšŹ;/žDAwź¤Ąť/lożľ˛ž1D7Ƈ7ˆé™ZAł5ľ DA Oʁk•‘ űmáŽBŰírMďWxDŢĄúL+Đm4Ü4Ғ8ŚBŤľ;ĄwG“ép<NW?݇}rR@ÎfRFb5و">q…bԄĖ}I΅ŐĆe­Ÿů˘Ü6´ŕ≵Sçu~VLŠ)Ąž&ąÂśf&¤ĘŠ{ÂŞ`Vd”ŰŤ@°főÄńłŻ,6 °Ç<âz•_'^LmD›ŤyF*2 N÷´qŸjV‚ai•}꼢ě1PľÎc˝^çˇÁĽ0G$"Ôq%ŕ‰TŒŤľnqî–”1Fßń˛č 3ԇfoƒęż˝nöń XĄ‘Ŕ#ŢÁ\ ‘‚‘˛4Ţž›/Çgsc-Úfąs3KFë+wr4œMaŇ߃kEzQ˝ńý0?ďŒ?×ţ%ƒłBa)ö—łÉŔ쏾Ěz´2'Ó濌ńűůęGw2=šśebËßÇÁ–€ĽŤňqvp‚ąÁ•ÜĂŇl˜O§r4,Ô.ĐâűpţŕóxŃÁCĚ =j–2Á§É|1˃ň6”Y–ČU5ţ+P×˝ýţ¸„Ť‚endstream endobj 7 0 obj 741 endobj 5 0 obj <> /Contents 6 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 14 0 obj <> endobj 15 0 obj <> endobj 12 0 obj <> endobj 11 0 obj <>stream xœ…V PSWžäŢ[A¨Ü Ô\ŚőEą(>ęƒN‹€@)R¨€U*#€Q^ň/IH䂐' „ ¨ř˝˛ ZŠXëXeiEŞľŰ˛C+ăv°ş=é;ł'XíěÎÎ$™{ţűŸ˙üçűż˙űĂÁ¸v‡ĂqŢśëŁŘ;˝3rł$â,Ťi…ĹƒcyŐβÄzŔĆ_łä-ÁŢ媜žę8冁ĂÎ űe̞ĂÉŽ4fdJł$)űrË~‹#Ÿş{>1Ś%Âş{Ż‚‹á+Vˇ[ˇĚŸĐí-GLL=iëeŠĘŞňráθíŮ 9ďŒ?v_ťożJˆ­Ľk 5ІlĐęMô$Aőľ(ôĽ% y°tîTĂZ°öŕSK RËW@g¸hz% €Ë“Ÿ€ Vü_ĄšĎř˝śr㖥Żoş˙dúáý§ô‹âŐ,¸gőNH J~,E@ŽÂŠ)“CĎM18uÆHŒ jÜ Ôâýď §ÝeHŕ<őpoN—ßݕ‹6? ¨qœÉŸžťő ?Ż•oO=úfü'zć €o°K3ˆă3ý•-%çRú}âĐxe…\]Y <&ăĹN#ÂŤBUUĄ “äng Ćř–<#-ëńçëYžé‡ŰŸ=f3w"›ÖĎŕł,ËYX„ jCEQó¸użÜ×yëhOeĺIဒaj˛^ŻŤ7(ľ‡Ó4ÁZ1Cúž@GŹłąaNxÍ#ř—xła6`0˜˜;6•uÎĎQPđ„$^(+?Tj(oŚÇᄷmFQ]}ƒLWHĂp§şŚ]çą>ŁŒšŹ-GŤ¨Qk­yéëőJ]a#}đhŽ>ůˆŮáł‘¤FŸ.% ţşŇɍzl ßóŠű#ńą§< ĎçMHBňÇU€w{čĚ­>ň‰˜č!JÎvżĚt5wv‘ÔăÓgΰî(ĚĘ!‚š˛ü1bÇýM|{˜?5†jęďďăăjzgüý‡nČďMl^ŸľÔdáóŠgöĹůĐĂ+ .,ՔÖ.ĽŰ ŰwĘŻ(O*N”œ,nÎbrČŘ÷D넔ö­ŕŽ~ZKPá ĺúChh/Ľ7ĄľT+oD뙞0’/ŢD´ă=ţşł #ľ•>КlŒĐŽÓ+krI*<ŻžŹšÉ˝wř읯Óăë„5EZEýď-5JPK­-UZ^V(T˝h)đ”.fÎėT7ŕ@´(u%ÖӅĐa+1'&wŕQÜ˙zÜŁżźű”AnUTŞ+ʅ˘œ Â ź÷Ü'40ƒLÂĆśĚ9jüüÔř]!rüĆŹäX7˙pޟˇţ 7˝ŕW ×[qjş $ń#_żöŸI8‹A,Xw†NĽŞ %#Čôr]M]uMĐ⠜xłšĺÇŠUłĚŹUŻ–¸~fŤ“ĎdÍí-ýƒ‚z›u/.‹+ڛŸ íÁśĹűˎ3ÇČ =Ý˝ÇZĘĽ­ÂłMőÚÚ:F/0")V)Ť*•B™2§1_“ĂBwĄĽ×•őĐÁy ŃL0I]zk$ŕ^˙ůÖŢÓHŇÎÄń˘żăS—Dšr÷yDÇ Ý¸ŇqáÓzúƯ̈é&Ô)˙Ż›ś ś=k ăCÁEMUľŠ”Éĺe2\§ŚkŐ@°r2uS!°ŇVWWkĐ ďîČՕŐVęQŻ7ÖUjTZz ŕÁ…#u cX'KĽB]U!„‚˝<@6  §|łeƒ+łď]Ŕ:ô::˛Ž 1ě?Gŕ"e endstream endobj 16 0 obj 2602 endobj 9 0 obj <> endobj 8 0 obj <>stream xœV tSe~éňŢYB°M ˆ¸ 3((ët¤B˛ Ú˝iŇfiŇ%I—ź¤Kzh“—&iŇ&mšśĐĘŚŹ˘(hľ3ĂÁÝŁqĐă!UtţŕCĎüI[hAĎĚišÓžűżť}ßwďĎ#b˘79iŐ3[žŮćx'˝DŇŕ=üchKhľŕŇf(7çUk‹AŇíĄš3TP*0š™J=ĂhA z›ÎÁŘMŽj?Đ(†ôÓbŤk´łnđ€ŰŘXj7XĐ(‘äôʉ.Ďńi}ęí".J×KsZ´ÇD_żÇ˛đĐ]šŚt!J¤ŕ|ŃŃ´˝9ţTç.ŘýŽ4˙ŘI 'Ź ˘ć ‚čB0˝Jprął¸8n "@áňG4 8ň7]T3[đՅő˗%l˜??áÜ^xăvÂĽDŚ ďł :­ř‡ŕLÚËşó¸яߠ‰Hp˙÷œxmŠ.eťčGSůŔÜ*\gÓ; v“ÝÚ}#IGbk S1ÂĘ؍ ć6ělŮŽm1EÚb°(Ţ€–’hęn&PŘYМ 9ôßÖn[¸ éôĹŽćŢNŸ0ŕíf)űŇĽËA^čZ&8D!!5ŔÍáfq13qé÷"Ţ\ôŘĹšźÇ„ţ†x鎂SfŽ.>–ŻŞÚ šCý&z˜ź1璠ńľóރ÷ŕ\ś{͝ ĂD†řAŢ[AÔŒ~?(ČPK1ŔNF̜„_$ż‚7[O9~ŇßďŃ'(ô8ƒĆsł„\6ŠÓÍĐҖâCÂ|*8%ÄGQÔŤpPˇ7ťSâ~ž§wR°ľ4[.“IsĘÖÍEĆF†ŕ—AşCq] šˇőm¸š˝dwťű}'++z„ł˝Ś耯ĽłUďQXERv5Ÿşkůs‰2wR#3 cădXŁĂŒ :Á6Ę‘ÖĄY“Ťş—{šôBănëž[”á ˜H"d¸™ö‚ŕ¤V´s6ÖÎ[hÖ7ÔBQuE%Íż€ýę´S‡ŁFÁk˙˙ŠëŒÄ­Ę呸łI~çÇßôwMs˝˛ą+]@ˇˇśv4™‘, udĂvČĐ.^‡ƒőߒL3ŠBRző ƒă€ŰfwXí;č^ę¸Ţ+Ő3Ś"Ł0˝)ŐśˇđšĹKΧ!ą^ôZ…ŻĘcň%PJŤ“ ŸÝœâ ä ™˝:—×Pb2” ftůŚŽąëÜĆ&p‚mw{¸čø:Áˇç?;Ž|éż(דְĚţ,[Q[R§Ť7°ŔŇM'=Żíf ;„uLě`ŢőA4ŐËŔ´Č Óbő0-n6§Ě^>D‹Ő—HÔX+XŚQËb¨AodĘpJPŇ ˛Š;;>¤Ńýœ”üËĹdDžůÄÓzJxĐăp‚ë§UQn23Zá.őŽňdČšľĚYa5łŕŁŃVjţOš„楹 1ţWЏaü0¸Ćߥő1gŕ&ŒĆ>bś a˙ýœťĹú č2É(AIně 4ö§0Kƒhwd„IƒŃ!ë ůF͢ˆ‚Ůá:É-›TĽŰ€^'o=%Bűđ\SL5ŻM˝×ŇPçĆ'a}ó‹‡sťň–ƒłĐĺ:}‚Ţń5rĆÍęËÔÍácœ~  ČVh“ŠąäfgďŹßŔš"ÜŕĎşC8˙Ąs–|šĹÓq&ň6+Äš]Kpřőáđ×c¨†ť ƒbĐYőŽ›ÜXr;‘ ˙!9H˘÷'ÁĎČ4~(7ÁşuYŹŁ¨94/ř?éH~í˘Ž,?ËMÜśźTťCXˆőtžOÓÁş,{<ÂăŽŢşn ßéÔKDj*Ő*Ű-…ů Üľ-_ĄĎ˝üÓ¤ŤçĎťÚN Ő˙§Z4M°I˛Qťčs<-űö˙Ť§ˇĘtX´ąŐß ˘čđçţ)4óăŃ[‹˝” k)>^ěT†ćśi‰ü¨S(ţ§={›Ú§ľŮËĺ"îoGbŸŚ9#|Şç€›ĹŤ1Ŕň"‡Â°a"$§>Řřú˛TŠ^"ćvç¸Ó! ™l9Í?ĺĘ;™ih:&Ňh˝ß†ÓѢŰobJŒLDđÜ"nĆhr-2úŃ żŤśęVďa°ch´ŮxÚ F‹ÂŠŕOč/Ýş*čálťUŹĄâ˝`łď ěCÖ8n2‰žŸňü˛żŰ§ôvvööćufŠŠÉŹÜÜŹŹ˝šDMa;]ýďóĄő‚´ĐŇbiUś)!^Ť0„ÇVEźŒ[ˇŠÄÖڦڍ?ÜlŞQ†­ĘQ‹7Âd|1aÍí@7“Śéą9#™ŽěAř₅ Ëš…5&0AU|ŽOÓŮíi9"t %ąď† ć"łŇŻj‡x4Z펺zkkmcZ׎ą[Ř0"7őÁŕ Śyiű9ś‹ô;h÷ÜŚ)ž-ŔI­ ŸťîAČúŔîľÔCÝŚnU¨K ˝{˙×'™âjâU~uŔď´÷4 Ń{ׇw7:î=‡6đü׎\íťŽ…~ A74ů eŚrł/#%ľPżţYx ž|uóŐÂ÷őqŻ—ű‹ ›~qGNâŚäś}FĄąŔdcl%őĽƒŻ–š÷XŞČÓť™&pťÇíę*Š3ečEŘTËÔą§1›˝ÖôçÔ5o_?|/é)ڕ,÷Zg˘+nŤ=żsŤ÷PۛGk‹v ëÍúö0ńŹv—•lŕ. XŘScŤn/jRƒďÚĺ•UľUľ5xEĆ1ť+,•ľFK%”[č@˜Ąú~4§˙ýđí˙ ?üŠBż –ŽYłôéˇ×|ôáŰođIRßQbĚŃ4‰$5MŇsäpOĎarsJAK˝7í)iÔW˜ĄŞLČýƍ՘ŒFĐĹk]úĆ=ŹĹb˘ßĐŘXnâ3Ă~?üčżiŠĂ~‡eSţDz؉Xç?`§—>> endobj 18 0 obj <> endobj 10 0 obj <> endobj 19 0 obj <> endobj 2 0 obj <>endobj xref 0 20 0000000000 65535 f 0000001064 00000 n 0000010895 00000 n 0000001005 00000 n 0000001112 00000 n 0000000845 00000 n 0000000015 00000 n 0000000826 00000 n 0000004677 00000 n 0000004307 00000 n 0000009372 00000 n 0000001598 00000 n 0000001254 00000 n 0000007877 00000 n 0000001181 00000 n 0000001211 00000 n 0000004286 00000 n 0000007856 00000 n 0000009287 00000 n 0000010786 00000 n trailer << /Size 20 /Root 1 0 R /Info 2 0 R >> startxref 10945 %%EOF speech-dispatcher-0.9.1/doc/figures/priorities.eps0000644000175000017500000002024211447133617017157 00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: priorities.dia %%Creator: Dia v0.90 %%CreationDate: Sun Dec 7 20:07:36 2003 %%For: a user %%Magnification: 1.0000 %%Orientation: Portrait %%BoundingBox: 0 0 613 410 %%Pages: 1 %%EndComments %%BeginProlog /cp {closepath} bind def /c {curveto} bind def /f {fill} bind def /a {arc} bind def /ef {eofill} bind def /ex {exch} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth pop} bind def /tr {translate} bind def /ellipsedict 8 dict def ellipsedict /mtrx matrix put /ellipse { ellipsedict begin /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc savematrix setmatrix end } def /mergeprocs { dup length 3 -1 roll dup length dup 5 1 roll 3 -1 roll add array cvx dup 3 -1 roll 0 exch putinterval dup 4 2 roll putinterval } bind def %%EndProlog %%BeginSetup %%EndSetup 28.346000 -28.346000 scale -1.268000 -19.095500 translate 1.000000 1.000000 1.000000 srgb n 14.372100 10.045500 m 14.372100 18.995500 l 22.822100 18.995500 l 22.822100 10.045500 l f 0.100000 slw [0.200000] 0 sd [0.200000] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 14.372100 10.045500 m 14.372100 18.995500 l 22.822100 18.995500 l 22.822100 10.045500 l cp s 1.000000 1.000000 1.000000 srgb n 1.422080 10.095500 m 1.422080 19.045500 l 10.172080 19.045500 l 10.172080 10.095500 l f 0.100000 slw [0.200000] 0 sd [0.200000] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 1.422080 10.095500 m 1.422080 19.045500 l 10.172080 19.045500 l 10.172080 10.095500 l cp s 0.929412 0.949020 1.000000 srgb n 14.800000 16.300000 m 14.800000 17.350000 l 19.918000 17.350000 l 19.918000 16.300000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 14.800000 16.300000 m 14.800000 17.350000 l 19.918000 17.350000 l 19.918000 16.300000 l cp s 0.929412 0.949020 1.000000 srgb n 14.672100 11.800000 m 14.672100 12.850000 l 19.000020 12.850000 l 19.000020 11.800000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 14.672100 11.800000 m 14.672100 12.850000 l 19.000020 12.850000 l 19.000020 11.800000 l cp s 0.929412 0.949020 1.000000 srgb n 2.718000 16.500000 m 2.718000 17.550000 l 9.668000 17.550000 l 9.668000 16.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 2.718000 16.500000 m 2.718000 17.550000 l 9.668000 17.550000 l 9.668000 16.500000 l cp s 0.929412 0.949020 1.000000 srgb n 5.100000 11.750000 m 5.100000 12.800000 l 9.550000 12.800000 l 9.550000 11.750000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 5.100000 11.750000 m 5.100000 12.800000 l 9.550000 12.800000 l 9.550000 11.750000 l cp s 0.100000 slw [] 0 sd [] 0 sd 0 slc 0 slj 0 slc 0 slj [] 0 sd 0.909804 1.000000 0.800000 srgb n 11.962500 15.650000 m 11.962500 9.750000 l 11.500000 9.750000 l 12.425000 6.800000 l 12.425000 6.800000 l 13.350000 9.750000 l 12.887500 9.750000 l 12.887500 15.650000 l f 0.000000 0.000000 0.000000 srgb n 11.962500 15.650000 m 11.962500 9.750000 l 11.500000 9.750000 l 12.425000 6.800000 l 12.425000 6.800000 l 13.350000 9.750000 l 12.887500 9.750000 l 12.887500 15.650000 l cp s 0 slc 0 slj [] 0 sd n 11.962500 15.650000 m 11.962500 9.750000 l 11.500000 9.750000 l 12.425000 6.800000 l 12.425000 6.800000 l 13.350000 9.750000 l 12.887500 9.750000 l 12.887500 15.650000 l cp s 0.929412 0.949020 1.000000 srgb n 9.200000 4.700000 m 9.200000 6.400000 l 15.950000 6.400000 l 15.950000 4.700000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 9.200000 4.700000 m 9.200000 6.400000 l 15.950000 6.400000 l 15.950000 4.700000 l cp s [ /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /I /m /p /o /r /t /a /n /xi /xi /e /s /g /x /i /f /c /y /u /space /l /D /quotesingle /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi ] /e0 exch def /Courier-Bold_e0 undefinefont /Courier-Bold_e0 /Courier-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding e0 def currentdict end definefont pop /Courier-Bold_e0 ff 1.100000 scf sf ( !"#$%&'%) sw 2 div 12.650000 ex sub 5.850000 m ( !"#$%&'%) gs 1 -1 sc sh gr 0.100000 slw [] 0 sd [] 0 sd 0 slc n 11.100000 10.100000 m 9.050000 11.550000 l s 0 slj 1.000000 1.000000 1.000000 srgb n 10.677853 10.888538 m 11.100000 10.100000 l 10.215882 10.235406 l f 0.100000 slw [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 10.677853 10.888538 m 11.100000 10.100000 l 10.215882 10.235406 l cp s 0.100000 slw [] 0 sd [] 0 sd 0 slc n 11.343200 14.641000 m 9.350000 16.250000 l s 0 slj 1.000000 1.000000 1.000000 srgb n 10.971961 15.454746 m 11.343200 14.641000 l 10.469460 14.832256 l f 0.100000 slw [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 10.971961 15.454746 m 11.343200 14.641000 l 10.469460 14.832256 l cp s 0.100000 slw [] 0 sd [] 0 sd 0 slc n 13.472100 10.045500 m 15.550000 11.600000 l s 0 slj 1.000000 1.000000 1.000000 srgb n 14.352293 10.204435 m 13.472100 10.045500 l 13.873068 10.845015 l f 0.100000 slw [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 14.352293 10.204435 m 13.472100 10.045500 l 13.873068 10.845015 l cp s 0.100000 slw [] 0 sd [] 0 sd 0 slc n 13.450000 14.700000 m 15.572100 16.295500 l s 0 slj 1.000000 1.000000 1.000000 srgb n 14.329810 14.861041 m 13.450000 14.700000 l 13.849054 15.500473 l f 0.100000 slw [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 14.329810 14.861041 m 13.450000 14.700000 l 13.849054 15.500473 l cp s /Courier_e0 undefinefont /Courier_e0 /Courier findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding e0 def currentdict end definefont pop /Courier_e0 ff 0.800000 scf sf (!*++&,*) sw 2 div 7.450000 ex sub 12.500000 m (!*++&,*) gs 1 -1 sc sh gr /Courier_e0 ff 0.800000 scf sf ("$#,$*++) sw 2 div 17.400000 ex sub 17.000000 m ("$#,$*++) gs 1 -1 sc sh gr /Courier_e0 ff 0.800000 scf sf (%*-%) sw 2 div 16.522100 ex sub 12.545500 m (%*-%) gs 1 -1 sc sh gr /Courier_e0 ff 0.800000 scf sf ('#%./.0&%.#') sw 2 div 6.318000 ex sub 17.250000 m ('#%./.0&%.#') gs 1 -1 sc sh gr /Courier_e0 ff 0.800000 scf sf (") sw 2 div 12.450000 ex sub 9.100000 m (") gs 1 -1 sc sh gr ($) sw 2 div 12.450000 ex sub 9.900000 m ($) gs 1 -1 sc sh gr (.) sw 2 div 12.450000 ex sub 10.700000 m (.) gs 1 -1 sc sh gr (#) sw 2 div 12.450000 ex sub 11.500000 m (#) gs 1 -1 sc sh gr ($) sw 2 div 12.450000 ex sub 12.300000 m ($) gs 1 -1 sc sh gr (.) sw 2 div 12.450000 ex sub 13.100000 m (.) gs 1 -1 sc sh gr (%) sw 2 div 12.450000 ex sub 13.900000 m (%) gs 1 -1 sc sh gr (1) sw 2 div 12.450000 ex sub 14.700000 m (1) gs 1 -1 sc sh gr /Courier-Bold_e0 ff 0.800000 scf sf ( '%*$$2"%+3) sw 2 div 18.950000 ex sub 14.345500 m ( '%*$$2"%+3) gs 1 -1 sc sh gr (.%+*4/) sw 2 div 18.950000 ex sub 15.145500 m (.%+*4/) gs 1 -1 sc sh gr /Courier-Bold_e0 ff 0.800000 scf sf (5#*+'6%3.'%*$$2"%) sw 2 div 5.800000 ex sub 14.245500 m (5#*+'6%3.'%*$$2"%) gs 1 -1 sc sh gr (.%+*4/) sw 2 div 5.800000 ex sub 15.045500 m (.%+*4/) gs 1 -1 sc sh gr showpage speech-dispatcher-0.9.1/doc/figures/priorities.dia0000644000175000017500000000326511447133617017133 00000000000000‹í\]â6}çW öĄ/ʉí8‰—Y휪TŠRşűŒ 1ŒŰ ÇĚGúŰk;lB Ćł3ٌ4Œˆ<÷ä:÷œëk_řřé~™őoš,E‘_ }žĎŠT䋫ÁˇŻżžOŸŽ{SÁ>č߅dËžţź4ďŽ7J­>ŒFwww {(™*$ČÄ”|ô/Ë26҃Fƒë^ż˙Ř@Ę3×6W™RRL׊÷sśäWƒ)›ý˝Ĺ:Oը͸Y‘˛˲ŤÁťšýŒ6fF;vž°˝b+.ëf—Ť˘zˆzXí 9`Çź>łUęAůâúÝçđ]uK› [[M7zD-™\ˆ|Gr–U@‚ú>çCLýCdţ!¤QNV…T’ ľ3-ŠŒłźBRrÍŰă”3–éyĘŘŢú\(Uš˙9ËĘS¨.˙Ϟs™¸"}šˆ;#XšŠş™Ü{šŽĘúƒ'롢ӌ7Ý˝ČŐĹĚ?8šw}Îk‘ňňȓŢsŔŇÍfŘč˜ăőq§zP]Ş%) ‘ą.7ćżlÓS3ÇŇ?š…búŸŠ{*–§LŚý÷ý/Ĺý`›muŽéŐŕ`wzęicZ|öćgUlŸcpŒŕ  Šťž˙LÁL§uŠý`ů"ă[$¤‘( ”1ŇşjŠ0Ďřr2+džŸw/íŁ…˛´Ţ÷ó;ĽşXżábqŁž2O[š/oŠťIĂęčx:E§>)ŐCĆë<_/+ëáÓŐŊ­YYB„‚ÄF őË š$›cýĄ -¨gZ\ÂÉÓhw´x´@H:\"€ýډ˜¤É sE¤czÎ.nB L áęÖ)tˆZŻb:.řŕqĺ‚Nů•j{¤ąé@ƒh"D&/$^+G—NË aGƒçŁÁĎâVdšßVýĎRw DˆœWJaäw•¤kY ŠF‰1"x 1a˘ƒ•€ŘëJÉÉľSřÝ(}źvN<ó!™Ďgł—\žĎ3ąšÜRüSäŠeO˘ÔN8ΆŃäRbćdĹŇt÷ ¨öź€ &?G]…ƒ4 Űř$Ý  éĘ*FnŠç¨X8šsÚ2ö›;ă.u6Ć˙W~ݐ8gN]ę!i­Ń'r b¤Qc:Ö)3Ą(Ńl€ć};`e&dďQďÝŐĆz°śbg\­e⡼9^gš:Đ9ńÄéç!ŠÖ‰  Ń\ß ůšXKÁĺű/E–>>V<luĚƒn ťavj¨ľAŞłź‘éýqb™XäKŢü¤śë§N\ăIďeÔáw‘óu XWŰ3MčQ@“›CŰĆTŤQ ŐÁü…´e>˜y>áyj}9ÓĂŚ´ZŐŔmO°t¨ĚVő›hęs8+)&ՄْęŕĄrś=ÉxžxjI´­MƒYvǸ a`pĆࣥŮŕĄ×œŠbŃĄŽCiCC›$ #{ȄěŸ6n6qoÎÚ:îźmD`>SŁ”čك3ilV¤˛Ç{ž9äcĂP˘Ž˝ŠŽ9o›9čĚ!FŒcϤA˜Ē&4ĄŹ3NԖŽg§îb3gâęží–ko…8v? s‹Elƒ ż'h$Il=ClΓ1„Č€ĆúíËßüXň˛d ţś>üďzěŞŸ]†ë6=źŠ‚s‹‰iBŻŠ”ˆěa‰iş"abťLđŤ…•,R C§ -÷Bë!Öi‚WMpnľ1YśIR+šçÚTŻĆv˝ŇąŽ‚j× á+8+1v:UhŠ ‡‚ŹSŻęŕܤÓxŐ#Š|*aťĂU…‰É"€×°fČ %ćbƔžüN!Ú)Dc uęŕUâ ôXčz=EՐR4LŃÚÇv{Á|ň.´ťŻ ˘čɞčöUő:hÝdQľNźĘƒ{ –ůtŠ!*ö\X˜=qóąŹ+‰‘i´0g¸D#Çč´aĺŠKš^ОߪäŮüíöc=‡T4Ç]'^傺čÇfuäY,ޤ"2R€+Ľ@ŻB)~)x™˙¤úâťbtzᎍ×ŠĹijQ˝ˇ_ŐsÝŰů.ŸëŢŽ(dnçNspeech-dispatcher-0.9.1/doc/figures/architecture.txt0000644000175000017500000000137511447133617017506 00000000000000 applications protocol output modules interface Speech Dispatcher core synthesizers .-----------------------. |Emacspeak| :s l: < > | Speech Dispatcher | :m : |Apollo| :h i: | - configuration | :o : |Festival| |Speakup| :a b: | - synchronization | :d A: |Flite| :r r: | - sound icons | :u P: . |User center| :e a:

| - history | :l I: . . :d r: < > | - punctuation, ... | :e : . . : y: < > | [||| priority queues] | : : . . : : < > | | : : . `-----------------------' speech-dispatcher-0.9.1/doc/figures/architecture.png0000644000175000017500000006316411447133617017457 00000000000000‰PNG  IHDRŸç×dŞÚsBITŰáOŕ pHYsĐĐš‹çŸ IDATxœěw\ÉŔ_( @D@A:*@D ¨wv=ą—*–ł÷SąâŮ+Š`ݧžíDĹlŘ0ŇDńP MžßŁ{kĘBH˜ď‡nŢÎź)ŮĚۙ7…ÁçóƒÁ`0LBIŃŔ`0 #c°uÇ`0 ŚĄ­;ƒÁ`0 lÝ1 ƒih`ëŽÁ`0LC[w ƒÁ`Řşc0 ÓĐŔÖƒÁ`0˜††Š˘3€ÁȘ…‹E^˙„ĺXŽĺ YNžĆ0đ^u˜Ż@Ń9Ŕ`0Š€ŁŁčĐ <2Á`0LC[w ƒÁ`Řşc\.7>žŤč\`0yĎĺrńo˙?đŹ:Lƒ"''§°XљŔ`0r'——SQ˘čLĐ ÜwÇ`0Ü\ž˘ł€ÁČlÝ1˜úÇż˙ŚoÝźnČ@Ks}óćş^Îćĺĺ*6Wúş }]FÍ YNv-ŚŒKJLZ§t,[:×ÉŽ…$!ĺ FVŕq˜ÇË-6›ŁčŒÔ!˘ďÜűŰ7A„ŠŠŮŐëŃ͌M’+@–/'_˘&Eœ™dąXöíÓO Ň!yrČ FjrsylmŕpňożFŕž;ŚAÁápśi€% g~űVÜç—яâ2ż”ed_‰¸ďÔĆůÇ÷Ë(:w5#'Ÿţ>~ţv'úĺŻý—––Nöő9ó9€b3‰Š°ŮlÚÉ`ëŽÁÔ3Ţźy Á{ŰŘÚŤŞŞŞŠŤť¸ş‡8 ×#ÂQ4†ĚăĺôëëŐԀŮÝłc̓‡d%˙ţ›>aě0 S=3‰ă~#ŹŠ$wŸ?{ňKďŽÍ Y6VM—-+0ŠđőkaŔä1-Œľ­-–,šUňí›$…bŠŠ98´9x䌧WĎŻ_ ÷‡“ ‚ŽKKK—˙1ĎŢƤ™!ŤŁsëm[‚*++%,oř?çűőő˛0ŐkjŔlcośxáĚââ" !Ç¤. E˝ĄFßżciŽß˙oIęƒŠ ™g0Ŕçó‰ #FEEFEE‘•ÔU.ĺ‚ÔU?×…BYUT=ŞđżW]Ÿ.Eď >č7rœ¸0ČV ôŰůs!‰††ćÝč—-- 7—×Í˝mFĆ"źĽ•uÔ˝çęęŐŢMINôôp&ź~ý‡żFóňňşsçŽtqiŽĹ!׆LRS_*ź1ŹwßąkżaŁéSÇ;;ľœ9ăG‡&ž‰2)1áéËn‡v΋‹‹‚wmůŽa۟zô읐ô)émvżţCR’Ăöí–äîžÝ[ż}+ţľßŕ÷Ÿ€ŤW.’ÍÎÎzđřő‡O_'Ě€‹ÎÔ¨tNmœ 5%IřÖßgOŔŐëџ˛K= Ǐţd#ŕwóŚľ°qKpFfq旲Ká‘p5ü"Ě q!uŠë amm›‘Y,ÓýúzEßŰJČ6–‘ĎzwꆷFÔyŁĘŻ9 ]ťvUWWWUUľłłťző*‘Ĺcǎq8WW×OŸ>Q ÉĽĽĽż˙ţ;‡ĂaąX^^^"“Č3qQ^^>wî\‡Ł§§7wî܊Š âîéÓ§;uędddtöěY>Ÿ˙čŃŁŽ;2™L îÝť§ĽĽIQöÚ@.cJJŠČŞ(++›1c†ŽŽŽžžŢÔŠSKKKEGÜ7(Ź]lÝşŐŘظK—.™™™„°G...|Ę/”CC…×-AddäĽđH›ŰP˙^ŧO˜Ů˘…9ń˜›ˇ Ţ{˜€„/ßFŻÝx-[YĄ­­mŕůŤˇčc\ÂżĐĄŁŤ$w[ś˛€čGqšB‰ŢŒ|‚>&§}eee‘E@…ĺŸsĘÉąČÁЄÁ‡ŸîÜ90`€8%(<Ń&WŰęJcÝů|ţ“'Oć͛çčč ĆÎűœœ†††ÔBň…‰‰ H’šZů|ž……J"''ĚĚĚČ閕•€’’ŸĎgłŮĐśmŰĐĐĐÂÂBé ^„Ë(\ŚŚŚđĺ˗ÂÂBâqY'CœBtÁăńĐW```@sss‰ˆâj›CC…×-AٞîäżŘ×ďŔظ9šŃ$:¸™Ĺ ŠŠ…>2™LBIIIňťƏZRí­“§/€[gqÁ.üsËĚĚÔŐ5ű[’ňţÚo0XX´š:}Ύ]űď>ˆ%ŤHBęR×EUÔô?ĺ]NĘť055ˑغ§źËI}šCIb ”4ĺ]Nvî÷™ŒIołŃ5™+GŢý›Ÿô6›"Wä SHNű’ţąĚĚ,rňůzzlptlťmGhúÇB‘ŐRSëNnŻnܸ]ťvĺóůđüůóďYßđ˘ëЊ PVVćפ…$Ť***255ŐÖÖţđáƒ8%(<Ń&WŰęJcݡnÝ żţúëăǏ‰üĄ‹ŞŞ*4‹UEE…ZHžPVVFÁ$IB ^Đ/J\äëŁGęč|ŸtÁápN:%EŮkƒ@ů⫂€˘8d!…BŻ=Hˆź|ĘÚ&ÂPçPáuK“““ň.G&m(m˙tttŕQLYřof°X,rŁyűÎSôT;8´A-,Z@|âG‘úŠď"wŔă§o„oĄDŠ%ÔˇžäUuńđ€ĺ+×SKy—3kö"PWא¤źš˜š…>Ţ{đŠŹV Š H]oUQÓ?Ôč}ÉŤBĆUEE…Ź˙K^q-\̚Ć™‘×"sĽ¤¤D 虨p ““Ď߳靖ö÷†Íć„<%\-)ďrrrr$l(ÚŤŇŇRmmmeeĺÄÄDeee˛5Eá‰k‘BžT-$9ú’%K`űöíč#…! Úäj[]ifŐ-[ś Nœ8agg'p++++?? ¨…dš6m (LľI`ll šššššš€^yD2jÔ¨ĚĚĚóçϏ=šÇăMž<™Zs]@.ŁHŒŒŒ€ôvV^^.“ty<^AAüüEm ~púôi}}}==˝‰'顋M›6ikk{yyńx›Í^¸paeeĽ¸J÷î]Ÿ>}444X,VçΝ_źx!EŮkšŒoßžYĽĽĽÓŚMCSë{őęőńăGqĹ!ׁ°BtqěŘ1}}ýΝ;ţü™/ô”P|ĄÂšEćPáuKFnVVďţ͟ˇ`™˝ŁšşşŞŞŞŠŠŮŘq“žĹŚ ´ĹĎ_˝utlËbązôěýôE2YĂӗ)żô¤­­Ăd2Űwp9sîšäwĂŻÝkçÜQUUUWWϡO?B3JTœIřƒŸaŠŠľle5vܤ˜çIâ4źMĎ>bʁaeeĺŚÍŒ§˙>˜ŕF]ޡéšÓĐĐTSWwnßi˙ĄżČjWŹüSKK›ĂŃŻ})ꍢ*jú—ůĽlĆĚůŽžž{欅ٹ•9ůü#ÇÎ6127oyőz4‘VHŘquu ÷.žDV­Ů¤ĽĽÝĹĂ+ő=O’X"ó/ňZdŽŢ$gvěäĆfsĐT;Rd˘Äŧě҉ţÓŘl‹Ĺňňî…</ăŢőěŐG]]ƒĹburéu˙…Čš‘áö*33âXZZ"jľ ŻČ’ˇ-8%mrľ­ŽĚvłš0żm‚ipšÜü"°łsTtFLcŰ˝ą•W |ĹÇsu5M Ž)ĺĺĺŮŮŮíۡ˙üůóíۡ===e;€ĎwÇ4(đůîLă¤6çťëč蔗—ˇlŮrÝşu Ă´ƒ ­ťČ:îľc0 hŔ˝öÚó­ÖÓBi>EƒÁ`0˜†>ßÓ h çťc0ađůî`ëŽih4ř3â0ŒHäpF\=Ěc0 ÓĐŔÖƒÁ`0˜†śî˜Ec8߃Á#ŸóÝë*h<Œä„‡‡‹”㚏)âj˛6ÔÝz÷áCń÷Űđ9uFöĎdÝŃ8ŸIqßőz÷FŘ>3ú‡¸yˆhc>ŒäPĚč œ5 gŽ€ŔíÇäsÍM|W çn+fŸ;´ŐŚaCą(|ۖI°şűůógšćŠ~‚Î7W“\.2˘­Íĺš'^^a.§ť¸ľň¨%ÍÎŽíA™zbhhâ-GB˙âŋu”ŠlЁuç QwŮÂ4fx<OA~wqۆ`9<ÇSŒß˝îžIdÝ}}}ŕęŐŤu”ŠÜ`ł9✲Š=h“ťţýűŔ… ę(Ů"ƒž;XŘłgĄĄĄĽĽe|||XX‡ĂiŐŞŐÝťwQ˜¤¤$/// ‹ĺěěüäÉ"zXXXóćÍľ´´ţ÷ż˙•••!allŹťťťššš†††§§gbb"9­cccƒÝťw“srüřqkkk‹ĺŕŕ@~˝˘H‘miiÉáp’’’j_!2áóçĎ2܂JśÚęGGGůoTÜÄw ô;_îőë×}úô111155íßżJĘ=ČłgĎşşşš˜˜xxx[gCCCCCĂăǏˇjŐę×_˝v횡Ąá˜1cˆŁG644$˘H¨G8oǎsrr233›5kńă€Ë—/wîÜŮŘظK—.Ő*—:­°łw”˙FuÇMŠŁg˛°°đńăÇŞŞŞAAAL&óţýű……ß_ŠŃđޑ#Gœœœlll8@Žxůňĺ.]ş4oŢÜĂĂCÂżQhEAAÁ˝{÷TUUwíÚĹbą"## žżęQ›¤ż˙ţŰÖ֖ÉdÚŰŰKŘă—"Š8$ډVœWŸkgg÷ćÍ›ŞŞ*°ˇˇ‹‹€:<{öŒckkgΜ6l!_ľjŐ˛eËPDáěěŒ˘Ł´ ‘áS§NýöŰopţüůAƒQ”••Ł˘˘ştéB‘:ŇöőëW//Ż—/_FDDxyyU[ľß‰ś°°pΜ97oŢTUU4hĐęŐŤUUUáÇ>‹Hqýâŋ%K–ÄĹĹ)))9;;oذÁĘĘ Ýݡo߂ ,-->l`` ŠHmÄőŚM›6mÚÔ˘E‹ýű÷7i҄÷ěŮó˗/׎]KKK›;wîłgĎ*++[ľjľjŐŞnÝş ËĎĎűöíƒZľj•’’âîînaańčŃŁjk€z'Zúî3/˙hťtéBźÝ€““Ó­[ˇ <<|ܸq„\YYůâŋ...đcSUô3ńöö>~üxŰśmsrr¸\ށAvvś““›Í~őꕊŠŠäzţúë/rĆ.]ş4qâDâă˘E‹ćΝ ‘‘‘żýöńĺ*))>}=< )R—3Ô;э÷™—îĹýŇĽKţţţÝşu;}úôȑ#oŢź2`Ŕřńó$7łűöíCÝÖČČH???ň—ű×_uíÚÄ78Qj őN´@15˘6;Ń";ŐłgĎëׯ÷íŰ÷ʕ+'Ož>|8Pš¤ˆˆˆŢ˝{“ ŃŁGĚŻ)˘Ôƒ!3żűž}űž?ńńń{öěyüř1­ŇÓ§Oů|~UU˛˛D˙căƍpňäIţŕÁƒHžšš /_žD.˛m€ &äççűűűŔŚM›ČŞN:URRrîÜšĘĘĘ͛7S§Ž6lXLLLpp0ľi—!ŤWŻžtéҚ5kÖŹYsđŕA”sqřűű?ţüţýű'Ož|đŕA@@qëÁƒ+VŹxúôéŞUŤjš‡řřř }ŕʕ+ä~~~)))ŁFâKŮž};úrїťeËꄤˆ"uˇŢ<,?pŕ@œi’Ö­[ÇçóǏĎăń&L˜PUUľzőjꄤˆBA úîÔ}ÖŻ_żŞŤŤ+++@aaĄ††ş&bĹÄĜ8qâć͛¨7äęęę%%%ĽĽĽL&“Źsܸq‡VVVnßž˝ŻŻďŹYłŘl6‘Öۡo-,,RSS---ŐÔÔž}ű肠iÓŚÄäF‘Š“Gnޟٽ{÷j*KF}wGGÇŹŹŹ7oŢ0™Ě–-[śhŃ"&&ÄźüZ[[çĺĺŮÚÚNœ8qĐ AšššÄ]ôňdmm­ŻŻOę@P÷݉¸'!!'%%éęę" /_žźpáBTTTBBƒÁČĚĚv÷îÝĄC‡şšš]¸pĄ˙ţ=:uę”$/IÔ}÷;wîŔ§'Ý\`hyúžân)Şď>cÌS§N)++ˇiÓĆŰŰ{ňäÉzzz`jjZRňÓňŢ&Mšź~ý~tCcbbĚÍÍŃ­ˇoßş¸¸ŘÚÚŢ˝{×ĂĂă͛7ŃŃŃ­[ˇŽŠ2͛7/--ÍČČřńš™™'''ëééĺĺĺYYYŠŤŤ§§§‹TH‘şœĄîťGßżŁŠ™Řľ›ł|3PPĐAÜ-ŠűîUUUŽŽŽ_ž|! ľľľTUUŃĎ3&&ŚE‹ďŢ˝sqqaąXč´°°(..NLLD_Žľľľşşúťwď@|ƒCĽŚP÷Ý%9#NŠž{UUUłfͲ˛~ZŁŤŁŁ“Íd2)L’––VQQÇcłŮšššGCCٍ¨Ä÷Ý)˘ÔYöÝ555•”žkÓŇŇ"Ž;věpqqQQQ9zô¨p\4ŒOfßž}nnnéééŤV­BăEĹĹĹD,"!a%ÄłKzçΝ VŽ\)YAe@NNŘŘŘ´lŮ>~üHxÝşučW7oŢýć͛: Ó^S=Â7—äßžČÔʰÚÔiBóťżxńBŔ´@aaá˝{÷ˆČD 4ł ť$H…Vqë˗/h"Œ3EóňňDĆE#.đçŸňůü˝{÷Z[[ GGÁTUUťuëVYYšdɒĘĘĘ.]şt㤯w'Ăd2çϟůňe´&çéÓďŢ_{{{ ÉČČ@ƒöËpž‹‘#GŔŇĽKáÇ9ŮŇé!°łł€đđđ§OŸÚÚڒĺ+VŹČĎĎ g矺źd…ŐŚNŘzw4[>((čóţüóOřyćüŽ;Š‹‹÷ěŮ?ž&řńĺŽ\š2??őˆÚľkG–Qh–ßľkąX ů)Č- “4oŢ<˘ÝîÔŠuZRDĄ Ö˝6ťŮčë뀭­íĐĄCQ— Ú̙3FŒáććÄ ťŽ;˘$ŹŹŹŔŐՕŹířńăZZZ!!!0oŢ<$\°`RĹbąPÜž}űR§Ž044œ2eŠ’’’Üşď˝ző€sçÎ=~üŘČȈÚ#ĐŤW/sss‡ƒę "ślق~={öŹiśn݊Ülâ<ĺÚÚÚŔĺr}ű„ IDATEx ¤Ł˘˘(TŐěw'ÓłgO4ŐýÎۡoä3f̀ɓ'›˜˜ ~~~zúőë§ŁŁ“——§ŽŽŽ|‡Ňé!@S@&OžÜťwo ŘŚOŸ'Nœ°´´}Ú××WCCCMM­gϞćđáĂFFFMš4 #ćÉ2äčŃŁöööŞŞŞgüřń§N˘NŔÂÂÂ××÷Ν;ČJŐ5k׎=ztPPА!C<<<ÂÂÂ(‡……y{{>ÜËËËĹĹ%44”¸ekkűǸššIńtęÔiŐŞUíۡG9aVŻ^­§§7f̘7oŢPčéŃŁńž'+ëŽ×ť“Ůżżˇˇˇşş:‹Ĺňôô$ć7ýúëŻÁÁÁ666ŞŞŞl6ŰĎϏülŁŚŚ6xđ`čׯá‘BÁŔ7lŘФIMMÍáÇaďŢ˝÷ďߏVőX[[>|ŘĂĂCœŠS—3 l˝;š~Ô˘E B‚Ź×çϟŃähŘšs§ĄĄĄÁÖ­[‰ž’ŻŻohh(úr[ˇn}čĐ!´.‰)˘HG­wůň%XXXdÝ?}ú„&ƒƒ“Ôż˙Ó§O;::˛X,;;ťóçĎ{{{S§%E $šUGjłŞĄŽS—|V]í!OZQ8]ştINNnŰś-š;- Ôłęx<źż%˙Áynâť=wq{z+jVF>PĎŞËÍĺikż”˙ŕ|7Ľ¨Čžú™”y;@Ťć…Œ˘VÄQ X“DƒÁŔ§Č`¤§¸¸řýű÷hŢZ9#đůĎwÇÔ;°uÇHMeeĽ……Ĺ AƒdhÝš\.dź“˙´yGkó\íüî:ĎŐÔL‘˙´yGËÂBüLJD|î3!}?J[<==ş€gŐahöťcčýîŒH°uÇĐźŢC7đzwúƒ×ť €­;†v`ż;†nĐÓďŽ!ƒ×ť €­;†vŕőםcęŘşchöťcčöťcęJŠÎ#—Ëĺ&ž“şŽÖćvö¸“„AB<7Ž›"˙t-ń3)!ńń\.—Ťč\Đ•FľwLˇn×dMW“ŘôôťÚŰqŤüŠ×ť7ÂöšŃmßS{đ^u˛B\MâőîůSםă˝ęČPŻwo„íówż{#ÜÇG $yű;yň¤rRßńó󣸋ýîşAgż{ăis¨Ű Ih<–Žoßžß_gđŽu’€Ţţ¨űî¸o' ¨Ÿ„÷™ÇЇúťĎ|ăy&Ť_ak‡#şŽ¨[ď†ƒÁŔsć1´űÝ1tƒž~w źŢ]lÝ1´ŻwÇĐ źŢSďŔÖC;°ßC7čěwÇ`D‚םch^x˝;ýÁëÝŔ}w íŔ~w ÝŔ~wúC˝Ţ˝‚­;†v`ż;†n`ż;ŚŢ!ƒ‘ůţů§S§N,KCCŁ]ťvťvíŞŁU ŁîHĐáp8ňßĘxy…<öqbDŔfs2!›Ç+É3i(ŠÚŤ%+WTt™Ă…l•Ë'zm­{pppż~ýbbbĘĘĘž}űöňĺË3fŹZľŞ–j1999sçÎľłł366vvv^ąbEQQ‘@ňŻBÜu}űÝ1tűÝÉDGG÷ďß_ŃšÄÎŢÉÉÉIŃš$**JÜöyuMmGćŕ… ˝zőŞŹŹ}ú˜˜˜˜ššöďß?%%Hß1FH\\ťvÍĐĐp̘1„†ŃŁG"ŠŠŠ 055511ńöö~ţüy]—Ť.gśbccÝÝÝŐÔÔ444<==´š=a•ˆ‹K—.1 ň{R˙ţý ŇY­”„ÚîD;ţüM›6€śśöĉg͚efföŸöĺ!ôŸ:uęˇß~€óçĎ4ˆŠŹŹŐĽKčĐĄĂłgψ[śśśńńń„śŻ_żzyy˝|ů2""˝ l1HţH‘)ŰN´]ťvMHHˆ‹‹322˘†~Q(Eáë͛7oܸąE‹lҤ !ďŮłgNNNDDDZZڜ9sž>}ZYYiiišjŐ*4‚D–——÷öíŰGľjŐ*%%ĹÍÍÍÂÂBşGM8çTO]ÚľZ&!ws t:šwé&ňnMwý455ýđჀ°˛˛’Ď獨T?f&2z-‘<őş@ąŠW ő.§ ŁóTŽŮůÎÝ;ϋŠŹk˙L żąÂĂĂǍGȕ••/^źčââ]ştAV áäätëÖ-UŮŮŮDăSQQŃśmۜœ.—k``íääÄfł_˝zĽ˘˘ŇŁGŘŘX"bëÖ­ŁŁŁáçśK’RP|G}wÉw˘vlą(̖˝˝=˛SggçgϞ ¨âóůD6***Z´h‘‘‘ѤI“ĎŸ?7oŢ\__˙ß˙UQQĄ6‚–˘ś}÷   Ĺ‹ŤŠŠnŰśÍŇŇ2 @ŔC>~á…Ož|đööśˇˇŽŽ–á”ěwG#šĄĄĄ‡ŞŹŹ FˇPC…†oÝş$3,<^¨˘˘2|ř𩩩3gÎŔ™3g***† †^énŢź™••…ô ĺ2DëÝ)ĚVjj*ź|ů’Ďçóů|dź3Œ„dU***cǎ­¨¨8vě;vŹ˘˘bôčэލ „ÔÖşŤ¨¨Ź[ˇ.==}ŐŞU:::{÷î>}:9ĚŇĽKutt.\qqqHřňĺK>|¸ššzzôč%&&fΜ9cǎ€ňňr˛ś+WŽŃ& PUU%,™:ƒJQK͢E‹~ůĺˆŒŒ$ËťvíŠŢŽ_żniišzőjô}eff CÖ=""‚řIęÇSß]Üq5ľ\Ů?@Âĺ˗Ÿ?ţăǏK–,™?>Üž}ŰĹĹ%33311ąuëÖ7oޤˆ. şU\\üęŐŤ ,[śŒ,_šrĺţýű )œzíu.Y˛dܸqqqqcÌYşt).^źŘÓÓ3!!ÁŮŮůëׯŠO›6ÍÇÇ'55ŐÍ͍˜.RŘŚMz@ł˛˛bccCCCŃť;,]ştěŘąŻ_żÎÉÉŮš„y<§żťŹžI =QäjAŃßßßÄÄuâŸ>ý>JZćîÝťűřřüůçŸÄ #FŒ€ÇÖĄ‘ńâŋe˖ĄG aŻ=šźôĽË> BHaś†íۡwqqYąbEnnnľIL˜0>>Ż^˝ňóó:t(…P d;9šžŻw§ŔŢŢBBB222Đ„L;0™Ěůóç_ž|ůňĺË@ęÓ#rssEöćGŽ h,‡Üq_ˇnŸĎGŢ@$ŠwçąR˜-&“šbŊ{÷îÝťw;ŕńx"{ó'N€™3gÂĎwj#(!ľľîh@ě÷ß×ŃŃQWWGߍ€Ł÷řńăZZZ!!!0oŢ<$\°`Œ1‚ĹbĄi„}űöEˇôőőŔÖÖvčĐĄčäb>N™2EIIiĺʕHâěě C‡ŐŇŇÚˇoŸp&Ef€Î̜9ÓÔÔtÝşuÉÉÉĹĹĹ{öě144ěŢ˝{”lÝşy1ÄyĘľľľ€Ëĺ9r„BOŻ^˝ŕÇđžœîĐ üî ŞŞ^UUőţý{4ěÖŠS§đđpôʅHOO÷÷÷ßłgώ;ćΝKžF']=ި¨ˆŒŒěÚľ+E0áÔkŻÓÇÇçƍpăĆ ôJ žžžçĎŸŻŹŹŒŽŽ&ĚEŚnii™””Äfł[ľjU\\L!”œnÝşĄYÇȑ$+°ß}Ì0yňd4SÁĎĎÝęŮł'’tęÔ ÚˇoäzzzĐşukd–čׯŸŽŽN^^žşşúŔ 9›Í€Î;O˜05>˛]ć#‡őîfŤcǎHbeeŽŽŽHŽJ­ŻŻO6ŢC† ŃŐŐÍÍÍŐĐĐ@cűj#(!ľľî˗/ß°aƒ˝˝=‹ĹŇÔÔtssťpáB@@9ĚáǍŒŒš4iFL82dČŃŁGíííUUU9ÎřńăO:E„ˇąąa2™˝zőBó/ÖŽ]KVhaaáëë{çΝ¨¨(ءo_ǎ™LŚľľ5Ą¤Ú Đ6›}őęU—ž}űZXXlŢźŮŐŐuǎ5RâââŘĄCÂu*ŔÚľkŮlö¨QŁ(ôôčу˜ů)ëŢüÁfffóćÍłśś€Yłfýý÷ß666nnnhzގˇwRR’ľľuÓŚM?22200˜S- ŰďŢ0ĎЏ†ƒÁ éÚS M(..~˙ţ}FFŒ5J>‰âóÝ%„čłĘ°}Ż ň$99šsçÎJJJ^^^gϞ••Z|ž;ŚŢ­;†ŠÖ­[WVVZXX Ť„‡‡+: \“˛űÝ1tƒž~÷Sgp›óÔëÝaűĚŔű˝`čŢgžö„‡‡űűűŤŞŞśm۝™†PěłtŢŕś>î3!C}ž{#¤śgÄa02§Ąžď.OĐkďßż'›v×Ű‰ŠŠŠH9mM{ľÔţ|wUFÇÉr8ßÓPÁÖC;ĆůîľáÓ§O˝{÷633Űšsg›6mÇă9ŇÁÁaôčŃč4Itjhh¨ľľľąą11öآE‹ňňňqăƑOk%D|řđÁŰŰŰŢŢ>::ڐş+|œœěîîžhŃ"BÌ3lmmÝÜÜţůç$ą°°())P%2uÉK¤pđůî 9œď^żŔÖC;Ćůîľań⪞ž ÎÎÎ_ż~EÂ%K–Œ7...n̘1K—.…]ᏏŹŘŘXt< ™žžŽî"°M›6Â]çĽK—Ž;öőë×999DâŽđőʕ+÷ďßďââBȃ‚‚âăッƒ§L™‚$iiiŚ.y‰ů|wUFÇ߆,ÔŐôXˇf˙Ż}fęiuÝşůźIHëě2N“ŐŮ­ÓŘÄ7ďŕŃCރíP-5÷1#—q ˝ö8nJ§öŁ5˜nŽÇ$ħ!ĄÎwo0Čá|÷úöťchöť›™™%$$hhh…ćć扉‰,Ť´´ÔĆĆQ˛'[Ü5š™™Ybb˘ššZ~~žĽĽ%şEĄ3==]]]ˆţäɓٳg§ĽĽŮŮŮĹĆĆÖ4ő•¨Ž‘ÜďŽĘčx)|›yëVÎ_ÚbccŢÖqřגčÎ.ă†űůLô°?ô‰ăWĹq´6s–߈Q˝ Ÿ°žœŁĘčXΏA:Ń5!éÔ~ô˘%ăűţŇĺćÇÖžs? °ß˝†ŕÝlČŕÝl0´ŻwçóůrNQXXUU% !›v˜;wî AƒJJJŹŹŹę0ŠF`˝ťŻ›’’ôé뎤¤TZZŻb“oFîŐĐP›č?`т’œ>jL_55ć¨1}§ŹGqů|>ƒÁ¨¨Ü‡ű*ůˇ! Ń5‹ĹDxŸyŒÔŕ‘y íŔ~wOOĎóçĎWVVFGGŁÓ>>>7n܀7nřúúĘ$ĄnÝşĄiw„PUU5<<<33–SđőëW;;ť˛˛˛ăǏ“ĺHCUUŐű÷ď<(.z]”¨Žđť#ÓNž{‡VaűΗě˝Đžƒ-Ř١žËĺr ÁčÓ§˘óPĎ7Ó§Qí‚$ÄŐä;wŕӓn. hÔxúbmŒ´1ś9âVůS݈k„ísŁŰž§öŕ˝ęd…¸šÄ~w9Ăçó###ďŢ˝Ťčź(Œú¸ŢďUG†Úş7Âöůťß>+OčŒ$o'Ož”CNę;Ô;cSřÝżäĚ ť““W §ŁŐĽƒýúămZ™Š“3ZöţŰŤč””ZęÝÝۆÍx ß]n$''wîÜYIIÉËËëěŮłŠÎ}Ąó>ó§ÍŠýŽúÇŇőíŰ÷űë ž9/ č폺ďŢ űv2ő“¤ŘgŢwÜwŸEÜŕÚÎćJdĚ €Ő–fĆɑűĹÉŹ;˙íՒҲ5ťNŽÝ}j Oçs{–‘•ă}ć3őwŸůĆóLV;žÂÖq‹â¨[ď†ƒÁŔłę0´ƒb˝{ÔŁWđčĹU•>ůoŻ&G ŁĆbÎówŸ ܢĎzw Ý Żw—'x˝ťäŕőî`뎡ŽŽŽâˆkk×m8ŕ2pfôłřjĺ"QRb€Š˛˛€œ›ř.!ϚňŔÎŢQţwˆăŚŕg#ŘşchĹ>óGˇĚˇnŮžr“ť ;`ňޏŸs(ä””–mű~íî"pŤ!í3‘-ľßg^:đ>óŠÁÖC;(Öť[™›źşşgg`@óŚpńĆCż™ë)ä0ZöÖ°°óđ%ż_=w­œ&p—>ëÝ1tď3Ođzw°uÇĐę}晪*ÓÇôK‰:°aŃDˆy•D-'Ă{ľ*ő ďřŰęéh ÜĹ~wŒ8$÷ťß¸ţH•Ńńâ…(B˘Ęč¨ĘčČTędbäsâř5B(‰6ěw—œ\^:.ƒŔÖC;(üîmúLe´ě}ęŸ; ĂÉĆşvr¤×ěwLjCrżűžÝgŚL˛7ř§ĺ…ĺü˜oĺœ7{KŇĹ~wŒÔÔŔş_˝zľgϞzzz***FFFŒ‰‰!î2 ƒLŽ‚„Â×"˅‘<ˇŐ&Ą-~÷ó{—ôé<=0XݜߨŮFôó:˛y…źF`ż;FúÝßż˙ôćÍť­Ű缤|HIţ@žĹçóů|ž˛rÍ:TňôťŠ‚|KřşŃBažŞľzňË$úŻÚU€Ë—/_˝zľ€í&ÝłgOřąšPOOď͛7FFFßľ“–Š\n(n ˘¸‘bľ˘$ËŁ˘˘Ł˘˘jŁŞŚë݉_ˆ’’’ŚŚŚťťűöíŰk´˘iN‘,w­X¤^ď^§ŕőŹw_˛hW“&ěYsFţtčË—ź›gÁAxee%ÓMˇďœß§o íbK<ם‹´ŮÔÍHttô† ĐQr€>ëÝEZ(aKGž–ĐĘČ ƒ!ŃqˇnÝZ˝z5“É\łfͨQŁ ?~u˝–éŇĐďNŒĚ‹Ť?{öŹŤŤŤ‰‰‰‡‡ÇŐŤW–Kz@Ř‘VćřńăÖÖÖ,ËÁÁĄ.Ć?$˛î<€‘#G’…ŽŽŽQQQ[öďÝťWIIięÔŠĽĽĽ˛Ëä ×Ÿ›7o˙vďޝ¸đéÓ§œœœéÓ§˙ő×_ÂŃGŒńŕÁƒŇŇŇoߞݚsgĈu‘I)@Żx**߇R 'Nœhfffiišpá²˛2$Gż˘#FřřřH¨YŘIväČGGÇž}űfee‰T›––6pŕ@SSSccăŽ]ťCIä`...†††ŠŠŠ’’bhhŘŠS§ZV…ß˝Ni ~w _őLMMë:'ő ýîS‡×SŚÝ|Ś–éĘ˝ť°Ó]rÂĂĂRSSËĘĘŢźy3~üřǏ×E&iBm愝?~Ô¨QIIIeeeŻ_ż>~á…OžEŽS$\ďŢś5qíęćř(ćˆ–—pŹžÎë݉7Eb€ š†††fdd:t¨˛˛R`žuBçőîÂVľę§N*))9wî\eeĺć͛e›¨DÖŮőŒŒ IŻ[ˇÎČČhýúő))?ý”•• ŞŞŠTVVr A}÷ČČČĘĘĘČČHřŮş/]şTGGgá…'}řđáĐž}{—+VäććJžtahhhjj2`Ŕâ•čʕ+ЧOŸ_~ůΝ;GŽŇľkWŠS\´hR‹*PXíőë×---WŻ^=}útČĚ̆Ź{DDń/’ČęőîuGCZď~ăƍ‡†††˘—]hÓŚpÇ}Ú´i>>>ŠŠŠnnnDyž˛€„K–,7n\\\ܘ1c–.]Š„čîʕ+÷ďߏ^233œœnßžîzzz’Ýdő—ĆłĎ|6‰šĆEĆŐßßßÄÄdܸqđôéS™çPň_ďÎ'QÓ¸/_ž€áÇŤŠŠ 4=z$ŰěIdÝťté‡BŠË٧§ˇe˖’’’ŠS§ Čŕß˙%$čéŃÖŽÁʉ‰IëÖ­łłł9ňĺËb~>Ï%%Eۡo_`` ››[zzúŞUŤč0%$;;;+++55544TWW Ń3jmmmnn?~$GŃŇŇŞMŠşşşč,Ëüü|‘j÷îÝŰŤWŻÔÔÔ­[ˇ‚ĐĚĚÍÍMKKëɓ'ŠŠŠ111ęęęîîîľÉěwŻ=üń‡††Fßž}ËËË)‚…„„DDD˜››ĎŸ?˙ôéÓ!Ż]ťÖľkWčÚľ+zű$ ľąą8p (++ŻYłfÁ‚|>˙őëן?&űÎę/xŸyI wŢ ŢŐ%5ÂuőĺËŮ&!‘uŸ1cŹYłfíÚľ™™™ĺĺĺ\.wţüůâ1˘G7nÜ ŕ˙ű_BBBEEEFFĆěŮłŔŢŢžF9FÝ÷ŔŔ@řšăëׯ/**BămÚ´ŽËd2WŹXqďŢ˝{÷îŔÇÉwy<zóđăM(55˝Aúô‰|ˇFŁÂäćć.!ÔŽ_żžĎ燄„ˆSEÁ˜Lڧ§geeĺâŋ+++=<<˜LfmrEűÝk1‡ƒŸŒŒŒWŻ^ůůů :Tş´ÔŐŐÉÝÜÜZ´hqôčŃÝťwO›&¸Ýo=ď3OAnn.rÖ Ć<$$$##Cdۅ!ʌ““œ8q˘´´ő–Š_ÄĽ@"ëîééXQQńÇ4k֌Éd:99mÚ´‰ÍfoذAd”ŕŕ`‹E–,Z´HYYůƍvvvŞŞŞÍ›7?uęƒÁ˜7ŻfťŽ ‹žžž?OŠ€ăǏkii…„„€Hľ;vDsŹŹŹŔŐŐÉŮl6čëëO˜0ĄF™Š#zőę˙ý÷ăǏ eť”bëÖ­¨ď%ÎSŽFS¸\î‘#GŞÍ$ޗĄÓ°ß]ŽXZZ&%%ąŮěV­ZĄĄ/ÚĘ˘ŞŞęýű÷h•Śz_żqㆯŻ/ľÚŔŔŔ-[ś<~ü 96đ>ó"AýÖ­[Ϝ9~ô'Ožlbb‚f]řůůÉ-3vöNČdŇ+ł`Á1b‹ĹBVŠoßž˛MQҍ“VŹXŃťwo‡ŁŹŹÜŞUŤ%K–¤¤¤ˆëÁ[YY-^ź˜,ńőő˝y󌡡ˇŽŽ.ƒÁĐŇŇňđđŻé𸧧'šĘ§˘˘Ň­[7ň­Ă‡5iŇ$,,Ldłrúôi___ 55ľž={=zÉׯ_ߤI‹ELR,AAAcÌ 4hP׎]8 Cĺ...:tXśl™Čk׎ełŮŁFJHH ĐÓŁGbNĽl­;öť×ňš%ň7řy…ĽĽĺŋÍÍÍýýýCCC‰čČaoff6oŢČV§Ü łßƒ‰¤'Ŕb0rŁQďnlllffśqăFřů@Utaccƒ.BCC­­­‰aĆOŸ>őîÝŰĚĚlçΝmÚ´!ÔFGGˇiӆiHNNvww_´hňxź‘#G:88Œ=L).ĄŘŘXc^Ef1cĆ [[[77ˇţůI,,,JJJΊŠSň,É|ž;ýĄůůîň[w íhTçťO›6ÍÇÇ'55ŐÍ͍Çă@ffŚ““Óíۡ ;;ŰÓÓs÷îݨƒ›••‹_GŃ/^ěé限ŕěěüőëWBí7>|H‰4Ź\šr˙ţý„%^˛dɸqăâââÌłtéR"˜pBmÚ´îd g>> ŕîݝ𳚸633KHHĐĐĐ ë444üô铊ŠŠpŹôôtuuu"¤ššybb"‹Ĺ*--ľąąA6XdB"?ŠĚü“'OfϞ––fgg+N•85Í’Ź¨çťcŔťŮÁëÝ1´ŁQůÝ}||222rss;6tčД”psskѢĹŃŁG=z4mÚ4Šč|>ż˘˘BXŽLť0dÓ^{Df> `îÜšƒ *))ą˛˛’ar űÝ1ő<2ĄĘďnii™””Äfł[ľjU\\LȡlŮňřńăAƒQD÷ôô<ţ|eeett´CÖ>>>7n܀7nřúúĘ$ó_ż~ľłł+++;~ü89°ŞŞjxxxUUŐű÷ď>R IďüäɓrČI}‡zgěFĺw ŃŠľ°°¨ËÁ<ŘďNđâĹÓׯC ;vŤáéÓ§WŽ\%EÔŐwëŢ÷ńŠ#zôčĄč,Ô{đůîŘ˘Ó |ž;ýÁçť ă9ó ĆKěˆk˛`Ţźy›6m’męŐf S/hT~wL˝űÝ .Z1ab6Qt^~‚†çťŻXą" š4Q@]}wËĘţ‰´îՆŹSd˜ňŹSűÝqŻKĐČ3öťcčöť7čfÝ‹<œČě?^UUU[[ű˙ű’ ĂĂ͌Œš6mzőęU"|Ż^˝:věřôéSxöěY‡Č /^źhjjŞĽĽľaĂ"Jż~ýÔÔÔΟ?$çΝÓ××=z´ ˆ‘-GţŚxy…ä ×06›ŁŽ!W€ŸIŒtČžďNţH™ˇąąą´´žďŽh;gžú|w…@‹9ó2„<2O–_ž|š˙ţ͚5ťv횇‡!OKKëŃŁŸĎOOO'„666ććć˗/˙đáĂĺ˗ŃB^‚ëׯ‡……˝zőŞ ŕ?O˜ŻŻ/ƒÁ(//Gßżďíí=îőěwÇĐ ěw' íœyŽw§Ĺœy9`iiůúőë>}ú 0 '' tttĚÍÍoŢź ćććD`ƒĄŽŽ>lذ!C†üňË/K~GŒqřđaƒ1pŕ@rr ‹ˆˆ´Ś~ĎwÇĐ zžďŽÁP ?ëpěŘąŇŇŇżţú \\\š4iRRR˛mŰśńăÇŤ¨¨8p@ ʔ)SśnÝ, ůä•J•——×_#kkksrrŞŤŤ5îMHHŔZÝożývbbbCCCyyy]]Ýşuë´§é|´~™aQúîbąřÜšsŢŢŢĄĄĄ¤(˙ZşsçNPPĐŚM›đŕ͛7ľľľľ%&&NŸ>=))ŠŁŁŁżˇťşşöôôˆ˙‚ÜË˝öôôÔgüÝťwĂÂÂ^yĺ•k׎‰9pÍŔסoßöńń™MţÄ#Úźűîť3fĚ@‘Ż~ěh/^źhŃ"„ĐçŸ͟œœüꍯ"„šššúkçŚM›˘ŁŁBUUUÜńŕŕŕ_|!tćĚww÷>ř ##!ÔŇҢ=ÍřGӇĽĹÝťťťoÝş•˝eË<‚Ţ|úé§Ä™ůůůiďźsssWŹXńĂ?$''“$ăoohhŔó1Ą––__ßsçÎáńŇŇR}–çććććć~˙ý÷xIᚁÉËË+++ťwď^nnîƍ5^5<!´f͚đđđúúz‰DÂË^âMŇ/žbžřŠÉĄěXž˝íŽľŚŠTĘ0 Ă0ć?–G”Ç݇ Úߪ‰äůçŸŻŽŽŽŻŻżv횭­mPPÎ{'Nœˆ/ČY%öŠăƍĂGýÍÍÍÜů$ŻD­V÷×N˛&îH ýöíۗ——ścǎˆˆ¤w<ÍřGӇĽĹÝç͛gee5oŢź´´4î¸L&łľľ5°uF•——ăÛŕŕ`Qcn×F$mÝş5;;űÔŠSľľľ­­­ĄĄĄú&÷ÝwŸ}ö™Mpp°áeĺrůkŻ˝†Żmmmű;s˙ţý+WŽtqqqrrúňË/űń<ƒÄÝ 3üž= @!¤ŃCÝ̘{ď^VV6zôh†a4šĎ˜LVVžŹ̓MHH˲ď˝÷˲sćĚąąą1ň^ěď;::đIŹŁŁă`YŐŢގ35ROE"ž())éëëŰżżNŸ§ äŃ0w×řľdŘ >“o—H$SŚL9|řpiiéš5kL6€űűŇßߟœpťR93<<źŠŠéÖ­[ K–,1Ů$“¸; 8Ěíݗ.]zôčŃČČČÁް'Mjé,Ů7@XXúë œDŚ_xáôŹbüívâĉożý!´|ůňÁ2iǎ¸o˘žHů˜1cBJĽňĐĄCÖŃůhĆcQqw„Đ•+Wž>}ZUUő̰6ááá8ݲ˘˘"""„wˇśśfF­V7668pćççôŃGWŻ^5pďœ9s._žÜŰŰ{ńâE[ZZ¸ĺŹ3gÎdFăśń3ÝÝÝoßžmooďććÖÝÝmÂcˆťţ]Rż$*~IÔżK řśĺox˙Ă××חo+ţFAAATTTTTTAŸ•éŢ˝˛˛ŇĹĹĹŰŰűŇĽKxD§ÚWş ÷1bŮj—••?~ŊdDçvęp\­92ů™fPÂüůó‰ÍÄŮÚÚ–śËĘĘzçw ˇnÝşnÝ:óóóHXƒÂÂB{{űe˖ŐŐŐXG磏ĽĹÝǏďďď_RRRXXˆG´Ü'őŒ;X\\|čĐ!77ˇĂ‡ő÷v„L&KMMuvvÎĘƚ6mœ4iŇŹYłRRR ÷r.*****’H$ÜĂ™LśzőęÄÄÄe˖cÖŻ_Ť?$ÉśmŰú;ÓÝÝý›ožqqqIMM•Éd&|Čâîjsć)Źwç7gŢô^u^^^ĹĹĹbą8))éçŸFzÔŢ4¤Űˆ4šđđđŘšs'˲DĚM{VóňňŇŠ§1Ů3Lü°[#nöěŮwîÜń÷÷?sćŒÉVщáG}wč=š3gŽ\.אx0b<†{Ձž;!aégĘO"„Â"˘ű–osţmúîoźńŽLŽŽŽĆG­ćÄtďnmmýřńcnHŐĘĘŞťťťŻŻo̘1ėŤŐjźS×çšGŐŮŮŮ××7zôhîKjľZ$‘źÎɓ'ą:\CCƒž1ĂÄkđź{wwwcccDDDww÷öíۓ““MśŠ6Œy4ĂŢ!„ʇÎB}\¸Ş|4vfĐksuž:tŢ}(–ܝ˝‘†‘[¨z~aŘť#„ĆŽĺaűuńÂ?žŚďß$/ÔÜP¨T¸ŚŃś ;ÚźťBĄŔUćϰ3=gŢŐŐľŞŞjěŘąIIIx‹ŹOíÍđ:nnnçΝ#-YBÖÖÖeeeŁFâNĂëčT‡ĂZs䯌™af<<ó>Ó\ÚǛ{“DĄ;4Á$ ŸbpŠŤUÚŮýdţ>óÓ}Ü;;)Ú¸#Šsć)Ôwç7gŢtďţńÇŻ\šňɓ'Ä#ÔŢ PXXEp;–˜˜¨Ń)Ł­G´ćȈif˜™ß~űo†Š?čť´úîôCĄž;żđŻ7nܸ‹/śśśŽZľŠrŸ7čqw‹âîm@ÜÝH¨í3/żt~Ěs($$„oCţ~űĚóßÍćŔqqqÝÝÝU‹ôÝÚ}wΙG ­NŸΙGäăłâßťÇĆĆŽŠ, ‹Šť‚âîôăý_{6ôÂżw îĐÄÝ 9›¤ŤRŇBbąßśü {{^Ú B*•ڧ§#„xřŹŔťÔai}ćú>ójsć)D¨9ó€Nř6Ađ@Ü  ˆť‚źű ƒK큁qw€6 îN 6gžÂzwKϙGşúÍCVVև~8”vő†ař6a˜qw€6 îN 6gžÂzwKϙçŇŻ˛űíۡSĺÝ###ů6a˜qwҎśCŃC^X}é!î~Ph‹ËHżŘłgĎ:::Nš4 Ťˆ"]rsˆžţ˛Ŕ `ąúîýÂÉɉűWž’e٧OŸš°Ś1‹ó˛Śů}wBÎ&é_1_|ĹäĐt,O'RŠ”a†aĚ,xńî;wî”Éd¤S222Ž;vüřń 6ÁôôôŁG.]şýľËœŚ;` –ŚďÎeíÚľ^^^‰+Jé”pEšşşöôôhhź"„äršŸŸŸŁŁ#‰Ýž}ŰÇÇgňäÉ111XĐß"“ÉŚM›ĆŠs͛7ojźB¨ššyá…ÎÎÎ{öěńóóÓg|żÖlkkKLLœ>}zRRRGG‡;yôÝ 3ü„E.‹¤-yžB}÷€€€ČČČČČH^’çyčDŤ-.§Sç ëĘXYYýńÇȠܜŮ0܉,.\¸€šŤçňđĽÖ6!BßKćéDŰŐŐeggWSSÝÔԄţ~‚­ďšŒŹYł&;;ťŞŞ*55őŢ˝{Ąřřř‚‚‚ŠS§*ŠŇŇRŹ !‹×Ż_Ÿ™™YYYIfę\SçřŠ+źźźÖŽ]{ăƍäääúúz}ĆżfZZZ\\܂ ***žţúëŇŇRv†;ŃĘ/]°łű1xîËCg€>=˘Ë‰Ň mőîüƒw÷đđŘłgW\N§FűÁƒ'Mšäęęú§Ąş4d>|hÎ2đîćÁbűĚWWWoذĄĄĄÁŰŰűć͛ř˝úĺݛ››­ŹŹ¸Ż:99%[[ŰťwďökMăÎÎÎuuuĎ=÷Ü3*G3óIDAT7~M—üqÔ¨QOž<ńôôlhh0ŇśÁúĚ ľ9óˆ>ďnq9óÚârÚěŢ˝;..ŽľľU"‘Čĺrs´Őá€áĹÖť§§§gffĆĆĆöôôL:UăUľZý̰kçâďďâĉA3!„P__Ÿv ß°ńBęÝ ÔćĚSż9ó<źeXXXSSÓďż˙…GČn˜\,\¸°ššY­V׎=çʕ+ŕڇ%wďęęňööîíí=rä´śśfŚĽĽeóćÍÜÉx\­V7668p@ߚ3gÎdŚłÓ¨ C#× )++cYV.—§ŚŚ0Ţř5ĂĂĂ+**Bză#|qwúŠ­U*•Jž­ ˆ?O桚ËđŻ08™j,6îŽP(6nÜŘŰŰťsçNü_RĽR1 łzőjOOĎÝťwcuKlĂ0ŠŠŠ"‘hÖŹY6lXźx1^DĽR‘„5•JŐŐŐľnÝşÓ§OO™2%66văƍÜWš×ÚkΞ=[#÷ OkiiY˝zuMMÍôéÓˇoßîĺĺĽĎxă×lkkKKKť~ýz@@Ŕž}űěíí Ř9@ÜÝHjn(T*œžé@Ub… ° …§˛:88˜?ą*Ęú€ź;żQ“ąŘ¸;Ŕ#w:zw~ą‚kØëׯóő1‹ťÔqw@pXÁ™<@Đg  č3O 6gžB}w‹Ë™ĚF^^^ZZâI]Řd Ď<@Đgž@mÎ<…úîĐg*řU6č3Đô™ŢýîÝť˝˝˝jľz„ &LŕŰŔÜ@Ü  ˆťr6IWĽ¤#„Äb!ň‚T*MOOG<žŇčÝëęęX–9r¤••x÷ Мyˆť´qwUUp\(Ôwç÷ô”FďΡ ĂćĚCÜ  ˆťÓ…úîüBŁw,ˆť´qwľ9ó9󚤤¤´śś˛,ż|ůržÍ0͙‡¸;@w'P›3O!3ŻIeeecc#Bčĺ—yčű8œhÎ<ÄÝڀ¸;ýPXďÎ/4zwň3ÇQ,`řqw€6 îN 6gžÂzwș×D&“őôôˆD"777žm6͙‡¸;@w'P›3O!3ŻIhh(ß& š3qw€6 î˝;`á@Ü  ˆť¨Í™§°Ţrć5ÉČČřĺ—_X–]´hZŚ!Мyˆť´qwľ9óÖťCÎź&/^T*•!wws˙Rf4gâîm@Ü4zwșˇp îĐÄÝ ÔćĚSż9ó#úúúĚ˙ކšpáBWW—H$rvvöňňâŰ#МyĽR‰šä揻ˇutśľ×s8?aÜ„JĽ2ŻQ€™‹ĹĄuÖŐ*íěţ×üq÷śśG3ôý›¸´ˇˇŮAăÇĂgő'4îÝçΝ˷ ÁćĚÓwOHH01U@ܝ~(Źwç˝;`ᐸ{ţŽĎBů˙łĚl×ëţaŘśłgĎţÔCâî˙Ě˙B(/ľŮŽ×ż+Čě€wh<™ĎÎÎŽ­­eYvţüů™™™|›#` Ĺýű÷BͰ3śĄŮbáFŢCc ßű@3Öťó Ţrć“yđŕAg7ßF`v(Źwç˝{qqqGG‡H$z饗řśEŘ4g 4z÷   žM&4g 4zw0__ßvŠéŕĐw׀Ɯůüü|…BÁ˛ěěŮłˇlŮ¡9rć° gž {÷ŤWŻ–——#„lmmůśEŘXŽG¸ĐމDř‚eymĄCăÉ|uuľJĽ‰D'Nô÷÷çŰ@`众Żóú_Ĺ0ă0>œÇš×Ţ€đ;†ÚŊ%„œIENDŽB`‚speech-dispatcher-0.9.1/doc/figures/architecture.pdf0000644000175000017500000000747411447133617017446 00000000000000%PDF-1.3 %Ç쏢 5 0 obj <> stream xœ˝XËvŰF Ýó+f™.4Áź—MNÚfU'ň.§ E˘mśÔĂz$Çýú^ %J˛%‘Žuzź0Ebf€ ŕ˜GĄ¤VÖx#˙ţO‹Ÿżqż*”L”|ŒřžŹ3š„ËűB‹Şp)(AFŞč’đNGé˝p–2eqW|ÎJC¤ĹŸŘtRPÚk-~ůDńĺˇÎM†8JoϤŕ•4ÂDrŇ[Ą=%–ŽÚĘhhwdsTáa6NÇŕÄËœç ˛Ö Ł˘¤„!—¤1Âë$~çózą JĆ U˛xڇř§“:´ć;k$‘éŔ7h0”J¨ëxűS o÷†h ŒćŐŢněO!tNP˛Ň§íZŽíď!4Ü{ťyŔޏE’.jŕŔ/ŸÇSńţŃ)Jc˝¸˝cń§ąť–Úŕ”Hl¸ď†ĂO7?ÝţUXçĄAXLÁq;)ŢMç“M]ňgňP‡đ9ď (řó/7ŸřNƒ­TÚ7ĐřA^‹č¤21‹Že9~˜lĹ•DeDf Ąe<ˏ‹şÖŐ|śâEo‹ĎűX&ďá/ʎJBWҀ1"B’ŠÂq,ďӌDzá+A>0{‡˛ Ňm…Ó$˝ ĺÓŃŒţnmůŠ\’–sŠŃҲjëGĄ ÔQDEŰLw/R Ň('j(ů@ĂŠ„0Ň)“U[=ÍÖĺŞú§\î‘FLkŤ<‰—L%ĘAۏJöđ÷XöZřO˜¨-¨ ‚s2ŠM-ću=?4îoí´Ôށ,Üiăz]Ăo™HŠź)›rWWë˛Wš„؆ÇfÚžqƀ›0B8,g^uÎ{Ë ćÁ fpo +"‘đ? sJV4héU:çĺîUŻCÜ@& ľÇH Xď30›rSŠĹ˛š/Ťő“ĐŻô6hKÇ~¤xěěó2×đ56… 6%ݘôÇdZožzZ€áź t"T<ߪِ›iLé!ôv[BˆĐ E҃׎)—ßË%œˇבń|™cÚp­vV~›o֋͚ż…Ö6%ęDŘľ0—ó¸[č A¤éłDţľo"kŤ9yűć0‘_X})žO0s窍 €ć&ůs!›˘ˇ`,m¤‰śi0^÷…Ş´‹í‹MAĄˇ'ć™B<̀˛ŽV‹&Š5ňĎ2 Žž-G˧žŠn#×oô1ĆŁuňˆ‰ÖŹí›ş}CźŚF@áÜäž˙L1„źŻŰ=÷o\‚Žň˙œřp ěMDŞEaSM÷őAŕKŕ=ôŚÍ ‚kúܛrYgç0+&äԑsžUłI5ť%ďĚ:ŚŘ6 ۞´[ü  prĄŇÖć€AšyZ?ĚgŮjƒ>“;ՋVŸ§(ĆSđ>7ʍ×ÓöÍnn:˘¨]n’ĄĚŠŰD$ÉómE÷Ş+Pb†x>€ŢĆ6ą3äŽ}ł8?ƒ€Ő°*í"Ltz[_z]ƒYUž‹Á;<<7őĺýhőpbÚŇ)ĄçóP„ëiĘo]•łő6GŞňp ¸ŘbK05ęć’hŽ;=˝m8z oSžvcbNgvęz{c‰ţKDbЧ:KÚő"pe„_´ŠrŸIš—Aă#Ę:¸Aĺ~ƒŒ“ v–v ˝ÎR€…ś+řxëé4‡¤ôŰ*őP­Öóƒ2ÔęöŔIÄ+yRżÚ#°Í3˝{]Aď¨|ƒ)W§ŚżœofQO^ b=voî–ňž!đÓ1ćÝB×Ŕ™„ ˝œ íü=~XÎgŐ*ßvœŔŢ`ú€űQ˜Đ: ,"ˆ˜ôVľ-ô2×Đ>R.­ă–âwŐýfyFuŠ|á„Í’ĎÍëŽţ ęPş Gv U.ې⤠VŘEP_ÚíŘ)“Gߐ_Ě›/hUf6žg;÷í ŕÁă65C°ÖڌŢďMş‰†€ó€š BčM(łĘ‡ç[$,k3hŽI$Ţşŕsń/)OÉőendstream endobj 6 0 obj 1516 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 22 0 obj <> endobj 23 0 obj <> endobj 18 0 obj <> endobj 13 0 obj <> endobj 21 0 obj <> endobj 17 0 obj <> endobj 12 0 obj <> endobj 16 0 obj <> endobj 11 0 obj <> endobj 9 0 obj <> endobj 20 0 obj <> endobj 15 0 obj <> endobj 10 0 obj <> endobj 19 0 obj <> endobj 14 0 obj <> endobj 8 0 obj <> endobj 2 0 obj <>endobj xref 0 24 0000000000 65535 f 0000001832 00000 n 0000003085 00000 n 0000001773 00000 n 0000001621 00000 n 0000000015 00000 n 0000001601 00000 n 0000001880 00000 n 0000003018 00000 n 0000002603 00000 n 0000002800 00000 n 0000002533 00000 n 0000002389 00000 n 0000002194 00000 n 0000002943 00000 n 0000002732 00000 n 0000002462 00000 n 0000002326 00000 n 0000002122 00000 n 0000002877 00000 n 0000002664 00000 n 0000002259 00000 n 0000001921 00000 n 0000001951 00000 n trailer << /Size 24 /Root 1 0 R /Info 2 0 R /ID [(ëšĎĽS^œ+ŒÄÚq~ťŸ)(ëšĎĽS^œ+ŒÄÚq~ťŸ)] >> startxref 3299 %%EOF speech-dispatcher-0.9.1/doc/figures/architecture.eps0000644000175000017500000005416411447133617017462 00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: /home/hanke/speechd/working/doc/figures/architecture.dia %%Creator: Dia v0.88.1 %%CreationDate: Sun Jul 7 23:02:39 2002 %%For: a user %%Magnification: 1.0000 %%Orientation: Portrait %%BoundingBox: 0 0 1531 615 %%Pages: 1 %%BeginSetup %%EndSetup %%EndComments %%BeginProlog [ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def /Times-Roman-latin1 /Times-Roman findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Times-Italic-latin1 /Times-Italic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Times-Bold-latin1 /Times-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Times-BoldItalic-latin1 /Times-BoldItalic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /AvantGarde-Book-latin1 /AvantGarde-Book findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /AvantGarde-BookOblique-latin1 /AvantGarde-BookOblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /AvantGarde-Demi-latin1 /AvantGarde-Demi findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /AvantGarde-DemiOblique-latin1 /AvantGarde-DemiOblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Bookman-Light-latin1 /Bookman-Light findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Bookman-LightItalic-latin1 /Bookman-LightItalic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Bookman-Demi-latin1 /Bookman-Demi findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Bookman-DemiItalic-latin1 /Bookman-DemiItalic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Courier-latin1 /Courier findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Courier-Oblique-latin1 /Courier-Oblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Courier-Bold-latin1 /Courier-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Courier-BoldOblique-latin1 /Courier-BoldOblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-latin1 /Helvetica findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-Oblique-latin1 /Helvetica-Oblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-Bold-latin1 /Helvetica-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-BoldOblique-latin1 /Helvetica-BoldOblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-Narrow-latin1 /Helvetica-Narrow findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-Narrow-Oblique-latin1 /Helvetica-Narrow-Oblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-Narrow-Bold-latin1 /Helvetica-Narrow-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Helvetica-Narrow-BoldOblique-latin1 /Helvetica-Narrow-BoldOblique findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /NewCenturySchoolbook-Roman-latin1 /NewCenturySchoolbook-Roman findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /NewCenturySchoolbook-Italic-latin1 /NewCenturySchoolbook-Italic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /NewCenturySchoolbook-Bold-latin1 /NewCenturySchoolbook-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /NewCenturySchoolbook-BoldItalic-latin1 /NewCenturySchoolbook-BoldItalic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Palatino-Roman-latin1 /Palatino-Roman findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Palatino-Italic-latin1 /Palatino-Italic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Palatino-Bold-latin1 /Palatino-Bold findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Palatino-BoldItalic-latin1 /Palatino-BoldItalic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /Symbol-latin1 /Symbol findfont definefont pop /ZapfChancery-MediumItalic-latin1 /ZapfChancery-MediumItalic findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /ZapfDingbats-latin1 /ZapfDingbats findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding isolatin1encoding def currentdict end definefont pop /cp {closepath} bind def /c {curveto} bind def /f {fill} bind def /a {arc} bind def /ef {eofill} bind def /ex {exch} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth pop} bind def /tr {translate} bind def /ellipsedict 8 dict def ellipsedict /mtrx matrix put /ellipse { ellipsedict begin /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc savematrix setmatrix end } def /mergeprocs { dup length 3 -1 roll dup length dup 5 1 roll 3 -1 roll add array cvx dup 3 -1 roll 0 exch putinterval dup 4 2 roll putinterval } bind def 28.346000 -28.346000 scale -5.020000 -25.585000 translate %%EndProlog 0.929412 0.945098 1.000000 srgb n 27.000000 6.000000 m 27.000000 25.500000 l 51.000000 25.500000 l 51.000000 6.000000 l f 0.100000 slw [1.000000] 0 sd [0.200000] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 27.000000 6.000000 m 27.000000 25.500000 l 51.000000 25.500000 l 51.000000 6.000000 l cp s 1.000000 1.000000 1.000000 srgb n 52.000000 8.500000 m 52.000000 11.500000 l 58.000000 11.500000 l 58.000000 8.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 52.000000 8.500000 m 52.000000 11.500000 l 58.000000 11.500000 l 58.000000 8.500000 l cp s 0.921569 0.921569 0.921569 srgb n 27.900000 8.450000 m 27.900000 24.450000 l 39.900000 24.450000 l 39.900000 8.450000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 27.900000 8.450000 m 27.900000 24.450000 l 39.900000 24.450000 l 39.900000 8.450000 l cp s 1.000000 0.870588 0.717647 srgb n 24.000000 6.000000 m 24.000000 25.500000 l 26.000000 25.500000 l 26.000000 6.000000 l f 0.010000 slw [0.200000] 0 sd [0.200000] 0 sd 0 slj 0.003922 0.003922 0.003922 srgb n 24.000000 6.000000 m 24.000000 25.500000 l 26.000000 25.500000 l 26.000000 6.000000 l cp s 0.984314 1.000000 0.796078 srgb n 41.000000 8.500000 m 41.000000 24.500000 l 43.000000 24.500000 l 43.000000 8.500000 l f 0.010000 slw [0.200000] 0 sd [0.200000] 0 sd 0 slj 0.003922 0.003922 0.003922 srgb n 41.000000 8.500000 m 41.000000 24.500000 l 43.000000 24.500000 l 43.000000 8.500000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf 0.000000 0.000000 0.000000 srgb (SSIP) dup sw 2 div 25.250000 ex sub 5.050000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.000000 scf sf (module) dup sw 2 div 42.000000 ex sub 7.000000 m gs 1 -1 sc sh gr (API) dup sw 2 div 42.000000 ex sub 8.000000 m gs 1 -1 sc sh gr /Courier-Bold-latin1 ff 1.200000 scf sf (speechd) dup sw 2 div 38.950000 ex sub 5.000000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.000000 scf sf (applications) dup sw 2 div 9.050000 ex sub 5.100000 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 6.000000 6.000000 m 6.000000 8.500000 l 14.000000 8.500000 l 14.000000 6.000000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 6.000000 6.000000 m 6.000000 8.500000 l 14.000000 8.500000 l 14.000000 6.000000 l cp s /Helvetica-Bold-latin1 ff 1.200000 scf sf (Emacspeak) dup sw 2 div 10.000000 ex sub 7.500000 m gs 1 -1 sc sh gr 0.170000 slw [0.200000] 0 sd [0.300000] 0 sd 0 slc n 10.050000 18.950000 m 10.050000 21.950000 l s /Helvetica-Bold-latin1 ff 1.000000 scf sf (synthesizers) dup sw 2 div 55.000000 ex sub 5.000000 m gs 1 -1 sc sh gr 0.913725 0.913725 0.913725 srgb n 44.000000 8.500000 m 44.000000 11.500000 l 50.000000 11.500000 l 50.000000 8.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 44.000000 8.500000 m 44.000000 11.500000 l 50.000000 11.500000 l 50.000000 8.500000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf (apollo) dup sw 2 div 47.000000 ex sub 10.500000 m gs 1 -1 sc sh gr 0.921569 0.921569 0.921569 srgb n 44.000000 16.500000 m 44.000000 19.500000 l 50.000000 19.500000 l 50.000000 16.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 44.000000 16.500000 m 44.000000 19.500000 l 50.000000 19.500000 l 50.000000 16.500000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf (flite) dup sw 2 div 47.000000 ex sub 18.500000 m gs 1 -1 sc sh gr 0.170000 slw [0.200000] 0 sd [0.300000] 0 sd 0 slc n 55.065000 20.620000 m 55.065000 23.620000 l s 0.454902 0.556863 0.658824 srgb n 29.465000 20.020000 m 29.465000 21.020000 l 39.465000 21.020000 l 39.465000 20.020000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 29.465000 20.020000 m 29.465000 21.020000 l 39.465000 21.020000 l 39.465000 20.020000 l cp s /Helvetica-latin1 ff 1.000000 scf sf (queue priority 1) 30.165000 20.770000 m gs 1 -1 sc sh gr () 30.165000 21.770000 m gs 1 -1 sc sh gr 0.921569 0.921569 0.921569 srgb n 44.000000 12.500000 m 44.000000 15.500000 l 50.000000 15.500000 l 50.000000 12.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 44.000000 12.500000 m 44.000000 15.500000 l 50.000000 15.500000 l 50.000000 12.500000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf (Odmluva) dup sw 2 div 47.000000 ex sub 14.500000 m gs 1 -1 sc sh gr 0.921569 0.921569 0.921569 srgb n 15.000000 16.000000 m 15.000000 18.500000 l 21.000000 18.500000 l 21.000000 16.000000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 15.000000 16.000000 m 15.000000 18.500000 l 21.000000 18.500000 l 21.000000 16.000000 l cp s /Helvetica-Bold-latin1 ff 1.200000 scf sf () dup sw 2 div 18.000000 ex sub 11.000000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.000000 scf sf (server) dup sw 2 div 34.000000 ex sub 7.000000 m gs 1 -1 sc sh gr (core) dup sw 2 div 34.000000 ex sub 8.000000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.000000 scf sf (output) dup sw 2 div 47.000000 ex sub 7.000000 m gs 1 -1 sc sh gr (modules) dup sw 2 div 47.000000 ex sub 8.000000 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 52.000000 16.500000 m 52.000000 19.500000 l 58.000000 19.500000 l 58.000000 16.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 52.000000 16.500000 m 52.000000 19.500000 l 58.000000 19.500000 l 58.000000 16.500000 l cp s /Helvetica-Bold-latin1 ff 1.200000 scf sf (Flite) dup sw 2 div 55.000000 ex sub 18.500000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.200000 scf sf () dup sw 2 div 49.065000 ex sub 22.620000 m gs 1 -1 sc sh gr 0.170000 slw [0.200000] 0 sd [0.300000] 0 sd 0 slc n 47.065000 20.620000 m 47.065000 23.620000 l s 1.000000 1.000000 1.000000 srgb n 52.000000 12.500000 m 52.000000 15.500000 l 58.000000 15.500000 l 58.000000 12.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 52.000000 12.500000 m 52.000000 15.500000 l 58.000000 15.500000 l 58.000000 12.500000 l cp s /Helvetica-Bold-latin1 ff 1.200000 scf sf (Odmluva) dup sw 2 div 55.000000 ex sub 14.500000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.200000 scf sf (Apollo) dup sw 2 div 55.000000 ex sub 10.500000 m gs 1 -1 sc sh gr 0.913725 0.913725 0.913725 srgb n 15.000000 6.000000 m 15.000000 8.500000 l 23.000000 8.500000 l 23.000000 6.000000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 15.000000 6.000000 m 15.000000 8.500000 l 23.000000 8.500000 l 23.000000 6.000000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf (elisp) dup sw 2 div 19.000000 ex sub 7.000000 m gs 1 -1 sc sh gr (library) dup sw 2 div 19.000000 ex sub 8.000000 m gs 1 -1 sc sh gr 0.110000 slw [] 0 sd [] 0 sd 0 slj 0 slc 0.921569 0.921569 0.921569 srgb n 23.000000 9.500000 m 15.000000 9.500000 l 15.000000 15.000000 l 22.000000 15.000000 l 22.000000 22.000000 l 23.000000 22.000000 l f 0.000000 0.000000 0.000000 srgb n 23.000000 9.500000 m 15.000000 9.500000 l 15.000000 15.000000 l 22.000000 15.000000 l 22.000000 22.000000 l 23.000000 22.000000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf (C library) dup sw 2 div 19.000000 ex sub 12.500000 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.000000 scf sf (Perl) dup sw 2 div 18.000000 ex sub 17.000000 m gs 1 -1 sc sh gr (binding) dup sw 2 div 18.000000 ex sub 18.000000 m gs 1 -1 sc sh gr 0.921569 0.921569 0.921569 srgb n 15.000000 19.500000 m 15.000000 22.000000 l 21.000000 22.000000 l 21.000000 19.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 15.000000 19.500000 m 15.000000 22.000000 l 21.000000 22.000000 l 21.000000 19.500000 l cp s /Helvetica-Bold-latin1 ff 1.000000 scf sf (Python) dup sw 2 div 18.000000 ex sub 20.500000 m gs 1 -1 sc sh gr (binding) dup sw 2 div 18.000000 ex sub 21.500000 m gs 1 -1 sc sh gr 0.170000 slw [0.200000] 0 sd [0.300000] 0 sd 0 slc n 18.500000 23.000000 m 18.500000 25.500000 l s 1.000000 1.000000 1.000000 srgb n 6.000000 9.500000 m 6.000000 11.105575 l 14.000000 11.105575 l 14.000000 9.500000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 6.000000 9.500000 m 6.000000 11.105575 l 14.000000 11.105575 l 14.000000 9.500000 l cp s /Helvetica-Bold-latin1 ff 1.200000 scf sf (Speakup) dup sw 2 div 10.000000 ex sub 10.650000 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 6.000000 11.400000 m 6.000000 12.955575 l 14.000000 12.955575 l 14.000000 11.400000 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 6.000000 11.400000 m 6.000000 12.955575 l 14.000000 12.955575 l 14.000000 11.400000 l cp s /Helvetica-Bold-latin1 ff 1.200000 scf sf (Bash) dup sw 2 div 10.040077 ex sub 12.555575 m gs 1 -1 sc sh gr /Helvetica-Bold-latin1 ff 1.000000 scf sf (client libraries) dup sw 2 div 19.000000 ex sub 5.050000 m gs 1 -1 sc sh gr 0.454902 0.556863 0.658824 srgb n 28.385731 22.606491 m 28.385731 23.606491 l 38.385731 23.606491 l 38.385731 22.606491 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 28.385731 22.606491 m 28.385731 23.606491 l 38.385731 23.606491 l 38.385731 22.606491 l cp s 0.454902 0.556863 0.658824 srgb n 28.935731 21.306491 m 28.935731 22.306491 l 38.935731 22.306491 l 38.935731 21.306491 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 28.935731 21.306491 m 28.935731 22.306491 l 38.935731 22.306491 l 38.935731 21.306491 l cp s /Helvetica-latin1 ff 1.000000 scf sf (queue priority 2) 29.685731 22.099854 m gs 1 -1 sc sh gr () 29.685731 23.099854 m gs 1 -1 sc sh gr /Helvetica-latin1 ff 1.000000 scf sf (queue priority 3) 29.185731 23.399854 m gs 1 -1 sc sh gr () 29.185731 24.399854 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 30.205076 17.155575 m 30.205076 18.255575 l 34.755076 18.255575 l 34.755076 17.155575 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 30.205076 17.155575 m 30.205076 18.255575 l 34.755076 18.255575 l 34.755076 17.155575 l cp s /Courier-latin1 ff 0.800000 scf sf (history) dup sw 2 div 32.505076 ex sub 17.905575 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 33.020076 14.835575 m 33.020076 15.935575 l 39.155076 15.935575 l 39.155076 14.835575 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 33.020076 14.835575 m 33.020076 15.935575 l 39.155076 15.935575 l 39.155076 14.835575 l cp s /Courier-latin1 ff 0.800000 scf sf (sound icons) dup sw 2 div 36.105076 ex sub 15.605575 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 29.270076 12.485575 m 29.270076 13.585575 l 37.655076 13.585575 l 37.655076 12.485575 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 29.270076 12.485575 m 29.270076 13.585575 l 37.655076 13.585575 l 37.655076 12.485575 l cp s /Courier-latin1 ff 0.800000 scf sf (synchronisation) dup sw 2 div 33.505076 ex sub 13.305575 m gs 1 -1 sc sh gr 1.000000 1.000000 1.000000 srgb n 32.220076 10.085575 m 32.220076 11.185575 l 39.146214 11.185575 l 39.146214 10.085575 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 32.220076 10.085575 m 32.220076 11.185575 l 39.146214 11.185575 l 39.146214 10.085575 l cp s /Courier-latin1 ff 0.800000 scf sf (configuration) dup sw 2 div 35.755076 ex sub 10.855575 m gs 1 -1 sc sh gr /Courier-latin1 ff 0.800000 scf sf () dup sw 2 div 30.561214 ex sub 4.585575 m gs 1 -1 sc sh gr 1.000000 0.999999 0.999999 srgb n 6.055077 13.385575 m 6.055077 14.655575 l 14.055077 14.655575 l 14.055077 13.385575 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 6.055077 13.385575 m 6.055077 14.655575 l 14.055077 14.655575 l 14.055077 13.385575 l cp s 1.000000 1.000000 1.000000 srgb n 6.005077 15.185575 m 6.005077 17.355575 l 14.005077 17.355575 l 14.005077 15.185575 l f 0.100000 slw [] 0 sd [] 0 sd 0 slj 0.000000 0.000000 0.000000 srgb n 6.005077 15.185575 m 6.005077 17.355575 l 14.005077 17.355575 l 14.005077 15.185575 l cp s /Courier-latin1 ff 0.800000 scf sf 0.479948 0.417519 0.909091 srgb (History client) dup sw 2 div 10.090077 ex sub 14.255575 m gs 1 -1 sc sh gr /Courier-latin1 ff 0.800000 scf sf (Configuration) dup sw 2 div 9.983078 ex sub 16.180265 m gs 1 -1 sc sh gr (client) dup sw 2 div 9.983078 ex sub 16.980265 m gs 1 -1 sc sh gr showpage speech-dispatcher-0.9.1/doc/figures/architecture.dia0000644000175000017500000000461111447133617017420 00000000000000‹í]MsŰ8˝űW°”ŤBŕ€qěŠdvggŞŚfS•ĚŮIÄ ErI*Žć°ż}˛KŠ ¨cF˘ěŠc‹f ú˝nźŕ7?Y&ÎgQ”q–Ţ ë ‘N˛iœÎo}üő5ü|{őfóŸäżyÁ—Žź#-ŐO7ƒEUĺ?F÷÷÷n˛.y•nŻÜRŒţǓ„ä/ˇďžňŠ×/đŞ*âńŞNʗâf0ć“Oó"[ĽÓćŽI–d…ó™'7ƒW3ý1Ýž}uď~S9ĎEń`e™ge,ŻUëüÉľ§÷ŠŻÍĽR^I硯ŢŻęˇl^hőţՒó8mL‚'őc`—bŒŰ>ĹÄJbĽą—wyVTŤĆŇ8ËÁÓÚXUŹD[Sĺ„'r^mb}Œ‰ĎqńЎ8­ űxcaÝʂU˙ŽâŠ(őđă‹Oď\4WGšž˝ü\ťF{é-ákQ4ĆŢmŠÍiú¤ńöúwłńĤjZýĄâé”Sçľó.ű2ؒł¤ćxz3řˇwŕ‰¤ ŻÍóćŮśˇé0h?ěĘĚxüŕ8ٜy"[şöĂ! Ű[‰XŢM˛"} ^ëĆiSÚˇw‘OŒŒ,D<_TťVZ;÷8+Ś˘8ĐŻ5%ڞWît¨ŰöÄt†Ú‡˝r‘Ýßí„QkŠ•ü*îĘjlÜT¤ŤĽ!LyšHD:ß×E.>Č5 lŔLÁáKGFŕ–‚pşL„ša8$ň FĚÚř Œ i×#<ňH?ŔĆ$É ü@ZÚřV. ¸Ň"KäÂɍŐçďRžąK ‡Š\Ć´GI—’.ŕyľOA9q)ü˘.őíčëzŚaüszH}Â8úl6cňăEóŕ;€%0 Ś0`‘”ť‹ďAƒĹ¤™°–ńl6ŸX>Š/Ő´„S:äÍ鈋Ă!sŮ5˘. •Ý֎UŠÇŮ?ů~tig°´”öDhs>|řý˝…Ö6ËŇÍű¨o_ĆÉúfŔ‹˜'G˘ĚwdO׿˙›H>‹*žđ×ď˛dÚöA Đs['RĂxwúŁ­žÄót)şí™i]+ůăߏŒ#“*¨‹†*YżĆŇý‡¤é€žżĚŚŤD\˝}˙űéš?9ĘýFň,Ÿ;ż’BćÇČ%J|#kř˜ĘŠ€‹<Ň >äBLÎ?â2çŐd!Šď††]0‰äâăp`8¨g j  ‡„Č%2ó \JŻe<Ćľ|tžç‰ôÇJöL١dˆö űgÍĚ̤Y‰•ľbŠ“ 8ĺ:™-‡g([`AäŮĐ !ÁPF™ ¨)‰rřďŸK>)sÁ?ůĄŁŠôƒřţˆSąĎß# řOÝŔóą?D‹ŽŽĽm’Hۧ!m?2iz'ŇŠnĺ3MŢšPʘj&´uę!m’[ŻĎĐ2×!U°}=ÝT-3, ָDč¸ŒÓÝH§œL‹}ŹĂo„[ŽÓj!ĘřoŮ=}K8MÇó3Nd\Őô=°ŢvÁDť`Â;ŃĎTʙú<…,Ö¸üçc¨4ÖGnPçąžďFĺąoó,I˛~%ąfCx–dZ‘)L5ŁfSśeS9•‡¤Óö­<>ýáVâÓȊOŰ/f}†P ÖuášS1Š}ŤZý5‘÷öUŰäyŠÄjކ0ˆű7@Úă’ţO”" WŃJxÔÚ˝W‹'ÝÔ*tS¸ČMś‘›nz‰ŰĹmfˇPŘFCÚÄlŚ|Ş‹€-Ę*–ÍéaĚf˝Žćcă:öĄŒÜëZ–Z×Ö"@Ţ_ŠBvŒ#ŮšgIŤŮXž'őC•<ׯ‹ K:*-dŤ*_UN˝źąĹ|).`lľH ˇzÖĂÂSŐĂ:̅ąo7‰‡Ń°˘Ç˝hX/›“‹†…íJb@ţJĂÂßCĂÂ5,|Ѱ^DĂÂĄU¸ĽpіlŁ- śôkbmdkP¨ÝčNô˘;˝|œíšîdW*"@žżYyB/+O^Úďű˝~ׯP0DČr_e•Ăúżk¨Ź˛Y9 •\>´uĎëË%ľ´N--v&Q°Idť3‰ÁíL˘—I&‘ŐˇÚ™Ä`v&I' şœƒ<×#fnťG™ZĺýۜÄú,cűȜü`4lÍ~lË~ňkä…‚(ŘP (?Č)° śÚ§† 6h*ťŮ˘‰ K€<řŻ?˙r>Žó¸ŹúG…}ŃąŔˇZŘƒŒëʍ§í ęšN7eœ…tţŹXú˙$[ą:3ZÜďUňK}ąă˘śáPž';€r°ÁştŠšHw€rNE–ĆĽ>ޤ@ŔýBhhÖÇz‰ŠŁB8˜dé,žŻŠŢ˘ ß'¸ůćç׋V'ŻQƒIĎ3‡Ţ6&=_šźŢüŹ+üíß=‚ݐžĽXB,Ä &–¨%.jIuîžIżˇV‚OA%ą:ĚĎ$‘ýśNBkGđVJ Š(ŃëĐNśü­ž):˛ÓŽžJœŤIKܞÎA—Çřj:Ęç™10Ťź™ÍQľ”ŔWÓGŞWH‡]œtŠ~ßÉ ń:/˛‰(Kůb“ç^×Uóżd†Ŕ&ZBij+ěöĂVţ@ĺĺ3Ův ›Ĺ0 ľ2$9öZěŚ8sr%™#OĎ6ťłäQlĹŁ†[% ,‰žĘnoA˘ j–œ! ˝ۗNę‚‘^Ö•Š$.s'‰Ç-ő˝ĐVv,Żö{ wt—F`]ŢŠ„úŁ „EX×ýî ďE‘ô=O0Bť‰†Ë0]ˇžŠů°35|™Šu–dD6ëů•ŽcfD5ßúÝäď×Ő"KűĚŻ~ż3 b Łbł6'ŃKxD_×B Äý;0ĆlDĎ2Í Vi…Ë2Č6É` 9˝¤Ľ̂[Đ$.RľśZĆđëŐj0ë/=N,ú˝>´;…&ÁŢŹUƏ×*űŹŃ̋8+âjíüw%V ŠĹÉŹŇěw‚"; @k•˝fnŠÖ*3˝2­ đUľCŇüŃ>˘ 8čžEó˝ü7/řňöę˙OžßîՓspeech-dispatcher-0.9.1/doc/figures/architecture-future.ps0000644000175000017500000015757411447133617020636 00000000000000%!PS-Adobe-1.0 %%BoundingBox: 0 0 594 842 %%Creator: Qt 3.3.6 %%Title: architecture-future %%CreationDate: So kv? 13 17:39:43 2006 %%Orientation: Landscape %%Pages: 1 %%DocumentFonts: BitstreamVeraSans-Bold BitstreamVeraSans-Roman BitstreamVeraSans-Oblique %%EndComments %%BeginProlog % Prolog copyright 1994-2005 Trolltech. You may copy this prolog in any way % that is directly related to this document. For other use of this prolog, % see your licensing agreement for Qt. /d/def load def/D{bind d}bind d/d2{dup dup}D/B{0 d2}D/W{255 d2}D/ED{exch d}D /D0{0 ED}D/LT{lineto}D/MT{moveto}D/S{stroke}D/F{setfont}D/SW{setlinewidth}D /CP{closepath}D/RL{rlineto}D/NP{newpath}D/CM{currentmatrix}D/SM{setmatrix}D /TR{translate}D/SD{setdash}D/SC{aload pop setrgbcolor}D/CR{currentfile read pop}D/i{index}D/bs{bitshift}D/scs{setcolorspace}D/DB{dict dup begin}D/DE{end d}D/ie{ifelse}D/sp{astore pop}D/BSt 0 d/LWi 1 d/PSt 1 d/Cx 0 d/Cy 0 d/WFi false d/OMo false d/BCol[1 1 1]d/PCol[0 0 0]d/BkCol[1 1 1]d/BDArr[0.94 0.88 0.63 0.50 0.37 0.12 0.06]d/defM matrix d/nS 0 d/GPS{PSt 1 ge PSt 5 le and{{ LArr PSt 1 sub 2 mul get}{LArr PSt 2 mul 1 sub get}ie}{[]}ie}D/QS{PSt 0 ne{ gsave LWi SW true GPS 0 SD S OMo PSt 1 ne and{BkCol SC false GPS dup 0 get SD S}if grestore}if}D/r28{{CR dup 32 gt{exit}if pop}loop 3{CR}repeat 0 4{7 bs exch dup 128 gt{84 sub}if 42 sub 127 and add}repeat}D/rA 0 d/rL 0 d/rB{rL 0 eq{/rA r28 d/rL 28 d}if dup rL gt{rA exch rL sub rL exch/rA 0 d/rL 0 d rB exch bs add}{dup rA 16#fffffff 3 -1 roll bs not and exch dup rL exch sub/rL ED neg rA exch bs/rA ED}ie}D/uc{/rL 0 d 0{dup 2 i length ge{exit}if 1 rB 1 eq{3 rB dup 3 ge{1 add dup rB 1 i 5 ge{1 i 6 ge{1 i 7 ge{1 i 8 ge{128 add}if 64 add}if 32 add}if 16 add}if 3 add exch pop}if 3 add exch 10 rB 1 add{dup 3 i lt{dup}{2 i}ie 4 i 3 i 3 i sub 2 i getinterval 5 i 4 i 3 -1 roll putinterval dup 4 -1 roll add 3 1 roll 4 -1 roll exch sub dup 0 eq{exit}if 3 1 roll}loop pop pop}{3 rB 1 add{2 copy 8 rB put 1 add}repeat}ie}loop pop}D /sl D0/QCIgray D0/QCIcolor D0/QCIindex D0/QCI{/colorimage where{pop false 3 colorimage}{exec/QCIcolor ED/QCIgray QCIcolor length 3 idiv string d 0 1 QCIcolor length 3 idiv 1 sub{/QCIindex ED/x QCIindex 3 mul d QCIgray QCIindex QCIcolor x get 0.30 mul QCIcolor x 1 add get 0.59 mul QCIcolor x 2 add get 0.11 mul add add cvi put}for QCIgray image}ie}D/di{gsave TR 1 i 1 eq {false eq{pop true 3 1 roll 4 i 4 i false 4 i 4 i imagemask BkCol SC imagemask}{pop false 3 1 roll imagemask}ie}{dup false ne{/languagelevel where{pop languagelevel 3 ge}{false}ie}{false}ie{/ma ED 8 eq{/dc[0 1]d /DeviceGray}{/dc[0 1 0 1 0 1]d/DeviceRGB}ie scs/im ED/mt ED/h ED/w ED/id 7 DB/ImageType 1 d/Width w d/Height h d/ImageMatrix mt d/DataSource im d /BitsPerComponent 8 d/Decode dc d DE/md 7 DB/ImageType 1 d/Width w d/Height h d/ImageMatrix mt d/DataSource ma d/BitsPerComponent 1 d/Decode[0 1]d DE 4 DB/ImageType 3 d/DataDict id d/MaskDict md d/InterleaveType 3 d end image}{ pop 8 4 1 roll 8 eq{image}{QCI}ie}ie}ie grestore}d/BF{gsave BSt 1 eq{BCol SC WFi{fill}{eofill}ie}if BSt 2 ge BSt 8 le and{BDArr BSt 2 sub get/sc ED BCol{ 1. exch sub sc mul 1. exch sub}forall 3 array astore SC WFi{fill}{eofill}ie} if BSt 9 ge BSt 14 le and{WFi{clip}{eoclip}ie defM SM pathbbox 3 i 3 i TR 4 2 roll 3 2 roll exch sub/h ED sub/w ED OMo{NP 0 0 MT 0 h RL w 0 RL 0 h neg RL CP BkCol SC fill}if BCol SC 0.3 SW NP BSt 9 eq BSt 11 eq or{0 4 h{dup 0 exch MT w exch LT}for}if BSt 10 eq BSt 11 eq or{0 4 w{dup 0 MT h LT}for}if BSt 12 eq BSt 14 eq or{w h gt{0 6 w h add{dup 0 MT h sub h LT}for}{0 6 w h add{dup 0 exch MT w sub w exch LT}for}ie}if BSt 13 eq BSt 14 eq or{w h gt{0 6 w h add{dup h MT h sub 0 LT}for}{0 6 w h add{dup w exch MT w sub 0 exch LT }for}ie}if S}if BSt 24 eq{}if grestore}D/mat matrix d/ang1 D0/ang2 D0/w D0/h D0/x D0/y D0/ARC{/ang2 ED/ang1 ED/h ED/w ED/y ED/x ED mat CM pop x w 2 div add y h 2 div add TR 1 h w div neg scale ang2 0 ge{0 0 w 2 div ang1 ang1 ang2 add arc}{0 0 w 2 div ang1 ang1 ang2 add arcn}ie mat SM}D/C D0/P{NP MT 0.5 0.5 rmoveto 0 -1 RL -1 0 RL 0 1 RL CP fill}D/M{/Cy ED/Cx ED}D/L{NP Cx Cy MT/Cy ED/Cx ED Cx Cy LT QS}D/DL{NP MT LT QS}D/HL{1 i DL}D/VL{2 i exch DL}D/R {/h ED/w ED/y ED/x ED NP x y MT 0 h RL w 0 RL 0 h neg RL CP BF QS}D/ACR{/h ED/w ED/y ED/x ED x y MT 0 h RL w 0 RL 0 h neg RL CP}D/xr D0/yr D0/rx D0/ry D0/rx2 D0/ry2 D0/RR{/yr ED/xr ED/h ED/w ED/y ED/x ED xr 0 le yr 0 le or{x y w h R}{xr 100 ge yr 100 ge or{x y w h E}{/rx xr w mul 200 div d/ry yr h mul 200 div d/rx2 rx 2 mul d/ry2 ry 2 mul d NP x rx add y MT x y rx2 ry2 180 -90 x y h add ry2 sub rx2 ry2 270 -90 x w add rx2 sub y h add ry2 sub rx2 ry2 0 -90 x w add rx2 sub y rx2 ry2 90 -90 ARC ARC ARC ARC CP BF QS}ie}ie}D/E{/h ED/w ED/y ED/x ED mat CM pop x w 2 div add y h 2 div add TR 1 h w div scale NP 0 0 w 2 div 0 360 arc mat SM BF QS}D/A{16 div exch 16 div exch NP ARC QS} D/PIE{/ang2 ED/ang1 ED/h ED/w ED/y ED/x ED NP x w 2 div add y h 2 div add MT x y w h ang1 16 div ang2 16 div ARC CP BF QS}D/CH{16 div exch 16 div exch NP ARC CP BF QS}D/BZ{curveto QS}D/CRGB{255 div 3 1 roll 255 div 3 1 roll 255 div 3 1 roll}D/BC{CRGB BkCol sp}D/BR{CRGB BCol sp/BSt ED}D/WB{1 W BR}D/NB{0 B BR}D/PE{setlinejoin setlinecap CRGB PCol sp/LWi ED/PSt ED LWi 0 eq{0.25 /LWi ED}if PCol SC}D/P1{1 0 5 2 roll 0 0 PE}D/ST{defM SM concat}D/MF{true exch true exch{exch pop exch pop dup 0 get dup findfont dup/FontName get 3 -1 roll eq{exit}if}forall exch dup 1 get/fxscale ED 2 get/fslant ED exch /fencoding ED[fxscale 0 fslant 1 0 0]makefont fencoding false eq{}{dup maxlength dict begin{1 i/FID ne{def}{pop pop}ifelse}forall/Encoding fencoding d currentdict end}ie definefont pop}D/MFEmb{findfont dup length dict begin{1 i/FID ne{d}{pop pop}ifelse}forall/Encoding ED currentdict end definefont pop}D/DF{findfont/fs 3 -1 roll d[fs 0 0 fs -1 mul 0 0]makefont d} D/ty 0 d/Y{/ty ED}D/Tl{gsave SW NP 1 i exch MT 1 i 0 RL S grestore}D/XYT{ty MT/xyshow where{pop pop xyshow}{exch pop 1 i dup length 2 div exch stringwidth pop 3 -1 roll exch sub exch div exch 0 exch ashow}ie}D/AT{ty MT 1 i dup length 2 div exch stringwidth pop 3 -1 roll exch sub exch div exch 0 exch ashow}D/QI{/C save d pageinit/Cx 0 d/Cy 0 d/OMo false d}D/QP{C restore showpage}D/SPD{/setpagedevice where{1 DB 3 1 roll d end setpagedevice}{pop pop}ie}D/SV{BSt LWi PSt Cx Cy WFi OMo BCol PCol BkCol/nS nS 1 add d gsave}D /RS{nS 0 gt{grestore/BkCol ED/PCol ED/BCol ED/OMo ED/WFi ED/Cy ED/Cx ED/PSt ED/LWi ED/BSt ED/nS nS 1 sub d}if}D/CLSTART{/clipTmp matrix CM d defM SM NP} D/CLEND{clip NP clipTmp SM}D/CLO{grestore gsave defM SM}D /LArr[ [] [] [ 13.333 4.000 ] [ 4.000 13.333 ] [ 4.000 4.000 ] [ 4.000 4.000 ] [ 6.667 4.000 4.000 4.000 ] [ 4.000 6.667 4.000 4.000 ] [ 6.667 4.000 4.000 4.000 4.000 ] [ 4.000 6.667 4.000 4.000 4.000 4.000 ] ] d /pageinit { % 210*297 mm (landscape) 90 rotate 0.75 -0.75 scale/defM matrix CM d } d %%EndProlog %%BeginSetup % Fonts and encodings used /BitstreamVeraSans-BoldList [ [ /BitstreamVeraSans-Bold 1.0 0.0 ] [ /BitstreamVeraSans-Bold 1.0 0.0 ] [ /Helvetica-Bold 0.936 0.000 ] ] d %%BeginFont: Bitstream Vera Sans Bold %!PS-Adobe-3.0 Resource-Font %%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. %%Creator: Converted from TrueType by Qt 25 dict begin /_d{bind def}bind def /_m{moveto}_d /_l{lineto}_d /_cl{closepath eofill}_d /_c{curveto}_d /_sc{7 -1 roll{setcachedevice}{pop pop pop pop pop pop}ifelse}_d /_e{exec}_d /FontName /BitstreamVeraSans-Bold def /PaintType 0 def /FontMatrix[.001 0 0 .001 0 0]def /FontBBox[-198 -235 1417 928]def /FontType 3 def /Encoding StandardEncoding def /FontInfo 10 dict dup begin /FamilyName (Bitstream Vera Sans) def /FullName (Bitstream Vera Sans Bold) def /Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc.) def /Weight (Bold) def /Version (Release 1.10) def /ItalicAngle 0.0 def /isFixedPitch false def /UnderlinePosition -227 def /UnderlineThickness 258 def end readonly def /CharStrings 27 dict dup begin /.notdef{600 0 50 -176 550 705 _sc 50 -176 _m 50 705 _l 550 705 _l 550 -176 _l 50 -176 _l 106 -120 _m 494 -120 _l 494 649 _l 106 649 _l 106 -120 _l _cl}_d /colon{400 0 112 0 288 547 _sc 112 547 _m 288 547 _l 288 358 _l 112 358 _l 112 547 _l 112 189 _m 288 189 _l 288 0 _l 112 0 _l 112 189 _l _cl}_d /A{774 0 5 0 769 729 _sc 534 133 _m 240 133 _l 194 0 _l 5 0 _l 275 729 _l 499 729 _l 769 0 _l 580 0 _l 534 133 _l 287 268 _m 487 268 _l 387 558 _l 287 268 _l _cl}_d /B{{762 0 92 0 692 729 _sc 384 447 _m 413 447 435 453 451 466 _c 466 479 474 498 474 524 _c 474 549 466 568 451 581 _c 435 594 413 601 384 601 _c 280 601 _l 280 447 _l 384 447 _l 565 390 _m 605 378 636 357 658 325 _c 680 293 692 255 692 209 _c 692 139 668 86 620 52 _c 572 17 500 0 404 0 _c 92 0 _l 92 729 _l 374 729 _l 475 729 548 713 594 683 _c 639 652 662 603 662 536 _c 662 500 653 470 637 445 _c 620 420 596 402 565 390 _c 390 128 _m 428 128 456 136 475 152 _c 494 168 504 192 504 224 _c 504 255 494 279 475 295 _c 456 311 428 319 390 319 _c 280 319 _l 280 128 _l 390 128 _l }_e{_cl}_e}_d /D{830 0 92 0 778 729 _sc 280 587 _m 280 142 _l 347 142 _l 423 142 482 161 523 199 _c 563 237 584 292 584 365 _c 584 437 563 492 523 530 _c 483 568 424 587 347 587 _c 280 587 _l 92 729 _m 290 729 _l 400 729 483 721 537 705 _c 591 689 638 663 677 625 _c 711 592 736 554 753 511 _c 769 468 778 419 778 365 _c 778 310 769 261 753 218 _c 736 174 711 136 677 104 _c 637 66 590 39 536 23 _c 481 7 399 0 290 0 _c 92 0 _l 92 729 _l _cl}_d /I{372 0 92 0 280 729 _sc 92 729 _m 280 729 _l 280 0 _l 92 0 _l 92 729 _l _cl}_d /M{995 0 92 0 903 729 _sc 92 729 _m 331 729 _l 497 339 _l 664 729 _l 903 729 _l 903 0 _l 725 0 _l 725 533 _l 557 140 _l 438 140 _l 270 533 _l 270 0 _l 92 0 _l 92 729 _l _cl}_d /P{733 0 92 0 692 729 _sc 92 729 _m 404 729 _l 496 729 567 708 617 667 _c 667 625 692 567 692 491 _c 692 414 667 355 617 314 _c 567 273 496 253 404 253 _c 280 253 _l 280 0 _l 92 0 _l 92 729 _l 280 593 _m 280 389 _l 384 389 _l 420 389 448 397 468 415 _c 488 433 498 458 498 491 _c 498 523 488 548 468 566 _c 448 584 420 593 384 593 _c 280 593 _l _cl}_d /S{{720 0 72 -13 647 742 _sc 599 706 _m 599 552 _l 559 570 520 583 482 592 _c 444 601 408 606 374 606 _c 329 606 296 599 274 587 _c 252 575 242 556 242 530 _c 242 510 249 494 264 484 _c 278 473 305 464 343 456 _c 423 440 _l 503 424 561 399 595 366 _c 629 332 647 285 647 224 _c 647 144 623 84 575 45 _c 527 6 455 -13 357 -13 _c 311 -13 264 -8 218 0 _c 171 8 124 20 78 38 _c 78 197 _l 124 172 169 153 213 141 _c 256 128 298 122 339 122 _c 379 122 411 128 433 142 _c 455 156 466 175 466 201 _c 466 223 458 241 443 253 _c 428 265 399 277 355 287 _c 282 303 _l 209 319 156 344 122 378 _c 88 412 72 458 72 516 _c 72 588 95 644 142 683 _c 188 722 256 742 344 742 _c }_e{384 742 425 739 467 733 _c 509 727 553 718 599 706 _c _cl}_e}_d /T{682 0 5 0 677 729 _sc 5 729 _m 677 729 _l 677 587 _l 435 587 _l 435 0 _l 247 0 _l 247 587 _l 5 587 _l 5 729 _l _cl}_d /a{{675 0 43 -13 596 560 _sc 329 246 _m 292 246 264 239 246 227 _c 228 215 219 197 219 173 _c 219 151 226 133 241 121 _c 256 108 277 102 303 102 _c 336 102 364 113 386 137 _c 408 161 420 190 420 226 _c 420 246 _l 329 246 _l 596 312 _m 596 0 _l 420 0 _l 420 81 _l 396 47 370 23 341 9 _c 311 -5 276 -13 234 -13 _c 177 -13 131 3 96 36 _c 60 68 43 111 43 164 _c 43 228 65 275 109 305 _c 153 335 222 350 317 350 _c 420 350 _l 420 364 _l 420 391 409 411 387 424 _c 365 437 331 444 285 444 _c 247 444 212 440 180 432 _c 148 424 118 413 91 399 _c 91 532 _l }_e{128 541 165 548 203 553 _c 241 557 279 560 317 560 _c 415 560 486 540 530 501 _c 574 462 596 399 596 312 _c _cl}_e}_d /b{{716 0 84 -13 671 760 _sc 375 113 _m 412 113 440 126 460 154 _c 480 181 490 221 490 273 _c 490 325 480 364 460 392 _c 440 419 412 433 375 433 _c 337 433 309 419 289 392 _c 269 364 259 325 259 273 _c 259 221 269 181 289 154 _c 309 126 337 113 375 113 _c 259 467 _m 283 499 309 522 339 537 _c 368 552 402 560 440 560 _c 507 560 562 533 606 479 _c 649 425 671 357 671 273 _c 671 188 649 119 606 66 _c 562 13 507 -13 440 -13 _c 402 -13 368 -5 339 9 _c 309 23 283 47 259 79 _c 259 0 _l 84 0 _l 84 760 _l 259 760 _l 259 467 _l _cl}_e}_d /c{{593 0 43 -13 526 560 _sc 526 530 _m 526 387 _l 502 403 478 415 454 423 _c 430 431 405 435 380 435 _c 331 435 293 420 266 392 _c 238 364 225 324 225 273 _c 225 221 238 181 266 153 _c 293 125 331 111 380 111 _c 407 111 433 115 458 123 _c 482 131 505 143 526 159 _c 526 16 _l 498 6 470 -1 442 -6 _c 414 -10 386 -13 358 -13 _c 259 -13 182 12 126 62 _c 70 112 43 183 43 273 _c 43 363 70 433 126 484 _c 182 534 259 560 358 560 _c 386 560 414 557 442 552 _c 470 547 498 540 526 530 _c _cl}_e}_d /d{{716 0 45 -13 632 760 _sc 456 467 _m 456 760 _l 632 760 _l 632 0 _l 456 0 _l 456 79 _l 432 47 405 23 376 9 _c 347 -5 314 -13 276 -13 _c 208 -13 153 13 110 66 _c 66 119 45 188 45 273 _c 45 357 66 425 110 479 _c 153 533 208 560 276 560 _c 314 560 347 552 376 537 _c 405 522 432 499 456 467 _c 341 113 _m 378 113 406 126 426 154 _c 446 181 456 221 456 273 _c 456 325 446 364 426 392 _c 406 419 378 433 341 433 _c 303 433 275 419 255 392 _c 235 364 226 325 226 273 _c 226 221 235 181 255 154 _c 275 126 303 113 341 113 _c _cl}_e}_d /e{{678 0 43 -13 630 560 _sc 630 275 _m 630 225 _l 221 225 _l 225 184 240 153 266 133 _c 291 112 326 102 372 102 _c 408 102 446 107 485 118 _c 523 129 563 146 604 168 _c 604 33 _l 562 17 521 6 480 -1 _c 438 -9 397 -13 356 -13 _c 257 -13 180 12 125 62 _c 70 112 43 182 43 273 _c 43 362 70 432 124 483 _c 178 534 252 560 346 560 _c 432 560 500 534 552 482 _c 604 430 630 361 630 275 _c 450 333 _m 450 366 440 393 421 413 _c 401 433 376 444 345 444 _c 311 444 283 434 262 415 _c 241 396 228 369 223 333 _c 450 333 _l _cl}_e}_d /g{{716 0 45 -215 632 559 _sc 456 93 _m 432 61 405 37 376 22 _c 347 7 314 0 276 0 _c 209 0 154 26 110 79 _c 66 131 45 198 45 280 _c 45 361 66 428 110 480 _c 154 532 209 559 276 559 _c 314 559 347 551 376 536 _c 405 521 432 498 456 466 _c 456 547 _l 632 547 _l 632 55 _l 632 -32 604 -99 548 -145 _c 492 -191 412 -215 307 -215 _c 273 -215 240 -212 208 -207 _c 176 -201 144 -193 112 -183 _c 112 -47 _l 142 -64 172 -77 202 -86 _c 231 -94 260 -99 290 -99 _c 347 -99 389 -86 416 -61 _c 442 -36 456 2 456 55 _c 456 93 _l 341 433 _m 305 433 276 419 256 393 _c 236 366 226 328 226 280 _c 226 230 235 192 255 166 _c 275 140 303 127 341 127 _c }_e{377 127 406 140 426 167 _c 446 193 456 231 456 280 _c 456 328 446 366 426 393 _c 406 419 377 433 341 433 _c _cl}_e}_d /h{712 0 84 0 634 760 _sc 634 333 _m 634 0 _l 458 0 _l 458 54 _l 458 254 _l 458 302 457 334 455 352 _c 453 370 449 383 444 392 _c 437 403 428 412 416 418 _c 404 424 390 428 376 428 _c 339 428 310 414 290 386 _c 269 358 259 319 259 269 _c 259 0 _l 84 0 _l 84 760 _l 259 760 _l 259 467 _l 285 499 312 522 342 537 _c 372 552 405 560 441 560 _c 504 560 552 540 585 502 _c 617 463 634 407 634 333 _c _cl}_d /i{343 0 84 0 259 760 _sc 84 547 _m 259 547 _l 259 0 _l 84 0 _l 84 547 _l 84 760 _m 259 760 _l 259 617 _l 84 617 _l 84 760 _l _cl}_d /l{343 0 84 0 259 760 _sc 84 760 _m 259 760 _l 259 0 _l 84 0 _l 84 760 _l _cl}_d /m{{1042 0 83 0 963 560 _sc 591 456 _m 613 490 639 515 669 533 _c 699 551 733 560 770 560 _c 832 560 880 540 913 502 _c 946 463 963 407 963 333 _c 963 0 _l 787 0 _l 787 285 _l 787 289 788 294 788 298 _c 788 302 788 309 788 318 _c 788 356 782 384 771 402 _c 759 419 741 428 716 428 _c 682 428 657 414 639 387 _c 621 359 611 320 611 269 _c 611 0 _l 435 0 _l 435 285 _l 435 345 429 384 419 402 _c 409 419 390 428 364 428 _c 330 428 304 414 286 387 _c 268 359 259 320 259 269 _c 259 0 _l 83 0 _l 83 547 _l 259 547 _l 259 467 _l 280 497 305 520 333 536 _c 361 552 391 560 425 560 _c }_e{462 560 495 550 524 532 _c 553 514 575 488 591 456 _c _cl}_e}_d /o{687 0 43 -13 644 560 _sc 344 435 _m 305 435 275 421 255 393 _c 235 365 225 325 225 273 _c 225 220 235 180 255 152 _c 275 124 305 111 344 111 _c 382 111 411 124 431 152 _c 451 180 462 220 462 273 _c 462 325 451 365 431 393 _c 411 421 382 435 344 435 _c 344 560 _m 438 560 511 534 564 484 _c 617 433 644 363 644 273 _c 644 183 617 112 564 62 _c 511 12 438 -13 344 -13 _c 250 -13 176 12 123 62 _c 69 112 43 183 43 273 _c 43 363 69 433 123 484 _c 176 534 250 560 344 560 _c _cl}_d /p{{716 0 84 -207 671 560 _sc 259 79 _m 259 -207 _l 84 -207 _l 84 547 _l 259 547 _l 259 467 _l 283 499 309 522 339 537 _c 368 552 402 560 440 560 _c 507 560 562 533 606 479 _c 649 425 671 357 671 273 _c 671 188 649 119 606 66 _c 562 13 507 -13 440 -13 _c 402 -13 368 -5 339 9 _c 309 23 283 47 259 79 _c 375 433 _m 337 433 309 419 289 392 _c 269 364 259 325 259 273 _c 259 221 269 181 289 154 _c 309 126 337 113 375 113 _c 412 113 440 126 460 154 _c 480 181 490 221 490 273 _c 490 325 480 364 460 392 _c 440 419 412 433 375 433 _c _cl}_e}_d /r{493 0 84 0 490 560 _sc 490 398 _m 474 405 459 410 444 414 _c 429 417 414 419 399 419 _c 354 419 319 404 295 376 _c 271 347 259 306 259 252 _c 259 0 _l 84 0 _l 84 547 _l 259 547 _l 259 457 _l 281 493 306 519 336 535 _c 365 551 400 560 441 560 _c 447 560 453 559 460 559 _c 466 559 476 558 490 556 _c 490 398 _l _cl}_d /s{{595 0 52 -13 548 560 _sc 511 530 _m 511 397 _l 473 412 437 424 403 432 _c 368 440 335 444 304 444 _c 270 444 246 439 230 431 _c 214 423 206 410 206 393 _c 206 379 212 368 224 361 _c 236 353 258 348 290 344 _c 321 340 _l 410 328 470 310 501 284 _c 532 258 548 217 548 161 _c 548 103 526 59 483 30 _c 440 1 376 -13 291 -13 _c 255 -13 217 -10 179 -5 _c 140 0 100 8 60 20 _c 60 153 _l 94 135 130 122 167 114 _c 203 106 241 102 279 102 _c 313 102 338 106 356 116 _c 373 125 382 139 382 158 _c 382 174 376 185 364 193 _c 352 201 328 207 293 211 _c 262 215 _l 184 224 130 242 99 269 _c 67 295 52 335 52 389 _c 52 447 71 490 111 518 _c 151 546 212 560 294 560 _c }_e{326 560 359 557 395 552 _c 431 547 469 540 511 530 _c _cl}_e}_d /t{478 0 13 0 455 702 _sc 275 702 _m 275 547 _l 455 547 _l 455 422 _l 275 422 _l 275 190 _l 275 164 280 147 290 138 _c 300 129 320 125 350 125 _c 440 125 _l 440 0 _l 290 0 _l 221 0 172 14 143 43 _c 114 71 100 120 100 190 _c 100 422 _l 13 422 _l 13 547 _l 100 547 _l 100 702 _l 275 702 _l _cl}_d /v{652 0 15 0 637 547 _sc 15 547 _m 190 547 _l 326 169 _l 462 547 _l 637 547 _l 422 0 _l 230 0 _l 15 547 _l _cl}_d /y{652 0 12 -215 634 547 _sc 12 547 _m 187 547 _l 334 176 _l 459 547 _l 634 547 _l 404 -51 _l 380 -111 353 -154 323 -178 _c 292 -202 251 -215 201 -215 _c 100 -215 _l 100 -100 _l 155 -100 _l 184 -100 205 -95 219 -86 _c 233 -76 243 -59 251 -35 _c 256 -20 _l 12 547 _l _cl}_d end readonly def /BuildGlyph {exch begin CharStrings exch 2 copy known not{pop /.notdef}if true 3 1 roll get exec end}_d /BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec }_d FontName currentdict end definefont pop %% Font Page 00 /BitstreamVeraSans-Bold-ENC-00 [ /.notdef/M/e/s/a/g/D/i/p/t/c/h/r/T/S/A/P/I/o/v/d/B/l/y/m/b/colon/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef] def /BitstreamVeraSans-Bold-Uni-00 BitstreamVeraSans-Bold-ENC-00 /BitstreamVeraSans-Bold MFEmb %%BeginFont: BitstreamVeraSans-Bold %!PS-AdobeFont-1.0 Composite Font %%FontName: BitstreamVeraSans-Bold-Uni %%Creator: Composite font created by Qt 25 dict begin /FontName /BitstreamVeraSans-Bold-Uni def /PaintType 0 def /FontMatrix[1 0 0 1 0 0]def /FontType 0 def /FMapType 2 def /Encoding [ 0]def /FDepVector [ /BitstreamVeraSans-Bold-Uni-00 findfont ]def FontName currentdict end definefont pop %%EndFont %%EndFont /BitstreamVeraSans-ObliqueList [ [ /BitstreamVeraSans-Oblique 1.0 0.0 ] [ /BitstreamVeraSans-Italic 1.0 0.0 ] [ /Helvetica-Oblique 0.988 0.000 ] ] d %%BeginFont: Bitstream Vera Sans Oblique %!PS-Adobe-3.0 Resource-Font %%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. %%Creator: Converted from TrueType by Qt 25 dict begin /_d{bind def}bind def /_m{moveto}_d /_l{lineto}_d /_cl{closepath eofill}_d /_c{curveto}_d /_sc{7 -1 roll{setcachedevice}{pop pop pop pop pop pop}ifelse}_d /_e{exec}_d /FontName /BitstreamVeraSans-Oblique def /PaintType 0 def /FontMatrix[.001 0 0 .001 0 0]def /FontBBox[-261 -235 1259 928]def /FontType 3 def /Encoding StandardEncoding def /FontInfo 10 dict dup begin /FamilyName (Bitstream Vera Sans) def /FullName (Bitstream Vera Sans Oblique) def /Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc.) def /Weight (Oblique) def /Version (Release 1.10) def /ItalicAngle -11.0 def /isFixedPitch false def /UnderlinePosition -213 def /UnderlineThickness 143 def end readonly def /CharStrings 8 dict dup begin /.notdef{600 0 50 -176 550 705 _sc 50 -176 _m 50 705 _l 550 705 _l 550 -176 _l 50 -176 _l 106 -120 _m 494 -120 _l 494 649 _l 106 649 _l 106 -120 _l _cl}_d /F{575 0 27 0 587 729 _sc 169 729 _m 587 729 _l 571 646 _l 251 646 _l 209 431 _l 498 431 _l 482 348 _l 193 348 _l 125 0 _l 27 0 _l 169 729 _l _cl}_d /a{{613 0 41 -13 547 560 _sc 537 312 _m 476 0 _l 386 0 _l 403 83 _l 376 50 346 26 312 10 _c 278 -5 241 -13 200 -13 _c 153 -13 115 1 85 29 _c 55 57 41 93 41 138 _c 41 202 66 252 117 289 _c 168 326 238 345 328 345 _c 453 345 _l 458 369 _l 458 371 459 374 459 377 _c 459 380 460 385 460 392 _c 460 421 448 444 424 460 _c 400 476 367 484 325 484 _c 295 484 265 480 235 472 _c 204 464 172 453 140 439 _c 156 522 _l 190 534 223 544 255 550 _c 287 556 319 560 349 560 _c 413 560 462 546 496 518 _c 530 490 547 449 547 396 _c 547 385 546 372 544 358 _c 542 343 540 328 537 312 _c 440 275 _m 350 275 _l }_e{276 275 222 265 187 245 _c 151 225 134 195 134 154 _c 134 125 143 102 161 86 _c 179 70 204 62 236 62 _c 284 62 327 79 363 114 _c 399 149 424 196 436 255 _c 440 275 _l _cl}_e}_d /e{{615 0 46 -13 571 560 _sc 481 322 _m 481 327 482 332 483 338 _c 483 344 484 349 484 355 _c 484 395 472 426 449 449 _c 425 472 394 484 354 484 _c 309 484 270 469 236 441 _c 202 413 176 373 158 322 _c 481 322 _l 559 252 _m 141 252 _l 139 239 137 229 137 222 _c 136 215 136 209 136 204 _c 136 158 150 123 178 99 _c 206 74 245 62 296 62 _c 334 62 371 66 406 75 _c 441 83 474 96 504 114 _c 487 25 _l 454 11 420 2 386 -4 _c 352 -10 317 -13 282 -13 _c 206 -13 147 5 107 41 _c 66 77 46 128 46 195 _c 46 251 56 304 76 353 _c 96 402 126 446 166 485 _c 191 509 221 527 256 540 _c 291 553 328 560 368 560 _c 430 560 479 541 516 504 _c 552 467 571 417 571 355 _c }_e{571 340 570 324 568 307 _c 566 289 563 271 559 252 _c _cl}_e}_d /r{411 0 35 0 463 560 _sc 446 464 _m 436 468 426 472 414 475 _c 402 477 390 479 377 479 _c 329 479 287 460 251 424 _c 215 388 192 339 180 279 _c 125 0 _l 35 0 _l 142 547 _l 232 547 _l 215 462 _l 238 493 266 517 300 534 _c 333 551 368 560 406 560 _c 415 560 424 559 434 558 _c 444 557 453 555 463 553 _c 446 464 _l _cl}_d /s{{521 0 11 -13 500 560 _sc 500 531 _m 483 446 _l 459 458 433 468 407 475 _c 381 481 354 485 326 485 _c 278 485 241 477 214 461 _c 187 445 174 423 174 395 _c 174 363 205 338 269 321 _c 273 319 277 318 279 318 _c 308 309 _l 368 292 408 274 428 256 _c 448 238 458 213 458 182 _c 458 124 435 77 389 41 _c 343 5 282 -13 208 -13 _c 179 -13 149 -10 117 -5 _c 85 0 49 8 11 20 _c 29 113 _l 61 95 94 82 126 74 _c 158 65 188 61 218 61 _c 262 61 297 70 325 89 _c 352 108 366 132 366 161 _c 366 192 330 217 258 237 _c 249 239 _l 218 247 _l }_e{172 259 138 274 117 294 _c 96 314 86 339 86 370 _c 86 428 107 475 151 509 _c 195 543 254 560 330 560 _c 360 560 389 557 417 552 _c 445 547 472 540 500 531 _c _cl}_e}_d /t{{392 0 64 0 423 702 _sc 423 547 _m 409 477 _l 230 477 _l 172 180 _l 170 169 168 160 167 152 _c 166 144 166 139 166 135 _c 166 114 172 99 185 89 _c 197 79 217 75 245 75 _c 336 75 _l 321 0 _l 235 0 _l 181 0 141 10 115 31 _c 89 52 76 84 76 126 _c 76 133 76 141 77 150 _c 78 159 80 169 82 180 _c 140 477 _l 64 477 _l 78 547 _l 153 547 _l 183 702 _l 273 702 _l 243 547 _l 423 547 _l _cl}_e}_d /u{{634 0 57 -13 589 547 _sc 67 217 _m 131 547 _l 221 547 _l 157 220 _l 153 204 151 190 150 179 _c 148 167 148 158 148 151 _c 148 123 156 101 173 86 _c 190 71 214 64 245 64 _c 293 64 334 80 370 113 _c 405 145 428 189 439 244 _c 499 547 _l 589 547 _l 483 0 _l 393 0 _l 411 86 _l 385 54 355 29 320 12 _c 285 -4 248 -13 209 -13 _c 161 -13 123 0 97 25 _c 70 51 57 87 57 135 _c 57 144 57 156 59 171 _c 61 185 63 201 67 217 _c _cl}_e}_d end readonly def /BuildGlyph {exch begin CharStrings exch 2 copy known not{pop /.notdef}if true 3 1 roll get exec end}_d /BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec }_d FontName currentdict end definefont pop %% Font Page 00 /BitstreamVeraSans-Oblique-ENC-00 [ /.notdef/F/e/a/t/u/r/s/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef] def /BitstreamVeraSans-Oblique-Uni-00 BitstreamVeraSans-Oblique-ENC-00 /BitstreamVeraSans-Oblique MFEmb %%BeginFont: BitstreamVeraSans-Oblique %!PS-AdobeFont-1.0 Composite Font %%FontName: BitstreamVeraSans-Oblique-Uni %%Creator: Composite font created by Qt 25 dict begin /FontName /BitstreamVeraSans-Oblique-Uni def /PaintType 0 def /FontMatrix[1 0 0 1 0 0]def /FontType 0 def /FMapType 2 def /Encoding [ 0]def /FDepVector [ /BitstreamVeraSans-Oblique-Uni-00 findfont ]def FontName currentdict end definefont pop %%EndFont %%EndFont /BitstreamVeraSans-RomanList [ [ /BitstreamVeraSans-Roman 1.0 0.0 ] [ /BitstreamVeraSans 1.0 0.0 ] [ /Helvetica 0.988 0.000 ] ] d %%BeginFont: Bitstream Vera Sans %!PS-Adobe-3.0 Resource-Font %%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. %%Creator: Converted from TrueType by Qt 25 dict begin /_d{bind def}bind def /_m{moveto}_d /_l{lineto}_d /_cl{closepath eofill}_d /_c{curveto}_d /_sc{7 -1 roll{setcachedevice}{pop pop pop pop pop pop}ifelse}_d /_e{exec}_d /FontName /BitstreamVeraSans-Roman def /PaintType 0 def /FontMatrix[.001 0 0 .001 0 0]def /FontBBox[-182 -235 1287 928]def /FontType 3 def /Encoding StandardEncoding def /FontInfo 10 dict dup begin /FamilyName (Bitstream Vera Sans) def /FullName (Bitstream Vera Sans) def /Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc.) def /Weight (Roman) def /Version (Release 1.10) def /ItalicAngle 0.0 def /isFixedPitch false def /UnderlinePosition -213 def /UnderlineThickness 143 def end readonly def /CharStrings 41 dict dup begin /.notdef{600 0 50 -176 550 705 _sc 50 -176 _m 50 705 _l 550 705 _l 550 -176 _l 50 -176 _l 106 -120 _m 494 -120 _l 494 649 _l 106 649 _l 106 -120 _l _cl}_d /plus{838 0 106 0 732 627 _sc 460 627 _m 460 355 _l 732 355 _l 732 272 _l 460 272 _l 460 0 _l 378 0 _l 378 272 _l 106 272 _l 106 355 _l 378 355 _l 378 627 _l 460 627 _l _cl}_d /comma{318 0 77 -115 220 124 _sc 117 124 _m 220 124 _l 220 40 _l 140 -115 _l 77 -115 _l 117 40 _l 117 124 _l _cl}_d /hyphen{361 0 49 234 312 314 _sc 49 314 _m 312 314 _l 312 234 _l 49 234 _l 49 314 _l _cl}_d /slash{337 0 0 -92 337 729 _sc 254 729 _m 337 729 _l 83 -92 _l 0 -92 _l 254 729 _l _cl}_d /A{684 0 8 0 676 729 _sc 342 632 _m 208 269 _l 476 269 _l 342 632 _l 286 729 _m 398 729 _l 676 0 _l 573 0 _l 507 187 _l 178 187 _l 112 0 _l 8 0 _l 286 729 _l _cl}_d /B{{686 0 98 0 615 729 _sc 197 348 _m 197 81 _l 355 81 _l 408 81 447 92 473 114 _c 498 136 511 169 511 215 _c 511 260 498 293 473 315 _c 447 337 408 348 355 348 _c 197 348 _l 197 648 _m 197 428 _l 343 428 _l 391 428 426 437 450 455 _c 474 473 486 500 486 538 _c 486 574 474 602 450 620 _c 426 638 391 648 343 648 _c 197 648 _l 98 729 _m 350 729 _l 425 729 483 713 524 682 _c 564 650 585 606 585 549 _c 585 504 574 468 553 442 _c 532 416 502 399 462 393 _c 510 382 548 360 575 327 _c 601 294 615 253 615 204 _c 615 138 592 88 548 53 _c 504 17 441 0 360 0 _c 98 0 _l 98 729 _l }_e{_cl}_e}_d /C{{698 0 56 -13 644 742 _sc 644 673 _m 644 569 _l 610 599 575 622 537 638 _c 499 653 460 661 418 661 _c 334 661 270 635 226 584 _c 182 533 160 460 160 364 _c 160 268 182 194 226 143 _c 270 92 334 67 418 67 _c 460 67 499 74 537 90 _c 575 105 610 128 644 159 _c 644 56 _l 609 32 572 15 534 4 _c 496 -7 455 -13 412 -13 _c 302 -13 215 20 151 87 _c 87 154 56 246 56 364 _c 56 481 87 573 151 641 _c 215 708 302 742 412 742 _c 456 742 497 736 535 725 _c 573 713 610 696 644 673 _c _cl}_e}_d /D{770 0 98 0 711 729 _sc 197 648 _m 197 81 _l 316 81 _l 416 81 490 103 537 149 _c 583 195 607 267 607 365 _c 607 463 583 534 537 580 _c 490 625 416 648 316 648 _c 197 648 _l 98 729 _m 301 729 _l 442 729 546 699 612 641 _c 678 582 711 490 711 365 _c 711 239 677 147 611 88 _c 545 29 441 0 301 0 _c 98 0 _l 98 729 _l _cl}_d /E{632 0 98 0 568 729 _sc 98 729 _m 559 729 _l 559 646 _l 197 646 _l 197 430 _l 544 430 _l 544 347 _l 197 347 _l 197 83 _l 568 83 _l 568 0 _l 98 0 _l 98 729 _l _cl}_d /I{295 0 98 0 197 729 _sc 98 729 _m 197 729 _l 197 0 _l 98 0 _l 98 729 _l _cl}_d /K{656 0 98 0 677 729 _sc 98 729 _m 197 729 _l 197 421 _l 524 729 _l 651 729 _l 289 389 _l 677 0 _l 547 0 _l 197 351 _l 197 0 _l 98 0 _l 98 729 _l _cl}_d /M{863 0 98 0 765 729 _sc 98 729 _m 245 729 _l 431 233 _l 618 729 _l 765 729 _l 765 0 _l 669 0 _l 669 640 _l 481 140 _l 382 140 _l 194 640 _l 194 0 _l 98 0 _l 98 729 _l _cl}_d /O{787 0 56 -13 731 742 _sc 394 662 _m 322 662 265 635 223 582 _c 181 528 160 456 160 364 _c 160 272 181 199 223 146 _c 265 92 322 66 394 66 _c 465 66 522 92 564 146 _c 606 199 627 272 627 364 _c 627 456 606 528 564 582 _c 522 635 465 662 394 662 _c 394 742 _m 496 742 577 707 639 639 _c 700 571 731 479 731 364 _c 731 248 700 157 639 89 _c 577 21 496 -13 394 -13 _c 291 -13 209 21 148 89 _c 86 157 56 248 56 364 _c 56 479 86 571 148 639 _c 209 707 291 742 394 742 _c _cl}_d /P{603 0 98 0 569 729 _sc 197 648 _m 197 374 _l 321 374 _l 367 374 402 385 427 409 _c 452 433 465 467 465 511 _c 465 555 452 588 427 612 _c 402 636 367 648 321 648 _c 197 648 _l 98 729 _m 321 729 _l 402 729 464 710 506 673 _c 548 636 569 582 569 511 _c 569 439 548 384 506 348 _c 464 311 402 293 321 293 _c 197 293 _l 197 0 _l 98 0 _l 98 729 _l _cl}_d /S{{635 0 66 -13 579 742 _sc 535 705 _m 535 609 _l 497 627 462 640 429 649 _c 395 657 363 662 333 662 _c 279 662 237 651 208 631 _c 179 610 165 580 165 542 _c 165 510 174 485 194 469 _c 213 452 250 439 304 429 _c 364 417 _l 437 403 491 378 526 343 _c 561 307 579 260 579 201 _c 579 130 555 77 508 41 _c 460 5 391 -13 300 -13 _c 265 -13 228 -9 189 -2 _c 150 5 110 16 69 32 _c 69 134 _l 109 111 148 94 186 83 _c 224 71 262 66 300 66 _c 356 66 399 77 430 99 _c 460 121 476 152 476 194 _c 476 230 465 258 443 278 _c 421 298 385 313 335 323 _c 275 335 _l 201 349 148 372 115 404 _c 82 435 66 478 66 534 _c 66 598 88 649 134 686 _c 179 723 242 742 322 742 _c }_e{356 742 390 739 426 733 _c 461 727 497 717 535 705 _c _cl}_e}_d /T{611 0 -2 0 614 729 _sc -2 729 _m 614 729 _l 614 646 _l 355 646 _l 355 0 _l 256 0 _l 256 646 _l -2 646 _l -2 729 _l _cl}_d /U{732 0 87 -13 645 729 _sc 87 729 _m 186 729 _l 186 286 _l 186 208 200 151 228 117 _c 256 83 302 66 366 66 _c 429 66 475 83 503 117 _c 531 151 546 208 546 286 _c 546 729 _l 645 729 _l 645 274 _l 645 178 621 107 574 59 _c 527 11 458 -13 366 -13 _c 274 -13 204 11 157 59 _c 110 107 87 178 87 274 _c 87 729 _l _cl}_d /a{{613 0 60 -13 522 560 _sc 343 275 _m 270 275 220 266 192 250 _c 164 233 150 205 150 165 _c 150 133 160 107 181 89 _c 202 70 231 61 267 61 _c 317 61 357 78 387 114 _c 417 149 432 196 432 255 _c 432 275 _l 343 275 _l 522 312 _m 522 0 _l 432 0 _l 432 83 _l 411 49 385 25 355 10 _c 325 -5 287 -13 243 -13 _c 187 -13 142 2 109 33 _c 76 64 60 106 60 159 _c 60 220 80 266 122 298 _c 163 329 224 345 306 345 _c 432 345 _l 432 354 _l 432 395 418 427 391 450 _c 364 472 326 484 277 484 _c 245 484 215 480 185 472 _c 155 464 127 453 100 439 _c 100 522 _l }_e{132 534 164 544 195 550 _c 226 556 256 560 286 560 _c 365 560 424 539 463 498 _c 502 457 522 395 522 312 _c _cl}_e}_d /b{{635 0 91 -13 580 760 _sc 487 273 _m 487 339 473 390 446 428 _c 418 466 381 485 334 485 _c 286 485 249 466 222 428 _c 194 390 181 339 181 273 _c 181 207 194 155 222 117 _c 249 79 286 61 334 61 _c 381 61 418 79 446 117 _c 473 155 487 207 487 273 _c 181 464 _m 199 496 223 520 252 536 _c 281 552 316 560 356 560 _c 422 560 476 533 518 481 _c 559 428 580 359 580 273 _c 580 187 559 117 518 65 _c 476 13 422 -13 356 -13 _c 316 -13 281 -5 252 10 _c 223 25 199 49 181 82 _c 181 0 _l 91 0 _l 91 760 _l 181 760 _l 181 464 _l _cl}_e}_d /c{{550 0 55 -13 488 560 _sc 488 526 _m 488 442 _l 462 456 437 466 411 473 _c 385 480 360 484 334 484 _c 276 484 230 465 198 428 _c 166 391 150 339 150 273 _c 150 206 166 154 198 117 _c 230 80 276 62 334 62 _c 360 62 385 65 411 72 _c 437 79 462 90 488 104 _c 488 21 _l 462 9 436 0 410 -5 _c 383 -10 354 -13 324 -13 _c 242 -13 176 12 128 64 _c 79 115 55 185 55 273 _c 55 362 79 432 128 483 _c 177 534 244 560 330 560 _c 358 560 385 557 411 551 _c 437 545 463 537 488 526 _c _cl}_e}_d /d{{635 0 55 -13 544 760 _sc 454 464 _m 454 760 _l 544 760 _l 544 0 _l 454 0 _l 454 82 _l 435 49 411 25 382 10 _c 353 -5 319 -13 279 -13 _c 213 -13 159 13 117 65 _c 75 117 55 187 55 273 _c 55 359 75 428 117 481 _c 159 533 213 560 279 560 _c 319 560 353 552 382 536 _c 411 520 435 496 454 464 _c 148 273 _m 148 207 161 155 188 117 _c 215 79 253 61 301 61 _c 348 61 385 79 413 117 _c 440 155 454 207 454 273 _c 454 339 440 390 413 428 _c 385 466 348 485 301 485 _c 253 485 215 466 188 428 _c 161 390 148 339 148 273 _c _cl}_e}_d /e{{615 0 55 -13 562 560 _sc 562 296 _m 562 252 _l 149 252 _l 153 190 171 142 205 110 _c 238 78 284 62 344 62 _c 378 62 412 66 444 74 _c 476 82 509 95 541 113 _c 541 28 _l 509 14 476 3 442 -3 _c 408 -9 373 -13 339 -13 _c 251 -13 182 12 131 62 _c 80 112 55 181 55 268 _c 55 357 79 428 127 481 _c 175 533 241 560 323 560 _c 397 560 455 536 498 489 _c 540 441 562 377 562 296 _c 472 322 _m 471 371 457 410 431 440 _c 404 469 368 484 324 484 _c 274 484 234 469 204 441 _c 174 413 156 373 152 322 _c 472 322 _l _cl}_e}_d /f{352 0 23 0 371 760 _sc 371 760 _m 371 685 _l 285 685 _l 253 685 230 678 218 665 _c 205 652 199 629 199 595 _c 199 547 _l 347 547 _l 347 477 _l 199 477 _l 199 0 _l 109 0 _l 109 477 _l 23 477 _l 23 547 _l 109 547 _l 109 585 _l 109 645 123 690 151 718 _c 179 746 224 760 286 760 _c 371 760 _l _cl}_d /g{{635 0 55 -207 544 560 _sc 454 280 _m 454 344 440 395 414 431 _c 387 467 349 485 301 485 _c 253 485 215 467 188 431 _c 161 395 148 344 148 280 _c 148 215 161 165 188 129 _c 215 93 253 75 301 75 _c 349 75 387 93 414 129 _c 440 165 454 215 454 280 _c 544 68 _m 544 -24 523 -93 482 -139 _c 440 -184 377 -207 292 -207 _c 260 -207 231 -204 203 -200 _c 175 -195 147 -188 121 -178 _c 121 -91 _l 147 -105 173 -115 199 -122 _c 225 -129 251 -133 278 -133 _c 336 -133 380 -117 410 -87 _c 439 -56 454 -10 454 52 _c 454 96 _l 435 64 411 40 382 24 _c 353 8 319 0 279 0 _c 211 0 157 25 116 76 _c 75 127 55 195 55 280 _c 55 364 75 432 116 483 _c 157 534 211 560 279 560 _c }_e{319 560 353 552 382 536 _c 411 520 435 496 454 464 _c 454 547 _l 544 547 _l 544 68 _l _cl}_e}_d /h{634 0 91 0 549 760 _sc 549 330 _m 549 0 _l 459 0 _l 459 327 _l 459 379 448 417 428 443 _c 408 469 378 482 338 482 _c 289 482 251 466 223 435 _c 195 404 181 362 181 309 _c 181 0 _l 91 0 _l 91 760 _l 181 760 _l 181 462 _l 202 494 227 519 257 535 _c 286 551 320 560 358 560 _c 420 560 468 540 500 501 _c 532 462 549 405 549 330 _c _cl}_d /i{278 0 94 0 184 760 _sc 94 547 _m 184 547 _l 184 0 _l 94 0 _l 94 547 _l 94 760 _m 184 760 _l 184 646 _l 94 646 _l 94 760 _l _cl}_d /k{579 0 91 0 576 760 _sc 91 760 _m 181 760 _l 181 311 _l 449 547 _l 564 547 _l 274 291 _l 576 0 _l 459 0 _l 181 267 _l 181 0 _l 91 0 _l 91 760 _l _cl}_d /l{278 0 94 0 184 760 _sc 94 760 _m 184 760 _l 184 0 _l 94 0 _l 94 760 _l _cl}_d /m{{974 0 91 0 889 560 _sc 520 442 _m 542 482 569 511 600 531 _c 631 550 668 560 711 560 _c 767 560 811 540 842 500 _c 873 460 889 403 889 330 _c 889 0 _l 799 0 _l 799 327 _l 799 379 789 418 771 444 _c 752 469 724 482 686 482 _c 639 482 602 466 575 435 _c 548 404 535 362 535 309 _c 535 0 _l 445 0 _l 445 327 _l 445 379 435 418 417 444 _c 398 469 369 482 331 482 _c 285 482 248 466 221 435 _c 194 404 181 362 181 309 _c 181 0 _l 91 0 _l 91 547 _l 181 547 _l 181 462 _l 201 495 226 520 255 536 _c 283 552 317 560 357 560 _c 397 560 430 550 458 530 _c 486 510 506 480 520 442 _c }_e{_cl}_e}_d /n{634 0 91 0 549 560 _sc 549 330 _m 549 0 _l 459 0 _l 459 327 _l 459 379 448 417 428 443 _c 408 469 378 482 338 482 _c 289 482 251 466 223 435 _c 195 404 181 362 181 309 _c 181 0 _l 91 0 _l 91 547 _l 181 547 _l 181 462 _l 202 494 227 519 257 535 _c 286 551 320 560 358 560 _c 420 560 468 540 500 501 _c 532 462 549 405 549 330 _c _cl}_d /o{612 0 55 -13 557 560 _sc 306 484 _m 258 484 220 465 192 427 _c 164 389 150 338 150 273 _c 150 207 163 156 191 118 _c 219 80 257 62 306 62 _c 354 62 392 80 420 118 _c 448 156 462 207 462 273 _c 462 337 448 389 420 427 _c 392 465 354 484 306 484 _c 306 560 _m 384 560 445 534 490 484 _c 534 433 557 363 557 273 _c 557 183 534 113 490 63 _c 445 12 384 -13 306 -13 _c 227 -13 165 12 121 63 _c 77 113 55 183 55 273 _c 55 363 77 433 121 484 _c 165 534 227 560 306 560 _c _cl}_d /p{{635 0 91 -207 580 560 _sc 181 82 _m 181 -207 _l 91 -207 _l 91 547 _l 181 547 _l 181 464 _l 199 496 223 520 252 536 _c 281 552 316 560 356 560 _c 422 560 476 533 518 481 _c 559 428 580 359 580 273 _c 580 187 559 117 518 65 _c 476 13 422 -13 356 -13 _c 316 -13 281 -5 252 10 _c 223 25 199 49 181 82 _c 487 273 _m 487 339 473 390 446 428 _c 418 466 381 485 334 485 _c 286 485 249 466 222 428 _c 194 390 181 339 181 273 _c 181 207 194 155 222 117 _c 249 79 286 61 334 61 _c 381 61 418 79 446 117 _c 473 155 487 207 487 273 _c _cl}_e}_d /r{411 0 91 0 411 560 _sc 411 463 _m 401 469 390 473 378 476 _c 366 478 353 480 339 480 _c 288 480 249 463 222 430 _c 194 397 181 350 181 288 _c 181 0 _l 91 0 _l 91 547 _l 181 547 _l 181 462 _l 199 495 224 520 254 536 _c 284 552 321 560 365 560 _c 371 560 378 559 386 559 _c 393 558 401 557 411 555 _c 411 463 _l _cl}_d /s{{521 0 54 -13 472 560 _sc 443 531 _m 443 446 _l 417 458 391 468 364 475 _c 336 481 308 485 279 485 _c 234 485 200 478 178 464 _c 156 450 145 430 145 403 _c 145 382 153 366 169 354 _c 185 342 217 330 265 320 _c 296 313 _l 360 299 405 279 432 255 _c 458 230 472 195 472 151 _c 472 100 452 60 412 31 _c 372 1 316 -13 246 -13 _c 216 -13 186 -10 154 -5 _c 122 0 89 8 54 20 _c 54 113 _l 87 95 120 82 152 74 _c 184 65 216 61 248 61 _c 290 61 323 68 346 82 _c 368 96 380 117 380 144 _c 380 168 371 187 355 200 _c 339 213 303 226 247 238 _c 216 245 _l 160 257 119 275 95 299 _c 70 323 58 356 58 399 _c 58 450 76 490 112 518 _c 148 546 200 560 268 560 _c }_e{301 560 332 557 362 552 _c 391 547 418 540 443 531 _c _cl}_e}_d /t{392 0 27 0 368 702 _sc 183 702 _m 183 547 _l 368 547 _l 368 477 _l 183 477 _l 183 180 _l 183 135 189 106 201 94 _c 213 81 238 75 276 75 _c 368 75 _l 368 0 _l 276 0 _l 206 0 158 13 132 39 _c 106 65 93 112 93 180 _c 93 477 _l 27 477 _l 27 547 _l 93 547 _l 93 702 _l 183 702 _l _cl}_d /u{634 0 85 -13 543 547 _sc 85 216 _m 85 547 _l 175 547 _l 175 219 _l 175 167 185 129 205 103 _c 225 77 255 64 296 64 _c 344 64 383 79 411 110 _c 439 141 453 183 453 237 _c 453 547 _l 543 547 _l 543 0 _l 453 0 _l 453 84 _l 431 50 405 26 377 10 _c 348 -5 315 -13 277 -13 _c 214 -13 166 6 134 45 _c 101 83 85 140 85 216 _c _cl}_d /v{592 0 30 0 562 547 _sc 30 547 _m 125 547 _l 296 88 _l 467 547 _l 562 547 _l 357 0 _l 235 0 _l 30 547 _l _cl}_d /w{818 0 42 0 776 547 _sc 42 547 _m 132 547 _l 244 120 _l 356 547 _l 462 547 _l 574 120 _l 686 547 _l 776 547 _l 633 0 _l 527 0 _l 409 448 _l 291 0 _l 185 0 _l 42 547 _l _cl}_d /y{592 0 30 -207 562 547 _sc 322 -50 _m 296 -114 271 -157 247 -177 _c 223 -197 191 -207 151 -207 _c 79 -207 _l 79 -132 _l 132 -132 _l 156 -132 175 -126 189 -114 _c 203 -102 218 -75 235 -31 _c 251 9 _l 30 547 _l 125 547 _l 296 119 _l 467 547 _l 562 547 _l 322 -50 _l _cl}_d /z{525 0 43 0 482 547 _sc 55 547 _m 482 547 _l 482 465 _l 144 72 _l 482 72 _l 482 0 _l 43 0 _l 43 82 _l 381 475 _l 55 475 _l 55 547 _l _cl}_d end readonly def /BuildGlyph {exch begin CharStrings exch 2 copy known not{pop /.notdef}if true 3 1 roll get exec end}_d /BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec }_d FontName currentdict end definefont pop %% Font Page 00 /BitstreamVeraSans-Roman-ENC-00 [ /.notdef/E/m/a/c/s/p/e/h/d/hyphen/k/K/T/S/O/r/u/U/A/P/I/B/l/b/i/y/t/o/n/C /slash/plus/z/f/g/w/v/comma/M/D/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef] def /BitstreamVeraSans-Roman-Uni-00 BitstreamVeraSans-Roman-ENC-00 /BitstreamVeraSans-Roman MFEmb %%BeginFont: BitstreamVeraSans-Roman %!PS-AdobeFont-1.0 Composite Font %%FontName: BitstreamVeraSans-Roman-Uni %%Creator: Composite font created by Qt 25 dict begin /FontName /BitstreamVeraSans-Roman-Uni def /PaintType 0 def /FontMatrix[1 0 0 1 0 0]def /FontType 0 def /FMapType 2 def /Encoding [ 0]def /FDepVector [ /BitstreamVeraSans-Roman-Uni-00 findfont ]def FontName currentdict end definefont pop %%EndFont %%EndFont /F1 21.3333/BitstreamVeraSans-Bold-Uni DF /F2 16/BitstreamVeraSans-Roman-Uni DF /F3 14.6667/BitstreamVeraSans-Bold-Uni DF /F4 16/BitstreamVeraSans-Oblique-Uni DF /F5 13.3333/BitstreamVeraSans-Roman-Uni DF /F6 10.6667/BitstreamVeraSans-Roman-Uni DF /F7 16/BitstreamVeraSans-Bold-Uni DF %%EndSetup %%Page: 1 1 %%BeginPageSetup QI %%EndPageSetup [1 0 0 1 474 172]ST 1 3 B 0 1 PE WB W BC 0 0 281 373 R CLSTART 474 172 281 373 ACR CLEND B P1 F1 F 46 Y<0001000200030003000400050002>[21 0 14 0 13 0 13 0 14 0 15 0 0 0]104 21 XYT <000600070003000800040009000A000B0002000C>[17 0 7 0 13 0 15 0 14 0 10 0 12 0 15 0 14 0 0 0]127 132 XYT [1 0 0 1 106 170]ST CLO [1 0 0 1 106 170]ST 1 3 B 0 1 PE WB 0 0 283 57 R CLO [1 0 0 1 106 170]ST CLSTART 106 170 283 57 ACR CLEND B P1 WB F2 F 24 Y<00010002000300040005>[10 0 15 0 9 0 9 0 0 0]52 11 XYT 44 Y<0005000600070007000400080009000A0005000600070003000B>[9 0 10 0 9 0 9 0 9 0 10 0 10 0 6 0 9 0 10 0 9 0 9 0 0 0]118 21 XYT [1 0 0 1 106 320]ST CLO [1 0 0 1 106 320]ST 1 3 B 0 1 PE WB 0 0 283 57 R CLO [1 0 0 1 106 320]ST CLSTART 106 320 283 57 ACR CLEND B P1 WB F2 F 34 Y<000C000D000D000E>[10 0 9 0 9 0 0 0]38 11 XYT [1 0 0 1 106 246]ST CLO [1 0 0 1 106 246]ST 1 3 B 0 1 PE WB 0 0 283 57 R CLO [1 0 0 1 106 246]ST CLSTART 106 246 283 57 ACR CLEND B P1 WB F2 F <000F001000040003>[13 0 7 0 9 0 0 0]38 11 XYT [1 0 0 1 106 397]ST CLO [1 0 0 1 106 397]ST 1 3 B 0 1 PE WB 0 0 283 57 R CLO [1 0 0 1 106 397]ST CLSTART 106 397 283 57 ACR CLEND B P1 WB F2 F 24 Y<000E000600070003000B00110006>[10 0 10 0 9 0 9 0 9 0 10 0 0 0]67 11 XYT 44 Y<000E000600070007000400080009000A00120006>[10 0 10 0 9 0 9 0 9 0 10 0 10 0 6 0 12 0 0 0]95 21 XYT [1 0 0 1 0 0]ST CLO 3 5 B 0 1 PE NB NP 344 473 MT 344 535 LT QS [1 0 0 1 863 170]ST 1 3 B 0 1 PE WB 0 0 164 169 R CLO [1 0 0 1 863 170]ST CLSTART 863 170 164 169 ACR CLEND B P1 WB F3 F 14 Y<000D000D000E>[10 0 10 0 0 0]31 13 XYT <000F00100011>[11 0 11 0 0 0]28 49 XYT <0010000C00120013000700140002000C>[11 0 7 0 10 0 9 0 4 0 10 0 10 0 0 0]68 82 XYT [1 0 0 1 863 376]ST CLO [1 0 0 1 863 376]ST 1 3 B 0 1 PE WB 0 0 164 169 R CLO [1 0 0 1 863 376]ST CLSTART 863 376 164 169 ACR CLEND B P1 WB F3 F <0015000C0016000900090017>[11 0 7 0 4 0 7 0 7 0 0 0]46 59 XYT [1 0 0 1 0 0]ST CLO 1 1 B 0 1 PE NB NP 863 254 MT 754 254 LT QS 1 B BR /WFi true d NP 863 254 MT 850 261 LT 850 247 LT 863 254 LT CP BF QS /WFi false d /WFi true d NP 754 254 MT 768 247 LT 768 261 LT 754 254 LT CP BF QS /WFi false d NB NP 863 460 MT 754 460 LT QS 1 B BR /WFi true d NP 863 460 MT 850 467 LT 850 453 LT 863 460 LT CP BF QS /WFi false d /WFi true d NP 754 460 MT 768 453 LT 768 467 LT 754 460 LT CP BF QS /WFi false d [1 0 0 1 747 232]ST CLO [1 0 0 1 747 232]ST CLSTART 747 232 134 28 ACR CLEND B P1 1 B BR F2 F 19 Y<000D000D000E>[9 0 9 0 0 0]28 37 XYT <001300140015>[11 0 10 0 0 0]26 70 XYT [1 0 0 1 747 430]ST CLO [1 0 0 1 747 430]ST CLSTART 747 430 134 28 ACR CLEND B P1 1 B BR F2 F <001600100017001300140015>[11 0 7 0 3 0 11 0 10 0 0 0]47 43 XYT [1 0 0 1 749 254]ST CLO [1 0 0 1 749 254]ST CLSTART 749 254 134 28 ACR CLEND B P1 1 B BR F2 F <000500060007000700040008>[9 0 10 0 9 0 9 0 9 0 0 0]56 39 XYT [1 0 0 1 778 464]ST CLO [1 0 0 1 778 464]ST CLSTART 778 464 65 21 ACR CLEND B P1 1 B BR F2 F 16 Y<0018001000030019001700170007>[10 0 7 0 9 0 3 0 3 0 3 0 0 0]44 10 XYT [1 0 0 1 263 182]ST CLO [1 0 0 1 263 182]ST 1 1 B 0 1 PE WB 0 0 126 37 R CLO [1 0 0 1 263 182]ST CLSTART 263 182 126 37 ACR CLEND B P1 WB F2 F 24 Y<0005000600070007000400080009000A00070017>[9 0 10 0 9 0 9 0 9 0 10 0 10 0 6 0 9 0 0 0]84 21 XYT [1 0 0 1 263 254]ST CLO [1 0 0 1 263 254]ST 1 1 B 0 1 PE WB 0 0 126 42 R CLO [1 0 0 1 263 254]ST CLSTART 263 254 126 42 ACR CLEND B P1 WB F2 F 16 Y<0014001A001B0008001C001D>[10 0 9 0 6 0 10 0 10 0 0 0]55 15 XYT <000E000E00150014>[10 0 10 0 5 0 0 0]35 75 XYT 36 Y<001700190018001000030010001A>[3 0 3 0 10 0 7 0 9 0 7 0 0 0]48 39 XYT [1 0 0 1 263 325]ST CLO [1 0 0 1 263 325]ST 1 1 B 0 1 PE WB 0 0 126 43 R CLO [1 0 0 1 263 325]ST CLSTART 263 325 126 43 ACR CLEND B P1 WB F2 F 17 Y<001E001F001E00200020>[11 0 5 0 11 0 13 0 0 0]53 16 XYT <000E000E00150014>[10 0 10 0 5 0 0 0]35 74 XYT 37 Y<001700190018001000030010001A>[3 0 3 0 10 0 7 0 9 0 7 0 0 0]48 39 XYT [1 0 0 1 263 402]ST CLO [1 0 0 1 263 402]ST 1 1 B 0 1 PE WB 0 0 126 43 R CLO [1 0 0 1 263 402]ST CLSTART 263 402 126 43 ACR CLEND B P1 WB F2 F 17 Y<001E001F001E00200020>[11 0 5 0 11 0 13 0 0 0]53 16 XYT <000E000E00150014>[10 0 10 0 5 0 0 0]35 74 XYT 37 Y<001700190018001000030010001A>[3 0 3 0 10 0 7 0 9 0 7 0 0 0]48 39 XYT [1 0 0 1 0 0]ST CLO 1 1 B 0 1 PE NB NP 388 200 MT 474 200 LT QS 1 B BR /WFi true d NP 388 200 MT 402 193 LT 402 207 LT 388 200 LT CP BF QS /WFi false d /WFi true d NP 474 200 MT 461 207 LT 461 193 LT 474 200 LT CP BF QS /WFi false d [1 0 0 1 413 182]ST CLO [1 0 0 1 413 182]ST CLSTART 413 182 41 25 ACR CLEND B P1 1 B BR F2 F 18 Y<000E000E00150014>[10 0 10 0 5 0 0 0]35 3 XYT [1 0 0 1 0 0]ST CLO 1 1 B 0 1 PE NB NP 388 275 MT 474 275 LT QS 1 B BR /WFi true d NP 388 275 MT 402 268 LT 402 281 LT 388 275 LT CP BF QS /WFi false d /WFi true d NP 474 275 MT 461 281 LT 461 268 LT 474 275 LT CP BF QS /WFi false d [1 0 0 1 413 260]ST CLO [1 0 0 1 413 260]ST CLSTART 413 260 41 19 ACR CLEND B P1 1 B BR F2 F 15 Y<000E000E00150014>[10 0 10 0 5 0 0 0]35 3 XYT [1 0 0 1 0 0]ST CLO 1 1 B 0 1 PE NB NP 388 346 MT 474 346 LT QS 1 B BR /WFi true d NP 388 346 MT 402 339 LT 402 353 LT 388 346 LT CP BF QS /WFi false d /WFi true d NP 474 346 MT 461 353 LT 461 339 LT 474 346 LT CP BF QS /WFi false d [1 0 0 1 413 325]ST CLO [1 0 0 1 413 325]ST CLSTART 413 325 41 25 ACR CLEND B P1 1 B BR F2 F 18 Y<000E000E00150014>[10 0 10 0 5 0 0 0]35 3 XYT [1 0 0 1 0 0]ST CLO 1 1 B 0 1 PE NB NP 385 425 MT 480 425 LT QS 1 B BR /WFi true d NP 385 425 MT 399 418 LT 399 432 LT 385 425 LT CP BF QS /WFi false d /WFi true d NP 480 425 MT 467 432 LT 467 418 LT 480 425 LT CP BF QS /WFi false d [1 0 0 1 413 406]ST CLO [1 0 0 1 413 406]ST CLSTART 413 406 41 25 ACR CLEND B P1 1 B BR F2 F <000E000E00150014>[10 0 10 0 5 0 0 0]35 3 XYT [1 0 0 1 503 281]ST CLO [1 0 0 1 503 281]ST 1 1 B 0 1 PE WB 0 0 223 221 R CLO [1 0 0 1 503 281]ST CLSTART 503 281 223 221 ACR CLEND B P1 WB F4 F 15 Y<00010002000300040005000600020007>[9 0 9 0 10 0 6 0 10 0 7 0 9 0 0 0]68 12 XYT [1 0 0 1 521 346]ST CLO [1 0 0 1 521 346]ST 1 1 B 0 1 PE WB 0 0 188 19 R CLO [1 0 0 1 521 346]ST CLSTART 521 346 188 19 ACR CLEND B P1 WB F5 F 14 Y<0005001A001D000400080010001C001D001900210003001B0019001C001D>[7 0 7 0 8 0 7 0 8 0 5 0 8 0 8 0 3 0 7 0 8 0 5 0 3 0 8 0 0 0]100 44 XYT [1 0 0 1 521 374]ST CLO [1 0 0 1 521 374]ST 1 1 B 0 1 PE WB 0 0 188 19 R CLO [1 0 0 1 521 374]ST CLSTART 521 374 188 19 ACR CLEND B P1 WB F5 F <000600100019001C00100019001B001900070005>[8 0 5 0 3 0 8 0 5 0 3 0 5 0 3 0 8 0 0 0]55 66 XYT [1 0 0 1 521 402]ST CLO [1 0 0 1 521 402]ST 1 1 B 0 1 PE WB 0 0 188 19 R CLO [1 0 0 1 521 402]ST CLSTART 521 402 188 19 ACR CLEND B P1 WB F5 F <000800190005001B001C0010001A>[8 0 3 0 7 0 5 0 8 0 5 0 0 0]43 72 XYT [1 0 0 1 521 432]ST CLO [1 0 0 1 521 432]ST 1 1 B 0 1 PE WB 0 0 188 19 R CLO [1 0 0 1 521 432]ST CLSTART 521 432 188 19 ACR CLEND B P1 WB F5 F <0004001C001D002200190023001100100003001B0019001C001D>[7 0 8 0 8 0 4 0 3 0 8 0 8 0 5 0 8 0 5 0 3 0 8 0 0 0]83 52 XYT [1 0 0 1 521 464]ST CLO [1 0 0 1 521 464]ST 1 1 B 0 1 PE WB 0 0 188 19 R CLO [1 0 0 1 521 464]ST CLSTART 521 464 188 19 ACR CLEND B P1 WB F5 F <001D0007001B0024001C0010000B>[8 0 8 0 5 0 9 0 8 0 5 0 0 0]50 25 XYT <001B00100003001D00050006000300100007001D0004001A>[5 0 5 0 8 0 8 0 7 0 8 0 8 0 5 0 8 0 8 0 7 0 0 0]84 79 XYT [1 0 0 1 521 316]ST CLO [1 0 0 1 521 316]ST 1 1 B 0 1 PE WB 0 0 188 19 R CLO [1 0 0 1 521 316]ST CLSTART 521 316 188 19 ACR CLEND B P1 WB F5 F <0008001900230008000A00170007002500070017>[8 0 3 0 8 0 8 0 5 0 3 0 8 0 7 0 8 0 0 0]61 51 XYT <001300140015>[9 0 8 0 0 0]20 116 XYT [1 0 0 1 872 226]ST CLO [1 0 0 1 872 226]ST 1 1 B 0 1 PE WB 0 0 146 82 R CLO [1 0 0 1 872 226]ST CLSTART 872 226 146 82 ACR CLEND B P1 WB F6 F 22 Y<00060010001C00250019000900070005>[7 0 5 0 7 0 6 0 3 0 7 0 7 0 0 0]49 18 XYT <000300040004000700050005>[7 0 6 0 6 0 7 0 7 0 0 0]40 70 XYT <001B001C>[4 0 0 0]11 113 XYT 37 Y<0025000300100019001C00110005>[6 0 7 0 5 0 3 0 7 0 7 0 0 0]42 28 XYT <000500060007000700040008>[7 0 7 0 7 0 7 0 6 0 0 0]41 73 XYT 52 Y<0005001A001D001B000800070005001900210007001000050026>[7 0 6 0 7 0 4 0 7 0 7 0 7 0 3 0 5 0 7 0 5 0 7 0 0 0]76 5 XYT <00070002001100170003001B00070005>[7 0 11 0 7 0 3 0 7 0 4 0 7 0 0 0]53 84 XYT 67 Y<001D0007000400070005000500030010001A>[7 0 7 0 6 0 7 0 7 0 7 0 7 0 5 0 0 0]59 10 XYT <00040003000600030018001900170019001B001900070005>[6 0 7 0 7 0 7 0 7 0 3 0 3 0 3 0 4 0 3 0 7 0 0 0]64 72 XYT [1 0 0 1 872 420]ST CLO [1 0 0 1 872 420]ST 1 1 B 0 1 PE WB 0 0 146 82 R CLO [1 0 0 1 872 420]ST CLSTART 872 420 146 82 ACR CLEND B P1 WB F6 F 37 Y<00020003001D0003002300070005>[11 0 7 0 7 0 7 0 7 0 7 0 0 0]53 12 XYT <001B00080007>[4 0 7 0 0 0]18 68 XYT <0025000300100019001C00110005>[6 0 7 0 5 0 3 0 7 0 7 0 0 0]42 89 XYT 52 Y<0018001000030019001700170007>[7 0 5 0 7 0 3 0 3 0 3 0 0 0]35 32 XYT <0009000700250019000400070005>[7 0 7 0 6 0 3 0 6 0 7 0 0 0]43 70 XYT [1 0 0 1 0 0]ST CLO 1 1 B 0 1 PE NB NP 97 547 MT 154 547 LT QS 1 B BR /WFi true d NP 97 547 MT 110 540 LT 110 554 LT 97 547 LT CP BF QS /WFi false d /WFi true d NP 154 547 MT 141 554 LT 141 540 LT 154 547 LT CP BF QS /WFi false d [1 0 0 1 97 508]ST 1 3 B 0 1 PE WB 0 0 59 18 R [1 0 0 1 164 501]ST CLO [1 0 0 1 164 501]ST CLSTART 164 501 72 28 ACR CLEND B P1 1 B BR F5 F 18 Y<00060010001C0004000700050005>[8 0 5 0 8 0 7 0 8 0 7 0 0 0]50 11 XYT [1 0 0 1 161 533]ST CLO [1 0 0 1 161 533]ST CLSTART 161 533 103 28 ACR CLEND B P1 1 B BR F5 F 10 Y<0019001D001B00070010000A00060010001C0004000700050005>[3 0 8 0 5 0 8 0 5 0 5 0 8 0 5 0 8 0 7 0 8 0 7 0 0 0]84 9 XYT 28 Y<0004001C000200020011001D001900040003001B0019001C001D>[7 0 8 0 13 0 13 0 8 0 8 0 3 0 7 0 8 0 5 0 3 0 8 0 0 0]99 2 XYT [1 0 0 1 97 471]ST CLO [1 0 0 1 97 471]ST CLSTART 97 471 90 28 ACR CLEND B P1 1 B BR F7 F 19 Y<000E001700180019001200160003>[11 0 10 0 16 0 11 0 11 0 4 0 0 0]73 2 XYT <001A>[0 0]6 81 XYT [1 0 0 1 161 106]ST CLO [1 0 0 1 161 106]ST CLSTART 161 106 189 43 ACR CLEND B P1 1 B BR F2 F 17 Y<0013000600060017001900040003001B0019001C001D0005>[11 0 10 0 10 0 3 0 3 0 9 0 9 0 6 0 3 0 10 0 10 0 0 0]93 28 XYT <0003001D0009>[9 0 10 0 0 0]29 126 XYT 37 Y<00030004000400070005000500190018001900170019001B001A>[9 0 9 0 9 0 9 0 9 0 9 0 3 0 10 0 3 0 3 0 3 0 6 0 0 0]91 27 XYT <001B001C001C00170005>[6 0 10 0 10 0 3 0 0 0]38 123 XYT [1 0 0 1 548 106]ST CLO [1 0 0 1 548 106]ST CLSTART 548 106 134 38 ACR CLEND B P1 1 B BR F2 F 15 Y<0027000700050005000300230007>[13 0 9 0 9 0 9 0 9 0 10 0 0 0]68 30 XYT 35 Y<00280019000500060003001B0004000800070010>[12 0 3 0 9 0 10 0 9 0 6 0 9 0 10 0 9 0 0 0]84 25 XYT [1 0 0 1 880 106]ST CLO [1 0 0 1 880 106]ST CLSTART 880 106 134 28 ACR CLEND B P1 1 B BR F2 F 19 Y<000F0011001B00060011001B>[13 0 10 0 6 0 10 0 10 0 0 0]55 39 XYT QP %%Trailer %%Pages: 1 %%DocumentFonts: BitstreamVeraSans-Bold BitstreamVeraSans-Roman BitstreamVeraSans-Oblique %%EOF speech-dispatcher-0.9.1/doc/figures/architecture-future.png0000644000175000017500000012110611447133617020756 00000000000000‰PNG  IHDRc­EÔ IDATxœěÝL÷ř˙÷|„Oł–sšľČiÖrŞ%rN†Oň‘wĺT^➠qN)ɝœőǕ˛Ä‘ź89œTîÚ9ĽŘ•Rěžr˜VIĄ•Sp•\ÉzrîÔ~!šŠrޜŸŇj‰œjąÜh°H5Xř¤ůţ1dĎîĂîňűůř-óžyĎűýޝŮ}Íű=ď‘ Ă›˙ľŇ€U‡H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”Ŕ‰H œˆ”k›$Ižy kҁo$i™ËXˆ”kŢčŒNLL8NLLL~6š"ĺŹDJ(ÔĚ3ĺâ^1ó´ŽýbđšžşźŚ ,І٠ç~xÎąđÜĎ5mX‘ňÖ"%Şí§mœčşÜľŇɂĐŘ ę^Şťř‹‹SSSÖ’ŠŠŠţ÷űkŸŻľŻ6ü›áđăai“x(ĐqĄĂžrC}Cࡀ´Iň=ŕŤ~Şşďýž“„“““ ő >ŸĎ˙ żĄžaffĆJ˙xźúŠjŸĎç{ŔWŻ›ůbĆ~FĘUŔęA¤„Bľý¨­ŻˇŻĺ‡-K‘šaŤäčřiGíóľbÓü:Ł×FŸ‰>ÓřFC7úÎüәž‹y|ó€o‹oôŁQ㞑ž™NźšhyťeÁ$!D8ŽÜSŠiÚřőń;žsâO˜Ë'~?ńDőľĎ×jˇ5-­Uî­|Ąî/%‡ŃkŁľąÚ@ m’Ŕo˝6şŇ…Âş`čîíŽyśĆ0Œš§k†Žٓ„ú´?—ˇČ˛,W퍝>ć=ŐńÂ0ŒôÍtěPLUUQ"BťBݗşç“ŇéúŁő˛,+ĽJýŃz]׍Œˆ(3Ăä•dhwH–eY–CťCÉţä}˜5O7šť îśžŐjĽjšV´^ÝŽŠ!o‘ŤöU%ŻĚo됾l îÂ0ŒąëcUűŞdY–ˇČńĂq}Z瀲2ąń1uťj̆ał†ş]MßLśŁ>z0j?ʒýÉŞ}Us9”ëŘtfž;ÉAŸÖUU5_Ǟ9Žčć–f/%°X]JŠŇÜҜž™6fôÍtë[­JŠŇŮŐé1‡â~˝ňe˝žđ^˘ U_Ż0 #y%Ýľ' !˘ŁíçŰői]ŸÖŰϡ+ĽJꓔÇTNjôÍ´ŞŞÍ-ÍÚm͘5†Ž™šIUŐÎw;u]O§ÓąCąúWę›ŰKežPJ•䕤ŽëşŽw÷v+ĽŠě !â‡ăMg›Ňé´1kŒ|4Ül?ß>Wë}U‰“‰t:m†ŚiÉ+nżr\Ę沋Ô')ĽTąˇOô`”“/•uhÔ<]Óůn§aďvFFŠJŠbĆN&]×E1_‡v…ÇÚm-3s—$]×'Á`P”8/Ę(ĽŠyа¤Ói/%°(ć׼ýbŤil|ĚţťÂ‘rá˝DţĆŽ…v…ŹƒÁ`*5JB4ˇ4Ű×o~ł9v(ć1Őń *ź”Ę~Y×%RŞyşŚ˝ŁÝžÔ~ž˝ćék5ÇîŹĘzżĆě^6—]Џeś'_ +ëĐHö'Ë-7 ŁüŃrű…šśxĆؤRКgkD‰(ßY;ëîď˛vIŠżŻyśfdtdî„0›˝?|ÎŹ§’X”úŁőMod˙yĐôFSýќWN­…šF xůâ17Ź]ź…Č_üpÜl4m˛:L ĂBd^RľÇ ŞŞÚ/ÁÚš\Öu‰”Eq\$ÖnkÖeÝĚâéş.˲ůÚĺó˘Ę㞠÷ Ňěě‡FůÎňÄɄ/9R•REÓ\ŰYcěúXűůöĐîuáĆ%ÉqIĽRŢű”( o‚;‚căÎ%ÓŘřXpGĐ|íŰdMŢFžxĚ kď%ň¤ÝÖćo řr‰RŞčÓśűpf QâzÁ5#Ő~ Öž/ťE]ÖőzĹ×ő$črš˛y/;űĄŃÚÖ*„°˛ÚSŁŁćŘźéÓó—-\’dYśÎx†a4žn´ö•yŸRë[­y”€;Y–sň°_Ě#Rň2ňĹcnXťx/‘§ŚłMY†ŘÎ,ĹďSJgďSršŹ[HŸR掜 ].?çUśűŠGŸŕ™űĄaĽšS>t_ę6ďN°ÜFöF:ť:çn>ź­5žnô’ݍŽkšŚOë­oľF÷ĎßL˜ú$5w˘yAşăž[ ]J`Q–.Rňň+ĹcnXť˜%yš'Ú~Ňfż+ɔJĽÚ~Ôf­Őő‹ű˛ÔőóŽę§Ş=Ś:Ô|ŁŚëçŮŮt÷î]Y–­;~ćéÉ$•{*ű˙ľßž¤÷ýŢĘ=•^śłITBťCżȚ4đŤČžˆa›7FQ—ç)ĺJuź0 #•Jޏ)ĽŠăyJÚm-ş?*˲˘(Žçu÷v[ד23t>OéĘýĎSĘ`˛˘űي˘ˆ Çö{ě\Ęćž Ă0FFGĚç)en `őŤyśfhxȘ5ôi}ŕWÁ`{“€˘ó8KxhWČ|¨‰Ĺź‰Ŕ|5RršOiąšaíâ˝ÄRq?Sp°žu÷v‡v‡D‰0ŻĹ&KÄ|ňlë[­sOžM§[ŰZUUľ?yśý|{ůÎň‘FĚšÎ6ĹÇÝG ¸Œ|YlnXť$#cęw ($ÉíÓĺž ŕŃčľŃł˙tvř7á>żĽ(JuUuăëáPŘžNŰŰmç~tîÓO?UUľîpݙÓg¤ż˜ű)Ňó˞cŻťőÇ[âËg"I’¤OëÇžuŹ÷—˝wďލ썴ţ ľâąŠürĂÚĹŻU,"%°ń+&ćžĂRq?ĹpŔjF¤Nô-€}J€5F˛l’üú+żVyć{g&?›tŹłRĹsX=%, ‘`홛Ŕőž‘ú$uîŸĎÝšs§"\ŃsšgyöNđŁď°>YłÖxœ‚Ďăú+b XYYŠŃkŁOţí“CW‡*Ę+˛nľÔ(ĘʀՃ>% ťBŽs˝X~áP8q<ŃŇÜbţk†SSS ő ‡Ň&É÷€ŻúŠęž÷űŹufž˜Š‹×ůđů|žę§ŞÇ?ˇç999ŮPßŕóůüúęfffʜ­€ó+6Yűbm 6IáPřžŽ{âÔwO™Ie”ľ˝ÝfßËđo†Ă‡ĽMRŕĄ@Džků\ń^ŽóűýœU`ů)a}ňx7s5.ýkWôščŕƒŽ…žyŔˇĹ7úѨqĎHßL'^M´źÝbĽžP÷BĺžJ-­iˇľÚƒľOT?1ńű +5WîŠÔ4müúř?ß9ń'ėg ë î暓ŸM†żí _7tŁőíÖ ď]°ňŠű‡:Y–GGG ÝčšŘsîGç:ޙ‹ˆFŻ>}Śń;†n ôœů§3}˙Úgmx¤áHôď˘Sˇ§85Ŕ 0€ź¤ÓéúŁő˛,+ĽJýŃz]×ç“nŚc‡bŞŞŠÚęžÔí%ičęPhwH”uťÚŢŃn-×4­ţh˝ş]%BŢ"WíŤJ^I.˜d}ś…ú´?—ˇČ˛,W퍝>fen_Íţ"ó0 íY™[ĆŽŠŞjĚޡ0×!–ź’ íɲ,Ërhw(Ů_n.ŠV&.ő6”\_^şŽË˛ěXG”ű ʑOsKł}Ió›ÍąCąě™O몪ć*@üpźélSŽ˝8’BťBćëčÁhë[­VR˛?YľŻĘÚ°ľ­ŐŹ"%äIUŐÎw;u]O§ÓąCąúWęÍĺé›iUU›[šľŰš1k ]ŞyśfÁ¤‘ŃĽTéîí6fąëcÁA+T¨ÚW•8™H§Ó†ahš–ź2˙3Â%ÉůDFŰϡëÓş>­ˇŸoWJ•Ô'ŠĚŐr˝0uvuV}˝ĘŃń—âModům”ů+j`p@)U’W’şŽëşŢÝŰ­”*CW‡ź¤ZššÔŘP)…v…ÇÚm-k>ćeI§ÓV8¤ëzâd" Š絏Ě¨Şšž™6˛É܋˝œJŠbßP×uEQrmXNDJ(űĽV— Ť.InWU]Žť^*ś^¸\3ö)ł†ş]ľ÷GišŚ(Jޟ_Ž%5O×Ř;Ę Ăh?ß^ót—T/—Ɓ %W¤46>ÜtŹ“JĽjž­%˘|gyěPŹťwž+;K>ł†(™[)^ólÍČčČÜq7›űü`˘D8ş—ÝKk?Žs ÷`ÜŹ,ÎÂȇ˥V— Ť.I.WU]Žť_*ś^¸\3^D¤dMg›â‡ăÖżÍo6ǞĎ>J'sŰ̘Jť­YutOőriŘPr…Mg›â/ĹłŻ3kŒ]k?ßÚ˛_+q9?8ĚT*ľ@ŸRŽţ÷HI)U4-űAM¤+‹cß:văƍžŢ}zţRŤéÖçˇj ëV.IwîÜŮö•mÖ\R›7ožs玙ÔÓŰsă÷7śnŰZQ^QűbmĎ/秓rI˛ îŰi 4pëó[‹ŞŻŠáhCď/{§ţ4eţŰö“ś†WćČG#ŃýŃĚŇfol|LÝŽv_ę6oSČy Xœ…‘Y–çz“ Ă0ŒĆӍÖ7züpźůÍćŹ[š$EF;ßíô˛k}zţNh—${ŔSœű” Ă0Ó¨Ş1kTíŤr)pćś5O×8Öoď¸ď>%—Ô\ż–\šXßćŻö•ĽT‰ě4˝Ńä¸&b8ƒŃýQEQD‰ƒ‰ă ëô%žœSQ”Ěš1ľŰZtT–eEQâ‡ăú´nĺŮÝŰ­nWSŠTěů˜RŞ8ćöt” Ăť>Vót9?gdo$sOŔŠŕ,Œ|¸\juš°ę’ärUŐĺz°űĽbë…Ë5c—)󚱩j_UăëJŠ’ëîíŹŰ ¨ŞjÍn—ź’tĚ}ç’ęĺŇ8€<Š\đ%|¸\j5r_XuOĘuUŐĺz°űĽbë…Ë5c—H)ë5cĂ0’ýI!Dăë.í“u[ç“ޏ>OéJ–ç)šÔ@ˆ”.$ƒÇ~‹rOřţҗú$x(űěÖ IâKSśç8ČajjŞí'mąçc„IŔ:@˜pA¤x%I’,ËŐűŞ;ßë\é˛`i1đœxň,8)€‘8)€‘8)€‘8)€‘8)€‘8)€‘8)€‘8)€‘8)€‘8)€‘8)€SÉJ` “$iĽ‹Ź7†aŹt`CăçÍFĂ7Ż ú”Ŕ‰>%Xy\ÄŠˆk䊂HŠ8#"N€Ő†Ÿ7ëßź^0ú‹&ŔĚĄëbWřń°Ďç“$É÷€/đP üxŘ}§SSSŇ&I’$i“455ĺRŸĎWŠěşŘ•šŽÇeÍĄˆźf‰v ˆ”`1äkĽß 'łńÝßǒŽw:^¨}!v0ŚÝ֌Yc|tüÔë§ÜéĹ_\˙#D‰˙#z/÷ş”jhxčîÝť/ÔžĐńNG~őĘ;Źg–źY>mˆŁ‰ ÇqTů5ŁšUŽM˛Ś–=Röé>ŐuÝçóyßQe¤ňĂß~ŘúVëąo‹ě‰ 8첗ńÇ˙÷˙ůßÁ`pbb"żrfć°l܋ZŹü—të}JXnˇţxKńBě…Á_:ĆŃĺ2ńű‰űaůÎň†WĘw–řŰÝ˜ŠBˆO˙řiޅtä`Žˆ›™™ixľÁ˙ ß 6=XůľJŸĎgŘüő š< K’ÔsšÇʰçr$IáPXdŒŻëşŘUVV&m’*Ę+şŢsůţÍpőSŐž|Ň&) ŰóĚU*ŽH Ë­ńőF!Dďżô>ůˇOnÝş5đP 6V;řÁ Ë&?ďBÄDžąC1!DÇĎÜĆō˙÷¸"¸=˜w!łćpá§Ž6LýiĘěüőŕ“ű¤\"§RŠôÍ´,ËOţí“f°T÷Râ… óŰ^¸`-ˇë{żď…ÚʂeZZpÔkđƒÁ'ŞŸ¸{÷nj<Ľkz(úżßüżŽhĘQ*Gă7:Ú(Ž&Z(ÇQQä׌î›äJM^IFöF?M[ŰZsĺ …étÚ0Œt:-„ƒšö22:Úrd¸¨rfć`Ž0v}ĚžUdOD1ňŃČÜV!"{#†ahš&˲(šŻĚ˛,ëÓşcwY3™OÝąďWÓ4!DpGĐĽT âxń‚ű”ňÇřN X8šh pGEąl÷)YfffŽýîÚŕƒ-Í-wîÜQˇŤ“ŸMfŽ6ü›á'ţ扚§kúţľĎ\RýTő˙ßCĂC•‘J‘1íľ,Ë取'^IÔžXť¨rşäusŸĎw÷î]cÖ›„BÜŇ_H˛,ĎĚĚ!jcľqąůÍ毝8÷ĎçNţăÉŘĄ˜ŮdĎ-k&ŽÔĚ›ŠůÝŃÄńâ‘Rţř„ĹÂŃD …ă8*Šĺ”,ć06Q"Œ{YÖŹ{šîÂO/d.ż7çŚó˛—Ëé%Rš™™Ůźył) ~0řdő“ĺ–<^Q^qăżo ]ŞüZĽX|¤¤O랲Ě~A¤´t¸O +ŻúëŐBsˆÓ=Ń{šW–e]×­‘QşŽË˛Ü{šWÜ[ć’ŢÇĄ7úťQóß˙uCÚ2˙­ŽŞîŢřŻm?nťńß7‚;‚f˜äž‰őÂdŽÍün7qa))-9÷gŽaĘő–aéŹô{XnUœůޙáß OýiJ155uŚůŒâÔÉ,OUęů—ž;wîDŸ‹Ú§÷ů|Ńç˘wîÜéIödn˛lÎ|ďŒâءMNNNýięÄk'„gž{ĆZĄîpâءŽ !^jȚIăw…'^;1ő§ŠÉÉI3“űvQ"Ž}űŘřÇă➘ül˛ë˝ŽŹŠ‹Hi9d˝ElĽ 7Eťž­ô{XVĺ;Ę/^žřĚß?łuŰVI’~řáÁ_v_ęŽ{Ů9/œâÂ{„ąçcŽĺćűärËŻúŠę_ !~řám_Ův÷î݁_ T?Um­`FJćsç^gxćďžéěęœřtbëś­•SéX­ňk•#Ă#áGĂOüÍŇf)üŐp˙żőŸűţš%Ź„ܧTÉŰřNI˘‘×޲!-ń#öV9ç.8ŽŠ‚fÜ xŁ˝ Oi…I’4óĹL]źÎď÷űđ5źÚ î s‰ďŸľÄ299ŮPßŕóůüúę̛ç’>›Ź}ą68I655ŐPßx( m’|řŞŸŞî{żo™Ť Ź-DJ+ďČ?ŠŢWN§SăŠk׎i>s¤áHőžjíśf-ąV‡Ă•{*5Mż>~çĎwNüăÜ0ÖÉĎ&Ă_ ‡v…ĆŻşŃúvŤŮO-„8đÍž-žŃF{Fúf:ńj˘ĺí–¨'°v0Ę(ŢGße]n|9~űůvkHîčŒ>ń7O´žŐj_ň‹/ŒßĎĚa拙‡˙úáÉÉI!D]źŽlGŮŠďdš RÚ$éÓşýH¸cô݊`ôůbĂśP8ŽŁ˘ 7Ţh/čSZî÷ŻGŸ‹ZŻË-ż{÷Žcɍ?Ü0_ĎĚ̜xíDYY™´I’$ió_nžu떙Ô˙Żýu‡˛ß#z4tşń´9ą °ľ˝ÝVQ^!m’ü~˙3÷ĚŕƒŢSíW:ě“őůđUF*ÍG€u‰Hiĺůô[ŻÍžç’˙™{}ě[ÇnܸŃÓŰŁOë†ałóáÖ­ĎoÔ@Öü{z{nüţĆÖm[+Ę+j_ŹíůĺJΤ ,ł3ß?ÓušŤób§ĄŁĘ>ůÉę'=Śf˛Žthi-ńZâD㉶ˇŰ–ž`0Ę(E™ű.3Őe‰ßďO}’˛â¨‰‰‰‡~ŘL ŁŁŁ@ö`I!î‰ń˙˙đĂŰ~ÚV^^ÎľpŒž[K4ú.Œ~4xhţĐ8ó˝3§ž{ĘK޸˙ÐůÁţp¸6V;11Qx9Žă¨(hĆ ‚7Ú ~ćoů#%ŸĎ§ÝÖ|ĚÝqtęť§Î65“ęâuĺ;ËĎ)Ëj拙­ľŐ>iˆ”VÄEJŇ&ÉĐ ą)ŸTąP¤$î iłdÜ+B™ůĆ ÇqT4ăÁíŁď֒š§kŽ}ëŘÔÔÔĚ3moˇÝřř†•tć3-?j9÷ƒsSš÷ÄčŒxTůľĘŽ‹]ćÄSš:Ű|śúëŐŮwŹ;Ą]ĄŽŸu䗺 á˙nć˝9X͈”–ƒ”Mů´żÓ~gęÎśmŰś}eŰčďF;ß봒†Ż_űĎkW<,m–Žź|$›{Žő™ďé˝Ü[QQ!m’Â_ ßýóÝîKÝĹŠ°ě{řt^č<óOg*#•§ž{Şë˝Ž‰ßOxOu1óĹLßű}ľąÚÇîČÍű+ˆQFůŁ×r˝ZOŁďň¨K~Ő/źŃ}g6ˇŻ{˘ďßú>üoü÷ÁËw–÷\ꙿŠĎ5Ő1úÎĘR–ĺňGËŽ6ÔĹłĎ9™ľä^jˇn>{Ŕňă8* šqƒŕöbýü"\~|ÂÖ+"ĽŐ)evČ俯{˘!ŃpăƍÁ_zI]ŕ>%oĺwŻăşůěˏă¨(hĆ ‚7ڋőó‹půń [݈”VO¤äţŕćüĚ|1łyëć\Ó08R—"R2ĺŞéşůěˏă¨(hĆ ‚7Ú îSŠojjŞĄž!đP@Ú$ůđU?UÝ÷~Ÿ™$IŇĚ3uń:ß>ŸĎWýTőřÇăöm‡3~<,m’:.txLšül˛öĹÚ@ m’ÂĄpĎeŰSłî‰Sß=e&•=RćxţĎřÇăŐOUű|>ßžşxÝĚ LŠčR†â*Ö˝}ě€ IDAT= Ż6ˆ{÷-šőů-ľTő’ş¤¸y €ŐÎ@žhĂőŞđ÷´j_Uâd"N†ĄiZňJ˛j_••yô`´ý|ť>­ëÓzűůvĽTI}’2SGFG”RĽťˇŰ˜5ĆŽw“ýÉ“Ň7ÓŞŞ6ˇ4kˇ5cÖş:TólľťřáxÓŮŚt:mĚ#wŰϡ›ŠŠORJŠb/Lô`ÔĽú.e(źŃŹŁŠ¸'.!DhW(y%ŠëşŽëCW‡BťBÍo6{IuÔ+ď:zŠç pGEA3nźŃ^Đ:ůăś^áG‰Đu=WćÍ-Íö%Ío6ÇĹĚ×уŃÖˇZ­¤d˙|ˆĺ’dĆBšvçHí ™ŻcĎÇ2 ăR}—2+RňČ{śCĂCńĂquť*J„źEŽě‰´w´{L5–+RĘŻj8ŽŠ‚fÜ xŁ˝X?÷c,?ĆwŽW…ßr…ŤŤŞ_oô?čĎĚ<NĎOź&Äääd86xĺĐ?>:xh.ufffŰśmSSSîI@`ôŁQ+É}w333[ˇÎ=zŘ˙ üú¸Ł0ŰśmËU}—2ë>%p>ňĆ÷rQЌo´DJůăś^ţŁbbâŘŤÇú˙­ż|GyčńPôš¨ő ŕ,™ßŇfɜB@Ú$‰˙qćfŽďždč†Řäľ.ÖÂě…ů‹ůÔE”ay#ĽľuЭ㪍 ßËEA3nźŃ^0ŁćäqEőtŹž’˜ĘĘĘúŢď3tŁűRwőŢęłß?[űb­•jvÍ˙űů¤5…€˘(šŚ9z~LRKŐÉĎďËÓ#ĽTÉ,ŒőzQe(–yžŢ˜ľ^— |źřę´.+^)Kf“¨xŹ˘î庥ÁĄŢË˝ÖâŽ_tŮ×ęúyWőSŐćëęŞęţ÷űłfć’T󍚮ŸweMrWóTMfa\Öw)C-Eśj˝˛ŇýÂĄ°c…p(ěX§ˆ{_g %m’üú+Ť¨Őv˝×ea]ýxŻ ‹šŠ ÷Ygm˜GEVO݋[’Âs‹ětvuÎÍ}w[k<ÝXóôüdtуŃöŽěsߍŠŰŐîKÝćTlƒֆ.Ié›iuűüÜw#D÷G]ęb-œ›űŽĂëÜw.e(źŃ˛MëăÄĺĽ ĹŞZćŽF>ąR‡†‡Özc.'÷oOUU~5ŕ˛ÉŠ”9SáEZ…•Ęe­”s•Ł7Ţh/hüĺŚiZýŃzkę­Ş}UÉ+óÓ.ëÓzüp\Ţ"˲\ľŻjěú˜}ŰĄŤCĄÝ!Q"ÔíŞcÂ.—¤ôÍtěPLUUQ"BťBݗş­ÝłFăéF3)¸#hŸĺĚ0ŒąëcUűŞdY–ˇČńĂq}ZwŠűŐ+N×­—eY)UęÖ[óË9J24<¤”*­m÷•ßťÂĎƒŃýQEQD‰ƒ‰ă }zž¨főEÉZýąëc5OטŮąÚÍ=)•Jޏ)ĽJ–ˇŐľ‚#Ł#ćŰŞ(ʂoŤK o4—Łi­˙¸÷RřbU-ł­Ź™ ÈŠ­őĆ\NÎVš5RŠTó›ÍňŮZn? łl˛ ^¤UXŠ\ÖJ9W9šqƒŕö‚ÖÉ_Q>aëőÁ;KQ/Ă0TUí|ˇS×őt:;ŤĽŢĘÓZ'y%ŠnW‡Žĺűž,m_§¤\<šÖĐĎ5/Ĺ.VŐ2!Y–͝˴ۚ(ÉL_cšœrľŇČG#VK*Š˘ÝvŢźˇŞţ^ŻĄOËZ)ç*G3nźŃ^Đ:ů+Ę'l˝>xg)ęĺ O몪Zyš/:ßí í ĽoŚs̋%=kpJĘĹăŃ´Oë^Ęź‘RhwČ|a>K×ό¸Ô})ęĽëzâd" ÚŻ‹[y†Ńüfsô`4W„ćݒž58%ĺ˛ÁĎ×ĹúƲ˙úě|ˇÓ| Y# :–gîąóÝN󧪃źEœż'Ç ş2Ůs󸚑ű7}ć)+öźsaüĽxŐńҘŽ$ű_ĄÝ!—MňkGĽ„ąçcšVśłˇXŽuě{ďîíś&ĚZ<űÂúŁőŽŐc¤˝ˇšKś ž5šž šqĂŕö‚ÖÉ_Q>aŠTŞćŮQ"Ęw–ÇĹş{ťíů;מ5DɗąAîQ4îIŽ “nťł-Ě^˜l3w-]˝â/Ĺkž­™‹…fĹË çňĂYcElđóuąžąěŽyĄÁ|mýUE×őĚăË0•}IÝŽŽ]Ónk‘˝kCëřRUŐZ3ٟ4ft:ÝůngdOÄ^Ť†QőőŞîŢnsčo:ŽeţwsüpÜZ­űRˇľÜě=NßL—?Z^`uź4Ś#IÓ4+IŢ"ťlâ˝ěŰZľ íšď´ŸH=ś˜{-ĆŽY§\Y–Űϡkš67Y˗ł9T}˝JÓ´ć–ůđĎz°Ř6ˇg+o‘;ť:­ű9󖫦Xšqƒŕö‚ÖÉ_1?ałĆŘő1sě5M,Ô÷’ůd›“TUÍőă kEŹ…‹íSšSÜzÝ?@*•÷GJďvwÇĆDznîgąÁĎ×Ĺ:Ÿ8~'N&Äý'™Ť™Ě›Mďvš í'ćśĆýW4Zßjť>–őŒÇŐ2Ůc9uťj-ŻÚWe-ˇî`L^IXyŸŮ쩙 ˝7‚}[kV˝_ X s Evi1÷Z؛Č1(:W樟űEYΚá‚mnĎÖŃ1•ˇœďƒfÜ xŁ˝ uňˇŸ0}z~Ŕ[ćW—ă~ë{ČÁ%)~8nëϔľ"ÖÂĹާäP”zɲlżâŘxşQÜ)†‘ě/t:ƒHi…lđóuąÎ'ŽŸĹćťT*•ššI)UŹ…Öĺ űOđňGËͅŽ;„˘DDöFŻÇŐ Ăůh$v(ÜĚ2pŤÄVBež„Ö%űŻöüŞăą1íź÷)yoű*Yk§”*‹m1÷ZŘűť\zŘě9اń,°ÍłÖˇ@šjŠEĄ7Ţh/hüĺś^źłőŠîĆÇ5MÓ§őÖˇZŁűç `/ÉĐ𐪪Ö4Ůy଱"6řůşXßX™ż_kžŽą–ŘĂĚ=fűjg]ďą˙ČśłOoŕq5ű˜şŹ\jW”ęxoL‹÷ű”<6‚§Ú}yo1÷ZÜwĎgî9d_¸˜6w)XފžáĆD3nźŃ^Đ:ů+Ę'l˝>xg)ęĽÝÖ˘űŁY ŕ(‰nš &qÇYcElđóuąžą2}Ú§Y#Ö˛ţHľwäb­Źëzwowâx–ľ„öţ1k"ľdŽű”ň­Î|Á˛ek¸>O)×& 6‚c[÷ű”źˇ˜{‘ň¸OÉ}á˘Ú|ÁśĘCŃ3ܘhĆ ‚7ڋ˙%ëÚÄĄaîŤ%ž=?ýCmŹvôÚ¨¸'fž˜˝6zîçÂĄ°•ZŠěx§cüĆřĚ̌¸'=h%ˇťš}pZď/{§ŚŚN~űdÖĆ_žŸ;űÔwNMNNN~6yú;§ ŹŽW÷ÄÄÄÄš>÷Dőâć–už×éĐﲑÇFp8ńډÉĎ&'''O|焵°ĄžÁ|á˝Ĺ+~0hOj|˝Ń şN7žîx§c拙™™™á‡ńřëÓeľąëcń—âs“Ş•ĽT‰ě4žn´ßO8v}Źńtcdod cĎdž†‡YyYÍ0ŒÖśÖ஠(ęvľńtcŽ9¸ Ă0fć7›Í'PƒÁć7›ďť“GQ9{ŠŽ—V2ËŻ(JůŁĺssŇd{Čufą˝7‚cŰć7›Í6 ƒMg›3.,ŞĹšŢh*ßYnŸ%ϞžN§_o 홡)ĽJtÔţ”ŘŹ9řrĎ!oEĎpc˘7Ţh/$cĄËfČE’$óm¸ÎXď,–߆=š8Ÿä­ëb× ľ/˜ŻŤöUهˇ­-ö3ƒüp͸AđF{ąĐŒžŔĆĂ)cůÂŁĘŻU6źÔP]UPSžęż˙ءŽYЧ^;ľ‚eŹ3ô)ĺX(Ž&ZŔٜAu‰h}ŤŐšó`-˘OŠpGEA3nźŃ^ЧX3††‡:~Ö1řÁŕ­?Ţşű?w•-JůÎňęŞęş—ęĘĘĘVşt€u…>Ľü‹ĹÂŃD …ă8* šqƒŕö‚ç)€‘8qŸR0m°Î)ŔŽŻE܉”7"%xĹĎŕśDJůăLŹWĚčNDJŕD¤NDJŕD¤NDJŕD¤NDJŕD¤NDJŕD¤€ľM’¤•.Ö!"%€Hy1ˇm{ť­˘źBÚ$ůýţgţî™ÁÜÝĚ3ĺâž[1|ř*#•]ďu9V(RWŻőWÇőWŁuƒH `†ă_—$!ęďŸéşÜŐyąÓЍяFeŸüdő“ îŽí§mœčşÜ•™deŽĽľÄk‰'ÚŢn+vuW5łae@¤°TÚ~ÔÖsą' ‹M˘ě‘˛žK=Mo4yŮŞŻˇŻĺ‡-.ëřđxî@ĎĽžs?­ŤŻłNüab|tÜě&Ş{šŽćŠ}ZŻyŞćXý1żß}.Úö“šłśŸśEFý~żľm]}]ôš¨Śi˛,[ ŐŤ;\gčFëŰ­ľ/֚ üĂ‘Ž ]†nŒ˙6K“šÝt=—zŽ˝zln“—T~­Ň˜5Ź.ŹĚ%Ţ÷ĺR{Wdf#äÓĐ(˘\ÝǀeĂ9(ܲG.ťČL íľŸo_TţU_Ż0 #y%ÝuĎhx( z)›Gî͘wţBMÓ Ă0kĄ>­[똥”}‘ŃuťjĚĆŹĄŞęŘő1{ěëŰfţĐMO„v…ęÖ'Ż$3˖ěO–ď,wlbežY<űűr/€˝U3Ą@.o%ß; ˘uňWh ĂJÖ+† ˇlǑË.2“ĆŽƒÁȞHăéĆÎw;SŸ¤Ü3ť>Ú˛ţ ƒŠÔü&öüői=y% [ßjőR6Ü›1ďüEŽHÉžNÖ !˛'Ň}ŠťłŤ3˛7âŘ*W¤”N§3 JĽZßjě8‚OĂ0”R%y%iĚú´ž™yfńěKźďËĽ‚Hiľ˘uňˇt? kĽëC …[śăČeٓfä•dăéĆčÁ¨RŞDöF˛ţź6ĹÇŰ;ćű šÎ6ŐżRoĎß"ËrhwČž˛{ŮÂŃnkŃýQY–ƒÁ`gW§š°ý|ťş]Bw­ˆËŇ~ž]Qy‹lNś1—y*Ůą7Ećďűr/@ăëć@žœP—ˇ’ďIżřóeÍ|Bâh˘€Ây9ŽěŽÉűp“¤œ?Ÿ\’,3_Ěl޺ٸ—eľ3ß?sşńtćňć–ćß>á%÷ŐDY×ńRÁ< †Ľ“ŤĺůŢń‚šďŔúgŸÜy95źÚŕx€ě­ĎoŠĽj–UŸ´ev#¤RŠśů‰I+ŐŔÚB¤Öł• ~üهżî{żoffffffř7âĚűaş.w…w…ËĘĘËËĘĘ*vVô\î)zٖłeč¸ŔZDOhţčľЅى —yš‡Ë3únřĂ᎟vô˙ş˙Ö­[˛,‡ Ő˝TWŻËÜ6üxřÜ÷ĎU?U™4řëÁSß=5üápąFßeĘl´âŽžĂJaô]!ř¸çOP,M´P8űq伍dn 6‹˝éˆ”Ö"ĽB0úŹ+܁“7š°+YéŤß°pśÇŠ _n !R˛ŕśüřÉ`™mŔSý:;Ór`Š1úŹ+üzÎŰÚjşľUZŹEDJ`˝1ŸD´ŇĽXKVŞĹŚŚŚü~˙ÔÔÔÜżš˙לÄ<ô˝ßgŚJ’tîçĚÎ1Ť‹lbb"üxXÚ$…OLLX+[{ą^w]ě*{¤LÚ$ tźÓá(LÖTI’NźvÂçóUműÉÜŁuŰ~Ú=őűýVÁz.ő{ő˜ľţÄ&ĆGÇŽ{šŽćŠ}ZŻyŞćXý1‘Ű‘8ŇuĄËЍŃáŃáß{L•eYÓ´čsŃşúšéݏŐŤ;\gčFëŰ­ľ/Öş,<ňň‘ĘŻUłÎFÖnkí?n?ńíž› +Á@žhĂőjąďŠý€’ˇČ‘=‘Îw;—gׅh}Ťľ|gš(Š˘Ô<[308ŕ=Ő^ÎbUƒMœO€ÂšGü22Á}\ŠE/ŐČ舺]5f cÖPUuěú˜aÉţdůÎrGa„ú´žY3’1 CÓ4Y–3‹j˝NO„v…ęÖ'Ż$3K’5U‘™š,˙-™kĄšš=C]×3 šDň{Ła˘O (ëˆŇŇZâľÄ‰Ćmoˇ-¸Ő ŢY{ćűgş.wu^ě4tcôŁQŮ'?Yý¤ÇÔLůU–“yšZéRŹŤŞ5ÂĄpŮö˛žééşÜUśŁŹâą !Ä /žĐüĎÍĆŹĄOëö•}ř›˙Ě̌őúÜÎőôöTěŹ8űĎg沰ćéšĆ×ÍŃw™ľX†ĎĄË[šž„%BëäOŘzUx¤d̢D†ÚĘěßť>ŚŞjÖkBó\ŹŞŞ(ÁÁÖˇZíŰ&Ż$CťC˛,˲ÚJöß7<Ŕ}ŰűĘ\"ěgíEĽ žĺżŹţ˘lđىó P¸y˝ž+)™ăîÔíŞľ ý|ť˘(ňŮç䊔RŸ¤BťC˘D„v‡RŠ”š°űRˇRŞČ[䌳ó9´ŸoWˇŤBˆŕŽ •Ůwš™*„HOȲ\ţhyꓹ̵ŰZtT–ĺ`0ŘŮŐé˛0•JEöDœßőUX:DJ… uňÇ'l˝*­ÇÇĺ-˛,ËUűŞě߆a ]2;@ÔíŞăŹî’”ž™ŽŠ™ŁBťBݗć{<ź(đ‚HÉa­W™HŠ´Nţř„­WyDJó] ˛Ú˛˝5mŠŽ[˙6żŮl]Î)Ůo5 C×ukŚ+IJhˇ5EQźl›ĹŹ‘ź’l<Ý=UJ•ČŢČ}›ťŚćěiɨžwKt4­Â;˛˛â|n9ŁŞ}U‰“ óĨiZňJŇşƒE=m?ߎOëú´Ţ~ž])UŹKN#Ł#JŠŇÝŰmĚc×ǂ;‚Ö8j—¤ôÍ´ŞŞÍ-ÍÚm͘5†ŽŐ<;™Ěű€/ˆ”Ö"ĽBĐ:ůăś^ҧ”ÉމdF0ž/ç%+ka–ÔY×Tďu™5ę_ЎžćLuňłDGÓ*ź#+׎8ŸZÎăH”ĚOôœYŒć–fű’ć7›c‡žźé˙`ÔŢç“ěŸą\’ĚX(×îź(đ‚Hi!R*„dÜIŢYS<ӆëŒ$-î¸Xpýş—ëĘś—ú÷űNďôčŒćÚ0kVÖBżßŸú$ĺĐo%Mýięáż~Řz–šËś šůbfóÖÍĆ˝ě+;RíŮ.śšr1¨˘MáÇĂ /5Ô˝\—GŞX¨ŚĂ×Ćj­çÁ‚ó P¸ĺ<ŽÂĄpuUuăëös˛UŒt:Ź%“““ápxrrRáĐ?>:xh.ufffŰśmćiÜ%)Œ~4j%šďnfffëÖ­öŠąĹ˝‹uÎDzÉő–ń˝ăĎSZ&Ł×Fkcľ@@Ú$ß<0zmtĽ …e’8žhűI›¸'ZŢnIź’Č;ŸĘ=•ý˙Úo_Ňű~oĺžĘ<˛jxľAÜťoÉ­ĎoŠĽŞ—Ô•%IҢžCŐyĄóĚ?ŠŒTžú÷ş&~?á=ŐĹĚ3}ď÷ŐĆjO_řńę‹-3€ŐݧˇçĆďolÝśľ˘ź˘öĹڞ_öŘSíq‹"P¸őů-óő;wś}e›ôĽÍ›7ßšsgÁ¤[Ÿß ¨YÂ¤Źťóů|wďŢ-źŽčq˟÷6ěěęTJ•ć–ćôÍ´1k¤oŚ[ßjUJkIŹ*‹=.źŹ_ľŻŞńőFĽTąő˛AwÉĘZ808 ŞŞ5÷]ňJŇ1÷÷˛ !BťBVVCW‡BťBÍo6{Iud[ŹÓȂGSţ'Ž•ž#ËKą9'…[ăhÖť>Ö~ž=´;dŻwŚÓiU›˙Z)U4MsćłP’ŞŞŽ<-‹:ů{áތKןí¸lőuy+ůŢY­“?Ÿ°Ô')ĽTqĚ{cĆŘř˜ýOŹK)%ű“BˆĆ×í ÍÉÓ쟢żđœĎSş’ĚşÚ‚eŠŽ[ł6EöDě?úÝSe”Šy‰g%îČňRxžą€Â­ŕq¤OĎĎ #şO)×\’â‡ăöËUvk:R*âˇÉš;.xůlŠwÄ÷Ž´Nţ<~ÂęÖ;fÓ˛4˝ŃT´ŢĘMŸÖă/ĹEąç™kVPĂ0ŇétýŃzY–•RĽţh}Ž[KąXKr֘5dYvLłťŹGSfŒTři]ŸÖ]Śap¤.E¤ä^ÓüvŔXŢă(˛7ŇŮŐ97÷Ým­ńtŁý™ уŃöŽěsߍŠŰŐîKÝf§ýŔŕ€ľĄKRúfZÝ>?÷ÝČG#ŃýQkw™Ĺۀ‘ŇšC¤´&Đ:ůóř ;;”LcăcÁA+ˇŘĄXňJŇ>:ËeVPĂ0TUí|ˇS×őt:;ŤĽžĐ*Á0Œ%8Ykšć˜+™GSŽią§őúWęłŰĽR)kŒ{Şą”‘RŽú㎠ĆňGƒŃýQEQD‰ƒ‰ă }ZˇŠa>OIQ”ŹĎSť>Vótů´ĽČވ}t€KR*•Š=SJ•,ĎSʰœ‘RgWgkŽ IDATpGpîPçŰŹß6†1÷\ÁÔ')!DÓMňyn&ôŒ1ՙ+†‘N§Ťž^e>'ƚ9ÖąG{Á2ĎąYsB4ˇ4›Ă:re˜UŽÜšŢhRĹ,šőÚţˆ­ĚĚü 0ŘgśŒ÷Fđř–ŮwĘ÷Ž;Z'?a˛,çęíą?îFŃÚć|TœËŹ ÎŹŚuűĎ;˘¸g !„,Ë5ĎÖä}“ýËrA‹ĘvĹďČňRžą€Â­’ăhĹ P ÷fĚ\.o‘‡Ž™ˇa›×Í73ľ˝ŁÝ|Š ˘é&]ם/u[O˘sœc3WˆîvžŰiĚÉţ¤€eî1ł`­m­ć~łć „¨?Zo=Ŕ#k†YĺĘmŽä˝Ý˛,7žn4_çŞfŽ–ş:”u‘R!hü=RĘźY3óą˜öm'Á`P”äóó.hÉá%@Ę㣞îČZ˘ŞpX%Çъ @î͘šŮűËŢ3MgÎľœŤŐZšeć3ůŮd¸2œ8ž¨;TçWüŁż=űýłfëç(~ĺ\Ë9šDžđł ƒ öţK/ďfQŹők”y@Ů[Ţĺťsm˝Aš*’ľ˛kŤjŔŞÂqTyŒžË➨­Ťm<ŮXńX–ťքuóc€Ńw… Oi9ÔĆj~50řďƒá݆ĽÍRĹ˙Šüƒ}ý}V˜”KŕĄŔđŐák˙yíኇĽÍґ—Äb13Šýö;SwśmŰśí+ŰF7Ęĺ„uŔ:gežŘ˜Źžď•.Hń­×z€B’$iłTýőęľ& â!čS*ąřzľR—‘2oý\7´źČěSĘş‚im5‹—’s> ÇqTĹéSÂŞAŸR!˛—°˘8geeE+]<­ÔŰşv[ ëç:ŤŁď€UÇţÓv拙şxďŸĎçŤ~ŞÚ>5ˆ$I3_ĚÔ˝\ç÷űí›LNN6Ô7ř|>˙ƒţ†ú†™™™\ë‡÷˝ßçŘűřÇă@@Ü[ b-Ž[[ń2cú ČVđˆˆ”€U텺*÷TjiMť­ŐŹ}˘ú ó\Ś# G˘ş=e˙ه+÷Tjš6~}üΟďœřÇšÖOO´ü ĹąÇ–ľ4mČú/€ƒÁŚůc|çzľŞîSjni>ńíůPçÜ?Ÿťö_׺Ţë2S[ŰZę\ňœůbćáż~xrr2űú÷DŕáŔ@˙€uÓíÔÔÔĂ?œú$ĺĐ_üşZđ>ĽőméÎ'?ĎSšÚúW[ ƒÁŕÄÄDÖő-ř–ďĺ˘ŕ>ĽbqoŤekIîS*}JŔŞVűü}$ÖŞüő őoôš¨cý™™™Ż(++“6I’$mţË͡nÝĘšţ&Ńp´Ąĺ‡óÝJ?í¨ůFÍň‡IXq×ţëZdOÄ1>Şđ0ŠçrĎ3÷LQJë@潣Y'źĺÓU‚H XՁŔ}˙–n}~+WŞâءŽÝ¸q٧ˇGŸÖ Ă0fďťP”š~ĂцŢ_öNýiĘüˇí'm ݏuRa˝şqăFůcĺEĎvbbBń+ ŻCfNÖ.úyV "%`U3ÎÍ˙űů¤ZŞşŹß{šˇóBg8öů|Bˆ‰?.Đ'ŕ÷űŁŁm?iBô˝ßç/őWF* .5֞ń˙/ߙ3Rę{żŻ2Réóůü~ĂŤ ք:¤/ůđ=ógŹű茌Ś$I:ů'/ţü˘šÂŠďœňűÝ•żŸ<4ŔO~6éĐßöăśđăaŸĎWVVćžw!ÄšœŤxŹBÚ$ůđřćű]|V„$IgžwĆ÷€Ď˙ żç—=ćÂÉÉÉęŞji“TöHŮđ‡Ăs ?›ŹŒTšç—Őş.v•=R&m’:ŢépYhî]’¤@ `ÍW$IŇšœ <$Šě‘˛ů‚ށ‡ö“Ffyrexâľ>ŸŻâą űć™k !2×ĚŐ§dýľ˙ť¨6ÁR RVľŽ_tÝ÷ďĎťŞŸŞvY˙îÝť˛,[˙vüláhâx˘í'mâžhyť%ńJ"ď˘bMťöńľđcáŹImoˇŠ?ŇřFMÓFGGo||Ú&dâííé›icÖH§Ň‘ŻEžůűšąv~ż_Ó4!Ä\÷ŚaÔ|ŁŚlG™#óᇭŕ|řˇĂw>żÓsš§ýÇí3Ó3ćŘ?—˝ŸxíÄľß]ëëí3t#őI*˛'ŇušKX´ŰZűŰ­űlŐŤ;\gčFëŰ­ľ/΍*?ňň‘ĘŻUłós!f_íŽt]č2tctxtřˇĂ. ŗS}ö\ę9öę1káÄ&ĆGÇ Ă¨Ž‹sg‰ŽŸwT­Ú;e–'W†˛,kš}.ZW_—ÇšY™;͜Ň{›`IcŞĎ Š6\ŻVę=śS¤ő"z0ÚŢŃŽOëú´Ţ~ž])URŸ¤\ĘݍŽkšŚOë­oľF÷G3łÍTľŻŞńőFĽT1ż!VÄ?š–î|â1OĽÔ9FŽ˝ŁÝ0Œąń1y‹l}ę ĂH}’RU5{.ł†(™ßÝĐŐĄňĺÖżíçŰc‡bŽ-ęÖ7ˇ4›ŻÇ‘=ű‡Đ}Xa֜%ú´ođ3IQ¸7ă‚Í+„ĐuÝą˛ýž}ĄŚiömłŽ–8ží Ő­O^IZkf]˜ěOÚűĆçËóĺ‰Â~R*ßY>6>ćŘťŁ<š24WÓ4M–ĺĹŽ™őťŢńbÁŚËZý\\ŢJŽ—Ń:ůăś^­ŞHIŸÖă‡ăŠ˘Č˛\ľŻjěúXćúvÚm-ş?*˲˘(ńĂq}Z÷)%ű“BˆĆ׋V™ĹŰŕGÓĘFJÚmMQ”ŹIń—âőŻÔߡhv>ϑёŘó1uťj=Ć\Ý>DľžŐjÇMg›ů‡v…††‡Ěב=‘d˙}ßúî{WU5q2aý&ĂÚB¤´j)ež–e9N;ÖĚ)eŽfF*•j}Ť5˛7ÝuY¨”*É+IcÖpůîŤúzU÷Ľî䕤=Ť\ĺɕafüă}Í<"%ďm’‘R!hüń [Ż6â{:kȲœž™ĺ\źl6řŃ´˛‘ŇŔŕ@dŻsâ;S0”RĹ0Œd2¸#Řůn§9úÎ0Œ_ݗOüĽ¸Ő_dFÍÓ5Ý˝ÝöĚu]—eyŽi֐eŮö¸ěÝ,vůÎry‹\ľŻŞő­Vú—Ö"ĽUk)"ĽčţhěPLÓ´ôÍtěůš (5O×4žŢhďFÎşZüĽx*•2fĄá!y‹ě˛PŢ"]ҧőÄńDŽHičęPůŁĺ‘˝‘‘ŃGÉ3˓+ĂĆӍƬŃxşąj_Őb×t dYNĽœĂFźˇI.DJ…ŕ>%`Ł›šš:Ó|&ö|Ěşą͍7ĘËłOçđé?Í“iN–xňŰ'űzűj_Ź <0UÜušËš†AqíÚľĘÇç'˙ďńđŁ÷Ý őáżÚ2ˇţĎ˙Ÿ˝űmŤş˙ÇîWítoÔ˘ë(E×Q‹ě¨LÄ6e" Ĺ…ˇ:§LŤł"ŐiůťíGCßjí2$› )ÓHŇ fQ’˘ą¤H4 oŃ$źĹŢIźă" îD?qŚ2٨ě¨EvÔN÷F ŇýţqÍsmß8Ž;öóńGäÜ{îšçžűĂ÷ĺsîšţÚjĽ‘H2Y;!ÄRo NC×BŽĂŽĄ÷‡~öÄĎrQ{˝gzçîĚUWW›Ÿ0[w[Ľ‰ŢÓމ‹ÔGPH™ĚźĂl~ÂLý€jzśŠ˙~•‰ŢoĂ/*Ť+Y6퐛ćÇÍ,Ëj6iLF哙ÉĺI—áÜżç˜{˜á÷‡űN÷­4Ľ ÷1ˇÁ`P ůy@>ŕőaŮĂťJUY˝V˘(šŚ-OZúßéO—lKBĘřl*ě›g]Í.Ă×ŃÄkśhŸăŸĹœ7Rüm^Žm_6?ÜúŰÖΗ;Ľ)Ěf&‰1›9}ěf,ń0łŐMé>ŐţgŘwڗáÚâńxÍkä ŠŢ<[´JüÍłó¤ÉŮÔz˘U~ĺúJ­ťŔ›gWmJeMEAF/Œ6L‚ÂşrőJş—)šššžm ^ ’y"Ü&.N4=Ű˝%„Ôí¨k˙}ťpGˆÇă}gúvţÇNvŤ×-F5ôúĘ߯Č˙ęśęzşz„;‚ +&{ÓĽĎ.ŐŐŐIs/}vÉü¨r„útk÷ęo|ŚŃ˙Š_A_öŰ÷ˇžhÍq˝@iĄ(ŠŞ ,?ˇd&AŮÉWˇž2€:,UاQćgSţŽ'™äÉVą)Ÿ–tœěĐmב „eYë.Ť<čB(Ş{ŹNž>ůÉdÝcuăăň‚ýýÜօ×ńˇůń‰q)Žăěűě—?żĚVąňÓqÇ%Žq§žvžç˝Ży;ŒdĄ7ŃuŐ ž7˜ź,ł<íe~%É őjDőŽ;*ťç˲ÖYbQAŤeŠJ~+Ź™˛=› Űű`íĄ÷]Ń*ńŢwĺ˝ďVcĂňIĘ .kŃ)<§ „H @ ‘€žSĘ~+Ţân™ť37ôţPÎK•sY/[„+IN Ëvt&ĐŚëŒď´OťMKm¤LFSđjPš(ë ‚ĐôlĂ0š-ŠÝF}Am/śiśh†i|ŚQ¸#ÄăqÍM<—$NQ$VĎyôĂQM•ĆuÔĽŠŇŒ~8šœ@łEă}Í;ö?cËň‘Ź3Oüţ6oŰcŰďŘŻ˜ŰŢÚ>Ÿ\„‚Ą‹Ÿ^Ě|A…Η;ý_řƒ`ěfŒÝÄz~ăŃh4ś=śžˇúä4ž7|ÎNF“œX=óÓŻŸv?ď&„¸Ž¸Nż~:mşďÔł€<*ęÖü"‡VËR…ç ¨lĎ&ôžËEQąXLŁŃBA¨¸§BœIB™ľZ­ßď×ëő„đ×ášÖHÓÓ-˜œ˙B>Ű´ăj „ř­xĄ&~+œ6XúËÍýőţOüÚmڔ‰Išš ‡Ăڟš"×# Ă‚P}_uŕó€T`EďťŮřěč…Ńtůôž+%¨Ć2 ´)¤ š+ô>‡őDŠv! Ă$ˇşĚĚĚHQ!DŻÓ/ť <ˆBr>?2üHšUyoĺ졳„C­Aż]/=;4p~Ŕ\gÖnÓŚKœŽď ß졳EUTTĚ~;ë{Ă'ϕ2ŠŽŠžť3ל?ăZ€C¤%…ă8yŒ„đ7aőÄ$ᗑä|"‘Hr<ď>îî9ŐCéůSű„[=q2AúŢî …BrĘP(Ô÷vŸ ‰ĺîCďiśhV¸ő3ˆ” ¤4íkň÷ÄoĹăˇâ-Ç[˛ÎÇuÄuĐq0“yźl|ŚQšŢđ‹†Ůog}§},˚Œ&őÄÉν{ÎźĂ,ˇzBôz˝y‡yřüpÖE€|@¤%ĽădÍĐŐ÷U×jęęęȆ,ói{ą­îń:ófŞ‚úľý×ö˝vy–ëyW‹ŤĽí…śL+řŢđ577+&677÷üš'˂@~ő˘EOÂ•ŞŹŸ3ö_ň÷źÚ3ńżłłł,ËZł¸š]–§,r‚ŕŐ`ƒ­!üu8Ăôůă{Ýç{Ă7ýĎivk~Ěě>îśÔ[2œ›X?‰vЛh㏍Ž#ŽŚg›˛(’”UٞMŃ!O– ŔyƒJ ŞąL`GgmJšŃwŚď ă ýY{čZHäĹńąqBČÎ˙ؙ˜fřýáĆ=™§Ď“ÎW:ÎôŸëy1đy€f蝖ÎM&?k‹ÄÜ/¸=­ßë>•ôkĎ÷şĎPk 6RŚá醉‹™ĎM ŠĚfĆ\gxg`śVČs܏Çăˇâ'^8Ѹ7mG85šˇŞ ĄKUűtęŤ)N‹ĹÓ;Nv$ţk|Č8ůÉdćéó„ă¸Čő%žwźÔ‘á\qiý$×Ő¤R§ÓeQŞ<M';ꍝ¸,ŢC×Bś˝śÄľ¨ĎÓo,›äśrŢן9)gţŽ'ŮĺšŢŻl^Ÿ—­béM´ý€çůB§ôeqŔäéhÇ÷ňęĄËvt&J¤EA Ő˛TeŃ'Äépšv˜\Í.•4ŃhÔđƒôŠ•LŇgQ¤L“m¤D^$ł™K’zß)×8O¨ *ĺkj–)U~zßiľÚŔçigIç˝mżkËd.Yncý—üMöڜôěBď;X×ĐűŽ” Ëvt&đ]˜=aĽ*‹ďo˝^?ńфţ~˝JßiŸ˙3żÔ_+“ôY)ĂdŚGLŽC.çagsIނ‡P;ôސVŤÍdnÚąďhşöÇľŽ#.§#›Ŕ#OmJÁŤÁ†_6h9mĘŔO}.Iߌ”şŽfڋREąľ)äڔŠŞąL`Ggß ŮĂVŞ˛ě}71‘ř*I…Ą÷‡|§}›Č0=Qíţ”Xź “Š™'.ˇkzzZ.žúÜe:¤e+Ł„_X˜ ‘”DJE oË ÎřÍŽČĽ*›;MŠĐĐôl“ůQłœ`ŮôŮ)ë;áŽPQY‘îyĹÜő)%*ް0"%(7ˆ”Š"ĽrƒóEާîçÝÝ]Ýńx\1˝ó•NéĂ؇cś§m™§Ď+×Q™_2ećŰފËdnÁIŻ3Ę~ů¤űd÷ŏ/f37[Ť-3"%€0ćÎdneoOXˆ` օ•żrÖˇBqE ‘@n8;{Ďöž{ç\Ík¨ j§u'!d|bœ2|aŘú´5óôů6éŸ4›VÜSQyoĽçëy—çO&s b5m2E˘q `A˙őěeŘ:š+vđjp§u§ű˜ű„űDë•ró˝îó˝á›ţç4ť‰5?fvw[ę-YäÉrŢ{^ż~č˝!“Ń”Ăóžî5ýŘţ&ěiő ŸĆŽĚÜY„"RRo{Y_;(“ń )AšA¤Ĺß ŮË"RýpôŕáƒCď ™ëĚ*ɖĽŐjŸŸ{é|šłíwm+ÝH w–!GJ™ôO[_;hŮ-JÜjDJP&)@ńĂ7höV) ź3ĐÖŃ616ĄxľĽ"Y&ł¨”Č‹™żˇVw–ą˘xÖ×*ěŚáx†â„H Šß†B \tŸę>÷? Ů˘Y}nƇŒ}o÷9ç敗ëĆEČ7Ô0Ź‚(=ř­1{™ˇ) ž|ĺää'“ è$ËźM)x5ŘđË-§ľĽb°ß§TÚÇ^žś.'ٮӚG¤% ˝ď֎FŁ˙hźçO=žÓžUfĺ:ę"óKŚĚ|;ĂUqŤĚ Řˆ˘Xzw<%šQ@˛˝;WŇ86Š"Ľ5ĽŮ˘™œ˜ô˝áë>Ő˝š|N˙ů´é§ŚŃ Ł‚ ‚ŕ˙Ôßhkts窜PX¸UR(™Đ˘d6  RZkR°töíłŻtfÉ¤Ňh4l>XqOE录ž<Žç]ž<9,'PâoĚÂÁép2›†a,OY‚Wƒ‰É„;‚ó°SŁŃ$.F]Í.†a4[4Žf— éқ1^UŹ=x5¨Őj–Ĺ`˝‡ëşđ…2úᨥÖ@m¤´Ű´}gú!ćÇÍçäŃQ­V+Ü(ŠňöiˇiŠ”ÉhZ)Ň­K> ŠĽ¤‰áp¸áéf3Cm¤,OY¤1x¤š‰Éä+];ä"ĽźKž=ŇlŃŻŰ^lSOŚ2Ë\gî;Ű˝çEáŽŕżäOů씀ýÎýćGÍąH,v3Ö´ˇég–Ÿ…żËsşڞśĹoĆ“Éd~Ô‹Ĺ‚_g˙=ëů']z÷1wĎŠĹ{ţÜă:â*Ú÷ŻÇxi=–šHěvÇ+"/ü˙—~BHçď:Ovœ”´u´šš™Í !dâ㉀?Ŕßćm{lűűüž-p5 CĄPř›Ĺs'ebBȕ/ŻAiľˇśĎܘ‰„"‘P${Z=Ë..ż×űfŻuˇUšŘ`mpwÇnĆř_[[ëq{Č÷—÷”GHÖk€œ![¨ĂRU¨}Jn˜ä]=]‰işţŘe?`—çz}^ő<ůŰ<ÇqiÓßš­ÜÔWSň„X,Ʋlěf,űÍČV™ŸMůťžd—g‘ě n+ç}ÍšIœhÜaěčE1t-ÄmĺxžE‘‹-ˇ<ϓ DÎ!t-¤Č6]bBH$˛¸.Ž[\6t-”x*Ľ[t~č›}Cž[˜˜.7BHç+á†űÎöI˙vżÚ}ĺďW{7­™”cߕŒ}—Rŕ‹@űËíţĎü4M{_÷6îi$„Œ^=ń‰ŕt°ÉŢd~Ôě:ę"I^r6Ým¤j‰SM'„yBUPŇř˘™,œ6ü˛Á?á×n[8ăü—üžPË0 ™'ÔÔƏÇă555Ąk!Í !DŻ×œ0יóľ‘é!R’> RJiôĂуŽƒňűľ lOŰŢ_ KQPşřAťMëŸđëď×'ć–a¤¤ŐjýŸ,,ţ:l~Â,˙HĄžxüVÜd6 źłäTŇnÓzO #}! IDATy­ťŹĚfF¸#TÜSĄ)­t텅H JžS(jň­áÂżßFՇƒ>?Üśßd41 C ˙+Ź’˜˘Ńhl{mž7|„Ń ٚ*MAÂ$€”šěMáŻĂŇ`sßÍÉÓ;~×qň'ŰÚۖ} ÎyŔélvFoD…;‚çřʆ˝iÚ×Ôrź%~+żo9ÚŇt ő{Ó5ü˛Ął˝Sq*Íý{ŽŚi†fÂáđ~çâĂE,˧SŒĘőÚ W)ľw—t„řë€ĺ)‹Júšš9šŚĺűŢî[vîcnß>2Oz^ďq?ąćĄˆXw[-V UA8~bčÜPâ,ÝvóŔň#ŮtžÔY[[kř‰ĄúžjnëĘ^:×q˛ƒŰÂU×TW×Ts۸Ž—:2\đŇg—ö˙ŸýŠąďúßéo9ÚBUP‹ĹňóĹłŘ}ÂýđON~=qÖk€\)ŠVűu ­üĽŞ¨zßŮöÚŹťŹö˝vBČšwĎyZ=@ꐓ˛œ{Y ŰÝÓMo Ďž}vââÄđ Ťôž“Xž˛˜1űŢňĹ#ńBz‡ŢwŇôžËDĂÓ ö}ö&;šYŠzß@IB›@Qëďë÷˙ŻżúžęĘ{+ÎLNL*ž¸Pč=Ó;Ÿ­ŽŽŽžŻ:đ÷@˙;ý™ŹĹ}Ü}ň']‡ŠwppYߙžđ?Ă“ ߊúWĂ"‡ßŽJU‘˙šž󄹇 ] Éăt­=´)IĐŚ¤Ž˘(N7ôސéSĄË‹ĐŚ%iCĄ Ç}ořěűě “2„;`X3ˆ”ĘEQ4M[ž´dŘOĘGňe‘@YĂ/ô Œč „6%€Đď Ě!RPBżŁľ‡ĐŠ zß(!RPB¤ „H @ ‘€Ćž%ŒF+…QC ô RĘÜR@éÁ/d߃Ľ{łÜŕjŻ˝ď”)(Ą÷]öĐX P(ŠZŃ%=]ú•ćPĚp0—6tłĚڔ Ü­ôŽPNݏŐŔ%@ĄPK1›Ó#ŚîWťÉüňKĽűWe"” DJP Ä…jďŻ=ń›Ž˙tşP°Ž!R€’EQT÷ŤÝš-†aœ§üë2EQݧşľŰ´ŇOĹňƂ 8;™Í ł™q^&˝üW^<ń‡çśۤő6>Ó(ܤ‰ŁŽj ÔFJťMŰwŚ/ďŰPŽ´Z­×ç%„œ{÷\ĄËë"%(e/^ C‘ë‘™čŒ§Ő#Ożňĺ•` ¨č/×ŢÚ>sc&ŠDB‘p8Źž^ú,ý€­Xiç˝ţ/üÁ@0v3Ćnb=żYČg˙łű;^éy1ŕřżôç|c@annNú ý¨!‚ë¨KłE“˛—]bĘtM˜(Š:?$/8ôţEQ† yÝ(  -×äěň,™oBHčZHúşâśrňôH$’˜LúŔqܒôÜ2éľ˜ĎVn*8%}ŽÝŒąUŹ<Ýűš7r="––,˜<í¸ˇY˝uZŠ2G"ű;!Ķז˜ŔűšW>7“—JšáЉ˝}˝„ë.Ť<Ĺö+!¤ë]šÝ˘|[§;za”€Â“śĚů59ťŃŘJf ˇ%2O¨ Jœ•Óţ]UúÄé)ňݒ’HÓ_Ú_n÷ć§iÚűşˇqOc˛8`ňqŒĺď<*+ë´Sş@ÓôĺŔeC­AN0őŐTbă4QŢRĹż)' ‚P]]=;;‰D´Zm<Żźˇ’|G¤óąiy˛NwôCď;(eáŻĂ ž s§ž˜ă¸%髖IŻ’Ob”|#bzÄ4za4~+Ţ{ڎĽš%ťĚ ůŒ‹ÝŒ99ćććNźp"1ÁęűČ1 ă|ÎIřë!dřü0ůŽÔ˙ź~}…I!DJPĘZގÄoĹăˇâ-G[šö5Š'nÚ×´$ýeŇł,œ&Owqt ‡ĂdžŻŸYh;j˛7…żKEĚ}7—Íö@4[4Ţ/!dâ㉜gîzŢE9űöYBČŔť„eݰN!R€RV˙x}ĄŚúžjNËuźÔĄž¸ădˇ…ŤŽŠŽŽŠćś-ŸŢ}ÂýđONîöÓöb[Ýăuć'ĚTőkűŻí{íŇtënŤĹjĄ*¨ÇO JĘr&?Fčőzë.ëô?ڇŢşřńEšŚĺsJL‰ôDX×đœRž”̆9<§TJÖi5*ž&ŠßŠ{Z=gß:kßg87œ ĺRš-šŮog§‚SŇŁM*G/Œîţĺn–egggm{mCď­ż>ÖéŽ^chS€R@}ŻňŢĘąǚŸoî}ł7óĹ;_ędYöG†%6§œŘđtˇ•›%„88r¸ PTđc@áĄM)OJfCŠڔJ Ş1CŻtśˇśłUl<' ]š•ĂŽÎڔ dáňA¸#\şt‰ŇůRçz “ C ](F)_N–zËŏ/˛UŹ×çu5ť ]Č#tK(źbë}oč}W´Pe;:č} „H @ Ď)eřr} H M @ ‘€zßĺú Źú˛@ąA›€"%%ôžPBO0œ°RčˆĽ‘@ řĘ_{¸5/68 s8 $Ą÷€"%(#hý€ !R@Jˆ”rĆÉ߸§QłECm¤4[4{'ţ6‘˜ x5¨ż_Ÿyúüń˝î3Ô¨”FŁixşaââDćso(ŠĚfĆ\gxg`m6 ˇÔŸËBP†)äFߙžƒŽƒögíĄk!‘ÇÇĆ !;˙cgbšá÷‡÷4fž>O:_é8?ĐŽ_äĹŔ皥wZvf87™ř˝X$ć~Áíiőř^÷ĺ#ňL„le^‡ŢןľԒ „eYënëřÄxž –×üK^8őՔN§‹ĹbŠé';˙5>dœüd2óôyÂq\äzdÉz_ęČpޏ´~’ëjŇ?ŠÓé˛(U™_‘ňwMÎ.ĎŢ„ŻĎËmĺČb|Č8őՔ<]ú026"]ąš­\âŇś&) ĎóŽCzMo˘‡âÝĹĚťzş¸­!¤îąşţ~y˝‘ëŽăřŰüšméZĘâ€ÉÓŃ^ćW’œ@5– ěčL v˛—áÖq˛ŁîąşËËâ]1t-dŰkË÷A‰ƒ~•˛¨@ÇsŻĎŤž&‰°Ulćéł(RŚÉ6ůĆnĽsĹĺ"%ńŽH6dyk^·."Ľ5CąíľEŽGxžďxŠĂ¸Ă(O—>°Uěŕđ xWŒ\89s%îcnë.kěf,v3V˙d˝ű„[NfßgÝŒ‰˘8ţŃxíľň"ŽCŽŽ?vĺ{ë ‘R)A5– ěčL v˛—áśě/ô9‡ƒ~•˛¨@NşROăőyí왧ϢH&3î0Jż”g1W\.RB›Rv)­BˆÜœËóźزĚm埯y×mE…p'ŸÂĄk!Žăäd‘Čâ‚ĆFŠY)t-Ämĺxž4”DDJĽŐX&°Ł3ÚÉ^†GŘ2żßÂßćĎ9čM4MÓőOÖË]A$“ŸLwúô-šD"ÍGšišfŤŘć#Íňw°˘H“ţIśŠ•Z0R–Vž¸laĘDW šŚŐŰaDQ´î˛fž>‹"e˜LęűW÷h]k{k˙_ú1›ú\1}¤ÄßćG>ŃétŢ×VĐ\–˜UžŽ×ęÝ_Őç*6VFo˘ë­ë˙Kż˜#ˆ”ÖŒbÓ/€Ň‡ËŸ_śîś˛U,ˇ•“ĎŮtK‰â’vTE˛‘F¤f%ű>{vçĹzHŠ” Ëvt&P;ŮËđS˙…žbŰkë}ł—żÍóˇůŢ7{Ů*Vž7˝¸,÷™újJˇ]726"/Ëq\˙_úyžD"ööćç›ĺ<ĺ4#Œp[9éŮ1ƒHIĽ0ĺ#‘›§7Ńň# …”DQďŠ#Œ´śˇÚöÚŘ*śîąşÄÂŐçŚ hڸèˆç3—§ëľz÷×e;ÇŞ„…ƒĂƒRăCNʉHiÍ,)ÉFĆF‹gŠ´))2Šýqmëo[u:݊Nůu‘R)A5– ěčL v˛—áŚţ =!¤ŤgIĎőŽ?vÉ}´l{m‰÷a#c#őOÖ§\ ›OţŞî˙Kżń!cb’e#%•”,Ž:.R )‡÷ݲéĹĽAˆBÉÔÜ›ŸoNwh%ĎM<ŹRžŽ×Ĺ9|E2DJkfŮHɞϺďŠ#c#ňł…,ËNŰŘÝÇÜÖÝ Ď)YwYŸSRŹnđ˝ABHÖż Źˆ”J ŞąL`Ggľ“˝aéĄ'K;ľ‹˘‰D䘇­boăxžgYVţě>áÖétdƒňÎXúĐőÇ.Ű^›˘[ü˛‘’JaĘGW ÇĄeFh°°'&X6}vEĘúzÇßćU†aPĚ]_‘Rq_‘rEˆ”ÖƲ‘R˙@żnťŽl ľԎ´Đłăd˝‰–Óđü÷•7юCŽtŸEQ|oPˇ˝Ä”DDJĽŐX&°Ł3ÚÉ^–GŘŇ_čŐ」 Ĺę‡ÖÝÖËË ßĐw•ß÷lŤ{RŻNľóIoב,Žˎú­zW:Jxn#Ľćç›÷mĄĐb÷!őšâz‹”ŠsřŠ”+B¤T’Źť­‰c…—*DJĽŐX&°Ł3ÚÉ^ÖGXâ/ôdš6Ľä›é…Y,+ D+ …BŠ€§˙/ýşíşÄî"˘(’ DŃʉDD›’˜í÷wľÔĆb1ńŽxůóËś_-<ô2ůɤń!cćéł.RćɌG>áyžçyŠxňřĹęsĹő)çđÉ)•$é4/t)Ö"ĽR‚j,Řљř˙R´Y@NšŽşČü’)3ßÎpUœüďŔť‰sţ:`yĘ"}śÔ[Ć.ŒĽĚvnnŽŚiůßžˇű šžmňžîÝů;ýŸúĺ‰Ć/}v)1™bA•€:çagďŮŢsůa UAí´î$„ŒOŒB†/ [Ÿśfž>ß&ý“FŁń`óÁŠ{**ď­ôźŕq=ďňźŕÉdnĄPEQT 4„Ż…[_l%„  ›Ě&óăćh4šÉÜtĹ (ŞňŢĘö—ŰŰÚŰ\G]kš9°ŽPŐů‡Îţwú ]ČVĄCľu,Ă:$Ëý~oŰkëíK=ÜÜTpŠŰĘ ž7(-;>1nÝe•fŮ~es<çˆĹbümŢűš7ą9"ąH“ţIŽăß[čVúóňç—Ĺťb$é8ŮáxΑ¸ JaĘGÎĎ ÝvÝĺŔĺÜćYzҝM9ž^ÓđŠĚótMÎ.O|;ŔŠdqŔäéhÇ˝ÍęĄËvt&P;ŮËđ›ôO:žsp[9˛aá,‰ƒ ‘ď_aIJlĘWM}5eÝe•^pT÷XÝČ Ł„ÇnĆlż˛Ń4ͲŹă9›O)‰ß‡[ň vŢןŇĂĘÜVŽľ˝Uń€“zaĘŽ‘|6ĺ闝âž"qťŠ0RX‘ľ923˛qqJ86›şŘŠĎ%K†*]ďr~ěáx†â”#3'ßË ^¸¤Ź;évΗLŕ9%("9€çôŸO›~j˝0*‚ ţOýśF÷1w&s œá‡ěĄMŠTĄ "“)‹ýâżäď{Ťoěoc3334Mltr:ÎLć’B´)Irxâx†â„6Ľ˘…6Ľƒ6ĽŐŔáž=aĽ _k,óF¤’Ů/nrNśÇ3'DJE ‘R‰A¤´ŠŢl °VVÔ׎ÜFÖĆ @!R€BEmJé”ĚöŹGŃ XČwĎÉJ›4gĄKQ\P'‡6%€"‚  H MŠđ|Żű ľj#ĽŃhžn˜¸8Q¨’dтĄ˛Hvł€”÷˝2ÚR H R*°ÎW:ÎôŸëy1đy€f蝖….Xb$)Üœ'ł™aĆň”%x5˜˜L¸#8;5Mâ"ŃhÔŐěbFłEăjv ‚.˝éÓč…QĹڃWƒZ­–Ěçq—UnńRYm,ŔzHŠŔ|ö 2Md#Ń߯zo¨ăĽŽB ŠČ~ç~óŁćX$ťkÚŰô3ËĎÂ_‡ĺš]mOŰâ7㉷Ú&“Éü¨9‹ż Îţ{ÖóOşôîcîžS=Š5öüšÇuÄE6ćyĂ2PńR9l#Ŕz%BśrR‡d節‚żÍ;žsЛhšŚëŸŹŸúj*1Áä'“ĆF˛p[šŢžŢ gEŽGěěǑ Äřqđ˝Ayuâ]ąľ˝UšĽŰŽóžćM\pꍊú'ëišŚ7юçüm^eó3™ľěDĄÎ‹Äj‘?tőt%Śéúc—ý€]žëő-ŮAÉřŰ<ÇqiÓßš­\bÇb1–ec7cŮoFśÔĎŚť^%oNţŽÉŮĺ™Ço(QksdfxÜć<粢^¨ŢuGeWâ|Yj'{99Œ;Œ˝oöŚ›KąíľőžŮËßćůŰ|lş’ć^\fŤŘÁáAńŽ8őՔnťndldŮY‘ëŽăşzşb7câ]qň“IënŤź:ÇsŽŽ“‘HDź+^ţü˛nťN.^čZˆ­b cŰkSŮüLfŠo`ĄęŞAREJ‘H$1M$IŒ|sEQäyŢ}­Óé‡kQIßq˛ĂńœCţˇë]ö}ömĐʔůő:ßXŮĺYÎű˛€HŠ” R*1ˆ”Vľ“˝œaS_MétşşGëZŰ[ű˙ŇŻˆj“‚mŻ-ąÍgdl¤ţÉúegIąPş-RĚŸ7>d”>Ű÷ٓ łúHIe Ľ¨"%e˘ť"ِ~Ž(:9Źť­——yž_HŻ’[R#’N§›ôOŽn;˛Tć×kDJ°Ž!R*%ˆ”J "ĽŐŔ ŕł'?CżÚ:œ'Ł˙=zé‹KÓ˙˜ž¸8Qű@íĐ{CZ­VZE$‘>K˘Ń¨ÉdŠFŁ„ÍM0Ôn[˜+Buuu<WŸĽŐjŸäYŠ-RŹN„ĘĘJiHÍM𫠢0ŐŐŐé6Ÿ˘Ň]ň,ő ,•’ŻÍz3ʟ”ĺÔh4Ąk!͍ôo8ŽŠŠQdŤŕ<ěÔoŐˇýŽmôÂhűËí/ůŮžeH'TŮ^‘rv=I•syę,XK'šžmšů×LÉoéČâ€ÉÇ1–żó¨Ź¨Wc9\JLş]†ó%8Üł——#lž¸ÜŽéé鉿M”÷<Ą*(q^$„P)ň2ƒ…{bŐY"/Ś|^?幔|űž¤0?XœŤ\Qf‘’ĘJQEJ]=]žă‹C2tżÚ}ĺ˙]xg ]9†‰ÝŒ1›éßśßľě8ŠžG‚ÓÁ–ŃëQ‹Őâ<ŕlzś)?ۡ DJŇDJkĆôˆŠőĹÖĆ=d͡ˇôŞ‘R)A¤Tb)­Ćž+2I÷Éî‹_”'(ZW˘ßFš*Nú̲l,Ś|ň~ŮY\ý6›śŠM.Œü9EŞŘč+ŠŢˆ˛Ul&„KŸ]ę;Ű'Ü„;Bߙž“]';Ű;UŇ[wY[ţł% wßëžéŤÓËŽÂPk¨ýqmŰďŰŽüýJӾ„Ikoú˙M7în”>çűFAń9ܗ” j)f3czÄä{ݡěRŠ)ÂÁPkH~=ƒ"ssYúĽL%+Č!DJć:ęR\gžI Ţ]rMřë€ĺ)‹ôŮRoť0–2[•YÖ_Xţ:r–:ëSÖ䨧ďűk_ňôžżöYŸ˛.f’~Ňß×ď˙_ő}Օ÷Vœ˜œ˜Ô߯WIß{Św6>[]]]}_uŕďţwú3Y‹ű¸űäNşĹŕŕkcnn<Ź^â…ąHŹűŐîw\G]+ĘÄ÷–/üŻđŔůߪ‰™ť_p{Z=ËFb3Š^‚Œä¤ !ƇŒ#Œđ<Ďóüä'“ƇŒ]ě’çÚöÚzűR 7œâśrƒď JˎOŒ[wY—šáś.Ž}wůóËś_ŮäŐĽ,ĄôaaěťžLÇž …BÇľśˇ†Ž…Äť˘xW ] IC‡BĄL6°PĘńź¸+Ň4šŽo-•ů)×äěň,ö}qWtsłU,˲ň¨0<Ď;9čM4˝‰vrČ/` „x}^nëÂ{¤ań߃ňöň"ßżnˆeٔŻšújĘşË*˝Œ¨îąş‘F2™ …ěűěl›â}JŠ6Sţ|9pYzŸ˲˞OIĹH$Ň|¤Yˇ]G6éMÍGšŞ^v ˘ÜŽąXL1VxA”ůő‘ŇŠ´ţśľţÉúČőH,k~žYšč>ćśî˛ĆnĆb7cőOÖťO¸ĽéŇ/2‘ëžç;^ęoFˇQţě>ćśî^ČĺۚI¤dßg—GŹ} v|bœçyţ6ßü|ł<ć~şĹWZ梅H)Q$aYVNŔßć‡,ËŚ;œ‡Ľ×uXwY'?Y2úhŠüF@MW€UB¤Tb)­j'{kp„•üá[œXœĽĘBMÓÖÝÖäŰÖž$eUó ˆ”V„ŰĘ%7>sÜâÄĐľPâ›ÇäÛçů”ăě˟˝C×B™DJÉŻ)“×ĹVąŠô)Vˇ’2-DJţ6?ůÉdÝcuňoO„űűČ#‰o™W,U˙óúń‰qQG>‘{y¤L)˘M V‘Ňj`“ě­Á˜!%?ÂLqn`q–Şäaě;éCÎk $ÇžŁ(JźŤĂsI™‡ ]ş-)ÇŢL= çŇá=—Í„âżä÷źŕšň啹š9iĘ Ď ĚEŤlÇžK9 Bíľ—?ż,AJQ”×çu5ťKÉ% ^ îvŕĘÂëôzýÄĄ^ŻON)Ü&>žh9Úâ9摟ƒZűj,ţŁ0öÝj`DXg¸­\ř›°r"Džż^˜ţ&œÝ(šDž˙,ÎŘ@¤7ËB¤wÓĽÔřLŁű¨[ęŒ'őO^~uŤ.3VâĎĎ҃Ád9ů‡“rŰ›Ęâ=ęq=żG99ť˙ԝ˜@űŽňŢĘö—ŰŰÚŰV:\d ‘RQ+ů(żh7‚5Wč}ë‰ó€ÓŮěŒŢˆ wů…cMűšZގÄoĹăˇâ-G[šd3ä}Óž&ĎqĎB&Ç[äéƇŒ=]=‚ DŁŃƒ˙÷`şĹçţ=GÓ4C3ápxżsż<eŮŕt0ĺęV_f( ĂXę-ƒç‡uM|{¸BüV|ěocÎNyŠëëÜťç„;‚š: rw÷œęÉuIaxb’Ą 5{hľČœMč}ëZŮöž+IeŐű.qsÖlÓÖ¸Ńűn56,ŸĘ~^ČD&ëz߀Rž;„TčcŠ EQ/wj4ÍÍĐűCňçŃ Ł‰i(ŠŇjľňDi)f3#-Ľ’284Ô†ńźŕ‘։FŁ–z ľ‘Ň߯÷_ňKÎ čď×S)í6mߙ>E!ĺĚĽ)ÉkO™'!$k4ůíjń[‹˙ŚÜŽîSÝÚmZyŇôp8lzÄDm¤L˜äÁcĽ’?ŤläWĄ/­ëXĄw@ *ôi]0ůŤrŽU(fy:ÚËüJ’ę՘aőB:^ęŕy~pxŚéÖöVéłN§S¤œüdRž¸¸Ô{ˤʞ^Ęłľ˝U.’íWśţżô‹wőąÝö…”ô&zň“IńŽšq<çPٜ”kO™§ÄńœŁăd‡ôšăd‡ăВĚŰŐ|¤Yz'uâJ러oým+Ďó­żmľî˛Ś,R&[ĄNeWâ|Yj'{yťW(_…>­ &5PÎľ Ĺ,O=ňÚ IDATG{†çQŮ^p2Ůpőj̰Ţ!<ϧü,}Š} VąŽĚSŇ4ÍßćEQŒĹb‰“żPÜÇÜƇŒÍGšG>Qߜ”kO™§ärŕ2ˇ•ďŠâ]‘ă¸ŠŻŚÔśë6ŸźRšŚcą˜´4M§,R&[ĄNeW–퉐š’z,oĄ?@ΕíŠŘFtȡBčřÝ]†§ĆŠŞ(eš w\ş‘äϚ-šţłý ť„9Ąâž ibć)†‰D"R‡ˇĘĘJyb(ŇjľŠÂ„Ăáą cç´UÚÄN}™”3]žsŮ}Ü=7?ç{Ăç˙ԟÉv)2—ˇ˘şşZ„Äš‚ TTTČ ŞlEćűB1]úP†'BćđœRöÖ&–(+…>­ d%>ŽŻšš9 Ťć„öߡg‘˛îŃşž?őyŇó§ĹáÔ­ťŹžßxâńxôF´ÉŢ$MtvB\G\ÝŻvýϘ"sšŚŐß.2O™4žťďĎ>÷q÷Jˇ‹R÷ŘâVX~n‘&r[šĄóC‚ ôt-nšúV@ţ R€RVđ¨ h°fź=ކ_6TVW˛,›EJďiďđůać&>—rî=Ó;wgŽşşÚü„ŮşŰ*M4ď0›Ÿ0S? šžmę§_‘šű˜Ű`0¨TBĘŰ^›FŁ‘Ó<|Đü¸Yźťx€Ľ\éÁ˙{pŕě€Č‹Ŕ˙™2fƒbƒž•…'ßĘçüšœ]úëy_b›S„˛¨á|ě”üG)וõȹ%X{ęŐ¸Ł(*‹I-6ŐŐՂ HůŰ<ł™‘ŇŒ~8zâř‰éL'UĽ†™››“WĄŘ†a"‘ˆ´ĆĘĘĘt‹Ž~Ů E !Úű´ă4$ŽBĘ$1Űä•zŽ{&.NÔŐŐYamxş!‡ő–Nş]ś–çËú…6%(.kß„F'€â'‡I„ýĎîďzľKź+ňˇů D"â÷˛[Äd4éˇę‡ţkhŕü€~ťŢđ !‹•vŸę2<`8ůęÉĆ=– ‘@!áG}…ž?őyŇ󧞺ÇęR&˜››Ó°aNh˙}{&ZwY=żńÄăńčh“]ŮűŽîą:yę‹¸ť{Nőřţěsw+2ąüÜŇÓŐCć—YŠó°“â:âę~ľ{ěĆ2)<"%Č/Š˘|§}ÚmZj#e2š‚WƒňŹśŰ4[4 Ă4>Ó(ÜYčcCžV›˘×ëƒÓ éސ>Żőz=!Dça'ł™a63ÎĂNů%ůáoIŕ‹€VŤő˝îS/qÉ‹‡Ăᆧ˜Í ľ‘˛áŽŕt8™Í Ă0–§,‰6EQÂÁyŘŠŃhÂh4ęjv1 ŁŮ˘q5ť¤~edšVM˙§~Ó#Ś…#ęlYŒ0÷ď9ćfřýážÓЎ×ŰămřeCeu%˲™dŘ{ŚwîÎ\uuľů łuˇU1ˇďtßđűĂĚ=K:ËĽ\¤ńWáoÂá…“›ƒź§˝'¨,^IRć`Ţa6?aŚ~@5=ŰÔ˙N&…‡B ĐňwMÎ.Ďܖ„bŰk‹\đ<ßńR‡q‡QšŢńRGý“ő‘ëţ6ďxÎŃ|¤9yíÍGš˝>Ż(Š‘ëzÍóź(Š^ŸWJě>ćśî˛ĆnĆb7cőOÖťO¸ĺěű챛ąÄ G>aŤŘ‘F–Ý^ĹâľԎOŒó<Ďß曟ośďłŤo[ĹŠwĹČőˆăCN,ŐşË*U%óÄ2¨ÔUĘ2´ţśUJ‹ĹšŸoEqüŁńÚjĺmtrtýąkŮ}—Ą,˜<íkvo#Ő|ümžżÍ÷žŮËVąĄk!yŽý€}äƒéů~Çqýéçy>‰ŘŘĽ]#&ÔFň‡ËËň5őՔnťnd,Ĺ1œŰMSŠFÜ:Ž;*ťąŔ˛P;e ?‰’”bą…;~žçɆ…Ěš­ÜTpJúťcŤŘ䵏|0bŰkEąăd[Ĺö˙Ľ_EŰ^›đp'ߛ†Ž…8Ž“sP<ŕ}ÍËqÜĺŔĺt%Tü›¸x"žç˙nťźŻy#חä@YRԭܲ™'–AĽŽŇ•A^Ě¸ĂŘ?Đ/@ ;s˘<#ĽŽž%Ąfםě])ÂWÁßćŘtl{mŢ×łŠ˛~ŐĹWƒHŠÄ RZ Ô@YC¤T$J>RJůoňËϓÓóˇy)¨¨ýqíČ#uŐ‰˘(ßĺ/ÉůŽ(Ç Ékäśr­í­+-ĄdŇ?Y÷X]âđÁęK]ţü˛uˇ•­bš­Üŕđ`ŠÄ EÍ4ó ęJTÜg/mÍEq䃊YɾϞxó˝zĺ))ÂéH$’.V—đ<ď>áÖét‰{SNŸî[Ĺ&FÝ<Ďł,›ë­Y‘R‰A¤´xN ƒă8ĹÝdrf3Sť˝včüť‰mxşaîßsŁFkˇ×2 #ĺ ż˜2üM˜ŤâŇ­Ë˙‰ŕŻŇ;+ŐřLŁű¨[ę—É@[ŚGLŁFăˇâ˝gz[šßô˛¤¨ˇ˘Ě3ŠŤ%éˇráoЉ O7 ¤íĹ6˙%żëˆkŮ uZ­vÉżUڙogŇÍ%„´ügËôôôĐđ›EQź›Ń(łłłŐ÷USߍ¨¨˜]}á ˆ” 0\G\Ăá0™'ÁŤÁĆgžfYVŁbý…ľĺxKӁ&Bˆý€ý`óAë/žnÚ×Ôrź%~+żo9ş&%˝^ď˙Äď{Ă×ýjŠ`IąF…šĎŃ4ÍĐL8ŢďÜżěv5ٛÂ_‡Ľ1ćž[|@|IQ÷5­(ótu•Žó€ÓŮěŒŢˆ wĎq<˝ăw'˙p˛­˝l\v;`ňđ ˙~U‰Ő !Ăç‡űĎö›Œ&)Î˙KʌIJŹÜÁ2Ă8r&Ż-VPäpA(ůŰŮĺ™Ű’ô}Ű:Nvp[9˛Ôţ¸vđ˝Ay"˝‰–“]\&ˆÔę‰D!S_-<ąĂóźă9˝‰Ś7юCůÁ›tkŒD"şíşŽ—:%TŹQąřČ#R)NçőyÓ%“˙íč×mב ¤öÚńĆĺš]ěbŤXšŚĎ-5ĂĚÓŐUÚş˝+6?ß̲,˲‰Ó ž7¨ŰŽKJY0y:Ú×ěRF–{N)yšŚZ“DQĹÖöÖäݝüÁś×&=žˇfÔŤßëŽĘŽÄW˙˛đÚň•z¨ç՞+ż2÷Ý˲ľŰkFŁď´oů%WNer5;hő9ŔÚČßťŇÓ˝=KŠ"ŠŇ†§ěűěÉď“YĽ,ś.’żó(ĺşl{mÖ]Vű^;!äÜťç<­ž€? ż_OŇl]ăžFVĂv÷tÓčłoŸ¸81ü_ĂR29}ň‡ŕtpçěôžňJĂL_úěRĎŤ=ŁŽćuÓ¤)ŤąHŽdČ\ş]ś–çËú…Ă}ŢŘ˙RtČS"R(ˆ”J^1Tiߙžž?ő¨ô3ĚZyFJümžĺ?[†ßž››Ť{ŹÎ{ĘkxĐ ĎM.CüVüŕáƒc˙=FÓ´mÍűšˇâžŠe#%BHđjđÄ '&ţw‚|GŒ;Œ­/´6<ݐ×M“> R* ˆ”V‡ű j Ó˙˜öžću<ç`h&üMxââ„ď-_ŕ‹@>V‡H  | R*yŻRŠ˘t:ÝĐ{CŚGLůČźÜ"Ľ†HŠÄ RZ Œč°Ó˙œ&„Ř÷Ů™Í ŮHô÷띇r˜dzÄDQ”âĺŮç(Š2MäűŔ’Ţ´­ŃhŸi ‡ĂCď?eéť%Cç‡Ěuf†a†iřEƒâˇŔ荨ÓáÔjľÔFJŤŐ6=Ű˝ąäSY<wuéď×3 Cm¤ô÷ë]Í.•/ńuő°JżE1ç#L(Uřa`LFӕż_Ńm×5ím˛fr? ŹL<ď{ŤŻçĎ=3˙ZxťMÓŁŒZž˛BÚ~×v˛ădó‘fi4źîWťOüć„㐣ďLů>vŸújJzâS¸#TÜS‘8…Ěę‹-9 éƒS†Ú…'DƒÓÁ~ÄqœžiľÚ™™•‰íBúűőßüózmüąQťM[ˇŁŽi_“ÔôĺLá‚P(ĹÖŚohS*ZhS*1hSZ îŮáě[g'ţwběĂąšĎéśë¤7ŻGŁŃęűŞišŽÝŒ1 #q9pY~N‰,=Ő§,|ž+.žP Ľ6q^$„P)ňj‚„ÜüŸú>8ýéĹÍŘ@zßěu:œyŠ#X') DJPn)-DJ%‘Ňjŕp_•čhő}ŐrdBi˛7{÷\o_ŻńAăĂ?}Řř1peṼě"Ľ\ľ)Éžţçt4řxâě[gĺ”Pś) DJPn)-DJ%‘Ňjŕ9Ľ0Ó(ܤ‰ŁŽj ÔFJťMŰwŚOe"ŔC¤J/^ C‘ë‘™čŒ§Ő#Ożňĺ•` (őBlomŸš1 E"ĄH8–“ľýž-p5 CĄPř›°4ąóĺN˙ţ` ťc7ąžß,$Ţ˙ěţŽW:D^ řţ/ý*!¨Ľ ]€bA­‹Ço Hžw\ľúŇRşŇ߯'„„ż›-ć荨4=‰hľZ)™VŤőâ_Lö„9B´Ű´ţ‰…é2í6ířGă†Z!$~+^c¨‰ßŠKÓŰN´ŮöŘ´Ű´‰‰“'Bţ(˘Łuqœ—¤őuŠ(N8rŐX&°Ł3Hiëë0ĘI¤´¸ě<Ą*(q^TNWOvW$—ćš‘"ß-™"-ř"Đţrť˙3?MÓŢ×˝{ÓM„üA¤T$Ö׼ 8á<Ę Tc™ŔŽÎz߁Rřë…^sáoÂÇĽLĂqܒdU ɸ­œÜé.1q$HÓM˜F/ŒĆoĹ{Ďôś4ˇ¨LXcˆ”@ŠĺxKüV<~+Ţr´Ľi_SĘ4Műš–$;°ĚyŔélvFoD…;‚çřÂóHŽ#ރŽƒáp˜Ě“ŕŐ`ă3 ÍDMöŚđ×ai4ˆšďćT&Ź1DJ T˙x}ĄŚúžjNËuźÔ‘2MÇÉn W]S]]SÍm[LÖůRgmm­á'†ęűŞš­ Mm/śŐ=^g~ÂLUPżś˙Úž×.MˇîśZŹŞ‚:qüÄĐš!•‰?âR….@ąŔsJËX_8süœŹ•őuŠ(N8rŐX&°Ł36%%DJJˆ”` ´ŔB6şPHxŸ@Jˆ”2Ľ¸Ą€†ŢwJˆ””Đűnxl  !R(kř- %ôžPB¤ „H @ ‘€Ft(wEá™ţrŚxĽ2 ڔĘݲwÊ;i€r€6%€˛†F$€”ĐŚTîä&#Š˘|§}ÚmZj#e2š‚Wƒň\Š˘[–Ú^lÓlŃ0 ÓřLŁpGď>Ő­ÝŚMŮEQT÷ŤÝŇRN‡“Ě“”K ‚ŕ<ěd63ĚfĆyx1™'žă͍FŁé>Ő­^’ŃG ľj#ĽÝŚí;Ó§2 DJ°hâ㉀?Ŕßćm{lűűÉ÷ ˘(Ę-/wúżđÁŘÍť‰őüĆ#/~ĺË+Á@0]ĹŋCÁPäzd&:ăiM˝T{kű̍™H( EÂᰜŹí÷mŤ`  …Â߄ŐK˛˙ŮýŻtˆźđü_úU&¤ƒ§ů˝<˘EQąXLŁŃBA¨¸§BœIҐÚmÚńĆ ľBHüVźĆPż—’E"­V›n-Ąk!ýýzBHřë°ŮbŽŢˆ&/ĽŐjýŸř“=aŽFŁŇJý ӗ-‰v›śíD›mMťM›˜8y"@ńcqMČÎŁœ@5– ěčL R*w‰‘RâÁvúFŠ|ˇ$‡t‹§;O¨ *eŚ–ěŽH6.-yš’ž´żÜî˙ĚOÓ´÷uoăžĆtŠžąVçQN Ëvt&Đű.7OňŹťü3Çq\$¤L–<7üőBŻšđ7aŽăŇež$YŐB2n+'wş[ś$ŚGLŁFăˇâ˝gz[š[T&¤ƒH)Ö,†)H°Ä˛lp:(˙ë:â:č8‡É< ^ 6>“iăLËń–ř­xüVźĺhKÓžŚ”išö5-Iv`!™ó€ÓŮěŒŢˆ wĎqzIšěMáŻĂŇhsßÍŠLH‘ŇŞŹ}SĎÚŻŃ}ÂýđO–WÚöb[Ýăuć'ĚTőkűŻí{íćS˙x}ĄŚúžjNËuźÔ‘2MÇÉn W]S]]SÍm[LÖůRgmm­á'†ęűŞš­œzIŹť­Ť…Ş N?1tnHe"@:xN)K)ÕüUćŻ.çĎ#€B‘tŻ( řĆY \ŽĘ ÎxóěŠĎD* Žo€œC¤´Ĺ#%Bźsč•‘ c¤5î}ˇ–(+ˆ”–WœMIé`‡Ź"ĽŒźI§ŕ(+xN)#RR̍Kˆ‘r‘Ň gź„ çđćŮEąH‚“â)IÎĺ$-ś˜Ö<§´*Š{ń5{N {-%źßr˝ďVeíűă!Xč}—k˝ŹvEóÄsܣ٢Ńh4ݧşĽi‚ 8;™Í ł™qv’ů…´EůNűôz=ľ‘2ÔüŸúŢĐ߯§6R&Ł)x5¸Ňd‰‘˙•×nÓŚMŸŞĚáp¸áéf3Cm¤,OY˘Ń¨źEQ‰™g˛Ékř˙Űšc×(ώăwĐBźA"´p9TPč‡RJ‰›NU(ÔčŇ…2äŽ]TŠÄNĹ 8çtéVĹẔ8ě ä„DîŔ–{CŽCbÔ_b4Ä8ä>Ÿ)÷đÜűsúLsşŮyÔéuzŁŁŁ­fŤň,#7üGmvĆMW``yŽc€ŒiĎľ}tčĽÁ‘‘öíŐÁâ^qňӓkˇh:Îž}ű*•JY–ľZíĽ—{ký§ý-M{ń“śö2ßžnţ†{~QY–ƒîăî&ŤźéŸ­Ji€TŤŐţýĘűë×>O+ŐZu󶉗ۜöÚń ÷ÜţŁÝúŽuçĎ;ËËË+#[XĺĎŔ óíťRß__űŰóÁz˝¸ˇ:XÜ/ęÔwdí÷*eYŽüŮívßü}îůÜçšSÍÎŁNżßď=é˝ţ"ďćŒě"Ji€L\œ˜řfbéÁRůOٚ^}VgüËńÉéÉîăn÷qwrjrüâřN,}ô“Ł7~źQ–ĺŇŇŇĽŻ/msĎË˙. íÚS҉ç ßý{ƒ_ex7g`7QJäúľëŁŁŁG>>Ň8بď_˝Ż2óĂLýĂzăpŁq¸Q?PŸš6łKßüéćě/łľ˝ľc'Ž}6śÍ=ßúůÖäÔdľV{ńjÍo›ÇO_˙ŁíďćŒě&ĚHî)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)b埓ŃIDAT$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJI)$Ľ”@RJé)ĐN/q*ŢIENDŽB`‚speech-dispatcher-0.9.1/doc/figures/architecture-future.pdf0000644000175000017500000003025711447133617020751 00000000000000%PDF-1.3 %Ç쏢 8 0 obj <> stream xœ˝Z[o[É F­Ë‘OGÎMQ$mľMł›°;÷9óZ ? >Ź÷)ŠW]Č’>ôď—ä\Ź#*‹fłđ0ÙC~䐎żŹŮ5_3ü/üüx_Š˙ňwłţĺß5_˙˙˙ŤćÂąľÔZŻ…uö~p†?žţłžűs- ˙ŒżbüPż‡3Ă}­XƒsDm#ĽÁíśž3Q›úëĎő—5'Q㏏÷ëżŢÔěš9͍s뛏 9çknÖ7w5°­ŻP)n ~§Á­nîëwż; †Łł?ÝüZ_ÁbŢXŤ .śâÚjXpóŠ~7Ž“áůíçGg‘ńo7ë÷^ƒ„ °Z§×JxE †=ˆt°E<Âô}Í-Ă)$ś‘ŽŰ€†-¨#hpm˜ś šć˘†R¨eŁ3ĂŞ+sK0ŕEĐ‰Ń¸Ş†€ƒG{ÁŠą`t˛y0Ňô}-âđ`"ŠO|=ÁĚ2îş°QHP<žýzűőbżšŐËÜ]lÁÜq46›;ŮÜČ×KCp`.´ƒ]şTö¤ŕ“ép°ß€ÎFź˜°›113Ü×Rą¨" ł =W_vŹ1˘KCÉ ^ ^Žƒ?7 żşăĎџŸŽ[Xü´– ˙ţ {~ŞĽÍF€¤V$°n….."ľĹ F<˘F‘!š0–~Ŕv٦Ęnć"0p­pčm¤­!<$ę˜VŁy–źdƒáÁIxŚ~&-ýëG8€!H>™^¤Dj:ĎAtúřéłęyG…cÍş+}Ž›1ř\ÁňJ+Đ âî VÓpËuXÂÉkŸ‚ÖűߋÇ/ĎĎg-}ێÄ+ K”6”?<˜Ó¤‡´>$hQPçśž;yĺ&~•d¸źÚFź´O˘˛Źw'­ÂŻIĽ [•ôߙӬ[JWčTr˘4§ŽLMo=ěŠBÖť“Vmâáś ˙%k%jë)cXHș¨ĂžĘ„ĽŚ3í7 şŞ†ł ôîŃfZŔRаÂŕź?žĎžżhy˛¸C”[*ŠłÜD%I‰ł§Ü Î#ďĚ_R<[ÚĹęíĺtś+Wđ1Ę%,9OÔÖSœ"şŹ ŽČ °ÎŹ#˜ňrńxô}ÔLA‚Ѝ$¸ Ľ˘ś‘2RDř€3QG ­„pÝéܤ"‘^MóŮŹÚ_ŃHqÔůƒ˛ąS1á!Ť‹+xr1 žl(-zé\Ö wߜŻ!šJŢéÎZQńĄŽKđ!ŠWłýÚ˘áƒ`X0ěŐu?χěcIS! ‡$=‰ĘZ:Ö_KŹe­ěv2ÂĄŽĎ_/&ËUHÌiŘťŽçőââĹó˜dŔů+A9*×?ł9¸ĹôuG!OnA wÜŐžX˗ FĂ RE=/{ƒxa“Ú5ŚťŕŐO$œűŕßýţťőz5úâAÔč\÷CMbü:ŠY'—GŹœĆ”Rⷍtˆ¸#Ä$—×˙ŔvJ!ՐXQsÍXl|hĎ(…e9§ŁĽI ÉbzL|T’œ°Š  ôm”l9;rR՟éBĘť×mĘĐ)™óI‹k*Ą˝M4Ţ_Bŕ ă#š!lÔDkł`çhÇófBôF@•L´;Ëܥ犂A;mÝ&1š#Ä~§L•ŇŢ}ĂÚd.ŹË’šs-sE:˜‹xżÝ\ †îţÓ.#‹ăl­ÖŒÎF•¨'>Bí„U›řľˆľi…¸OŚ]i§WnÚi'ŰɈŇJDyťDÎßŔJÚţOV’œîŁ˘iꌁ†şÍ7ÎKDׅDCAľxé^ň Ť7ůë$ͽ皭ߍ JšďN^šI P–“BśNX¤˝˝<ďˇŰ$9d¸T…€a}rcs‹Ź(ó?m1śÖ$jë)­Tu,Ńsa•ŠEł~ੂܲ‘ńHÍßńŮţ‚?`ŽžĎ}eŻ8{¨p'[Đľ˜ÇBП;’q ľŒĹ r'ꘞ ĎĘĺłťvđ§i+mŮZ “niŻWĂÉtšš?XĚ}5˝§3Ĺz)ŢÉŰRŹTÜŠśâžÎŠ#w_Ĺ9ÎşĂzĂPŠxkOçËé|1ŻFÝěqťŮŠ6i w¨–ƁN:woS‹FkfŞ,Áߕ2Ńš'óŃbŮU˛Sx:Žp'[P¸˜Ç˘Ţ˜˛ÂžÎ #woC˘sö°žŻżJŠčÜĂĺęó7—Ón׌>C˝;Ů>äĆFÖŰ7T˛ŢžÎzS¤ŻŢ–Ô<¤śnPmŽHçUľřărú(źćqp{ĺ/,&÷ĄÓÁj4LŤŐ°ăŢ+mXşŮ‰/ćądâ-XO‹e@2§äÂĚŰDŐ˰.pé*lđ&}…É÷SŮPX<ř¤¤Ĺ¤ÍżŻŚŁ‚(Nóť ›öŞÎ.gƒEÔH4hOŇHçÝVjnŢôŒĹíÄ­ďů͆ƒńŕŐ|v )ŕuń°ěg 1"ͅú&8ƒŃ‰§ŸÖÚű@*Qš˙l°ź‰X1%ĽÔ>.DťNŞ]ĂR#äm1ű(°Gxß*,WôWą˙náŢO@ƒ ĺóęí|¸pű>„󄏁ä<\Ýv§ ÖzŘB–8,˜°?eŐ&ž~ďy9 .Ú$S-9ďN^š 鱗Á¸@˘ŕeÁ—.­ˇŔ.ŽŕnÖWÚř2çň;á6QÖzÔuŹî°˘=œň .EŒ;1¨ä—çźŇ‡xŢďýăëîC~ÄŚ÷Ź‹ŮŤůӗƒ Œ€ęɑٴĚv§é ‹pŽZ 4ő śÄ†ÇD:ů˛ořý”řŮx<  Ć0eˆjţWpb–ŹÎäÓZIăSŒkw[}›S<‘ĘaćěMSŚłĺlôĹ}۔ÇŃxëǚó¨~ąsP€ŘÎ^łƒíĽ×ţGLSoŞŸ™`žpť’…^ˇďćP¸-†“jú@fă; xĂ÷ă­[âĚaxô7h×ý ć÷!qGG{rš_. qŢ×˙͏•öendstream endobj 9 0 obj 2490 endobj 7 0 obj <> /Contents 8 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /Rotate 90>> endobj 1 0 obj <> endobj 6 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> endobj 5 0 obj <>stream xœkhŮDŔ€ endstream endobj 4 0 obj <>stream xœc`Ů endstream endobj 18 0 obj <>stream xœUQ{L[U?ˇĺ^nŠJÓš2mo˘ yčY˘֚q0J„eĄ]Kév[şś0RŤcpJĄĐ"t@/ďŔ%Fd 覛cÁhĆCÁŒéˇ¸dÉţ9g^Lź1Ćď$_žóýžÇůý"D€ ˆCĹyď –o2ëŞě…ZKnRÁXőCË&YLIÉÉáŞX|Ŕ/ŠđKbčxb{b&a”FE ţéŠFĎŁŢgQÇs@L5žĄěJk­ÍdŹp0qEĹń ‰˙eR222]íż“c°›Œće!¨6°•VłÁâČd˛…j–5dŒl­ľÂÎhőzƒ>܌Ѳ†ÓŒĘĚŹÖĘj&.;žIMNNI\ę?ďgv&— S`ľ6&LĂtň RD‘¤(Ż€c h@ E@°p‡¨!n‰ö‹nĄ) žęŘ@ęU”źAl‡ĐZHŒo"§ĚÓď›ďœ…ăň?Ţü…ݧëÔ)Žç–ó|  űź|Ć4Ww˘(řx} :2Ş4F5¤œXŘáÜţŽ€r`U6öűúňHŻ\)}§ŠÍŐZ§” ]ČáŹPE0ZĘ!5ćdźx#ˇŠh””^C’•%$jŘ9ŕl?çn„Gá‰3y9´”ëß"%A-oĄú-uŁzD iţľˆęIŹ _öę)ţľżĚäJ‚/86pâFôŇ}6„4Ąźť/H×p–Č:9ˇöҡŐóŻćäWëu c…˝‡ů3–ÇÖőšÓ́O|´ô~Wł÷ăćX[ÇÖ9mŐeÎ2HŤôă‹^ˇĎíWŚRçm °ŽÎź]Šh˙pí[:u)mHńö )]+ěłÇb`đÓсţ‘áI˙¤˜vč]ĐŐvNPaĘąŠ"H!•šBąd:ĹňądUŻ&W¨#{TkS[#l’—|fţ.8ĺéčS\\c]煥ňŞúž‹w§ŰŤÜÄbň.ţÄŐŸd-Ăg÷#1ć„qšü")ĺxŕČyďđÁ˘ŠÉŻťÝžvżň7)€oěĹ=]ŕ”ż˙­nwóúČ÷7Ҳ†ňé0œň+ńcmŢă…odÍ­-°Ňg|Áčq{”ËčšwBč—˙ŹşrˆWţ×(ś)ßDW__ßĐĐlŕKHßüĘZŢŇ&|ĄśYWӘĺ’ó1 ÚŚśř”YŇ™×JďÍĚvő^V\ę řż¸Lť"["uśůôŽ*ÚÝ^áĐ<@*™3/M“é‚Ó#łÓƒÓ“ʑŔd÷B׃Ţn÷\€–8†1DyÁÜajó™ĐžÍΨ(ţ4YÄú endstream endobj 19 0 obj 996 endobj 20 0 obj <>stream xœ]V TSW~ä˝Đ‹ŠIÄąŽ¨œ B\q@<"k4$”Mb­ŇZĺ↠a n8b´"›ŕăĆŇZĹq™ą=c­3XĘP˙—Ţ8gn ś§“s^ÎÍ}÷˙Ţ˙ß÷˙/4%śŁhšVÄE“Ďä(mƆÜěčDýRżƒ.Ů/FŻő °P rZxĎN/BŘ`šk12ČQ„Ĺ'ßł_ë÷Ľ` Ec(Mç—-4dł´ié9*ą>“'OůmgZ`` jƒńÝUhJś6MŻR“E^ŠÎ™‘˘Ď™§ZHNëtÚ$UšÎ˜™ž­JLNNIś…­NÔĽlRi´:mfŚ!Oĺ˝ĐGőA@Ŕ4?ňőÁHö*’~śjŠĘVŔďv(Š7Ú́ć]ĆJěŘ1ŽŒh”=çě$•šŠÝ=ĆQ”'G…RţÔDj9F­ 4”5ŠŚÂŠUTC-ŚfP3)_*–ФB¨(j!%§ä„>JLQŸRhzÝmço‡ěDŠś‹ŽŠç‹˙ʸ2˘\ćëÄŞŮ%l2ű3—Ŕ5sß@­ł%U‚ H…-ě‚I|žÄ€?‹÷Y2<—Ĺeo3đc›lo)W˛Żŕă,´aĂ e ‰Rf‹­ăń(a<ƒýYH°v0ĹÜNnMJr\AQÉ>ŁÂ“ŤÜYV\ęĐĽŇă‡ţR^Q]}˛,2w“ ź†>*‘p ^đ…ŕ>ýoXŽ$xŚßźk^N„ŕöâ đG”xk 3dĆ Ičú;C­‡š*Î*ËĎԖףčdfy¨ÄŮň5Ş´„šč{ŕ+řƒŻtÂ]ÜŹwđeî2ÖťŕkÉŔykíĂîBƒsŢfť66@ +ČR—§ŕ U0;Ăűn˛Ą§Žđ„ý;ş^~Ů|Ů|꺉žJžŘôՕS—Đ-Ԓնáüzóšň ’÷#|ą”‡ŮŹLč1ëcV§ę5J<›ĹR1,beC÷/lŒŒJ٢ċXgŢ1P*(%,@ťp…ǁjLă0ŹŔ̅9ƒ@C0,ń~ƒƒ”%˜áűZ4Ôąa >\Ó;8ŘÚűP9 dďW)L{˜ar9MĐ @ĺ&Ű*ř¸‚ŠŹÂelzűښp’"ďƒÇŕŮ!UÁçc•˛ćXó=í=yjŹŠk“`Á‰˙˛QóžOü˘°°řž×?4őöÚŕł đw`Ż7šÜ|‡Ýq6őUo‹ÉN{nY“ĄIŔő_ŕ sć>LkQĘúZÓÂĎ-–/Bńzí2 8FŔă4š°řŚx[Îđ| ŁßĐB%äń%eh*EíE-Ű.¤őĎčŔ4Éyę,Ć8řű ŕNý=?Ő*ą‚ݲ>9k JB›*6ŸŮfÚq|WŤd÷KţŕÓş‹ˇˆßÎn1Žlޟˇ'U2˘Ž Rş({ƒxŁĎ.° B˝'š;nvמFŔ ë^Żč‰ëĐÔ`1y(šďkŕI˜œćú|<ψžĽłe*i"âA|HŮܖGxXƸçŻŔÔsă)Jü`Ř^/&gUÜcsú‚ŕÔôy¤lT)x€’PzŰF§ů6aÓj&\Ös˛ž§/>=z¨xç1xrE%;Đçh ŠNĚ‘ČĚ?qDŹ˙çŃäŰ&¤`x¸ÉžSĘNöď;‰ §"ĺxěd,ĹóđüoąîVĂĺŰgŽä–+ƌ{?AéüŒě˙—C]ĆŚÔZ݉uG×! úƒ!yšLœ3<Â_ŇĎFúđ^¤qź4ţ=ř쬆Äďjkö¨QôsŸě**.D’Ô퇛”Đřˆ֒4>7Ý!nč˛E' w†MM֒!& „!2bŚć€#ń¸#ÝĄ&Š„˙{yÔľőrZ}\űÜӞ„ś…ę@쉙ŤŔŰ üqóůfZîŕľň‹G;XÍÄofA‘k9ˆž%VăVtbů %fŤT•şJÔćq­šŽďU[Rđ>ĹCIbđGâQxЂÔú„äô‘uŔ6úlŮŰĆćm›‰ľ„=ě;2…śá˛ht…(ÁĚ`oÓV%ś”ś5ʰš™_ŁG ˇEŤlěł#ó}ZĽ0—S„öe0ŢM–/TVđY՟E§$ĐƁ݂ëXŐFbévČŮŇëŐęA’ö“Ć4ăöˇ)ó ŇDşŤŒąŤ/J8’R“)‘5lŞmĚo’w˘k'š[%˛|dŘSxäc Laqd𲆹I Ąkő5ő—ŞL7ËMÍĽűw—đpţŮiÄ1¤m:IR F.7YsçťţëădOďl<š^­Ă;żű-¸pCKnajQ<ůŻ˘ř¨5ćt8ŠDIy Ť$˛ć.î˙§qÇŻÓ¸ăg’ćj^}Ž1Ť[|?Œ†Ů÷sżNťŞLm‹8ÂQ|–6Fe8ŕž§9l’O\˜&tm÷`˙đŔ„çԐjšź<ˆbĺ &ŠaľmĚTˆY9çT f™âŤYpp€ ŁŔá Ł#L8äčDQ˙Ăé endstream endobj 21 0 obj 2125 endobj 22 0 obj <>stream xœ]V TÇíf˜î”IƒŠÎ ‹Ę&b\HX â î ;TÔh´D AÀ""‰€ ‘ݍ jÔ°F4 : ‹fL̏‰&ŻçÔpňk0ů˙äOĎéꎎ÷ęŐ}÷Ý*š26˘hš–ú‡˝M~3Ăâ[ÓSWF*C]VÄÄŚť„+ă]ÜÝ #kZ˜b$LíÁJÝa]ś™ŠŠńń)Śą=ęĚaßxJDÓYů%ţIÉŮ)ńąqirÇđŤfÎtţ_ĎŹůóçˡf˙ýE“Ť”;‡Œ˜Ä¤dEŒ2ÍKîOF'&ĆGÉcł“ăRĺ‘ŃŃ1ŃłˆČĘů˘řÄřää¤ šŁż“ÜĂÝ}– šyźŽ^NÂO•‡Ę HŒLůG'EQŽ’ÉS§[ÚL#eXsGŰ7čńvbÎz’Ů„qü´ąöV"SىrEŮR먼TĺJŮQëŠeT eO-§QîÔ4*ˆšE9P+Š`jB…S‹)O*‚šCÍ VSĄÔ›Ôj ĺG9Sa”?eJŁĚ¨ń”Áš2ŚPyT3=ŽöŁďт‘ˇŃ1‘‘hٍŃŘĘ8ܸŔ¸ŰX/öw0 ˜íĚyćť™-aŘvöWnĂs5c‚ĆäŒůŢÄŐd•I–ÉA“ ¨6ÓšĄ2X§ÜU´ „$ţNżdpĄN!ĆŚ .Qˆ˙Íô@’>Qó8‡Sx,6>ÄJî b3Q(ăń4˝3ž,8‹=ÔO˜ˇc[Vnš´ĺćgpžěąÝÇö—ŁJTUX~ôdiIůŃzČՙM4šP™°ź;NeŃŐăÓ‡űŹ$şˆCÉWú˛~¨g%Ý´t ´ŐG…JńŸ}‚œ\Üâŕ˝VáˇQ*š0Ē0ŇzçşzP$$Ŕ ~˙Ő]_eVĹ6†Vů!۸ac쇽ŸČÁ&ô>€7Šds™Üš["çśęŒŤfőÓŽ‹[ýŠdfşű¨L ˘ G†DBœ%D ÖÐNyǍ˜ăDšó#Š!ˆŇƒŘ€ž 4ŁąčŐBŻ6Lk%z-AĂt˘ŤĽçę9ÉŤÚłŞk7&ŁĄ¨&×ZN"´U×4ߟŒš2/Ŝ‰ŠY{4ÚČhq;9Ě^CU{+˛Nf~Ž@Q(:7ń˝Ě”,ĺŢŐdP0ŕĄ2ŮtzWy*ń\žöYBědˇ3!=-=Uąkâ"¨[0릅ĽF˝ľ40¸Mo*ö|şąš…o…q${MŻaŤ„ŚATľ<žîa‹pŔ-8Áô'ŻŔB<_♲C>üłl‰Í—{ťšŽč XÜPke'ęUeB¨|T'áI^ްG§ŕçáL\ÓĘS†ĽMńŔ4ö’Iqŕ ŚÁćޕĘÖŠ$gŃ}o"ů'7źđĂçqË˝fť…=30ťýčŠÔLˇ-M#<×Зľ"Ý ńJđtScOä„ŢJ _âk‡° ÂŚuö-Ëď%˙ˆ`úĺ§rçf2{ÖćĹç(K—Ä{“Śš‹aé°`sëzvŇiYeJIâ§áÜč"„jBŔfŻZIžjĆJžN2ĂS;ÖĂ@YB7Ě#, X‘°$šđŻ×‡•´ÂöPţ‡oŕ xlŘ÷ŮË‚9˜ß|84ŠOw€g}a@$Á=üŕrΚřŻkN$,BO_ěűÔڃi_0e„ži‹6ÄŁ´éDŇĹĚÓ{OźĆĺwđGžßşŰ8ÍÝ 9Ёƒ]K_ăsV+”hEÂ$]6c°-vĹY8 H ۆz+ŻÜ’őś_1‚ąěÄ2pÁďJçƒÇŻŘ‡â[Ҹb7;RŐÁü’4ŽÄő6¤îhča­0E+ś„3 „‚¤ ؤx‰ Ÿa´#Öźp|Y°˙~ĂĄ °˝Ě ŞIMu€u7=Ô'‚O =5Lę‹łGكĽŇN6Ť`ץíˆóٸŮWćÔĽßĐ'ld_KŃ jč§Z~."łŢá!›šŽŤšxžôjç`ę‚l/ĹÍ# -#XC!D°ĂM뽟"Ö{Č^Wäa äjč'ZźyÁFَ\Á]ŁĎQ*Ţ1ƒŚßÉ|'Éź•¤ŽÓ ;UÝŠ`уŇĆóUœ¤ódiĹÇ7qŮÜü˝‡vĄp´5a˝7'Šű‘hOVvÁC!'Uƒpxy$¸7 YÉó;‘kŞ‚­ń¤Y˜Ă>sŽ~˝VvnsË{×Qú׊Km\2‹voÉPŚ'nÉ^ƒbP|QÚY%{>ßWÍ˝É:ö,s¤FígęĎ_.iC`Î狉cœľ„Ň´[á á gťŻ­Čő°ěżjxivA\,˜ń ş‰Ç˛™˝:c~}4ŒWČÔY7sg ˜IëÖ˝ëˇ)ڏííMiﬓÂi–$­[˜ŃA?& 9B›öó°}@Đwz9QŤhUŠň?:%íbw}¸ăŕűˆ‹Í+Ş“ †)dâL,QŃíÄvą§/ëct ăšśý I?)‹j‹ËC!Zřy(ˆčq >ă‚S~‹@áé8Oô¸´ň§„ŹK†H­ßśb2ŠÎˆJLWfnÜľ ˝…ÂKă꓿ÜYs¨ r(¸xsUԕ ţXĄAôęRmăšęVt=YŮćX‰ßiœ(é™}"áTËäű­?×á|ČRZ÷ZC´­}P@ä1KȰĘćá+ʤAž2Đ3$ňü]ŠŔÎÓ;˛ž­+íiŹěl”J˛üš€lFŒ††Ď ‡˙ĐYó°GŁďœ{GŹľĚh‰śŞ_ž‰ ‚ď2˘xƤß0 g-aŁP&va°ŁŢËoňĄú2ńßC čÝ$čŮÄڐľ-ĚŁ‡ˆëÄż1ř]ř‰ˆeˆXÎŕœ"bTE?Ö &Dh‰žu XŠÇ„o.ވ“ĆžÚ^‡ŽsBĄ+éǎżťÁ۰ŒžƒT(d j2–pŐ\GòÓ;ۓĂÂ4fşŢYNÜp&Ń=c^nżëÝÄŁI6ŹŻŁ_Îdžš# ’ZgW`ˇŕŢcQ?ĹŁp~ŮČKěޏöY+ß/9)ƒŰŹ6č 憌GÇIS“óVsý̑oĎVŠ÷ >i­,Eq9!{°INöţ„a)‰P'Érn[ú{[Óńć[ҏ#NŚ6Łc¨8żňQiâQҞí)iń‰[ß_‡¸Ĺ1ŐM×ëN ˆ>ű˘ŕT17Ş[†p{IŽ|áƒŤHo"#7 pތŚţԋłؕ;zÜřëčÓɆż•¤Ńpö1(†•<úţúíŽ;51ÁRhg%a盔ÝÖ }B4Ý|ćźÂR˙5ÉˢePł.㾯7´%˙ˇĄ=Ę+ƒ°.ŠşDB5¨xQ8 Gšuy5pO?;Ź˘_‰_ňvßdłhŃŽĚ ¸śŤŚa@ڤˆ`ď=ꠕǻýaˇÁ*łLˇ†p7›„‰óFňÄ×ČÓĺ‰ÍҎ e†gÔ&}cŐ™š>.4GQ˙Ç&Ë endstream endobj 23 0 obj 2855 endobj 15 0 obj <> endobj 24 0 obj <> endobj 11 0 obj <> endobj 25 0 obj <> endobj 13 0 obj <> endobj 26 0 obj <> endobj 14 0 obj <> endobj 10 0 obj <> endobj 12 0 obj <> endobj 2 0 obj <>endobj xref 0 27 0000000000 65535 f 0000002825 00000 n 0000011688 00000 n 0000002756 00000 n 0000003193 00000 n 0000003045 00000 n 0000002873 00000 n 0000002595 00000 n 0000000015 00000 n 0000002575 00000 n 0000011083 00000 n 0000009929 00000 n 0000011365 00000 n 0000010337 00000 n 0000010841 00000 n 0000009636 00000 n 0000002961 00000 n 0000002991 00000 n 0000003340 00000 n 0000004422 00000 n 0000004442 00000 n 0000006653 00000 n 0000006674 00000 n 0000009615 00000 n 0000009835 00000 n 0000010201 00000 n 0000010665 00000 n trailer << /Size 27 /Root 1 0 R /Info 2 0 R >> startxref 11844 %%EOF speech-dispatcher-0.9.1/doc/figures/architecture-future.flw0000644000175000017500000001762311447133617020772 00000000000000PKű­4i…ľ/mimetypeapplication/x-kivioPKű­4“ 0{.Ňé maindoc.xmlí][sŰ6~÷ŻŔjwMó~ŮąÓIě¤őÔn<‘ť}D(X†"ľ$eGýő ^$I°eQ)ҙ&"ń8‡çœďŕBđü§ďó<˘4ĂI|124}P&O/Fżß:őG?˝;9˙ŰŐçËű˙Ü}ßđ#N&IHŽ•˙Ěfĺ`šâɧMAx:ËI=¤šâÚ8†‹ćľëʏJ~o~Β§ňçĎŃĹ.aN:töý´ld´iŕ<ÉglýÔĽeŒóěbΉœ'éĹč×-ţ2‰Š+ýâżxwÎ˙ŃÓuŽćŮYńŤ,<Ήp4^Ŕ§Ľc"Ý O&ˆhçF<š]ÁGnašä9§ŕĚp>EÉS8ƒiN”Ć3¸@¸.ŰYW}{ĂÖ^Öu ÓÉœ=Wě 搧 qń0yŠâ…9ŕ­g‹ŽxJ&árŽâœŁčuœŁ4†“§§ˆr“$ pƒç˜§ţ[/Ií×ńb)PüóĽĽr@>?<œŢ‘žƒ/čĽä6 ŸcqĚą§ܓ˙óNŃ=ŕMŔ]š„(Ëř@‚ó×;F˙[sŔDłœśVXé:gé{”Îq Ś*|~ÖîČb.^–<ýřĺ”čˆřIŠ•çşBŠżĎó]ć<‰żB)~DAÔG˘ÎœÇIŮŰe”ăG-…[ů‚˘Ň˛^đ!ţ@đ›Hßv[xöáÝÂĹśâҋČĂ#źAâ )ŽŐŁçŏ¸J–9˜ĂtŠă$d'ó‹‘ăjn`ŔSEžmh~PPYę>Yl‹T—nĐCž˝ö¤sH~żˇG`V3œ8šéykŔ—újHRLœ ”–1O˛pëËŕüç%‘"ŤşZ_*%$Wˆş"8ÍJ’ŹdŹŽŽĽÜŃ2ČP~-HSŒOWŐő%.z ž_Œ,ÇŠ$Y‘Ž˜Áşç¤Ô!î¸ @ˆÜ,˜˜hÔôč"e/“8&ž”¤÷DA(żÁY^ßo/ĐŰj7ÄvuQˆă ˇBCL××Q­ű˘ŇpBhI@ŇÔŮýđjë+, dĹ˙ďW bŁŢĆ!VEŠżžĚš›^öE§:ß04Ď,íĚą™"•Óć獭ݛ%ŢV^*ë\ŔźHY†łť×ëÜ%ŃŞ°!° 3[˘ŞÚŽę'ąd˝ĄŒ5măj{‡\×Qď´\âM˛ú÷î”ÖŽůÚ]ćk ˜ďţ œ{lC)78°t9Aƒąč”˘yďŽ<–ŠpK¸Ž­ŮŽ1ZŰüZ+šcúŤąu] äŞ)ŒoUýŀ[â\'XÖđ{ŔMngRśËe–'s–/ĘâďÓ4yúÁIFEQöNAĹśŸ¨ú+ߘrmAgŻ€Ź;ßқŞĘŸQ2Gyş*5˛ÓŐ~sŮé_żYětŞ˝í󳝲ťŰšá­žË„Ř7¸ś×ľ„Íf†ijf5,0L÷5Ć=M÷¤ąşŻ9Ž/r%÷P ‹ƒLÇ—‰DkO TËTXˆĽ†j(0Ëoüşżƒ÷w×Ĺî÷G<áßőe¨]_ô•CĚN1ь^Ĺ}Kâ]>ŚĂ5'Ä_¤Ś –-L>œ[€iY8!´Ć$ Ľ,…=؊té Eăň¤ó!ňâÍE5jśŠÇX×0V5ŰtŮŚ–QSs’(/ëšKu×ČźzÔ^ٚvjżÓ:yd֓G§mó:2ĐWšxjąœîi§Ł8Ô¤“ Á*6—#ˆîܒ:öŕÖúTřýÁÂ/;†î ž˘‡žď犻ŮflĆ ÁWßR’gk–×9ĺšWMś˜z9íňět [ŕ0cGËÝu˘ýpÁ‹cu=aŠś*ĐnóÚó”űsË4ť×˔óěŮy>¤‘ň#óC ÚGCĘwŢÔwŞWR•ď‘ďřĺ™zš§]žcűŐň˜Ł™AŔł[šŽë|M!ąE¤|gďžÓ<‡­q Z›—§™Vĺ'†ĺö0ŒĽÄĽęCŤ^c!š§éniۚi؂ úĹ:)ł;Łőěš!œ;Œ‰xAŒî¤@´D/^M&ŽZ8ŕ!×6_3Ö Á˙‡żš< vYŸ‚"E0Bv‚éÂPc‘8Ę5Š‹yź{R™Ě ˘ƒż ČÔ]MwÍJŤŻqšk ‹'ŁU) [‹¨˜G1Ď04.Ď_ߝD˜ŒrRîMMŠ‚EAEěÓ ëp$´ÓÎ8-cŽŞ’ƒ9ćxőśSWí9šÁů9-"?ŒQ¨$l-˘˘"EEĂи<]ž]ţăŠ‰ŽŠ‰,ÝĐ,żóL‘ý3ŃNř´Œ>ĺCf¸DÂ(ËÔq’€1Š”„5DS4ꏠHĐá Hm.V›‹ľš¸ĺpýîíĹ|{ƒéŘ8şÚ^\˙ŃśˇŘM÷ă“řQ7[z°ÝĺŐˇoéŐNzĐЕ3ŞM*BqşH]TĘBűŠJYTĘňƒŚ,›eČî¤ĹMZ:ëT‰KűŁM\vąw‹ˇĆ_"} lv_@{ciŽÇ|GDe1Tĺ*‹QY u[e1*‹iĺĄő vwÓšžÉbĘ:›‰ˆĘb~Ŕ,Śš˙aˇxŤaü˛˜g6 Ši•Ŕ¨†śS•Ŕ¨F<Ů|UĽ;1ů˝ż>•ź´ß9ŽäĹ÷7˝ó=žÝâ;FńWH\,˝çťˆ*mQiˑ¤-ݎăŇň¨ÓŞ ]ë>ťÉpÝú#n†ű*{-űšîFŮŽžtqŁŰڎ^äPĽń˝ĐEŁ,ϑ‹EëPՔKí˛^,Pť,/úNÎŚžÜö Á|™˘ěŔdӖß)˛YĹkż›ĎŇ4&Ělcë›ď20Ç7ź€oúZç$~˜céšoˇĆŔăZŚ8Ěł4]B6~ŁIIXS6Ĺ;Ă Šw8ĎŘXĹá,Mbü'Źb!ůčj¤C_yKňńőC’OłuÎÍcč@ćI‘O`K‘?ŒŃ¤$Ź)›"Ÿá…E>|äłHq’âbžUńސ€wŠ—|Ç;;­sÎFńĂh&†ů2źcŽ ďŔMJš˛)Ţ^XPźĂÇ;3bĽ ˙{̊tF:f#I~[ŇiśÎ˜ůa HŠKŽĺI*?ŒŃ¤,Ź!›"á…E:|¤&ńž.S5ĎvÔÓ˙e}SOłuÎđĚcČ@ćؚíˆĂ\C3%dă‡1š”„5eSÔ3ź° ¨‡zb”?%é7§„.0%ÁR ~ÄLí+=$i6ÝÎWUö˝ŇÓls5„ĆŹ˝HÂřĎŔe75čš'!?ŒÝ°!ŰySI1Đŕ‚b ޡéě4B(ůƧ➷ä—¤źŰOÝoşżţ$ĄŰŘv-M==wƒ<ґu¸äšćöL )Ph>ßnefZ:ç.lZ,~­A9Ԏ`Šq† ăđî-Hńe†!Ę2'ŕŚ8!´Q}W dŤ8ŸĄ‚jŇěŸÍ—ĚIybę¤ śó ÝgÓ8„nŹzfĘdgí;‰çlŽsDG8-š1ťßÔŞăüG×ü*ýˇich˜˘Ť)×ŮŤëŕâižÖt&óů2ĆĄÚÂ|dîÄäĄqün>r]MšÔ^\͉Šgŕ_űÉç ĺ@űĺ#ŻogŒMŠ•EÚ\{2•ó9ĎűĹ"Şů'0žÔŤű¸\Ś_Đ‡Šęƒ 7‰ؑ1Ků÷óľiRUš„đńš÷ÜOłë—ś‰ţ€é¤VË8KŇ8UęJŞí2~(žĎń5ż`—ůĎUńë~Uşě[P–HľŃŃýĂí÷ŻŤ(&”~ËהćE~ć‘%ĽëqďŹÝ/(=I­7YB˘Í%t"!N’TśŠ]Úi,WŞę–˙Čˆ˜xÖ˝uQg(-g—Ťüڏy|zâŒiôąŇ6ŕČp"SĂpĐŚrÜ+BśëŸ†˘ŻYФ•˘!Ľaľáwƒ‚:şŞFύ(€ĘqjKĘĄl ăsFĎtňˇR üCš~"éŒd‹lśp_š1:uAŃßůâjž˜]1:ş`ăa2Lôv7´é›†(Ń´öôI›üŘÓ;Ł+uťjŕˇFČĆ]\#ă{oëüĂé#@űV>ĘO,Äm >5—.^œ˙!wŻŹ8ć Ů˝î,Ž@W˜ăôć5Ňz~ÉÖř0F8é Đsœ!›>A~ńPKű­4q öÚę ţ preview.pngí—é7Ž÷ÇU>Œ˘Œ!űžK ‘,مŮ 2$4YĆ.ű’˛‡Š¤>Ì!Y#Ć:Ł0Cd(kƾŌ1_żs~˙Á÷é÷őŕŢ÷}pĎ=÷ýŕžsÓmŹL8σÎ311qš™ٝćF&Ś3L€s§Ş›Ţ÷ç´Pąą°żÍ 2Œö–öƒƒS’’“6V7ČSäSÚ;ډ$âŇďĽS6–6Č$2˛YUQUőŽ*ż ‹Á"?"ąuزň˛ĚäLü ĂG‰I1IůŮůŘ&lţó|ä;dfzfYIY{S{RBR/ގˇŁˇŞźę`ăOŔ÷v÷nll””-‘—2ł3ąą ĂÎĆÎ ęE$ĂŕaˆHDXP˜—ŤWYE¸ctƒňOWPSTSťŚ†€#ź<˝22íě Œ @œ!w,„@‚z{‘Hˆ+DMU rss313ľcÚą-X|7Ŕ €8@DO‘•“•3¸i`gaGœ"ć—ä#1Hm-m9E9nnü(^THŔ Mż5•œZšafd`Qś^Ę^úś%˛Ď`Ŕ ŹjRŸô8„ƒN¨//ř45Éčů…O繌IĺI?ČŰdœíČV‰×Ţ4|˝s"‚[’6×w댒ŠÔĘad={¨¸Z~~[öÎUű\y›§I &{‰ #ŞŮäŢŐÚŽňcšşmë×ô5˘k"zA靍ä+Q‡„ëióńO+´Ä=€÷ť$ĹyލyžeYnƒ>ň ĽŽ‹n{‘ˆhnDźqÎŮ7 Zę75@nˇÄQ­yšş°ŹĺBľ7D¤öO.‡łO-{đˆmŠĹG[ţ˜wfÖi’ľ_kľö_Yßąćîáyf˘bŢĂ?Œöş/?ěɌ*wk¤dîGxę–ňœóš!”ŤÍvB`ŠQiëÝUđćLcŕЂý,ŞĹms>s^ՂÇaé€JŃ4˙Ť%‹ÁŃ-mgł•™ŒoëHqÎDÂ:ƒ—2ŮIșᢡ*TńŁ÷ŃŘ>8Ő0*űȤv7qéŽŃޞOťîĘ;#!ăë ůîŹM‹dÜbăzčĎÜe!t›QŽéžItOWAśŠÇşŸ “áآkpˇÇќ^ÎewNz*J¤›h)c6R0˛¨ôxQœ×I~qĎŢ÷8‹_úHgŢ𕙞Ěb“ŒéVrěI߸JY[kËP ůűózŃâYF ą óÂâVlݑ㍪ú<ń-Ô柍FĹđEéűď™ŕ őÍ˝ŃqçÎ*rip _KŠšq᠀>Nó€"k÷[椢…Rύ¨VXŻ­9ČlHúŞĺ5( ˇÓh*đbŽŻNÚ-LšÓG‚˝U)›­L§¸_mâ™OŔŒâŹŻ\’ŞN‹Mď{:˛Öýo4H(Ž˙íÂCňRř‹¤0hŹ+T”c˛•Ť¸4>†–S}şpiĺDŰ˙ł[oî ą2đ[ÂúĘq }–$“cyŤY뎗\'߇É*"]#ĆŰ.[_Úˁ%íR^ŠŚfAÝÜđBX|gQě€úşƒvňuî-Íaë`úŮR8××==ęÖżŒ˝‘`a÷¸óâ[żđ+!ěÇĐX|ŤŘH…ą’ˇ,ű˘ĺ´uô*ë‰IčfŐWŸdúF‡ČŮépĂ!gżÔu0ŠáJÖű}ˆęšKO“CŢDť{ëČß#P#'ƒćáÎ*Ďő¤ë&‚vsTşDôË÷O2sM'L[Ĺ`7곝¸ŽLOřŐÝXÓ ˇ¸důź9^>dqƒź›}ŻpčiéAŠx^1˝/Ă e›šŕęş/3sÍ+€ëÁÝűę‹L_ČĘ˅JVÝ ÁS-fA ď‰ëĆÚł\úqË˝BĽ_:‹úvCtĽ7cˇŠ¨äőŮ÷(ĺüŽ…×ýÁ5zß/UůМg#x;cŁ÷͗ë%kţžŢąś4ő‰:>â…ž™Ÿě%Wó/ЁĹĚŐÓę9¤-XI¨s炨8gŔŹëŠXNš5Ghœŕ“ćƃGížůš%ć+ş^šĐ€4*œľ$­j%ƒ=*^"*Ć#Š] r-t_ž.Ł÷Ď=쯊śzMků‡¸ŤékýÍ>U‘>śÁĎŕĐYŮGŤ oŒů{s ˛u…_ –Ň灘˜™…Ţ6 „Ť…Ő—ţaW•Šě?¸+Ł`=—ôĆÔ,I!żZFt‡9¸ăń'Ű””Ćb‚gřÚ?“‘˜œéôVŇІWŁjýáý†j˝ĹóíJY0eÓKöĎЉűސă+Óޜhxś“ĹźöEců> Š .Ţ]?Śţ†Ü;jÄT݅`hŽ ÂH#GHÄB4ËD6Ô[~ť¨Ü~6ŇleËĚąř‡Yg~‚řäFĘŢyőüĎĂH4ŠůuMtKöGcŁÚ‘ř{`ŕKŠ>ęšÄçH [/Œ|y…ó#Á}3†qťš˜­á•ěM>żź$;z˔ňŞŕg'Ęçy<üŃçĘ!;ŁĂ‹˝.ŕÁóWÇTQÍĽł;Źń›&dĎř9b´Č´9ĘEáÜ$îíЎ$Ŕ" ‚~q|YŒě_ ű_‹ÓĄś ę &ňÜűXđČG Z\rĺěeőLĎŠ“”w –)ˇä(ěë‘ÚłîĄ7–Ě}×2'žß;‚ul?E;sĂŔ˙BßŢx‡AţřŔeĂ­íFăC%”Â?˘^ŠÝyvî/ÝŮĽ‡|źŸÉ3‹č˙^›& TňrϘ}49=Ó┤‰Ń+N…ßwv(ĂÜ@űßΖŁ}IIoŘ áŒęfú“ǡ­.ôCřŞÍ2BOˆ)SÂGZuÉhőű6‰žŔîxů ˘Yä•g­ŇŕŇšôIa录ÝUőŽ:~ł8K$ŠŻkÚĆ7tkăŮ'%hÔÚ Ë)żmE“çüő(ž€-­wé4}zôkë˝e‘§{OÔÖ@N„)ľ iťY-űšš´6JF2U˜iœeh}Gš"äš9Ú˙sŮle5Ůg_>ĘÔ‘ßVUŐľČבą™´Vr) ž(0âÜź>ݜ!vĄŕkBBË˝hócŢú¨ľv˛}ÝvřĐS(¤ęuůmţŸşˇ+5Á7UnEĺ[.Ţ2ąđťöS´x݈ $*Nş7Y™ŻĄ’¸şűřg„Đ­@˜bvQ‚¨™ éE÷E^tžM6ŻMĽ•‘Á‹s˝°Š}ÔsۗŠ÷ýI ÷śę%÷äŽ_6Ç\o­ŢÓßH §9tcŸŇ.[w本w¨qťű¸˜çáqGŰ8TžĄf3L řa üűĄsxŇŹ0Jódg;dĺWŇ )>E3#-{ś/-¨úÚÔű€ƒUe‡T׆.źhůŐ¸ łÓ{easqZVÁŒ›Ë+-/Ć2Áę q0CrD ÄÁŸ˛ÇŇŹ;T´ĂĘR}´/Ż´nZd÷÷獟ĺaZM™0ŕŕIŹĐ9ĹÄE=h‹ć:îƒę ˙ýgńđŔÄpOVăß40Ó˘Lź ńî{™QŹŁó,tźe;ňÝ{™uź™ŤUă‹ĎYŽľŚS ?Z˛Ô×3ŹşăX歕á¸Ćoż‚źű‹Ž”.0űŃŠŁNYŽH7d}GOm‚šŻý=—2űzÜĽżK0Éł–xřűáÍ`:"O ­ Ë'Ó"ł}ĐKÎYĎďyą-˘ŕŹßIęEŽĚě-tëÂüsT4i%_hě˙ŰŹgĹüʗďO›őˆ˙z–íAܤ†S,;ž ŽÇÔĺâš5YbC ­ťޟŚœrŚëw¸5>V)˙Y߼q$JgČ}‘YÇŚX!´0—ĺŞďCŸŮ!dĺaFE-óäNÚĽ<őö˜ż‹u#'›-ş-÷ĄÉŒÔĺř€ťZnqí"'š&ţAŐw •é•Sźú=ßí<žV¸Z9×Ü2I˛čH:*4ŐÓ-ĆłLý.3ťę1L6?:Ë.˝É*ěÝŢż8ę MÔAŕ1ËŘ10žš3ěÁ+Ćš:úĹÂîZC,˛î61ŢěŃç:JżÎ×Ő:žýEÍ0żÂ˛ô-,ň˛K2>.MýV5Ü˝+ňCŇ::šăNŔÝCÝ Jŕ×Ü8L˛ĺKB*ýŃS60:4ó73÷ä<ŘđIWNëýüÝ:¸äýšIUć?.öýBÂŘľźéŘýüIľ3FçŃĺˇč×@ú8+ŢËąß:*áŇ äË3C d 1123 57[1 0 0 1 0 0]sl 8 false 0 57 di /sl 64011 string uc î˝Q,*´Űň˝Đß-+6*űZ4:2DűZ,Č*ö˝đŮZ2*ąłJžEÍ0żÂ˛ôý-B*śJ-¸Ô6.2âŇGTÎú÷ß:JÂâĆ*ôHË0+4 .Ëť,6Aä*üI,,ü˝Ř:.4ŔĎIźö9.Ţ+úYW-ýýúł*đ;+đýŇ3 <žÜß3LžűŮăRąś-.:éżYú3Ń52ŔłÓúŐ°śĂČ2*Î*ŢýýőťÇ*>ŮŘ09Úż*G´Sąůý÷IB×2žÇžEWöE,JĐ3ş+ +LZŘ=Z4ľ¸ĎO6*űZ4:2DŰNîZ0źŐ*ĆZF-+.ßłŃVŢúşžBĹ;ÜóR,Č*.0đAÖžęŃ-°PŮRZŕŢüý1żűJžZ1ď .7Ňť.ýýÁ;ŐRîô6ě*+Ćśî5˝,ň0Ŕ24¸T8ÂČĆîüä/:ýçDăę¸/+ĂWŢů6ß7J+3ĹŘîąJž2Sű,,Nł;1ŔóžŐ Xâ?ÍĐÇHťË<śIĚżĺĂ*ÂŰ0üŃ*L,ű=ę<ú/FßÔ532,*,ä2Ä*ňÖOËëýĺý2čěRßĎÎ/-RíÉ.J×ÓóÇZÚFÁÁ˛ ö:,Z:ÂR,Î÷J,â>Ďĺ˛JćMś/+*K>ËúĺAÄJ°ÇF<*<ŢUéÖč ÜűÜÇüńý¸ĆDýÍGÝą2ÎĎŔˇQY°ŇB,ä7ÁRřňˇĚ¸Ô/˝M*.,ůA:JęMś´ÍAđřVśíăŢíL*ŕYÁő¸*ď7N>5ZF3 :4ľ/´GČž<*3Pď3Ů+řż*ží;Ň×ýý=3G2*Fáś9WW/*Î9Öšź0-.:éżYú3Ńš.K=+ź¸MđNOĆNĚݡČB*çÖ*Ô3ă°üä305Ö?LčÔîđ SFçŃŐS,őáCöĺ0:ČóL*8OŢůĹžHĂ6ěş40+űZ4:2 Dť˛ŢËQÁJLDůý+6*.1RđŮZ2*ął.żđĺ1Á*;ě¸ß+ŔHÄ=T:ß2H3ŔŔ*ë5äýýŃN0.ĆŘŔL2*ă˝ZSI> ˝F0ĎôËíŘôý˝P8-Môú1Y¸/+Ü×ÂÔúQ5SůIýAÂĚ÷ýěĺÄŢ,KQ::Öé+ĘĐÇHťË<śIŢž=/Zýý=/ŇVKÄ3şŢ5 1VęůČBéÜűÔ<0IɞƿEÖö/,î*Ćęýýô;>3;BđÖÝś+Zź4ŢËáöýÝť¸J.2**Ěú4űĹżúÇFŇ:*ůď0JŕĆžÖ1 ď.7Üý+˛ÓÍ*ř+×<6ß56ś-+°ČâJ*WUćýý,ęÝ2żE2Bí/61,ÂŕW1BîN+îýýúłĘ8/:ěKFÇđT*ÇÂń>žćĘň V,L0ěşŕAZž-J°ýýŐ@Đ@JťY<*ăÔÔľXŢ÷5öýýÖOËëÉýúÍú4űAžýßFĘM+*/*ĹBďűEJ9ß.×Q1â*Óűý9- ÷5;ś-+JŕJ*Ů1ďý˝BđÖI2żE2BË/ä1,¡61BîN+L*.ßZż*LŻÔš10:č7*ůÖÂM32Cśń3ÝJ+8*ÇűýÍîÖ5 VŔúQé>ąé×Y?C+íľź/Z>6FČÁZ*;ßűOPşý0ćMBĎá@ł´ýIýÎS;žýĂ2FŔ**Î*ŢýýőťÇ*>ŮŘĚńHżžEí?ú /FßžE<*ěĹÂ/ĆŕőćůJ+ÄCěOŢËQú,,ś*Lôý˛3ÓíV*űQ9KÚ*ZF3Î4ľűý9+űž*ŢőäĚNBĂ1ń:6JP3ťR,í ˝+DSP..ôż*ŢšćŇŢZüL.ěJžĆîüP36ýçDă.ôČýýYJŢşľCżBĹď*-Ě>Ţ.*8=öýVC1-ŰČżüą1ďV,T0ěŢŕ 9BžŻ:ňÜBG3W9Z3éKčú˝ôú<Ă5öSFçŃŐS,őýú˝ŇZěçÉ6?´JÂŇGZŢâłZâĚýđR1đî*7˛ł7UëŮíšćî9Rč 1ă9żžź:*î5D?ß>Ü2żE2:ŃÂHÁ,K9ß?.ÂA2*61-ÂŕW1BîN+P*Vł6ú/ŰĎÁ-=*Çč-*ĺJZĆňP,Ěśö7Vş* 0î***:JŔ8żäé,úýýťMż:*ÂÚJC0žźB22.Ë8?ÎęMK*;6űÖ+čT-žK=óGÉ.+ZÔÔ@ÚJ-ü˝¸LU, îZK4.žCE:**F2Á˛ÂđßćěľĆĎAđWůźĎáęś.,A<*.Ä;B*D°óť=.Ę9*Ăý3,ŢőP2ć˛*JXÝKÓž+*J°óÖ*Ý 5*:ńę++ÖéüŃ.:Sś*O,ž°;żĚ/*2šńžP,şY+¸ĆŃ90žćEŻĆĹRH6ëű0CřLÜłíA¸Ę7ĹJîN,âVGĎ..**ČQ Xžż*Züݡ*JĚ.+ł0-ŢćŢăEFR+,*Ţň3+Ĺ-ŢđýýA-ÎáüšĹJŢężJJÝĆîŔ/L,Â8*ď.âG*;ľŕ:9ĎşBŘů7° ňĂşéÜYňBE8żŢĎ.RůĂ3Ŕ*Já/0Îß*<Ă,:K*4ŐHJ**:Ć;řň7L*8ŇŢ/4ś.*öýýÍI*.üýýV*>üŐ2*ę¸:- AVÎ<î**ĚCLŢď*Öúýýă*ň./:;*R ÔNĘ6ÚZżĆ*,.ŢęńňĆżRDŇô,-Č*ŘOQŘż*@BDťĐUë,;ůźĎáęś.,A<ŢÓ2FĘű˝ő.+*Ë1TžÔ,ĆÓ8ž°+ćřč 4XÝß?/öŰ*ňBĺ82žŰK+Ć:*+*>ÜĆ+G5*:ôä+Ë.öß,ÂĘäÍÚRGőö:1ϲRëóËčň-Ćę9÷¸Ó8EďĂ8ąá;2ÚĆ *9O/.+*J*ŘřL/ć<*ąé+ćV*ÉXWßóEFŃ*ŰU1,.śôĚ.Jń**2ŢüN0:S:,Â2W3ŢÉMż:*MÔßőö:1ϲRëóË čň-Ćę9÷¸Ó8Eďø5߸ó3íSä;/ś*ňÁżÎZ7˝řBĘ,/éöĹ1Rńç:ĆĆäźJž=Ý/Á*BUýýĺěŃç:JżÎ×UëÇËüL PDŘčľű43Öő5ó@Ŕóč=ÜŃĘM4î*°;łÍÚ8ŔŮT+ŕ-F0ĎôËíŘôý˝Q8-Môú1Yříý5Lĺú˝őą/WłQ´ř5CçćTÝ óUNŢÜYŇŮ2ÔUÍö̰,-Č*L,žäî*×6K?*JˇĎ-ČHÄýýÁ;şż+Lžűűôâ¸Ç;37WóŮźĂ.ęůø5߸ó3íSä;/2 *ę-+žű-/*,ŕ*2G:,T4.0đAžJŢĆEEÖéĚęôB°Ďϲ¸JOL;*ŕĐÜ1=ZŢ:Ęâ*RžM˛źíř?îJ,ě>ž8ŮŇ×űýú-,Â*üAžJťY<*ăÔÔšëÇÓ,MLDČ/1>KGË÷ńHłŔîR,ŢýKžC*MÝÓ0ÇçťéŐĆžťÝRľ;V ŐHďGăFĐž-3śŃ*,,ůś*îG:JZB˝M.Ćý˛Ë°´WłQ´ř5CçR@F:BĆÍ,*żŻ*Ĺ<*ü9BFJ-S6N¸íř?îJ,ě>žJJI8*ö/.ĆZ4ÍďżÎĹZÓG×çYâNM×îž2Ţýś,Ţý+Á-˛:ú/NőWÝL,ôűLŰĂZŰřÂő>ńĆ, 8NŢË,ćRßÚŃACTJž=Őż;šüÉMűőýó:łüIšźÇÔŘ=EűĂʲ>582CD9Q*úIZśž0ĐBĆňÜóUNŢÜYŇŮ2ÔUÍöĚ °,-Č*L,8şŢÇ,RôĎ:ž2ÄüśžůĚOŔ*BUýýĺťMż:*ÂFřUëÇËüLPDČ,-Ŕ*ň˛:śö3ăűZ,ŢýCŔC*M˝@2ÇCę KŐčď<9ŘY×ĎĹĂĐK?ąGEˇš2ĹS;+ąÚČĎRĐŃMŢúĺđEOŔ8ńőăVĺPě8ŕ ŻTNŢ6ľ°>Ä>+=;üé.ŰÉžCŔéQśä1ŰTĹËöÎŰĂZŰřÂ7OCé×ÇŮÁśĘ43BáĂ6Ă:?+FA,KYŢŰ.Ę;ÚźŔąžćÓ¸ ęÂ1ëW.éÓQęRČÇŢPÖů˛D.R:˛´îĂĐ9P+,KŃĺ.îZC,˛îş1+Čú@6,ŢV7ÁÎú÷ß:JÂâ;+GW2,/ßćILĂ=UĆ žCTÄŕĹX2ŢK8ĆłúQ+Ęľ6ýýIČž¸ÂéÉśP2ŰTĹËöÎŰĂZŰřÂ7OC3ę.5Lĺú˝őą//ÜöSDçŃŐS,őýü˝ą3W÷Í @Đô?.ZđBB°ĺ˝öĐB.9ÄΡüÉĂćúÍüń@ŻÚ*PŰKĂEUĆžCLÄLĹě2ŢO8ZBąëŮI6Äŕą3RĹśť3ĺ2ĎUóÖ39ŘŮ 2ÔUÍÖĎ>=żË2+ôÍî/ZF/Î4ľűý˝Čâž*UUćýýľ:JŔ;şŔ./+ÖAĘýýąGîŔEŇśą/3BMććC+Fâ+XFĘ0+4îî şA+ó2ŐA;9Nú27Öő5ó@Ŕóč=´>ăNZ=.ÄFôAö,ĘÍ,RńBüýAżşJž×1ďýýE2*B0,č:43Âť.ż.1Úî0?ěVK ,ä2DŘI+ÚĺÄŐž,ůźĎěLÖXťŕÄĐĘ.´LťY<*ăÔÔÁAă+ĆÝžýý/FçůM2*ú98LBŢ/AĘ.FÚŔ.ĘďJ1ě>ŢHÄłK ĆćăˇÖő5ó@Ŕóč=ěŰě4LŕŃĆN5ĐĆ+â˝ŘPCŮ,8ž÷ß*ł8áýý<ÚÝĆżE2*Bč087LB*ĆśŢ/ľRď07ĎAVî0,NBĂ11;6*°GîŔEŇśą /3BMăćĘ÷ż+VâŰÍ2L4ĆRI*ZČ,*ĘËśMĚ<Ď,NRÇOŇűM:Ćš:ĐVż.G;ýE˛@´ňŻĎęٰě4LäWˡ0Ö8Đäýąĺ ASŢżÍŕÇHťË<śýĺýUéÖčÜűÜK,ľ:žÇéŢĆGýăĎě6LBžî@ŻÚ*PŰKĂEUĆLű9łúHĘň6:ĐžÂ-L*ÉM,JďÓśM Ô<3,:BôÜ+żÚ-;ă4Nć3÷ÝKąŻM95ăP>ÁŰQŃKž,Kąá1>űZ4:2DťP*1É;J-ĺš2Îâľß:*äčJ.ăÍ90+LN8 3ćçŔ:R2ÄüËSâń2čşD.<Đ×9źB6JĂOÎşŰ=őĺŔůÄ,K*2ˇň5?*Â5FżŃ=SžJQF-ú˝-+äš@3,4Q8SŔł@.+ ÂUFˇÁ0SŇýŰĹÝIŔNIýć,°C˝Ö?<*´WĂEĐ>3úÍÝľĂ4ŕ+0É8žJěżĆŻ/<ňÂúíÎ×ÖĎĹð=ČßŔćCýíűVKď- źČPřňłČŢűÝýíVLUüŃĂŇť/+ĘF0Äę÷9Ü>2ßÁ;˛Ěý°;DýŃýÚO6AžSľP+.ăđ2úI0ĎôËíŘ@ú:@žäčBúşQ °ŕÉÂşZADŘĘFIçÁů5ś¸ń6**.ěýąAîž,ôSEă7ń*Zˇ˛ÁžŢź7żĆX/<ňÂúíÎ×ÖĎĹð=Č;,ęI÷+Ţś4J?ěř ýý>Ç++ÔÔÎýýíJž.Mö.34,ZYBýýĺ¸Ţ/ľP;ËMŇ*2řBŔ9îýýLß:˝Ý=ĺSî4Y<đżŰćR46Ö/NNKĹąńP0** 4áĚ*žśž5OŢÚŐKĎJ*Ʋ1´âÇ,žK1ÖŐ0Rü4Ă2:LŻĂLťŢGLÚđÄŔ*:A:*.H,żšÔR =2ĘJJ2đ˝Ř6M-10:BŢËń=-Ŕ*6×0I;-ŢBü+RHśÄšůRFJDăJśHJSÚćŘçŮWPÎٰ=Č;ZâGîTř9ž÷S*˛8 áýý<ä3Ëť2ýýÝż*žďNW9:żÖĹ:Ćîž5ěĘLDĹZôç+;Îú++úŐśČű.¸đź/8ďOLHÖ57WřŮČÝŰR**žî1,*žś ž-O:L;FZşĎÎľZ*RşĂřîýG0Ú+ý-:-×č,ŢÖ=GśĹ2ĺÚĎ:*41.*CľJîÖ?Č;.žVQÉďâ,P4NU/ĹćZ6*Đ?0 *Ěľ+ń21°ťĎűĎŢÜ×ĎĹð=ČĎÜA3ž°Ué÷żđ*âYŢýý,ĚFđ;.*üQ2ďÄ+XśßNJ3KDĹZá@ł´ýž4ć˝3äąćÇÄ ÎĎO˝UˇÇÖ1ĎźXJÖ˝ßîZˇB*éBËŰ8**JÂ9+6Ď+Ö@˝ńLď6AÚá*ü9RUńúËY5<*ß,-Ţčś*-ÁFˇ?ő3ďĘE4, žůž*Îî0.8ŘŕĘJN,ž30BŔšŐ6Ĺ,+P1ćS.DŰŮíšçĂ4:JěC8FÚ/Ęŕ+Đž>űşY˛˝>Öľ´ňŻĎęð:ýçDăę4I RAÓäŻúýYŔů5Cś-+*áÇ×Ü:ÂZ*:ďž5XËL<Ĺ::Ö1,*íK/2Ţ˝ĎLTQÎ=őUZĺDŘóľÓÖ-¸Ń*,*Ű-6JýýÍ40 ZLýýYF6žćűýI<í*ĆFËý+AÚáž-/*ôÁ.žÄś*:>8Ţčüý˝ôťLÚńÄđ×53śŢ*1WŻPŢôüý˝ľB*2¸,1QtďR: 0B*áąŐJÁýš9/*28íáî*îĘ÷ĂôĹ,ůäÄH@ČóR0Î9P.*T9ĂŕWKÇżĂ1P÷.,NBĂQ2ďÄ+JÔ-Xśś4CFŔJJI2 *ö/?.+ÎŘD0ÝíÇń>Ö˛7ëřŮTężőS*+Ţů+0ÎýýO.-:ńýýÍčE?ýýÉSF:,ň>IŰá*ú˝÷@;28žJZ*ž21:ěý AńIPšěB*BP*4ěžŢKUĘ/ÚĆ.:;FîXC8/,ŢśÎ>ĹX;VAżťÚöÂşY˛˝>Öľ´ňŻĎę°Ö8ĐäýąĺASúžÍŕÇHť Ë<śýĺýUéÖčÜűÜK,ľ:žÇéŢĆGýăĎ,3XVŔűýÍŮÂď,Bóä>С.7?ĘšřćA,B.ýýľHÉI,*,Á0ěŻ*Vťň.ľ<ďä+8<ŕKľÂ*žŕ++Jä72ڹùÇJ,üý˝Ö6Ĺ,Żž+öÝşĂ.ôďÄ6X =J@DÖÚ5ęEEřÖR´LCÚľ>2,žĆMIźJç1-+żÎçą,¸¸*ŇťŔ+đÝÂMKI8žôŮČÉNKR*ŢBYśÄ+*OFžĆâýN7*ÂZž*AîüŔ-X<ŕGľÂ*žł ++Jî;2ÚEÄC+îüJ<ĆÂýý9@áĎJ6Z*ńAY;żťF>Ć.Y˛˝>Öľ´ňŻĎVǰÔ.G5śÂźZÔű;Y4í¸ßí..*:ĹB*L/ -*í1Ë*Ę13*+QC*.Â-:ůýUÝR-Ć>6ŢřüýÝô/1ÚPÂMß:ýAĹG22ęYżŢׯĘ3ÖŰýýí70*ŔĚ@á;BžS++žďă UN*BŐÄ;ĺ5ë9/ôË7ťV>UĐĘ?Kĺ,8Ď9Ęł˝âÉŕŮě÷ů/0žßß*6QąüňEą.=DJďćVëH˝ĎK,*âS0*7ď*ÂŇůN Ač*ŘĚD:ńâßÚîžÁÂśA6ÄÝľĂ4ŕ+ŢęMđśľ6ł,00ˇń°Ŕ+Réýý9@ÁúĹ;8*ř8.öä,**žJ=ťůĐśŇMˇˇ9B1Ĺ =á5ë9/ôË7ťV>UĐĘ?Kĺ,8Ď9Ęł˝âÉŕŮě÷ů30*ČĎő1,î,/č*žćŃ6**ńîśXLJ@DÖÚ5ęEEřÖRDҰřßPôAMSşéG˝Ýß*IťĘ2.,Nćß1PÍ/ śź¸N*:*NÔŕ/-ĺBžýŃ>Lž0źúÍŇ+ńŐ2Â*:4ŰĹ0*2ľ3ďVBB*+:ŇĘŕçüCˇF˛ĂD+ÓRÂ*:.÷91ÚV0<2/Ŕ5 4îäóÇ++žÂRť9ăăťŢFFĚ6Y˛˝>Öľ´ňŻĎ˛RăŇ.ľ,,VZ˛@VQž˛N-2ŘÉÓ**5äČŘÄ?Uáä×ĎĹĂĐů?Ńݰ˛Ůí ŕ¸Â<ĺíŰR2;7ZőXÔ,*V?UXWáČÓŻńęćáLçűČçYCŘëľ/Ż>+2+>ľ-3UăČUéÖ°łęFEřÖR¸Ý°řUÄ´ůWÜöB ;2.žžM9öÜËÓ**UăČUéÖ°łęFEřÖR¸Ý°řUÄÜĆľëůø5߸ó3Ý2÷XŻÄÜĆľëůø5߸ó3Ý2÷XŻÄÜĆľëůø 5߸ó3Á°H3+VîŮŘŇ8Eďø5߸ó3EďýľU65úÔ@ÓáPşĎMęćMńęÓQęÂýÝWŻVîŮŘŇ8EďĂ8ŻMíZę7ĘęóÁ*% d 1123 57[1 0 0 1 0 0]sl 8 false 0 171 di /sl 64011 string uc îý51*,**žĺöLĹÖĎľBô0PźĆ=ü@>řLňśíA¸Â7ťÁŻľZđÁFďľKĎALĹůźĎMęćE6š-=Iâ3˝54ť;¸Úő5GŕÄ ÜßÖEB÷KĚöŮÎć5ĎáťÝć;´ň7ÄŰżÇ9đÂÝ/ĂÜ2GěůĂ8ŻMíZę7Ęú:QúWRňĂćďÜYň2Eř0áěŢâ1ˇŕíŔLYÂ8 őűLĹÖĎľBô0PźĆ=ü@>řLňśíA¸Â7ťÁŻľZđÁFďľKĎALĹůźĎMęćE6š-=Iâ3˝54ť;¸Úő5GŕÄÜßÖEB÷KĚö ŮÎć5ĎáťÝć;´âĚ85ťČEB÷KĚöŮÎć5ĎáĘX>şîĐ*úýý<Ď2*ŻSíUNJňĎî˝Á/N+8ĎO+CŻMŘ6šŻ/E÷ŮĘúî0 PźĆ=ü@>řLňBŮ5Ű+Ŕ-2Î.ó˛äÍůŇąłJ6?:ťń-ÄźU7<ÍËK0ęĆGá´đľC÷ß7Ęú:QúWRňĂ毴A¸-.1:JZ: I/*,Y+++×Uä?>ĆŕJĚËK0ęśű-2*G.Tś1-śÄD*úőWÄ*CěŮš2ěýýĺ8,ś9UZÚÓJJA6ŢË-Ďúé4÷ýÝ,EĘI÷ZQęJ1-÷ý˝<¸ą<14îî28SßÂá+UâÁFYâ3˝ 54ť;¸ĘëĂě*ß+.2CDYü*,čůýęRĹÎ*4Ĺ÷IDÁ6Öďř1:*őýŰM20*ňá,*ŔŘ*ëV-˝üBPÍ?Ę16-.J.-BˇZĐ ËťZ0Đ@Č,żîż-˛B¸śľ.ĹŇZŕďž?đKĚXťŕżÎI°*5úÔ@ÓáÓÝć7:Fž*G7.8źLˇIđ+C7P:ž*ďű,46ű×JNH EÁ6Öďř1*ž-ýYC*28Vžß×ČŇĚŘŔ÷žŻ*Züž4ʾǸL?.B3ą÷Ń˝Ţ-1ćZňîî2ěRßÚŕ/UNÁFŰřÂËöýŮ?Ä/ź UÉčďčYň02XJžđIÉí>3¸XNÜűýI6ĺJ*KśëżO:*2â61FDÁ6Öďř1:*źú÷3¸;-X2Iüú<űý˝?߿ѳWßşJB žĹŘăG÷Výý9ąÜ÷AÔÎäŢ>6PYXÚ*OĐĹ˝ZŢż,FFŔMT:2şÝŻĂ˛ĆŃUÍÖ3ý˝ŮŕÖŢľłSGěđĂěŻŢ74ÚĂ*úýIý łŔXNžZŐŻZÍÖÉJý44ĚSßCSFŕÄéĺž*âKÎŔůĂ6Jě°.ĆďGČKZćśZ/ÄŮ4.ňŔ+FůR2ž:űýÝPŃ+žĆÔł0P=. /,á/ÂľF-514îî28S+çÁ*Ţ3UÚ˝ÎŮLç×ŘůNćŮĎTĎŻŮ?@îFÇěĘŢC82ř,XJ*:Fł2,*6íűŢGTÚÜžéĺć2I š-=ËřÂYÂşŐBMYâŮXÓ˝+ޡ;FÂ*×Äý>žöÄďŢ.2˝7Üé+Âľ:ŐÎîč68Ö௴âŕ67îJľĂĐUłőÇÎľąÓLŃ´UF J3ޡ;FÂ*1*äVůô1ÁĎöŢ..çOAśJă/,*ű-Xž2Úýő8ß/FčýýăżÇ´ôż@ÚĆ**îž1*Ŕ-ëśŕ *ŢťW-ÖÍćEěżNŐHŻMSäçËĘ1BřWłĆşU.×;Ä<ŇŃC˝ěŃ048OŢÇ>HOĂ5Dčůíč:1ťîđ5/Ä=3ĆÄ6FĚÓNóúý YŕVßÍźBß3AL.ěýšĹÎF*ę93Bí<ó¸Î/1<**Fî+żŢşËŢ3-*őĺÔC;ŃÚôČXÓŰěçÇů9:ĂżÚ?żę2MZ:I/* ,á*8OŢ?ůŰMĂ5DČ6?¸ôŮŘâKíŻŢ4Lď>BĚąMHĺîUďŢçřý˝/Á/ťˇß.?/ż*X2Iüú<űýY-WłYZ˛*8ńË˝Ż/ Ă/A<**.9śKýýĹŘăG÷Vľ6ž<çáýěDąUÉXťŕÄĐĘŃEˇî+ĆÝžý°äÔ.ĆçBŕYPZB*üúZ2:LđĘžĚ?-+,Cł15 8ËŢ6ž2Ţýś,X×YÎŕW7G7żÜüÔ´ťćVHď2EđK1ŕ9ÁÄR*Ń3Ŕ,ż=ĘAÚޡÉ;JÄőýýŐ<342Ä0JËD*2çŘÖîL, F*ˇ2ŇîüýIš5/+2Đľ6JşáSMËčEĚżNŐHŻMSäçËFö*V6â˝ĐžT,âBżAÂŢ+.MćFýăL˛řýýůČBéÜűÔLŕîŢ ŔE=R+*°ĚJ*ú˝>+ŐęARďÔÄĚÄŢ×/RÇR.žÖŇőß.ŇP.*:/śÂ´ŢľłéÁäđ3ĹÖŻľ6Ů4RÚżÇPťŕÄĐĘŃEC9îň ĺ,;÷I˝7ŃÁ,Ćš2ęY2ż*Jś4JůŔ÷ý˝<Ě=+LąĐŢŔE=R+ÎŃżŢßQ>őÁ3RťB-RŇśUM×âÂ<ŇŃC˝ěŃP28OŢĎP ĆÔDě´L˝ťUMG>šÍPÁ*/Ŕä0@Jřß>J:˛,2ý9@MžÄ4ÝE2Îâľß:*äč2/âÍ90+LěIę;´ę7áÔ,4ľZĐSÍÖĎ> ńňPLU2*.°P3¸0/8OŢňß;TFăÄV°LZ:I/*,á* 8OŢżP>9ĆŕJříŮDčK×:¸äýšIURZżÍĐÇHťË<śýőýEÉćČý˛;łYK*=Ĺż;šüÁAĂRîZ.ËńÝVÂäşÖĎľBô0P Dó3EȰĚěâĎ1Ző:Öýý9Nď=Lś+-ß*1<*öÝÇžÁÁ:úŐĂÎH2ŔČžßż>*>Í63+ú9QŢÓP2ü,říŮDčKĂ*ůQÖ* BĚ,RĂŮüýIO°J*Ň7Çš-+<6ß=NR2:ťßâÁ7ťÁŻľZĐSÍÖĎ>ńňPXť*8=öýVCľÂî,0Ŕ+..ô-+ŔGÂą=ś?*ž üËűŐ.68N+J÷âĆĆĎ÷ś,XłŔ>0ĐýÜÓĎ8TŢĆUŮ5V*äQ+ҡ6ýýÉJH:*ę1ôŰż*žŻ:ÎLĎĆJęMĆ1Eř0áěŢNŃ HďOăîä×Z2žŻTńHçÇNH*UáŢYĆćE<ś+-ß*:çÎ*űĺCç×3Ň*ĆłúQ+žőśçM3RMĆŕđěăćçöççJîî=Čůß.Ú ç.M˝@2ÇCęKŐčďD9řü,ŇőO,Îęč¸ÖÎF*÷5öýÝžśÁĐÁM2RÚšÁ.AÔ:/´ň7ÄŰżÇPťŕÁČďNOZNĚIˇÇ<*ç@ çÇVHž.ç=ŻDSÂŇťöÇÜAÄ×ôëÍ?Żö×3FÖ+*=Zž0ÁĎöV,41ĐÖÚUC¸ÎŐő,ž÷ÍăľČ.GäíOJłL**K:Áą4áč Ó¸ÚăÁPK+Ćý˛Ë°´/@6´ďýäŻúýYŔů5Cś-+*MëŢÂŕG-âž73ĎáčŇ@ŮQÚżÇPťŕšČKÚOĘX1JÓOîě;GÇă-R W*řÄ+NU7=BŐHSĺČż*żĘ×ĹĹS51ŃKž,FąýĹ<ÎÄ:ĂăG¸ć,žńď?é.ŰÉž6DďĘ9<žÂĺJ,ˇÜĆÎĹ:Ö*BĚ.RĂ ŮüýIOň/5Úż*3PďÇRÚąž6Ö;3¸â;ÁŮöŮM¸Ć-;¸ő3íSÄN=ö,,Â޲;-ÂüB2ą-Čú@6,ŢV72ÎäŃK:;ËűĂő N@EJú;:ÝT7G3Đ<žůí/,ěOJ0@ť02CJŕYBżňXÂó:łüIšźÇ,5ú>Ěňçé>żů˝üÝŘÄÓôëő7<ś-+ĘÚ0Äę÷Y 8?Ćî,@đßÄNć;ÁăW.ˇXQJ0LćÓQşQCLNó52:ÓĂÂ6ÎWą÷1/2đBŔęâîO;+4ÁRůäľWŮöĚNL-âGßZšÓĎ-I ¸K*1ˇ*ÔË7ßýÜŻúýýR,Ţý6VřĘ:¸Ó8A÷ÎCN*ő7/Ŕ*:đć1@RřßJJ:˛řĘžĚĚN+,GąÍKžřĚOŔ*BUM>XŢL Hęśî*ČŇ2+D˛ô7ńóý÷éŢ7žJ/JZ:˝°,Â82+UĹÍźZÔŢĚą,śĆ-ÚśB7,>Ţß÷X ,Ţý5ÇĘA<źÂ0âůLU;ŇMęśî*P8ʲąÁüCČýýĎŇü9J:śÖJWě+/*.1čôJ340ĘPKúýÝR++žü7JÚŻň5CBťś Ă3O*Đ@Č-EBëźĺ4őJđĘRDÔôÂĆčA:JT53CśJ+L*ý5=Îá@ł´ýIýĂáQIBé.îř0Î7PŃĹô;í5WĂÎ8ŻáĂ-ś í<óÂřýIÎÓZ´>ŢĆJ6Ţ/-Ę-2.äÍ?Kž*č>ÁüýýATîJ:8ćŢĂ*ÚČżMĘ*ô9BžÇBÉIű5Űść41KđČRDÔôNDż A:J.P5CśJ+*á/.Ďý:Ö9OWFźřż×ŔÄĚ3JľJLAĺßÜYň2E8Fž9ńË˝Ż/ýý9PTň˛8FśŢ,,żőE4ŢĎ´ˇQHéý ýAČŢ*úĺSâRöĂ4ŇJÚÎż5+ś?-A0޲VłYZBJ2žSBĘÜÚZžçĂÁÔś1<ĺÂĐŻłĹśÉBŰ8žTÉŢG°îŢ.NBĂAśJ: Î9.*ú@8IűŢV=MßMQ.Z9ḹ2ŰTĹÉşćOąáż-JËD*2çD8JňN¸K,Ż*N9,*Q>ž×ĹŔ*.çýýY>KÖJSěĂ4ŇJ ÚĎż,žUCśŻ*´Ó./.1ý,;2./,Á+PA8ŘŕGĆF=ČĚÓGQTŔNđúËŃÂ;đ-üÝś+QX-MôúAĹřÍýĹ4äGťÇĎ@8Iű ŢV1°ŇH×Pˇ7á¸=2ŰTĹŮşćGąáG¸:üŮPíâ?@ŕ1ĺJĐUÍöаśńSB.ĆBÓˇăŢ/3śí×N2*ąóýýČť>.:ŔĎÝśú N×7ď.1.ZŻD¸˛Nů2Ýą˝ćÓ¸ÚäÁXCEĚĎ-+:žńĐ/<1ËÚ?ČĹMšÇőNĐQśJ*5ŃĎąOŘ/XFéÁXÓáPşćMęćE6š -=ËřÂ7OCSěâż=ęV°ěăćDĘňę8<řÔćż´@žÂđą3ŢČř58ŻáÔç;MËÚ?ČܲžÄĐĘ>ľ<ĚZ.Jç1Ń*żÎçń+ÂüB 2ą1čşD.<Đ×˝đ+Läęŕ,D7-ý6ł˛őíčŃÔĘŢźôîLšNÖÜ+ŐEBçQAÝż´óÍĚNř.M*şČPřňłČŢG<ž´Ëă˝XJŻ 2łíúÔł;-Zéşž:/ŇÖJÄ3ĘĐÄôüWťčČ3ęĺ8X˛Ĺ.éEî¸-=űňđEćÔüçÇNÍZ.*BĚ/2ĂŮ,-*ăME:ňŻÂ6Ň1: üDPĹ,:ő:ÖQSMšýÔšE*ęá4Ŕ**Ćë?Nń˛ěÜ9ř2EÔÉ8ĹÄ;Ů´ÚżÇŰź2%% d 1123 57[1 0 0 1 0 0]sl 8 false 0 228 di /sl 64011 string uc îýČ+ž***ZĺéĆťQ<ťŔ;*Zź@JĘá26R3žýëŃ-LJ+ĺż6Îý.Á/,2Ă×đŇĎ6ĎZSí¸ľ-ĐAĚVĐJÔXŘGĚňŔäëů K9Żá¸çďŕBX6óż1âď8ľZĐÍXź-ëčIGÇň3XęËűýÍÝžEľÎá@ł´ýIýECîýŰÁŢüý˝:ĂńŇĎ6ĎZSí¸ľ-ŔđÖV ĐJ>ěŘGĚňŔäëůK9Żá¸çďćB8NJHńś-=űňđEćÔüçÇNÍZ.*ĘÍ/2ńBěÚżžŢH2*şIŢż4*FPîý×°<ÓĎ>ŃZQ í¸ľ-<7á=3îąďJ*Ż7ýýý+ĺć-Ó:3őýýŰ1.B**ňżRGîÚłúýÍÚ.Ȱ6,:ýýIÇ,űÍĎ4+4PĂ>˛×äëůK9Żá? ¸ś*,?Ććřý˝ń8Ć*;ĂýýQ8ĺ6ß/0JĐL.ćÎ÷Ä+Ŕ9.Ä×Ď*ÄĎ0*LL-.˝7áV1ÜîÂ02G.T0/ěłŢĂĎ8ź**=+1 ľďPKě4OYDJMSPČEˇßľłđLďÔEľ:2ć1,*ź1śÎ,*UáŢYĆćNł>ă>ęçŮěëžć×ů,,ÚN7ąëů0Ně˝ýY9Qđú× =Â9śĎŃüýÝ4*ÎăÂýýýľĐžçëŕËݡÄ.ľ1BéÖÍGÚć83ô4GF*żôŐ,÷ý˝>AČ˝W;ýýQLAF/ü ÝŢ*ŇZB˝đßěBJ.*68Rî*ĐŻýY1çýý/ĺV=,1Ü:.βŢö×ĺQćç0ÚBč-ń2-śś5ľ4đÔRřĐ+DȰĐÚÇ5šáќРQYŃ.ěľěJM/ńĚÜâRATŐ.ž.ç=ďŔ,ŃŃĎ>ŃZQí¸ľ-JLVż,*žńýč4L˛ć˝ěBXÖžîAZň4Î.,2ËŮ4.˛DÄýýÉ ÁąVńR4..řŮŮÉŰęĺ8X˛Ĺ.šĂ8,žűđ*žZć?6*ÚÍ3ÚŢ*=1PŘ×Ď+A6JčLS>**ŔÖÄß.Čč?/ó/Q˛ŢÚýő8ß; >Fćž5MťZ8ĹÎď,?ě>âWĎňO-˛>ăNˇ=AôPç1-+żÎçĹěJ×ĹŔ*LBřATŐ.žč,ÎAU7ăS/UřÔąE:ęKÚž*C´ë >*î9EŢËąç:***7Ď+LđÔ;YJÖźJß>üýIĚŘ=+ĹĐJZÎ5Zě´ËŮőÁHŕÄUňś<ýŢşłžJîÜ4î*-î˝í<ó¸á*N ŕVüľPÇ*WGšZîâ5Ě枡ýíGŔMRśÎ+AÄř>DĚęŕOƲŇÉíJŮřQQÔ04ÂI,đ×čćčř;ŐľGŮ+çUĺ/.*:Ż0K*X ŕýŘLÂ<ĺýIęGA:áB0,ĆNWĹ1Ćť.úÁłžűĎžESŢýůLĎJĆNřŮůÉťęĺ8X˛Ĺ.šĂ8AđíMëđĚşÔýý=3ťúá-XZ *8ńË˝Ż/ľ6Ţ>6PYXJKçż7ÔLQńčÁ-YśL-Ä9˝źŔ8K+îU7śJ0K*,żőąćśż4ĺ4đÎRřĐ+DȰԴ=âGßZçčć äř;׾GŮ+Kˇę/.*+ÁŐM*,ăňS*C´U:žĆCF2JžîH9ΚďúýÝBĘ,ŔES2,JäŐ,¸ž,7ÔˇůźćMęśĂ8M+Ż*Ěť >.JĆüýíEŢCMśż+RŃ0*LŘH°*,KżŢÖż-¸:¸ťç*7OCűZ=ůÉĎÂÜóę0ÂĚÜA:ŢóçCËIűÜŮĆůýśćĎőX=.2žąĘžžBF2ŢżćMíźńV4ÔŘý ýQ3ťA/źöŇßôëYĚNďôü°9ů×Á5ë;ß´Ŕ8,žžßÖáÝÖĂRÚ?ČܲžÄĐĘźÖÇűăRLí¸´-LŔ÷=3î.Ă2*;SëýýĂ ľGď*˛ÖĚÜK,ĚŇ0**ćő?LžáĆł×.đýýá*ÚíO+ŮASÄ*/¸ÔěĚY@°IšśĎGĎT˛ňĂă=IéźćMęćEî¸-=ËřđŰTCű?M3ÓLMYVH÷×ôÁHŕÄÜ+ŐE BçŇAíÓČçYCČR?DřŕđÇÍłIň;´ň7śŰżÇPť÷XÓĘüČĎÂTĎĎA@ÍúVůK9ŻMížé7ʲčÉ1ăş<,ÖŢľOŃ-WčČ3 ęĺ8X˛Ĺ.éEî¸-=éüÎŰ´é=;ž/źUDGćĐÔĘŢźôîLšNÖÜ+ŐEB×ô1ëłŮH3+VîŮĐçż@łă.ôą1AŘMŔó7śŰżÇ ł˝ćáĚÄÂňÖĎWCÍúVŮŇ9ŻMížé7ĘVůÁHô˛NNĹ7ëČ÷âĺŘOű2Eř0ÚěŢâŘIňŻQML¸ęćÔĘQźÔWčĹÖĎľŢó0P ÔűK9šD<ĐáÄ´ăşđąëĐźÂ7;+GM*ľĂđűEŢHö:;G´˛Uä=Ié@óěřůě<ČAř=3çŻMٰH÷×´SőÔÝő@ĎşĎIÇĆ 8EŘ?ńÇͳɸľűťľ3ă5űÇÂňÖĎWCÍúVŮŇšéíšÉRÜćÍNNĹ7ëČ÷âĺŘOŰŮüÜŮÂđĂüNL¸ęćÔĘQźÔWčŰóőŰO >YňQ<ĐáÄ´ăşđąëĐěW˝íWL÷L˝<;G´˛Uä=Ié@óěřůě<ČAř=3çďď7ÂAňK+NÔEĹÜć4ĐZ4ů˛ŕ:WÁâ=IůéÔôŢÄH@ČěŐĘüČĎÂTďö0ĐIĆéąśQ,ÇĘŕË6::<żÚĆ,ŕźUҲŕ:WÁâ=IéźćěLíX ť÷XÓĘüČĎÂTďö0ĐI2/žĐ0+ZPŐGJůŮ:ĆÎB8**Ú:żEŃîřNJBĂÜš3ěÁ,žůRžđžMëžłăúAŃôĂ>2ő4@Î:Ĺ ó<ÍúVůKš5ťšóăšÓ°řUÄžSâë5>Ńô*ăWŕĚűĐś**îŔ.ĚĘŔ5>ÂFűZçü9-4Á-2KˇýYśŢË´ŢN LýńĘňLIš.5RĆá¸ÇQźÔűÎŰĂÜŰřđ7OCĎ=ëJ*56˲¸:Ů2â´6ćűýýô/ŇGJ6ÜýýĺG8**Ú:ż=ŃîDTýýÍŰ ÂýÓCĆýý÷-Küý/1Ę6Ę*Rí<ęýľYLćKş*ŻÝłçË5âę:ˇżJĚAŘľŔó17ň@ϲRăňÁËęYÄ<řÔáEĆüJč6,+82 žúĺýŕ+č-ÄIŔ*žžžžĎ*@Ňó˝Đ×üý˝ŕ+AŘ+ć?1*¸ă/NK>ôľX:šÁNˇCůźćěřůě<Č0ÓĘźÖÇűăRLí¸ş-ç9 NËK:J2*ŕîűý˝ě1>îć<ŕ+Â0ń1>žéč÷YPńýý͜޿:2ůAąí1ëW˝íWLç Îȡť=Řś>3,NÂTA@ŃĂ.,ÚřžÂ0JOL;*ŕĐÜ1=Zź;,â*RžMňˇ7ëűŮ8íŢ´0LT-×ĘKâYGˇżJĚAŘľŔű@AíÓ Čˇş=V=ČÔě÷Y8ÓZŢ.Đůýý×1âą*ČÎĚäúˇÍDQś>+ó5ą*ÄźU7ORÖăüP0ŻOşÉQźÔűÎŰóőŰO>7TCľľLŔĎş˛+äÚÂýýÍťJˇP86:,öI ĚžđŔ-O:ú/ÚÔĎŮ<ś>+,-÷S*:B0îR,XˇŔ>0<ýľGÜżXÂäٸÇQźÔűÎŰóőŰO>7TCľľLžîź˛+ÄđÔýýÍťJˇ P86:°˛HĚžđŔ-O:ĂżÚÔĎŮ<ś>+L*ýá3śă3ŔÝžúÝóö0ŕ5řÎ*<éËM3ÖőÁěEEřÖRDҰěě.Jśň÷ö˝ĐÔýýI ůžđĘFBJQ-żÁÍRě1=ÎÚZ0ŢćÍ/Lđł7Ű?żM3:°˛HĚžEĚZýýA0<ýľóSUPZIWđÎŰóőŰO>7TCľľL:î˝M+Ć Ü,řýýÝřž-ĚÇN9Bý×úPÇÎáúŰ.Ę:Â*C*2âîşXMĹQî0,ň˛:śö3ăűZ,8śŕć.Ë/L°üíčŃÔĘŢźŘâKšéíšÉ RDҰěěÂ*ďűÄ,NUKż*ŐHZ>ńž*ě°ŢË+2üé07Ä*8NŢňJ8ýÇRÄBý×úPÇÎáúŰ.>Q.*:.°śXŢŮřŇ?=ÖÍ@ˇ ćEFęQ2Öň1W˛ADȰěěÂ6M÷Ä,ŢÔĎžU9śŢC÷ňżűýÍÜžš3BKĆá˝<É;ŕ˝ËΚ3ĆĹ=ĐůÔHłă.ôą1AŘFřô@+ VřÁ@Ř57OCľľŔP-ďÜ8*3üýY,÷śžU9śŢCˇňżVá˝4ŢşáöýýĎ.>AâďIő°>+=3ř,ěOJ0Ěś´13ťUÍذ,Îč <1ŰËýíÔ:@űK5ëĂÄĐĘáEďDϲóĚýđR*ćýßZ8źŢłBFâ*0ąÔťůÁßRş@+?.ˇúĺÓ6G8I×Äý>ž÷ÄďýýM3ĆŔ =ĚďKLíčŃÔĘŻńŢß÷X,Č5đöÍEC4M¸éN8*Ę×ôë90M ď×.Nß3ĺú:Ďľł˛ąĺ=IűňÎëU=% d 1123 57[1 0 0 1 0 0]sl 8 false 0 285 di /sl 64011 string uc îýČ+ž***î4-T+ć˛76M/X4žýýY<4+:@óŰąĘÚ,Çů.:LDYÔÄĚ.çĂ*G5*XFĘ0+4îîşA+îý6ßł×F-ÂŮĆś B/UGËźöĂşđ=Í5űáDśQšO+ŇBÄÓĹBîP/ö˝Ŕ¸Dńĺťčä9Ö9ę×°>źňŔ*ôŻVľ.;;N˛˛ąĺ=Ié*ÔĹD1ő˛ľ>ž ččRú2-ěŇžűý9-÷S*:śńGלľFÓĎçĎE,ÖĹŻŰKÂÂ:ĎĎËGÍúV-ÖHčFÚŃŰÎ*+3ŰćIÔżšŘą*ŘČŻý 2-8LžĚ0,1IĎÚŐÜ=EýIJ¸˝ŰĆśş-Ű2íľó<ÍúV-ÖHčFÚŃG-ŢŰĘÔĹBî<,Bý×úPÇÎáúŕš°íëśUMŃMľ.Z9 á¸Á23Kŕď7ňLşÝÓÉşđą7ŢřRńîĚô:žýěß:ťÂ+ľTî0*2ýłŔ@Ü=ůěÄŮD¸îMA.Z9á¸M23Kŕď7VTž@?3SŘ QX:śśNUýÇAő7ő˛A>žÚÁß÷2-ěŇŢË*2ř,@Ü=ÇHß++VĘÄĚ.S3ŢHÄó0:<ŔÂáEÖŇçâ=3CîŢHřď@9đÇÍł* éMËÁšŘE4JęÓÎşÂ+ľTŢüýÝÄý>žöÄŻďGÇň382Ţŕ˛ňćĆô;Ţĺú:;NFÜżOËPäÇÖ6şÚ7Âşđą7ŢřRńîĚôČ, 2š?69ŻŢË4öý*ŢĘłíüZBJďŕš<í=ę6SYăR>ç@śď69<ŔÂáEÖŇçâF3ÉżĹŮżĆQźÔ+V9ł8ěçě+/:ôT2Ô6F V+XFĘ0+4îîÚ÷ĚNř.M*ČźB/2.ËH9JňĹżBšÎäŃK:;Ëű=9:°ä@@ÎçBöĺRMSZJěáČßŮ8QK´;Ć/.şW>,˛ ćúY1çÎ*Q8-ť*>ł2*=D.÷É=+,áĆÂ58î*Bč*îÝűŻ4ÂŔŻßJQÄZř˛*ŢýýőťÇ,+ŔĘŐ0>5FËŔVë=A2NďÎ9 š,DČôĐÚÇ-7ô*PçNÍÜP3ÚM,âÔ×Ďŕüý˝6LëEÝłWâ*ęD9:N+?@ĆŻ,ŃŇĎŰ˝éď7âš:XLUüâĹűÝ5ă:1R68 đâë5>ńý˝ťŔ.ˇőąJAFŢ+âŕüý˝ˇÇÖ=ôŔćŰLżř-ŐˇçýýRřŘQYÔă¸+9ż*QŃ:Uóâ/,ˇÜćIÔżÄĐŰ>ľ<ĚZ. *BĚ/2ĂŮ,-*ăME:ňŻÂ6Ň1:üDPĹ,2ő:ŔÖ=ŇĎŰ˝éď7âš:NÁNđá*X0çýÚłÖý9*¸ýýÝť+Ď,žůżNÚî*+Ţş Z*Ţ2=*Ú1ÄĚÎŢ.+ë/ÁüżM2ůâTGˇżJĚAřĹłÎϲAăËÂ=6+6HÉýäĺÁU,î˝ůňž2Rޡ:-ňIßZż *LŻÔFł>M>VčŮ8íJÜ-ďÉAÇÎĎóýýą7Čý×NÜŢÂß9ŢýR<8Jç+02ü,8Đ*Ó@Ŕş>*?Ô-ß+CŰČżąSĆÓ¸đ,żF Yň9éJMçXČEˇJß1ŘîäÁűýýá@ł´ýIýECîýŰÁŢüý˝:ĂńŇĎ6ĎZSí¸ş-S9ÂŇĂ;2ŢŇć-Ŕý/P.,27Ú9OŕÇ/ +6Ż,žšRß?42ôL4ÄÎÄÓňýŃ˝ŕ.ż*QŃ:Uóâ/,ˇÜćIÔżÄĐŰ>ľđžÂ/*ńą+ŢúÇ1ŮýýKZ9.*ÜÍşˇ2*8=öýV CÇčRČSÖŃľGÜżş1,ąďäÝÔÂś*Ř4*ĺ=¸2.žř.;QYě;1Ň-RˇÉÖąÍÂěG42FLé::Â×úťÍ48::TIĆżŃSĆÓ¸ đ,żFYň9éJMçXČEˇžâ,*á×*ĎśéËE2.ň-+*Ý=Ô8,ZÓŻîAňJĐńŃĎ>ŃZQí¸ş-÷8.RBäüG4ÂĘĘËŢ×J.*KC8J2TśŢ,Ţüă>âTGˇżJĚAřĹłÎϲAăËÚJ°HĂ=ťřDOîźń0D TBőňOĸŕčą*NĆH3ŃíCčRČSÖŃľGÜżú1L@;Ëź7ôPGˇżJĚAřĹłÎϲAăËÂ=6+RřßJJ:˛řĎERôĎ:ž2Äü+ 8F2*T5žÜVł>Q?VçŮ8íJř-;DĎâĚ0ŮŃĚÚJ:ĺ5űáDćRŘŮŮË:ü2ĆĺTMUéĹÚÜóö0°I2,*âđâçZťčÇ5.đş Ď˝V-7OšUŮ3đĚZÖ˛ł˛ąűĆęŮ8íJAŕůWŰâ=IűňÎýĆPDČô´´=0*ŔOěŃÓĎĂóM´í¸ş-ď/ťR*ÇóäĎ.˛ŇÁüM DçRŘé1E×Ý6OňW7ëę÷âQIGňIĐÇÄĐŰźÖÇűăRLíčćäĚQźřçKý;˲>ëĂ̲-+VZ˛ĐçżXŘÖëęĺ8Xň9éŢ=Ď Ű/äRLÓćć5ÉQźüĆÁü:ĆüN°>ĎT˛ňĂă=I˝âK˝2N˝BĺîřNJBĂüýýł74+D˛XÄGÄDXLâ8X˛í.É59P+Ćš*:8ÄŢ/SVÇŻôűK9šD< ĐááEÖ7˛T*ÇÖąÍÂXFžâŕH2žüýAAH*.Űřž<ÄJ*AR2ˇřßĐűý9O˛ăÍúÖăÖáżUÚÁĆGÚćÜ3@AHĘ,:ő*:6/ BůéN*R;2Đśâ*N0žÓK.Ň?*?GJ>í˝8ĐŇááEÖ7˛T*ÚýýĺWMR,BI6JýýáB9*B8ťJ3M:žéRűý˝ô<üýQDN <Ý6¸F:ĂÉ2×Á5ëEßđŕÁJ*ąź5žSM+J°Ęçż2Ú:ð*ŕ3JĐR*4/žŕ8:ČőI1Sčďď7ę0DĹ:.˝+A>;2Z8îň- ä+žžÖÇç3ÚşÇ.7WAá81Xď>L@îLůPÖâöZ.J:ŇH4*Ń9ÂŢ3,ÚZ*´9,*ńýŰ52.ć*L÷üń:OGHÜżëJŃ,Ţűý ˝ěDXRL:*ŢB9*B8ťŢÇ-*7ĹL6č09VäGđ,żFY˛í.É59,+6ůŻ*@ŰΞ50ś´+üÝF*4ýé.*R52ăůÍÁ>óöö0 ´-Ë4Ţ<ôę=Ď51R6JýýÉš÷+,Ló-1î.=÷ä˝řŇýýŻ@ěúéČÖ6šFöĂš2×Á5ëEßđŕÁS*L9žŔ=4śŢ*ĺ@Ţýů0 *ă˝J*ś´+ĎşýˇĆĐ89íŢ´ÎS+R>+KBůď*Ă+úý˝ůß>RBôč-.K/ż*Á+ĚÎ0+TÔüýÍŇ3;*ăěăÖáżYÚÁĆGÚć Ü3@AHĘ,:ő*>FĎž-0ś´+üýýN*Ř,žžź52ăůÍÁ>óöö0´-ËWZÓľí;ÍúVŮŇőż7ł1ÄűB*×XRŢ/-:3*TÍ/Ú Z*F5*.*ŃřžRÜýFNSĹĹľZEćę,Uťů8÷âĺŘOť9ę2ş2,JDÔĎI4ś;,ż*Ŕ<Âą0žýł**Z´92ăůÍÁ>óöö0´- ËWZÓľí;ÍúVŮŇľÉ7Ä:*3úšČRÜöYNNĹĹľÎ5Ď÷ÔXđÇÍłÉř°×ßćY,ž°Q3ă9őĂÂňöö0ŕ5řÎ*<éËM3ÖľSí ?E6:*ĎşđŰĆĆ8EŘ?ńÇͳɸľűťľ3ă5űÇÂňÖĎWCÍúVŮŇšéíšÉRÜćÍNNĹ7ëČ÷âĺŘOŰŮüÜŮÂ%% d 1123 57[1 0 0 1 0 0]sl 8 false 0 342 di /sl 64011 string uc îýČ+ž***ZĺéćśćÖŢ6OŇ47ťŻ÷âĺŘ9ŘŮćŮUYÜU?Ńݰ>ĎT˛ňĂă=IéźćěLíXť÷XÓĘüČĎÂTĎĎA@ÍúVůKš 5ťšóăEȰLQŘż*@BDçňŢ÷AňK+NÔEĹĎľGÜżXÂäٸÇQźÔűÎŰóőŰO>7TCűZ=ůÉĎÂÜóö0ô˛:ÉŐŇŮďĆQźÔűÎŰóőŰO>7TCűZ=ůÉĎÂÜóö0ô˛: Q:ŻçиE7÷âĺŘ9ŘŮüÜŮÂĐK?ńřPśďR<.Ć2łőRžĘ@đî-7TCĹľŔłLçčGýăĎ40ÂJ¸1I:Í+RŔ¸DńĺťčFßĎ.ŇYĘ+BřWłĆşWMšýÔáEÖŃżęĐ@Đ6 Ĺşđąë1ëW˝íWL×*ăRÇR.žÖŇľT°ÖóĚF/+D7Âů¸*Jś2žŢ6üýě-đC*żżú>*2şA+OC1ÄK4-ˇWMšűÔŮGĆW .Ô*9ĆĐ0+ZPĹ-îýýéL;JÁäÇĆÖ*ł˝Ę,/áö15JÄD*ćKDĚžĆáJ˝OďĆ5.đşĎť=VőÚşITŢGăRŔ¸DńĺťTTŮ ×ô/H/+3ÄđĎ/Bń<üý˝ô+ľľđ8-žžśň-+ś>+ă/1ČJö5śWMľOZąí¸Ú-×ĂŢ4î+Q;ľYÎĘś*üýÝÂÔúÇ95;B @Îđ<ŻĺX2ŰZ+ĘĂűýŰR,.âBĂš4ĹÚJ:ĺ5ëEßDĺăE°,ěSÄŢJź4*.PO0ŮěÇŃ::JśIŘ*MˇéýýĺHîôPěŻžĆ Ď÷ś,Č58>ż>0đŘÄěČŢäÜóś1°5ż?Ţ-¸ýýÝť+/4LÁâ¸ÜĐ/ž;*Ośá2@*äĺĆ:çýÚłÖÝŃśâ/,ˇÜćÜ3ÔˇXÜ ;=ḭ̂Â*üľVJç1Ń*żÎçM+śÖ6+Dś8.Jńç:ĆĆ@*ŘŢŢ4ÉJ÷ýĂF.-**ĹÚZŻGˇ4,*ßËÎćýý=łűýý×1ÚÖĆ6 ř*Q-żÁÍćö˛÷ýýĎ.>AĘ+BřążĆşWMľOîČ,ŇN>,JVčůZ,Č=,*Ć,FLńůÔáGĆW.ÔKSMłřýýăÉNć2š¸<,ň I˝+ABŢäL÷Iéď-ëMFě4NüAŘPřôÔÉľâ.ÚŃ6;Mń75ćSDçŃŐSLJFľ@Ď?ýçLčÄ3R6LëEÝłWĆKV*ËÓŻś:ß Ă?FńŔËóâS22.úíR*ĐŐžüýýŐHîâLĐć-ä˝@ÝS<ňB˝A+=.;J0*,CFÍéćď3Úż*ORQąüÚQË:FČž-ĚBD;W łN;ó3çďď7ę3DÍ*ă+RĆŘBXÂ*Ţ2ą-ÚÍZ*üŐL92üU,Ĺ5çśT:÷ÝćDçŮŮXÜ;=ḭ̂î˛:śö37ń6@*6Q+ÎŕW ýýÍDV@ł/Gˇű-7OLß:INśK2K*ľÚZąGˇ4,,ÂőE4*WĺNXťŢRä++ÚăžE-:úŐGżĘ-3BGśš6ĹH;Ă66Ë9*Ç ý,íOŢ?QĆŕJĐůÔáGĆW.ÔKSMłüýýVÚ÷Ő?ďIű1ϸžČŮÂGůNňXöžűÝ4*ĺ?ťá3SF?ĆúY˛ËňëWAíĆ3śRC ĘýVźŃNćŻHV:0žýýľ8áýýÓřäý=?L*ČŰýý5Ŕ4ŕ,ÎűZ4>65Ëšî6°ÓĆMĘ×ÎśÚ?Ćú Y˛ÍňëWAíĹ4śVCÂýDKß,ľÎ6.Â:><ćŻÉDŮýÍ˝;ÓĆZüŢ8X2ŕCAęVQĚŔ*Ë0ŕťG*<úýÝ.đď*ŐHîĘNXő+V Uş´ÜŻúýýR,Č5đÎÚşĆQâćşF+ŐFK4-ÇńŮěóJ´;ÖP2ĆONŐÇľ÷âQHAŘUřôÔÉőK1ÚÔ6KYJÖ*BI3*äÁ߿ -ÁľýýÁŢźÂHŘ*+úATNó3+;Ţü>*BI<śá/EéÇŮ;îDϲóĚýđR*ćýßZ8źŢłBFâ*0ąÔťůÁßRş@+?.ˇRXHâ ŃŃżŢßQ>őÁ3śá3ÄüV:<=űÔąGĆW.´3,L=ČťđWH÷ÇĺĂ@ÉÜŰóđWö+ő>MÔďI/:ÜŻ.5*Ä=+TďÔýýQ3ťż-, +űJ*ŢAŘ:.žččBFBJŢňGA*.Ĺ.ěśßä¸đÖ.şďR<.Ć2Óő˝KĹíß1ÚîĘFřž51ŃKž,FFíOJˇßóŻFĎĎá3śň* ĘýVźŃNćŻüX,Č=,*.,CÓ5ĺG;;GHÜżłM=+*°÷ÜF;A2NďÎůPíě¸÷ÄĘžšČď*ŢĘłíüZB4M,ú>Ěňçé>żů˝ ýÝŘÄÓôëőËâýý9?ĘšřÁÁ:üé.ŰÉžŻŔFâđJ;đÖ -MĆW.DË@ń,żŮGŘźřôÔÉľâ.ÚŃ6XFĘ0+4îîF@ÎňÁżžJćňK+IGÇ,.¸äüýY×ĹŔ*LBřĎ//0ÜŘ0ÄýýÉ>L* çŢĹýĆŢ;AVVQDŔÄX*S<ě=ň/ÚÉžŻŔFâđŢ;<ĐááEśŢ97Ö*ÇóäĎ.ęŮŇ9ŻM9ĎçÜI˛ĎŰĆż°°üË?¸RIBéâć OúG°*×Äý>ž÷ÄďýýM3*ýĹ3đ:ÉŃÂş˝.×ęJľXąđ1ŰTřô7śŰżÇł˝ćČŮóÎ/°XÂ?ôâ0Y;O7Ű;žáFŢZäŘľ˝ B6Ăĺ<*ü9=âK@ÇVŕÓ;˛ÁőV@Ň<ŕÔťĺěÇ.VDG°ŇÇŮLçĘôÉž°°üË?¸RIBUćć7+Úă+XFĘ0+4îîşA+îýBK 8°ÇP=ě6KEşĺ°K?;´ëšôĚNŢĐç;MËÚ?Čä˛ÝźĐĘXÖÇžĎU,ÖDRNŻ.ËîGé?Ó¸˛íŮš<+ÉPĹ6łđÔRDŃűřÇ °DßPŕĂôS*CŇM9şĺ¸Ĺ;ËěâKLůÁĆEęćEî¸-=éüÎ?ľUýňNIŢć?+V7>ĐBŔPöĚóČTLGŘőëGÇžOŃMÄDˇU> ËçźűNCSěNFß++ęĘÄě2ŢŕF;Ç;VVZ¸WńôűÎĹÖĎľŢó0PřçăľÎWűŃ=ÇHß++ęĘÄě2ŢŘF;Ë;VVZ¸WńôűÎĹ ÖĎľŢó0PřçăľÎW17JOL;*ŕĐܡ@L8:ś6+÷ôNÜQÖCČË6/9?+VRŘđŘÂHłă.,>Ď8WIťů0ÚěŢâŘI˛ăë¸ĺ* ČÎĚäúˇÍČąˇěLß72FÄžşš<ç=6+Rřß>J:˛řş*ĎI0ŕężDÍ0żÂ˛ôÍşžĆCŮÖžPáŢIM7Ű*Đ/ˇíżMN˛3ťčČ 3.RLGŘźřô7śŰżÇł˝ćČŮóĚ+.0đŃ*JZĚĂĆ-.8MJÜGÇň3Ä*ö>Ëňçé>żšN*ëDÉýÚžŕ:čÜ÷WéL0ŢÔ÷*K4 RŻ+6ÉĎłĚâR2ç¸ÚőJ;<ŘÂHłă.,>Ő8ëGťů0ÚěŢâŘI˛ăë¸ĺ*JJ/ť+żĐ9P+,KŃĹ,îZC,˛îş1+Čú@6,ŢV 7ĂÎú÷ß:JÂâ;+GW2,/ßćÝKĂą2śO3SôNĐQB,*6ĺ,ÂŕWż+žđĎ72řBL0č-.˝7ą9âG.ôSčćď.ęMذ÷Ô=M śüąťR*ÇóäĎ.ęŮŇ9ŻáÔç;MËÚ?Čܲž6>Mâćş-.źČPřňłČŢűÝýíVLUüŃĂŇť/+ĘF0Äę÷9Ü>4KÁ;˛Ěý°; ż0ŔŮÂď,Bó0?ĚKŢ;Oâ×=ÇHß2*BI5:äŻ.0Ň.Ţýôç+;ΞńJ0ć˝Ŕß,+ÂŕVˇčRÄRÖËľGçżęLÎç˛CA2â÷L šNÖÜďÓEB×ô1WˇŮěCžĚ0,1IĎÚ52*áS*ÓśéýýŃN0.ÖŘŔüý˝-+<6ß=ĂR2žťßúýIé+AÚKĂą2śN3ˇôNĐQ śJ*;*ŔÝžEľÎá@ł´ýIýECîýŰÁŢüý˝:ĂńŇĎ6ĎZEí¸Đ-×ĂJŃç°X:ĆńĂôĆZťáUľZ°ë9Řđ´G˛*ä˝@ÝS<ň B9J2-îýýEĹďý˝3â-,Ęť2ýýÝż*žŻ:Î4ĎĆJęM2NśŢ/ľRď6,8SLĚGÇň3ěűŕĂE22ę-+žő-FR+žá.üIUP ĐDȰ4´ńWA¸:Ů2V,.NY7ů´éŮęĆQźÔWčĹÖŻí:ČÍPě4OYDJDČKúŐ34JśJ+PŢýý,ŕ4Č58K*î˝Đ2ĺĐ˝ÚZ <ÎÂîPAěVŢRLĚGÇň3Ä**á×*ĎśéËE2.ň-+*ÝU/żÓŻîAN˛ĐDȰ4´ňWĎ-×ĂŢĚňçé >żůËEćRßÚŃACč+8F2*=NÍ.üÇčRČSÖĐľżýĹľZW-+2°ŃÍWťáWOâ=I÷łU>+,*Jż6ÇQQKćMˇJEă-,ĹćN ×Ďľ8ý0PôŐÍ7JD3R0VU°=ÜŻ.:*Ä=+RďÔýýQ?Ű/+Úż*3PďÇLÚŻ*Ćóž5ěÎŔâLöŢ+.ßVĺ>;ĺĚNř.M*Čź B22.Ëźň0Čť>.:ŔĎ˝ž-1,žč,ÎAU7ăS/š÷Ô=GĆW.´Ż9EDŔ?śMŔóÍÉ>6űÜśÔŰF/ŕR+çEIZňŮč:÷00Đŕ ÄܡúEB×Ýź´*çNJC8*Ę×ôë90MŻNžÍŕÇHťË<śýőýUéÖčÜűÜÇXK*=Őż;šüÉM/<ÚR-ůýIľ3á/Zč7TśíB öďäÍIľź,ÁőąČĆąQÔäGÂI,đ×čćčř;ÇľGçżęL:E2śüđNžŢöý˝ůśĘ,/áöĹTJČD.žCťň+*ĘQJůŮ:ĆÎB8 βŻ8ŢCč*îÝőO4.2Kä96ßÎŢăGâYGˇżJĚA¸C2ŕÚŔÉ;JJôȡó-ĐBĆF×Ďľ8ý0PôŐÍ7JD3R0A8PÁ*/śś8 :JřßJJ:ŇĆSQQĐ*żĚ×ĺ:Jťĺš<é?Nľ.âGßZçčćäř;Éľ GçżęL:E2śťŔĆšÝôý˝ˇB3šôŔćĂTÖSâë56-IÉ2-žđ@ŻĺźSFJçŕFžĺŕüý˝>ťëŃAé°GL+:őđ8ĐŐĚÚJ:ĺ 5Ű6.Ż8ŕZĐ6-ď.ŻZéOý=7źň-ŔÝžF×Ďľ8ý0PôŐÍ7JDSSäÔĐ=ˇOęĘ×6*.ÉÚQUM5éĹęÜóö0đI2ĎżšC*Ţ 20:ÚŻÂT.ř*ůßěą3Ż*2ÁőýýˇIç÷ˇ*ZüŔ7Âť3ĹRîň8ĐŐĚÚJ:ĺ5Ű5.M˝ÖĚZ+0˛éVüQL*+óű˝´ŇMß:Ăż âÇ7ťńöľZ°˝űę*ĐÇȰ´?GÇULIBéüĆAĎľGÜżú1,*6źIÖ-ßYŢĂK.,Ę-ÚZ*Ţýŕ+ĚşžűYV1ŔĐÇą>*úYëK ř/Ç5.đşĎUOB,:Rć1/*ČľPKPÁ3.:JşÝ20M˝@2ǡ°MíFü7ĘęYIšŢĎ+žĘžZUéÖëBęÉÄôüWĹľ:ýż27ÚÉ +*ÄZ*ß7áĂT.,Ę-Â+*6żďžšF*4Zýý˝őAVJýéÖČü˝řQB:2îň8ĐŐĚÚJ:ĺ5Ű5.ąÝŐ4ť+0ŢúË2ĆZF-+.ß ł14ż*J:ąF:M´ňËáÝżÇűóą1FD*ćRGç0,ÖŢćNŃ-×ĂJ´:îř.;QYěýýđî<ôę=ĎšĎ4ż*ń*Ż*RX>ôęAĂ-J C,ëEIóŔ/î˝2ą÷ůH6::TÝJŔÉšĆܸđ,żFYň°:â˛:ľB;6žÖéŢI:žÖÉJýXB<âÄó3íLźöÔRřĐ+¸Ó°řUÄ< TĂáEĆýJFýł:JZúýÝť6PżŔŻôYŇL:ŢFJ6žŮÍ/ż.Ŕ,üýĹËß2Îżđ/5Ţýąż2*°BJ2Tś:,Qő:ťóâ/,ˇÜćă J*üĎAA>:6*2ÄG6+ÂöÚDÂ.×Ďľöů0PDóăšÓ°řUÄNą7ľB++úĺYÁőČ*îGN ńč:<âÄ7řč°ćŇUYÜU?Ńݰ>ĎTFÜżó7.ČńĚű<¸ŮšĂŇB=ßřĺO4äźY?6íZŔ+öÍňĐ5F:ÇÔH5Ä.×Ďľöů0PD óăšÓ°řUÄę°˝šŐĆ4ą ĎTFÜżXę×ٸÇZűőWšůKĹKÂę:;ÝłÚżÇPť÷XÓĘüČĎÂTďö0ŕ5řÎ*<éËM3ÖőÁHŕÄűÎá:ŕČřđ0PÔűKUěÔŐ ß*5ĘĎÂTĎĎA@ÍúVůK9ŻáG¸J*,KĆćD0*ä@;*6ß*2žJ/<ŘÜç*U7/,¸+0ěF:+L4ýýÍŇ3;JÁä5Ë**ŕ8T4 Xę*ýő8Ŕůýý×1,Úś.ßRM2+ýýíŮ6+°şIRĹBžEżś´:ľĂĐG;űÇ2Ţ,Ý?Ë8˛SUPZIšśĎG<ęG¸ś*,ëľĂžÍű Ô*Nł*6802;*U9łž3ŕĺHÝ*-9O>ýŘLüýŐŢ0ńQHę7LÂGĘ>ÚÖ+ýý˝BŔýý=Fôä;NDôă.RĆHůř<Ű*Áążśł :ľĂĐCëőË*Ţ,Ý?Ë8˛SUPZIˇÜćôňóĘ>8ŻáŰą2*ôY6žűýÝ@ČDŔ4+÷ýýĂ0B.ňýšI0śJÁP8ʲą9;ŕĂEÚÖ +ýý˝ą7ú÷áBűä;*ű-Pž2Úýő8ß/BĆýý9/ŕÓżÚ?Čä˛Ýľ,*5úÔ˛¸ÎOWCżűâöLůŃŐÉŢś<+őÂîć*ĘÂ×úç1 -Fę*ÁŢű˝őá*Ţú+ABí<ó¸ř0Q´JýýĹą?SGő8Ďş:,+:>1*ůM,ľ,ďîJ̸ăůĹž7Oőó8˛ňűâőL;+éůóąÓ ś?+őÂîć*ĘŔßňă/-Fę*-Â9˝źß*Hč@őâąűý˝Ę÷äÝÖŔ¸-żŢůË>ÚÖż2*Ů41ĚÔő8Żş*.ĂJîNýýéÖčÜŢćž Mżśś:1ðĂ0*% d 1123 57[1 0 0 1 0 0]sl 8 false 0 399 di /sl 64011 string uc îý51*,**ž˛¸ÎĎő=Ů5Ă->+V9ÜěÚŕĎYÚšÄßž5-ZDKR:B6îZ-şł>2Ô3öýIš5/+2ĐK.P-*;Wé7ĆH.*ĚN ßĂ7Â*:üB˛Â,Ú¸Âď+ĺWÄ*CÜýýÝČNRJśVďP:88âKĎşý0ÖČňPŃ-7ťIˇŰR>Ţ/+V9ÜěâŕĎYâú6ÂIMCšÁÇ ÉPˇâ?EËÄIě53çŻMٰH÷3A4-śM*éÁŐEŮśň53IÁ+*JNďŰßâOŻFđČËPá9őĂÂňÖĎWCÍúÚ.žóßéóYň7śŰ żÇë3ćĹ1ĂÂňÖĎWCÍúęF*°=ÇűéŢ7ĘâńÂíÝ0+QÚ:ĂGęă-ĚŰŕĎYâó6Őż:Nîž*<ČŔ/2ä7ĘęĚžźşRNNĹĹľÎ5ĎCAŔQîL;+éůóąÓś?+ˇ×K4?Ćľľ°ł ČŮL÷ü7Z?çËP1°5żPŃĚÚJ:Á5Ă/VĚťX,áÇ.âă0Ä8,?ÚÁ+.M7K/0**6ąé682*D1NžĆŕÓ.ÄŮ4.ňĚžžš1 ßűýýęKś99:âď6˛ÚZ,NTÂ*7D=ąČéX÷ü;ZMçťŰ-×ĂJřňÖ8LNXGˇżJ8AŘŰYI=ĂMęĆéC:*źô÷340:çÖA 1ĆßJč682*Ä<Č˝W;ă,JR>ß72ćZ.ýýQśę*+OLĹ˝îŢ/=J/Á÷=9@CŃÚ?Čőí*EÇX*:Ë8â@,çŃá¸2;ˇóâ/ ,ˇÜRT˝śŃüS=VX°ž*Úýő8KB*Î95:łĎ>FÚ;*ž:Fî*:*ŔRŔE:ÎËłîĺ9áň,,îÜśîž3ĘFBçääP=ľĂđűEŢ LěG9GHÜżNĎCÉ>ÚĐżWáóWłâ=I×ǸDąÇŔUDÖłÚÜÓÄşđ=ESĺ=.1čIłŔăO02*Iüú.Űś,ŃZBťˇ1ĘďJ+ ZŇWěÇĺTOZŔöďĺő2.ęTFśŘ@:ÎNřö18ÚR+FäEýŕ4<ŃÇŮL÷ü7Z;őĚĹ89íJÎRřŘQ˝WÔ2ż5Ĺž<ŘđQźVęJŢ+N4śśá-ą/ ľÄďŕ4ÚHKâŰYů˝AČÖ.CPŻĚĘÇQź°=ł0ZČPřňłČBďQŮäđI;ÎBÂŘľźéŘUó1ËMŻć˛;łńNÖܡúEBÇëÁźćí 5**řŔJĐçżęLîä4Úůýýë5öýÝ0Vűý˝ô<8NżÍGóIK3LýÍLąýá22AÚŻÂ<*ńM/N<ÄäĺH+*646+*ůń0Q8K NQŔóËáÝżÇÔžč 9Ň9ď´,*žÜ:Ʋ¸:Ů2ÚŮŔJ*:îLłä-Fť7ýÓĘÓńÝ0ZݸJö5śĐ.L-ÝŃłžýýAÔ-ßËEĘ2ŢăÉNććřž-08ě÷Ţ ×Ż>ä-üĂ3´@Čý×äňąâĘşđ=EĘ3*äQ+¡6Ď/?+ôÝť¸JPP8ĆN?žĆJźV*JâÇZťńöľZĐ?Îř-óá/>ő.żNŃ- ×ĂŢŰ?.,*71ÚűŢ-FÎÓśüÁC5ć˝ű9-őýýˇ9ÄA7:íJBÜV-üýÝÄÓňýŃ˝*ńQĘ+č8B6F*7Ať*˛FEÄCĹJŔ3* ŃL92üǰPH÷Ç7ä8.żîAîP<ňÖOËëýĺý*S8>*2RŕÉČ<8/KíFü7ʲ/ŇüJűĆĚIAU:çňJ´;śľ/ż*ĚZ<íúQ ÍřýÝžRGHŢ?čJ÷IM74ýńýđ@ŻĺH3ŰEO:âĂÂ3Ę*Ň<>4J2ą÷ůHó*äU.Z@ěúéČ28ś+1őşîâBĚV+č=ÂFťˇ K+˛?*Ě×°PH÷Ç7ä.*ńŃ*ŕFÄEÇ::Ö1,*í1ĆđJ+Â.őˇ?ŕG´ňËáÝżÇÔžč9Ň9ď´,*žÜ:Ʋ¸:Ů2ÚŮŔK*NR Á*?UÁ+žŔŢ*íV*ůýä+ĘüÍýŮ9PżŔŻô9?+CALZÓK?KĎ*Ě/L*2ČQB:2*Ç4;*ăěî*ŃR,ŔZ+1őşîâBĚV+đ Ý0,.ÄK+˛Ó2ü×°PH÷Ç7ä*ž;1řYďÔEÇ:2ć1,*ź1ĆđJ+â>ϡ?ŕG´ňËáÝżÇÔžč/?,ľĂ-ż*3śĐăŇŻÇÔŢš CżÂňöö0ô8W÷ŔÁVLDWäâ=I×ÇĐ-BĂ=ťřDOîź=3DTBőňOÄ46śM*ÚŘÄÓôëőË>QŔóËáÜżÇü>´:D6ą.:9< NŢ-ű÷I7JĆ÷ćçď7ęGŘĐ/1Ď3OHčÇÔ@Đ=ł0žźB22.Ëź>3Čť>.:ŔĎ96śM*úýňN4:ćCEQŔóËáÜżÇü>´Ĺ, žNřúˇé>=ŃÄOŘ,íă.<ĐááEÖš˛ă48.*Ćă÷PLH÷×´SHŕÄܡęEBçÍŕP,*Z˝;+N0*Ěá*Â>*BKEźÓ6+:P÷ ěTÄ3:;ËűĎ8Ű41,.ÇTÍ9ZđßZ2žŻ5÷,:ýýÝůłL:2:,ĐŰSäüFĎWőôű8â@,ËPGˇżJĚAŘMŔó7YŰżÇüň˛. -ž2ťťU,ĆR*°Ä+Ć:*DĹ´Ä**ÂT*JŐŇą.JK:ýýIˇ3O+JLRŢú12¸K-QFďR,ÜÇ-Ú,ŃńGśü/ťR*ÇóäĎ.Nň LEŃżMęÖł¸âR=ľĂĐ77J@Á2ĹďR2DýýI˝6*öňýýË-ΞźćÄßßËIăS*˛Y<*7ýá-ÚĘçúUá+:ę˝ú˝5*FÓĹ, ŢÔS+ýýÝ**ÁýŮIWBŔˇŕ3ą,G?*őďšő,ÇP1D,QÔ¸IšśĎG1+*θNżÔ0*áýýB8SŢâ*5+J+ĚS4ÇľEöÂô2**řŔJĐçżÄŢÇÓěĺ8X˛Ĺ.éEî¸-=W+ÓU¸. ľYđ>/*ÂúýíË5ÎŢü˝>*DÁýKEń,Ĺ4ž**ŢIZ°J0MCZA,śôDő6Ö**ťK:çňJMîâTőą1AŘM Ŕó7śŰżÇÔžčWS,;1JJ>žä,žń°*ZČ´0/8?*+*θNžÔ0*áýýB8SŢż9BđťÇ8EBć˛áG*ć5,ÇP1D,QÔ¸Iš śĎGçŻů42Î=őŃ?îóCÜRľ;VąHŻ.ä<.Î=őŃ?îóCÜRľ;VąHď<,ńĂ6÷QđŃťÝRľ;VąHď<,ńĂ6÷QđŃťÝRľ; VąHď<,=żFR*4OJ2Ä˝FžąŇ+Ţ˝ůá>R*á,-:˝ˇ%% d 1123 57[1 0 0 1 0 0]sl 8 false 0 456 di /sl 64011 string uc îýP+ž***ZYˇÎ*<ŻĺH3Űś*ĘĂűýýđ,-žÎŢ*ŐQ2ˇőéüýAć/;QIVŘýýOÖÔúÇ9šá*é9žÖ5+*J-ćá?ż˛.ž ňÎźęůø5ßDń3A;B3âż,Ţűý˝ěDL1ž÷Ţ*žŻBŢZúýYMFJ.žčRűý˝ô<Ŕ-ÂNđă+16Î-čM**ć,úśM:7+:ť 5ĐWĂ7ťV>š6Ę.đZPJö52GśĹ+ž˝ë*2ś;ůś÷<3DŘÜŻž8RÍÔĆŮäŇáěşĎěLÖäşŕO.P,ˇÎ*śýýÍŮÄćżß*ž ŻBŢZúýYMFJ.žćZüÄ3JëRż2ž50Öüř2**DžHX3NM*NíŔ˛UŻM95ă8-=żFR*ÉÖąÍÂXFŢZ*Ćšż+XÍ:đňă űýÍÎQđËýňSýýĺ°Ú÷Ő?ďÄ+¸Jť.**7J9Ő.Đ;*ĐÁřŻíAčW.éĘQÚÂŢN:14žL32Ŕ×91B6žôÁSÎZVZ*đÝ0 ,.Äď+ĚÎ0+TÔüýÍŇ3;*ăěE0öě>űĂÚRľ;VąHď<,=żFş:ľÜAşűTAčW.éĘQÚÂŢN:19âËő/YÝčø5ßDń3 A;B3âß-ˇńťßéŐ¸ĎěLÖäşŕO.ä5CđÍâQůźĎěLÖäşŕO.PEěQęĂ**ÎA.Đ;*ĐDzÔÁ×ĎĹĂ:6łÚRRB@B*÷É=+,áŢż5WžłĎ2ÎKń7-úRČüLXŇŮ2ôYFŻRĆ, BĂÚťż°Č,úýý,/;QIVŘJ+ÇĂűÇ:ŢNę×QLA8ZL*â/0*Kż+VÍ:đěŐűýýN5ÎÂÔúÇ9šá*IČĐÝĆ5ó@Ŕű5Q6 4Đ*ÚýýíÜžĐ*ýýÝÄčýýąA;B*ĘÝ3,âűý˝ěDXÂ*ŢB6*BŔ3ŕ+Xł+ç:ÇşˇŢ+-úRČüLXŇŮ2ôYFŻRRłćÇ-* +ĎMńM1RîN,.˝+ĹĘ*üA0*üÓ1QŘ*AYűĂÚRľ;VĺHŻTËÇć1,1č1ĚFžćZüä/Ě.+đüýIľ7AL* Z60*6ß.ď*ŐŘ:.*čÄ4Â*ÚZžőNçYâø5ßDô3ńčĘž:´Îş:2JJŇ81Î.=÷ä˝řŇ5>ś:.ś3šôÇćŰ2+:ő,- ÖHKâçÉůýýÇ@ŢVÚ÷Ő?ďÄ+ź>O˝;AčW.éÔQ6É;**VÁ2L041,+.K/=+ĆÎ0+TÔÜJż-Kž4OJ2äüĂ2Jůß>R B@B*÷Y-+,áöž5WžNĂ2ž°ő7-úRČüLXŇŮ2ÔSÍB<ą.ZENĆä9ô:1űUçYÂ*Ü0ŔłęőěĹ3<÷Á7ÚKůŘK5üý´ Ăďł:Vá´őÄÎ:ĂIňP@ë8ŰÜ0/ş7.éÖéŰ=?şýGöüĺAŰ;**š*žőÝĂíýú@=2*ŢC*ęÇ4Üý8şýńÉĎ3*žM*Ö; >şýGöüĺAU?**Q*ZIPöüšîűÍYäX**8*Ţ´Ć:W¸âé,í˝/Hôä+*-*š;ŔÓ:âHšďűńŕáęB,**žË*ß°.°ŃÝ öüťďY°6*ĆSöąö+ĺYĚ.26ýýľ9ĹSÎZ6ýR,Q3Â*>ÁĂ4;JŢĘźČ+Ă2=.JáÇ1*ü1ôJťYĐJž:ń+6M6K*Ĺ@ď J4Üý*şýńÉŕ/ÚHKâŰYůýÝFÍÂGšKňüý1ŢM;ľÍÎŔSâë5ż°Ě°Ţ˛K:**śň+AôJĎňłÍüŘVĹŔîä @page @vskip 0pt plus 1filll This manual documents Say for Speech Dispatcher, version @value{VERSION}. Copyright @copyright{} 2001, 2002, 2003, 2006 Brailcom, o.p.s. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". @end quotation @end titlepage @ifnottex @node Top, , (dir), (dir) This manual documents Say for Speech Dispatcher, version @value{VERSION}. Copyright @copyright{} 2001, 2002, 2003, 2006 Brailcom, o.p.s. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". @end quotation @end ifnottex @ifhtml @heading Say for Speech Dispatcher @end ifhtml @chapter General @code{spd-say} is a very simple client for Speech Dispatcher that takes some text from the command line and some simple parameters and passes them to Speech Dispatcher for synthesis. The resulting synthesized speech is then played on your speakers. It can also be used for stopping and cancelling speech on Speech Dispatcher. Usage: @code{spd-say [options] ["some text"]} @table @code @item -r or --rate Set the rate of the speech (between -100 and +100, default see below). @item -p or --pitch Set the pitch of the speech (between -100 and +100, default see below). @item -R or --pitch-range Set the pitch range of the speech (between -100 and +100, default see below). @item -i or --volume Set the volume (intensity) of the speech (between -100 and +100, default see below). @item -o or --output-module Set the output module. Default see below. @item -O or --list-output-modules List the output modules that are available with the current server. @item -I or --sound-icon Play the sound icon. @item -l or --language Set the language. The parameter is an iso language code, like @code{en} or @code{cs}. Default see below. @item -t or --voice-type Set the preferred voice type (male1, male2, male3, female1, female2, female3, child_male, child_female). @item -L or --list-synthesis-voices List the ''synthesis voices'' supported by an output module. If no -o option is supplied, -L displays the synthesis voices provided by the default output module. Otherwise, it displays the synthesis voices provided by the chosen module. @item -y or --synthesis-voice Set the synthesis voice. The synthesis voice is an attribute of the chosen synthesizer. Most users will probably not wish to set it, but this setting is provided for completeness. @item -m or --punctuation-mode Set the punctuation mode (none, some, all). Default see below. @item -s or --spelling Spell the message. @item -x or --ssml Set SSML mode on (default: off). The text contains SSML markup. @item -e or --pipe-mode Set pipe mode on (default: off). Reads text from stdin, writes to stdout, and also sends to Speech Dispatcher. @item -w or --wait Wait till the end of speaking the message. In this mode, spd-say returns only after the message is fully spoken on the speakers or after it gets discarded. @item -S or --stop Stop the previous message in Speech Dispatcher (regardless of the client who sent it and it's priority) before saying the specified message. If no message is specified, it just performs the stop function. @item -C or --cancel Similar to @code{-S}, but it stops (cancels) all the messages in all the queues in Speech Dispatcher. Use this for total stop of speech. @item -v or --version Print version and copyright info. @item -h or --help Print a short help message. @end table Defaults for rate, pitch, and volume are determined by @code{DefaultRate}, @code{DefaultPitch}, and @code{DefaultVolume} settings in the @code{speechd.conf} file. Factory defaults are 0, 0, and 100 respectively. The default language code is determined by the @code{DefaultLanguage} setting in the @code{speechd.conf} file. Factory default is @code{en} (English). The default output module is determined by the @code{LanguageDefaultModule} setting in the @code{speechd.conf} file. Factory default is @code{flite}. The default punctuation mode is determined by the @code{DefaultPunctuationMode} setting in the @code{speechd.conf} file. Factory default is @code{none}. @chapter Pipe Mode In pipe mode (option @code{--pipe-mode} or @code{-e}), spd-say reads text from stdin, writes to stdout, and also sends the text to Speech Dispatcher. Example: @example $ cat README | spd-say -e @end example If a line begins with the characters @emph{!-!}, the line is sent to Speech Dispatcher as a SSIP command. Example: @example $ spd-say --pipe-mode The quality of mercy is not strained. !-!SET SELF VOICE FEMALE1 It droppeth as the gentle rain from heaven Upon the place beneath: it is twice blest; !-!SET SELF RATE 50 It blesseth him that gives and him that takes. ^D @end example Note that each line of input is individually sent to Speech Dispatcher, therefore in the example above, the word @emph{heaven} is taken as the end of a sentence. It should be possible to use other text filtering utilities, such as @code{tr} or @code{fmt} to compensate. For example, the following command would clean up most cases: @example $ cat INSTALL | fmt -u -w 1500 | spd-say -e @end example If the text itself contains @emph{!-!}, just make sure it is not at the start of the line to prevent it from being interpreted as a SSIP command. The following sed command will do the job: @example $ cat myfile | sed -e 's/^!-!/ !-!/g' - | spd-say -e @end example The input is sent to Speech Dispatcher as fast as it will accept and queue it. To wait for each line to be spoken, use the @code{--wait} or @code{-w} option. Example: @example $ spd-say --pipe-mode -w This line is spoken and processing waits for speaking to finish before this line is sent to Speech Dispatcher. ^D @end example You can abort a long speech narative with the @code{--cancel} or @code{-C} option. @example $ spd-say -C @end example @bye @c speechd.texi ends here speech-dispatcher-0.9.1/doc/ssip.texi0000644000175000017500000020135213371163700014457 00000000000000\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename ssip.info @settitle Speech Synthesis Interface Protocol @finalout @c @setchapternewpage odd @c %**end of header @syncodeindex pg cp @syncodeindex fn cp @syncodeindex vr cp @dircategory Sound @dircategory Development @direntry * SSIP: (ssip). Speech Synthesis Interface Protocol. @end direntry @titlepage @title Speech Synthesis Interface Protocol @author Tom@'a@v{s} Cerha <@email{cerha@@freebsoft.org}> @author Hynek Hanke <@email{hanke@@freebsoft.org}> @author Milan Zamazal <@email{zamazal@@freebsoft.org}> @author @url{http://www.freebsoft.org} @page @vskip 0pt plus 1filll This manual documents Speech Synthesis Interface Protocol, version 0.2. Copyright @copyright{} 2001-2007 Brailcom, o.p.s., http://www.brailcom.cz . @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' @end quotation You can also (at your option) distribute this manual under the GNU General Public License: @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled ``GNU General Public License'' @end quotation @end titlepage @ifnottex @node Top, Introduction, (dir), (dir) This manual documents Speech Synthesis Interface Protocol, version 0.2. Copyright @copyright{} 2001, 2002, 2003 Brailcom, o.p.s., http://www.brailcom.cz . @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' @end quotation You can also (at your option) distribute this manual under the GNU General Public License: @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled ``GNU General Public License'' @end quotation Please contact us on @url{http://www.freebsoft.org} @end ifnottex @ifhtml @heading Menu @end ifhtml @contents @menu * Introduction:: * Basic Terminology:: * General Rules:: * SSIP Commands:: * Return Codes:: * Appendices:: * GNU Free Documentation License:: * GNU General Public Licence:: @end menu @node Introduction, Basic Terminology, Top, Top @chapter Introduction @menu * Purpose:: * Protocol Philosophy:: * Higher Level API:: @end menu @node Purpose, Protocol Philosophy, Introduction, Introduction @section Purpose Speech Synthesis Interface Protocol is a device independent layer for speech synthesis, developed with the goal of making the usage of speech synthesis easier for application programmers. It takes care of most of the output-related tasks necessary to solve in speech enabled applications. What is a very high level GUI library to graphics, Speech Synthesis Interface Protocol is to speech synthesis. Up to now, the applications that wanted to implement speech output had to handle all the device dependent aspects of communication with different speech synthesizers themselves. Speech Synthesis Interface Protocol (SSIP) aims to provide a totally independent abstract set of commands by which different applications can talk to some central Speech Server installed on the system that than talks to the synthesizers themselves. This way, user applications don't have to care about the particular synthesizers available on the system and the synthesizers don't have to care about the installed user applications. SSIP is not only a device independent language for speech synthesis related requests, but also a mechanism to coordinate the interaction and conflicts between different clients' needs in a central place in the system. Through the priority system, the central Speech Server that implements SSIP can decide which messages are considered the most important at any particular time and say them, while possibly supressing others. @node Protocol Philosophy, Higher Level API, Purpose, Introduction @section Protocol Philosophy Speech Synthesis Interface Protocol defines a reasonable subset of the different capabilities provided by the different synthesizers. It supports some basic events (message, key, character, ...) as well as changing the basic voice parameters (language, voice, rate, pitch, ...) or the more advanced ones (punctuation mode, spelling mode, ...). None of the commands or parameters of SSIP depends on the characteristics of the particular devices that are being used. For example when the client application wants to change the language for the next message, it only calls the appropriate SSIP command and it leaves the Speech Server to decide which synthesizer to use. SSIP was designed to allow multiple simultaneous connections to the server. A connection is identified by an identification string provided by the client application and an id number. Each connection with all its parameters is considered a closed space independent of the others, so that different clients can maintain different settings in their connections and then the Speech Server should take care of setting the right parameters on the synthesizer according to the origin of each request. One client can even establish several connections to maintain different contexts. SSIP also solves the issue when more than one client wants to speak at one time or when more messages come than it's possible to say. Each message has an assigned priority and according to this priority, when multiple messages come to the server, they are directly said, postponed or suppressed. It is important to understand the difference between SSIP and higher level protocols like SABLE, VoiceXML or SSML. Speech Synthesis Interface Protocol is not a markup language in which one would write a document. SSIP is rather the underlaying tool that the application would use to let you read and browse the documents encoded in either ordinary formats (like plain text, HTML, PDF) or the voice-enabled formats (SABLE, VoiceXML, SSML). These higher level protocols describe only how the document should be said, while SSIP is the means to actually do it on your system. In this manner, one of the supported formats of the messages you can send through SSIP is SSML. @node Higher Level API, , Protocol Philosophy, Introduction @section Higher Level API SSIP is the basic interface protocol that is being used in the communication of a client with the central Speech Server on a system. However, in many cases it may be more convenient for application programmers not to use SSIP directly (having to care about open socket connections etc.) but rather use an interface wrapper written in the specific programming language they use. There is no obstacle in SSIP for this option, and in fact, this approach is highly encouraged. This way, application programmers should finally be able to use such simple functions as speech_open(), speech_printf() and speech_set_rate() in their programs. We believe this can make writing new speech enabled applications a lot easier and allow programmers to make more of them. @node Basic Terminology, General Rules, Introduction, Top @chapter Basic Terminology @itemize @cindex SSIP @cindex Speech Synthesis Interface Protocol @item @emph{Speech Synthesis Interface Protocol} or @emph{SSIP} is the device-independent protocol described in this document through which client application can send their requests for speech synthesis to the Speech Server. @cindex Speech Server @item @emph{Speech Server} is the server application that implements Speech Synthesis Interface Protocol, as described in this document, and provides an interface for client applications. @cindex client @cindex client application @item @emph{Client} or @emph{client application} is every application that connects to Speech Server and talks to it through the Speech Synthesis Interface Protocol. In other words, this is the application that ``wants to speak''. @cindex message @item @emph{Message} is a chunk of text that a client sends to Speech Server to request saying something or play some sound. @item @emph{To cancel a message} means to stop saying it and/or remove it from the queue of messages waiting to be said. However, it is not removed from the history, where it was stored after being received by Speech Server. @end itemize @node General Rules, SSIP Commands, Basic Terminology, Top @chapter General Rules SSIP communicates with the clients through a defined set of text commands, in the usual manner for common Internet protocols. The characters sent through the Speech Synthesis Interface Protocol are encoded using the UTF-8 encoding. Each SSIP command, unless specified otherwise, consists of exactly one line. The line is sent in the following format: @example @var{command} @var{arg} ... @end example where @var{command} is a case insensitive command name and @var{arg}s are its arguments separated by spaces. The command arguments which come from a defined set of values are case insensitive as well. The number of arguments is dependent on the particular command and there can be commands having no arguments. All lines of SSIP input and output must be ended with a pair of carriage return and line feed characters, in that order. When you connect to Speech Server, you should at least set your client name, through the @code{SET SELF CLIENT_NAME} command (@pxref{Parameter Setting Commands}). This is important to get a proper identification of your client --- to allow managing it from the control center application and to identify it in a message history browser. You might want to set other connection parameters as well. Look for more details in @ref{Parameter Setting Commands}. An SSIP connection is preferably closed by issuing the @code{QUIT} command, see @ref{Other Commands}. SSIP is a synchronous protocol --- you send commands and only after a complete response from SSIP arrives back are you allowed to send the next command. Usually, the SSIP connection remains open during the whole run of the particular client application. If you close the connection and open it again, you must set all the previously set parameters again, SSIP doesn't store session parameters between connections. The protocol allows you to perform commands influencing other currently connected or previously connected clients. This allows you to write a control application managing or browsing all the messages received by the current Speech Server process. The mechanism is completely relaxed, there are no restrictions on managing some aspects of sound output for other users, however, there is a mechanism to prevent one user from seeing history messages of another user. Some of the commands (@ref{Speech Output Control Commands} and @ref{Parameter Setting Commands}) take an argument in the form: @example @{ @var{id} | all | self @} @end example where the value can be the @code{id} of the connection the command should be performed on (a positive number), the string @code{all} to act on all clients of this server or @code{self} to act on the connection itself. Unless you are writing a special client for managing Speech Server or unless you have specific needs, you should only use the @code{self} value for this argument. Not all parameter setting commands may receive all kinds of the first parameter defined above, for instance, some of them may receive only @code{self}. SSIP replies have the following format: @example @var{ccc}-line 1 @var{ccc}-line 2 ... @var{ccc}-line @var{n}-1 @var{ddd} line @var{n} @end example where @var{n} is a positive integer, and @var{ccc} and @var{ddd} are three-digit long numeric codes identifying the result of the command. The last line determines the overall result of the command. The result code is followed by an English message describing the result of the action in a human readable form. @node SSIP Commands, Return Codes, General Rules, Top @chapter SSIP Commands Commands recognized by SSIP can be divided into several groups: Speech synthesis and sound output commands, speech control commands, parameter setting commands, commands retrieving information about current client and server settings, commands handling the message history, and other commands. Each of these command groups is described in one of the following sections. In the command descriptions, the command is written together with its arguments. Optional arguments are enclosed by square brackets (@code{[} and @code{]}), alternatives are separated by the vertical rule (@code{|}) and are grouped within braces (@code{@{} and @code{@}}) or square brackets for mandatory or optional arguments respectively. Literal argument values are typeset in lowercase letters (they are case insensitive), and variable arguments are typeset @var{like this}. Ellipsis denoted by three dots (@code{...}) means repetition (zero or more times) of all the arguments within the current brackets. @menu * Speech Synthesis and Sound Output Commands:: * Speech Output Control Commands:: * Message Priority Commands:: * Blocks of Messages Commands:: * Parameter Setting Commands:: * Information Retrieval Commands:: * Message Events Notification and Index Marking:: * History Handling Commands:: * Other Commands:: @end menu @node Speech Synthesis and Sound Output Commands, Speech Output Control Commands, SSIP Commands, SSIP Commands @section Speech Synthesis and Sound Output These commands invoke actual output to particular output device. The particular way how the message is handled depends on current speech parameter settings and user configuration. @table @code @item SPEAK @anchor{SPEAK} Start receiving a text message and synthesize it. After sending a reply to the command, Speech Server waits for the text of the message. The text can spread over any number of lines and is finished by an end of line marker followed by the line containing the single character @code{.} (dot). Thus the complete character sequence closing the input text is @code{CR LF . CR LF}. If any line within the sent text starts with a dot, an extra dot is prepended before it. During reception of the text message, Speech Server doesn't send responses for the lines sent. The response line is sent only immediately after the @code{SPEAK} command and after receiving the closing dot line. The content of the message can be either a plain text or a SSML (Speech Synthesis Markup Language) text. See @code{SET SELF SSML_MODE}. There is no guarantee that the SSML markup will be respected, so the application shouldn't rely on them. The external parameters can still be set by the parameter setting commands. SSML is intended only for additional markup inside the message. In SSML mode, each message must begin with @code{} and end with @code{}. Speech Server can start speech synthesis as soon as a sufficient amount of the text arrives; it generally needn't (but may) wait until the end of data marker is received. There is no explicit upper limit on the size of the text, but the server administrator may set one in the configuration or the limit can be enforced by available system resources. If the limit is exceeded, the whole text is accepted, but the excess is ignored and an error response code is returned after processing the final dot line. The reply takes the form @example 225-msg_id 225 OK MESSAGE QUEUED @end example where @var{msg_id} is a unique id assigned to this message in Speech Server. This is useful for the @ref{History Handling Commands} commands as well as for @ref{Message Events Notification and Index Marking}. The @code{SPEAK} command might be used for example in this way: @example SPEAK 230 OK RECEIVING DATA hi . 225-21 225 OK MESSAGE QUEUED @end example @item CHAR @var{char} Speak letter @var{char}. @var{char} can be any character representable by the UTF-8 encoding. The only exception is the character space (@code{ }); that can't be sent directly. In this case, a string @code{space} must be sent instead. @example CHAR e CHAR \ CHAR space CHAR & @end example This command is intended to be used for speaking single letters, e.g. when reading a character under cursor or when spelling words. @item KEY @var{key-name} @anchor{SSIP KEY} Speak key identified by @var{key-name}. The command is intended to be used for speaking keys pressed by the user. @var{key-name} is a case sensitive symbolic key name. It is composed of a key name, optionally prepended with one or more prefixes, each containing an auxiliary key name and the underscore character. Key name may contain any character excluding control characters (for example, the characters in the range 0 to 31 in the ASCII table, characters in the range 128 to 159 in the Latin-* tables and other ``invisible'' characters), spaces, underscores, and double quotes. The recognized key names are: @itemize @item Any single UTF-8 character, excluding the exceptions defined above. @item Any of the symbolic key names defined in @ref{Key Names}. @end itemize Examples of valid key names: @example a A shift_a shift_A @'{u} $ enter shift_kp-enter control_alt_delete control @end example @item SOUND_ICON @var{icon-name} @anchor{SSIP SOUND_ICON} Send a sound identified by @var{icon-name} to the audio output. @var{icon-name} is a symbolic name of the given sound from the standard set listed in @ref{Standard Sound Icons}, or another name from the particular Speech Server sound icon configuration. @end table @node Speech Output Control Commands, Message Priority Commands, Speech Synthesis and Sound Output Commands, SSIP Commands @section Controlling Speech Output These commands can stop or resume speech or audio output. They all affect only the synthesis process and output to a sound device, they do not affect the message history. @table @code @item STOP @{ @var{id} | all | self @} Immediately stop outputting the current message (whatever it is --- text, letter, key, or sound icon) from the identified client, if any is being output. If the command argument is @code{self}, the last message from the current client connection is stopped. If it is @code{all}, stop currently output message or messages from all the clients. Otherwise, argument @var{id} must be given as a positive integer and the currently processed message from the client connection identified by @var{id} is stopped; if there is none such, do nothing. @item CANCEL @{ @var{id} | all | self @} This command is the same as @code{STOP}, with the exception that it stops as yet unspoken output messages as well. All currently queued messages are stored into the message history without being sent to the audio output device. @item PAUSE @{ @var{id} | all | self @} Stop audio output immediately, but do not discard anything. All the currently speaking and currently or later queued messages are postponed and saved for later processing, until a corresponding @code{RESUME} command is received. The meaning of the command arguments is the same as in the @code{STOP} command. @item RESUME @{ @var{id} | all | self @} Cancel the effect of the previously issued @code{PAUSE} command. Note that messages of the priority ``progress'' and ``notification'' received during the pause are not output (but they remain stored in the message history). It is an error to send the @code{RESUME} command when the output corresponding to the given argument is not paused by a previous invocation of the @code{PAUSE} command. Such an error is signaled by a @code{4XX} return code. The meaning of the command arguments is the same as in the @code{STOP} command. @end table @node Message Priority Commands, Blocks of Messages Commands, Speech Output Control Commands, SSIP Commands @section Priority Setting Commands @cindex priorities A speech synthesizer can't synthesize everything that comes to it, for the simple reason that messages are often coming faster than a synthetic voice can say them. On the screen of a monitor, there is relatively a lot of space compared to one-channel speech synthesis output. For this reason, SSIP implements a system of several priorities targeted at different types of messages. The idea is that the task of the programmer of a client application is only to assign a meaningful priority to each message and all the synchronization and switching between the messages (that can be coming from different clients) is automatically handled by the Speech Server by applying certain rules based on the priorities. @menu * Priority Categories:: What are the available priorities. * Priority Diagram:: Schematic diagram of used priority model. * Priority Setting Commands:: * Examples of Using Priorities:: A few examples of using the priorities. @end menu @node Priority Categories, Priority Diagram, Message Priority Commands, Message Priority Commands @subsection Priority Categories Speech Synthesis Interface Protocol provides a system of five priorities. Every message will either contain explicit priority information, or the default value will be used. Please see also the diagram below. @heading Priority @code{important} @cindex Priority important This message will be said immediately as it comes to server. It is never interrupted. When several concurrent messages of this priority are received by server, they are queued and said in the order they came. When a new message of level @code{important} comes while a message of another priority is being spoken, the other message is canceled and the message with priority @code{important} is said instead. Other messages of lower priorities are postponed (priority @code{message} and @code{text}) until there are no messages of priority important waiting, or are canceled (priority @code{notification} and @code{progress}). These messages should be as short as possible and should rarely be used, because they block the output of all other messages. @heading Priority @code{message} @cindex Priority message This message will be said when there is no message of priority @code{important} or @code{message} waiting in the queue. If there are, this message is postponed until those messages are spoken. This means that the priority @code{message} doesn't interrupt itself. If there are messages of priority @code{notification}, @code{progress} or @code{text} waiting in the queue or being spoken when a message of priority @code{message} comes, they are canceled. @heading Priority @code{text} @cindex Priority text This message will be said when there is no message of priority @code{important} or @code{message} waiting in the queue. If there are, this message is postponed until the previous messages are spoken. The priority text interrupts itself. This means that if several messages of this priority are received, they are not said in the order they were received, but only the latest of them is said; others are canceled. If there are messages of priority @code{notification} and @code{progress} waiting in the queue or being spoken when a message of priority @code{text} comes, they are canceled. @heading Priority @code{notification} This is a low priority message. If there are messages with priorities @code{important}, @code{message}, @code{text} or @code{progress} waiting in the queues or being spoken, this @code{notification} message is canceled. This priority interrupts itself, so if more messages with priority @code{notification} come at the same time, only the last of them is spoken. @heading Priority @code{progress} This is a special priority for messages that are coming shortly one after each other and they carry the information about some work in progress (e.g.@ @code{Completed 45%}). If new messages interrupted each other (see priority Notification), the user might not receive any complete message. This priority behaves the same as ``notification'' except for two things: @itemize @item The messages of this priority don't interrupt each other, instead, a newly arriving message is canceled if another message is being spoken. @item Speech Server tries to detect the last message of a series of messages (for instance, it's important for the user to hear the final @code{Completed 100%} message to know the work has completed). Speech Server waits until there are no more messages of this priority waiting in queues and if the last of them wasn't spoken yet, it speaks it with the priority @code{message}. @end itemize This way, even if Speech Server is busy speaking messages of other priorities, we are still sure that the important messages at the end of the @code{progress} sequences will be said. @node Priority Diagram, Priority Setting Commands, Priority Categories, Message Priority Commands @subsection Priority Diagram @image{figures/priorities,,,Speech Synthesis Interface Protocol Priorities} @node Priority Setting Commands, Examples of Using Priorities, Priority Diagram, Message Priority Commands @subsection Priority Setting Commands When a priority is set for a given connection, all the newly arriving messages will be said with this priority until it is changed for a new value. @itemize @item SET self PRIORITY @var{p} This command sets message priority to @var{p}. @var{p} must be one of the values @code{important}, @code{text}, @code{message}, @code{notification}, @code{progress}. @xref{Priority Categories}. Only @code{self} is allowed as the `target' argument. @end itemize @node Examples of Using Priorities, , Priority Setting Commands, Message Priority Commands @subsection Examples of Using Priorities Example uses for priority @code{important} are: @itemize @item error messages @item very important messages @item ... @end itemize Example uses for priority @code{message} are: @itemize @item regular program messages @item warnings @item ... @end itemize Example uses for priority @code{text} are: @itemize @item text the user is working on @item menu items @item ... @end itemize Example uses for priority @code{notification} are: @itemize @item less important status information @item letters when typing input @item run-time help @item ... @end itemize Example uses for level @code{progress} are: @itemize @item ``completed 15%'', ``completed 16%'', ``completed 17%'' @item ``Loading sounds'', ``Loading graphics'', ``Loading ai'', ... @end itemize @node Blocks of Messages Commands, Parameter Setting Commands, Message Priority Commands, SSIP Commands @section Blocks of Messages Commands Block commands allow the client to concatenate several messages to form one block that behaves as one message in the priority system and history. After opening the block, client can send a specified subset of the commands and the messages introduced by @code{SPEAK} will be processed immediately, however there will be no priority interaction before closing the block. The @ref{Speech Output Control Commands} also handle the whole block as one message. Take for example this message from an email client: @example > Hi, how are you? I'm fine. Thank you. @end example The character `>' clearly marks who said which part. So it'd be nice to say the two lines with different voices, however, it'd be desirable to treat it all as one message with priority TEXT and have it put together in history, because in fact, it logically @emph{is} one message. @table @code @item BLOCK BEGIN Opens a block of messages. There will be no priority interaction between the messages inside the block, the whole block will be treated as one message of the priority that was specified by previous @code{SET} command. It can only be called outside of a block; nesting is not allowed. @itemize The allowed commands inside a block are: @item @code{SPEAK} @item @code{SOUND_ICON} @item @code{CHAR} @item @code{KEY} @item @code{SET SELF RATE} @item @code{SET SELF PITCH} @item @code{SET SELF VOLUME} @item @code{SET SELF VOICE} @item @code{SET SELF LANGUAGE} @item @code{SET SELF PUNCTUATION} @item @code{SET SELF CAP_LET_RECOGN} @item @code{QUIT} @item @code{BLOCK END} @end itemize @item BLOCK END Closes a block of messages, see @code{BLOCK BEGIN}. It can be only called inside a block opened by @code{BLOCK BEGIN}; nesting is not allowed. @end table A more complete example of SSIP communication using BLOCKs. @example [...] SET SELF PRIORITY TEXT 202 OK PRIORITY SET BLOCK BEGIN 260 OK INSIDE BLOCK SET SELF VOICE MALE1 209 OK VOICE SET SPEAK 230 OK RECEIVING DATA The word 225 OK MESSAGE QUEUED SET SELF VOICE MALE2 209 OK VOICE SET SPEAK 230 OK RECEIVING DATA `Free' 225 OK MESSAGE QUEUED SET SELF VOICE MALE1 209 OK VOICE SET SPEAK 230 OK RECEIVING DATA in Free Software refers to freedom, not price. 225 OK MESSAGE QUEUED BLOCK END 261 OK OUTSIDE BLOCK @end example @node Parameter Setting Commands, Information Retrieval Commands, Blocks of Messages Commands, SSIP Commands @section Parameter Setting The @code{SET} command sets various control parameters of the synthesized speech or server configuration. The parameter is always denoted by the second command argument. All the settings take effect on the connections specified in the first argument (@pxref{General Rules}) and until the parameter setting is changed by another invocation of the appropriate @code{SET} command or until the connection is closed. The voice property and TTS-processing settings can sometimes be without any real effect if the end synthesizer doesn't provide the required functionality. This is not considered an error in the implementation of SSIP. @table @code @item SET self CLIENT_NAME @var{user}:@var{client}:@var{component} Set client's name. Client name consists of the user name, client (application) identification, and the identification of the component of the client (application). Each of the parts of the client name may contain only alphanumeric characters, dashes (@code{-}) and underscores (@code{_}). For example, for a client called @code{lynx} that creates an SSIP connection for its command processing, the name could be set in the following way: @example SET CLIENT_NAME joe:lynx:cmd_processing @end example The client name is used in the server configuration settings, client listings and message history handling. All its three parts can be arbitrary, but it's important to define and follow rules for each application supporting Speech Synthesis Interface Protocol, so that a Speech Server user can configure all the aspects of the speech output easily. Usually, this command should be sent as the very first command when a new SSIP connection is established. The command may be sent only once within a single connection. Attempts to change the client's name once it's already set are answered with an error code. Only @code{self} is allowed as the `target' argument. @item SET all DEBUG @{ON|OFF@} If set to @code{ON}, Speech Dispatcher will write all its debugging information (including output modules) with maximal verbosity into a debug directory which is reported by the server to the client in reply to this command. When subsequently set to @code{OFF}, Speech Dispatcher will stop writing out debugging information into this path and close all the appropriate logging files. The intended use for this functionality is on-line debugging from client application. If the user wants to report a problem, the client application will ask him/her for a place to generate the logs, to repeat the situation that he/she considers to be a bug, and then perhaps it will automatically pack the logs and offer to send them to the developers of Speech Dispatcher or another appropriate place where the contained information can be processed. Warning: This option results in a lot of data being written into the output logs and so should not be left on for an unnecessarily long time. @example SET all DEBUG ON 262-/home/hanke/.cache/speech-dispatcher/log/debug 262 OK DEBUGGING SET @end example @item SET @{all | self | @var{id} @} OUTPUT_MODULE @var{module} Set the output module to @var{module}. This overrides the selection based on language. Only values returned by the @code{LIST OUTPUT_MODULES} command are permitted. @xref{list-output-modules}. @example SET self OUTPUT_MODULE espeak 216 OK OUTPUT MODULE SET @end example @item GET OUTPUT_MODULE Get the output module currently in use. This takes no parameters and simply returns the current output module. @example GET OUTPUT_MODULE 251-espeak 251 OK GET RETURNED @end example @item SET @{ all | self | @var{id} @} LANGUAGE @var{language-code} Set recommended language for this client according to @var{language-code}. @var{language-code} is the code of the language according to RFC 1766. For example, to set the preferred language to Czech, you send the following command: @example SET SELF LANGUAGE cs @end example Please note, that switching a language may require switching a voice, so this command may actually override a previous call to @code{SET VOICE} or @code{SET SYNTHESIS_VOICE}. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultLanguage} setting in the @code{speechd.conf} file. The factory default is @code{en} (English). @item SET @{self@} SSML_MODE @var{mode} Set the mode of the text received in the message body sent by the @code{SPEAK} command. This can be either a plain text, if @code{mode} is set to @code{off} or a SSML marked text, if @code{mode} is set to @code{on}. There is no guarantee that the SSML markup will be respected, so the application shouldn't rely on them. The external parameters can still be set by the parameter setting commands. SSML is intended only for additional markup inside the message. In SSML mode, each message must begin with @code{} and end with @code{}. For example a simple `hello world' looks like this: @example SET SELF SSML_MODE on SPEAK Hello world! . @end example @item SET @{ all | self | @var{id} @} PUNCTUATION @{ all | some | none @} Set punctuation mode to the given value. @code{all} means speak all punctuation characters, @code{none} means speak no punctuation characters, @code{some} means speak only punctuation characters set in the synthesizer's configuration. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultPunctuationMode} setting in the @code{speechd.conf} file. The factory default is @code{none}. @item SET @{ all | self | @var{id} @} SPELLING @{ on | off @} Switch spelling on or off. If spelling is set to on, all the incoming messages will be said letter-by-letter, instead of speaking them as whole words. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultSpelling} setting in the @code{speechd.conf} file. The factory default is @code{off}. @item SET @{ all | self | @var{id} @} CAP_LET_RECOGN @{ none | spell | icon @} Set capital letters recognition mode. @code{none} switches this feature off. @code{spell} causes capital letters to be spelled in the speech using the table set as @code{CAP_LET_RECOGN_TABLE}. With parameter @code{icon}, each capital letter will be preceeded by a sound icon (either sound or textual) specified by the user in his configuration. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultCapLetRecognition} setting in the @code{speechd.conf} file. The factory default is @code{none}. @item SET @{ all | self | @var{id} @} VOICE_TYPE @var{name} Set the voice identified by @var{name}. @var{name} must be one of the voice identifiers returned by the command @code{LIST VOICES} (@pxref{Information Retrieval Commands}). There is a standard set of voice identifiers defined in @ref{Standard Voices}. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultVoiceType} setting in the @code{speechd.conf} file. The factory default is @code{MALE1}. @item GET VOICE_TYPE Gets the current pre-defined voice. A list of voice identifiers can be obtained by the command @code{LIST VOICES} (@pxref{Information Retrieval Commands}). @example GET VOICE_TYPE 251-MALE1 251 OK GET RETURNED @end example @item SET @{ all | self | @var{id} @} SYNTHESIS_VOICE @var{name} Set the voice identified by @var{name}. @var{name} is a voice name recognized by the current synthesizer. It must be one of the names returned by the command @code{LIST SYNTHESIS_VOICES} run for the appropriate synthesizer. (@pxref{Information Retrieval Commands}). Please note, that switching to a particular voice may require switching a language, so this command may actually override a previous call to @code{SET LANGUAGE}. @item SET @{ all | self | @var{id} @} RATE @var{n} Set the rate of speech. @var{n} is an integer value within the range from -100 to 100, lower values meaning slower speech and higher values meaning faster speech. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultRate} setting in the @code{speechd.conf} file. The factory default is 0. @item GET RATE Get the current rate of speech value. @example GET RATE 251-10 251 OK GET RETURNED @end example @item SET @{ all | self | @var{id} @} PITCH @var{n} Set the pitch of speech. @var{n} is an integer value within the range from -100 to 100, lower values meaning lower pitch and higher values meaning higher pitch. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultPitch} setting in the @code{speechd.conf} file. The factory default is 0. @item GET PITCH Get the current pitch value. @example GET PITCH 251-10 251 OK GET RETURNED @end example @item SET @{ all | self | @var{id} @} VOLUME @var{n} Set the volume of speech. @var{n} is an integer value within the range from -100 to 100. lower values meaning lower volume and higher values meaning higher volume. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultVolume} setting in the @code{speechd.conf} file. The factory default is 100. @item GET VOLUME Get the current volume value. @example GET VOLUME 251-100 251 OK GET RETURNED @end example @item SET @{ all | self | @var{id} @} PAUSE_CONTEXT @var{n} Set the number of (more or less) sentences that should be repeated after a previously paused text is resumed. If there isn't enough text before the pause spot, the entire message is repeated. @var{n} is a positive integer value specifying the number of sentences to repeat. The default for the Speech Dispatcher implementation of SSIP is determined by the @code{DefaultPauseContext} setting in the @code{speechd.conf} file. The factory default is 0. @item SET @{ all | self | @var{id} @} HISTORY @{ on | off @} Enable (@code{on}) or disable (@code{off}) storing of received messages into history. This command is intended for use by message history browsers and usually should not be used by other kinds of clients. @end table @node Information Retrieval Commands, Message Events Notification and Index Marking, Parameter Setting Commands, SSIP Commands @section Retrieving Information The @code{LIST} command serves for retrieving information that can be presented to the user for selection of the values to the @code{SET} command. The information listed is selected according to the first argument of the @code{LIST} command. @table @code @anchor{list-output-modules} @item LIST OUTPUT_MOUDLES Lists the available output modules putting each module identification name one on a single line. Example: @example LIST OUTPUT_MODULES 250-festival 250-espeak 250 OK MODULE LIST SENT @end example @item LIST VOICES Lists the available symbolic voice names putting each voice name on a single line. These are symbolic names that are mapped to the real voices used in the synthesizer either automatically or via synthesizer or output module configuration. Example: @example LIST VOICES 249-MALE1 249-MALE2 249-MALE3 249-FEMALE1 249-FEMALE2 249-FEMALE3 249-CHILD_MALE 249-CHILD_FEMALE 249 OK VOICE LIST SENT @end example @item LIST SYNTHESIS_VOICES Lists the available voices for the current synthesizer in use. These names differ from those obtained by @code{LIST VOICES} in that they are names of the real voices used inside the synthesizer. This feature should only be used to allow the user to choose the voice. All automatic switching of voices (unless user-configurable) should be done using the symbolic voice names which can be configured in the synthesizer. Each voice name is listed on a separate line together with its language code and dialect identification string separated by tabs. The dialect identification strings do not have well-defined meaning yet. If no dialect is specified by the synthesizer, the value @code{none} is used. Example: @example LIST SYNTHESIS_VOICES 249-afrikaans af none 249-welsh-test cy none 249-german de none 249-greek_test el none 249-en-rhotic en r 249-lancashire en uk-north 249 OK VOICE LIST SENT @end example @end table @node Message Events Notification and Index Marking, History Handling Commands, Information Retrieval Commands, SSIP Commands @section Message Events Notification and Index Marking @menu * Why Events Notification:: * Types of Events:: * Events Notifications in SSIP:: * Switching Notifications On and Off:: @end menu @node Why Events Notification, Types of Events, Message Events Notification and Index Marking, Message Events Notification and Index Marking @subsection Why Events Notification Applications can send messages to a Speech Server through the SSIP @code{SPEAK} command. However, this command only puts the received message into a queue in Speech Server and returns immediately. The message then will or will not be said at some particular time according to its priority. Through Message Events Notification, the application is able to discover certain kind of events, including when the message started to be played on the speakers, when it terminated playing, when it was paused and resumed, or when it was interrupted/discarded. It is also possible to get notification when a certain place in the given text was reached while playing the synthesized text on the speakers -- this capability, however, might or might not be supported by the end synthesizer and so client applications should not rely on it. @node Types of Events, Events Notifications in SSIP, Why Events Notification, Message Events Notification and Index Marking @subsection Types of Events SSIP recognizes several types of events. Each event is reported together with the unique identification of the message and client it is associated with. This is an overview of available events. For detailed SSIP syntax, please look below. @table @code @item BEGIN This event means that the synthesizer just started to speak the message and the user is able to hear the speech on his/her speakers. Please note that not every message stored for speaking by the @code{SPEAK} command will issue this event. It can issue the @code{CANCEL} event instead. @item END This event means that the synthesizer just terminated speaking the message (by reaching its end) and the user is no longer able to hear the speech on their speakers. Again, note that not every message that has already reported the @code{BEGIN} event will necessarily get to the @code{END} event. It might instead issue the @code{CANCEL} or @code{PAUSE} events. @item CANCEL The @code{CANCEL} event is reported when the message was canceled (either after @code{BEGIN} during speaking or even before, when waiting in the queues) and will not be spoken anymore. @item PAUSE The event @code{PAUSE} means that the message that was being spoken was paused and no longer produces any sound on the speakers, but was not discarded and the rest of the message might be spoken again after the @code{RESUME} command is sent. @xref{Speech Output Control Commands}. This will be reported by the @code{RESUME} event. @code{PAUSE} is always preceded by the event @code{BEGIN}, and can be followed by either the event @code{RESUME} or @code{CANCEL}. @item RESUME The event @code{RESUME} means that a message that was paused while being spoken, just started to continue and again produces sound in the speakers. @code{RESUME} is always preceeded by the event @code{PAUSE}, and can be followed by either the event @code{END} or @code{CANCEL}. @item INDEX_MARK This event means that some previously specified place in the text (so-called index mark) was reached when speaking the synthesized message in the speakers. It is always accompanied by an additional parameter that indicates which place it is -- the name of the index mark. @end table Example (not in SSIP syntax): This SSML message @example Hello, how does it work? @end example would issue the following sequence of events if it is not discarded or paused: @example BEGIN INDEX_MARK "mark1" END @end example or this one if it gets paused after the first index mark and then later resumed. @example BEGIN INDEX_MARK "mark1" PAUSE RESUME END @end example @node Events Notifications in SSIP, Switching Notifications On and Off, Types of Events, Message Events Notification and Index Marking @subsection Events Notification in SSIP Event notifications, if requested, are reported asynchronously in SSIP. This means that they are not sent as replies to any particular requests but can arrive anytime. However, notifications can't arrive in the time between when a SSIP command is sent by the client and its reply is sent back by the server. Each notification consists of a multi-line SSIP reply as defined in @ref{General Rules}, and includes at least two parameters: @code{msg_id} and @code{client_id}. @code{msg_id} is the identification number of the message the event is related to, @ref{SPEAK} while @code{client_id} is the identification number of the client who sent the message. Some events may have additional parameters. @table @code @item INDEX_MARK @example 700-msg_id 700-client_id 700-index_mark 700 END @end example The event @code{INDEX_MARK} carries a special parameter @code{index_mark} which is a string of characters identifying the index mark, as specified by the client application (e.g. by the SSML tag . @item BEGIN @example 701-msg_id 701-client_id 701 BEGIN @end example @item END @example 702-msg_id 702-client_id 702 END @end example @item CANCEL @example 703-msg_id 703-client_id 703 CANCELED @end example @item PAUSE @example 704-msg_id 704-client_id 704 PAUSED @end example @item RESUME @example 705-msg_id 705-client_id 705 RESUMED @end example @end table @node Switching Notifications On and Off, , Events Notifications in SSIP, Message Events Notification and Index Marking @subsection Switching Notifications On and Off The client application might or might not want to receive the notifications about events, or it might want to receive some but not others. SSIP allows clients to specify which notifications are to be used. The following commands for setting notifications on and off affect all the text messages (sent by the @code{SPEAK} SSIP command) based on when the appropriate @code{SPEAK} command was called. So if for example, you set all notifications on, send a message and then set all notifications off, you will receive all the available notifications for that message even though it might start speaking after the notifications are already turned off. @table @code @item SET SELF NOTIFICATION ALL @{ on | off @} Set all available event notifications to either ``on'' or ``off'' for for the messages that follow. @xref{Types of Events}. @item SET SELF NOTIFICATION BEGIN @{ on | off @} @item SET SELF NOTIFICATION END @{ on | off @} Set the event notifications for @code{BEGIN} or @code{END} to either ``on'' or ``off'' for the messages that follow. @xref{Types of Events}. @item SET SELF NOTIFICATION CANCEL @{ on | off @} Set the event notifications for @code{CANCEL} to @code{mode} where @code{mode} is either ``on'' or ``off'' for switching the notifications on or off for the messages that follow. @xref{Types of Events}. @item SET SELF NOTIFICATION PAUSE @{ on | off @} @item SET SELF NOTIFICATION RESUME @{ on | off @} Set the event notifications for @code{PAUSE} or @code{RESUME} to @code{mode} where @code{mode} is either ``on'' or ``off'' for switching the notifications on or off for the messages that follow. @xref{Types of Events}. @item SET SELF NOTIFICATION INDEX_MARKS @{ on | off @} Set the event notifications for @code{INDEX_MARK} to either ``on'' or ``off'' for switching the notifications on or off for the messages that follow. @xref{Types of Events}. @end table @node History Handling Commands, Other Commands, Message Events Notification and Index Marking, SSIP Commands @section History Handling @menu * Purpose of Message History:: * Message History in SSIP:: @end menu @node Purpose of Message History, Message History in SSIP, History Handling Commands, History Handling Commands @subsection Purpose of Message History It seems a good feature for the blind and visually impaired to provide the possibility to browse, through some simple client, the history of received and previously said messages. Some messages are even received by Speech Server without being said, because there will always be more space for information on the screen than speech output can possibly provide. For this reason, SSIP defines a set of commands that allow client applications to browse through the history of previously received messages saved on the server. The idea is that @emph{each} message received by the server should be accessible through the history and the user can search for it later by time, keywords or using other methods. On the other hand, this may cause security issues as several clients may connect to Speech Server and they might originate from different users. For this reason, only those messages that come from the same user should be accessible by default (if not overridden in server configuration). @node Message History in SSIP, , Purpose of Message History, History Handling Commands @subsection Message History in SSIP History is handled by the @code{HISTORY} command. It can take many forms, described below, that allow browsing, retrieving and repeating stored messages. In each invocation of the @code{HISTORY} command there is no difference between processing spoken or not spoken messages, all the received messages are processed. The implementation of these history commands in the Speech Dispatcher implementation of SSIP is still under way. If you want to use them, please contact us to see the current status. There is a @dfn{history cursor} pointing to some message in the history. You can move it across history messages and retrieve the message the cursor is pointing to, using the @code{HISTORY CURSOR} set of command arguments described below. @table @code @item HISTORY GET CLIENT_LIST List known client names, their identifiers and status. Each connection is listed on a separate line in the following format: @example @var{id} @var{name} @var{status} @end example where @var{id} is a client id that can be used in other history handling requests or in the speech output control commands (@pxref{Speech Output Control Commands}), @var{name} is the client name as set through the @code{SET SELF CLIENT_NAME} command, and @var{status} is @code{1} for connected clients and @code{0} for disconnected clients. @var{id}s are unique within a single run of Speech Server. Sample SSIP reply: @example 240-0 joe:speechd_client:main 0 240-1 joe:speechd_client:status 0 240-2 unknown:unknown:unknown 1 240 OK CLIENTS LIST SENT @end example @item HISTORY GET CLIENT_ID Return id of the client itself. The id is listed on a separate line in the following format: @example @var{id} @end example Example: @example 200-123 200 OK CLIENT ID SENT @end example @item HISTORY GET CLIENT_MESSAGES @{ @var{id} | all | self @} @var{start} @var{number} List identifiers of messages sent by the client identified by @var{id}. If the special identifier @code{all} is used, identifiers of messages sent by all clients are listed; if the special identifier @code{self} is used, identifiers of messages sent by this client are listed. @var{number} of messages is listed, starting from the message numbered @var{start}. Both @var{number} and @var{start} must be positive integers. The first message is numbered 1, the second 2, etc. If the given range exceeds the range of available messages, no error is signaled and the given range is restricted to the available range of messages. Messages are sorted by the criterion used in the last client's invocation of the @code{HISTORY SORT} command. If no @code{HISTORY SET} has been invoked yet, the messages are sorted from the oldest to the newest, according to their time of arrival at Speech Server. Each message id is listed, together with other information, on a separate line, in the following format: @example @var{id} @var{client-id} @var{client-name} "@var{time}" @var{priority} "@var{intro}" @end example @var{client-id} is a numeric identifier of the client which sent the message, @var{client-name} is its name as set by the @code{SET SELF CLIENT_NAME} command (@pxref{Parameter Setting Commands}). @var{time} is the time of arrival of the message, in the fixed length @code{YYYY-MM-DD HH:MM:SS} format. @var{priority} is the priority of the message, one of the values accepted by the @code{SET SELF PRIORITY} command (@pxref{Parameter Setting Commands}). @var{intro} is the introductory part of the message of a certain maximum length, see the @code{HISTORY SET SHORT_MESSAGE_LENGTH} command. @var{intro} does not contain any double quotes nor the line feed character. All the message identifiers in the history, regardless of clients that issued them, are unique within a single run of Speech Server and remain unchanged. @item HISTORY GET LAST List the id of the last message sent by the client. The id is listed on a separate line of the following format: @example @var{id} @end example If the client hasn't sent any message yet, return an error code. @item HISTORY GET MESSAGE @var{id} Return the text of the history message identified by @var{id}. If @var{id} doesn't refer to any message, return an error code instead. The text is sent as a multi-line message, with no escaping or special transformation. An example SSIP response to the command: @example 200-Hello, world! 200-How are you? 200 OK MESSAGE SENT @end example @item HISTORY CURSOR GET Get the id of the message the history cursor is pointing to. The id is listed on a separate line. Sample SSIP reply to this command: @example 243-42 243 OK CURSOR POSITION RETURNED @end example @item HISTORY CURSOR SET @{ @var{id} | all | self @} @{ first | last | pos @var{n} @} Set the history cursor to the given position. The meaning of the first argument after @code{SET} is the same as in the @code{HISTORY GET CLIENT_MESSAGES} command. The argument @code{first} asks to set the cursor on the first position and the argument @code{last} asks to set the cursor on the last position of the history of the given client. If the argument @code{pos} is used, the position is set to @var{n}, where @var{n} is a positive integer. It is an error if @var{id} doesn't identify any client or if @var{n} doesn't point to any existing position in the history. As for the order and numbering of the messages in the history, the same rules apply as in @code{HISTORY GET CLIENT_MESSAGES}. See above. @item HISTORY CURSOR @{ forward | backward @} Move the cursor one position @code{forward}, resp. @code{backward}, within the messages of the client specified in the last @code{HISTORY CURSOR SET} command. If there is no next, resp. previous, message, don't move the cursor and return an error code. @item HISTORY SAY @var{id} Speak the message from history identified by @var{id}. If @var{id} doesn't refer to any message, return an error code instead. The message is spoken as it would be sent by its originating command (@code{SPEAK} or @code{SOUND_ICON}), but the @emph{current} settings (priority, etc.) apply. @item HISTORY SORT @{ asc | desc @} @{ time | user | client_name | priority | message_type @} Sort the messages in history according to the given criteria. If the second command argument is @code{asc}, sort in ascending order, if it is @code{desc}, sort in descending order. The third command argument specifies the message property to order by: @table @code @item time Time of arrival of the message. @item user User name. @item client_name Client name, excluding user name. @item priority Priority. @item message_type Type of the message (text, sound icon, character, key), in the order specified in the Speech Server configuration or by the @code{HISTORY SET MESSAGE_TYPE_ORDERING} command. @end table The sorting is stable --- order of all the messages that are equal in the given ordering remains the same. The sorting is specific to the given client connection, other connections are unaffected by invocation of this command. @item HISTORY SET SHORT_MESSAGE_LENGTH @var{length} Set the maximum length of short versions of history messages to @var{length} characters. @var{length} must be a non-negative integer. Short (truncated) versions of history messages are used e.g. in the answer to the @code{HISTORY GET CLIENT_MESSAGES} format. @item HISTORY SET MESSAGE_TYPE_ORDERING "@var{ordering}" Set the ordering of the message types, from the minimum to the maximum. @var{ordering} is a sequence of the following symbols, separated by spaces: @code{text}, @code{sound_icon}, @code{char}, @code{key}. The symbols are case insensitive and each of them must be present in @var{ordering} exactly once. The specified ordering can be used by the @code{HISTORY SORT} command. @item HISTORY SEARCH @{ @var{id} | all | self @} "@var{condition}" Return the list of history messages satisfying @var{condition}. The command allows searching messages by given words. The output format is the same as the @code{HISTORY GET CLIENT_MESSAGES} command. The meaning of the first argument after @code{SEARCH} is the same as the @code{HISTORY GET CLIENT_MESSAGES} command. @var{condition} is constructed according to the following grammar rules: @table @code @item @var{condition} :: @var{word} Matches messages containing @var{word}. @item @var{condition} :: ( ! @var{condition} ) Negation of the given condition. @item @var{condition} :: ( @var{condition} [ & @var{condition} ... ] ) Logical AND --- all the conditions must be satisfied. @item @var{condition} :: ( @var{condition} [ | @var{condition} ... ] ) Logical OR --- at least one of the conditions must be satisfied. @end table Spaces within the condition are insignificant and ignored. The following rules apply to @var{word}s: @itemize @minus @item @var{word} is a sequence of adjacent alphanumeric characters. @item If @var{word} contains any upper-case letter, the search for the word is case sensitive, otherwise it's case insensitive. @item @var{word} must match whole word, not only its substring. @item @var{word} can contain the wild card characters @code{?}, substituting any single alphanumeric character, and @code{*}, substituting any number (incl. zero) of alphanumeric characters. @end itemize Returned messages are sorted by the following rules: @enumerate @item The primary sorting is defined by the number of the satisfied subconditions on the top level of the given condition, from the highest (best matching messages first) to the lowest. This takes effect only if the given condition is the OR rule. @item The criterion used in the last client's invocation of the @code{HISTORY SORT} command. If no @code{HISTORY SORT} has been invoked yet, the messages are sorted from the oldest to the newest, according to their time of arrival. @end enumerate @end table @node Other Commands, , History Handling Commands, SSIP Commands @section Other Commands @table @code @item QUIT Close the connection. @item HELP Print a short list of all SSIP commands, as a multi-line message. @end table @node Return Codes, Appendices, SSIP Commands, Top @chapter Return Codes Each line of the SSIP output starts with a three-digit numeric code of the form @var{NXX} where @var{N} determines the result group and @var{xx} denotes the finer classification of the result. SSIP defines the following result groups: @table @var @item 1xx Informative response --- general information about the protocol, help messages. @item 2xx Operation was completely successful. @item 3xx Server error, problem on the server side. @item 4xx Client error, invalid arguments or parameters received. @item 5xx Client error, invalid command syntax, unparseable input. @item 7xx Event notifications. See @xref{Events Notifications in SSIP}. @end table Result groups @var{1xx} and @var{2xx} correspond to successful actions, other groups to unsuccessful actions. Only the groups defined here may be returned in an SSIP connection. Currently, for return codes in the range @code{100}--@code{599}, only the meaning of the first digit of the result code is defined. The last two digits are insignificant and can be of any value. Clients shouldn't rely on the unspecified digits in any way. However, the return codes in the range @code{700}--@code{800}, reserved for events notification, are well defined in the appropriate section of SSIP documentation and client applications can rely on them. In the future, these return codes should be fixed so that clients can rely on them. @menu * Sample SSIP Dialog:: @end menu @node Sample SSIP Dialog, , Return Codes, Return Codes @section Example of an SSIP Dialog The following example illustrates a sample dialog with SSIP. The client connects to a Speech Server, sets all the common parameters, sends two text messages, displays the list of clients, instructs Speech Server to repeat the second message, and closes the connection. Lines starting with a numeric code are response lines of the server, other lines are the lines sent by the client. @example SET SELF CLIENT_NAME joe:vi:default 208 OK CLIENT NAME SET SET SELF PRIORITY MESSAGE 202 OK PRIORITY SET SPEAK 230 OK RECEIVING DATA Hello, I'm am SSIP communication example! How are you? . 225 OK MESSAGE QUEUED SPEAK 230 OK RECEIVING DATA Still there? . 225 OK MESSAGE QUEUED HISTORY GET CLIENT_LIST 240-1 jim:Emacs:default 0 240-2 jim:Emacs:default 0 240-3 unknown:unknown:unknown 0 240-4 jim:Emacs:default 1 240-5 joe:vi:default 1 240 OK CLIENTS LIST SENT HISTORY GET LAST 242-39 joe:vi:default 242 OK LAST MSG SENT HISTORY SAY 39 225 OK MESSAGE QUEUED QUIT 231 HAPPY HACKING @end example @node Appendices, GNU Free Documentation License, Return Codes, Top @appendix Appendices @menu * Key Names:: List of the symbolic key names. * Standard Sound Icons:: List of the standard sound icon names. * Standard Voices:: @end menu @node Key Names, Standard Sound Icons, Appendices, Appendices @appendixsec Key Names This appendix defines all the recognized symbolic key names. The names are case sensitive. @subheading Special Key Names @table @code @item space @item underscore @item double-quote @end table @subheading Auxiliary Keys @table @code @item alt @item control @item hyper @item meta @item shift @item super @end table @subheading Control Character Keys @table @code @item backspace @item break @item delete @item down @item end @item enter @item escape @item f1 @item f2 @item f3 @item f4 @item f5 @item f6 @item f7 @item f8 @item f9 @item f10 @item f11 @item f12 @item f13 @item f14 @item f15 @item f16 @item f17 @item f18 @item f19 @item f20 @item f21 @item f22 @item f23 @item f24 @item home @item insert @item kp-* @item kp-+ @item kp-- @item kp-. @item kp-/ @item kp-0 @item kp-1 @item kp-2 @item kp-3 @item kp-4 @item kp-5 @item kp-6 @item kp-7 @item kp-8 @item kp-9 @item kp-enter @item left @item menu @item next @item num-lock @item pause @item print @item prior @item return @item right @item scroll-lock @item space @item tab @item up @item window @end table @node Standard Sound Icons, Standard Voices, Key Names, Appendices @appendixsec Standard Sound Icons There are none currently. @node Standard Voices, , Standard Sound Icons, Appendices @appendixsec Standard Voices The following voice names are always present in the output of the @code{LIST VOICES} command (@pxref{Information Retrieval Commands}): @table @code @item MALE1 @item MALE2 @item MALE3 @item FEMALE1 @item FEMALE2 @item FEMALE3 @item CHILD_MALE @item CHILD_FEMALE @end table The actual presence of any of these voices is not guaranteed. But the command @code{SET VOICE} (@pxref{Parameter Setting Commands}) must accept any of them. If the given voice is not available, it is mapped to another voice by the output module. @node GNU Free Documentation License, GNU General Public Licence, Appendices, Top @appendix GNU Free Documentation License @center Version 1.2, November 2002 @cindex FDL, GNU Free Documentation License @include fdl.texi @node GNU General Public Licence, , GNU Free Documentation License, Top @appendix GNU General Public License @center Version 2, June 1991 @cindex GNU General Public License @include gpl.texi @bye speech-dispatcher-0.9.1/doc/texinfo.tex0000644000175000017500000135240313423333357015016 00000000000000% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2018-02-12.17} % % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, % 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 % Free Software Foundation, Inc. % % This texinfo.tex file is free software: you can redistribute it and/or % modify it under the terms of the GNU General Public License as % published by the Free Software Foundation, either version 3 of the % License, or (at your option) any later version. % % This texinfo.tex file is distributed in the hope that it will be % useful, but WITHOUT ANY WARRANTY; without even the implied warranty % of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU % General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program. If not, see . % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. This Exception is an additional permission under section 7 % of the GNU General Public License, version 3 ("GPLv3"). % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % https://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or % https://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or % https://www.gnu.org/software/texinfo/ (the Texinfo home page) % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is https://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} % LaTeX's \typeout. This ensures that the messages it is used for % are identical in format to the corresponding ones from latex/pdflatex. \def\typeout{\immediate\write17}% \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexraggedright=\raggedright \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexsp=\sp \let\ptexstar=\* \let\ptexsup=\sup \let\ptext=\t \let\ptextop=\top {\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putworderror\undefined \gdef\putworderror{error}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Give the space character the catcode for a space. \def\spaceisspace{\catcode`\ =10\relax} % Likewise for ^^M, the end of line character. \def\endlineisspace{\catcode13=10\relax} \chardef\dashChar = `\- \chardef\slashChar = `\/ \chardef\underChar = `\_ % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script auto-ma-ti-cal-ly ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\thisisundefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % @errormsg{MSG}. Do the index-like expansions on MSG, but if things % aren't perfect, it's not the end of the world, being an error message, % after all. % \def\errormsg{\begingroup \indexnofonts \doerrormsg} \def\doerrormsg#1{\errmessage{#1}} % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % Output routine % % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt } % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Output a mark which sets \thischapter, \thissection and \thiscolor. % We dump everything together because we only have one kind of mark. % This works because we only use \botmark / \topmark, not \firstmark. % % A mark contains a subexpression of the \ifcase ... \fi construct. % \get*marks macros below extract the needed part using \ifcase. % % Another complication is to let the user choose whether \thischapter % (\thissection) refers to the chapter (section) in effect at the top % of a page, or that at the bottom of a page. % \domark is called twice inside \chapmacro, to add one % mark before the section break, and one after. % In the second call \prevchapterdefs is the same as \lastchapterdefs, % and \prevsectiondefs is the same as \lastsectiondefs. % Then if the page is not broken at the mark, some of the previous % section appears on the page, and we can get the name of this section % from \firstmark for @everyheadingmarks top. % @everyheadingmarks bottom uses \botmark. % % See page 260 of The TeXbook. \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 % 0: marks for @everyheadingmarks top \noexpand\or \the\toks4 \the\toks6 % 1: for @everyheadingmarks bottom \noexpand\else \the\toks8 % 2: color marks }% } % \gettopheadingmarks, \getbottomheadingmarks, % \getcolormarks - extract needed part of mark. % % \topmark doesn't work for the very first chapter (after the title % page or the contents), so we use \firstmark there -- this gets us % the mark with the chapter defs, unless the user sneaks in, e.g., % @setcolor (or @url, or @link, etc.) between @contents and the very % first @chapter. \def\gettopheadingmarks{% \ifcase0\topmark\fi \ifx\thischapter\empty \ifcase0\firstmark\fi \fi } \def\getbottomheadingmarks{\ifcase1\botmark\fi} \def\getcolormarks{\ifcase2\topmark\fi} % Avoid "undefined control sequence" errors. \def\lastchapterdefs{} \def\lastsectiondefs{} \def\lastsection{} \def\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\txipagewidth \newdimen\txipageheight % Main output routine. % \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. % \shipout a vbox for a single page, adding an optional header, footer, % cropmarks, and footnote. This also causes index entries for this page % to be written to the auxiliary files. % \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Common context changes for both heading and footing. % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \def\commmonheadfootline{\let\hsize=\txipagewidth \texinfochars} % % Retrieve the information for the headings from the marks in the page, % and call Plain TeX's \makeheadline and \makefootline, which use the % values in \headline and \footline. % % This is used to check if we are on the first page of a chapter. \ifcase1\topmark\fi \let\prevchaptername\thischaptername \ifcase0\firstmark\fi \let\curchaptername\thischaptername % \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi % \ifx\curchaptername\prevchaptername \let\thischapterheading\thischapter \else % \thischapterheading is the same as \thischapter except it is blank % for the first page of a chapter. This is to prevent the chapter name % being shown twice. \def\thischapterheading{}% \fi % \global\setbox\headlinebox = \vbox{\commmonheadfootline \makeheadline}% \global\setbox\footlinebox = \vbox{\commmonheadfootline \makefootline}% % {% % Set context for writing to auxiliary files like index files. % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. % We don't want .vr (or whatever) entries like this: % \entry{{\indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingyyy.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 24pt \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen % Main part of page, including any footnotes \def\pagebody#1{\vbox to\txipageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1\relax \unvbox#1\relax \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Argument parsing % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % For example, \def\foo{\parsearg\fooxxx}. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\argtorun{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. Also remove a @texinfoc % comment (see \scanmacro for details). Pass the result on to \argcheckspaces. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argremovetexinfoc #1\texinfoc\ArgTerm} \def\argremovetexinfoc#1\texinfoc#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurrence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \argtorun. % (Similarly, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} % \parseargdef - define a command taking an argument on the line % % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as environments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At run-time, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Environment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty outside of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal. \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\unskip\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on|off}% \fi\fi } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. \addgroupbox \prevdepth = \dimen1 \checkinserts } \def\addgroupbox{ % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \txipageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\txipageheight \page \fi \fi \box\groupbox } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. Not documented, written for gawk manual. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @include FILE -- \input text of FILE. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable % we want to expand any @value in FILE. \turnoffactive % and allow special characters in the expansion \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @include of #1^^J}% \edef\temp{\noexpand\input #1 }% % % This trickery is to read FILE outside of a group, in case it makes % definitions, etc. \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other \catcode`\`=\other \catcode`\'=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} % \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\centersub\centerH \else \let\centersub\centerV \fi \centersub{\hfil \ignorespaces#1\unskip \hfil}% \let\centersub\relax % don't let the definition persist, just in case } \def\centerH#1{{% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }} % \newcount\centerpenalty \def\centerV#1{% % The idea here is the same as in \startdefun, \cartouche, etc.: if % @center is the first thing after a section heading, we need to wipe % out the negative parskip inserted by \sectionheading, but still % prevent a page break here. \centerpenalty = \lastpenalty \ifnum\centerpenalty>10000 \vskip\parskip \fi \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi \line{\kern\leftskip #1\kern\rightskip}% } % @sp n outputs n lines of vertical space % \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment \def\c{\begingroup \catcode`\^^M=\active% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \cxxx} {\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}} % \let\comment\c % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent {\restorefirstparagraphindent \indent}% \gdef\noindent{\restorefirstparagraphindent \noindent}% \global\everypar = {\kern -\parindent \restorefirstparagraphindent}% } % \gdef\restorefirstparagraphindent{% \global\let\indent = \ptexindent \global\let\noindent = \ptexnoindent \global\everypar = {}% } % @refill is a no-op. \let\refill=\relax % @setfilename INFO-FILENAME - ignored \let\setfilename=\comment % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newbox\boxB \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % % For LuaTeX % \newif\iftxiuseunicodedestname \txiuseunicodedestnamefalse % For pdfTeX etc. \ifx\luatexversion\thisisundefined \else % Use Unicode destination names \txiuseunicodedestnametrue % Escape PDF strings with converting UTF-16 from UTF-8 \begingroup \catcode`\%=12 \directlua{ function UTF16oct(str) tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377') for c in string.utfvalues(str) do if c < 0x10000 then tex.sprint( string.format(string.char(0x5c) .. string.char(0x25) .. '03o' .. string.char(0x5c) .. string.char(0x25) .. '03o', (c / 256), (c % 256))) else c = c - 0x10000 local c_hi = c / 1024 + 0xd800 local c_lo = c % 1024 + 0xdc00 tex.sprint( string.format(string.char(0x5c) .. string.char(0x25) .. '03o' .. string.char(0x5c) .. string.char(0x25) .. '03o' .. string.char(0x5c) .. string.char(0x25) .. '03o' .. string.char(0x5c) .. string.char(0x25) .. '03o', (c_hi / 256), (c_hi % 256), (c_lo / 256), (c_lo % 256))) end end end } \endgroup \def\pdfescapestrutfsixteen#1{\directlua{UTF16oct('\luaescapestring{#1}')}} % Escape PDF strings without converting \begingroup \directlua{ function PDFescstr(str) for c in string.bytes(str) do if c <= 0x20 or c >= 0x80 or c == 0x28 or c == 0x29 or c == 0x5c then tex.sprint( string.format(string.char(0x5c) .. string.char(0x25) .. '03o', c)) else tex.sprint(string.char(c)) end end end } \endgroup \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}} \ifnum\luatexversion>84 % For LuaTeX >= 0.85 \def\pdfdest{\pdfextension dest} \let\pdfoutput\outputmode \def\pdfliteral{\pdfextension literal} \def\pdfcatalog{\pdfextension catalog} \def\pdftexversion{\numexpr\pdffeedback version\relax} \let\pdfximage\saveimageresource \let\pdfrefximage\useimageresource \let\pdflastximage\lastsavedimageresourceindex \def\pdfendlink{\pdfextension endlink\relax} \def\pdfoutline{\pdfextension outline} \def\pdfstartlink{\pdfextension startlink} \def\pdffontattr{\pdfextension fontattr} \def\pdfobj{\pdfextension obj} \def\pdflastobj{\numexpr\pdffeedback lastobj\relax} \let\pdfpagewidth\pagewidth \let\pdfpageheight\pageheight \edef\pdfhorigin{\pdfvariable horigin} \edef\pdfvorigin{\pdfvariable vorigin} \fi \fi % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as being undefined. \ifx\pdfoutput\thisisundefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % % See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and % related messages. The final outcome is that it is up to the TeX user % to double the backslashes and otherwise make the string valid, so % that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to % do this reliably, so we use it. % #1 is a control sequence in which to do the replacements, % which we \xdef. \def\txiescapepdf#1{% \ifx\pdfescapestring\thisisundefined % No primitive available; should we give a warning or log? % Many times it won't matter. \xdef#1{#1}% \else % The expandable \pdfescapestring primitive escapes parentheses, % backslashes, and other special chars. \xdef#1{\pdfescapestring{#1}}% \fi } \def\txiescapepdfutfsixteen#1{% \ifx\pdfescapestrutfsixteen\thisisundefined % No UTF-16 converting macro available. \txiescapepdf{#1}% \else \xdef#1{\pdfescapestrutfsixteen{#1}}% \fi } \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot be supported due to the design of the PDF format; use regular TeX (DVI output) for that.)} \ifpdf % % Color manipulation macros using ideas from pdfcolor.tex, % except using rgb instead of cmyk; the latter is said to render as a % very dark gray on-screen and a very dark halftone in print, instead % of actual black. The dark red here is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. We use % black by default, though. \def\rgbDarkRed{0.50 0.09 0.12} \def\rgbBlack{0 0 0} % % rg sets the color for filling (usual text, etc.); % RG sets the color for stroking (thin rules, e.g., normal _'s). \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\rgbBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % \pdfcatalog{/PageMode /UseOutlines} % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\dopdfimage#1#2#3{% \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % pdftex (and the PDF format) support .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\pdfimgext=\empty \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \errhelp = \nopdfimagehelp \errmessage{Could not find image file #1 for pdf}% \else \gdef\pdfimgext{JPG}% \fi \else \gdef\pdfimgext{jpeg}% \fi \else \gdef\pdfimgext{jpg}% \fi \else \gdef\pdfimgext{png}% \fi \else \gdef\pdfimgext{PDF}% \fi \else \gdef\pdfimgext{pdf}% \fi \closein 1 \endgroup % % without \immediate, ancient pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifdim \wd0 >0pt width \pdfimagewidth \fi \ifdim \wd2 >0pt height \pdfimageheight \fi \ifnum\pdftexversion<13 #1.\pdfimgext \else {#1.\pdfimgext}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} % \def\setpdfdestname#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \makevalueexpandable \turnoffactive \iftxiuseunicodedestname \ifx \declaredencoding \latone % Pass through Latin-1 characters. % LuaTeX with byte wise I/O converts Latin-1 characters to Unicode. \else \ifx \declaredencoding \utfeight % Pass through Unicode characters. \else % Use ASCII approximations in destination names. \passthroughcharsfalse \fi \fi \else % Use ASCII approximations in destination names. \passthroughcharsfalse \fi \def\pdfdestname{#1}% \txiescapepdf\pdfdestname }} % \def\setpdfoutlinetext#1{{% \indexnofonts \makevalueexpandable \turnoffactive \ifx \declaredencoding \latone % The PDF format can use an extended form of Latin-1 in bookmark % strings. See Appendix D of the PDF Reference, Sixth Edition, for % the "PDFDocEncoding". \passthroughcharstrue % Pass through Latin-1 characters. % LuaTeX: Convert to Unicode % pdfTeX: Use Latin-1 as PDFDocEncoding \def\pdfoutlinetext{#1}% \else \ifx \declaredencoding \utfeight \ifx\luatexversion\thisisundefined % For pdfTeX with UTF-8. % TODO: the PDF format can use UTF-16 in bookmark strings, % but the code for this isn't done yet. % Use ASCII approximations. \passthroughcharsfalse \def\pdfoutlinetext{#1}% \else % For LuaTeX with UTF-8. % Pass through Unicode characters for title texts. \passthroughcharstrue \def\pdfoutlinetext{#1}% \fi \else % For non-Latin-1 or non-UTF-8 encodings. % Use ASCII approximations. \passthroughcharsfalse \def\pdfoutlinetext{#1}% \fi \fi % LuaTeX: Convert to UTF-16 % pdfTeX: Use Latin-1 as PDFDocEncoding \txiescapepdfutfsixteen\pdfoutlinetext }} % \def\pdfmkdest#1{% \setpdfdestname{#1}% \safewhatsit{\pdfdest name{\pdfdestname} xyz}% } % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % % by default, use black for everything. \def\urlcolor{\rgbBlack} \def\linkcolor{\rgbBlack} \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \setpdfoutlinetext{#1} \setpdfdestname{#3} \ifx\pdfdestname\empty \def\pdfdestname{#4}% \fi % \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Read toc silently, to get counts of subentries for \pdfoutline. \def\partentry##1##2##3##4{}% ignore parts in the outlines \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % TODO this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Too % much work for too little return. Just use the ASCII equivalents % we use for the index sort strings. % \indexnofonts \setupdatafile % We can have normal brace characters in the PDF outlines, unlike % Texinfo index files. So set that up. \def\{{\lbracecharliteral}% \def\}{\rbracecharliteral}% \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } {\catcode`[=1 \catcode`]=2 \catcode`{=\other \catcode`}=\other \gdef\lbracecharliteral[{]% \gdef\rbracecharliteral[}]% ] % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \nextsp} \def\getfilename#1{% \filenamelength=0 % If we don't expand the argument now, \skipspaces will get % snagged on things like "@value{foo}". \edef\temp{#1}% \expandafter\skipspaces\temp|\relax } \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable % do we want to go so far as to use \indexnofonts instead of just % special-casing \var here? \def\var##1{##1}% % \leavevmode\setcolor{\urlcolor}% \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else % non-pdf mode \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\setcolor = \gobble \let\pdfsetcolor = \gobble \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput % % For XeTeX % \ifx\XeTeXrevision\thisisundefined \else % % XeTeX version check % \ifnum\strcmp{\the\XeTeXversion\XeTeXrevision}{0.99996}>-1 % TeX Live 2016 contains XeTeX 0.99996 and xdvipdfmx 20160307. % It can use the `dvipdfmx:config' special (from TeX Live SVN r40941). % For avoiding PDF destination name replacement, we use this special % instead of xdvipdfmx's command line option `-C 0x0010'. \special{dvipdfmx:config C 0x0010} % XeTeX 0.99995+ comes with xdvipdfmx 20160307+. % It can handle Unicode destination names for PDF. \txiuseunicodedestnametrue \else % XeTeX < 0.99996 (TeX Live < 2016) cannot use the % `dvipdfmx:config' special. % So for avoiding PDF destination name replacement, % xdvipdfmx's command line option `-C 0x0010' is necessary. % % XeTeX < 0.99995 can not handle Unicode destination names for PDF % because xdvipdfmx 20150315 has a UTF-16 conversion issue. % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753). \txiuseunicodedestnamefalse \fi % % Color support % \def\rgbDarkRed{0.50 0.09 0.12} \def\rgbBlack{0 0 0} % \def\pdfsetcolor#1{\special{pdf:scolor [#1]}} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\rgbBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % PDF outline support % % Emulate pdfTeX primitive \def\pdfdest name#1 xyz{% \special{pdf:dest (#1) [@thispage /XYZ @xpos @ypos null]}% } % \def\setpdfdestname#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \makevalueexpandable \turnoffactive \iftxiuseunicodedestname % Pass through Unicode characters. \else % Use ASCII approximations in destination names. \passthroughcharsfalse \fi \def\pdfdestname{#1}% \txiescapepdf\pdfdestname }} % \def\setpdfoutlinetext#1{{% \turnoffactive % Always use Unicode characters in title texts. \def\pdfoutlinetext{#1}% % For XeTeX, xdvipdfmx converts to UTF-16. % So we do not convert. \txiescapepdf\pdfoutlinetext }} % \def\pdfmkdest#1{% \setpdfdestname{#1}% \safewhatsit{\pdfdest name{\pdfdestname} xyz}% } % % by default, use black for everything. \def\urlcolor{\rgbBlack} \def\linkcolor{\rgbBlack} \def\endlink{\setcolor{\maincolor}\pdfendlink} % \def\dopdfoutline#1#2#3#4{% \setpdfoutlinetext{#1} \setpdfdestname{#3} \ifx\pdfdestname\empty \def\pdfdestname{#4}% \fi % \special{pdf:out [-] #2 << /Title (\pdfoutlinetext) /A << /S /GoTo /D (\pdfdestname) >> >> }% } % \def\pdfmakeoutlines{% \begingroup % % For XeTeX, counts of subentries are not necessary. % Therefore, we read toc only once. % % We use node names as destinations. \def\partentry##1##2##3##4{}% ignore parts in the outlines \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{1}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{2}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{3}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% \dopdfoutline{##1}{4}{##3}{##4}}% % \let\appentry\numchapentry% \let\appsecentry\numsecentry% \let\appsubsecentry\numsubsecentry% \let\appsubsubsecentry\numsubsubsecentry% \let\unnchapentry\numchapentry% \let\unnsecentry\numsecentry% \let\unnsubsecentry\numsubsecentry% \let\unnsubsubsecentry\numsubsubsecentry% % % For XeTeX, xdvipdfmx converts strings to UTF-16. % Therefore, the encoding and the language may not be considered. % \indexnofonts \setupdatafile % We can have normal brace characters in the PDF outlines, unlike % Texinfo index files. So set that up. \def\{{\lbracecharliteral}% \def\}{\rbracecharliteral}% \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } {\catcode`[=1 \catcode`]=2 \catcode`{=\other \catcode`}=\other \gdef\lbracecharliteral[{]% \gdef\rbracecharliteral[}]% ] \special{pdf:docview << /PageMode /UseOutlines >> } % ``\special{pdf:tounicode ...}'' is not necessary % because xdvipdfmx converts strings from UTF-8 to UTF-16 without it. % However, due to a UTF-16 conversion issue of xdvipdfmx 20150315, % ``\special{pdf:dest ...}'' cannot handle non-ASCII strings. % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753). % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \nextsp} \def\getfilename#1{% \filenamelength=0 % If we don't expand the argument now, \skipspaces will get % snagged on things like "@value{foo}". \edef\temp{#1}% \expandafter\skipspaces\temp|\relax } % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable % do we want to go so far as to use \indexnofonts instead of just % special-casing \var here? \def\var##1{##1}% % \leavevmode\setcolor{\urlcolor}% \special{pdf:bann << /Border [0 0 0] /Subtype /Link /A << /S /URI /URI (#1) >> >>}% \endgroup} \def\endlink{\setcolor{\maincolor}\special{pdf:eann}} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}% \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} % % % @image support % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\doxeteximage#1#2#3{% \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % XeTeX (and the PDF format) supports .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\xeteximgext=\empty \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \errmessage{Could not find image file #1 for XeTeX}% \else \gdef\xeteximgext{JPG}% \fi \else \gdef\xeteximgext{jpeg}% \fi \else \gdef\xeteximgext{jpg}% \fi \else \gdef\xeteximgext{png}% \fi \else \gdef\xeteximgext{PDF}% \fi \else \gdef\xeteximgext{pdf}% \fi \closein 1 \endgroup % \def\xetexpdfext{pdf}% \ifx\xeteximgext\xetexpdfext \XeTeXpdffile "#1".\xeteximgext "" \else \def\xetexpdfext{PDF}% \ifx\xeteximgext\xetexpdfext \XeTeXpdffile "#1".\xeteximgext "" \else \XeTeXpicfile "#1".\xeteximgext "" \fi \fi \ifdim \wd0 >0pt width \xeteximagewidth \fi \ifdim \wd2 >0pt height \xeteximageheight \fi \relax } \fi % \message{fonts,} % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % % can get a sort of poor man's double spacing by redefining this. \def\baselinefactor{1} % \newdimen\textleading \def\setleading#1{% \dimen0 = #1\relax \normalbaselineskip = \baselinefactor\dimen0 \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % PDF CMaps. See also LaTeX's t1.cmap. % % do nothing with this by default. \expandafter\let\csname cmapOT1\endcsname\gobble \expandafter\let\csname cmapOT1IT\endcsname\gobble \expandafter\let\csname cmapOT1TT\endcsname\gobble % if we are producing pdf, and we have \pdffontattr, then define cmaps. % (\pdffontattr was introduced many years ago, but people still run % older pdftex's; it's easy to conditionalize, so we do.) \ifpdf \ifx\pdffontattr\thisisundefined \else \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1-0) %%Title: (TeX-OT1-0 TeX OT1 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1) /Supplement 0 >> def /CMapName /TeX-OT1-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <23> <26> <0023> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 40 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1IT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1IT-0) %%Title: (TeX-OT1IT-0 TeX OT1IT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1IT) /Supplement 0 >> def /CMapName /TeX-OT1IT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <25> <26> <0025> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 42 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <23> <0023> <24> <00A3> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1IT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1TT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1TT-0) %%Title: (TeX-OT1TT-0 TeX OT1TT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1TT) /Supplement 0 >> def /CMapName /TeX-OT1TT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 5 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <21> <26> <0021> <28> <5F> <0028> <61> <7E> <0061> endbfrange 32 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <2191> <0C> <2193> <0D> <0027> <0E> <00A1> <0F> <00BF> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <20> <2423> <27> <2019> <60> <2018> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1TT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi % Set the font macro #1 to the font named \fontprefix#2. % #3 is the font's design size, #4 is a scale factor, #5 is the CMap % encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit). % Example: % #1 = \textrm % #2 = \rmshape % #3 = 10 % #4 = \mainmagstep % #5 = OT1 % \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% } % This is what gets called when #5 of \setfont is empty. \let\cmap\gobble % % (end of cmaps) % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\thisisundefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} % where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Definitions for a main text size of 11pt. (The default in Texinfo.) % \def\definetextfontsizexi{% % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1095} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1}{OT1} \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defsl\slshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\ttfont=\deftt \let\bffont = \defbf \let\ttslfont=\defttsl \let\slfont=\defsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for math mode superscripts (7pt). \def\sevennominalsize{7pt} \setfont\sevenrm\rmshape{7}{1000}{OT1} \setfont\seventt\ttshape{10}{700}{OT1TT} \setfont\sevenbf\bfshape{10}{700}{OT1} \setfont\sevenit\itshape{7}{1000}{OT1IT} \setfont\sevensl\slshape{10}{700}{OT1} \setfont\sevensf\sfshape{10}{700}{OT1} \setfont\sevensc\scshape{10}{700}{OT1} \setfont\seventtsl\ttslshape{10}{700}{OT1TT} \font\seveni=cmmi7 \font\sevensy=cmsy7 \def\sevenecsize{0700} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2}{OT1} \setfont\chapit\itbshape{10}{\magstep3}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep3}{OT1} \setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} \setfont\chapsf\sfbshape{17}{1000}{OT1} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3}{OT1} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 \def\chapecsize{1728} % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1}{OT1} \setfont\secrmnotbold\rmshape{12}{\magstep1}{OT1} \setfont\secit\itbshape{10}{\magstep2}{OT1IT} \setfont\secsl\slbshape{10}{\magstep2}{OT1} \setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\secsf\sfbshape{12}{\magstep1}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2}{OT1} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 \def\sececsize{1440} % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} \setfont\ssecit\itbshape{10}{1315}{OT1IT} \setfont\ssecsl\slbshape{10}{1315}{OT1} \setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} \setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315}{OT1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} % Reduced fonts for @acronym in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{1000}{OT1} \setfont\reducedit\itshape{10}{1000}{OT1IT} \setfont\reducedsl\slshape{10}{1000}{OT1} \setfont\reducedsf\sfshape{10}{1000}{OT1} \setfont\reducedsc\scshape{10}{1000}{OT1} \setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 \def\reducedecsize{1000} \textleading = 13.2pt % line spacing for 11pt CM \textfonts % reset the current fonts \rm } % end of 11pt text font size definitions, \definetextfontsizexi % Definitions to make the main text be 10pt Computer Modern, with % section, chapter, etc., sizes following suit. This is for the GNU % Press printing of the Emacs 22 manual. Maybe other manuals in the % future. Used with @smallbook, which sets the leading to 12pt. % \def\definetextfontsizex{% % Text fonts (10pt). \def\textnominalsize{10pt} \edef\mainmagstep{1000} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1000} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstephalf}{OT1} \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defsl\slshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\ttfont=\deftt \let\bffont = \defbf \let\slfont=\defsl \let\ttslfont=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for math mode superscripts (7pt). \def\sevennominalsize{7pt} \setfont\sevenrm\rmshape{7}{1000}{OT1} \setfont\seventt\ttshape{10}{700}{OT1TT} \setfont\sevenbf\bfshape{10}{700}{OT1} \setfont\sevenit\itshape{7}{1000}{OT1IT} \setfont\sevensl\slshape{10}{700}{OT1} \setfont\sevensf\sfshape{10}{700}{OT1} \setfont\sevensc\scshape{10}{700}{OT1} \setfont\seventtsl\ttslshape{10}{700}{OT1TT} \font\seveni=cmmi7 \font\sevensy=cmsy7 \def\sevenecsize{0700} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter fonts (14.4pt). \def\chapnominalsize{14pt} \setfont\chaprm\rmbshape{12}{\magstep1}{OT1} \setfont\chapit\itbshape{10}{\magstep2}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep2}{OT1} \setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\chapsf\sfbshape{12}{\magstep1}{OT1} \let\chapbf\chaprm \setfont\chapsc\scbshape{10}{\magstep2}{OT1} \font\chapi=cmmi12 scaled \magstep1 \font\chapsy=cmsy10 scaled \magstep2 \def\chapecsize{1440} % Section fonts (12pt). \def\secnominalsize{12pt} \setfont\secrm\rmbshape{12}{1000}{OT1} \setfont\secit\itbshape{10}{\magstep1}{OT1IT} \setfont\secsl\slbshape{10}{\magstep1}{OT1} \setfont\sectt\ttbshape{12}{1000}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} \setfont\secsf\sfbshape{12}{1000}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep1}{OT1} \font\seci=cmmi12 \font\secsy=cmsy10 scaled \magstep1 \def\sececsize{1200} % Subsection fonts (10pt). \def\ssecnominalsize{10pt} \setfont\ssecrm\rmbshape{10}{1000}{OT1} \setfont\ssecit\itbshape{10}{1000}{OT1IT} \setfont\ssecsl\slbshape{10}{1000}{OT1} \setfont\ssectt\ttbshape{10}{1000}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} \setfont\ssecsf\sfbshape{10}{1000}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1000}{OT1} \font\sseci=cmmi10 \font\ssecsy=cmsy10 \def\ssececsize{1000} % Reduced fonts for @acronym in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{900}{OT1} \setfont\reducedit\itshape{9}{1000}{OT1IT} \setfont\reducedsl\slshape{9}{1000}{OT1} \setfont\reducedsf\sfshape{9}{1000}{OT1} \setfont\reducedsc\scshape{10}{900}{OT1} \setfont\reducedttsl\ttslshape{10}{900}{OT1TT} \font\reducedi=cmmi9 \font\reducedsy=cmsy9 \def\reducedecsize{0900} \divide\parskip by 2 % reduce space between paragraphs \textleading = 12pt % line spacing for 10pt CM \textfonts % reset the current fonts \rm } % end of 10pt text font size definitions, \definetextfontsizex % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000}{OT1} \setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000}{OT1} \setfont\shortconttt\ttshape{12}{1000}{OT1TT} % We provide the user-level command % @fonttextsize 10 % (or 11) to redefine the text font size. pt is assumed. % \def\xiword{11} \def\xword{10} \def\xwordpt{10pt} % \parseargdef\fonttextsize{% \def\textsizearg{#1}% %\wlog{doing @fonttextsize \textsizearg}% % % Set \globaldefs so that documents can use this inside @tex, since % makeinfo 4.8 does not support it, but we need it nonetheless. % \begingroup \globaldefs=1 \ifx\textsizearg\xword \definetextfontsizex \else \ifx\textsizearg\xiword \definetextfontsizexi \else \errhelp=\EMsimple \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} \fi\fi \endgroup } % % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname #1font\endcsname % change the current font } \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. % We don't bother to reset \scriptscriptfont; awaiting user need. % \def\resetmathfonts{% \textfont0=\rmfont \textfont1=\ifont \textfont2=\syfont \textfont\itfam=\itfont \textfont\slfam=\slfont \textfont\bffam=\bffont \textfont\ttfam=\ttfont \textfont\sffam=\sffont % % Fonts for superscript. Note that the 7pt fonts are used regardless % of the current font size. \scriptfont0=\sevenrm \scriptfont1=\seveni \scriptfont2=\sevensy \scriptfont\itfam=\sevenit \scriptfont\slfam=\sevensl \scriptfont\bffam=\sevenbf \scriptfont\ttfam=\seventt \scriptfont\sffam=\sevensf } % % The font-changing commands (all called \...fonts) redefine the meanings % of \STYLEfont, instead of just \STYLE. We do this because \STYLE needs % to also set the current \fam for math mode. Our \STYLE (e.g., \rm) % commands hardwire \STYLEfont to set the current font. % % The fonts used for \ifont are for "math italics" (\itfont is for italics % in regular text). \syfont is also used in math mode only. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used % in, e.g., the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\assignfonts#1{% \expandafter\let\expandafter\rmfont\csname #1rm\endcsname \expandafter\let\expandafter\itfont\csname #1it\endcsname \expandafter\let\expandafter\slfont\csname #1sl\endcsname \expandafter\let\expandafter\bffont\csname #1bf\endcsname \expandafter\let\expandafter\ttfont\csname #1tt\endcsname \expandafter\let\expandafter\smallcaps\csname #1sc\endcsname \expandafter\let\expandafter\sffont \csname #1sf\endcsname \expandafter\let\expandafter\ifont \csname #1i\endcsname \expandafter\let\expandafter\syfont \csname #1sy\endcsname \expandafter\let\expandafter\ttslfont\csname #1ttsl\endcsname } \newif\ifrmisbold % Select smaller font size with the current style. Used to change font size % in, e.g., the LaTeX logo and acronyms. If we are using bold fonts for % normal roman text, also use bold fonts for roman text in the smaller size. \def\switchtolllsize{% \expandafter\assignfonts\expandafter{\lllsize}% \ifrmisbold \let\rmfont\bffont \fi \csname\curfontstyle\endcsname }% \def\switchtolsize{% \expandafter\assignfonts\expandafter{\lsize}% \ifrmisbold \let\rmfont\bffont \fi \csname\curfontstyle\endcsname }% \def\definefontsetatsize#1#2#3#4#5{% \expandafter\def\csname #1fonts\endcsname{% \def\curfontsize{#1}% \def\lsize{#2}\def\lllsize{#3}% \csname rmisbold#5\endcsname \assignfonts{#1}% \resetmathfonts \setleading{#4}% }} \definefontsetatsize{text} {reduced}{smaller}{\textleading}{false} \definefontsetatsize{title} {chap} {subsec} {27pt} {true} \definefontsetatsize{chap} {sec} {text} {19pt} {true} \definefontsetatsize{sec} {subsec} {reduced}{17pt} {true} \definefontsetatsize{ssec} {text} {small} {15pt} {true} \definefontsetatsize{reduced}{small} {smaller}{10.5pt}{false} \definefontsetatsize{small} {smaller}{smaller}{10.5pt}{false} \definefontsetatsize{smaller}{smaller}{smaller}{9.5pt} {false} \def\titlefont#1{{\titlefonts\rm #1}} \let\subsecfonts = \ssecfonts \let\subsubsecfonts = \ssecfonts % Define these just so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \definetextfontsizexi \message{markup,} % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Markup style infrastructure. \defmarkupstylesetup\INITMACRO will % define and register \INITMACRO to be called on markup style changes. % \INITMACRO can check \currentmarkupstyle for the innermost % style. \let\currentmarkupstyle\empty \def\setupmarkupstyle#1{% \def\currentmarkupstyle{#1}% \markupstylesetup } \let\markupstylesetup\empty \def\defmarkupstylesetup#1{% \expandafter\def\expandafter\markupstylesetup \expandafter{\markupstylesetup #1}% \def#1% } % Markup style setup for left and right quotes. \defmarkupstylesetup\markupsetuplq{% \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuplqdefault \else \temp \fi } \defmarkupstylesetup\markupsetuprq{% \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuprqdefault \else \temp \fi } { \catcode`\'=\active \catcode`\`=\active \gdef\markupsetuplqdefault{\let`\lq} \gdef\markupsetuprqdefault{\let'\rq} \gdef\markupsetcodequoteleft{\let`\codequoteleft} \gdef\markupsetcodequoteright{\let'\codequoteright} } \let\markupsetuplqcode \markupsetcodequoteleft \let\markupsetuprqcode \markupsetcodequoteright % \let\markupsetuplqexample \markupsetcodequoteleft \let\markupsetuprqexample \markupsetcodequoteright % \let\markupsetuplqkbd \markupsetcodequoteleft \let\markupsetuprqkbd \markupsetcodequoteright % \let\markupsetuplqsamp \markupsetcodequoteleft \let\markupsetuprqsamp \markupsetcodequoteright % \let\markupsetuplqverb \markupsetcodequoteleft \let\markupsetuprqverb \markupsetcodequoteright % \let\markupsetuplqverbatim \markupsetcodequoteleft \let\markupsetuprqverbatim \markupsetcodequoteright % Allow an option to not use regular directed right quote/apostrophe % (char 0x27), but instead the undirected quote from cmtt (char 0x0d). % The undirected quote is ugly, so don't make it the default, but it % works for pasting with more pdf viewers (at least evince), the % lilypond developers report. xpdf does work with the regular 0x27. % \def\codequoteright{% \ifmonospace \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax '% \else \char'15 \fi \else \char'15 \fi \else '% \fi } % % and a similar option for the left quote char vs. a grave accent. % Modern fonts display ASCII 0x60 as a grave accent, so some people like % the code environments to do likewise. % \def\codequoteleft{% \ifmonospace \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax % [Knuth] pp. 380,381,391 % \relax disables Spanish ligatures ?` and !` of \tt font. \relax`% \else \char'22 \fi \else \char'22 \fi \else \relax`% \fi } % Commands to set the quote options. % \parseargdef\codequoteundirected{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequoteundirected\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequoteundirected\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}% \fi\fi } % \parseargdef\codequotebacktick{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequotebacktick\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequotebacktick\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}% \fi\fi } % [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. \def\noligaturesquoteleft{\relax\lq} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Font commands. % #1 is the font command (\sl or \it), #2 is the text to slant. % If we are in a monospaced environment, however, 1) always use \ttsl, % and 2) do not add an italic correction. \def\dosmartslant#1#2{% \ifusingtt {{\ttsl #2}\let\next=\relax}% {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}% \next } \def\smartslanted{\dosmartslant\sl} \def\smartitalic{\dosmartslant\it} % Output an italic correction unless \next (presumed to be the following % character) is such as not to need one. \def\smartitaliccorrection{% \ifx\next,% \else\ifx\next-% \else\ifx\next.% \else\ifx\next\.% \else\ifx\next\comma% \else\ptexslash \fi\fi\fi\fi\fi \aftersmartic } % Unconditional use \ttsl, and no ic. @var is set to this for defuns. \def\ttslanted#1{{\ttsl #1}} % @cite is like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection} \def\aftersmartic{} \def\var#1{% \let\saveaftersmartic = \aftersmartic \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}% \smartslanted{#1}% } \let\i=\smartitalic \let\slanted=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font % @b, explicit bold. Also @strong. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\plainfrenchspacing{% \sfcode`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default % @t, explicit typewriter. \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } % @samp. \def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} % @indicateurl is \samp, that is, with quotes. \let\indicateurl=\samp % @code (and similar) prints in typewriter, but with spaces the same % size as normal in the surrounding text, without hyphenation, etc. % This is a subroutine for that. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \plainfrenchspacing #1% }% \null % reset spacefactor to 1000 } % We *must* turn on hyphenation at `-' and `_' in @code. % (But see \codedashfinish below.) % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. -- rms. { \catcode`\-=\active \catcode`\_=\active \catcode`\'=\active \catcode`\`=\active \global\let'=\rq \global\let`=\lq % default definitions % \global\def\code{\begingroup \setupmarkupstyle{code}% % The following should really be moved into \setupmarkupstyle handlers. \catcode\dashChar=\active \catcode\underChar=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\normaldash \let_\realunder \fi % Given -foo (with a single dash), we do not want to allow a break % after the hyphen. \global\let\codedashprev=\codedash % \codex } % \gdef\codedash{\futurelet\next\codedashfinish} \gdef\codedashfinish{% \normaldash % always output the dash character itself. % % Now, output a discretionary to allow a line break, unless % (a) the next character is a -, or % (b) the preceding character is a -. % E.g., given --posix, we do not want to allow a break after either -. % Given --foo-bar, we do want to allow a break between the - and the b. \ifx\next\codedash \else \ifx\codedashprev\codedash \else \discretionary{}{}{}\fi \fi % we need the space after the = for the case when \next itself is a % space token; it would get swallowed otherwise. As in @code{- a}. \global\let\codedashprev= \next } } \def\normaldash{-} % \def\codex #1{\tclose{#1}\endgroup} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is bad. % @allowcodebreaks provides a document-level way to turn breaking at - % and _ on and off. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}% \fi\fi } % For @command, @env, @file, @option quotes seem unnecessary, % so use \code rather than \samp. \let\command=\code \let\env=\code \let\file=\code \let\option=\code % @uref (abbreviation for `urlref') aka @url takes an optional % (comma-separated) second argument specifying the text to display and % an optional third arg as text to display instead of (rather than in % addition to) the url itself. First (mandatory) arg is the url. % TeX-only option to allow changing PDF output to show only the second % arg (if given), and not the url (which is then just the link target). \newif\ifurefurlonlylink % The main macro is \urefbreak, which allows breaking at expected % places within the url. (There used to be another version, which % didn't support automatic breaking.) \def\urefbreak{\begingroup \urefcatcodes \dourefbreak} \let\uref=\urefbreak % \def\dourefbreak#1{\urefbreakfinish #1,,,\finish} \def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% look for second arg \ifdim\wd0 > 0pt \ifpdf % For pdfTeX and LuaTeX \ifurefurlonlylink % PDF plus option to not display url, show just arg \unhbox0 \else % PDF, normally display both arg and url for consistency, % visibility, if the pdf is eventually used to print, etc. \unhbox0\ (\urefcode{#1})% \fi \else \ifx\XeTeXrevision\thisisundefined \unhbox0\ (\urefcode{#1})% DVI, always show arg and url \else % For XeTeX \ifurefurlonlylink % PDF plus option to not display url, show just arg \unhbox0 \else % PDF, normally display both arg and url for consistency, % visibility, if the pdf is eventually used to print, etc. \unhbox0\ (\urefcode{#1})% \fi \fi \fi \else \urefcode{#1}% only url given, so show it \fi \fi \endlink \endgroup} % Allow line breaks around only a few characters (only). \def\urefcatcodes{% \catcode`\&=\active \catcode`\.=\active \catcode`\#=\active \catcode`\?=\active \catcode`\/=\active } { \urefcatcodes % \global\def\urefcode{\begingroup \setupmarkupstyle{code}% \urefcatcodes \let&\urefcodeamp \let.\urefcodedot \let#\urefcodehash \let?\urefcodequest \let/\urefcodeslash \codex } % % By default, they are just regular characters. \global\def&{\normalamp} \global\def.{\normaldot} \global\def#{\normalhash} \global\def?{\normalquest} \global\def/{\normalslash} } % we put a little stretch before and after the breakable chars, to help % line breaking of long url's. The unequal skips make look better in % cmtt at least, especially for dots. \def\urefprestretchamount{.13em} \def\urefpoststretchamount{.1em} \def\urefprestretch{\urefprebreak \hskip0pt plus\urefprestretchamount\relax} \def\urefpoststretch{\urefpostbreak \hskip0pt plus\urefprestretchamount\relax} % \def\urefcodeamp{\urefprestretch \&\urefpoststretch} \def\urefcodedot{\urefprestretch .\urefpoststretch} \def\urefcodehash{\urefprestretch \#\urefpoststretch} \def\urefcodequest{\urefprestretch ?\urefpoststretch} \def\urefcodeslash{\futurelet\next\urefcodeslashfinish} { \catcode`\/=\active \global\def\urefcodeslashfinish{% \urefprestretch \slashChar % Allow line break only after the final / in a sequence of % slashes, to avoid line break between the slashes in http://. \ifx\next/\else \urefpoststretch \fi } } % One more complication: by default we'll break after the special % characters, but some people like to break before the special chars, so % allow that. Also allow no breaking at all, for manual control. % \parseargdef\urefbreakstyle{% \def\txiarg{#1}% \ifx\txiarg\wordnone \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordbefore \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordafter \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak} \else \errhelp = \EMsimple \errmessage{Unknown @urefbreakstyle setting `\txiarg'}% \fi\fi\fi } \def\wordafter{after} \def\wordbefore{before} \def\wordnone{none} \urefbreakstyle after % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \ifx\XeTeXrevision\thisisundefined \let\email=\uref \else \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \fi \fi % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle setting `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct'. \kbdinputstyle distinct % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. \def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}} \def\xkey{\key} \def\kbdsub#1#2#3\par{% \def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi } % definition of @key that produces a lozenge. Doesn't adjust to text size. %\setfont\keyrm\rmshape{8}{1000}{OT1} %\font\keysy=cmsy9 %\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% % \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% % \vbox{\hrule\kern-0.4pt % \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% % \kern-0.4pt\hrule}% % \kern-.06em\raise0.4pt\hbox{\angleright}}}} % definition of @key with no lozenge. If the current font is already % monospace, don't change it; that way, we respect @kbdinputstyle. But % if it isn't monospace, then use \tt. % \def\key#1{{\setupmarkupstyle{key}% \nohyphenation \ifmonospace\else\tt\fi #1}\null} % @clicksequence{File @click{} Open ...} \def\clicksequence#1{\begingroup #1\endgroup} % @clickstyle @arrow (by default) \parseargdef\clickstyle{\def\click{#1}} \def\click{\arrow} % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\switchtolsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a math (or tt) \. % FYI, plain.tex uses \\ as a temporary control sequence (for no % particular reason), but this is not advertised and we don't care. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \ifmmode\else % only go into math if not in math mode already \tex \mathunderscore \let\\ = \mathbackslash \mathactive % make the texinfo accent commands work in math mode \let\"=\ddot \let\'=\acute \let\==\bar \let\^=\hat \let\`=\grave \let\u=\breve \let\v=\check \let\~=\tilde \let\dotaccent=\dot % have to provide another name for sup operator \let\mathopsup=\sup $\expandafter\finishmath\fi } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \catcode`' = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus \let' = \ptexquoteright } } % for @sub and @sup, if in math mode, just do a normal sub/superscript. % If in text, use math to place as sub/superscript, but switch % into text mode, with smaller fonts. This is a different font than the % one used for real math sub/superscripts (8pt vs. 7pt), but let's not % fix it (significant additions to font machinery) until someone notices. % \def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi} \def\finishsub#1{$\sb{\hbox{\switchtolllsize #1}}$}% % \def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi} \def\finishsup#1{$\ptexsp{\hbox{\switchtolllsize #1}}$}% % @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}. % Ignore unless FMTNAME == tex; then it is like @iftex and @tex, % except specified as a normal braced arg, so no newlines to worry about. % \def\outfmtnametex{tex} % \long\def\inlinefmt#1{\doinlinefmt #1,\finish} \long\def\doinlinefmt#1,#2,\finish{% \def\inlinefmtname{#1}% \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi } % % @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if % FMTNAME is tex, else ELSE-TEXT. \long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish} \long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{% \def\inlinefmtname{#1}% \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi } % % For raw, must switch into @tex before parsing the argument, to avoid % setting catcodes prematurely. Doing it this way means that, for % example, @inlineraw{html, foo{bar} gets a parse error instead of being % ignored. But this isn't important because if people want a literal % *right* brace they would have to use a command anyway, so they may as % well use a command to get a left brace too. We could re-use the % delimiter character idea from \verb, but it seems like overkill. % \long\def\inlineraw{\tex \doinlineraw} \long\def\doinlineraw#1{\doinlinerawtwo #1,\finish} \def\doinlinerawtwo#1,#2,\finish{% \def\inlinerawname{#1}% \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi \endgroup % close group opened by \tex. } % @inlineifset{VAR, TEXT} expands TEXT if VAR is @set. % \long\def\inlineifset#1{\doinlineifset #1,\finish} \long\def\doinlineifset#1,#2,\finish{% \def\inlinevarname{#1}% \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \else\ignorespaces#2\fi } % @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set. % \long\def\inlineifclear#1{\doinlineifclear #1,\finish} \long\def\doinlineifclear#1,#2,\finish{% \def\inlinevarname{#1}% \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi } \message{glyphs,} % and logos. % @@ prints an @, as does @atchar{}. \def\@{\char64 } \let\atchar=\@ % @{ @} @lbracechar{} @rbracechar{} all generate brace characters. \def\lbracechar{{\ifmonospace\char123\else\ensuremath\lbrace\fi}} \def\rbracechar{{\ifmonospace\char125\else\ensuremath\rbrace\fi}} \let\{=\lbracechar \let\}=\rbracechar % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \ptexc \let\dotaccent = \ptexdot \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \ptext \let\ubaraccent = \ptexb \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{% \ifx\textnominalsize\xwordpt % for 10pt running text, lllsize (8pt) is too small for the A in LaTeX. % Revert to plain's \scriptsize, which is 7pt. \count255=\the\fam $\fam\count255 \scriptstyle A$% \else % For 11pt, we can use our lllsize. \switchtolllsize A% \fi }% \vss }}% \kern-.15em \TeX } % Some math mode symbols. Define \ensuremath to switch into math mode % unless we are already there. Expansion tricks may not be needed here, % but safer, and can't hurt. \def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi} \def\ensuredmath#1{$\relax#1$} % \def\bullet{\ensuremath\ptexbullet} \def\geq{\ensuremath\ge} \def\leq{\ensuremath\le} \def\minus{\ensuremath-} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in the cm % typewriter fonts as three actual period characters; on the other hand, % in other typewriter fonts three periods are wider than 1.5em. So do % whichever is larger. % \def\dots{% \leavevmode \setbox0=\hbox{...}% get width of three periods \ifdim\wd0 > 1.5em \dimen0 = \wd0 \else \dimen0 = 1.5em \fi \hbox to \dimen0{% \hskip 0pt plus.25fil .\hskip 0pt plus1fil .\hskip 0pt plus1fil .\hskip 0pt plus.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, they should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} \def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\ttfont \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % Glyphs from the EC fonts. We don't use \let for the aliases, because % sometimes we redefine the original macro, and the alias should reflect % the redefinition. % % Use LaTeX names for the Icelandic letters. \def\DH{{\ecfont \char"D0}} % Eth \def\dh{{\ecfont \char"F0}} % eth \def\TH{{\ecfont \char"DE}} % Thorn \def\th{{\ecfont \char"FE}} % thorn % \def\guillemetleft{{\ecfont \char"13}} \def\guillemotleft{\guillemetleft} \def\guillemetright{{\ecfont \char"14}} \def\guillemotright{\guillemetright} \def\guilsinglleft{{\ecfont \char"0E}} \def\guilsinglright{{\ecfont \char"0F}} \def\quotedblbase{{\ecfont \char"12}} \def\quotesinglbase{{\ecfont \char"0D}} % % This positioning is not perfect (see the ogonek LaTeX package), but % we have the precomposed glyphs for the most common cases. We put the % tests to use those glyphs in the single \ogonek macro so we have fewer % dummy definitions to worry about for index entries, etc. % % ogonek is also used with other letters in Lithuanian (IOU), but using % the precomposed glyphs for those is not so easy since they aren't in % the same EC font. \def\ogonek#1{{% \def\temp{#1}% \ifx\temp\macrocharA\Aogonek \else\ifx\temp\macrochara\aogonek \else\ifx\temp\macrocharE\Eogonek \else\ifx\temp\macrochare\eogonek \else \ecfont \setbox0=\hbox{#1}% \ifdim\ht0=1ex\accent"0C #1% \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% \fi \fi\fi\fi\fi }% } \def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} \def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} \def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} \def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} % % Use the European Computer Modern fonts (cm-super in outline format) % for non-CM glyphs. That is ec* for regular text and tc* for the text % companion symbols (LaTeX TS1 encoding). Both are part of the ec % package and follow the same conventions. % \def\ecfont{\etcfont{e}} \def\tcfont{\etcfont{t}} % \def\etcfont#1{% % We can't distinguish serif/sans and italic/slanted, but this % is used for crude hacks anyway (like adding French and German % quotes to documents typeset with CM, where we lose kerning), so % hopefully nobody will notice/care. \edef\ecsize{\csname\curfontsize ecsize\endcsname}% \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% \ifmonospace % typewriter: \font\thisecfont = #1ctt\ecsize \space at \nominalsize \else \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize \fi \fi \thisecfont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\switchtolllsize R}% \hfil\crcr\Orb}}% }$% } % @textdegree - the normal degrees sign. % \def\textdegree{$^\circ$} % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\thisisundefined \def\Orb{\mathhexbox20D} \fi % Quotes. \chardef\quotedblleft="5C \chardef\quotedblright=`\" \chardef\quoteleft=`\` \chardef\quoteright=`\' \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % @setcontentsaftertitlepage used to do an implicit @contents or % @shortcontents after @end titlepage, but it is now obsolete. \def\setcontentsaftertitlepage{% \errmessage{@setcontentsaftertitlepage has been removed as a Texinfo command; move your @contents command if you want the contents after the title page.}}% \def\setshortcontentsaftertitlepage{% \errmessage{@setshortcontentsaftertitlepage has been removed as a Texinfo command; move your @shortcontents and @contents commands if you want the contents after the title page.}}% \parseargdef\shorttitlepage{% \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } % Settings used for typesetting titles: no hyphenation, no indentation, % don't worry much about spacing, ragged right. This should be used % inside a \vbox, and fonts need to be set appropriately first. \par should % be specified before the end of the \vbox, since a vbox is a group. % \def\raggedtitlesettings{% \rm \hyphenpenalty=10000 \parindent=0pt \tolerance=5000 \ptexraggedright } % Macros to be used within @titlepage: \let\subtitlerm=\rmfont \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \parseargdef\title{% \checkenv\titlepage \vbox{\titlefonts \raggedtitlesettings #1\par}% % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\secfonts\rm \leftline{#1}}% \fi } % Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make \makeheadline and \makefootline in Plain TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\txipageheight by -12pt \global\advance\vsize by -12pt } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @evenheadingmarks top \thischapter <- chapter at the top of a page % @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page % % The same set of arguments for: % % @oddheadingmarks % @evenfootingmarks % @oddfootingmarks % @everyheadingmarks % @everyfootingmarks % These define \getoddheadingmarks, \getevenheadingmarks, % \getoddfootingmarks, and \getevenfootingmarks, each to one of % \gettopheadingmarks, \getbottomheadingmarks. % \def\evenheadingmarks{\headingmarks{even}{heading}} \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} \parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } \parseargdef\everyfootingmarks{\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname \global\expandafter\let\csname get#1#2marks\endcsname \temp } \everyheadingmarks bottom \everyfootingmarks bottom % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \parseargdef\headings{\csname HEADINGS#1\endcsname} \def\headingsoff{% non-global headings elimination \evenheadline={\hfil}\evenfootline={\hfil}% \oddheadline={\hfil}\oddfootline={\hfil}% } \def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting \HEADINGSoff % it's the default % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapterheading\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapterheading\hfil\folio}} \global\oddheadline={\line{\thischapterheading\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapterheading\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapterheading\hfil\folio}} \global\oddheadline={\line{\thischapterheading\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\thisisundefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil\relax \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi % % Try typesetting the item mark so that if the document erroneously says % something like @itemize @samp (intending @table), there's an error % right away at the @itemize. It's not the best error message in the % world, but it's better than leaving it to the @item. This means if % the user wants an empty mark, they have to say @w{} not just @w. \def\itemcontents{#1}% \setbox0 = \hbox{\itemcontents}% % % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi % \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% % \ifinner\else \vadjust{\penalty 1200}% not good to break after first line of item. \fi % We can be in inner vertical mode in a footnote, although an % @itemize looks awful there. }% \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. Assignments % have to be global since we are inside the implicit group of an % alignment entry. \everycr below resets \everytab so we don't have to % undo it ourselves. \def\headitemfont{\b}% for people to use in the template row; not changeable \def\headitem{% \checkenv\multitable \crcr \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings \global\everytab={\bf}% can't use \headitemfont since the parsing differs \the\everytab % for the first item }% % % default for tables with no headings. \let\headitemcrhook=\relax % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we again encounter the problem the 1sp was intended to solve. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% Reset from possible headitem. \global\colcount=0 % Reset the column counter. % % Check for saved footnotes, etc.: \checkinserts % % Perhaps a \nobreak, then reset: \headitemcrhook \global\let\headitemcrhook=\relax }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi % Test to see if parskip is larger than space between lines of % table. If not, do nothing. % If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt % to keep parskip somewhat smaller % than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt % to keep parskip somewhat smaller % than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\-=\active \catcode`\_=\active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\normaldash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % % Unfortunately, this has the consequence that when _ is in the *value* % of an @set, it does not print properly in the roman fonts (get the cmr % dot accent at position 126 instead). No fix comes to mind, and it's % been this way since 2003 or earlier, so just ignore it. % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % Like \expandablevalue, but completely expandable (the \message in the % definition above operates at the execution level of TeX). Used when % writing to auxiliary files, due to the expansion that \write does. % If flag is undefined, pass through an unexpanded @value command: maybe it % will be set by the time it is read back in. % % NB flag names containing - or _ may not work here. \def\dummyvalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax \noexpand\value{#1}% \else \csname SET#1\endcsname \fi } % Used for @value's in index entries to form the sort key: expand the @value % if possible, otherwise sort late. \def\indexnofontsvalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax ZZZZZZZ \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get the special treatment we need for `@end ifset,' we call % \makecond and then redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end executes the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @ifcommandisdefined CMD ... @end executes the `...' if CMD (written % without the @) is in fact defined. We can only feasibly check at the % TeX level, so something like `mathcode' is going to considered % defined even though it is not a Texinfo command. % \makecond{ifcommanddefined} \def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}} % \def\doifcmddefined#1#2{{% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname #2\endcsname\relax #1% If not defined, \let\next as above. \fi \expandafter }\next } \def\ifcmddefinedfail{\doignore{ifcommanddefined}} % @ifcommandnotdefined CMD ... handled similar to @ifclear above. \makecond{ifcommandnotdefined} \def\ifcommandnotdefined{% \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}} \def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}} % Set the `txicommandconditionals' variable, so documents have a way to % test if the @ifcommand...defined conditionals are available. \set txicommandconditionals % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named IX. % It automatically defines \IXindex such that % \IXindex ...rest of line... puts an entry in the index IX. % It also defines \IXindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is IX. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \expandafter\chardef\csname#1indfile\endcsname=0 \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \expandafter\chardef\csname#1indfile\endcsname=0 \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % The default indices: \newindex{cp}% concepts, \newcodeindex{fn}% functions, \newcodeindex{vr}% variables, \newcodeindex{tp}% types, \newcodeindex{ky}% keys \newcodeindex{pg}% and programs. % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% \requireopenindexfile{#3}% % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all index macros. % Argument #1 is generated by the calling \fooindex macro, % and it is the two-letter name of the index. \def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx} \def\doindexxxx #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx} \def\docodeindexxxx #1{\doind{\indexname}{\code{#1}}} % Used when writing an index entry out to an index file to prevent % expansion of Texinfo commands that can appear in an index entry. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \definedummyletter\@% \definedummyletter\ % % % For texindex which always views { and } as separators. \def\{{\lbracechar{}}% \def\}{\rbracechar{}}% % % Do the redefinitions. \definedummies } % Used for the aux and toc files, where @ is the escape character. % \def\atdummies{% \definedummyletter\@% \definedummyletter\ % \definedummyletter\{% \definedummyletter\}% % % Do the redefinitions. \definedummies \otherbackslash } % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % % For control letters, we have \definedummyletter, which omits the % space. % \def\definedummyword #1{\def#1{\string#1\space}}% \def\definedummyletter#1{\def#1{\string#1}}% \let\definedummyaccent\definedummyletter % Called from \indexdummies and \atdummies, to effectively prevent % the expansion of commands. % \def\definedummies{% % \let\commondummyword\definedummyword \let\commondummyletter\definedummyletter \let\commondummyaccent\definedummyaccent \commondummiesnofonts % \definedummyletter\_% \definedummyletter\-% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\DH \definedummyword\L \definedummyword\O \definedummyword\OE \definedummyword\TH \definedummyword\aa \definedummyword\ae \definedummyword\dh \definedummyword\exclamdown \definedummyword\l \definedummyword\o \definedummyword\oe \definedummyword\ordf \definedummyword\ordm \definedummyword\questiondown \definedummyword\ss \definedummyword\th % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\atchar \definedummyword\arrow \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\entrybreak \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\expansion \definedummyword\geq \definedummyword\guillemetleft \definedummyword\guillemetright \definedummyword\guilsinglleft \definedummyword\guilsinglright \definedummyword\lbracechar \definedummyword\leq \definedummyword\mathopsup \definedummyword\minus \definedummyword\ogonek \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\quotedblbase \definedummyword\quotedblleft \definedummyword\quotedblright \definedummyword\quoteleft \definedummyword\quoteright \definedummyword\quotesinglbase \definedummyword\rbracechar \definedummyword\result \definedummyword\sub \definedummyword\sup \definedummyword\textdegree % % We want to disable all macros so that they are not expanded by \write. \macrolist \let\value\dummyvalue % \normalturnoffactive } % \commondummiesnofonts: common to \definedummies and \indexnofonts. % Define \commondummyletter, \commondummyaccent and \commondummyword before % using. Used for accents, font commands, and various control letters. % \def\commondummiesnofonts{% % Control letters and accents. \commondummyletter\!% \commondummyaccent\"% \commondummyaccent\'% \commondummyletter\*% \commondummyaccent\,% \commondummyletter\.% \commondummyletter\/% \commondummyletter\:% \commondummyaccent\=% \commondummyletter\?% \commondummyaccent\^% \commondummyaccent\`% \commondummyaccent\~% \commondummyword\u \commondummyword\v \commondummyword\H \commondummyword\dotaccent \commondummyword\ogonek \commondummyword\ringaccent \commondummyword\tieaccent \commondummyword\ubaraccent \commondummyword\udotaccent \commondummyword\dotless % % Texinfo font commands. \commondummyword\b \commondummyword\i \commondummyword\r \commondummyword\sansserif \commondummyword\sc \commondummyword\slanted \commondummyword\t % % Commands that take arguments. \commondummyword\abbr \commondummyword\acronym \commondummyword\anchor \commondummyword\cite \commondummyword\code \commondummyword\command \commondummyword\dfn \commondummyword\dmn \commondummyword\email \commondummyword\emph \commondummyword\env \commondummyword\file \commondummyword\image \commondummyword\indicateurl \commondummyword\inforef \commondummyword\kbd \commondummyword\key \commondummyword\math \commondummyword\option \commondummyword\pxref \commondummyword\ref \commondummyword\samp \commondummyword\strong \commondummyword\tie \commondummyword\U \commondummyword\uref \commondummyword\url \commondummyword\var \commondummyword\verb \commondummyword\w \commondummyword\xref } % For testing: output @{ and @} in index sort strings as \{ and \}. \newif\ifusebracesinindexes \let\indexlbrace\relax \let\indexrbrace\relax {\catcode`\@=0 \catcode`\\=13 @gdef@backslashdisappear{@def\{}} } { \catcode`\<=13 \catcode`\-=13 \catcode`\`=13 \gdef\indexnonalnumdisappear{% \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else % @set txiindexlquoteignore makes us ignore left quotes in the sort term. % (Introduced for FSFS 2nd ed.) \let`=\empty \fi % \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else \backslashdisappear \fi % \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else \def-{}% \fi \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else \def<{}% \fi \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else \def\@{}% \fi } \gdef\indexnonalnumreappear{% \useindexbackslash \let-\normaldash \let<\normalless \def\@{@}% } } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\commondummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\commondummyletter##1{\let##1\empty}% % All control words become @asis by default; overrides below. \let\commondummyword\commondummyaccent \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% \def\_{\normalunderscore}% \def\-{}% @- shouldn't affect sorting % \uccode`\1=`\{ \uppercase{\def\{{1}}% \uccode`\1=`\} \uppercase{\def\}{1}}% \let\lbracechar\{% \let\rbracechar\}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\DH{DZZ}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\TH{TH}% \def\aa{aa}% \def\ae{ae}% \def\dh{dzz}% \def\exclamdown{!}% \def\l{l}% \def\oe{oe}% \def\ordf{a}% \def\ordm{o}% \def\o{o}% \def\questiondown{?}% \def\ss{ss}% \def\th{th}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. \defglyph gives the control sequence a % definition that removes the {} that follows its use. \defglyph\atchar{@}% \defglyph\arrow{->}% \defglyph\bullet{bullet}% \defglyph\comma{,}% \defglyph\copyright{copyright}% \defglyph\dots{...}% \defglyph\enddots{...}% \defglyph\equiv{==}% \defglyph\error{error}% \defglyph\euro{euro}% \defglyph\expansion{==>}% \defglyph\geq{>=}% \defglyph\guillemetleft{<<}% \defglyph\guillemetright{>>}% \defglyph\guilsinglleft{<}% \defglyph\guilsinglright{>}% \defglyph\leq{<=}% \defglyph\lbracechar{\{}% \defglyph\minus{-}% \defglyph\point{.}% \defglyph\pounds{pounds}% \defglyph\print{-|}% \defglyph\quotedblbase{"}% \defglyph\quotedblleft{"}% \defglyph\quotedblright{"}% \defglyph\quoteleft{`}% \defglyph\quoteright{'}% \defglyph\quotesinglbase{,}% \defglyph\rbracechar{\}}% \defglyph\registeredsymbol{R}% \defglyph\result{=>}% \defglyph\textdegree{o}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist \let\value\indexnofontsvalue } \def\defglyph#1#2{\def#1##1{#2}} % see above \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. % TODO: Two-level index? Operation index? % Workhorse for all indexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% \requireopenindexfile{#1}% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \safewhatsit\dosubindwrite }% \fi } % Check if an index file has been opened, and if not, open it. \def\requireopenindexfile#1{% \ifnum\csname #1indfile\endcsname=0 \expandafter\newwrite \csname#1indfile\endcsname \edef\suffix{#1}% % A .fls suffix would conflict with the file extension for the output % of -recorder, so use .f1s instead. \ifx\suffix\indexisfl\def\suffix{f1}\fi % Open the file \immediate\openout\csname#1indfile\endcsname \jobname.\suffix % Using \immediate above here prevents an object entering into the current % box, which could confound checks such as those in \safewhatsit for % preceding skips. \typeout{Writing index file \jobname.\suffix}% \fi} \def\indexisfl{fl} % Output \ as {\indexbackslash}, because \ is an escape character in % the index files. \let\indexbackslash=\relax {\catcode`\@=0 \catcode`\\=\active @gdef@useindexbackslash{@def\{{@indexbackslash}}} } % Definition for writing index entry text. \def\sortas#1{\ignorespaces}% % Definition for writing index entry sort key. Should occur at the at % the beginning of the index entry, like % @cindex @sortas{september} \september % The \ignorespaces takes care of following space, but there's no way % to remove space before it. { \catcode`\-=13 \gdef\indexwritesortas{% \begingroup \indexnonalnumreappear \indexwritesortasxxx} \gdef\indexwritesortasxxx#1{% \xdef\indexsortkey{#1}\endgroup} } % Write the entry in \toks0 to the index file. % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \useindexbackslash % \indexbackslash isn't defined now so it will be output % as is; and it will print as backslash. % The braces around \indexbrace are recognized by texindex. % % Get the string to sort by, by processing the index entry with all % font commands turned off. {\indexnofonts \def\lbracechar{{\indexlbrace}}% \def\rbracechar{{\indexrbrace}}% \let\{=\lbracechar \let\}=\rbracechar \indexnonalnumdisappear \xdef\indexsortkey{}% \let\sortas=\indexwritesortas \edef\temp{\the\toks0}% \setbox\dummybox = \hbox{\temp}% Make sure to execute any \sortas \ifx\indexsortkey\empty \xdef\indexsortkey{\temp}% \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi \fi }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsortkey}{\noexpand\folio}{\the\toks0}}% }% \temp } \newbox\dummybox % used above % Take care of unwanted page breaks/skips around a whatsit: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write or \pdfdest will make \lastskip zero. The result is that % sequences like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % \newskip\whatsitskip \newcount\whatsitpenalty % % ..., ready, GO: % \def\safewhatsit#1{\ifhmode #1% \else % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \whatsitskip = \lastskip \edef\lastskipmacro{\the\lastskip}% \whatsitpenalty = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\whatsitskip glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\whatsitskip \fi % #1% % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\whatsitskip \fi \fi} % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \plainfrenchspacing \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 12 % See comment in \requireopenindexfile. \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi \openin 1 \jobname.\indexname s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \typeout{No file \jobname.\indexname s.}% \else \catcode`\\ = 0 % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \thisline \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\ttbackslash}% \let\indexlbrace\{ % Likewise, set these sequences for braces \let\indexrbrace\} % used in the sort key. \begindoublecolumns \let\dotheinsertentrybox\dotheinsertentryboxwithpenalty % % Read input from the index file line by line. \loopdo \ifeof1 \else \read 1 to \nextline \fi % \indexinputprocessing \thisline % \ifeof1\else \let\thisline\nextline \repeat %% \enddoublecolumns \fi \fi \closein 1 \endgroup} \def\loopdo#1\repeat{\def\body{#1}\loopdoxxx} \def\loopdoxxx{\let\next=\relax\body\let\next=\loopdoxxx\fi\next} \def\indexinputprocessing{% \ifeof1 \let\firsttoken\relax \else \edef\act{\gdef\noexpand\firsttoken{\getfirsttoken\nextline}}% \act \fi } \def\getfirsttoken#1{\expandafter\getfirsttokenx#1\endfirsttoken} \long\def\getfirsttokenx#1#2\endfirsttoken{\noexpand#1} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. {\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13 \catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13 \catcode`\$=3 \gdef\initialglyphs{% % Some changes for non-alphabetic characters. Using the glyphs from the % math fonts looks more consistent than the typewriter font used elsewhere % for these characters. \def\indexbackslash{\math{\backslash}}% \let\\=\indexbackslash % % Can't get bold backslash so don't use bold forward slash \catcode`\/=13 \def/{{\secrmnotbold \normalslash}}% \def-{{\normaldash\normaldash}}% en dash `--' \def^{{\chapbf \normalcaret}}% \def~{{\chapbf \normaltilde}}% \def\_{% \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }% \def|{$\vert$}% \def<{$\less$}% \def>{$\gtr$}% \def+{$\normalplus$}% }} \def\initial{% \bgroup \initialglyphs \initialx } \def\initialx#1{% % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. % The glue before the bonus allows a little bit of space at the % bottom of a column to reduce an increase in inter-line spacing. \nobreak \vskip 0pt plus 5\baselineskip \penalty -300 \vskip 0pt plus -5\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus 1\baselineskip \leftline{\secfonts \kern-0.05em \secbf #1}% % \secfonts is inside the argument of \leftline so that the change of % \baselineskip will not affect any glue inserted before the vbox that % \leftline creates. % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip \egroup % \initialglyphs } \newdimen\entryrightmargin \entryrightmargin=0pt % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % \def\entry{% \begingroup % % For pdfTeX and XeTeX. % The redefinition of \domark stops marks being added in \pdflink to % preserve coloured links across page boundaries. Otherwise the marks % would get in the way of \lastbox in \insertentrybox. \let\domark\relax % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % No extra space above this paragraph. \parskip = 0in % % When reading the text of entry, convert explicit line breaks % from @* into spaces. The user might give these in long section % titles, for instance. \def\*{\unskip\space\ignorespaces}% \def\entrybreak{\hfil\break}% An undocumented command % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\entrybreak{\unskip\space\ignorespaces}% \def\doentry{% % Save the text of the entry \global\setbox\boxA=\hbox\bgroup \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. % Not absorbing as a macro argument reduces the chance of problems % with catcodes occurring. } {\catcode`\@=11 \gdef\finishentry#1{% \egroup % end box A \dimen@ = \wd\boxA % Length of text of entry \global\setbox\boxA=\hbox\bgroup\unhbox\boxA % #1 is the page number. % % Get the width of the page numbers, and only use % leaders if they are present. \global\setbox\boxB = \hbox{#1}% \ifdim\wd\boxB = 0pt \null\nobreak\hfill\ % \else % \null\nobreak\indexdotfill % Have leaders before the page number. % \ifpdf \pdfgettoks#1.% \hskip\skip\thinshrinkable\the\toksA \else \ifx\XeTeXrevision\thisisundefined \hskip\skip\thinshrinkable #1% \else \pdfgettoks#1.% \hskip\skip\thinshrinkable\the\toksA \fi \fi \fi \egroup % end \boxA \ifdim\wd\boxB = 0pt \global\setbox\entrybox=\vbox{\unhbox\boxA}% \else \global\setbox\entrybox=\vbox\bgroup % We want the text of the entries to be aligned to the left, and the % page numbers to be aligned to the right. % \parindent = 0pt \advance\leftskip by 0pt plus 1fil \advance\leftskip by 0pt plus -1fill \rightskip = 0pt plus -1fil \advance\rightskip by 0pt plus 1fill % Cause last line, which could consist of page numbers on their own % if the list of page numbers is long, to be aligned to the right. \parfillskip=0pt plus -1fill % \advance\rightskip by \entryrightmargin % Determine how far we can stretch into the margin. % This allows, e.g., "Appendix H GNU Free Documentation License" to % fit on one line in @letterpaper format. \ifdim\entryrightmargin>2.1em \dimen@i=2.1em \else \dimen@i=0em \fi \advance \parfillskip by 0pt minus 1\dimen@i % \dimen@ii = \hsize \advance\dimen@ii by -1\leftskip \advance\dimen@ii by -1\entryrightmargin \advance\dimen@ii by 1\dimen@i \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line \ifdim\dimen@ > 0.8\dimen@ii % due to long index text % Try to split the text roughly evenly. \dimen@ will be the length of % the first line. \dimen@ = 0.7\dimen@ \dimen@ii = \hsize \ifnum\dimen@>\dimen@ii % If the entry is too long (for example, if it needs more than % two lines), use all the space in the first line. \dimen@ = \dimen@ii \fi \advance\leftskip by 0pt plus 1fill % ragged right \advance \dimen@ by 1\rightskip \parshape = 2 0pt \dimen@ 0em \dimen@ii % Ideally we'd add a finite glue at the end of the first line only, % instead of using \parshape with explicit line lengths, but TeX % doesn't seem to provide a way to do such a thing. % % Indent all lines but the first one. \advance\leftskip by 1em \advance\parindent by -1em \fi\fi \indent % start paragraph \unhbox\boxA % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % Word spacing - no stretch \spaceskip=\fontdimen2\font minus \fontdimen4\font % \linepenalty=1000 % Discourage line breaks. \hyphenpenalty=5000 % Discourage hyphenation. % \par % format the paragraph \egroup % The \vbox \fi \endgroup \dotheinsertentrybox }} \newskip\thinshrinkable \skip\thinshrinkable=.15em minus .15em \newbox\entrybox \def\insertentrybox{% \ourunvbox\entrybox } % default definition \let\dotheinsertentrybox\insertentrybox % Use \lastbox to take apart vbox box by box, and add each sub-box % to the current vertical list. \def\ourunvbox#1{% \bgroup % for local binding of \delayedbox % Remove the last box from box #1 \global\setbox#1=\vbox{% \unvbox#1% \unskip % remove any glue \unpenalty \global\setbox\interbox=\lastbox }% \setbox\delayedbox=\box\interbox \ifdim\ht#1=0pt\else \ourunvbox#1 % Repeat on what's left of the box \nobreak \fi \box\delayedbox \egroup } \newbox\delayedbox \newbox\interbox % Used from \printindex. \firsttoken should be the first token % after the \entry. If it's not another \entry, we are at the last % line of a group of index entries, so insert a penalty to discourage % widowed index entries. \def\dotheinsertentryboxwithpenalty{% \ifx\firsttoken\isentry \else \penalty 9000 \fi \insertentrybox } \def\isentry{\entry}% % Like plain.tex's \dotfill, except uses up at least 1 em. % The filll stretch here overpowers both the fil and fill stretch to push % the page number to the right. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else \ifx\XeTeXrevision\thisisundefined #2 \else \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \fi \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 % private names \newbox\partialpage \newdimen\doublecolumnhsize % Use inside an output routine to save \topmark and \firstmark \def\savemarks{% \global\savedtopmark=\expandafter{\topmark }% \global\savedfirstmark=\expandafter{\firstmark }% } \newtoks\savedtopmark \newtoks\savedfirstmark % Set \topmark and \firstmark for next time \output runs. % Can't be run from withinside \output (because any material % added while an output routine is active, including % penalties, is saved for after it finishes). The page so far % should be empty, otherwise what's on it will be thrown away. \def\restoremarks{% \mark{\the\savedtopmark}% \bgroup\output = {% \setbox\dummybox=\box\PAGE }abc\eject\egroup % "abc" because output routine doesn't fire for a completely empty page. \mark{\the\savedfirstmark}% } \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % If not much space left on page, start a new page. \ifdim\pagetotal>0.8\vsize\vfill\eject\fi % % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% \savemarks }% \eject % run that output routine to set \partialpage \restoremarks % % We recover the two marks that the last output routine saved in order % to propagate the information in marks added around a chapter heading, % which could be otherwise be lost by the time the final page is output. % % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. \advance\vsize by -\ht\partialpage \vsize = 2\vsize % % For the benefit of balancing columns \advance\baselineskip by 0pt plus 0.5pt } % The double-column output routine for all double-column pages except % the last, which is done by \balancecolumns. % \def\doublecolumnout{% % \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit\PAGE to\dimen@ \setbox2=\vsplit\PAGE to\dimen@ \global\advance\vsize by 2\ht\partialpage \onepageout\pagesofar \unvbox\PAGE \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\txipagewidth{\box0\hfil\box2}% } % Finished with with double columns. \def\enddoublecolumns{% % The following penalty ensures that the page builder is exercised % _before_ we change the output routine. This is necessary in the % following situation: % % The last section of the index consists only of a single entry. % Before this section, \pagetotal is less than \pagegoal, so no % break occurs before the last section starts. However, the last % section, consisting of \initial and the single \entry, does not % fit on the page and has to be broken off. Without the following % penalty the page builder will not be exercised until \eject % below, and by that time we'll already have changed the output % routine to the \balancecolumns version, so the next-to-last % double-column page will be processed with \balancecolumns, which % is wrong: The two columns will go to the main vertical list, with % the broken-off section in the recent contributions. As soon as % the output routine finishes, TeX starts reconsidering the page % break. The two columns and the broken-off section both fit on the % page, because the two columns now take up only half of the page % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns % and the final section into the vbox of \txipageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the % page builder, unlike penalties (see The TeXbook, pp. 280-281). \penalty0 % \output = {% % Split the last of the double-column material. \savemarks \balancecolumns }% \eject % call the \output just set \ifdim\pagetotal=0pt % Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. \global\output = {\onepageout{\pagecontents\PAGE}}% % \endgroup % started in \begindoublecolumns \restoremarks % Leave the double-column material on the current page, no automatic % page break. \box\balancedcolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize. \global\vsize = \txipageheight % \pagegoal = \txipageheight % \else % We had some left-over material. This might happen when \doublecolumnout % is called in \balancecolumns. Try again. \expandafter\enddoublecolumns \fi } \newbox\balancedcolumns \setbox\balancedcolumns=\vbox{shouldnt see this}% % % Only called for the last of the double column material. \doublecolumnout % does the others. \def\balancecolumns{% \setbox0 = \vbox{\unvbox\PAGE}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \ifdim\dimen@<5\baselineskip % Don't split a short final column in two. \setbox2=\vbox{}% \global\setbox\balancedcolumns=\vbox{\pagesofar}% \else \divide\dimen@ by 2 % target to split to \dimen@ii = \dimen@ \splittopskip = \topskip % Loop until left column is at least as high as the right column. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht1<\ht3 \global\advance\dimen@ by 1pt \repeat }% % Now the left column is in box 1, and the right column in box 3. % % Check whether the left column has come out higher than the page itself. % (Note that we have doubled \vsize for the double columns, so % the actual height of the page is 0.5\vsize). \ifdim2\ht1>\vsize % It appears that we have been called upon to balance too much material. % Output some of it with \doublecolumnout, leaving the rest on the page. \setbox\PAGE=\box0 \doublecolumnout \else % Compare the heights of the two columns. \ifdim4\ht1>5\ht3 % Column heights are too different, so don't make their bottoms % flush with each other. \setbox2=\vbox to \ht1 {\unvbox3\vfill}% \setbox0=\vbox to \ht1 {\unvbox1\vfill}% \else % Make column bottoms flush with each other. \setbox2=\vbox to\ht1{\unvbox3\unskip}% \setbox0=\vbox to\ht1{\unvbox1\unskip}% \fi \global\setbox\balancedcolumns=\vbox{\pagesofar}% \fi \fi % } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % Let's start with @part. \outer\parseargdef\part{\partzzz{#1}} \def\partzzz#1{% \chapoddpage \null \vskip.3\vsize % move it down on the page a bit \begingroup \noindent \titlefonts\rm #1\par % the text \let\lastnode=\empty % no node to associate with \writetocentry{part}{#1}{}% but put it in the toc \headingsoff % no headline or footline on the part page % This outputs a mark at the end of the page that clears \thischapter % and \thissection, as is done in \startcontents. \let\pchapsepmacro\relax \chapmacro{}{Yomitfromtoc}{}% \chapoddpage \endgroup } % \unnumberedno is an oxymoron. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines these (using marks) as the number+name, number % and name of the chapter. Page headings and footings can use % these. @section does likewise. \def\thischapter{} \def\thischapternum{} \def\thischaptername{} \def\thissection{} \def\thissectionnum{} \def\thissectionname{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achieve this, remember the "biggest" unnum. sec. we are currently in: \chardef\unnlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unnlevel \chardef\unnlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unnlevel \def\headtype{U}% \else \chardef\unnlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % % \putwordChapter can contain complex things in translations. \toks0=\expandafter{\putwordChapter}% \message{\the\toks0 \space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz % \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % % \putwordAppendix can contain complex things in translations. \toks0=\expandafter{\putwordAppendix}% \message{\the\toks0 \space \appendixletter}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } % normally unnmhead0 calls unnumberedzzz: \outer\parseargdef\unnumbered{\unnmhead0{#1}} \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. % \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } % normally calls appendixsectionzzz: \outer\parseargdef\appendixsection{\apphead1{#1}} \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection % normally calls unnumberedseczzz: \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. % % normally calls numberedsubseczzz: \outer\parseargdef\numberedsubsec{\numhead2{#1}} \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } % normally calls appendixsubseczzz: \outer\parseargdef\appendixsubsec{\apphead2{#1}} \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } % normally calls unnumberedsubseczzz: \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. % % normally numberedsubsubseczzz: \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally appendixsubsubseczzz: \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally unnumberedsubsubseczzz: \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip \nobreak \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. % Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip % Define plain chapter starts, and page on/off switching for it. \def\chapbreak{\dobreak \chapheadingskip {-4000}} % Start a new page \def\chappager{\par\vfill\supereject} % \chapoddpage - start on an odd page for a new chapter % Because \domark is called before \chapoddpage, the filler page will % get the headings for the next chapter, which is wrong. But we don't % care -- we just disable all headings on the filler page. \def\chapoddpage{% \chappager \ifodd\pageno \else \begingroup \headingsoff \null \chappager \endgroup \fi } \parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % \chapmacro - Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % Not used for @heading series. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yappendixkeyword{Yappendix} \def\Yomitfromtockeyword{Yomitfromtoc} % \def\chapmacro#1#2#3{% \expandafter\ifx\thisenv\titlepage\else \checkenv{}% chapters, etc., should not start inside an environment. \fi % FIXME: \chapmacro is currently called from inside \titlepage when % \setcontentsaftertitlepage to print the "Table of Contents" heading, but % this should probably be done by \sectionheading with an option to print % in chapter size. % % Insert the first mark before the heading break (see notes for \domark). \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% \gdef\thissection{}}% % \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{\thischaptername}}% \else\ifx\temptype\Yomitfromtockeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{}}% \else\ifx\temptype\Yappendixkeyword \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\appendixletter}% % \noexpand\putwordAppendix avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \else \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\the\chapno}% % \noexpand\putwordChapter avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordChapter{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert the chapter heading break. \pchapsepmacro % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \domark % {% \chapfonts \rm \let\footnote=\errfootnoteheading % give better error message % % Have to define \lastsection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\lastsection{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \nobreak % Avoid page breaks at the interline glue. \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text of the title, % #2 is the section level (sec/subsec/subsubsec), % #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc), % #4 is the section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% \def\sectionlevel{#2}% \def\temptype{#3}% % % It is ok for the @heading series commands to appear inside an % environment (it's been historically allowed, though the logic is % dubious), but not the others. \ifx\temptype\Yomitfromtockeyword\else \checkenv{}% non-@*heading should not be in an environment. \fi \let\footnote=\errfootnoteheading % % Switch to the right set of fonts. \csname #2fonts\endcsname \rm % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs \ifx\temptype\Ynothingkeyword \ifx\sectionlevel\seckeyword \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% \gdef\thissection{\thissectionname}}% \fi \else\ifx\temptype\Yomitfromtockeyword % Don't redefine \thissection. \else\ifx\temptype\Yappendixkeyword \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \else \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \fi\fi\fi % % Go into vertical mode. Usually we'll already be there, but we % don't want the following whatsit to end up in a preceding paragraph % if the document didn't happen to have a blank line. \par % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert space above the heading. \csname #2headingbreak\endcsname % % Now the second mark, after the heading break. No break points % between here and the heading. \global\let\prevsectiondefs=\lastsectiondefs \domark % % Only insert the space after the number if we have a section number. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\lastsection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \lastsection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\lastsection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\lastsection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) However, when a paragraph is not started next % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out % or the negative glue will cause weirdly wrong output, typically % obscuring the section heading with something else. \vskip-\parskip % % This is so the last item on the main vertical list is a known % \penalty > 10000, so \startdefun, etc., can recognize the situation % and do the needful. \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \else \ifx\XeTeXrevision\thisisundefined \else \global\pdfmakepagedesttrue \fi \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \tocreadfilename } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \entryrightmargin=\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % redefined for the two-volume lispref. We always output on % \jobname.toc even if this is redefined. % \def\tocreadfilename{\jobname.toc} % Normal (long) toc. % \def\contents{% \startcontents{\putwordTOC}% \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\partentry = \shortpartentry \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Parts, in the main contents. Replace the part number, which doesn't % exist, with an empty box. Let's hope all the numbers have the same width. % Also ignore the page number, which is conventionally not printed. \def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}} \def\partentry#1#2#3#4{% % Add stretch and a bonus for breaking the page before the part heading. % This reduces the chance of the page being broken immediately after the % part heading, before a following chapter heading. \vskip 0pt plus 5\baselineskip \penalty-300 \vskip 0pt plus -5\baselineskip \dochapentry{\numeralbox\labelspace#1}{}% } % % Parts, in the short toc. \def\shortpartentry#1#2#3#4{% \penalty-300 \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip \shortchapentry{{\bf #1}}{\numeralbox}{}{}% } % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\hskip.7em#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup % Move the page numbers slightly to the right \advance\entryrightmargin by -0.05em \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @tex ... @end tex escapes into raw TeX temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain @ character. \envdef\tex{% \setupmarkupstyle{tex}% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \catcode `\`=\other \catcode `\'=\other % % ' is active in math mode (mathcode"8000). So reset it, and all our % other math active characters (just in case), to plain's definitions. \mathactive % % Inverse of the list at the beginning of the file. \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\sp=\ptexsp \let\*=\ptexstar %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode \let\t=\ptext \expandafter \let\csname top\endcsname=\ptextop % we've made it outer \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip \ifnum\lastpenalty<10000 % Penalize breaking before the environment, because preceding text % often leads into it. \penalty100 \fi \vskip\envskipamount \fi \fi }} \def\afterenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % % If this cartouche directly follows a sectioning command, we need the % \parskip glue (backspaced over by default) or the cartouche can % collide with the section heading. \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi % \setbox\groupbox=\vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \addgroupbox \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \newdimen\nonfillparindent \def\nonfillstart{% \aboveenvbreak \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt % Turn off paragraph indentation but redefine \indent to emulate % the normal \indent. \nonfillparindent=\parindent \parindent = 0pt \let\indent\nonfillindent % \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } \begingroup \obeyspaces % We want to swallow spaces (but not other tokens) after the fake % @indent in our nonfill-environments, where spaces are normally % active and set to @tie, resulting in them not being ignored after % @indent. \gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% \gdef\nonfillindentcheck{% \ifx\temp % \expandafter\nonfillindentgobble% \else% \leavevmode\nonfillindentbox% \fi% }% \endgroup \def\nonfillindentgobble#1{\nonfillindent} \def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword % end paragraph for sake of leading, in case document has no blank % line. This is redundant with what happens in \aboveenvbreak, but % we need to do it before changing the fonts, and it's inconvenient % to change the fonts afterward. \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it in one command. #1 is the env name, #2 the definition. \def\makedispenvdef#1#2{% \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}% \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}% \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two environment synonyms (#1 and #2) for an environment. \def\maketwodispenvdef#1#2#3{% \makedispenvdef{#1}{#3}% \makedispenvdef{#2}{#3}% } % % @lisp: indented, narrowed, typewriter font; % @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvdef{lisp}{example}{% \nonfillstart \tt\setupmarkupstyle{example}% \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenvdef{display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenvdef{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill\relax \gobble } \let\Eflushright = \afterenvbreak % @raggedright does more-or-less normal line breaking but no right % justification. From plain.tex. Don't stretch around special % characters in urls in this environment, since the stretch at the right % should be enough. \envdef\raggedright{% \rightskip0pt plus2.4em \spaceskip.3333em \xspaceskip.5em\relax \def\urefprestretchamount{0pt}% \def\urefpoststretchamount{0pt}% } \let\Eraggedright\par \envdef\raggedleft{% \parindent=0pt \leftskip0pt plus2em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedleft\par \envdef\raggedcenter{% \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedcenter\par % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \makedispenvdef{quotation}{\quotationstart} % \def\quotationstart{% \indentedblockstart % same as \indentedblock, but increase right margin too. \ifx\nonarrowing\relax \advance\rightskip by \lispnarrowing \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\thisisundefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } \def\Esmallquotation{\Equotation} % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % @indentedblock is like @quotation, but indents only on the left and % has no optional argument. % \makedispenvdef{indentedblock}{\indentedblockstart} % \def\indentedblockstart{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi } % Keep a nonzero parskip for the environment, since we're doing normal filling. % \def\Eindentedblock{% \par {\parskip=0pt \afterenvbreak}% } \def\Esmallindentedblock{\Eindentedblock} % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% % Don't do the quotes -- if we do, @set txicodequoteundirected and % @set txicodequotebacktick will not have effect on @verb and % @verbatim, and ?` and !` ligatures won't get disabled. %\do\`\do\'% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \setupmarkupstyle{verb}% \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion. \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % % We typeset each line of the verbatim in an \hbox, so we can handle % tabs. The \global is in case the verbatim line starts with an accent, % or some other command that starts with a begin-group. Otherwise, the % entire \verbbox would disappear at the corresponding end-group, before % it is typeset. Meanwhile, we can't have nested verbatim commands % (can we?), so the \global won't be overwriting itself. \newbox\verbbox \def\starttabbox{\global\setbox\verbbox=\hbox\bgroup} % \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab \divide\dimen\verbbox by\tabw \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox }% } \endgroup % start the verbatim environment. \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart \tt % easiest (and conventionally used) font for verbatim % The \leavevmode here is for blank lines. Otherwise, we would % never \starttabox and the \egroup would end verbatim mode. \def\par{\leavevmode\egroup\box\verbbox\endgraf}% \tabexpand \setupmarkupstyle{verbatim}% % Respect line breaks, % print special symbols as themselves, and % make each space count. % Must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}% \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt \newcount\defunpenalty % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \defunpenalty=10003 % Will keep this @deffn together with the % following @def command, see below. \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \printdefunline, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % % As a further refinement, we avoid "club" headers by signalling % with penalty of 10003 after the very first @deffn in the % sequence (see above), and penalty of 10002 after any following % @def command. \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil\relax \endgraf \nobreak\vskip -\parskip \penalty\defunpenalty % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remaining is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) } % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \doingtypefnfalse % distinguish typed functions from all else \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } \newif\ifdoingtypefn % doing typed function? \newif\ifrettypeownline % typeset return type on its own line? % @deftypefnnewline on|off says whether the return type of typed functions % are printed on their own line. This affects @deftypefn, @deftypefun, % @deftypeop, and @deftypemethod. % \parseargdef\deftypefnnewline{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxideftypefnnl\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETtxideftypefnnl\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @txideftypefnnl value `\temp', must be on|off}% \fi\fi } % Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } % Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \doingtypefntrue \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } % Types: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% \par % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % Determine if we are typesetting the return type of a typed function % on a line by itself. \rettypeownlinefalse \ifdoingtypefn % doing a typed function specifically? % then check user option for putting return type on its own line: \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else \rettypeownlinetrue \fi \fi % % How we'll format the category name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. We'll always have at % least two. \tempnum = 2 % % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % % If doing a return type on its own line, we'll have another line. \ifrettypeownline \advance\tempnum by 1 \def\maybeshapeline{0in \hsize}% \else \def\maybeshapeline{}% \fi % % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % % The final paragraph shape: \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2 % % Put the category name at the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% text of the return type \ifx\temp\empty\else \tclose{\temp}% typeset the return type \ifrettypeownline % put return type on its own line; prohibit line break following: \hfil\vadjust{\nobreak}\break \else \space % type on same line, so just followed by a space \fi \fi % no return type #3% output function name }% {\rm\enskip}% hskip 0.5 em of \rmfont % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. We used to recommend @var for that, so % leave the code in, but it's strange for @var to lead to typewriter. % Nowadays we recommend @code, since the difference between a ttsl hyphen % and a tt hyphen is pretty tiny. @code also disables ?` !`. \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } % these should not use \errmessage; the glibc manual, at least, actually % has such constructs (when documenting function pointers). \def\badparencount{% \message{Warning: unbalanced parentheses in @def...}% \global\parencount=0 } \def\badbrackcount{% \message{Warning: unbalanced square brackets in @def...}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\thisisundefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi % alias because \c means cedilla in @tex or @math \let\texinfoc=\c \newcount\savedcatcodeone \newcount\savedcatcodetwo % Used at the time of macro expansion. % Argument is macro body with arguments substituted \def\scanmacro#1{% \newlinechar`\^^M \def\xeatspaces{\eatspaces}% % % Temporarily undo catcode changes of \printindex. Set catcode of @ to % 0 so that @-commands in macro expansions aren't printed literally when % formatting an index file, where \ is used as the escape character. \savedcatcodeone=\catcode`\@ \savedcatcodetwo=\catcode`\\ \catcode`\@=0 \catcode`\\=\active % % Process the macro body under the current catcode regime. \scantokens{#1@texinfoc}% % \catcode`\@=\savedcatcodeone \catcode`\\=\savedcatcodetwo % % The \texinfoc is to remove the \newlinechar added by \scantokens, and % can be noticed by \parsearg. % We avoid surrounding the call to \scantokens with \bgroup and \egroup % to allow macros to open or close groups themselves. } % Used for copying and captions \def\scanexp#1{% \expandafter\scanmacro\expandafter{#1}% } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \commondummyword\macro1\commondummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\commondummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\endcsname \csname#2\endcsname } % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \ % to recognize macro arguments; this is the job of \mbodybackslash. % % Non-ASCII encodings make 8-bit characters active, so un-activate % them to avoid their expansion. Must do this non-globally, to % confine the change to the current group. % % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. % \def\scanctxt{% used as subroutine \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other \passthroughcharstrue } \def\scanargctxt{% used for copying and captions, not macros. \scanctxt \catcode`\@=\other \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% used for @macro definitions \scanctxt \catcode`\ =\other \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } % Used when scanning braced macro arguments. Note, however, that catcode % changes here are ineffectual if the macro invocation was nested inside % an argument to another Texinfo command. \def\macroargctxt{% \scanctxt \catcode`\ =\active \catcode`\^^M=\other \catcode`\\=\active } \def\macrolineargctxt{% used for whole-line arguments without braces \scanctxt \catcode`\{=\other \catcode`\}=\other } % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. % {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\margbackslash#1{\char`\#1 } \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0\relax \else \expandafter\parsemargdef \argl;% \if\paramno>256\relax \ifx\eTeXversion\thisisundefined \errhelp = \EMsimple \errmessage{You need eTeX to compile a file with macros with more than 256 arguments} \fi \fi \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\commondummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\commondummyword \noexpand#1% \fi } % \getargs -- Parse the arguments to a @macro line. Set \macname to % the name of the macro, and \argl to the braced argument list. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname#1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % This made use of the feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. % Parse the optional {params} list to @macro or @rmacro. % Set \paramno to the number of arguments, % and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a % three-param macro.) Define \macarg.BLAH for each BLAH in the params % list to some hook where the argument is to be expanded. If there are % less than 10 arguments that hook is to be replaced by ##N where N % is the position in that list, that is to say the macro arguments are to be % defined `a la TeX in the macro body. % % That gets used by \mbodybackslash (above). % % If there are 10 or more arguments, a different technique is used: see % \parsemmanyargdef. % \def\parsemargdef#1;{% \paramno=0\def\paramlist{}% \let\hash\relax % \hash is redefined to `#' later to get it into definitions \let\xeatspaces\relax \parsemargdefxxx#1,;,% \ifnum\paramno<10\relax\else \paramno0\relax \parsemmanyargdef@@#1,;,% 10 or more arguments \fi } \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1 \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} % \parsemacbody, \parsermacbody % % Read recursive and nonrecursive macro bodies. (They're different since % rec and nonrec macros end differently.) % % We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro % body to be transformed. % Set \macrobody to the body of the macro, and call \defmacro. % {\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{% \xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}% {\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{% \xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}% % Make @ a letter, so that we can make private-to-Texinfo macro names. \edef\texiatcatcode{\the\catcode`\@} \catcode `@=11\relax %%%%%%%%%%%%%% Code for > 10 arguments only %%%%%%%%%%%%%%%%%% % If there are 10 or more arguments, a different technique is used, where the % hook remains in the body, and when macro is to be expanded the body is % processed again to replace the arguments. % % In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the % argument N value and then \edef the body (nothing else will expand because of % the catcode regime under which the body was input). % % If you compile with TeX (not eTeX), and you have macros with 10 or more % arguments, no macro can have more than 256 arguments (else error). % % In case that there are 10 or more arguments we parse again the arguments % list to set new definitions for the \macarg.BLAH macros corresponding to % each BLAH argument. It was anyhow needed to parse already once this list % in order to count the arguments, and as macros with at most 9 arguments % are by far more frequent than macro with 10 or more arguments, defining % twice the \macarg.BLAH macros does not cost too much processing power. \def\parsemmanyargdef@@#1,{% \if#1;\let\next=\relax \else \let\next=\parsemmanyargdef@@ \edef\tempb{\eatspaces{#1}}% \expandafter\def\expandafter\tempa \expandafter{\csname macarg.\tempb\endcsname}% % Note that we need some extra \noexpand\noexpand, this is because we % don't want \the to be expanded in the \parsermacbody as it uses an % \xdef . \expandafter\edef\tempa {\noexpand\noexpand\noexpand\the\toks\the\paramno}% \advance\paramno by 1\relax \fi\next} \let\endargs@\relax \let\nil@\relax \def\nilm@{\nil@}% \long\def\nillm@{\nil@}% % This macro is expanded during the Texinfo macro expansion, not during its % definition. It gets all the arguments' values and assigns them to macros % macarg.ARGNAME % % #1 is the macro name % #2 is the list of argument names % #3 is the list of argument values \def\getargvals@#1#2#3{% \def\macargdeflist@{}% \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion. \def\paramlist{#2,\nil@}% \def\macroname{#1}% \begingroup \macroargctxt \def\argvaluelist{#3,\nil@}% \def\@tempa{#3}% \ifx\@tempa\empty \setemptyargvalues@ \else \getargvals@@ \fi } \def\getargvals@@{% \ifx\paramlist\nilm@ % Some sanity check needed here that \argvaluelist is also empty. \ifx\argvaluelist\nillm@ \else \errhelp = \EMsimple \errmessage{Too many arguments in macro `\macroname'!}% \fi \let\next\macargexpandinbody@ \else \ifx\argvaluelist\nillm@ % No more arguments values passed to macro. Set remaining named-arg % macros to empty. \let\next\setemptyargvalues@ \else % pop current arg name into \@tempb \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}% \expandafter\@tempa\expandafter{\paramlist}% % pop current argument value into \@tempc \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}% \expandafter\@tempa\expandafter{\argvaluelist}% % Here \@tempb is the current arg name and \@tempc is the current arg value. % First place the new argument macro definition into \@tempd \expandafter\macname\expandafter{\@tempc}% \expandafter\let\csname macarg.\@tempb\endcsname\relax \expandafter\def\expandafter\@tempe\expandafter{% \csname macarg.\@tempb\endcsname}% \edef\@tempd{\long\def\@tempe{\the\macname}}% \push@\@tempd\macargdeflist@ \let\next\getargvals@@ \fi \fi \next } \def\push@#1#2{% \expandafter\expandafter\expandafter\def \expandafter\expandafter\expandafter#2% \expandafter\expandafter\expandafter{% \expandafter#1#2}% } % Replace arguments by their values in the macro body, and place the result % in macro \@tempa. % \def\macvalstoargs@{% % To do this we use the property that token registers that are \the'ed % within an \edef expand only once. So we are going to place all argument % values into respective token registers. % % First we save the token context, and initialize argument numbering. \begingroup \paramno0\relax % Then, for each argument number #N, we place the corresponding argument % value into a new token list register \toks#N \expandafter\putargsintokens@\saveparamlist@,;,% % Then, we expand the body so that argument are replaced by their % values. The trick for values not to be expanded themselves is that they % are within tokens and that tokens expand only once in an \edef . \edef\@tempc{\csname mac.\macroname .body\endcsname}% % Now we restore the token stack pointer to free the token list registers % which we have used, but we make sure that expanded body is saved after % group. \expandafter \endgroup \expandafter\def\expandafter\@tempa\expandafter{\@tempc}% } % Define the named-macro outside of this group and then close this group. % \def\macargexpandinbody@{% \expandafter \endgroup \macargdeflist@ % First the replace in body the macro arguments by their values, the result % is in \@tempa . \macvalstoargs@ % Then we point at the \norecurse or \gobble (for recursive) macro value % with \@tempb . \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname % Depending on whether it is recursive or not, we need some tailing % \egroup . \ifx\@tempb\gobble \let\@tempc\relax \else \let\@tempc\egroup \fi % And now we do the real job: \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}% \@tempd } \def\putargsintokens@#1,{% \if#1;\let\next\relax \else \let\next\putargsintokens@ % First we allocate the new token list register, and give it a temporary % alias \@tempb . \toksdef\@tempb\the\paramno % Then we place the argument value into that token list register. \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname \expandafter\@tempb\expandafter{\@tempa}% \advance\paramno by 1\relax \fi \next } % Trailing missing arguments are set to empty. % \def\setemptyargvalues@{% \ifx\paramlist\nilm@ \let\next\macargexpandinbody@ \else \expandafter\setemptyargvaluesparser@\paramlist\endargs@ \let\next\setemptyargvalues@ \fi \next } \def\setemptyargvaluesparser@#1,#2\endargs@{% \expandafter\def\expandafter\@tempa\expandafter{% \expandafter\def\csname macarg.#1\endcsname{}}% \push@\@tempa\macargdeflist@ \def\paramlist{#2}% } % #1 is the element target macro % #2 is the list macro % #3,#4\endargs@ is the list value \def\pop@#1#2#3,#4\endargs@{% \def#1{#3}% \def#2{#4}% } \long\def\longpop@#1#2#3,#4\endargs@{% \long\def#1{#3}% \long\def#2{#4}% } %%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%% % This defines a Texinfo @macro or @rmacro, called by \parsemacbody. % \macrobody has the body of the macro in it, with placeholders for % its parameters, looking like "\xeatspaces{\hash 1}". % \paramno is the number of parameters % \paramlist is a TeX parameter text, e.g. "#1,#2,#3," % There are four cases: macros of zero, one, up to nine, and many arguments. % \xdef is used so that macro definitions will survive the file % they're defined in: @include reads the file inside a group. % \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifnum\paramno=1 \def\xeatspaces##1{##1}% % This removes the pair of braces around the argument. We don't % use \eatspaces, because this can cause ends of lines to be lost % when the argument to \eatspaces is read, leading to line-based % commands like "@itemize" not being read correctly. \else \let\xeatspaces\relax % suppress expansion \fi \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\spaceisspace \noexpand\endlineisspace \noexpand\expandafter % skip any whitespace after the macro name. \expandafter\noexpand\csname\the\macname @@@\endcsname}% \expandafter\xdef\csname\the\macname @@@\endcsname{% \egroup \noexpand\scanmacro{\macrobody}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\braceorline \expandafter\noexpand\csname\the\macname @@@\endcsname}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% \egroup \noexpand\scanmacro{\macrobody}% }% \else % at most 9 \ifnum\paramno<10\relax % @MACNAME sets the context for reading the macro argument % @MACNAME@@ gets the argument, processes backslashes and appends a % comma. % @MACNAME@@@ removes braces surrounding the argument list. % @MACNAME@@@@ scans the macro body with arguments substituted. \expandafter\xdef\csname\the\macname\endcsname{% \bgroup \noexpand\expandafter % This \expandafter skip any spaces after the \noexpand\macroargctxt % macro before we change the catcode of space. \noexpand\expandafter \expandafter\noexpand\csname\the\macname @@\endcsname}% \expandafter\xdef\csname\the\macname @@\endcsname##1{% \noexpand\passargtomacro \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}% \expandafter\xdef\csname\the\macname @@@\endcsname##1{% \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname @@@@\endcsname\paramlist{% \egroup\noexpand\scanmacro{\macrobody}}% \else % 10 or more: \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble \fi \fi} \catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % {\catcode`\@=0 \catcode`\\=13 % We need to manipulate \ so use @ as escape @catcode`@_=11 % private names @catcode`@!=11 % used as argument separator % \passargtomacro#1#2 - % Call #1 with a list of tokens #2, with any doubled backslashes in #2 % compressed to one. % % This implementation works by expansion, and not execution (so we cannot use % \def or similar). This reduces the risk of this failing in contexts where % complete expansion is done with no execution (for example, in writing out to % an auxiliary file for an index entry). % % State is kept in the input stream: the argument passed to % @look_ahead, @gobble_and_check_finish and @add_segment is % % THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN (... rest of input) % % where: % THE_MACRO - name of the macro we want to call % ARG_RESULT - argument list we build to pass to that macro % PENDING_BS - either a backslash or nothing % NEXT_TOKEN - used to look ahead in the input stream to see what's coming next @gdef@passargtomacro#1#2{% @add_segment #1!{}@relax#2\@_finish\% } @gdef@_finish{@_finishx} @global@let@_finishx@relax % #1 - THE_MACRO ARG_RESULT % #2 - PENDING_BS % #3 - NEXT_TOKEN % #4 used to look ahead % % If the next token is not a backslash, process the rest of the argument; % otherwise, remove the next token. @gdef@look_ahead#1!#2#3#4{% @ifx#4\% @expandafter@gobble_and_check_finish @else @expandafter@add_segment @fi#1!{#2}#4#4% } % #1 - THE_MACRO ARG_RESULT % #2 - PENDING_BS % #3 - NEXT_TOKEN % #4 should be a backslash, which is gobbled. % #5 looks ahead % % Double backslash found. Add a single backslash, and look ahead. @gdef@gobble_and_check_finish#1!#2#3#4#5{% @add_segment#1\!{}#5#5% } @gdef@is_fi{@fi} % #1 - THE_MACRO ARG_RESULT % #2 - PENDING_BS % #3 - NEXT_TOKEN % #4 is input stream until next backslash % % Input stream is either at the start of the argument, or just after a % backslash sequence, either a lone backslash, or a doubled backslash. % NEXT_TOKEN contains the first token in the input stream: if it is \finish, % finish; otherwise, append to ARG_RESULT the segment of the argument up until % the next backslash. PENDING_BACKSLASH contains a backslash to represent % a backslash just before the start of the input stream that has not been % added to ARG_RESULT. @gdef@add_segment#1!#2#3#4\{% @ifx#3@_finish @call_the_macro#1!% @else % append the pending backslash to the result, followed by the next segment @expandafter@is_fi@look_ahead#1#2#4!{\}@fi % this @fi is discarded by @look_ahead. % we can't get rid of it with \expandafter because we don't know how % long #4 is. } % #1 - THE_MACRO % #2 - ARG_RESULT % #3 discards the res of the conditional in @add_segment, and @is_fi ends the % conditional. @gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \braceorline MAC is used for a one-argument macro MAC. It checks % whether the next non-whitespace character is a {. It sets the context % for reading the argument (slightly different in the two cases). Then, % to read the argument, in the whole-line case, it then calls the regular % \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC. % \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup \macroargctxt \expandafter\passargtomacro \else \macrolineargctxt\expandafter\parsearg \fi \macnamexxx} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Make them active and then expand them all to nothing. % \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{% \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \lastsection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \requireauxfile \atdummies % preserve commands, but don't expand them % match definition in \xrdef, \refx, \xrefX. \def\value##1{##1}% \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\lastsection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout }% \fi } % @xrefautosectiontitle on|off says whether @section(ing) names are used % automatically in xrefs, if the third arg is not explicitly specified. % This was provided as a "secret" @set xref-automatic-section-title % variable, now it's official. % \parseargdef\xrefautomaticsectiontitle{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @xrefautomaticsectiontitle value `\temp', must be on|off}% \fi\fi } % % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref{\putwordsee{} \xrefXX} \def\xref{\putwordSee{} \xrefXX} \def\ref{\xrefXX} \def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX} \def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]} % \newbox\toprefbox \newbox\printedrefnamebox \newbox\infofilenamebox \newbox\printedmanualbox % \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces % % Get args without leading/trailing spaces. \def\printedrefname{\ignorespaces #3}% \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}% % \def\infofilename{\ignorespaces #4}% \setbox\infofilenamebox = \hbox{\infofilename\unskip}% % \def\printedmanual{\ignorespaces #5}% \setbox\printedmanualbox = \hbox{\printedmanual\unskip}% % % If the printed reference name (arg #3) was not explicitly given in % the @xref, figure out what we want to use. \ifdim \wd\printedrefnamebox = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax % Not auto section-title: use node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Auto section-title: use chapter/section title inside % the square brackets if we have it. \ifdim \wd\printedmanualbox > 0pt % It is in another manual, so we don't have it; use node name. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We (should) know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf % For pdfTeX and LuaTeX {\indexnofonts \makevalueexpandable \turnoffactive % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. This ignores all spaces in % #4, including (wrongly) those in the middle of the filename. \getfilename{#4}% % % This (wrongly) does not take account of leading or trailing % spaces in #1, which should be ignored. \setpdfdestname{#1}% % \ifx\pdfdestname\empty \def\pdfdestname{Top}% no empty targets \fi % \leavevmode \startlink attr{/Border [0 0 0]}% \ifnum\filenamelength>0 goto file{\the\filename.pdf} name{\pdfdestname}% \else goto name{\pdfmkpgn{\pdfdestname}}% \fi }% \setcolor{\linkcolor}% \else \ifx\XeTeXrevision\thisisundefined \else % For XeTeX {\indexnofonts \makevalueexpandable \turnoffactive % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. This ignores all spaces in % #4, including (wrongly) those in the middle of the filename. \getfilename{#4}% % % This (wrongly) does not take account of leading or trailing % spaces in #1, which should be ignored. \setpdfdestname{#1}% % \ifx\pdfdestname\empty \def\pdfdestname{Top}% no empty targets \fi % \leavevmode \ifnum\filenamelength>0 % With default settings, % XeTeX (xdvipdfmx) replaces link destination names with integers. % In this case, the replaced destination names of % remote PDFs are no longer known. In order to avoid a replacement, % you can use xdvipdfmx's command line option `-C 0x0010'. % If you use XeTeX 0.99996+ (TeX Live 2016+), % this command line option is no longer necessary % because we can use the `dvipdfmx:config' special. \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A << /S /GoToR /F (\the\filename.pdf) /D (\pdfdestname) >> >>}% \else \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A << /S /GoTo /D (\pdfdestname) >> >>}% \fi }% \setcolor{\linkcolor}% \fi \fi {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \def\value##1{##1}% \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". \iffloat distinguishes them by % \Xthisreftitle being set to a magic string. \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd\printedrefnamebox = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % If the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd\printedmanualbox > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox to print the node names, TeX does not insert % empty discretionaries after hyphens, which means that it will not % find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, % this is a loss. Therefore, we give the text of the node name % again, so it is as if TeX is seeing it for the first time. % \ifdim \wd\printedmanualbox > 0pt % Cross-manual reference with a printed manual name. % \crossmanualxref{\cite{\printedmanual\unskip}}% % \else\ifdim \wd\infofilenamebox > 0pt % Cross-manual reference with only an info filename (arg 4), no % printed manual name (arg 5). This is essentially the same as % the case above; we output the filename, since we have nothing else. % \crossmanualxref{\code{\infofilename\unskip}}% % \else % Reference within this manual. % % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via the macro below so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% % Add a , if xref followed by a space \if\space\noexpand\tokenafterxref ,% \else\ifx\ \tokenafterxref ,% @TAB \else\ifx\*\tokenafterxref ,% @* \else\ifx\ \tokenafterxref ,% @SPACE \else\ifx\ \tokenafterxref ,% @NL \else\ifx\tie\tokenafterxref ,% @tie \fi\fi\fi\fi\fi\fi \fi\fi \fi \endlink \endgroup} % Output a cross-manual xref to #1. Used just above (twice). % % Only include the text "Section ``foo'' in" if the foo is neither % missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply % "see The Foo Manual", the idea being to refer to the whole manual. % % But, this being TeX, we can't easily compare our node name against the % string "Top" while ignoring the possible spaces before and after in % the input. By adding the arbitrary 7sp below, we make it much less % likely that a real node name would have the same width as "Top" (e.g., % in a monospaced font). Hopefully it will never happen in practice. % % For the same basic reason, we retypeset the "Top" at every % reference, since the current font is indeterminate. % \def\crossmanualxref#1{% \setbox\toprefbox = \hbox{Top\kern7sp}% \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}% \ifdim \wd2 > 7sp % nonempty? \ifdim \wd2 = \wd\toprefbox \else % same as Top? \putwordSection{} ``\printedrefname'' \putwordin{}\space \fi \fi #1% } % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME. SUFFIX % is output afterwards if non-empty. \def\refx#1#2{% \requireauxfile {% \indexnofonts \otherbackslash \def\value##1{##1}% \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs {\toks0 = {#1}% avoid expansion of possibly-complex value \message{\linenumber Undefined cross reference `\the\toks0'.}}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Define a control % sequence for a cross-reference target (we prepend XR to the control sequence % name to avoid collisions). The value is the page number. If this is a float % type, we have more work to do. % \def\xrdef#1#2{% {% Expand the node or anchor name to remove control sequences. % \turnoffactive stops 8-bit characters being changed to commands % like @'e. \refx does the same to retrieve the value in the definition. \indexnofonts \turnoffactive \def\value##1{##1}% \xdef\safexrefname{#1}% }% % \bgroup \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% \egroup % We put the \gdef inside a group to avoid the definitions building up on % TeX's save stack, which can cause it to run out of space for aux files with % thousands of lines. \gdef doesn't use the save stack, but \csname does % when it defines an unknown control sequence as \relax. % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 {\safexrefname}}% \fi } % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate at the beginning of the file. % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % Used when writing to the aux file, or when using data from it. \def\requireauxfile{% \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi \global\let\requireauxfile=\relax % Only do this once. } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for Info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % % Nested footnotes are not supported in TeX, that would take a lot % more work. (\startsavinginserts does not suffice.) \let\footnote=\errfootnotenest % % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\txipagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut % % Invoke rest of plain TeX footnote routine. \futurelet\next\fo@t } }%end \catcode `\@=11 \def\errfootnotenest{% \errhelp=\EMsimple \errmessage{Nested footnotes not supported in texinfo.tex, even though they work in makeinfo; sorry} } \def\errfootnoteheading{% \errhelp=\EMsimple \errmessage{Footnotes in chapters, sections, etc., are not supported} } % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarly, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from https://ctan.org/texarchive/macros/texinfo/texinfo/doc/epsf.tex.} % \def\image#1{% \ifx\epsfbox\thisisundefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names \def\xprocessmacroarg{\eatspaces}% in case we are being used via a macro % If the image is by itself, center it. \ifvmode \imagevmodetrue \else \ifx\centersub\centerV % for @center @image, we need a vbox so we can have our vertical space \imagevmodetrue \vbox\bgroup % vbox has better behavior than vtop herev \fi\fi % \ifimagevmode \nobreak\medskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \fi % % Leave vertical mode so that indentation from an enclosing % environment such as @quotation is respected. % However, if we're at the top level, we don't want the % normal paragraph indentation. % On the other hand, if we are in the case of @center @image, we don't % want to start a paragraph, which will create a hsize-width box and % eradicate the centering. \ifx\centersub\centerV\else \noindent \fi % % Output the image. \ifpdf % For pdfTeX and LuaTeX <= 0.80 \dopdfimage{#1}{#2}{#3}% \else \ifx\XeTeXrevision\thisisundefined % For epsf.tex % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \else % For XeTeX \doxeteximage{#1}{#2}{#3}% \fi \fi % \ifimagevmode \medskip % space after a standalone image \fi \ifx\centersub\centerV \egroup \fi \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \lastsection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\lastsection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \requireauxfile \atdummies % \ifx\thisshortcaption\empty \def\gtemp{\thiscaption}% \else \def\gtemp{\thisshortcaption}% \fi \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \lastsection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % For single-language documents, @documentlanguage is usually given very % early, just after @documentencoding. Single argument is the language % (de) or locale (de_DE) abbreviation. % { \catcode`\_ = \active \globaldefs=1 \parseargdef\documentlanguage{% \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \let_ = \normalunderscore % normal _ character for filename test \openin 1 txi-#1.tex \ifeof 1 \documentlanguagetrywithoutunderscore #1_\finish \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 \endgroup % end raw TeX } % % If they passed de_DE, and txi-de_DE.tex doesn't exist, % try txi-de.tex. % \gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 } }% end of special _ catcode % \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? Putting it in the current directory should work if nowhere else does.} % This macro is called from txi-??.tex files; the first argument is the % \language name to set (without the "\lang@" prefix), the second and % third args are \{left,right}hyphenmin. % % The language names to pass are determined when the format is built. % See the etex.log file created at that time, e.g., % /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. % % With TeX Live 2008, etex now includes hyphenation patterns for all % available languages. This means we can support hyphenation in % Texinfo, at least to some extent. (This still doesn't solve the % accented characters problem.) % \catcode`@=11 \def\txisetlanguage#1#2#3{% % do not set the language if the name is undefined in the current TeX. \expandafter\ifx\csname lang@#1\endcsname \relax \message{no patterns for #1}% \else \global\language = \csname lang@#1\endcsname \fi % but there is no harm in adjusting the hyphenmin values regardless. \global\lefthyphenmin = #2\relax \global\righthyphenmin = #3\relax } % XeTeX and LuaTeX can handle Unicode natively. % Their default I/O uses UTF-8 sequences instead of a byte-wise operation. % Other TeX engines' I/O (pdfTeX, etc.) is byte-wise. % \newif\iftxinativeunicodecapable \newif\iftxiusebytewiseio \ifx\XeTeXrevision\thisisundefined \ifx\luatexversion\thisisundefined \txinativeunicodecapablefalse \txiusebytewiseiotrue \else \txinativeunicodecapabletrue \txiusebytewiseiofalse \fi \else \txinativeunicodecapabletrue \txiusebytewiseiofalse \fi % Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex % for non-UTF-8 (byte-wise) encodings. % \def\setbytewiseio{% \ifx\XeTeXrevision\thisisundefined \else \XeTeXdefaultencoding "bytes" % For subsequent files to be read \XeTeXinputencoding "bytes" % For document root file % Unfortunately, there seems to be no corresponding XeTeX command for % output encoding. This is a problem for auxiliary index and TOC files. % The only solution would be perhaps to write out @U{...} sequences in % place of non-ASCII characters. \fi \ifx\luatexversion\thisisundefined \else \directlua{ local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub local function convert_char (char) return utf8_char(byte(char)) end local function convert_line (line) return gsub(line, ".", convert_char) end callback.register("process_input_buffer", convert_line) local function convert_line_out (line) local line_out = "" for c in string.utfvalues(line) do line_out = line_out .. string.char(c) end return line_out end callback.register("process_output_buffer", convert_line_out) } \fi \txiusebytewiseiotrue } % Helpers for encodings. % Set the catcode of characters 128 through 255 to the specified number. % \def\setnonasciicharscatcode#1{% \count255=128 \loop\ifnum\count255<256 \global\catcode\count255=#1\relax \advance\count255 by 1 \repeat } \def\setnonasciicharscatcodenonglobal#1{% \count255=128 \loop\ifnum\count255<256 \catcode\count255=#1\relax \advance\count255 by 1 \repeat } % @documentencoding sets the definition of non-ASCII characters % according to the specified encoding. % \def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz} \def\documentencodingzzz#1{% % % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% % % Supported encodings: names converted to tokens in order to be able % to compare them with \ifx. \def\ascii{\csname US-ASCII.enc\endcsname}% \def\latnine{\csname ISO-8859-15.enc\endcsname}% \def\latone{\csname ISO-8859-1.enc\endcsname}% \def\lattwo{\csname ISO-8859-2.enc\endcsname}% \def\utfeight{\csname UTF-8.enc\endcsname}% % \ifx \declaredencoding \ascii \asciichardefs % \else \ifx \declaredencoding \lattwo \iftxinativeunicodecapable \setbytewiseio \fi \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone \iftxinativeunicodecapable \setbytewiseio \fi \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine \iftxinativeunicodecapable \setbytewiseio \fi \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight \iftxinativeunicodecapable % For native Unicode handling (XeTeX and LuaTeX) \nativeunicodechardefs \else % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX) \setnonasciicharscatcode\active % since we already invoked \utfeightchardefs at the top level % (below), do not re-invoke it, otherwise our check for duplicated % definitions gets triggered. Making non-ascii chars active is % sufficient. \fi % \else \message{Ignoring unknown document encoding: #1.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii % \ifx\XeTeXrevision\thisisundefined \else \ifx \declaredencoding \utfeight \else \ifx \declaredencoding \ascii \else \message{Warning: XeTeX with non-UTF-8 encodings cannot handle % non-ASCII characters in auxiliary files.}% \fi \fi \fi } % emacs-page % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing, sorry: #1.}} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} % First, make active non-ASCII characters in order for them to be % correctly categorized when TeX reads the replacement text of % macros containing the character definitions. \setnonasciicharscatcode\active % \def\gdefchar#1#2{% \gdef#1{% \ifpassthroughchars \string#1% \else #2% \fi }} % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% \gdefchar^^a0{\tie} \gdefchar^^a1{\exclamdown} \gdefchar^^a2{{\tcfont \char162}} % cent \gdefchar^^a3{\pounds{}} \gdefchar^^a4{{\tcfont \char164}} % currency \gdefchar^^a5{{\tcfont \char165}} % yen \gdefchar^^a6{{\tcfont \char166}} % broken bar \gdefchar^^a7{\S} \gdefchar^^a8{\"{}} \gdefchar^^a9{\copyright{}} \gdefchar^^aa{\ordf} \gdefchar^^ab{\guillemetleft{}} \gdefchar^^ac{\ensuremath\lnot} \gdefchar^^ad{\-} \gdefchar^^ae{\registeredsymbol{}} \gdefchar^^af{\={}} % \gdefchar^^b0{\textdegree} \gdefchar^^b1{$\pm$} \gdefchar^^b2{$^2$} \gdefchar^^b3{$^3$} \gdefchar^^b4{\'{}} \gdefchar^^b5{$\mu$} \gdefchar^^b6{\P} \gdefchar^^b7{\ensuremath\cdot} \gdefchar^^b8{\cedilla\ } \gdefchar^^b9{$^1$} \gdefchar^^ba{\ordm} \gdefchar^^bb{\guillemetright{}} \gdefchar^^bc{$1\over4$} \gdefchar^^bd{$1\over2$} \gdefchar^^be{$3\over4$} \gdefchar^^bf{\questiondown} % \gdefchar^^c0{\`A} \gdefchar^^c1{\'A} \gdefchar^^c2{\^A} \gdefchar^^c3{\~A} \gdefchar^^c4{\"A} \gdefchar^^c5{\ringaccent A} \gdefchar^^c6{\AE} \gdefchar^^c7{\cedilla C} \gdefchar^^c8{\`E} \gdefchar^^c9{\'E} \gdefchar^^ca{\^E} \gdefchar^^cb{\"E} \gdefchar^^cc{\`I} \gdefchar^^cd{\'I} \gdefchar^^ce{\^I} \gdefchar^^cf{\"I} % \gdefchar^^d0{\DH} \gdefchar^^d1{\~N} \gdefchar^^d2{\`O} \gdefchar^^d3{\'O} \gdefchar^^d4{\^O} \gdefchar^^d5{\~O} \gdefchar^^d6{\"O} \gdefchar^^d7{$\times$} \gdefchar^^d8{\O} \gdefchar^^d9{\`U} \gdefchar^^da{\'U} \gdefchar^^db{\^U} \gdefchar^^dc{\"U} \gdefchar^^dd{\'Y} \gdefchar^^de{\TH} \gdefchar^^df{\ss} % \gdefchar^^e0{\`a} \gdefchar^^e1{\'a} \gdefchar^^e2{\^a} \gdefchar^^e3{\~a} \gdefchar^^e4{\"a} \gdefchar^^e5{\ringaccent a} \gdefchar^^e6{\ae} \gdefchar^^e7{\cedilla c} \gdefchar^^e8{\`e} \gdefchar^^e9{\'e} \gdefchar^^ea{\^e} \gdefchar^^eb{\"e} \gdefchar^^ec{\`{\dotless i}} \gdefchar^^ed{\'{\dotless i}} \gdefchar^^ee{\^{\dotless i}} \gdefchar^^ef{\"{\dotless i}} % \gdefchar^^f0{\dh} \gdefchar^^f1{\~n} \gdefchar^^f2{\`o} \gdefchar^^f3{\'o} \gdefchar^^f4{\^o} \gdefchar^^f5{\~o} \gdefchar^^f6{\"o} \gdefchar^^f7{$\div$} \gdefchar^^f8{\o} \gdefchar^^f9{\`u} \gdefchar^^fa{\'u} \gdefchar^^fb{\^u} \gdefchar^^fc{\"u} \gdefchar^^fd{\'y} \gdefchar^^fe{\th} \gdefchar^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. \def\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % \gdefchar^^a4{\euro{}} \gdefchar^^a6{\v S} \gdefchar^^a8{\v s} \gdefchar^^b4{\v Z} \gdefchar^^b8{\v z} \gdefchar^^bc{\OE} \gdefchar^^bd{\oe} \gdefchar^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% \gdefchar^^a0{\tie} \gdefchar^^a1{\ogonek{A}} \gdefchar^^a2{\u{}} \gdefchar^^a3{\L} \gdefchar^^a4{\missingcharmsg{CURRENCY SIGN}} \gdefchar^^a5{\v L} \gdefchar^^a6{\'S} \gdefchar^^a7{\S} \gdefchar^^a8{\"{}} \gdefchar^^a9{\v S} \gdefchar^^aa{\cedilla S} \gdefchar^^ab{\v T} \gdefchar^^ac{\'Z} \gdefchar^^ad{\-} \gdefchar^^ae{\v Z} \gdefchar^^af{\dotaccent Z} % \gdefchar^^b0{\textdegree{}} \gdefchar^^b1{\ogonek{a}} \gdefchar^^b2{\ogonek{ }} \gdefchar^^b3{\l} \gdefchar^^b4{\'{}} \gdefchar^^b5{\v l} \gdefchar^^b6{\'s} \gdefchar^^b7{\v{}} \gdefchar^^b8{\cedilla\ } \gdefchar^^b9{\v s} \gdefchar^^ba{\cedilla s} \gdefchar^^bb{\v t} \gdefchar^^bc{\'z} \gdefchar^^bd{\H{}} \gdefchar^^be{\v z} \gdefchar^^bf{\dotaccent z} % \gdefchar^^c0{\'R} \gdefchar^^c1{\'A} \gdefchar^^c2{\^A} \gdefchar^^c3{\u A} \gdefchar^^c4{\"A} \gdefchar^^c5{\'L} \gdefchar^^c6{\'C} \gdefchar^^c7{\cedilla C} \gdefchar^^c8{\v C} \gdefchar^^c9{\'E} \gdefchar^^ca{\ogonek{E}} \gdefchar^^cb{\"E} \gdefchar^^cc{\v E} \gdefchar^^cd{\'I} \gdefchar^^ce{\^I} \gdefchar^^cf{\v D} % \gdefchar^^d0{\DH} \gdefchar^^d1{\'N} \gdefchar^^d2{\v N} \gdefchar^^d3{\'O} \gdefchar^^d4{\^O} \gdefchar^^d5{\H O} \gdefchar^^d6{\"O} \gdefchar^^d7{$\times$} \gdefchar^^d8{\v R} \gdefchar^^d9{\ringaccent U} \gdefchar^^da{\'U} \gdefchar^^db{\H U} \gdefchar^^dc{\"U} \gdefchar^^dd{\'Y} \gdefchar^^de{\cedilla T} \gdefchar^^df{\ss} % \gdefchar^^e0{\'r} \gdefchar^^e1{\'a} \gdefchar^^e2{\^a} \gdefchar^^e3{\u a} \gdefchar^^e4{\"a} \gdefchar^^e5{\'l} \gdefchar^^e6{\'c} \gdefchar^^e7{\cedilla c} \gdefchar^^e8{\v c} \gdefchar^^e9{\'e} \gdefchar^^ea{\ogonek{e}} \gdefchar^^eb{\"e} \gdefchar^^ec{\v e} \gdefchar^^ed{\'{\dotless{i}}} \gdefchar^^ee{\^{\dotless{i}}} \gdefchar^^ef{\v d} % \gdefchar^^f0{\dh} \gdefchar^^f1{\'n} \gdefchar^^f2{\v n} \gdefchar^^f3{\'o} \gdefchar^^f4{\^o} \gdefchar^^f5{\H o} \gdefchar^^f6{\"o} \gdefchar^^f7{$\div$} \gdefchar^^f8{\v r} \gdefchar^^f9{\ringaccent u} \gdefchar^^fa{\'u} \gdefchar^^fb{\H u} \gdefchar^^fc{\"u} \gdefchar^^fd{\'y} \gdefchar^^fe{\cedilla t} \gdefchar^^ff{\dotaccent{}} } % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some % changes for Texinfo conventions. It is included here under the GPL by % permission from Frank Mittelbach and the LaTeX team. % \newcount\countUTFx \newcount\countUTFy \newcount\countUTFz \gdef\UTFviiiTwoOctets#1#2{\expandafter \UTFviiiDefined\csname u8:#1\string #2\endcsname} % \gdef\UTFviiiThreeOctets#1#2#3{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} % \gdef\UTFviiiFourOctets#1#2#3#4{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} \gdef\UTFviiiDefined#1{% \ifx #1\relax \message{\linenumber Unicode char \string #1 not defined for Texinfo}% \else \expandafter #1% \fi } % Give non-ASCII bytes the active definitions for processing UTF-8 sequences \begingroup \catcode`\~13 \catcode`\$12 \catcode`\"12 % Loop from \countUTFx to \countUTFy, performing \UTFviiiTmp % substituting ~ and $ with a character token of that value. \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx \uccode`\$\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} % For bytes other than the first in a UTF-8 sequence. Not expected to % be expanded except when writing to auxiliary files. \countUTFx = "80 \countUTFy = "C2 \def\UTFviiiTmp{% \gdef~{% \ifpassthroughchars $\fi}}% \UTFviiiLoop \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% \gdef~{% \ifpassthroughchars $% \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}% \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% \gdef~{% \ifpassthroughchars $% \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}% \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% \gdef~{% \ifpassthroughchars $% \else\expandafter\UTFviiiFourOctets\expandafter$\fi }}% \UTFviiiLoop \endgroup \def\globallet{\global\let} % save some \expandafter's below % @U{xxxx} to produce U+xxxx, if we support it. \def\U#1{% \expandafter\ifx\csname uni:#1\endcsname \relax \iftxinativeunicodecapable % All Unicode characters can be used if native Unicode handling is % active. However, if the font does not have the glyph, % letters are missing. \begingroup \uccode`\.="#1\relax \uppercase{.} \endgroup \else \errhelp = \EMsimple \errmessage{Unicode character U+#1 not supported, sorry}% \fi \else \csname uni:#1\endcsname \fi } % These macros are used here to construct the name of a control % sequence to be defined. \def\UTFviiiTwoOctetsName#1#2{% \csname u8:#1\string #2\endcsname}% \def\UTFviiiThreeOctetsName#1#2#3{% \csname u8:#1\string #2\string #3\endcsname}% \def\UTFviiiFourOctetsName#1#2#3#4{% \csname u8:#1\string #2\string #3\string #4\endcsname}% % For UTF-8 byte sequences (TeX, e-TeX and pdfTeX), % provide a definition macro to replace a Unicode character; % this gets used by the @U command % \begingroup \catcode`\"=12 \catcode`\<=12 \catcode`\.=12 \catcode`\,=12 \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 \gdef\DeclareUnicodeCharacterUTFviii#1#2{% \countUTFz = "#1\relax \begingroup \parseXMLCharref % Give \u8:... its definition. The sequence of seven \expandafter's % expands after the \gdef three times, e.g. % % 1. \UTFviiTwoOctetsName B1 B2 % 2. \csname u8:B1 \string B2 \endcsname % 3. \u8: B1 B2 (a single control sequence token) % \expandafter\expandafter \expandafter\expandafter \expandafter\expandafter \expandafter\gdef \UTFviiiTmp{#2}% % \expandafter\ifx\csname uni:#1\endcsname \relax \else \message{Internal error, already defined: #1}% \fi % % define an additional control sequence for this code point. \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp \endgroup} % % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp % to the corresponding UTF-8 sequence. \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% \parseUTFviiiB C\UTFviiiTwoOctetsName.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiB E\UTFviiiThreeOctetsName.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% \parseUTFviiiB F\UTFviiiFourOctetsName.{!,;}% \fi\fi\fi } % Extract a byte from the end of the UTF-8 representation of \countUTFx. % It must be a non-initial byte in the sequence. % Change \uccode of #1 for it to be used in \parseUTFviiiB as one % of the bytes. \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 \countUTFy = \countUTFz % Save to be the future value of \countUTFz. \multiply\countUTFz by 64 % \countUTFz is now \countUTFx with the last 5 bits cleared. Subtract % in order to get the last five bits. \advance\countUTFx by -\countUTFz % Convert this to the byte in the UTF-8 sequence. \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} % Used to put a UTF-8 byte sequence into \UTFviiiTmp % #1 is the increment for \countUTFz to yield a the first byte of the UTF-8 % sequence. % #2 is one of the \UTFviii*OctetsName macros. % #3 is always a full stop (.) % #4 is a template for the other bytes in the sequence. The values for these % bytes is substituted in here with \uppercase using the \uccode's. \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup % For native Unicode handling (XeTeX and LuaTeX), % provide a definition macro that sets a catcode to `other' non-globally % \def\DeclareUnicodeCharacterNativeOther#1#2{% \catcode"#1=\other } % https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M % U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block) % U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block) % U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A % U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B % % Many of our renditions are less than wonderful, and all the missing % characters are available somewhere. Loading the necessary fonts % awaits user request. We can't truly support Unicode without % reimplementing everything that's been done in LaTeX for many years, % plus probably using luatex or xetex, and who knows what else. % We won't be doing that here in this simple file. But we can try to at % least make most of the characters not bomb out. % \def\unicodechardefs{% \DeclareUnicodeCharacter{00A0}{\tie}% \DeclareUnicodeCharacter{00A1}{\exclamdown}% \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent \DeclareUnicodeCharacter{00A3}{\pounds{}}% \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar \DeclareUnicodeCharacter{00A7}{\S}% \DeclareUnicodeCharacter{00A8}{\"{ }}% \DeclareUnicodeCharacter{00A9}{\copyright{}}% \DeclareUnicodeCharacter{00AA}{\ordf}% \DeclareUnicodeCharacter{00AB}{\guillemetleft{}}% \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}% \DeclareUnicodeCharacter{00AD}{\-}% \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}% \DeclareUnicodeCharacter{00AF}{\={ }}% % \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}% \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}% \DeclareUnicodeCharacter{00B2}{$^2$}% \DeclareUnicodeCharacter{00B3}{$^3$}% \DeclareUnicodeCharacter{00B4}{\'{ }}% \DeclareUnicodeCharacter{00B5}{$\mu$}% \DeclareUnicodeCharacter{00B6}{\P}% \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}% \DeclareUnicodeCharacter{00B8}{\cedilla{ }}% \DeclareUnicodeCharacter{00B9}{$^1$}% \DeclareUnicodeCharacter{00BA}{\ordm}% \DeclareUnicodeCharacter{00BB}{\guillemetright{}}% \DeclareUnicodeCharacter{00BC}{$1\over4$}% \DeclareUnicodeCharacter{00BD}{$1\over2$}% \DeclareUnicodeCharacter{00BE}{$3\over4$}% \DeclareUnicodeCharacter{00BF}{\questiondown}% % \DeclareUnicodeCharacter{00C0}{\`A}% \DeclareUnicodeCharacter{00C1}{\'A}% \DeclareUnicodeCharacter{00C2}{\^A}% \DeclareUnicodeCharacter{00C3}{\~A}% \DeclareUnicodeCharacter{00C4}{\"A}% \DeclareUnicodeCharacter{00C5}{\AA}% \DeclareUnicodeCharacter{00C6}{\AE}% \DeclareUnicodeCharacter{00C7}{\cedilla{C}}% \DeclareUnicodeCharacter{00C8}{\`E}% \DeclareUnicodeCharacter{00C9}{\'E}% \DeclareUnicodeCharacter{00CA}{\^E}% \DeclareUnicodeCharacter{00CB}{\"E}% \DeclareUnicodeCharacter{00CC}{\`I}% \DeclareUnicodeCharacter{00CD}{\'I}% \DeclareUnicodeCharacter{00CE}{\^I}% \DeclareUnicodeCharacter{00CF}{\"I}% % \DeclareUnicodeCharacter{00D0}{\DH}% \DeclareUnicodeCharacter{00D1}{\~N}% \DeclareUnicodeCharacter{00D2}{\`O}% \DeclareUnicodeCharacter{00D3}{\'O}% \DeclareUnicodeCharacter{00D4}{\^O}% \DeclareUnicodeCharacter{00D5}{\~O}% \DeclareUnicodeCharacter{00D6}{\"O}% \DeclareUnicodeCharacter{00D7}{\ensuremath\times}% \DeclareUnicodeCharacter{00D8}{\O}% \DeclareUnicodeCharacter{00D9}{\`U}% \DeclareUnicodeCharacter{00DA}{\'U}% \DeclareUnicodeCharacter{00DB}{\^U}% \DeclareUnicodeCharacter{00DC}{\"U}% \DeclareUnicodeCharacter{00DD}{\'Y}% \DeclareUnicodeCharacter{00DE}{\TH}% \DeclareUnicodeCharacter{00DF}{\ss}% % \DeclareUnicodeCharacter{00E0}{\`a}% \DeclareUnicodeCharacter{00E1}{\'a}% \DeclareUnicodeCharacter{00E2}{\^a}% \DeclareUnicodeCharacter{00E3}{\~a}% \DeclareUnicodeCharacter{00E4}{\"a}% \DeclareUnicodeCharacter{00E5}{\aa}% \DeclareUnicodeCharacter{00E6}{\ae}% \DeclareUnicodeCharacter{00E7}{\cedilla{c}}% \DeclareUnicodeCharacter{00E8}{\`e}% \DeclareUnicodeCharacter{00E9}{\'e}% \DeclareUnicodeCharacter{00EA}{\^e}% \DeclareUnicodeCharacter{00EB}{\"e}% \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}% \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}% \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}% \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}% % \DeclareUnicodeCharacter{00F0}{\dh}% \DeclareUnicodeCharacter{00F1}{\~n}% \DeclareUnicodeCharacter{00F2}{\`o}% \DeclareUnicodeCharacter{00F3}{\'o}% \DeclareUnicodeCharacter{00F4}{\^o}% \DeclareUnicodeCharacter{00F5}{\~o}% \DeclareUnicodeCharacter{00F6}{\"o}% \DeclareUnicodeCharacter{00F7}{\ensuremath\div}% \DeclareUnicodeCharacter{00F8}{\o}% \DeclareUnicodeCharacter{00F9}{\`u}% \DeclareUnicodeCharacter{00FA}{\'u}% \DeclareUnicodeCharacter{00FB}{\^u}% \DeclareUnicodeCharacter{00FC}{\"u}% \DeclareUnicodeCharacter{00FD}{\'y}% \DeclareUnicodeCharacter{00FE}{\th}% \DeclareUnicodeCharacter{00FF}{\"y}% % \DeclareUnicodeCharacter{0100}{\=A}% \DeclareUnicodeCharacter{0101}{\=a}% \DeclareUnicodeCharacter{0102}{\u{A}}% \DeclareUnicodeCharacter{0103}{\u{a}}% \DeclareUnicodeCharacter{0104}{\ogonek{A}}% \DeclareUnicodeCharacter{0105}{\ogonek{a}}% \DeclareUnicodeCharacter{0106}{\'C}% \DeclareUnicodeCharacter{0107}{\'c}% \DeclareUnicodeCharacter{0108}{\^C}% \DeclareUnicodeCharacter{0109}{\^c}% \DeclareUnicodeCharacter{010A}{\dotaccent{C}}% \DeclareUnicodeCharacter{010B}{\dotaccent{c}}% \DeclareUnicodeCharacter{010C}{\v{C}}% \DeclareUnicodeCharacter{010D}{\v{c}}% \DeclareUnicodeCharacter{010E}{\v{D}}% \DeclareUnicodeCharacter{010F}{d'}% % \DeclareUnicodeCharacter{0110}{\DH}% \DeclareUnicodeCharacter{0111}{\dh}% \DeclareUnicodeCharacter{0112}{\=E}% \DeclareUnicodeCharacter{0113}{\=e}% \DeclareUnicodeCharacter{0114}{\u{E}}% \DeclareUnicodeCharacter{0115}{\u{e}}% \DeclareUnicodeCharacter{0116}{\dotaccent{E}}% \DeclareUnicodeCharacter{0117}{\dotaccent{e}}% \DeclareUnicodeCharacter{0118}{\ogonek{E}}% \DeclareUnicodeCharacter{0119}{\ogonek{e}}% \DeclareUnicodeCharacter{011A}{\v{E}}% \DeclareUnicodeCharacter{011B}{\v{e}}% \DeclareUnicodeCharacter{011C}{\^G}% \DeclareUnicodeCharacter{011D}{\^g}% \DeclareUnicodeCharacter{011E}{\u{G}}% \DeclareUnicodeCharacter{011F}{\u{g}}% % \DeclareUnicodeCharacter{0120}{\dotaccent{G}}% \DeclareUnicodeCharacter{0121}{\dotaccent{g}}% \DeclareUnicodeCharacter{0122}{\cedilla{G}}% \DeclareUnicodeCharacter{0123}{\cedilla{g}}% \DeclareUnicodeCharacter{0124}{\^H}% \DeclareUnicodeCharacter{0125}{\^h}% \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}% \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}% \DeclareUnicodeCharacter{0128}{\~I}% \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}% \DeclareUnicodeCharacter{012A}{\=I}% \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}% \DeclareUnicodeCharacter{012C}{\u{I}}% \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}% \DeclareUnicodeCharacter{012E}{\ogonek{I}}% \DeclareUnicodeCharacter{012F}{\ogonek{i}}% % \DeclareUnicodeCharacter{0130}{\dotaccent{I}}% \DeclareUnicodeCharacter{0131}{\dotless{i}}% \DeclareUnicodeCharacter{0132}{IJ}% \DeclareUnicodeCharacter{0133}{ij}% \DeclareUnicodeCharacter{0134}{\^J}% \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}% \DeclareUnicodeCharacter{0136}{\cedilla{K}}% \DeclareUnicodeCharacter{0137}{\cedilla{k}}% \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}% \DeclareUnicodeCharacter{0139}{\'L}% \DeclareUnicodeCharacter{013A}{\'l}% \DeclareUnicodeCharacter{013B}{\cedilla{L}}% \DeclareUnicodeCharacter{013C}{\cedilla{l}}% \DeclareUnicodeCharacter{013D}{L'}% should kern \DeclareUnicodeCharacter{013E}{l'}% should kern \DeclareUnicodeCharacter{013F}{L\U{00B7}}% % \DeclareUnicodeCharacter{0140}{l\U{00B7}}% \DeclareUnicodeCharacter{0141}{\L}% \DeclareUnicodeCharacter{0142}{\l}% \DeclareUnicodeCharacter{0143}{\'N}% \DeclareUnicodeCharacter{0144}{\'n}% \DeclareUnicodeCharacter{0145}{\cedilla{N}}% \DeclareUnicodeCharacter{0146}{\cedilla{n}}% \DeclareUnicodeCharacter{0147}{\v{N}}% \DeclareUnicodeCharacter{0148}{\v{n}}% \DeclareUnicodeCharacter{0149}{'n}% \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}% \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}% \DeclareUnicodeCharacter{014C}{\=O}% \DeclareUnicodeCharacter{014D}{\=o}% \DeclareUnicodeCharacter{014E}{\u{O}}% \DeclareUnicodeCharacter{014F}{\u{o}}% % \DeclareUnicodeCharacter{0150}{\H{O}}% \DeclareUnicodeCharacter{0151}{\H{o}}% \DeclareUnicodeCharacter{0152}{\OE}% \DeclareUnicodeCharacter{0153}{\oe}% \DeclareUnicodeCharacter{0154}{\'R}% \DeclareUnicodeCharacter{0155}{\'r}% \DeclareUnicodeCharacter{0156}{\cedilla{R}}% \DeclareUnicodeCharacter{0157}{\cedilla{r}}% \DeclareUnicodeCharacter{0158}{\v{R}}% \DeclareUnicodeCharacter{0159}{\v{r}}% \DeclareUnicodeCharacter{015A}{\'S}% \DeclareUnicodeCharacter{015B}{\'s}% \DeclareUnicodeCharacter{015C}{\^S}% \DeclareUnicodeCharacter{015D}{\^s}% \DeclareUnicodeCharacter{015E}{\cedilla{S}}% \DeclareUnicodeCharacter{015F}{\cedilla{s}}% % \DeclareUnicodeCharacter{0160}{\v{S}}% \DeclareUnicodeCharacter{0161}{\v{s}}% \DeclareUnicodeCharacter{0162}{\cedilla{T}}% \DeclareUnicodeCharacter{0163}{\cedilla{t}}% \DeclareUnicodeCharacter{0164}{\v{T}}% \DeclareUnicodeCharacter{0165}{\v{t}}% \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}% \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}% \DeclareUnicodeCharacter{0168}{\~U}% \DeclareUnicodeCharacter{0169}{\~u}% \DeclareUnicodeCharacter{016A}{\=U}% \DeclareUnicodeCharacter{016B}{\=u}% \DeclareUnicodeCharacter{016C}{\u{U}}% \DeclareUnicodeCharacter{016D}{\u{u}}% \DeclareUnicodeCharacter{016E}{\ringaccent{U}}% \DeclareUnicodeCharacter{016F}{\ringaccent{u}}% % \DeclareUnicodeCharacter{0170}{\H{U}}% \DeclareUnicodeCharacter{0171}{\H{u}}% \DeclareUnicodeCharacter{0172}{\ogonek{U}}% \DeclareUnicodeCharacter{0173}{\ogonek{u}}% \DeclareUnicodeCharacter{0174}{\^W}% \DeclareUnicodeCharacter{0175}{\^w}% \DeclareUnicodeCharacter{0176}{\^Y}% \DeclareUnicodeCharacter{0177}{\^y}% \DeclareUnicodeCharacter{0178}{\"Y}% \DeclareUnicodeCharacter{0179}{\'Z}% \DeclareUnicodeCharacter{017A}{\'z}% \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}% \DeclareUnicodeCharacter{017C}{\dotaccent{z}}% \DeclareUnicodeCharacter{017D}{\v{Z}}% \DeclareUnicodeCharacter{017E}{\v{z}}% \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}% % \DeclareUnicodeCharacter{01C4}{D\v{Z}}% \DeclareUnicodeCharacter{01C5}{D\v{z}}% \DeclareUnicodeCharacter{01C6}{d\v{z}}% \DeclareUnicodeCharacter{01C7}{LJ}% \DeclareUnicodeCharacter{01C8}{Lj}% \DeclareUnicodeCharacter{01C9}{lj}% \DeclareUnicodeCharacter{01CA}{NJ}% \DeclareUnicodeCharacter{01CB}{Nj}% \DeclareUnicodeCharacter{01CC}{nj}% \DeclareUnicodeCharacter{01CD}{\v{A}}% \DeclareUnicodeCharacter{01CE}{\v{a}}% \DeclareUnicodeCharacter{01CF}{\v{I}}% % \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}% \DeclareUnicodeCharacter{01D1}{\v{O}}% \DeclareUnicodeCharacter{01D2}{\v{o}}% \DeclareUnicodeCharacter{01D3}{\v{U}}% \DeclareUnicodeCharacter{01D4}{\v{u}}% % \DeclareUnicodeCharacter{01E2}{\={\AE}}% \DeclareUnicodeCharacter{01E3}{\={\ae}}% \DeclareUnicodeCharacter{01E6}{\v{G}}% \DeclareUnicodeCharacter{01E7}{\v{g}}% \DeclareUnicodeCharacter{01E8}{\v{K}}% \DeclareUnicodeCharacter{01E9}{\v{k}}% % \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}% \DeclareUnicodeCharacter{01F1}{DZ}% \DeclareUnicodeCharacter{01F2}{Dz}% \DeclareUnicodeCharacter{01F3}{dz}% \DeclareUnicodeCharacter{01F4}{\'G}% \DeclareUnicodeCharacter{01F5}{\'g}% \DeclareUnicodeCharacter{01F8}{\`N}% \DeclareUnicodeCharacter{01F9}{\`n}% \DeclareUnicodeCharacter{01FC}{\'{\AE}}% \DeclareUnicodeCharacter{01FD}{\'{\ae}}% \DeclareUnicodeCharacter{01FE}{\'{\O}}% \DeclareUnicodeCharacter{01FF}{\'{\o}}% % \DeclareUnicodeCharacter{021E}{\v{H}}% \DeclareUnicodeCharacter{021F}{\v{h}}% % \DeclareUnicodeCharacter{0226}{\dotaccent{A}}% \DeclareUnicodeCharacter{0227}{\dotaccent{a}}% \DeclareUnicodeCharacter{0228}{\cedilla{E}}% \DeclareUnicodeCharacter{0229}{\cedilla{e}}% \DeclareUnicodeCharacter{022E}{\dotaccent{O}}% \DeclareUnicodeCharacter{022F}{\dotaccent{o}}% % \DeclareUnicodeCharacter{0232}{\=Y}% \DeclareUnicodeCharacter{0233}{\=y}% \DeclareUnicodeCharacter{0237}{\dotless{j}}% % \DeclareUnicodeCharacter{02DB}{\ogonek{ }}% % % Greek letters upper case \DeclareUnicodeCharacter{0391}{{\it A}}% \DeclareUnicodeCharacter{0392}{{\it B}}% \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}% \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}% \DeclareUnicodeCharacter{0395}{{\it E}}% \DeclareUnicodeCharacter{0396}{{\it Z}}% \DeclareUnicodeCharacter{0397}{{\it H}}% \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}% \DeclareUnicodeCharacter{0399}{{\it I}}% \DeclareUnicodeCharacter{039A}{{\it K}}% \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}% \DeclareUnicodeCharacter{039C}{{\it M}}% \DeclareUnicodeCharacter{039D}{{\it N}}% \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}% \DeclareUnicodeCharacter{039F}{{\it O}}% \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}% \DeclareUnicodeCharacter{03A1}{{\it P}}% %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}% \DeclareUnicodeCharacter{03A4}{{\it T}}% \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}% \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}% \DeclareUnicodeCharacter{03A7}{{\it X}}% \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}% \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}% % % Vowels with accents \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}% \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}% \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}% \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}% \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}% \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}% % % Standalone accent \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}% % % Greek letters lower case \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}% \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}% \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}% \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}% \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}% \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}% \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}% \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}% \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}% \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}% \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}% \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}% \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}% \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}% \DeclareUnicodeCharacter{03BF}{{\it o}}% omicron \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}% \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}% \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}% \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}% \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}% \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}% \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}% \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}% \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}% \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}% % % More Greek vowels with accents \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}% \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}% \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}% \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}% \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}% % % Variant Greek letters \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}% \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}% \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}% % \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}% \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}% \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}% \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}% \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}% \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}% \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}% \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}% \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}% \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}% \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}% \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}% % \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}% \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}% % \DeclareUnicodeCharacter{1E20}{\=G}% \DeclareUnicodeCharacter{1E21}{\=g}% \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}% \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}% \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}% \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}% \DeclareUnicodeCharacter{1E26}{\"H}% \DeclareUnicodeCharacter{1E27}{\"h}% % \DeclareUnicodeCharacter{1E30}{\'K}% \DeclareUnicodeCharacter{1E31}{\'k}% \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}% \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}% \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}% \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}% \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}% \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}% \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}% \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}% \DeclareUnicodeCharacter{1E3E}{\'M}% \DeclareUnicodeCharacter{1E3F}{\'m}% % \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}% \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}% \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}% \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}% \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}% \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}% \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}% \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}% \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}% \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}% % \DeclareUnicodeCharacter{1E54}{\'P}% \DeclareUnicodeCharacter{1E55}{\'p}% \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}% \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}% \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}% \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}% \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}% \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}% \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}% \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}% % \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}% \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}% \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}% \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}% \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}% \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}% \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}% \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}% \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}% \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}% % \DeclareUnicodeCharacter{1E7C}{\~V}% \DeclareUnicodeCharacter{1E7D}{\~v}% \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}% \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}% % \DeclareUnicodeCharacter{1E80}{\`W}% \DeclareUnicodeCharacter{1E81}{\`w}% \DeclareUnicodeCharacter{1E82}{\'W}% \DeclareUnicodeCharacter{1E83}{\'w}% \DeclareUnicodeCharacter{1E84}{\"W}% \DeclareUnicodeCharacter{1E85}{\"w}% \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}% \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}% \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}% \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}% \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}% \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}% \DeclareUnicodeCharacter{1E8C}{\"X}% \DeclareUnicodeCharacter{1E8D}{\"x}% \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}% \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}% % \DeclareUnicodeCharacter{1E90}{\^Z}% \DeclareUnicodeCharacter{1E91}{\^z}% \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}% \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}% \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}% \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}% \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}% \DeclareUnicodeCharacter{1E97}{\"t}% \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}% \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}% % \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}% \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}% % \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}% \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}% \DeclareUnicodeCharacter{1EBC}{\~E}% \DeclareUnicodeCharacter{1EBD}{\~e}% % \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}% \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}% \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}% \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}% % \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}% \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}% % \DeclareUnicodeCharacter{1EF2}{\`Y}% \DeclareUnicodeCharacter{1EF3}{\`y}% \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}% % \DeclareUnicodeCharacter{1EF8}{\~Y}% \DeclareUnicodeCharacter{1EF9}{\~y}% % % Punctuation \DeclareUnicodeCharacter{2013}{--}% \DeclareUnicodeCharacter{2014}{---}% \DeclareUnicodeCharacter{2018}{\quoteleft{}}% \DeclareUnicodeCharacter{2019}{\quoteright{}}% \DeclareUnicodeCharacter{201A}{\quotesinglbase{}}% \DeclareUnicodeCharacter{201C}{\quotedblleft{}}% \DeclareUnicodeCharacter{201D}{\quotedblright{}}% \DeclareUnicodeCharacter{201E}{\quotedblbase{}}% \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}% \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}% \DeclareUnicodeCharacter{2022}{\bullet{}}% \DeclareUnicodeCharacter{202F}{\thinspace}% \DeclareUnicodeCharacter{2026}{\dots{}}% \DeclareUnicodeCharacter{2039}{\guilsinglleft{}}% \DeclareUnicodeCharacter{203A}{\guilsinglright{}}% % \DeclareUnicodeCharacter{20AC}{\euro{}}% % \DeclareUnicodeCharacter{2192}{\expansion{}}% \DeclareUnicodeCharacter{21D2}{\result{}}% % % Mathematical symbols \DeclareUnicodeCharacter{2200}{\ensuremath\forall}% \DeclareUnicodeCharacter{2203}{\ensuremath\exists}% \DeclareUnicodeCharacter{2208}{\ensuremath\in}% \DeclareUnicodeCharacter{2212}{\minus{}}% \DeclareUnicodeCharacter{2217}{\ast}% \DeclareUnicodeCharacter{221E}{\ensuremath\infty}% \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}% \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}% \DeclareUnicodeCharacter{2229}{\ensuremath\cap}% \DeclareUnicodeCharacter{2261}{\equiv{}}% \DeclareUnicodeCharacter{2264}{\ensuremath\leq}% \DeclareUnicodeCharacter{2265}{\ensuremath\geq}% \DeclareUnicodeCharacter{2282}{\ensuremath\subset}% \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}% % \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}% \DeclareUnicodeCharacter{2032}{\ensuremath\prime}% \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}% \DeclareUnicodeCharacter{2111}{\ensuremath\Im}% \DeclareUnicodeCharacter{2113}{\ensuremath\ell}% \DeclareUnicodeCharacter{2118}{\ensuremath\wp}% \DeclareUnicodeCharacter{211C}{\ensuremath\Re}% \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}% \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}% \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}% \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}% \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}% \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}% \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}% \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}% \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}% \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}% \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}% \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}% \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}% \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}% \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}% \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}% \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}% \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}% \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}% \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}% \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}% \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}% \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}% \DeclareUnicodeCharacter{2202}{\ensuremath\partial}% \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}% \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}% \DeclareUnicodeCharacter{2209}{\ensuremath\notin}% \DeclareUnicodeCharacter{220B}{\ensuremath\owns}% \DeclareUnicodeCharacter{220F}{\ensuremath\prod}% \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}% \DeclareUnicodeCharacter{2211}{\ensuremath\sum}% \DeclareUnicodeCharacter{2213}{\ensuremath\mp}% \DeclareUnicodeCharacter{2218}{\ensuremath\circ}% \DeclareUnicodeCharacter{221A}{\ensuremath\surd}% \DeclareUnicodeCharacter{221D}{\ensuremath\propto}% \DeclareUnicodeCharacter{2220}{\ensuremath\angle}% \DeclareUnicodeCharacter{2223}{\ensuremath\mid}% \DeclareUnicodeCharacter{2228}{\ensuremath\vee}% \DeclareUnicodeCharacter{222A}{\ensuremath\cup}% \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}% \DeclareUnicodeCharacter{222E}{\ensuremath\oint}% \DeclareUnicodeCharacter{223C}{\ensuremath\sim}% \DeclareUnicodeCharacter{2240}{\ensuremath\wr}% \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}% \DeclareUnicodeCharacter{2245}{\ensuremath\cong}% \DeclareUnicodeCharacter{2248}{\ensuremath\approx}% \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}% \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}% \DeclareUnicodeCharacter{2260}{\ensuremath\neq}% \DeclareUnicodeCharacter{226A}{\ensuremath\ll}% \DeclareUnicodeCharacter{226B}{\ensuremath\gg}% \DeclareUnicodeCharacter{227A}{\ensuremath\prec}% \DeclareUnicodeCharacter{227B}{\ensuremath\succ}% \DeclareUnicodeCharacter{2283}{\ensuremath\supset}% \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}% \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}% \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}% \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}% \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}% \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}% \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}% \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}% \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}% \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}% \DeclareUnicodeCharacter{2299}{\ensuremath\odot}% \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}% \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}% \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}% \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}% \DeclareUnicodeCharacter{22A8}{\ensuremath\models}% \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}% \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}% \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}% \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}% \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}% \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}% \DeclareUnicodeCharacter{22C6}{\ensuremath\star}% \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}% \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}% \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}% \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}% \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}% \DeclareUnicodeCharacter{2322}{\ensuremath\frown}% \DeclareUnicodeCharacter{2323}{\ensuremath\smile}% % \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}% \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}% \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}% \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}% \DeclareUnicodeCharacter{25C7}{\ensuremath\diamond}% \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}% \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}% \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}% \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}% \DeclareUnicodeCharacter{266D}{\ensuremath\flat}% \DeclareUnicodeCharacter{266E}{\ensuremath\natural}% \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}% \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}% \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}% \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}% \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}% \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}% \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}% \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}% \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}% \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}% \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}% \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}% \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}% \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}% \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}% \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}% \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}% \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}% % \global\mathchardef\checkmark="1370% actually the square root sign \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}% }% end of \unicodechardefs % UTF-8 byte sequence (pdfTeX) definitions (replacing and @U command) % It makes the setting that replace UTF-8 byte sequence. \def\utfeightchardefs{% \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterUTFviii \unicodechardefs } % Whether the active definitions of non-ASCII characters expand to % non-active tokens with the same character code. This is used to % write characters literally, instead of using active definitions for % printing the correct glyphs. \newif\ifpassthroughchars \passthroughcharsfalse % For native Unicode handling (XeTeX and LuaTeX), % provide a definition macro to replace/pass-through a Unicode character % \def\DeclareUnicodeCharacterNative#1#2{% \catcode"#1=\active \def\dodeclareunicodecharacternative##1##2##3{% \begingroup \uccode`\~="##2\relax \uppercase{\gdef~}{% \ifpassthroughchars ##1% \else ##3% \fi } \endgroup } \begingroup \uccode`\.="#1\relax \uppercase{\def\UTFNativeTmp{.}}% \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}% \endgroup } % Native Unicode handling (XeTeX and LuaTeX) character replacing definition. % It activates the setting that replaces Unicode characters. \def\nativeunicodechardefs{% \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNative \unicodechardefs } % For native Unicode handling (XeTeX and LuaTeX), % make the character token expand % to the sequences given in \unicodechardefs for printing. \def\DeclareUnicodeCharacterNativeAtU#1#2{% \def\UTFAtUTmp{#2} \expandafter\globallet\csname uni:#1\endcsname \UTFAtUTmp } % @U command definitions for native Unicode handling (XeTeX and LuaTeX). \def\nativeunicodechardefsatu{% \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNativeAtU \unicodechardefs } % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % define all Unicode characters we know about, for the sake of @U. \iftxinativeunicodecapable \nativeunicodechardefsatu \else \utfeightchardefs \fi % Make non-ASCII characters printable again for compatibility with % existing Texinfo documents that may use them, even without declaring a % document encoding. % \setnonasciicharscatcode \other \message{formatting,} \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be very finicky about underfull hboxes, either. \hbadness = 6666 % Following George Bush, get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \txipageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \txipagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax % if we don't reset these, they will remain at "1 true in" of % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in \else \ifx\XeTeXrevision\thisisundefined \special{papersize=#8,#7}% \else \pdfpageheight #7\relax \pdfpagewidth #8\relax % XeTeX does not have \pdfhorigin and \pdfvorigin. \fi \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{607.2pt}{6in}% that's 46 lines {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {-.2in}{0in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{673.2pt}{160mm}% that's 51 lines {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1\relax \advance\dimen0 by \voffset \advance\dimen0 by 1in % reference point for DVI is 1 inch from top of page % \dimen2 = \hsize \advance\dimen2 by \normaloffset \advance\dimen2 by 1in % reference point is 1 inch from left edge of page % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper % Default value of \hfuzz, for suppressing warnings about overfull hboxes. \hfuzz = 1pt \message{and turning on texinfo input format.} \def^^L{\par} % remove \outer, so ^L can appear in an @comment % DEL is a comment character, in case @c does not suffice. \catcode`\^^? = 14 % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \def\normaldoublequote{"} \catcode`\$=\other \def\normaldollar{$}%$ font-lock fix \catcode`\+=\other \def\normalplus{+} \catcode`\<=\other \def\normalless{<} \catcode`\>=\other \def\normalgreater{>} \catcode`\^=\other \def\normalcaret{^} \catcode`\_=\other \def\normalunderscore{_} \catcode`\|=\other \def\normalverticalbar{|} \catcode`\~=\other \def\normaltilde{~} % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Set catcodes for Texinfo file % Active characters for printing the wanted glyph. % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. % \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def\activetilde{{\tt\char126}} \let~ = \activetilde \chardef\hatchar=`\^ \catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \let\realunder=_ \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless \chardef \gtr=`\> \catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix \catcode`\-=\active \let-=\normaldash % used for headline/footline in the output routine, in case the page % breaks in the middle of an @tex block. \def\texinfochars{% \let< = \activeless \let> = \activegtr \let~ = \activetilde \let^ = \activehat \markupsetuplqdefault \markupsetuprqdefault \let\b = \strong \let\i = \smartitalic % in principle, all other definitions in \tex have to be undone too. } % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In Texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active % @ for escape char from now on. % Print a typewriter backslash. For math mode, we can't simply use % \backslashcurfont: the story here is that in math mode, the \char % of \backslashcurfont ends up printing the roman \ from the math symbol % font (because \char in math mode uses the \mathcode, and plain.tex % sets \mathcode`\\="026E). Hence we use an explicit \mathchar, % which is the decimal equivalent of "715c (class 7, e.g., use \fam; % ignored family value; char position "5C). We can't use " for the % usual hex value because it has already been made active. @def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} @let@backslashchar = @ttbackslash % @backslashchar{} is for user documents. % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. We switch back and forth between these. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. % {@catcode`- = @active @gdef@normalturnoffactive{% @passthroughcharstrue @let-=@normaldash @let"=@normaldoublequote @let$=@normaldollar %$ font-lock fix @let+=@normalplus @let<=@normalless @let>=@normalgreater @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let~=@normaltilde @let\=@ttbackslash @markupsetuplqdefault @markupsetuprqdefault @unsepspaces } } % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have @fixbackslash turn them back on. @catcode`+=@other @catcode`@_=@other % \enablebackslashhack - allow file to begin `\input texinfo' % % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % If the file did not have a `\input texinfo', then it is turned off after % the first line; otherwise the first `\' in the file would cause an error. % This is used on the very last line of this file, texinfo.tex. % We also use @c to call @fixbackslash, in case ends of lines are hidden. { @catcode`@^=7 @catcode`@^^M=13@gdef@enablebackslashhack{% @global@let\ = @eatinput% @catcode`@^^M=13% @def@c{@fixbackslash@c}% % Definition for the newline at the end of this file. @def ^^M{@let^^M@secondlinenl}% % Definition for a newline in the main Texinfo file. @gdef @secondlinenl{@fixbackslash}% % In case the first line has a whole-line command on it @let@originalparsearg@parsearg @def@parsearg{@fixbackslash@originalparsearg} }} {@catcode`@^=7 @catcode`@^^M=13% @gdef@eatinput input texinfo#1^^M{@fixbackslash}} % Emergency active definition of newline, in case an active newline token % appears by mistake. {@catcode`@^=7 @catcode13=13% @gdef@enableemergencynewline{% @gdef^^M{% @par% %@par% }}} @gdef@fixbackslash{% @ifx\@eatinput @let\ = @ttbackslash @fi @catcode13=5 % regular end of line @enableemergencynewline @let@c=@texinfoc @let@parsearg@originalparsearg % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. @catcode`+=@active @catcode`@_=@active % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. This macro, @fixbackslash, gets % called at the beginning of every Texinfo file. Not opening texinfo.cnf % directly in this file, texinfo.tex, makes it possible to make a format % file for Texinfo. % @openin 1 texinfo.cnf @ifeof 1 @else @input texinfo.cnf @fi @closein 1 } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These (along with & and #) are made active for url-breaking, so need % active definitions as the normal characters. @def@normaldot{.} @def@normalquest{?} @def@normalslash{/} % These look ok in all fonts, so just make them not special. % @hashchar{} gets its own user-level command, because of #line. @catcode`@& = @other @def@normalamp{&} @catcode`@# = @other @def@normalhash{#} @catcode`@% = @other @def@normalpercent{%} @let @hashchar = @normalhash @c Finally, make ` and ' active, so that txicodequoteundirected and @c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we @c don't make ` and ' active, @code will not get them as active chars. @c Do this last of all since we use ` in the previous @catcode assignments. @catcode`@'=@active @catcode`@`=@active @markupsetuplqdefault @markupsetuprqdefault @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message\\|emacs-page" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @enablebackslashhack speech-dispatcher-0.9.1/doc/mdate-sh0000755000175000017500000001373213465233610014243 00000000000000#!/bin/sh # Get modification time of a file or directory and pretty-print it. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1995-2018 Free Software Foundation, Inc. # written by Ulrich Drepper , June 1995 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST fi case $1 in '') echo "$0: No file. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: mdate-sh [--help] [--version] FILE Pretty-print the modification day of FILE, in the format: 1 January 1970 Report bugs to . EOF exit $? ;; -v | --v*) echo "mdate-sh $scriptversion" exit $? ;; esac error () { echo "$0: $1" >&2 exit 1 } # Prevent date giving response in another language. LANG=C export LANG LC_ALL=C export LC_ALL LC_TIME=C export LC_TIME # Use UTC to get reproducible result. TZ=UTC0 export TZ # GNU ls changes its time format in response to the TIME_STYLE # variable. Since we cannot assume 'unset' works, revert this # variable to its documented default. if test "${TIME_STYLE+set}" = set; then TIME_STYLE=posix-long-iso export TIME_STYLE fi save_arg1=$1 # Find out how to get the extended ls output of a file or directory. if ls -L /dev/null 1>/dev/null 2>&1; then ls_command='ls -L -l -d' else ls_command='ls -l -d' fi # Avoid user/group names that might have spaces, when possible. if ls -n /dev/null 1>/dev/null 2>&1; then ls_command="$ls_command -n" fi # A 'ls -l' line looks as follows on OS/2. # drwxrwx--- 0 Aug 11 2001 foo # This differs from Unix, which adds ownership information. # drwxrwx--- 2 root root 4096 Aug 11 2001 foo # # To find the date, we split the line on spaces and iterate on words # until we find a month. This cannot work with files whose owner is a # user named "Jan", or "Feb", etc. However, it's unlikely that '/' # will be owned by a user whose name is a month. So we first look at # the extended ls output of the root directory to decide how many # words should be skipped to get the date. # On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. set x`$ls_command /` # Find which argument is the month. month= command= until test $month do test $# -gt 0 || error "failed parsing '$ls_command /' output" shift # Add another shift to the command. command="$command shift;" case $1 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac done test -n "$month" || error "failed parsing '$ls_command /' output" # Get the extended ls output of the file or directory. set dummy x`eval "$ls_command \"\\\$save_arg1\""` # Remove all preceding arguments eval $command # Because of the dummy argument above, month is in $2. # # On a POSIX system, we should have # # $# = 5 # $1 = file size # $2 = month # $3 = day # $4 = year or time # $5 = filename # # On Darwin 7.7.0 and 7.6.0, we have # # $# = 4 # $1 = day # $2 = month # $3 = year or time # $4 = filename # Get the month. case $2 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac case $3 in ???*) day=$1;; *) day=$3; shift;; esac # Here we have to deal with the problem that the ls output gives either # the time of day or the year. case $3 in *:*) set `date`; eval year=\$$# case $2 in Jan) nummonthtod=1;; Feb) nummonthtod=2;; Mar) nummonthtod=3;; Apr) nummonthtod=4;; May) nummonthtod=5;; Jun) nummonthtod=6;; Jul) nummonthtod=7;; Aug) nummonthtod=8;; Sep) nummonthtod=9;; Oct) nummonthtod=10;; Nov) nummonthtod=11;; Dec) nummonthtod=12;; esac # For the first six month of the year the time notation can also # be used for files modified in the last year. if (expr $nummonth \> $nummonthtod) > /dev/null; then year=`expr $year - 1` fi;; *) year=$3;; esac # The result. echo $day $month $year # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: speech-dispatcher-0.9.1/doc/README0000644000175000017500000000250713372121501013461 00000000000000All project documentation is written using Texinfo. (You can get the latest texinfo.tex from ftp://ftp.gnu.org/gnu/texinfo.tex (and all GNU mirrors)) The Makefile in this directory allows you to build the documentation from Texinfo sources in one of these formats: info, HTML, DVI and PDF. To build one of supported formats, run "make ", Where is supplyed by name of the format in lowercase. For example: make info The make process REQUIRES: * Texinfo * Tex (for generating PDF and DVI) Copyright (C) 2001-2003 Brailcom, o.p.s Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' You can also (at your option) distribute this manual under the GNU General Public License: Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled ``GNU General Public License'' speech-dispatcher-0.9.1/doc/Makefile.in0000644000175000017500000010725413465233610014663 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/version.texi \ $(srcdir)/stamp-vti $(srcdir)/version-2.texi $(srcdir)/stamp-1 \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = AM_V_DVIPS = $(am__v_DVIPS_@AM_V@) am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) am__v_DVIPS_0 = @echo " DVIPS " $@; am__v_DVIPS_1 = AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@) am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@) am__v_MAKEINFO_0 = @echo " MAKEINFO" $@; am__v_MAKEINFO_1 = AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@) am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@) am__v_INFOHTML_0 = @echo " INFOHTML" $@; am__v_INFOHTML_1 = AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@) am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@) am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@; am__v_TEXI2DVI_1 = AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@) am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@) am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@; am__v_TEXI2PDF_1 = AM_V_texinfo = $(am__v_texinfo_@AM_V@) am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@) am__v_texinfo_0 = -q am__v_texinfo_1 = AM_V_texidevnull = $(am__v_texidevnull_@AM_V@) am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@) am__v_texidevnull_0 = > /dev/null am__v_texidevnull_1 = INFO_DEPS = ssip.info speech-dispatcher.info spd-say.info \ speech-dispatcher-cs.info am__TEXINFO_TEX_DIR = $(srcdir) DVIS = ssip.dvi speech-dispatcher.dvi spd-say.dvi \ speech-dispatcher-cs.dvi PDFS = ssip.pdf speech-dispatcher.pdf spd-say.pdf \ speech-dispatcher-cs.pdf PSS = ssip.ps speech-dispatcher.ps spd-say.ps speech-dispatcher-cs.ps HTMLS = ssip.html speech-dispatcher.html spd-say.html \ speech-dispatcher-cs.html TEXINFOS = ssip.texi speech-dispatcher.texi spd-say.texi \ speech-dispatcher-cs.texi TEXI2DVI = texi2dvi TEXI2PDF = $(TEXI2DVI) --pdf --batch MAKEINFOHTML = $(MAKEINFO) --html AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) DVIPS = dvips am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__installdirs = "$(DESTDIR)$(infodir)" am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(speech_dispatcher_TEXINFOS) \ $(speech_dispatcher_cs_TEXINFOS) $(srcdir)/Makefile.in \ $(ssip_TEXINFOS) README mdate-sh texinfo.tex DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ info_TEXINFOS = ssip.texi speech-dispatcher.texi spd-say.texi speech-dispatcher-cs.texi EXTRA_DIST = figures speech_dispatcher_TEXINFOS = gpl.texi fdl.texi speech-dispatcher.texi speech_dispatcher_cs_TEXINFOS = gpl.texi fdl.texi speech-dispatcher-cs.texi ssip_TEXINFOS = gpl.texi fdl.texi CLEANFILES = spd-say.info \ speech-dispatcher-cs.info \ speech-dispatcher.info \ ssip.info \ stamp-1 \ stamp-vti \ version-2.texi \ version.texi all: all-am .SUFFIXES: .SUFFIXES: .dvi .ps $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ssip.info: ssip.texi $(ssip_TEXINFOS) $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ `test -f 'ssip.texi' || echo '$(srcdir)/'`ssip.texi; \ then \ rc=0; \ else \ rc=$$?; \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc ssip.dvi: ssip.texi $(ssip_TEXINFOS) $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ `test -f 'ssip.texi' || echo '$(srcdir)/'`ssip.texi ssip.pdf: ssip.texi $(ssip_TEXINFOS) $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ `test -f 'ssip.texi' || echo '$(srcdir)/'`ssip.texi ssip.html: ssip.texi $(ssip_TEXINFOS) $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) `test -f 'ssip.texi' || echo '$(srcdir)/'`ssip.texi; \ then \ rm -rf $@ && mv $(@:.html=.htp) $@; \ else \ rm -rf $(@:.html=.htp); exit 1; \ fi speech-dispatcher.info: speech-dispatcher.texi $(srcdir)/version.texi $(speech_dispatcher_TEXINFOS) $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ `test -f 'speech-dispatcher.texi' || echo '$(srcdir)/'`speech-dispatcher.texi; \ then \ rc=0; \ else \ rc=$$?; \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc speech-dispatcher.dvi: speech-dispatcher.texi $(srcdir)/version.texi $(speech_dispatcher_TEXINFOS) $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ `test -f 'speech-dispatcher.texi' || echo '$(srcdir)/'`speech-dispatcher.texi speech-dispatcher.pdf: speech-dispatcher.texi $(srcdir)/version.texi $(speech_dispatcher_TEXINFOS) $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ `test -f 'speech-dispatcher.texi' || echo '$(srcdir)/'`speech-dispatcher.texi speech-dispatcher.html: speech-dispatcher.texi $(srcdir)/version.texi $(speech_dispatcher_TEXINFOS) $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) `test -f 'speech-dispatcher.texi' || echo '$(srcdir)/'`speech-dispatcher.texi; \ then \ rm -rf $@ && mv $(@:.html=.htp) $@; \ else \ rm -rf $(@:.html=.htp); exit 1; \ fi $(srcdir)/version.texi: $(srcdir)/stamp-vti $(srcdir)/stamp-vti: speech-dispatcher.texi $(top_srcdir)/configure @(dir=.; test -f ./speech-dispatcher.texi || dir=$(srcdir); \ set `$(SHELL) $(srcdir)/mdate-sh $$dir/speech-dispatcher.texi`; \ echo "@set UPDATED $$1 $$2 $$3"; \ echo "@set UPDATED-MONTH $$2 $$3"; \ echo "@set EDITION $(VERSION)"; \ echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \ (cmp -s vti.tmp$$$$ $(srcdir)/version.texi \ || (echo "Updating $(srcdir)/version.texi" && \ cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \ mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \ rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$ @cp $(srcdir)/version.texi $@ mostlyclean-vti: -rm -f vti.tmp* $(srcdir)/version.texi.tmp* maintainer-clean-vti: -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi spd-say.info: spd-say.texi $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ `test -f 'spd-say.texi' || echo '$(srcdir)/'`spd-say.texi; \ then \ rc=0; \ else \ rc=$$?; \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc spd-say.dvi: spd-say.texi $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ `test -f 'spd-say.texi' || echo '$(srcdir)/'`spd-say.texi spd-say.pdf: spd-say.texi $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ `test -f 'spd-say.texi' || echo '$(srcdir)/'`spd-say.texi spd-say.html: spd-say.texi $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) `test -f 'spd-say.texi' || echo '$(srcdir)/'`spd-say.texi; \ then \ rm -rf $@ && mv $(@:.html=.htp) $@; \ else \ rm -rf $(@:.html=.htp); exit 1; \ fi speech-dispatcher-cs.info: speech-dispatcher-cs.texi $(srcdir)/version-2.texi $(speech_dispatcher_cs_TEXINFOS) $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ `test -f 'speech-dispatcher-cs.texi' || echo '$(srcdir)/'`speech-dispatcher-cs.texi; \ then \ rc=0; \ else \ rc=$$?; \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc speech-dispatcher-cs.dvi: speech-dispatcher-cs.texi $(srcdir)/version-2.texi $(speech_dispatcher_cs_TEXINFOS) $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ `test -f 'speech-dispatcher-cs.texi' || echo '$(srcdir)/'`speech-dispatcher-cs.texi speech-dispatcher-cs.pdf: speech-dispatcher-cs.texi $(srcdir)/version-2.texi $(speech_dispatcher_cs_TEXINFOS) $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ `test -f 'speech-dispatcher-cs.texi' || echo '$(srcdir)/'`speech-dispatcher-cs.texi speech-dispatcher-cs.html: speech-dispatcher-cs.texi $(srcdir)/version-2.texi $(speech_dispatcher_cs_TEXINFOS) $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) `test -f 'speech-dispatcher-cs.texi' || echo '$(srcdir)/'`speech-dispatcher-cs.texi; \ then \ rm -rf $@ && mv $(@:.html=.htp) $@; \ else \ rm -rf $(@:.html=.htp); exit 1; \ fi $(srcdir)/version-2.texi: $(srcdir)/stamp-1 $(srcdir)/stamp-1: speech-dispatcher-cs.texi $(top_srcdir)/configure @(dir=.; test -f ./speech-dispatcher-cs.texi || dir=$(srcdir); \ set `$(SHELL) $(srcdir)/mdate-sh $$dir/speech-dispatcher-cs.texi`; \ echo "@set UPDATED $$1 $$2 $$3"; \ echo "@set UPDATED-MONTH $$2 $$3"; \ echo "@set EDITION $(VERSION)"; \ echo "@set VERSION $(VERSION)") > 1.tmp$$$$ && \ (cmp -s 1.tmp$$$$ $(srcdir)/version-2.texi \ || (echo "Updating $(srcdir)/version-2.texi" && \ cp 1.tmp$$$$ $(srcdir)/version-2.texi.tmp$$$$ && \ mv $(srcdir)/version-2.texi.tmp$$$$ $(srcdir)/version-2.texi)) && \ rm -f 1.tmp$$$$ $(srcdir)/version-2.texi.$$$$ @cp $(srcdir)/version-2.texi $@ mostlyclean-1: -rm -f 1.tmp* $(srcdir)/version-2.texi.tmp* maintainer-clean-1: -rm -f $(srcdir)/stamp-1 $(srcdir)/version-2.texi .dvi.ps: $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(DVIPS) $(AM_V_texinfo) -o $@ $< uninstall-dvi-am: @$(NORMAL_UNINSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ rm -f "$(DESTDIR)$(dvidir)/$$f"; \ done uninstall-html-am: @$(NORMAL_UNINSTALL) @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ done uninstall-info-am: @$(PRE_UNINSTALL) @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ done; \ else :; fi @$(NORMAL_UNINSTALL) @list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ else :; fi); \ done uninstall-pdf-am: @$(NORMAL_UNINSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ done uninstall-ps-am: @$(NORMAL_UNINSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ rm -f "$(DESTDIR)$(psdir)/$$f"; \ done dist-info: $(INFO_DEPS) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; \ for base in $$list; do \ case $$base in \ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$base; then d=.; else d=$(srcdir); fi; \ base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ if test -f $$file; then \ relfile=`expr "$$file" : "$$d/\(.*\)"`; \ test -f "$(distdir)/$$relfile" || \ cp -p $$file "$(distdir)/$$relfile"; \ else :; fi; \ done; \ done mostlyclean-aminfo: -rm -rf ssip.t2d ssip.t2p speech-dispatcher.t2d speech-dispatcher.t2p \ spd-say.t2d spd-say.t2p speech-dispatcher-cs.t2d \ speech-dispatcher-cs.t2p clean-aminfo: -test -z "ssip.dvi ssip.pdf ssip.ps ssip.html speech-dispatcher.dvi \ speech-dispatcher.pdf speech-dispatcher.ps \ speech-dispatcher.html spd-say.dvi spd-say.pdf spd-say.ps \ spd-say.html speech-dispatcher-cs.dvi \ speech-dispatcher-cs.pdf speech-dispatcher-cs.ps \ speech-dispatcher-cs.html" \ || rm -rf ssip.dvi ssip.pdf ssip.ps ssip.html speech-dispatcher.dvi \ speech-dispatcher.pdf speech-dispatcher.ps \ speech-dispatcher.html spd-say.dvi spd-say.pdf spd-say.ps \ spd-say.html speech-dispatcher-cs.dvi \ speech-dispatcher-cs.pdf speech-dispatcher-cs.ps \ speech-dispatcher-cs.html maintainer-clean-aminfo: @list='$(INFO_DEPS)'; for i in $$list; do \ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ done tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-info check-am: all-am check: check-am all-am: Makefile $(INFO_DEPS) installdirs: for dir in "$(DESTDIR)$(infodir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-aminfo clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: $(DVIS) html: html-am html-am: $(HTMLS) info: info-am info-am: $(INFO_DEPS) install-data-am: install-info-am install-dvi: install-dvi-am install-dvi-am: $(DVIS) @$(NORMAL_INSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \ $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ done install-exec-am: install-html: install-html-am install-html-am: $(HTMLS) @$(NORMAL_INSTALL) @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ $(am__strip_dir) \ d2=$$d$$p; \ if test -d "$$d2"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ else \ list2="$$list2 $$d2"; \ fi; \ done; \ test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done; } install-info: install-info-am install-info-am: $(INFO_DEPS) @$(NORMAL_INSTALL) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \ $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \ fi; \ for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$file; then d=.; else d=$(srcdir); fi; \ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ if test -f $$ifile; then \ echo "$$ifile"; \ else : ; fi; \ done; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done @$(POST_INSTALL) @if $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ done; \ else : ; fi install-man: install-pdf: install-pdf-am install-pdf-am: $(PDFS) @$(NORMAL_INSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done install-ps: install-ps-am install-ps-am: $(PSS) @$(NORMAL_INSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-1 \ maintainer-clean-aminfo maintainer-clean-generic \ maintainer-clean-vti mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-1 mostlyclean-aminfo mostlyclean-generic \ mostlyclean-libtool mostlyclean-vti pdf: pdf-am pdf-am: $(PDFS) ps: ps-am ps-am: $(PSS) uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ uninstall-pdf-am uninstall-ps-am .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-aminfo clean-generic \ clean-libtool cscopelist-am ctags-am dist-info distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-1 maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean \ mostlyclean-1 mostlyclean-aminfo mostlyclean-generic \ mostlyclean-libtool mostlyclean-vti pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-dvi-am \ uninstall-html-am uninstall-info-am uninstall-pdf-am \ uninstall-ps-am .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/doc/speech-dispatcher-cs.texi0000644000175000017500000010276111447133617017511 00000000000000\input texinfo @c -*-texinfo-*- @c %**start of header @documentencoding ISO-8859-2 @documentlanguage cs @setfilename speech-dispatcher-cs.info @settitle Speech Dispatcher @finalout @c @setchapternewpage odd @c %**end of header @syncodeindex pg cp @syncodeindex fn cp @syncodeindex vr cp @include version-2.texi @dircategory Sound @dircategory Development @direntry * Speech Dispatcher cs: (speechd-cs). Speech Dispatcher (in Czech). @end direntry @titlepage @title Speech Dispatcher @subtitle Zvládnutí Babylonu TTS' @subtitle pro Speech Dispatcher @value{VERSION} @author Tom@'a@v{s} Cerha <@email{cerha@@brailcom.org}> @author Hynek Hanke <@email{hanke@@volny.cz}> @author Milan Zamazal <@email{pdm@@brailcom.org}> @page @vskip 0pt plus 1filll Tento manuál se vzathuje ke Speech Dispatcher, verze @value{VERSION}. Jedná se však pouze o uživatelskou část dokumentace a upozorňujeme, že tento překlad již není aktuální! Poskytujeme jej s tím, že možná bude užitečný a to zejména v sekcích, které popisují obecné koncepty a myšlenky projektu, a to těm, kteří si nemohou přečíst anglickou dokumentaci. Nikdo by nicméně neměl spoléhat na technické detaily zde uvedené, protože mnoho věcí je již dnes jinak. Copyright @copyright{} 2001, 2002, 2003, 2006 Brailcom, o.p.s. @quotation Dáváme povolení kopírovat, distribuovat a/nebo modifikovate tento dokument pod podmínkami GNU Free Documentation License, Verze 1.2 nebo jakékoliv novější verze vydané Free Software Foundation, bez jakýchkoliv Invariant Sections (neměnných sekcí), bez Front-Cover Texts (texty na přední straně obálky) a bez Back-Cover Texts (texty na zadní straně obálky). Kopie této licence je přiložena v sekci nazvané ,,GNU Free Documentation License''. @end quotation @end titlepage @ifnottex @node Top, Úvod, (dir), (dir) Tento manuál se vzathuje ke Speech Dispatcher, verze @value{VERSION}. Jedná se však pouze o uživatelskou část dokumentace a upozorňujeme, že tento překlad již není aktuální! Poskytujeme jej s tím, že možná bude užitečný a to zejména v sekcích, které popisují obecné koncepty a myšlenky projektu, a to těm, kteří si nemohou přečíst anglickou dokumentaci. Nikdo by nicméně neměl spoléhat na technické detaily zde uvedené, protože mnoho věcí je již dnes jinak. Copyright @copyright{} 2001, 2002, 2003 Brailcom, o.p.s. @quotation Dáváme povolení kopírovat, distribuovat a/nebo modifikovate tento dokument pod podmínkami GNU Free Documentation License, Verze 1.2 nebo jakékoliv novější verze vydané Free Software Foundation; bez jakýchkoliv Invariant Sections (neměnných sekcí), bez Front-Cover Texts (texty na přední straně obálky) a bez Back-Cover Texts (texty na zadní straně obálky). Kopie této licence je přiložena v sekci nazvané ,,GNU Free Documentation License''. @end quotation @end ifnottex @ifhtml @heading Menu @end ifhtml @menu * Úvod:: Co to je Speech Dispatcher * Uživatelská dokumentace:: Používání, konfigurace * GNU General Public License:: Podmínky kopírování Speech Dispatcher * GNU Free Documentation License:: Podmínky kopírování tohoto manuálu * Index of Concepts:: @end menu @node Úvod, Uživatelská dokumentace, Top, Top @chapter Úvod @menu * Motivace:: Proč Speech Dispatcher? * Základní design:: Jak to pracuje? * Přehled základních rysů:: Co všechno umí? * Současný stav:: Jaký je současný stav? @end menu @node Motivace, Základní design, Úvod, Úvod @section Motivace @cindex Hlavní myšlenky, Motivace @cindex Filosofie Projekt Speech Dispatcher se snaží poskytnout na zařízení nezávislou vrstvu pro řečovou syntézu. Měl by poskytovat jednoduché rozhraní pro klientské aplikace (aplikace, které chtějí mluvit), stejně jako pro ovladače konkrétních zařízení (různé řečové syntetizéry). Vysoce kvalitní řečová syntéza je tu již dlouho a nyní je použitelná i pro běžné uživatele na jejich domácích počítačích. Občas to přichází jako nutnost, občas je to jen dobrá vlastnost, aby některé programy poskytovaly řečový výstup. Pro syntézu hlasu je tu široké pole využití od výukového software až po specializované systémy, jako jsou například nemocnice či laboratoře. Pro zrakově postižené uživatele je to jedna ze dvou základních cest, jak získat výstup z počítače (tou druhou je Braillský řádek). Existují různé řečové syntetizéry s různými schopnostmi. Některé z nich jsou hardwarové, některé softwarové. Některé jsou svobodným software a jsou volně dostupné na internetu. Programátoři to mají opravdu těžké, když chtějí své programy rozmluvit, protože potřebují nejprve najít nějaký vhodný syntetizér (dlouhé hodiny experimentování a tak dále) a potom jej potřebují nějak zprovoznit s jejich programem. Často musí psát pro tyto programy či hardwarová zařízení vlastní ovladače a dělají to znovu a znovu. Snadno si lze představit, že se to celé zhroutí když nevinný uživatel spustí dva programy najednou. Kdyby přesto nastartovaly oba, budou křičet jeden přes druhého. Tím je pro programátory velmi obtížné implementovat do svých programů podporu řečové syntézy (pro nevidomé uživatele, nebo prostě pro lepší uživatelské rozhraní) a je to jeden z důvodů, proč pořád ještě plně nevyužíváme toho, co řečová syntéza nabízí. V ideálním světě by programátoři mohli pro řečovou syntézu používat podobné příkazy, jako to dělají pro textový výstup na obrazovku (printf, puts, ...). V ideálním světě by existovalo nějaké speech_printf(), které by se staralo o to, aby byla zpráva přemluvena ve správný čas bez přerušování ostatních. Programátor by se tak nemusel starat o to, jak je přesně komunikace s řečovým syntetizérem implementována. V ideálním světě by byl v každé GNU/Linuxové distribuci nějaký řečový syntetizér a nějaké rozhraní starající se o aplikace, které chtějí mluvit, dovolující uživatelům nastavit si parametry řeči a poskytující nějaké jednoduché rozhraní (jako speech_printf()) pomocí nějaké sdílené knihovny pro programátory. Bude to jěště dlouhá cesta než se nám podaří dosáhnout tohoto stavu věcí, ale se Speech Dispatcherem děláme první krůčky... @node Základní design, Přehled základních rysů, Motivace, Úvod @section Základní design @cindex Design V komunikaci mezi všemi různými aplikacemi a syntetizéry je obrovský nepořádek. Proto jsme chtěli, aby byl Speech Dispatcher vrstva oddělující aplikace a syntetizéry tak, aby se aplikace nemusely starat o syntetizéry a syntetizéry se nemusely starat o interakci s aplikacemi. Rozhodli jsme se implementovat Speech Dispatcher jako server, který přijímá od aplikací příkazy přes protokol nazvaný @code{SSIP}, zpracovává je a, pokud je to nutné, zavolá příslušnou funkci daného výstupního modulu, který pak komunikuje s některým z různých syntetizátorů. Každý klient (aplikace, která chce mluvit) otevře socketové spojení na Speech Dispatcher a volá funkce jako say(), stop(), pause() poskytované knihovnou implementující tento protokol. Tato sdílená knihovna je stále na straně klienta a posílá Speech Dispatcheru SSIP příkazy přes otevřený socket. Když příkazy dorazí do Dispatchera, ten je zpracuje, přečte text, který by měl být přeříkán a vloží jej do fronty podle jeho priority. Potom se rozhodne kdy, s jakými parametry (nastavovanými klientským programem i uživatelem) a na jakém syntetizéru zprávu nechá přemluvit. Tyto požadavky na mluvení jsou pak zpracovávány výstupními moduly (pluginy) pro různé hardwarové a softwarové syntetizéry a přeříkány nahlas. @image{figures/architecture,155mm,,Architektura Speech Dispatchera} Detailní popis programování klientů i serveru je k dispozici v anglickém manuálu. @node Přehled základních rysů, Současný stav, Základní design, Úvod @section Přehled základních rysů Speech Dispatcher z pohledu uživatele: @itemize @bullet @item snadná konfigurace různých mluvících aplikací, centrální správa @item možnost volně rozhodovat, jaká aplikace bude mluvit s jakým syntetizérem @item méně času věnovaného konfiguraci a ladění různých aplikací využívajících syntézu @item historie zpráv pro zrakově postižené uživatele @end itemize Speech Dispatcher z pohledu programátora aplikace: @itemize @bullet @item snadná cesta, jak aplikaci rozmluvit @item jednotné rozhraní k různým syntetizérům @item synchronizace zpráv na vyšší úrovni (kategorizace pomocí priorit) @item možnost nemuset se starat o konfiguraci parametrů hlasu @end itemize @node Současný stav, , Přehled základních rysů, Úvod @section Současný stav @cindex Syntetizéry @cindex Ostatní programy TODO: @node Uživatelská dokumentace, GNU General Public License, Úvod, Top @chapter Uživatelská dokumentace @menu * Základní funkce:: Detailnější popis všech základních funkcí * Spouštění:: Volby příkazové řádky * Konfigurace:: Jak zkonfigurovat Speech Dispatcher @end menu @node Základní funkce, Spouštění, Uživatelská dokumentace, Uživatelská dokumentace @section Základní funkce V této sekci je detailnější popis základních funkcí Speech Dispatcheru. @menu * Model priorit zpráv:: Zpracování současně příchozích zpráv * Historie zpráv:: Ukládání zpráv pro pozdější nahlédnutí * Více výstupních modulů:: Interakce s různými syntetizéry * Autentifikace uživatelů:: Autentifikace pro přístup k historii @end menu @node Model priorit zpráv, Historie zpráv, Základní funkce, Základní funkce @subsection Model priorit zpráv @cindex priority Speech Dispatcher nemůže syntetizovat všechny zprávy, které do něj přichází z prostého důvodu, že zprávy přicházejí obyčejně rychleji, než je syntetický hlas dokáže číst. Na obrazovce monitoru je v porovnání s jednokanálovým řečovým výstupem relativně hodně místa. Z toho důvodu používáme systém několika priorit zaměřených na různé typy zpráv. Myšlenka je taková, že úlohou programátora klientské aplikace bude pouze určit pro každou zprávu určitou prioritu odpovídající typu dané zprávy. Veškerá synchronizace a přepínání mezi těmito zprávami (které mohou pocházet od různých klientů) potom bude zajištěno aplikováním určitých pravidel ve Speech Dispatcheru. @menu * Typy priorit:: * Diagram priorit:: * Příklady využití priorit:: @end menu @node Typy priorit, Diagram priorit, Model priorit zpráv, Model priorit zpráv @subsubsection Priority Categories Speech Dispatcher poskytuje systém pěti priorit. Každá zpráva obsahuje buď explicitní informaci o prioritě, nebo jí je přiřazena výchozí priorita. Prosím podívejte se také na přiložený diagram (dole). @subsubheading Priorita @code{important} @cindex Priorita important Tato zpráva bude přeříkána okamžitě, jak dorazí do serveru. Není nikdy přerušena. Když server obdrží současně několik různých zpráv této priority, ty jsou uloženy a přeříkány v pořadí, ve kterém přišly. Když přijde nová zpráva priority @code{important} a zrovna se říká nějaká jiná zpráva, tato jiná zpráva je zahozena. Další zprávy nižších priorit jsou buď pozdrženy (priorita @code{message} a @code{text}) než již nečekají na přeříkání žádné zprávy priority @code{important}, nebo jsou zahozeny (priority @code{notification} a @code{progress}). Tyto zprávy by měly být tak krátké, jak je to jen možné, a měly by být používány pouze zřídka, protože blokují výstup všech ostatních zpráv. @subsubheading Priorita @code{message} @cindex Priorita message Tato zpráva bude přeříkána, pokud již ve frontě nečeká žádná jiná zpráva priority @code{important} nebo @code{message}. V opačném případě je tato zpráva pozdržena dokud nebudou všechny přeříkány. To znamená, že priorita @code{message} nezastavuje sama sebe. Když ve frontě čekají zprávy priorit @code{notification} nebo @code{progress} nebo @code{text} když přijde zpráva priority @code{message}, jsou zahozeny. @subsubheading Priorita @code{text} @cindex Priorita text Tato zpráva bude přeříkána, když ve frontě nečeká žádná zpráva priority @code{important} nebo @code{message}. Pokud čeká, tato nová zpráva je pozdržena dokud nebudou předchozí zprávy přeříkány. Priorita text přerqušuje sama sebe. To znamená, že když přijde několik zpráv priority text, ty nejsou přeříkány v pořadí, ve kterém přišly, ale bude vyřčena pouze poslední z nich a ostatní jsou přerušeny a zahozeny. Pokud jsou ve frontě zprávy priorit @code{notification} nebo @code{progress} nebo se právě přeříkávají, jsou zahozeny. @subsubheading Priorita @code{notification} @cindex Priorita notification Toto je zpráva nízké priority. Pokud ve frontě čekají zprávy priorit @code{important}, @code{messages}, @code{text} nebo @code{progress} nebo jsou právě přeříkávány, tato nová zpráva priority @code{notification} je zrušena. Tato priorita přerušuje sama sebe, takže když přijde najednou více zpráv s prioritou @code{notification}, přeříká se pouze poslední z nich. @subsubheading Priority @code{progress} Toto je speciální priorita pro zprávy, které přicházejí krátce po sobě a nesou informaci o nějaké probíhající činnosti (např.@ @code{Dokončeno 45%}). Kdyby nové zprávy přerušovaly ostatní (viz. priorita Notification), uživatel by nemusel slyšet ani jednu zprávu do konce. Tato priorita se chová stejně jako @code{notification} s výjimkou dvou věcí. @itemize @item Zprávy této priority nepřerušují jedna druhou. Místo toho, pokud je zrovna přeříkávána jiná zpráva této priority, nově příchozí zpráva je zahozena. @item Speech Dispatcher se snaží detekovat poslední zprávu v sérii příchozích zpráv a zaručit její přeříkání (pro uživatele je důležité slyšet zprávu @code{Completed 100%}, aby věděl, že proces již skončil). Vždy, když ve frontě již nečeká žádná nová zpráva této priority a poslední příchozí zpráva ještě nebyla přeříkána, je její přeříkání vynuceno s prioritou @code{message}. @end itemize @node Diagram priorit, Příklady využití priorit, Typy priorit, Model priorit zpráv @subsubsection Diagram priorit @image{figures/priorities,,,Speech Dispatcher architecture} @c TODO: Generate a pdf version. (Why? -- Hynek Hanke) @node Příklady využití priorit, , Diagram priorit, Model priorit zpráv @subsubsection Příklady využití priorit Příklady použití priority @code{important} jsou: @itemize @item chybové hlášky @item velmi důležité zprávy @item ... @end itemize Příklady použití priority @code{message} jsou: @itemize @item běžné zprávy programu @item varování @item ... @end itemize Příklady použití priority @code{text} jsou: @itemize @item text, na kterém uživatel pracuje @item předčítaný text @item položky menu @item ... @end itemize Příklady použití priority @code{notification} jsou: @itemize @item méně důležité informace @item písmenka při vkládání @item run-time nápověda @item ... @end itemize Příklady použití priority @code{progress} jsou: @itemize @item ``dokončeno 15%'', ``dokončeno 16%'', ``dokončeno 17%'' @item ``Načítám zvuky'', ``Načítám grafiku'', ``Načítám ai'', ... @end itemize @node Historie zpráv, Více výstupních modulů, Model priorit zpráv, Základní funkce @subsection Historie zpráv @cindex history Pro nevidomé a zrakově postižené je dobrou vlastností, pokud mají možnost nějakým jednoduchým klientem procházet historii vyslovených zpráv. Některé méně důležité zprávy jsou přijmuty Speech Dispatcherem bez toho, aby byly přeříkány, protože jsou potlačeny důležitějšími informacemi. To je nedělitelná vlastnost každého řečového rozhraní, protože není možné podat v řečovém výstupu tolik informací, kolik se jich vejde na obrazovku. To je jeden z hlavních důvodů, proč je výhodné udržovat historii přijatých zpráv, aby se mohl uživatel podívat, zda mu neušlo něco důležitého. @menu * Přístupová práva:: Přístupová práva k historii zpráv @end menu @node Přístupová práva, , Historie zpráv, Historie zpráv @subsubsection Access Rights @cindex access rights Aby bylo ochráněno soukromí uživatelů, Speech Dispatcher omezuje přístup k historii na určitou podmnožinu přijatých zpráv. Platí následující pravidla: @itemize @bullet @item Všechny zprávy přijaté od určitého klientského spojení jsou tomuto spojení přístupny i v historii. @item Všechny zprávy odeslané určitým uživatelem jsou tomuto uživateli přístupny i v historii. @item @cindex @code{speechd} uživatel @cindex @code{speechd} skupina Všechny zprávy zaslané uživatelem @code{speechd} jsou přístupny všem uživatelům na daném systému, pod kterým běží Speech Dispatcher ve skupině @code{speechd}. @item Žádné další zprávy nejsou přístupné. @end itemize Dvě zprávy jsou považovány za identické jestliže jejich spojení pocházejí z toho samého počítače, uživatelská jména jsou stejná a jejich identita může být ověřena, jak je popsáno v @ref{Autentifikace uživatelů}. Pokud nemůže být uživatelova identita ověřena, tento uživatel je považován za jiného než všichni připojení nebo dříve připojení uživatelé. @node Více výstupních modulů, Autentifikace uživatelů, Historie zpráv, Základní funkce @subsection Více výstupních modulů @cindex výstupní modul @cindex syntetizátory Speech Dispatcher podporuje souběžné používání více výstupních modulů. Pokud tyto moduly poskytují dobrou synchronizaci, lze je při čtení zpráv kombinovat. Pokud např. modul1 mluví anglicky a česky, zatímco modul2 mluví pouze německy, tak pokud přijde nějaká zpráva v němčině, použije se modul2, zatímco pro ostatní jazyky se použije modul1. Na druhé straně jazyk není jediným kritériem pro takové rozhodnutí. Přesná pravidla pro výběr výstupího modulu mohou být ovlivněna v konfiguračním souboru @file{speechd.conf}. @node Autentifikace uživatelů, , Více výstupních modulů, Základní funkce @subsection Autentifikace uživatelů @cindex Identification Protocol @cindex identd @cindex RFC 1413 NOTE: Na implementaci této vlastnosti se pracuje, ale současná verze ji nepodporuje. Speech Dispatcher neposkytuje žádný explicitní autentifikační mechanismus. K ověření identity uživatlů používáme Identification Protocol definovaný v RFC 1413. @cindex mapování uživatlů V konfiguraci je možné specifikovat mapování uživatelů. To umožňuje jednat s určitými uživateli jako s jedním a přidělit jim stejná práva (např. procházet jejich @ref{Historie zpráv}). @node Spouštění, Konfigurace, Základní funkce, Uživatelská dokumentace @section Invoking @subsection Potřebná privilegia Speech Dispatcher může být obecně spouštěn pod obyčejným uživatelem. Snažili jsme se jej zabezpečit, jak jen to bylo možné, ale nejsme odborníky na počítačovou bezpečnost a kód může obsahovat nebezpečné chyby. Nedoporučujeme jej spouštět jako root nebo pod jiným vysoce privilegovaným uživatelem. Jediná omezení jsou tyto: @itemize @item Speech Dispatcher vytváří PID file standardně ve @file{/var/run/speech-dispatcher.pid}, takže @file{/var/run/} musí být danému uživateli přístupné k zápisu. To může být změněno nastavením volby @code{pidpath} při volání skriptu @code{./configure} při kompilaci. @item Když je zapnuto logování, výchozí cesta, kam Speech Dispatcher zapisuje svůj log, je @file{/var/log/speech-dispatcher.log}. To ale může být kdykoliv přenastaveno v hlavním konfiguračním souboru. @end itemize @subsection Volby příkazové řádky Speech Dispatcher může být spuštěn s těmito volbami: @code{speech-dispatcher [-@{d|s@}] [-l @{1|2|3|4|5@}] [-p=port] | [-v] | [-h]} @table @code @item -d or --run-daemon Spustí program jako démona (běží v pozadí, odpojí se od terminálu, atd.) Toto je výchozí chování. @item -s or --run-single Spustí program jako běžnou aplikaci běžící na popředí. @item -l level or --log-level=level Vybere požadovaný logovací úroveň. Logovací úroveň je číslo mezi 0 a 5 (0 znamená neloguj nic, 5 znamená zapisuj téměř vše včetně zpracovávaného textu.) Standardní je 3. @xref{Úrovně logování}. Logovací úroveň 5 by neměla být používána k jiným účelům, než pro hledání chyb a to pouze krátkodobě. Logy, které produkuje mohou narůst do obrovské velikosti a obsahují text čtený uživateli nezávisle na různých přístupových právech, jak platí pro historii. Spouštět server s touto úrovní logování tedy může snadno vést k narušení soukromí. @item -p or --port Zadá port, na kterém by měl server čekat na klienty. Výchozí je 6560. @item -v or --version Vypíše informace o verzi Speech Dispatchera. Také oznámí základní informace o copyrightu. @item -h or --help Vypíše nápovědu o volbách příkazové řádky, upozornění o copyrightu a emailovou adresu pro zasílání oznámení o chybách. @end table @node Konfigurace, , Spouštění, Uživatelská dokumentace @section konfigurace @cindex konfigurace Speech Dispatcher může být konfigurován na několika různých úrovních. Jedna z nich je nastavování globálních parametrů přes serverový konfigurační soubor. Je zde i podpora pro konfiguraci specifickou pro určité klienty. Některé aplikace mají vlastní mechanismus nastavování voleb souvisejících s řečovou syntézou. Pro detaily o těchto nastaveních se prosím podívejte do dokumentace daného programu. Následující kapitoly se zabývají pouze konfigurací na straně serveru přes konfigurační soubor. @menu * Syntaxe konfiguračního souboru:: * Volby v konfiguraci:: * Nastavení výstupních modulů:: * Úrovně logování:: @end menu @node Syntaxe konfiguračního souboru, Volby v konfiguraci, Konfigurace, Konfigurace @subsection Syntaxe konfiguračního souboru Pro načítání configurace založené na textových souborech používáme knihovnu DotConf, takže bude syntaxe nejspíš mnoha uživatelům povědomá. Každá z řetězcových konstant, pokud není uvedeno jinak, by měla být zakódována v UTF-8. Jména voleb nepoužívají jiné znaky než standardní ASCII sadu omezenou na znaky (@code{a}, @code{b}, ...), pomlčky (@code{-}) a podtržítka @code{_}. Komentáře a dočasně neaktivní volby začínají znakem @code{#}. Pokud chcete takovu volbu zapnout, stačí smazat znak komentáře a nastavit volbu na požadovanou hodnotu. @example # toto je komentar # InactiveOption "tato volba je zatim vypla komentarem" @end example Řetězce jsou uzavřeny v uvozovkách. @example LogFile "/var/log/speech-dispatcher.log" @end example Čísla jsou zapsána bez uvozovek. @example Port 6560 @end example Přepínače používají On (zapnuto) a Off (vypnuto). @example Debug Off @end example @node Volby v konfiguraci, Nastavení výstupních modulů, Syntaxe konfiguračního souboru, Konfigurace @subsection Configuration options Všechny dostupné volby jsou zdokumentovány přímo v konfiguračním souboru a jsou k nim uvedeny i příklady. Většina voleb je nastavena na výchozí hodnotu a zakomentována. Pokud je chcete změnit, postačí modifikovat jejich hodnotu a smazat symbol komentáře @code{#}. @node Nastavení výstupních modulů, Úrovně logování, Volby v konfiguraci, Konfigurace @subsection Output Modules Configuration Každý uživatel by si měl zapnout ve své konfiguraci alespoň jeden výstupní modul, pokud chce, aby Speech Dispatcher produkoval nějaký zvukový výstup. Když není načten žádný výstupní modul, Speech Dispatcher sice nastartuje, bude komunikovat s klienty a logovat zprávy do historie, ale nebude produkovat žádný zvuk. Každý výstupní modul je třeba do Speech Dispatchera natáhnout jednou řádkou ``AddModule'' v @file{etc/speechd.conf}. Navíc, každý výstupní modul má přiřazen vlastní konfigurační soubor. @menu * Natahování modulů ve speechd.conf:: * Konfigurační soubory výstupních modulů:: * Konfigurace generického výstupního modulu:: @end menu @node Natahování modulů ve speechd.conf, Konfigurační soubory výstupních modulů, Nastavení výstupních modulů, Nastavení výstupních modulů @subsubsection Natahování modulů ve speechd.conf @anchor{AddModule} Každý modul, který by se měl spustit při startu Speech Dispatchera, musí být natažen příkazem @code{AddModule} v konfiguraci. Všimněte si, že lze natáhnout jeden binární modul vícekrát s různými konfiguračními soubory a pod jinými jmény. To je užitečné hlavně pro natahování generických výstupních modulů. @xref{Konfigurace generického výstupního modulu}. @example AddModule "@var{module_name}" "@var{module_binary}" "@var{module_config}" @end example @var{module_name} je jméno daného výstupního modulu. @var{module_binary} je jméno binárního spustitelného souboru tohoto výstupního modulu. To může být buď cesta absolutní nebo relativní k @file{bin/speechd-modules/}. @var{module_config} je soubor s konfigurací pro tento konkrétní výstupní modul. Cesta může být absolutní i relativní k @file{etc/speech-dispatcher/modules/}. Tento parametr je volitelný (není třeba jej uvádět). @node Konfigurační soubory výstupních modulů, Konfigurace generického výstupního modulu, Natahování modulů ve speechd.conf, Nastavení výstupních modulů @subsubsection Konfigurační soubory výstupních modulů Každý výstupní modul je odlišný a proto má odlišné volby v konfiguraci. Prosím prostudujte si komentáře v daném konfiguračním souboru. Zde je popsáno pouze několik voleb, které jsou pro některé výstupní moduly společné. @table @code @item AddVoice "@var{language}" "@var{symbolicname}" "@var{name}" @anchor{AddVoice} Každý výstupní modul poskytuje nějaké hlasy a někdy dokonce podporuje různé jazyky. Z toho důvodu byl zaveden společný mechanismus, kterým můžou být tyto hlasy definovány v konfiguraci. Žádný modul ovšem není povinen tuto volbu používat. Některé syntetizátory, např. Festival, podporují symbolická jména SSIP přímo, takže konfigurace konkrétních hlasů se provádí v syntetizátoru samotném. Každému definovanému hlasu odpovídá přesně jedna řádka @code{AddVoice}. @var{language} je ISO kód jazyka tohoto hlasu (en, cs, de, ...) @var{symbolicname} je symbolické jméno, pod kterým chcete, aby byl tento hlas dostupný. @xref{Standardní hlasy}, pro seznam symbolických jmen, která můžete použít. @var{name} je jméno specifické pro daný výstupní modul. Prosím podívejte se na komentáře v příslušném konfiguračním souboru v sekci AddModule pro detailnější informace. Např. definice, kterou v součastnosti používáme pro Epos (generic) vypadá takto: @example AddVoice "cs" "male1" "kadlec" AddVoice "sk" "male1" "bob" @end example @item ModuleDelimiters "@var{delimiters}", ModuleMaxChunkLength @var{length} Často se výstupní modul nesnaží vysyntetizovat celý příchozí text najednou, ale místo toho jej nejprve rozřeže na menší kousky (věty, části vět) a ty potom postupně odesílá na syntézu. Tento přístup, využívaný některými výstupními moduly, je mnohem rychlejší, ale na druhé straně zase limituje schopnost syntetizéru poskytnout dobrou intonaci. Z toho důvodu máte obyčejně možnost zkonfigurovat si na jakých znacích (@var{delimiters}) by se měl text rozdělit na menší části (pokud jsou následovány nějakým whitespace znakem). Druhá volba (@var{length}) udává, po kolika znacích by se měl text násilně rozdělit, pokud nebyl nalezen žádný delimiter. Pokud tato dvě pravidla zpřísníte, dostanete lepší rychlost, ale vzdáte se určité části kvality intonace. Takže například pro pomalejší počítače doporučujeme do @var{delimiters} vložit i čárku (,), aby byl text rozdělen i na částech věty, zatímco na rychlejších počítačích je lepší tam čárku nedávat, takže do syntetizéru vždy dorazí celá souvětí. To samé platí o @code{MaxChunkLength}. Pro rychlejší počítače je lepší nastavit větší hodnotu. Například výchozí hodnoty ve výstupním modulu pro Festival jsou: @example FestivalMaxChunkLength 300 FestivalDelimiters ".?!;,:" @end example Výstupní modul se může také rozhodnout dělit věty na delimiters pouze pokud ty jsou následovány mezerou. Takže například ``file123.tmp'' by rozděleno nebylo, ale věta ``The horse raced around the fence, that was lately painted green, fell.'' by rozdělena byla (to je mimochodem velmi zajímavá věta). @end table @node Konfigurace generického výstupního modulu, , Konfigurační soubory výstupních modulů, Nastavení výstupních modulů @subsubsection Konfigurace generického výstupního modulu Generický výstupní modul uživatelům dovoluje jednoduše si napsat vlastní jednoduchý výstupní modul pro syntetizéry, které mají rozhraní ve formě jednoduchého řádkového klienta, pouze modifikací konfiguračního souboru. Tímto způsobem nemusí psát žádný specifický kód v C a uživatelé si mohou přidávat podporu pro výstupní zařízení i když neumí programovat. @xref{AddModule}. Klíčová část každého generického výstupního modulu je definice řetězce, který se má spouštět. @defvr {Konfigurace generického modulu} GenericExecuteSynth "@var{execution_string}" @code{execution_string} je příkaz, který by měl být zavolán v shellu, když je potřeba něco říct. Ve skutečnosti to může být více jak jeden příkaz, dohromady zřetězené operátorem @code{&&}. Když bude výstupní modul chtít přeříkávání zprávy zastavit, zašle těmto procesům signál KILL, takže je důležité, aby použité příkazy po obdržení KILL okamžitě přestaly mluvit. (Na většině GNU/Linuxových systémů má tuto vlastnost utilita @code{play}) V @code{execution_string} můžete využít těchto proměnných, které budou nahrazeny pořadovanými hodnotami, než bude příkaz vykonán. @itemize @item @code{$DATA} Text, který by měl být přeříkán. Znaky řetězce, které by nějak interferovali se zpracováním v bashi budou automaticky nahrazeny odpovídajícími escape sekvencemi. Asi bude ale nutné uvést kolem této proměnné uvozovky (např. takto: @code{\"$DATA\"}). @item @code{$LANG} Identifikační řetězec jazyka (ten je definován pomocí GenericLanguage). @item @code{$VOICE} Identifikační řetězec hlasu (ten je definován pomocí AddVoice). @item @code{$PITCH} Požadovaná výška hlasu (desetinné číslo definované v GenericPitchAdd a v GenericPitchMultiply) @item @code{$RATE} Požadovaná rychlost hlasu (desetinné číslo definované v GenericRateAdd a v GenericRateMultiply) @end itemize Tady je příklad z @file{etc/speech-dispatcher/modules/epos-generic.conf} @example GenericExecuteSynth \ "epos-say -o --language $LANG --voice $VOICE --init_f $PITCH --init_t $RATE \ \"$DATA\" | sed -e s+unknown.*$++ >/tmp/epos-said.wav && play /tmp/epos-said.wav >/dev/null" @end example @end defvr @defvr {Konfigurace generického modulu} AddVoice "@var{language}" "@var{symbolicname}" "@var{name}" @xref{AddVoice}. @end defvr @defvr {Konfigurace generického modulu} GenericLanguage "iso-code" "string-subst" Definuje, jaký řetězec @code{string-subst} by měl být nahrazen za @code{$LANG} pro daný @code{iso-code} ISO kód jazyka. Opět příklad z Epos generic: @example GenericLanguage "en" "english" GenericLanguage "cs" "czech" GenericLanguage "sk" "slovak" @end example @end defvr @defvr {Konfigurace generického modulu} GenericRateAdd @var{num} @end defvr @defvr {Konfigurace generického modulu} GenericRateMultiply @var{num} @end defvr @defvr {Konfigurace generického modulu} GenericPitchAdd @var{num} @end defvr @defvr {Konfigurace generického modulu} GenericPitchMultiply @var{num} Tyto parametry nastavují konverzi pro výpočet rychlosti a výšky. (@code{$RATE} a @code{$PITCH}). Výsledná rychlost (nebo výška) je dána následujícím vzorcem: @example (speechd_rate * GenericRateMultiply) + GenericRateAdd @end example kde speechd_rate je hodnota mezi -100 (nejnižší) a +100 (nejvyšší). Je třeba definovat nějakou rozumnou konverzi pro daný syntetizér. (Hodnoty v GenericNěcoMultiply jsou vynásobeny stem, protože stávající verze DotConfu nepodporuje desetinná čísla. Můžete tedy psát 0.85 jako 85 atd.) @end defvr @node Úrovně logování, , Nastavení výstupních modulů, Konfigurace @subsection Úrovně logování Ve Speech Dispatcheru je 6 různých úrovní logování. 0 znamená žádné logování, zatímco 5 znamená vypisovat téměř všechny dostupné informace. @itemize @bullet @item Úroveň 0 @itemize @bullet @item Žádné informace @end itemize @item Úroveň 1 @itemize @bullet @item Informace o startu a vypínání. @end itemize @item Úroveň 2 @itemize @bullet @item Informace o chybách, které nastaly. @item Alokace a uvolňování zdrojů při startu a při exitu. @end itemize @item Úroveň 3 @itemize @bullet @item Informace o přijímání/odepírání/zavírání klientských spojení. @item Informace o neplatných SSIP příkazech od klientů. @end itemize @item Úroveň 4 @itemize @bullet @item Je vypisován každý přijatý příkaz @item Informace o zpracovávání vstupu @item Informace o ukládání zpráv do front @item Informace o fungování historie, zvukových ikon, atd. facilities. @item Informace o práci vlákna speak() @end itemize @item Úroveň 5 (Ta slouží pouze pro ladící účely a může vypisovat opravdu *mnoho* dat. Používejte opatrně.) @itemize @bullet @item Všechna obdržená data jsou vypisována (zprávy od klientů) @item Ladící informace. @end itemize @end itemize @appendix Standardní hlasy @anchor{Standardní hlasy} @table @code @item MALE1 @item MALE2 @item MALE3 @item FEMALE1 @item FEMALE2 @item FEMALE3 @item CHILD_MALE @item CHILD_FEMALE @end table Skutečná dostupnost těchto hlasů není zaručena, ale příkaz @code{SET SELF VOICE} musí akceptovat jakýkoliv z nich. Pokud není daný hlas dostupný, je mapován na jiný hlas výstupním modulem. @node GNU General Public License, GNU Free Documentation License, Uživatelská dokumentace, Top @appendix GNU General Public License @center Version 2, June 1991 @cindex GPL, GNU General Public License @include gpl.texi @node GNU Free Documentation License, Index of Concepts, GNU General Public License, Top @appendix GNU Free Documentation License @center Version 1.2, November 2002 @cindex FDL, GNU Free Documentation License @include fdl.texi @node Index of Concepts, , GNU Free Documentation License, Top @unnumbered Index of Concepts @cindex tail recursion @printindex cp @bye @c LocalWords: texinfo setfilename speechd settitle finalout syncodeindex pg @c LocalWords: setchapternewpage cp fn vr texi dircategory direntry titlepage @c LocalWords: Cerha Hynek Hanke vskip pt filll insertcopying ifnottex dir fd @c LocalWords: API SSIP cindex printf ISA pindex Flite Odmluva FreeTTS TTS CR @c LocalWords: src struct gchar gint const OutputModule intl FDSetElement len @c LocalWords: fdset init flite deffn TFDSetElement var int enum EVoiceType @c LocalWords: sayf ifinfo verbatiminclude ref UTF ccc ddd pxref LF cs conf @c LocalWords: su AddModule DefaultModule xref identd printindex Dectalk GTK @c speechd.texi ends here @c LocalWords: emph soundcard precission archieved succes speech-dispatcher-0.9.1/doc/speech-dispatcher.texi0000755000175000017500000043710713424443547017121 00000000000000\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename speech-dispatcher.info @settitle Speech Dispatcher @finalout @c @setchapternewpage odd @c %**end of header @syncodeindex pg cp @syncodeindex fn cp @syncodeindex vr cp @include version.texi @dircategory Sound @dircategory Development @direntry * Speech Dispatcher: (speech-dispatcher). Speech Dispatcher. @end direntry @titlepage @title Speech Dispatcher @subtitle Mastering the Babylon of TTS' @subtitle for Speech Dispatcher @value{VERSION} @author Tom@'a@v{s} Cerha <@email{cerha@@brailcom.org}> @author Hynek Hanke <@email{hanke@@volny.cz}> @author Milan Zamazal <@email{pdm@@brailcom.org}> @page @vskip 0pt plus 1filll This manual documents Speech Dispatcher, version @value{VERSION}. Copyright @copyright{} 2001, 2002, 2003, 2006, 2007, 2008 Brailcom, o.p.s. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' @end quotation You can also (at your option) distribute this manual under the GNU General Public License: @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled ``GNU General Public License'' @end quotation @end titlepage @ifnottex @node Top, Introduction, (dir), (dir) This manual documents Speech Dispatcher, version @value{VERSION}. Copyright @copyright{} 2001, 2002, 2003, 2006 Brailcom, o.p.s. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License.'' @end quotation You can also (at your option) distribute this manual under the GNU General Public License: @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is included in the section entitled ``GNU General Public License'' @end quotation @end ifnottex @ifhtml @heading Menu @end ifhtml @menu * Introduction:: What is Speech Dispatcher. * User's Documentation:: Usage, Configuration... * Technical Specifications:: * Client Programming:: Documentation for application developers. * Server Programming:: Documentation for project contributors. * Download and Contact:: How to get Speech Dispatcher and how to contact us * Reporting Bugs:: How to report a bug * How You Can Help:: What is needed * Appendices:: * GNU General Public License:: Copying conditions for Speech Dispatcher * GNU Free Documentation License:: Copying conditions for this manual * Index of Concepts:: @end menu @node Introduction, User's Documentation, Top, Top @chapter Introduction @menu * Motivation:: Why Speech Dispatcher? * Basic Design:: How does it work? * Features Overview:: What are the assets? * Current State:: What is done? @end menu @node Motivation, Basic Design, Introduction, Introduction @section Motivation @cindex Basic ideas, Motivation @cindex Philosophy Speech Dispatcher is a device independent layer for speech synthesis that provides a common easy to use interface for both client applications (programs that want to speak) and for software synthesizers (programs actually able to convert text to speech). High quality speech synthesis is now commonly available both as propriatary and Free Software solutions. It has a wide field of possible uses from educational software to specialized systems, e.g. in hospitals or laboratories. It is also a key compensation tool for the visually impaired users. For them, it is one of the two possible ways of getting output from a computer (the second one being a Braille display). The various speech synthesizers are quite different, both in their interfaces and capabilities. Thus a general common interface is needed so that the client application programmers have an easy way to use software speech synthesis and don't have to care about peculiar details of the various synthesizers. The absence of such a common and standardized interface and thus the difficulty for programmers to use software speech synthesis has been a major reason why the potential of speech synthesis technology is still not fully expoited. Ideally, there would be little distinction for applications whether they output messages on the screen or via speech. Speech Dispatcher can be compared to what a GUI toolkit is for the graphical interface. Not only does it provide an easy to use interface, some kind of theming and configuration mechanisms, but also it takes care of some of the issues inherent with this particular mode of output, such as the need for speech message serialization and interaction with the audio subsystem. @node Basic Design, Features Overview, Motivation, Introduction @section Design @cindex Design @heading Current Design The communication between all applications and synthesizers, when implemented directly, is a mess. For this purpose, we wanted Speech Dispatcher to be a layer separating applications and synthesizers so that applications wouldn't have to care about synthesizers and synthesizers wouldn't have to care about interaction with applications. We decided we would implement Speech Dispatcher as a server receiving commands from applications over a protocol called @code{SSIP}, parsing them if needed, and calling the appropriate functions of output modules communicating with the different synthesizers. These output modules are implemented as plug-ins, so that the user can just load a new module if he wants to use a new synthesizer. Each client (application that wants to speak) opens a socket connection to Speech Dispatcher and calls functions like say(), stop(), and pause() provided by a library implementing the protocol. This shared library is still on the client side and sends Speech Dispatcher SSIP commands over the socket. When the messages arrive at Speech Dispatcher, it parses them, reads the text that should be said and puts it in one of several queues according to the priority of the message and other criteria. It then decides when, with which parameters (set up by the client and the user), and on which synthesizer it will say the message. These requests are handled by the output plug-ins (output modules) for different hardware and software synthesizers and then said aloud. @image{figures/architecture,155mm,,Speech Dispatcher architecture} See also the detailed description @ref{Client Programming} interfaces, and @ref{Server Programming} documentation. @heading Future Design Speech Dispatcher currently mixes two important features: common low-level interface to multiple speech synthesizers and message management (including priorities and history). This became even more evident when we started thinking about handling messages intended for output on braille devices. Such messages of course need to be synchronized with speech messages and there is little reason why the accessibility tools should send the same message twice for these two different kinds of output used by blind people (often simultaneously). Outside the world of accessibility, applications also want to either have full control over the sound (bypass prioritisation) or to only retrieve the synthesized data, but not play them immediatelly. We want to eventually split Speech Dispatcher into two independent components: one providing a low-level interface to speech synthesis drivers, which we now call TTS API Provider and is already largely implemented in the Free(b)Soft project, and the second doing message managemenet, called Message Dispatcher. This will allow Message Dispatcher to also output on Braille as well as to use the TTS API Provider separately. From implementation point of view, an opportunity for new design based on our previous experiences allowed us to remove several bottlenecks for speed (responsiveness), ease of use and ease of implementation of extensions (particularly output modules for new synthesizers). From the architecture point of view and possibilities for new developments, we are entirely convinced that both the new design in general and the inner design of the new components is much better. While a good API and its implementation for Braille are already existent in the form of BrlAPI, the API for speech is now under developement. Please see another architecture diagram showing how we imagine Message Dispatcher in the future. @image{figures/architecture-future,155mm,,Speech Dispatcher architecture} References: @uref{http://www.freebsoft.org/tts-api/} @uref{http://www.freebsoft.org/tts-api-provider/} @node Features Overview, Current State, Basic Design, Introduction @section Features Overview Speech Dispatcher from user's point of view: @itemize @bullet @item ability to freely combine applications with your favorite synthesizer @item message synchronization and coordination @item less time devoted to configuration of applications @end itemize Speech Dispatcher from application programmers's point of view: @itemize @bullet @item easy way to make your applications speak @item common interface to different synthesizers @item higher level synchronization of messages (priorities) @item no need to take care about configuration of voice(s) @end itemize @node Current State, , Features Overview, Introduction @section Current State @cindex Synthesizers @cindex Other programs In this version, most of the features of Speech Dispatcher are implemented and we believe it is now useful for applications as a device independent Text-to-Speech layer and an accessibility message coordination layer. Currently, one of the most advanced applications that works with Speech Dispatcher is @code{speechd-el}. This is a client for Emacs, targeted primarily for blind people. It is similar to Emacspeak, however the two take a bit different approach and serve different user needs. You can find speechd-el on @uref{http://www.freebsoft.org/speechd-el/}. speechd-el provides speech output when using nearly any GNU/Linux text interface, like editing text, reading email, browsing the web, etc. Orca, the primary screen reader for the Gnome Desktop, supports Speech Dispatcher directly since its version 2.19.0. See @uref{http://live.gnome.org/Orca/SpeechDispatcher} for more information. We also provide a shared C library, a Python library, a Java, Guile and a Common Lisp libraries that implement the SSIP functions of Speech Dispatcher in higher level interfaces. Writing client applications in these languages should be quite easy. On the synthesis side, there is good support for Festival, eSpeak, Flite, Cicero, IBM TTS, MBROLA, Epos, Dectalk software, Cepstral Swift and others. See @xref{Supported Modules}. We decided not to interface the simple hardware speech devices as they don't support synchronization and therefore cause serious problems when handling multiple messages. Also they are not extensible, they are usually expensive and often hard to support. Today's computers are fast enough to perform software speech synthesis and Festival is a great example. @node User's Documentation, Technical Specifications, Introduction, Top @chapter User's Documentation @menu * Installation:: How to get it installed in the best way. * Running:: The different ways to start it. * Troubleshooting:: What to do if something doesn't work... * Configuration:: How to configure Speech Dispatcher. * Tools:: What tools come with Speech Dispatcher. * Synthesis Output Modules:: Drivers for different synthesizers. * Security:: Security mechanisms and restrictions. @end menu @node Installation, Running, User's Documentation, User's Documentation @section Installation This part only deals with the general aspects of installing Speech Dispatcher. If you are compiling from source code (distribution tarball or git), please refer to the file @file{INSTALL} in your source tree. @subsection The requirements You will need these components to run Speech Dispatcher: @itemize @item glib 2.0 (@uref{http://www.gtk.org}) @item libdotconf 1.3 (@uref{http://github.com/williamh/dotconf}) @item pthreads @end itemize We recommend to also install these packages: @itemize @item Festival (@uref{http://www.cstr.ed.ac.uk/projects/festival/}) @item festival-freebsoft-utils 0.3+ (@uref{http://www.freebsoft.org/festival-freebsoft-utils}) @item Sound icons library @* (@uref{http://www.freebsoft.org/pub/projects/sound-icons/sound-icons-0.1.tar.gz}) @end itemize @subsection Recommended installation procedure @itemize @item Install your software synthesizer Although we highly recommend to use Festival for its excellent extensibility, good quality voices, good responsiveness and best support in Speech Dispatcher, you might want to start with eSpeak, a lightweight multi-lingual feature-complete synthesizer, to get all the key components working and perhaps only then switch to Festival. Installation of eSpeak should be easier and the default configuration of Speech Dispatcher is set up for eSpeak for this reason. You can of course also start with Epos or any other supported synthesizer. @item Make sure your synthesizer works There is usually a way to test if the installation of your speech synthesizer works. For eSpeak run @code{espeak "test"}, for Flite run @code{flite -t "Hello!"} and hear the speech. For Festival run @code{festival} and type in @example (SayText "Hello!") (quit) @end example @item Install Speech Dispatcher Install the packages for Speech Dispatcher from your distribution or download the source tarball (or git) from @url{http://www.freebsoft.org/speechd} and follow the instructions in the file @code{INSTALL} in the source tree. @item Configure Speech Dispatcher You can skip this step in most cases. If you however want to setup your own configuration of the Dispatchers default values, the easiest way to do so is through the @code{spd-conf} configuration script. It will guide you through the basic configuration. It will also subsequently perform some diagnostics tests and offer some limited help with troubleshooting. Just execute @example spd-conf @end example under an ordinary user or system user like 'speech-dispatcher' depending on whether you like to setup Speech Dispatcher as user or system service respectively. You might also want to explore the offered options or run some of its subsystems manually, type @code{spd-conf -h} for help. If you do not want to use this script, it doesn't work in your case or it doesn't provide enough configuration flexibility, please continue as described below and/or in @xref{Running Under Ordinary Users}. @item Test Speech Dispatcher The simplest way to test Speech Dispatcher is through @code{spd-conf -d} or through the @code{spd-say} tool. Example: @example spd-conf -d spd-say "Hello!" spd-say -l cs -r 90 "Ahoj" @end example If you don't hear anything, please @xref{Troubleshooting}. @end itemize @subsection How to use eSpeak NG or eSpeak with MBROLA Please follow the guidelines at @url{https://github.com/espeak-ng/espeak-ng/blob/master/docs/mbrola.md} (resp. @url{http://espeak.sourceforge.net/mbrola.html}) for installing eSpeak NG (resp. eSpeak) with a set of MBROLA voices that you want to use. Check the @file{modules/espeak-ng-mbrola-generic.conf} (resp. @file{modules/espeak-mbrola-generic.conf}) configuration files for the @code{AddVoice} lines. If a line for any of the voices you have installed (and it is supported by your version of eSpeak NG (resp. eSpeak), e.g. @code{ls /usr/share/espeak-ng-data/voices/mb/mb-*} (resp. @code{ls /usr/share/espeak-data/voices/mb/mb-*})) is not contained here, please add it. Check if @code{GenericExecuteString} contains the correct name of your mbrola binary and correct path to its voice database. Restart speech-dispatcher and in your client, select @code{espeak-ng-mbrola-generic} (resp. @code{espeak-mbrola-generic}) as your output module, or test it with the following command @example spd-say -o espeak-ng-mbrola-generic -l cs Testing @end example (resp. @example spd-say -o espeak-mbrola-generic -l cs Testing @end example ) @node Running, Troubleshooting, Installation, User's Documentation @section Running Speech Dispatcher is normally executed on a per-user basis. This provides more flexibility in user configuration, access rights and is essential in any environment where multiple people use the computer at the same time. It used to be possible to run Speech Dispatcher as a system service under a special user (and still is, with some limitations), but this mode of execution is strongly discouraged. @menu * Running Under Ordinary Users:: * Running in a Custom Setup:: * Setting Communication Method:: @end menu @node Running Under Ordinary Users, Running in a Custom Setup, Running, Running @subsection Running Under Ordinary Users No special provisions need to be done to run Speech Dispatcher under the current user. The Speech Dispatcher process will use (or create) a @file{~/.cache/speech-dispatcher/} directory for its purposes (logging, pidfile). Optionally, a user can place his own configuration file in @file{~/.config/speech-dispatcher/speechd.conf} and it will be automatically loaded by Speech Dispatcher. The preferred way to do so is via the @code{spd-conf} configuration command. If this user configuration file is not found, Speech Dispatcher will simply use the system wide configuration file (e.g. in @file{/etc/speech-dispatcher/speechd.conf}). @example # speech-dispatcher # spd-say test @end example @node Running in a Custom Setup, Setting Communication Method, Running Under Ordinary Users, Running @subsection Running in a Custom Setup Speech Dispatcher can be run in any other setup of executing users, port numbers and system paths as well. The path to configuration, pidfile and logfiles can be specified separately via compilation flags, configuration file options or command line options in this ascending order of their priority. This way can also be used to start Speech Dispatcher as a system wide service from /etc/init.d/ , although this approach is now discouraged. @node Setting Communication Method, , Running in a Custom Setup, Running @subsection Setting Communication Method Currently, two different methods are supported for communication between the server and its clients. For local communication, it's preferred to use @emph{Unix sockets}, where the communication takes place over a Unix socket with its driving file located by default in the user's runtime directory as @code{XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock}. In this way, there can be no conflict between different user sessions using different Speech Dispatchers in the same system. By default, permissions are set in such a way, that only the same user who started the server can access it, and communication is hidden to all other users. The other supported mechanism is @emph{Inet sockets}. The server will thus run on a given port, which can be made accessible either localy or to other machines on the network as well. This is very useful in a network setup. Be however aware that while using Inet sockets, both parties (server and clients) must first agree on the communication port number to use, which can create a lot of confusion in a setup where multiple instances of the server serve multiple different users. Also, since there is currently no authentication mechanism, during Inet socket communication, the server will make no distinction between the different users connecting to it. The default port is 6560 as set in the server configuration. Client applications will respect the @emph{SPEECHD_ADDRESS} environment variable. The method ('@code{unix_socket}' or '@code{inet_socket}') is optionally followed by it's parameters separated by a colon. For an exact description, please @xref{Address specification}. An example of launching Speech Dispatcher using unix_sockets for communication on a non-standard destination and subsequently using spd-say to speak a message: @example killall -u `whoami` speech-dispatcher speech-dispatcher -c unix_socket -S /tmp/my.sock SPEECHD_ADDRESS=unix_socket:/tmp/my.sock spd-say "test" @end example @node Troubleshooting, Configuration, Running, User's Documentation @section Troubleshooting If you are experiencing problems when running Speech Dispatcher, please: @itemize @item Use @code{spd-conf} to run diagnostics: @example spd-conf -d @end example @item Check the appropriate logfile in @file{~/.cache/speech-dispatcher/log/speech-dispatcher.log} for user Speech Dispatcher or in @file{/var/log/speech-dispatcher/speech-dispatcher.log}. Look for lines containing the string 'ERROR' and their surrounding contents. If you hear no speech, restart Speech Dispatcher and look near the end of the log file -- before any attempts for synthesis of any message. Usually, if something goes wrong with the initialization of the output modules, a textual description of the problem and a suggested solution can be found in the log file. @item If this doesn't reveal the problem, please run @example spd-conf -D @end example Which will genereate a very detailed logfile archive which you can examine yourself or send to us with a request for help. @item You can also try to say some message directly through the utility @code{spd-say}. Example: @example spd-say "Hello, does it work?" spd-say --language=cs --rate=20 "Everything ok?" @end example @item Check if your configuration files (speechd.conf, modules/*.conf) are correct (some uninstalled synthesizer specified as the default, wrong values for default voice parameters etc.) @item There is a know problem in some versions of Festival. Please make sure that Festival server_access_list configuration variable and your /etc/hosts.conf are set properly. server_access_list must contain the symbolic name of your machine and this name must be defined in /etc/hosts.conf and point to your IP address. You can test if this is set correctly by trying to connect to the port Festival server is running on via an ordinary telnet (by default like this: @code{telnet localhost 1314}). If you are not rejected, it works. @end itemize @node Configuration, Tools, Troubleshooting, User's Documentation @section Configuration @cindex configuration @cindex default values Speech Dispatcher can be configured on several different levels. You can configure the global settings through the server configuration file, which can be placed either in the Speech Dispatcher default configuration system path like /etc/speech-dispatcher/ or in your home directory in @file{~/.config/speech-dispatcher/}. There is also support for per-client configuration, this is, specifying different default values for different client applications. Furthermore, applications often come with their own means of configuring speech related settings. Please see the documentation of your application for details about application specific configuration. @menu * Configuration file syntax:: Basic rules. * Configuration options:: What to configure. * Audio Output Configuration:: How to switch to ALSA, Pulse... * Client Specific Configuration:: Specific default values for applications. * Output Modules Configuration:: Adding and customizing output modules. * Log Levels:: Description of log levels. @end menu @node Configuration file syntax, Configuration options, Configuration, Configuration @subsection Configuration file syntax We use the DotConf library to read a permanent text-file based configuration, so the syntax might be familiar to many users. Each of the string constants, if not otherwise stated differently, should be encoded in UTF-8. The option names use only the standard ASCII charset restricted to upper- and lowercase characters (@code{a}, @code{b}), dashes (@code{-}) and underscores @code{_}. Comments and temporarily inactive options begin with @code{#}. If such an option should be turned on, just remove the comment character and set it to the desired value. @example # this is a comment # InactiveOption "this option is turned off" @end example Strings are enclosed in doublequotes. @example LogFile "/var/log/speech-dispatcher.log" @end example Numbers are written without any quotes. @example Port 6560 @end example Boolean values use On (for true) and Off (for false). @example Debug Off @end example @node Configuration options, Audio Output Configuration, Configuration file syntax, Configuration @subsection Configuration options All available options are documented directly in the file and examples are provided. Most of the options are set to their default value and commented out. If you want to change them, just change the value and remove the comment symbol @code{#}. @node Audio Output Configuration, Client Specific Configuration, Configuration options, Configuration @subsection Audio Output Configuration Audio output method (ALSA, Pulse etc.) can be configured centrally from the main configuration file @code{speechd.conf}. The option @code{AudioOutputMethod} selects the desired audio method and further options labeled as @code{AudioALSA...} or @code{AudioPulse...} provide a more detailed configuration of the given audio output method. It is possible to use a list of preferred audio output methods, in which case each output module attempts to use the first availble in the given order. The example below prefers Pulse Audio, but will use ALSA if unable to connect to Pulse: @example AudioOutputMethod "pulse,alsa" @end example Please note however that some more simple output modules or synthesizers, like the generic output module, do not respect these settings and use their own means of audio output which can't be influenced this way. On the other hand, the fallback dummy output module tries to use any available means of audio output to deliver its error message. @node Client Specific Configuration, Output Modules Configuration, Audio Output Configuration, Configuration @subsection Client Specific Configuration It is possible to automatically set different default values of speech parameters (e.g. rate, volume, punctuation, default voice...) for different applications that connect to Speech Dispatcher. This is especially useful for simple applications that have no parameter setting capabilities themselves or they don't support a parameter setting you wish to change (e.g. language). Using the commands @code{BeginClient "IDENTIFICATION"} and @code{EndClient} it is possible to open and close a section of parameter settings that only affects those client applications that identify themselves to Speech Dispatcher under the specific identification code which is matched against the string @code{IDENTIFICATION}. It is possible to use wildcards ('*' matches any number of characters and '?' matches exactly one character) in the string @code{IDENTIFICATION}. The identification code normally consists of 3 parts: @code{user:application:connection}. @code{user} is the username of the one who started the application, @code{application} is the name of the application (usually the name of the binary for it) and @code{connection} is a name for the connection (one application might use more connections for different purposes). An example is provided in @code{/etc/speech-dispatcher/speechd.conf} (see the line @code{Include "clients/emacs.conf"} and @code{/etc/speech-dispatcher/clients/emacs.conf}. @node Output Modules Configuration, Log Levels, Client Specific Configuration, Configuration @subsection Output Modules Configuration Each user should turn on at least one output module in his configuration, if he wants Speech Dispatcher to produce any sound output. If no output module is loaded, Speech Dispatcher will start, log messages into history and communicate with clients, but no sound is produced. Each output module has an ``AddModule'' line in @file{speech-dispatcher/speechd.conf}. Additionally, each output module can have its own configuration file. The audio output is handled by the output modules themselves, so this can be switched in their own configuration files under @code{etc/speech-dispatcher/modules/}. @menu * Loading Modules in speechd.conf:: * Configuration files of output modules:: * Configuration of the Generic Output Module:: @end menu @node Loading Modules in speechd.conf, Configuration files of output modules, Output Modules Configuration, Output Modules Configuration @subsubsection Loading Modules in speechd.conf @anchor{AddModule} Each module that should be run when Speech Dispatcher starts must be loaded by the @code{AddModule} command in the configuration. Note that you can load one binary module multiple times under different names with different configurations. This is especially useful for loading the generic output module. @xref{Configuration of the Generic Output Module}. @example AddModule "@var{module_name}" "@var{module_binary}" "@var{module_config}" @end example @var{module_name} is the name of the output module. @var{module_binary} is the name of the binary executable of this output module. It can be either absolute or relative to @file{bin/speechd-modules/}. @var{module_config} is the file where the configuration for this output module is stored. It can be either absolute or relative to @file{etc/speech-dispatcher/modules/}. This parameter is optional. @node Configuration files of output modules, Configuration of the Generic Output Module, Loading Modules in speechd.conf, Output Modules Configuration @subsubsection Configuration Files of Output Modules Each output module is different and therefore has different configuration options. Please look at the comments in its configuration file for a detailed description. However, there are several options which are common for some output modules. Here is a short overview of them. @itemize @item AddVoice "@var{language}" "@var{symbolicname}" "@var{name}" @anchor{AddVoice} Each output module provides some voices and sometimes it even supports different languages. For this reason, there is a common mechanism for specifying these in the configuration, although no module is obligated to use it. Some synthesizers, e.g. Festival, support the SSIP symbolic names directly, so the particular configuration of these voices is done in the synthesizer itself. For each voice, there is exactly one @code{AddVoice} line. @var{language} is the ISO language code of the language of this voice. @var{symbolicname} is a symbolic name under which you wish this voice to be available. See @ref{Top,,Standard Voices, ssip, SSIP Documentation} for the list of names you can use. @var{name} is a name specific for the given output module. Please see the comments in the configuration file under the appropriate AddModule section for more info. For example our current definition of voices for Epos (file @code{/etc/speech-dispatcher/modules/generic-epos.conf} looks like this: @example AddVoice "cs" "male1" "kadlec" AddVoice "sk" "male1" "bob" @end example @item ModuleDelimiters "@var{delimiters}", ModuleMaxChunkLength @var{length} Normally, the output module doesn't try to synthesize all incoming text at once, but instead it cuts it into smaller chunks (sentences, parts of sentences) and then synthesizes them one by one. This second approach, used by some output modules, is much faster, however it limits the ability of the output module to provide good intonation. NOTE: The Festival module does not use ModuleDelimiters and ModuleMaxChunkLength. For this reason, you can configure at which characters (@var{delimiters}) the text should be cut into smaller blocks or after how many characters (@var{length}) it should be cut, if there is no @var{delimiter} found. Making the two rules more strict, you will get better speed but give away some quality of intonation. So for example for slower computers, we recommend to include comma (,) in @var{delimiters} so that sentences are cut into phrases, while for faster computers, it's preferable not to include comma and synthesize the whole compound sentence. The same applies to @code{MaxChunkLength}, it's better to set higher values for faster computers. For example, curently the default for Flite is @example FestivalMaxChunkLength 500 FestivalDelimiters ".?!;" @end example The output module may also decide to cut sentences on delimiters only if they are followed by a space. This way for example ``file123.tmp'' would not be cut in two parts, but ``The horse raced around the fence, that was lately painted green, fell.'' would be. (This is an interesting sentence, by the way.) @end itemize @node Configuration of the Generic Output Module, , Configuration files of output modules, Output Modules Configuration @subsubsection Configuration files of the Generic Output Module The generic output module allows you to easily write your own output module for synthesizers that have a simple command line interface by modifying the configuration file. This way, users can add support for their device even if they don't know how to program. @xref{AddModule}. The core part of a generic output module is the command execution line. @defvr {Generic Module Configuration} GenericExecuteSynth "@var{execution_string}" @code{execution_string} is the command that should be executed in a shell when it's desired to say something. In fact, it can be multiple commands concatenated by the @code{&&} operator. To stop saying the message, the output module will send a KILL signal to the process group, so it's important that it immediately stops speaking after the processes are killed. (On most GNU/Linux system, the @code{play} utility has this property). In the execution string, you can use the following variables, which will be substituted by the desired values before executing the command. @itemize @item @code{$DATA} The text data that should be said. The string's characters that would interfere with bash processing are already escaped. However, it may be necessary to put double quotes around it (like this: @code{\"$DATA\"}). @item @code{$LANG} The language identification string (it's defined by GenericLanguage). @item @code{$VOICE} The voice identification string (it's defined by AddVoice). @item @code{$PITCH} The desired pitch (a float number defined in GenericPitchAdd and GenericPitchMultiply). @item @code{$PITCH_RANGE} The desired pitch range (a float number defined in GenericPitchRangeAdd and GenericPitchRangeMultiply). @item @code{$RATE} The desired rate or speed (a float number defined in GenericRateAdd and GenericRateMultiply) @end itemize Here is an example from @file{etc/speech-dispatcher/modules/epos-generic.conf} @example GenericExecuteSynth \ "epos-say -o --language $LANG --voice $VOICE --init_f $PITCH --init_t $RATE \ \"$DATA\" | sed -e s+unknown.*$++ >/tmp/epos-said.wav && play /tmp/epos-said.wav >/dev/null" @end example @end defvr @defvr {GenericModuleConfiguration} AddVoice "@var{language}" "@var{symbolicname}" "@var{name}" @xref{AddVoice}. @end defvr @defvr {GenericModuleConfiguration} GenericLanguage "iso-code" "string-subst" Defines which string @code{string-subst} should be substituted for @code{$LANG} given an @code{iso-code} language code. Another example from Epos generic: @example GenericLanguage "en" "english" GenericLanguage "cs" "czech" GenericLanguage "sk" "slovak" @end example @end defvr @defvr {GenericModuleConfiguration} GenericRateAdd @var{num} @end defvr @defvr {GenericModuleConfiguration} GenericRateMultiply @var{num} @end defvr @defvr {GenericModuleConfiguration} GenericPitchAdd @var{num} @end defvr @defvr {GenericModuleConfiguration} GenericPitchMultiply @var{num} @end defvr @defvr {GenericModuleConfiguration} GenericPitchRangeAdd @var{num} @end defvr @defvr {GenericModuleConfiguration} GenericPitchRangeMultiply @var{num} These parameters set rate and pitch conversion to compute the value of @code{$RATE}, @code{$PITCH} and @code{$PITCH_RANGE}. The resulting rate (or pitch) is calculated using the following formula: @example (speechd_rate * GenericRateMultiply) + GenericRateAdd @end example where speechd_rate is a value between -100 (lowest) and +100 (highest) Some meaningful conversion for the specific text-to-speech system used must by defined. (The values in GenericSthMultiply are multiplied by 100 because DotConf currently doesn't support floats. So you can write 0.85 as 85 and so on.) @end defvr @node Log Levels, , Output Modules Configuration, Configuration @subsection Log Levels There are 6 different verbosity levels of Speech Dispatcher logging. 0 means no logging, while 5 means that nearly all the information about Speech Dispatcher's operation is logged. @itemize @bullet @item Level 0 @itemize @bullet @item No information. @end itemize @item Level 1 @itemize @bullet @item Information about loading and exiting. @end itemize @item Level 2 @itemize @bullet @item Information about errors that occurred. @item Allocating and freeing resources on start and exit. @end itemize @item Level 3 @itemize @bullet @item Information about accepting/rejecting/closing clients' connections. @item Information about invalid client commands. @end itemize @item Level 4 @itemize @bullet @item Every received command is output. @item Information preceding the command output. @item Information about queueing/allocating messages. @item Information about the history, sound icons and other facilities. @item Information about the work of the speak() thread. @end itemize @item Level 5 (This is only for debugging purposes and will output *a lot* of data. Use with caution.) @itemize @bullet @item Received data (messages etc.) is output. @item Debugging information. @end itemize @end itemize @node Tools, Synthesis Output Modules, Configuration, User's Documentation @section Tools Several small tools are distributed together with Speech Dispatcher. @code{spd-say} is a small client that allows you to send messages to Speech Dispatcher in an easy way and have them spoken, or cancel speech from other applications. @menu * spd-say:: Say a given text or cancel messages in Dispatcher. * spd-conf:: Configuration, diagnostics and troubleshooting tool * spd-send:: Direct SSIP communication from command line. @end menu @node spd-say, spd-conf, Tools, Tools @subsection spd-say spd-say is documented in its own manual. @xref{Top,,,spd-say, Spd-say Documentation}. @node spd-conf, spd-send, spd-say, Tools @subsection spd-conf spd-conf is a tool for creating basic configuration, initial setup of some basic settings (output module, audio method), diagnostics and automated debugging with a possibility to send the debugging output to the developers with a request for help. The available command options are self-documented through @code{spd-say -h}. In any working mode, the tool asks the user about future actions and preferred configuration of the basic options. Most useful ways of execution are: @itemize @bullet @item @code{spd-conf} Create new configuration and setup basic settings according to user answers. Run diagnostics and if some problems occur, run debugging and offer to send a request for help to the developers. @item @code{spd-conf -d} Run diagnostics of problems. @item @code{spd-conf -D} Run debugging and offer to send a request for help to the developers. @end itemize @node spd-send, , spd-conf, Tools @subsection spd-send spd-send is a small client/server application that allows you to establish a connection to Speech Dispatcher and then use a simple command line tool to send and receive SSIP protocol communication. Please see @file{src/c/clients/spd-say/README} in the Speech Dispatcher's source tree for more information. @node Synthesis Output Modules, Security, Tools, User's Documentation @section Synthesis Output Modules @cindex output module @cindex different synthesizers Speech Dispatcher supports concurrent use of multiple output modules. If the output modules provide good synchronization, you can combine them when reading messages. For example if module1 can speak English and Czech while module2 speaks only German, the idea is that if there is some message in German, module2 is used, while module1 is used for the other languages. However the language is not the only criteria for the decision. The rules for selection of an output module can be influenced through the configuration file @file{speech-dispatcher/speechd.conf}. @menu * Provided Functionality:: Some synthesizers don't support the full set of SSIP features. @end menu @node Provided Functionality, , Synthesis Output Modules, Synthesis Output Modules @subsection Provided functionality Please note that some output modules don't support the full Speech Dispatcher functionality (e.g. spelling mode, sound icons). If there is no easy way around the missing functionality, we don't try to emulate it in some complicated way and rather try to encourage the developers of that particular synthesizer to add that functionality. We are actively working on adding the missing parts to Festival, so Festival supports nearly all of the features of Speech Dispatcher and we encourage you to use it. Much progress has also been done with eSpeak. @menu * Supported Modules:: @end menu @node Supported Modules, , Provided Functionality, Provided Functionality @subsubsection Supported Modules @itemize @bullet @item Festival Festival is a free software multi-language Text-to-Speech synthesis system that is very flexible and extensible using the Scheme scripting language. Currently, it supports high quality synthesis for several languages, and on today's computers it runs reasonably fast. If you are not sure which one to use and your language is supported by Festival, we advise you to use it. See @uref{http://www.cstr.ed.ac.uk/projects/festival/}. @item eSpeak eSpeak is a newer very lightweight free software engine with a broad range of supported languages and a good quality of voice at high rates. See @uref{http://espeak.sourceforge.net/}. @item Flite Flite (Festival Light) is a lightweight free software TTS synthesizer intended to run on systems with limited resources. At this time, it has only one English voice and porting voices from Festival looks rather difficult. With the caching mechanism provided by Speech Dispatcher, Festival is faster than Flite in most situations. See @uref{http://www.speech.cs.cmu.edu/flite/}. @item Generic The Generic module can be used with any synthesizer that can be managed by a simple command line application. @xref{Configuration of the Generic Output Module}, for more details about how to use it. However, it provides only very rudimentary support of speaking. @item Pico The SVOX Pico engine is a software speech synthesizer for German, English (GB and US), Spanish, French and Italian. SVOX produces clear and distinct speech output made possible by the use of Hidden Markov Model (HMM) algorithms. See @uref{http://git.debian.org/?p=collab-maint/svox.git}. Pico documentation can be found at @uref{http://android.git.kernel.org/?p=platform/external/svox.git; a=tree;f=pico_resources/docs} It includes three manuals: - SVOX_Pico_Lingware.pdf - SVOX_Pico_Manual.pdf - SVOX_Pico_architecture_and_design.pdf @end itemize @node Security, , Synthesis Output Modules, User's Documentation @section Security Speech Dispatcher doesn't implement any special authentication mechanisms but uses the standard system mechanisms to regulate access. If the default `unix_socket' communication mechanism is used, only the user who starts the server can connect to it due to imposed restrictions on the unix socket file permissions. In case of the `inet_socket' communication mechanism, where clients connect to Speech Dispatcher on a specified port, theoretically everyone could connect to it. The access is by default restricted only for connections originating on the same machine, which can be changed via the LocalhostAccessOnly option in the server configuration file. In such a case, the user is reponsible to set appropriate security restrictions on the access to the given port on his machine from the outside network using a firewall or similar mechanism. @node Technical Specifications, Client Programming, User's Documentation, Top @chapter Technical Specifications @menu * Communication mechanisms:: * Address specification:: * Actions performed on startup:: * Accepted signals:: @end menu @node Communication mechanisms, Address specification, Technical Specifications, Technical Specifications @section Communication mechanisms Speech Dispatcher supports two communicatino mechanisms: UNIX-style and Inet sockets, which are refered as 'unix-socket' and 'inet-socket' respectively. The communication mechanism is decided on startup and cannot be changed at runtime. Unix sockets are now the default and preferred variant for local communication, Inet sockets are necessary for communication over network. The mechanism for the decision of which method to use is as follows in this order of precedence: command-line option, configuration option, the default value 'unix-socket'. @emph{Unix sockets} are associated with a file in the filesystem. By default, this file is placed in the user's runtime directory (as determined by the value of the XDG_RUNTIME_DIR environment variable and the system configuration for the given user). It's default name is constructed as @code{XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock}. The access permissions for this file are set to 600 so that it's restricted to read/write by the current user. As such, access is handled properly and there are no conflicts between the different instances of Speech Dispatcher run by the different users. Client applications and libraries are supposed to independently replicate the process of construction of the socket path and connect to it, thus establishing a common communication channel in the default setup. It should be however possible in the client libraries and is possible in the server, to define a custom file as a socket name if needed. Client libraries should respect the @var{SPEECHD_ADDRESS} environment variable. @emph{Inet sockets} are based on communication over a given port on the given host, two variables which must be previously agreed between the server and client before a connection can be established. The only implicit security restriction is the server configuration option which can allow or disallow access from machines other than localhost. By convention, the clients should use host and port given by one of the following sources in the following order of precedence: its own configuration, value of the @var{SPEECHD_ADDRESS} environment variable and the default pair (localhost, 6560). @xref{Setting Communication Method}. @node Address specification, Actions performed on startup, Communication mechanisms, Technical Specifications @section Address specification Speech Dispatcher provies several methods of communication and can be used both locally and over network. @xref{Communication mechanisms}. Client applications and interface libraries need to recognize an address, which specifies how and where to contact the appropriate server. Address specification consits from the method and one or more of its parameters, each item separated by a colon: @example method:parameter1:parameter2 @end example The method is either 'unix_socket' or 'inet_socket'. Parameters are optional. If not used in the address line, their default value will be used. Two forms are currently recognized: @example unix_socket:full/path/to/socket inet_socket:host_ip:port @end example Examples of valid address lines are: @example unix_socket unix_socket:/tmp/test.sock inet_socket inet_socket:192.168.0.34 inet_socket:192.168.0.34:6563 @end example Clients implement different mechanisms how the user can set the address. Clients should respect the @var{SPEECHD_ADDRESS} environment variable @xref{Setting Communication Method}, unless the user ovverrides its value by settins in the client application itself. Clients should fallback to the default address, if neither the environment variable or their specific configuration is set. The default communication address currently is: @example unix_socket:/$XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock @end example where `~' stands for the path to the users home directory. @node Actions performed on startup, Accepted signals, Address specification, Technical Specifications @section Actions performed on startup What follows is an overview of the actions the server takes on startup in this order: @itemize @bullet @item Initialize logging stage 1 Set loglevel to 1 and log destination to stderr (logfile is not ready yet). @item Parse command line options Read preferred communication method, destinations for logfile and pidfile @item Establish the @file{~/.config/speech-dispatcher/} and @file{~/.cache/speech-dispatcher/} directories If pid and conf paths were not given as command line options, the server will place them in @file{~/.config/speech-dispatcher/} and @file{~/.cache/speech-dispatcher/} by default. If they are not specified AND the current user doesn't have a system home directory, the server will fail startup. The configuration file is pointed to @file{~/.config/speech-dispatcher/speechd.conf} if it exists, otherwise to @file{/etc/speech-dispatcher/speechd.conf} or a similar system location according to compile options. One of these files must exists, otherwise Speech Dispatcher will not know where to find its output modules. @item Create pid file Check the pid file in the determined location. If an instance of the server is already running, log an error message and exit with error code 1, otherwise create and lock a new pid file. @item Check for autospawning enabled If the server is started with --spawn, check whether autospawn is not disabled in the configuration (DisableAutoSpawn config option in speechd.conf). If it is disabled, log an error message and exit with error code 1. @item Install signal handlers @item Create unix or inet sockets and start listening @item Initialize Speech Dispatcher Read the configuration files, setup some lateral threads, start and initialize output modules. Reinitialize logging (stage 2) into the final logfile destination (as determined by the command line option, the configuration option and the default location in this order of precedence). After this step, Speech Dispatcher is ready to accept new connections. @item Daemonize the process Fork the process, disconnect from standard input and outputs, disconnect from parent process etc. as prescribed by the POSIX standards. @item Initialize the speaking lateral thread Initialize the second main thread which will process the speech request from the queues and pass them onto the Speech Dispatcher modules. @item Start accepting new connections from clients Start listening for new connections from clients and processing them in a loop. @end itemize @node Accepted signals, , Actions performed on startup, Technical Specifications @section Accepted signals @itemize @bullet @item SIGINT Terminate the server @item SIGHUP Reload configuration from config files but do not restart modules @item SIGUSR1 Reload dead output modules (modules which were previously working but crashed during runtime and marked as dead) @item SIGPIPE Ignored @end itemize @node Client Programming, Server Programming, Technical Specifications, Top @chapter Client Programming Clients communicate with Speech Dispatcher via the Speech Synthesis Internet Protocol (SSIP) @xref{Top, , , ssip, Speech Synthesis Internet Protocol documentation}. The protocol is the actual interface to Speech Dispatcher. Usually you don't need to use SSIP directly. You can use one of the supplied libraries, which wrap the SSIP interface. This is the recommended way of communicating with Speech Dispatcher. We try so support as many programming environments as possible. This manual (except SSIP) contains documentation for the C and Python libraries, however there are also other libraries developed as external projects. Please contact us for information about current external client libraries. @menu * C API:: Shared library for C/C++ * Python API:: Python module. * Guile API:: * Common Lisp API:: * Autospawning:: How server is started from clients @end menu @node C API, Python API, Client Programming, Client Programming @section C API @menu * Initializing and Terminating in C:: * Speech Synthesis Commands in C:: * Speech output control commands in C:: * Characters and Keys in C:: * Sound Icons in C:: * Parameter Setting Commands in C:: * Other Functions in C:: * Information Retrieval Commands in C:: * Event Notification and Index Marking in C:: * History Commands in C:: * Direct SSIP Communication in C:: @end menu @node Initializing and Terminating in C, Speech Synthesis Commands in C, C API, C API @subsection Initializing and Terminating @deffn {C API function} SPDConnection* spd_open(char* client_name, char* connection_name, char* user_name, SPDConnectionMode connection_mode) @findex spd_open() Opens a new connection to Speech Dispatcher and returns a socket file descriptor you will use to communicate with Speech Dispatcher. The socket file descriptor is a parameter used in all the other functions. It now uses local communication via inet sockets. See @code{spd_open2} for more details. The three parameters @code{client_name}, @code{connection_name} and @code{username} are there only for informational and navigational purposes, they don't affect any settings or behavior of any functions. The authentication mechanism has nothing to do with @code{username}. These parameters are important for the user when he wants to set some parameters for a given session, when he wants to browse through history, etc. The parameter @code{connection_mode} specifies how this connection should be handled internally and if event notifications and index marking capabilities will be available. @code{client_name} is the name of the client that opens the connection. Normally, it should be the name of the executable, for example ``lynx'', ``emacs'', ``bash'', or ``gcc''. It can be left as NULL. @code{connection_name} determines the particular use of that connection. If you use only one connection in your program, this should be set to ``main'' (passing a NULL pointer has the same effect). If you use two or more connections in your program, their @code{client_name}s should be the same, but @code{connection_name}s should differ. For example: ``buffer'', ``command_line'', ``text'', ``menu''. @code{username} should be set to the name of the user. Normally, you should get this string from the system. If set to NULL, libspeechd will try to determine it automatically by g_get_user_name(). @code{connection_mode} has two possible values: @code{SPD_MODE_SINGLE} and @code{SPD_MODE_THREADED}. If the parameter is set to @code{SPD_MODE_THREADED}, then @code{spd_open()} will open an additional thread in your program which will handle asynchronous SSIP replies and will allow you to use callbacks for event notifications and index marking, allowing you to keep track of the progress of speaking the messages. However, you must be aware that your program is now multi-threaded and care must be taken when using/handling signals. If @code{SPD_MODE_SINGLE} is chosen, the library won't execute any additional threads and SSIP will run only as a synchronous protocol, therefore event notifications and index marking won't be available. It returns a newly allocated SPDConnection* structure on success, or @code{NULL} on error. Each connection you open should be closed by spd_close() before the end of the program, so that the associated connection descriptor is closed, threads are terminated and memory is freed. @end deffn @deffn {C API function} SPDConnection* spd_open2(char* client_name, char* connection_name, char* user_name, SPDConnectionMode connection_mode, SPDConnectionMethod method, int autospawn) @findex spd_open2() Opens a new connection to Speech Dispatcher and returns a socket file descriptor. This function is the same as @code{spd_open} except that it gives more control of the communication method and autospawn functionality as described below. @code{method} is either @code{SPD_METHOD_UNIX_SOCKET} or @code{SPD_METHOD_INET_SOCKET}. By default, unix socket communication should be preferred, but inet sockets are necessary for cross-network communication. @code{autospawn} is a boolean flag specifying whether the function should try to autospawn (autostart) the Speech Dispatcher server process if it is not running already. This is set to 1 by default, so this function should normally not fail even if the server is not yet running. @end deffn @deffn {C API function} void spd_close(SPDConnection *connection) @findex spd_close() Closes a Speech Dispatcher socket connection, terminates associated threads (if necessary) and frees the memory allocated by spd_open(). You should close every connection before the end of your program. @code{connection} is the SPDConnection connection obtained by spd_open(). @end deffn @node Speech Synthesis Commands in C, Speech output control commands in C, Initializing and Terminating in C, C API @subsection Speech Synthesis Commands @defvar {C API type} SPDPriority @vindex SPDPriority @code{SPDPriority} is an enum type that represents the possible priorities that can be assigned to a message. @example typedef enum@{ SPD_IMPORTANT = 1, SPD_MESSAGE = 2, SPD_TEXT = 3, SPD_NOTIFICATION = 4, SPD_PROGRESS = 5 @}SPDPriority; @end example @xref{Top,,Message Priority Model,ssip, SSIP Documentation}. @end defvar @deffn {C API function} int spd_say(SPDConnection* connection, SPDPriority priority, char* text); @findex spd_say() Sends a message to Speech Dispatcher. If this message isn't blocked by some message of higher priority and this CONNECTION isn't paused, it will be synthesized directly on one of the output devices. Otherwise, the message will be discarded or delayed according to its priority. @code{connection} is the SPDConnection* connection created by spd_open(). @code{priority} is the desired priority for this message. @xref{Top,,Message Priority Model,ssip, SSIP Documentation}. @code{text} is a null terminated string containing text you want sent to synthesis. It must be encoded in UTF-8. Note that this doesn't have to be what you will finally hear. It can be affected by different settings, such as spelling, punctuation, text substitution etc. It returns a positive unique message identification number on success, -1 otherwise. This message identification number can be saved and used for the purpose of event notification callbacks or history handling. @end deffn @deffn {C API function} int spd_sayf(SPDConnection* connection, SPDPriority priority, char* format, ...); @findex spd_sayf() Similar to @code{spd_say()}, simulates the behavior of printf(). @code{format} is a string containing text and formatting of the parameters, such as ``%d'', ``%s'' etc. It must be encoded in UTF-8. @code{...} is an arbitrary number of arguments. All other parameters are the same as for spd_say(). For example: @example spd_sayf(conn, SPD_TEXT, "Hello %s, how are you?", username); spd_sayf(conn, SPD_IMPORTANT, "Fatal error on [%s:%d]", filename, line); @end example But be careful with unicode! For example this doesn't work: @example spd_sayf(conn, SPD_NOTIFY, ``Pressed key is %c.'', key); @end example Why? Because you are supposing that key is a char, but that will fail with languages using multibyte charsets. The proper solution is: @example spd_sayf(conn, SPD_NOTIFY, ``Pressed key is %s'', key); @end example where key is an encoded string. It returns a positive unique message identification number on success, -1 otherwise. This message identification number can be saved and used for the purpose of event notification callbacks or history handling. @end deffn @node Speech output control commands in C, Characters and Keys in C, Speech Synthesis Commands in C, C API @subsection Speech Output Control Commands @subsubheading Stop Commands @deffn {C API function} int spd_stop(SPDConnection* connection); @findex spd_stop() Stops the message currently being spoken on a given connection. If there is no message being spoken, does nothing. (It doesn't touch the messages waiting in queues). This is intended for stops executed by the user, not for automatic stops (because automatically you can't control how many messages are still waiting in queues on the server). @code{connection} is the SPDConnection* connection created by spd_open(). It returns 0 on success, -1 otherwise. @end deffn @deffn {C API function} int spd_stop_all(SPDConnection* connection); @findex spd_stop_all() The same as spd_stop(), but it stops every message being said, without distinguishing where it came from. It returns 0 on success, -1 if some of the stops failed. @end deffn @deffn {C API function} int spd_stop_uid(SPDConnection* connection, int target_uid); @findex spd_stop_uid() The same as spd_stop() except that it stops a client client different from the calling one. You must specify this client in @code{target_uid}. @code{target_uid} is the unique ID of the connection you want to execute stop() on. It can be obtained from spd_history_get_client_list(). @xref{History Commands in C}. It returns 0 on success, -1 otherwise. @end deffn @subsubheading Cancel Commands @deffn {C API function} int spd_cancel(SPDConnection* connection); Stops the currently spoken message from this connection (if there is any) and discards all the queued messages from this connection. This is probably what you want to do, when you call spd_cancel() automatically in your program. @end deffn @deffn {C API function} int spd_cancel_all(SPDConnection* connection); @findex spd_cancel_all() The same as spd_cancel(), but it cancels every message without distinguishing where it came from. It returns 0 on success, -1 if some of the stops failed. @end deffn @deffn {C API function} int spd_cancel_uid(SPDConnection* connection, int target_uid); @findex spd_cancel_uid() The same as spd_cancel() except that it executes cancel for some other client than the calling one. You must specify this client in @code{target_uid}. @code{target_uid} is the unique ID of the connection you want to execute cancel() on. It can be obtained from spd_history_get_client_list(). @xref{History Commands in C}. It returns 0 on success, -1 otherwise. @end deffn @subsubheading Pause Commands @deffn {C API function} int spd_pause(SPDConnection* connection); @findex int spd_pause() Pauses all messages received from the given connection. No messages except for priority @code{notification} and @code{progress} are thrown away, they are all waiting in a separate queue for resume(). Upon resume(), the message that was being said at the moment pause() was received will be continued from the place where it was paused. It returns immediately. However, that doesn't mean that the speech output will stop immediately. Instead, it can continue speaking the message for a while until a place where the position in the text can be determined exactly is reached. This is necessary to be able to provide `resume' without gaps and overlapping. When pause is on for the given client, all newly received messages are also queued and waiting for resume(). It returns 0 on success, -1 if something failed. @end deffn @deffn {C API function} int spd_pause_all(SPDConnection* connection); @findex spd_pause_all() The same as spd_pause(), but it pauses every message, without distinguishing where it came from. It returns 0 on success, -1 if some of the pauses failed. @end deffn @deffn {C API function} int spd_pause_uid(SPDConnection* connection, int target_uid); @findex spd_pause_uid() The same as spd_pause() except that it executes pause for a client different from the calling one. You must specify the client in @code{target_uid}. @code{target_uid} is the unique ID of the connection you want to pause. It can be obtained from spd_history_get_client_list(). @xref{History Commands in C}. It returns 0 on success, -1 otherwise. @end deffn @subsubheading Resume Commands @deffn {C API function} int spd_resume(SPDConnection* connection); @findex int spd_resume() Resumes all paused messages from the given connection. The rest of the message that was being said at the moment pause() was received will be said and all the other messages are queued for synthesis again. @code{connection} is the SPDConnection* connection created by spd_open(). It returns 0 on success, -1 otherwise. @end deffn @deffn {C API function} int spd_resume_all(SPDConnection* connection); @findex spd_resume_all() The same as spd_resume(), but it resumes every paused message, without distinguishing where it came from. It returns 0 on success, -1 if some of the pauses failed. @end deffn @deffn {C API function} int spd_resume_uid(SPDConnection* connection, int target_uid); @findex spd_resume_uid() The same as spd_resume() except that it executes resume for a client different from the calling one. You must specify the client in @code{target_uid}. @code{target_uid} is the unique ID of the connection you want to resume. It can be obtained from spd_history_get_client_list(). @xref{History Commands in C}. It returns 0 on success, -1 otherwise. @end deffn @node Characters and Keys in C, Sound Icons in C, Speech output control commands in C, C API @subsection Characters and Keys @deffn {C API function} int spd_char(SPDConnection* connection, SPDPriority priority, char* character); @findex spd_char() Says a character according to user settings for characters. For example, this can be used for speaking letters under the cursor. @code{connection} is the SPDConnection* connection created by spd_open(). @code{priority} is the desired priority for this message. @xref{Top,,Message Priority Model,ssip, SSIP Documentation}. @code{character} is a NULL terminated string of chars containing one UTF-8 character. If it contains more characters, only the first one is processed. It returns 0 on success, -1 otherwise. @end deffn @deffn {C API function} int spd_wchar(SPDConnection* connection, SPDPriority priority, wchar_t wcharacter); @findex spd_say_wchar() The same as spd_char(), but it takes a wchar_t variable as its argument. It returns 0 on success, -1 otherwise. @end deffn @deffn {C API function} int spd_key(SPDConnection* connection, SPDPriority priority, char* key_name); @findex spd_key() Says a key according to user settings for keys. @code{connection} is the SPDConnection* connection created by spd_open(). @code{priority} is the desired priority for this message. @xref{Top,,Message Priority Model,ssip, SSIP Documentation}. @code{key_name} is the name of the key in a special format. @xref{Top,,Speech Synthesis and Sound Output Commands, ssip, SSIP Documentation}, (KEY, the corresponding SSIP command) for description of the format of @code{key_name} It returns 0 on success, -1 otherwise. @end deffn @node Sound Icons in C, Parameter Setting Commands in C, Characters and Keys in C, C API @subsection Sound Icons @deffn {C API function} int spd_sound_icon(SPDConnection* connection, SPDPriority priority, char* icon_name); @findex spd_sound_icon() Sends a sound icon ICON_NAME. These are symbolic names that are mapped to a sound or to a text string (in the particular language) according to Speech Dispatcher tables and user settings. Each program can also define its own icons. @code{connection} is the SPDConnection* connection created by spd_open(). @code{priority} is the desired priority for this message. @xref{Top,,Message Priority Model,ssip, SSIP Documentation}. @code{icon_name} is the name of the icon. It can't contain spaces, instead use underscores (`_'). Icon names starting with an underscore are considered internal and shouldn't be used. @end deffn @node Parameter Setting Commands in C, Other Functions in C, Sound Icons in C, C API @subsection Parameter Settings Commands The following parameter setting commands are available. For configuration and history clients there are also functions for setting the value for some other connection and for all connections. They are listed separately below. Please see @ref{Top,,Parameter Setting Commands,ssip, SSIP Documentation} for a general description of what they mean. @deffn {C API function} int spd_set_data_mode(SPDConnection *connection, SPDDataMode mode) @findex spd_set_data_mode() Set Speech Dispatcher data mode. Currently, plain text and SSML are supported. SSML is especially useful if you want to use index marks or include changes of voice parameters in the text. @code{mode} is the requested data mode: @code{SPD_DATA_TEXT} or @code{SPD_DATA_SSML}. @end deffn @deffn {C API function} int spd_set_language(SPDConnection* connection, char* language); @findex spd_set_language() Sets the language that should be used for synthesis. @code{connection} is the SPDConnection* connection created by spd_open(). @code{language} is the language code as defined in RFC 1766 (``cs'', ``en'', ...). @end deffn @deffn {C API function} int spd_set_output_module(SPDConnection* connection, char* output_module); @findex spd_set_output_module() @anchor{spd_set_output_module} Sets the output module that should be used for synthesis. The parameter of this command should always be entered by the user in some way and not hardcoded anywhere in the code as the available synthesizers and their registration names may vary from machine to machine. @code{connection} is the SPDConnection* connection created by spd_open(). @code{output_module} is the output module name under which the module was loaded into Speech Dispatcher in its configuration (``flite'', ``festival'', ``epos-generic''... ) @end deffn @deffn {C API function} char* spd_get_output_module(SPDConnection* connection); @findex spd_get_output_module() @anchor{spd_get_output_module} Gets the current output module in use for synthesis. @code{connection} is the SPDConnection* connection created by spd_open(). It returns the output module name under which the module was loaded into Speech Dispatcher in its configuration (``flite'', ``festival'', ``espeak''... ) @end deffn @deffn {C API function} int spd_set_punctuation(SPDConnection* connection, SPDPunctuation type); @findex spd_set_punctuation() Set punctuation mode to the given value. `all' means speak all punctuation characters, `none' menas speak no punctuation characters, `some' means speak only punctuation characters given in the server configuration or defined by the client's last spd_set_punctuation_important(). @code{connection} is the SPDConnection* connection created by spd_open(). @code{type} is one of the following values: @code{SPD_PUNCT_ALL}, @code{SPD_PUNCT_NONE}, @code{SPD_PUNCT_SOME}. It returns 0 on success, -1 otherwise. @end deffn @deffn {C API function} int spd_set_spelling(SPDConnection* connection, SPDSpelling type); @findex spd_set_spelling() Switches spelling mode on and off. If set to on, all incoming messages from this particular connection will be processed according to appropriate spelling tables (see spd_set_spelling_table()). @code{connection} is the SPDConnection* connection created by spd_open(). @code{type} is one of the following values: @code{SPD_SPELL_ON}, @code{SPD_SPELL_OFF}. @end deffn @deffn {C API function} int spd_set_voice_type(SPDConnection* connection, SPDVoiceType voice); @findex spd_set_voice_type() @anchor{spd_set_voice_type} Set a preferred symbolic voice. @code{connection} is the SPDConnection* connection created by spd_open(). @code{voice} is one of the following values: @code{SPD_MALE1}, @code{SPD_MALE2}, @code{SPD_MALE3}, @code{SPD_FEMALE1}, @code{SPD_FEMALE2}, @code{SPD_FEMALE3}, @code{SPD_CHILD_MALE}, @code{SPD_CHILD_FEMALE}. @end deffn @deffn {C API function} int spd_set_synthesis_voice(SPDConnection* connection, char* voice_name); @findex spd_set_voice_type() @anchor{spd_set_synthesis_voice} Set the speech synthesizer voice to use. Please note that synthesis voices are an attribute of the synthesizer, so this setting only takes effect until the output module in use is changed (via @code{spd_set_output_module()} or via @code{spd_set_language}). @code{connection} is the SPDConnection* connection created by spd_open(). @code{voice_name} is any of the voice name values retrieved by @xref{spd_list_synthesis_voices}. @end deffn @deffn {C API function} int spd_set_voice_rate(SPDConnection* connection, int rate); @findex spd_set_voice_rate() Set voice speaking rate. @code{connection} is the SPDConnection* connection created by spd_open(). @code{rate} is a number between -100 and +100 which means the slowest and the fastest speech rate respectively. @end deffn @deffn {C API function} int spd_get_voice_rate(SPDConnection* connection); @findex spd_get_voice_rate() Get voice speaking rate. @code{connection} is the SPDConnection* connection created by spd_open(). It returns the current voice rate. @end deffn @deffn {C API function} int spd_set_voice_pitch(SPDConnection* connection, int pitch); @findex spd_set_voice_pitch() Set voice pitch. @code{connection} is the SPDConnection* connection created by spd_open(). @code{pitch} is a number between -100 and +100, which means the lowest and the highest pitch respectively. @end deffn @deffn {C API function} int spd_get_voice_pitch(SPDConnection* connection); @findex spd_get_voice_pitch() Get voice pitch. @code{connection} is the SPDConnection* connection created by spd_open(). It returns the current voice pitch. @end deffn @deffn {C API function} int spd_set_voice_pitch_range(SPDConnection* connection, int pitch_range); @findex spd_set_voice_pitch() Set voice pitch range. @code{connection} is the SPDConnection* connection created by spd_open(). @code{pitch_range} is a number between -100 and +100, which means the lowest and the highest pitch range respectively. @end deffn @deffn {C API function} int spd_set_volume(SPDConnection* connection, int volume); @findex spd_set_volume() Set the volume of the voice and sounds produced by Speech Dispatcher's output modules. @code{connection} is the SPDConnection* connection created by spd_open(). @code{volume} is a number between -100 and +100 which means the lowest and the loudest voice respectively. @end deffn @deffn {C API function} int spd_get_volume(SPDConnection* connection); @findex spd_get_volume() Get the volume of the voice and sounds produced by Speech Dispatcher's output modules. @code{connection} is the SPDConnection* connection created by spd_open(). It returns the current volume. @end deffn @node Other Functions in C, Information Retrieval Commands in C, Parameter Setting Commands in C, C API @subsection Other Functions @node Information Retrieval Commands in C, Event Notification and Index Marking in C, Other Functions in C, C API @subsection Information Retrieval Commands @deffn {C API function} char** spd_list_modules(SPDConnection* connection) @findex spd_list_modules() @anchor{spd_list_modules} Returns a null-terminated array of identification names of the available output modules. You can subsequently set the desired output module with @xref{spd_set_output_module}. In case of error, the return value is a NULL pointer. @code{connection} is the SPDConnection* connection created by spd_open(). @end deffn @deffn {C API function} char** spd_list_voices(SPDConnection* connection) @findex spd_list_voices() @anchor{spd_list_voices} Returns a null-terminated array of identification names of the symbolic voices. You can subsequently set the desired voice with @xref{spd_set_voice_type}. Please note that this is a fixed list independent of the synthesizer in use. The given voices can be mapped to specific synthesizer voices according to user wish or may, for example, all be mapped to the same voice. To choose directly from the raw list of voices as implemented in the synthesizer, @xref{spd_list_synthesis_voices}. In case of error, the return value is a NULL pointer. @code{connection} is the SPDConnection* connection created by spd_open(). @end deffn @deffn {C API function} char** spd_list_synthesis_voices(SPDConnection* connection) @findex spd_list_synthesis_voices() @anchor{spd_list_synthesis_voices} Returns a null-terminated array of identification names of @code{SPDVoice*} structures describing the available voices as given by the synthesizer. You can subsequently set the desired voice with @code{spd_set_synthesis_voice()}. @example typedef struct@{ char *name; /* Name of the voice (id) */ char *language; /* 2-letter ISO language code */ char *variant; /* a not-well defined string describing dialect etc. */ @}SPDVoice; @end example Please note that the list returned is specific to each synthesizer in use (so when you switch to another output module, you must also retrieve a new list). If you want instead to use symbolic voice names which are independent of the synthesizer in use, @xref{spd_list_voices}. In case of error, the return value is a NULL pointer. @code{connection} is the SPDConnection* connection created by spd_open(). @end deffn @node Event Notification and Index Marking in C, History Commands in C, Information Retrieval Commands in C, C API @subsection Event Notification and Index Marking in C When the SSIP connection is run in asynchronous mode, it is possible to register callbacks for all the SSIP event notifications and index mark notifications, as defined in @ref{Message Event Notification and Index Marking,,, ssip, SSIP Documentation} @defvar {C API type} SPDNotification @vindex SPDNotification @anchor{SPDNotification} @code{SPDNotification} is an enum type that represents the possible base notification types that can be assigned to a message. @example typedef enum@{ SPD_BEGIN = 1, SPD_END = 2, SPD_INDEX_MARKS = 4, SPD_CANCEL = 8, SPD_PAUSE = 16, SPD_RESUME = 32 @}SPDNotification; @end example @end defvar There are currently two types of callbacks in the C API. @defvar {C API type} SPDCallback @vindex SPDCallback @anchor{SPDCallback} @code{void (*SPDCallback)(size_t msg_id, size_t client_id, SPDNotificationType state);} This one is used for notifications about the events: @code{BEGIN}, @code{END}, @code{PAUSE} and @code{RESUME}. When the callback is called, it provides three parameters for the event. @code{msg_id} unique identification number of the message the notification is about. @code{client_id} specifies the unique identification number of the client who sent the message. This is usually the same connection as the connection which registered this callback, and therefore uninteresting. However, in some special cases it might be useful to register this callback for other SSIP connections, or register the same callback for several connections originating from the same application. @code{state} is the @code{SPD_Notification} type of this notification. @xref{SPDNotification}. @end defvar @defvar {C API type} SPDCallbackIM @vindex SPDCallbackIM @code{void (*SPDCallbackIM)(size_t msg_id, size_t client_id, SPDNotificationType state, char *index_mark);} @code{SPDCallbackIM} is used for notifications about index marks that have been reached in the message. (A way to specify index marks is e.g. through the SSML element in ssml mode.) The syntax and meaning of these parameters are the same as for @ref{SPDCallback} except for the additional parameter @code{index_mark}. @code{index_mark} is a NULL terminated string associated with the index mark. Please note that this string is specified by client application and therefore it needn't be unique. @end defvar One or more callbacks can be supplied for a given @code{SPDConnection*} connection by assigning the values of pointers to the appropriate functions to the following connection members: @example SPDCallback callback_begin; SPDCallback callback_end; SPDCallback callback_cancel; SPDCallback callback_pause; SPDCallback callback_resume; SPDCallbackIM callback_im; @end example There are three settings commands which will turn notifications on and off for the current SSIP connection and cause the callbacks to be called when the event is registered by Speech Dispatcher. @deffn {C API function} int spd_set_notification_on(SPDConnection* connection, SPDNotification notification); @findex spd_set_notification_on @end deffn @deffn {C API function} int spd_set_notification_off(SPDConnection* connection, SPDNotification notification); @findex spd_set_notification_off @end deffn @deffn {C API function} int spd_set_notification(SPDConnection* connection, SPDNotification notification, const char* state); @findex spd_set_notification These functions will set the notification specified by the parameter @code{notification} on or off (or to the given value) respectively. Note that it is only safe to call these functions after the appropriate callback functions have been set in the @code{SPDCallback} structure. Doing otherwise is not considered an error, but the application might miss some events due to callback functions not being executed (e.g. the client might receive an @code{END} event without receiving the corresponding @code{BEGIN} event in advance. @code{connection} is the SPDConnection* connection created by spd_open(). @code{notification} is the requested type of notifications that should be reported by SSIP. @xref{SPDNotification}. Note that also '|' combinations are possible, as illustrated in the example below. @code{state} must be either the string ``on'' or ``off'', for switching the given notification on or off. @end deffn The following example shows how to use callbacks for the simple purpose of playing a message and waiting until its end. (Please note that checks of return values in this example as well as other code not directly related to index marking, have been removed for the purpose of clarity.) @example #include sem_t semaphore; /* Callback for Speech Dispatcher notifications */ void end_of_speech(size_t msg_id, size_t client_id, SPDNotificationType type) @{ /* We don't check msg_id here since we will only send one message. */ /* Callbacks are running in a separate thread, so let the (sleeping) main thread know about the event and wake it up. */ sem_post(&semaphore); @} int main(int argc, char **argv) @{ SPDConnection *conn; sem_init(&semaphore, 0, 0); /* Open Speech Dispatcher connection in THREADED mode. */ conn = spd_open("say","main", NULL, SPD_MODE_THREADED); /* Set callback handler for 'end' and 'cancel' events. */ conn->callback_end = con->callback_cancel = end_of_speech; /* Ask Speech Dispatcher to notify us about these events. */ spd_set_notification_on(conn, SPD_END); spd_set_notification_on(conn, SPD_CANCEL); /* Say our message. */ spd_sayf(conn, SPD_MESSAGE, (char*) argv[1]); /* Wait for 'end' or 'cancel' of the sent message. By SSIP specifications, we are guaranteed to get one of these two eventually. */ sem_wait(&semaphore); return 0; @} @end example @node History Commands in C, Direct SSIP Communication in C, Event Notification and Index Marking in C, C API @subsection History Commands @findex spd_history_select_client() @findex spd_get_client_list() @findex spd_get_message_list_fd() @node Direct SSIP Communication in C, , History Commands in C, C API @subsection Direct SSIP Communication in C It might happen that you want to use some SSIP function that is not available through a library or you may want to use an available function in a different manner. (If you think there is something missing in a library or you have some useful comment on the available functions, please let us know.) For this purpose, there are a few functions that will allow you to send arbitrary SSIP commands on your connection and read the replies. @deffn {C API function} int spd_execute_command(SPDConnection* connection, char *command); @findex spd_execute_command() You can send an arbitrary SSIP command specified in the parameter @code{command}. If the command is successful, the function returns a 0. If there is no such command or the command failed for some reason, it returns -1. @code{connection} is the SPDConnection* connection created by spd_open(). @code{command} is a null terminated string containing a full SSIP command without the terminating sequence @code{\r\n}. For example: @example spd_execute_command(fd, "SET SELF RATE 60"); spd_execute_command(fd, "SOUND_ICON bell"); @end example It's not possible to use this function for compound commands like @code{SPEAK} where you are receiving more than one reply. If this is your case, please see `spd_send_data()'. @end deffn @deffn {C API function} char* spd_send_data(SPDConnection* connection, const char *message, int wfr); @findex spd_send_data() You can send an arbitrary SSIP string specified in the parameter @code{message} and, if specified, wait for the reply. The string can be any SSIP command, but it can also be textual data or a command parameter. If @code{wfr} (wait for reply) is set to SPD_WAIT_REPLY, you will receive the reply string as the return value. If wfr is set to SPD_NO_REPLY, the return value is a NULL pointer. If wfr is set to SPD_WAIT_REPLY, you should always free the returned string. @code{connection} is the SPDConnection* connection created by spd_open(). @code{message} is a null terminated string containing a full SSIP string. If this is a complete SSIP command, it must include the full terminating sequence @code{\r\n}. @code{wfr} is either SPD_WAIT_REPLY (integer value of 1) or SPD_NO_REPLY (0). This specifies if you expect to get a reply on the sent data according to SSIP. For example, if you are sending ordinary text inside a @code{SPEAK} command, you don't expect to get a reply, but you expect a reply after sending the final sequence @code{\r\n.\r\n}. For example (simplified by not checking and freeing the returned strings): @example spd_send_data(conn, "SPEAK", SPD_WAIT_REPLY); spd_send_data(conn, "Hello world!\n", SPD_NO_REPLY); spd_send_data(conn, "How are you today?!", SPD_NO_REPLY); spd_send_data(conn, "\r\n.\r\n.", SPD_WAIT_REPLY); @end example @end deffn @node Python API, Guile API, C API, Client Programming @section Python API There is a full Python API available in @file{src/python/speechd/} in the source tree. Please see the Python docstrings for full reference about the available objects and methods. Simple Python client: @example import speechd client = speechd.SSIPClient('test') client.set_output_module('festival') client.set_language('en') client.set_punctuation(speechd.PunctuationMode.SOME) client.speak("Hello World!") client.close() @end example The Python API respects the environment variables @var{SPEECHD_ADDRESS} it the communication address is not specified explicitly (see @code{SSIPClient} constructor arguments). Implementation of callbacks within the Python API tries to hide the low level details of SSIP callback handling and provide a convenient Pythonic interface. You just pass a callable object (function) to the @code{speak()} method and this function will be called whenever an event occurs for the corresponding message. Callback example: @example import speechd, time called = [] client = speechd.SSIPClient('callback-test') client.speak("Hi!", callback=lambda cb_type: called.append(cb_type)) time.sleep(2) # Wait for the events to happen. print "Called callbacks:", called client.close() @end example Real-world callback functions will most often need some sort of context information to be able to distinguish for which message the callback was called. This can be simply done in Python. The following example uses the actual message text as the context information within the callback function. Callback context example: @example import speechd, time class CallbackExample(object): def __init__(self): self._client = speechd.SSIPClient('callback-test') def speak(self, text): def callback(callback_type): if callback_type == speechd.CallbackType.BEGIN: print "Speech started:", text elif callback_type == speechd.CallbackType.END: print "Speech completed:", text elif callback_type == speechd.CallbackType.CANCEL: print "Speech interupted:", text self._client.speak(text, callback=callback, event_types=(speechd.CallbackType.BEGIN, speechd.CallbackType.CANCEL, speechd.CallbackType.END)) def go(self): self.speak("Hi!") self.speak("How are you?") time.sleep(4) # Wait for the events to happen. self._client.close() CallbackExample().go() @end example @emph{Important notice:} The callback is called in Speech Dispatcher listener thread. No subsequent Speech Dispatcher interaction is allowed from within the callback invocation. If you need to do something more complicated, do it in another thread to prevent deadlocks in SSIP communication. @node Guile API, Common Lisp API, Python API, Client Programming @section Guile API The Guile API can be found @file{src/guile/} in the source tree, however it's still considered to be at the experimental stage. Please read @file{src/guile/README}. @node Common Lisp API, Autospawning, Guile API, Client Programming @section Common Lisp API The Common Lisp API can be found @file{src/cl/} in the source tree, however it's still considered to be at the experimental stage. Please read @file{src/cl/README}. @node Autospawning, , Common Lisp API, Client Programming @section Autospawning It is suggested that client libraries offer an autospawn functionality to automatically start the server process when connecting locally and if it is not already running. E.g. if the client application starts and Speech Dispatcher is not running already, the client will start Speech Dispatcher. The library API should provide a possibility to turn this functionality off, but we suggest to set the default behavior to autospawn. Autospawn is performed by executing Speech Dispatcher with the --spawn parameter under the same user and permissions as the client process: @example speech-dispatcher --spawn @end example With the @code{--spawn} parameter, the process will start and return with an exit code of 0 only if a) it is not already running (pidfile check) b) the server doesn't have autospawn disabled in its configuration c) no other error preventing the start occurs. Otherwise, Speech Dispatcher is not started and the error code of 1 is returned. The client library should redirect its stdout and stderr outputs either to nowhere or to its logging system. It should subsequently completely detach from the newly spawned process. Due to a bug in Speech Dispatcher, it is currently necessary to include a wait statement after the autospawn for about 0.5 seconds before attempting a connection. Please see how autospawn is implemented in the C API and in the Python API for an example. @node Server Programming, Download and Contact, Client Programming, Top @chapter Server Programming @menu * Server Core:: Internal structure and functionality overview. * Output Modules:: Plugins for various speech synthesizers. @end menu @node Server Core, Output Modules, Server Programming, Server Programming @section Server Core The main documentation for the server core is the code itself. This section is only a general introduction intended to give you some basic information and hints where to look for things. If you are going to make some modifications in the server core, we will be happy if you get in touch with us on @email{speechd-discuss@@nongnu.org}. The server core is composed of two main parts, each of them implemented in a separate thread. The @emph{server part} handles the communication with clients and, with the desired configuration options, stores the messages in the priority queue. The @emph{speaking part} takes care of communicating with the output modules, pulls messages out of the priority queue at the correct time and sends them to the appropriate synthesizer. Synchronization between these two parts is done by thread mutexes. Additionally, synchronization of the speaking part from both sides (server part, output modules) is done via a SYSV/IPC semaphore. @subheading Server part After switching to the daemon mode (if required), it reads configuration files and initializes the speaking part. Then it opens the socket and waits for incoming data. This is implemented mainly in @file{src/server/speechd.c} and @file{src/server/server.c}. There are three types of events: new client connects to speechd, old client disconnects, or a client sends some data. In the third case, the data is passed to the @code{parse()} function defined in @file{src/server/parse.c}. If the incoming data is a new message, it's stored in a queue according to its priority. If it is SSIP commands, it's handled by the appropriate handlers. Handling of the @code{SET} family of commands can be found in @file{src/server/set.c} and @code{HISTORY} commands are processed in @file{src/server/history.c}. All reply messages of SSIP are defined in @file{src/server/msg.h}. @subheading Speaking part This thread, the function @code{speak()} defined in @file{src/server/speaking.c}, is created from the server part process shortly after initialization. Then it enters an infinite loop and waits on a SYSV/IPC semaphore until one of the following actions happen: @itemize @bullet @item The server adds a new message to the queue of messages waiting to be said. @item The currently active output module signals that the message that was being spoken is done. @item Pause or resume is requested. @end itemize After handling the rest of the priority interaction (like actions needed to repeat the last priority progress message) it decides which action should be performed. Usually it's picking up a message from the queue and sending it to the desired output module (synthesizer), but sometimes it's handling the pause or resume requests, and sometimes it's doing nothing. As said before, this is the part of Speech Dispatcher that talks to the output modules. It does so by using the output interface defined in @file{src/server/output.c}. @node Output Modules, , Server Core, Server Programming @section Output Modules @menu * Basic Structure:: The definition of an output module. * Communication Protocol for Output Modules:: * How to Write New Output Module:: How to include support for new synthesizers * The Skeleton of an Output Module:: * Output Module Functions:: * Module Utils Functions and Macros:: * Index Marks in Output Modules:: @end menu @node Basic Structure, Communication Protocol for Output Modules, Output Modules, Output Modules @subsection Basic Structure Speech Dispatcher output modules are independent applications that, using a simple common communication protocol, read commands from standard input and then output replies on standard output, communicating the requests to the particular software or hardware synthesizer. Everything the output module writes on standard output or reads from standard input should conform to the specifications of the communication protocol. Additionally, standard error output is used for logging of the modules. Output module binaries are usually located in @file{bin/speechd-modules/} and are loaded automatically when Speech Dispatcher starts, according to configuration. Their standard input/output/error output is redirected to a pipe to Speech Dispatcher and this way both sides can communicate. When the modules start, they are passed the name of a configuration file that should be used for this particular output module. Each output module is started by Speech Dispatcher as: @example my_module "configfile" @end example where @code{configfile} is the full path to the desired configuration file that the output module should parse. @node Communication Protocol for Output Modules, How to Write New Output Module, Basic Structure, Output Modules @subsection Communication Protocol for Output Modules The protocol by which the output modules communicate on standard input/output is based on @ref{Top,,SSIP,ssip, SSIP Documentation}, although it is highly simplified and a little bit modified for the different purpose here. Another difference is that event notification is obligatory in modules communication, while in SSIP, this is an optional feature. This is because Speech Dispatcher has to know all the events happening in the output modules for the purpose of synchronization of various messages. Since it's very similar to SSIP, @ref{Top,,General Rules,ssip, SSIP Documentation}, for a general description of what the protocol looks like. One of the exceptions is that since the output modules communicate on standard input/output, we use only @code{LF} as the line separator. The return values are: @itemize @item 2xx OK @item 3xx CLIENT ERROR or BAD SYNTAX or INVALID VALUE @item 4xx OUTPUT MODULE ERROR or INTERNAL ERROR @item 700 EVENT INDEX MARK @item 701 EVENT BEGIN @item 702 EVENT END @item 703 EVENT STOP @item 704 EVENT PAUSE @end itemize @table @code @item SPEAK Start receiving a text message in the SSML format and synthesize it. After sending a reply to the command, output module waits for the text of the message. The text can spread over any number of lines and is finished by an end of line marker followed by the line containing the single character @code{.} (dot). Thus the complete character sequence closing the input text is @code{LF . LF}. If any line within the sent text contains only a dot, an extra dot should be prepended before it. During reception of the text message, output module doesn't send a response to the particular lines sent. The response line is sent only immediately after the @code{SPEAK} command and after receiving the closing dot line. This doesn't provide any means of synchronization, instead, event notification is used for this purpose. There is no explicit upper limit on the size of the text. If the @code{SPEAK} command is received while the output module is already speaking, it is considered an error. Example: @example SPEAK 202 OK SEND DATA Hello, GNU! . 200 OK SPEAKING @end example After receiving the full text (or the first part of it), the output module is supposed to start synthesizing it and take care of delivering it to an audio device. When (or just before) the first synthesized samples are delivered to the audio and start playing, the output module must send the @code{BEGIN} event over the communication socket to Speech Dispatcher, @xref{Events notification and index marking}. After the audio stops playing, the event @code{STOP}, @code{PAUSE} or @code{END} must be delivered to Speech Dispatcher. Additionally, if supported by the given synthesizer, the output module can issue events associated with the included SSML index marks when they are reached in the audio output. @item CHAR Synthesize a character. If the synthesizer supports a different behavior for the event of ``character'', this should be used. It works like the command @code{SPEAK} above, except that the argument has to be exactly one line long. It contains the UTF-8 form of exactly one character. @item KEY Synthesize a key name. If the synthesizer supports a different behavior for the event of ``key name'', this should be used. It works like the command @code{SPEAK} above, except that the argument has to be exactly one line long. @xref{Top, ,SSIP KEY,ssip, SSIP Documentation}, for the description of the allowed arguments. @item SOUND_ICON Produce a sound icon. According to the configuration of the particular synthesizer, this can produce either a sound (e.g. .wav) or synthesize some text. It works like the command @code{SPEAK} above, except that the argument has to be exactly one line long. It contains the symbolic name of the icon that should be said. @xref{Top,,SSIP SOUND_ICON, ssip, SSIP Documentation}, for more detailed description of the sound icons mechanism. @item STOP Immediately stop speaking on the output device and cancel synthesizing the current message so that the output module is prepared to receive a new message. If there is currently no message being synthesized, it is not considered an error to call @code{STOP} anyway. This command is asynchronous. The output module is not supposed to send any reply (not even error reply). It should return immediately, although stopping the synthesizer may require a little bit more time. The module must issue one of the events @code{STOPPED} or @code{END} when the module is finally stopped. @code{END} is issued when the playing stopped by itself before the module could terminate it or if the architecture of the output module doesn't allow it to decide, otherwise @code{STOPPED} should be used. @example STOP @end example @item PAUSE Stop speaking the current message at a place where we can exactly determine the position (preferably after a @code{__spd_} index mark). This doesn't have to be immediate and can be delayed even for a few seconds. (Knowing the position exactly is important so that we can later continue the message without gaps or overlapping.) It doesn't do anything else (like storing the message etc.). This command is asynchronous. The output module is not supposed to send any reply (not even error reply). For example: @example PAUSE @end example @item SET Set one of several speech parameters for the future messages. Each of the parameters is written on a single line in the form @example name=value @end example where @code{value} can be either a number or a string, depending upon the name of the parameter. The @code{SET} environment is terminated by a dot on a single line. Thus the complete character sequence closing the input text is @code{LF . LF} During reception of the settings, output module doesn't send any response to the particular lines sent. The response line is sent only immediately after the @code{SET} command and after receiving the closing dot line. The available parameters that accept numerical values are @code{rate}, @code{pitch} and @code{pitch_range}. The available parameters that accept string values are @code{punctuation_mode}, @code{spelling_mode}, @code{cap_let_recogn}, @code{voice}, and @code{language}. The arguments are the same as for the corresponding SSIP commands, except that they are written with small letters. @xref{Top,,Parameter Setting Commands,ssip, SSIP Documentation}. The conversion between these string values and the corresponding C enum variables can be easily done using @file{src/common/fdsetconv.c}. Not all of these parameters must be set and the value of the string arguments can also be @code{NULL}. If some of the parameters aren't set, the output module should use its default. It's not necessary to set these parameters on the synthesizer right away, instead, it can be postponed until some message to be spoken arrives. Here is an example: @example SET 203 OK RECEIVING SETTINGS rate=20 pitch=-10 pitch_range=50 punctuation_mode=all spelling_mode=on punctuation_some=NULL . 203 OK SETTINGS RECEIVED @end example @item AUDIO Audio has exactly the same structure as @code{SET}, but is transmitted only once immediatelly after @code{INIT} to transmit the requested audio parameters and tell the output module to open the audio device. @item QUIT Terminates the output module. It should send the response, deallocate all the resources, close all descriptors, terminate all child processes etc. Then the output module should exit itself. @example QUIT 210 OK QUIT @end example @end table @subsubsection Events notification and index marking @anchor{Events notification and index marking} Each output module must take care of sending asynchronous notifications whenever the synthesizer (or the module) starts or stops output audio on the speakers. Additionally, whenever possible, the output module should report back to Speech Dispatcher index marks found in the incoming SSML text whenever they are reached while speaking. See SSML specifications for more details about the @code{mark} element Event and index mark notifications are reported by simply writing them to the standard output. An event notification must never get in between synchronous commands (those which require a reply) and their reply. Before Speech Dispatcher sends any new requests (like @code{SET}, @code{SPEAK} etc.) it waits for the previous request to be terminated by the output module by signalling @code{STOP}, @code{END} or @code{PAUSE} index marks. So the only thing the output module must ensure in order to satisfy this requirement is that it doesn't send any index marks until it acknowledges the receival of the new message via @code{200 OK SPEAKING}. It must also ensure that index marks written to the pipe are well ordered -- of course it doesn't make any sense and it is an error to send any index marks after @code{STOP}, @code{END} or @code{PAUSE} is sent. @table @code @item BEGIN This event must be issued whenever the module starts to speak the given message. If this is not possible, it can issue it when it starts to synthesize the message or when it receives the message. It is prepended by the code @code{701} and takes the form @example 701 BEGIN @end example @item END This event must be issued whenever the module terminates speaking the given message because it reached its end. If this is not possible, it can issue this event when it is ready to receive a new message after speaking the previous message. Each @code{END} must always be preceeded (possibly not directly) by a @code{BEGIN}. It is prepended by the code @code{702} and takes the form @example 702 END @end example @item STOP This event should be issued whenever the module terminates speaking the given message without reaching its end (as a consequence of receiving the STOP command or because of some error) not because of a @code{PAUSE} command. When the synthesizer in use doesn't allow the module to decide, the event @code{END} can be used instead. Each @code{STOP} must always be preceeded (possibly not directly) by a @code{BEGIN}. It is prepended by the code @code{703} and takes the form @example 703 STOP @end example @item PAUSE This event should be issued whenever the module terminates speaking the given message without reaching its end because of receiving the @code{PAUSE} command. Each @code{PAUSE} must always be preceeded (possibly not directly) by a @code{BEGIN}. It is prepended by the code @code{704} and takes the form @example 704 PAUSE @end example @item INDEX MARK This event should be issued by the output module (if supported) whenever an index mark (SSML tag @code{}) is passed while speaking a message. It is preceeded by the code @code{700} and takes the form @example 700-name 700 INDEX MARK @end example where @code{name} is the value of the SSML attribute @code{name} in the tag @code{}. @end table @node How to Write New Output Module, The Skeleton of an Output Module, Communication Protocol for Output Modules, Output Modules @subsection How to Write New Output Module If you want to write your own output module, there are basically two ways to do it. Either you can program it all yourself, which is fine as long as you stick to the definition of an output module and its communication protocol, or you can use our @file{module_*.c} tools. If you use these tools, you will only have to write the core functions like module_speak() and module_stop etc. and you will not have to worry about the communication protocol and other formal things that are common for all modules. Here is how you can do it using the provided tools. We will recommend here a basic structure of the code for an output module you should follow, although it's perfectly ok to establish your own if you have reasons to do so, if all the necessary functions and data are defined somewhere in the file. For this purpose, we will use examples from the output module for Flite (Festival Lite), so it's recommended to keep looking at @code{flite.c} for reference. A few rules you should respect: @itemize @item The @file{module_*.c} files should be included at the specified place and in the specified order, because they include directly some pieces of the code and won't work in other places. @item If one or more new threads are used in the output module, they must block all signals. @item On module_close(), all lateral threads and processes should be terminated, all memory freed. Don't assume module_close() is always called before exit() and the sources will be freed automatically. @item We will be happy if all the copyrights are assigned to Brailcom, o.p.s. in order for us to be in a better legal position against possible intruders. @end itemize @node The Skeleton of an Output Module, Output Module Functions, How to Write New Output Module, Output Modules @subsection The Skeleton of an Output Module Each output module should include @file{module_utils.h} where the SPDMsgSettings structure is defined to be able to handle the different speech synthesis settings. This file also provides tools which help with writing output modules and making the code simpler. @example #include "module_utils.h" @end example If your plugin needs the audio tools (if you take care of the output to the soundcard instead of the synthesizer), you also have to include @file{spd_audio.h} @example #include "spd_audio.h" @end example The definition of macros @code{MODULE_NAME} and @code{MODULE_VERSION} should follow: @example #define MODULE_NAME "flite" #define MODULE_VERSION "0.1" @end example If you want to use the @code{DBG(message)} macro from @file{module_utils.c} to print out debugging messages, you should insert these two lines. (Please don't use printf for debugging, this doesn't work with multiple processes!) (You will later have to actually start debugging in @code{module_init()}) @example DECLARE_DEBUG(); @end example You don't have to define the prototypes of the core functions like module_speak() and module_stop(), these are already defined in @file{module_utils.h} Optionally, if your output module requires some special configuration, apart from defining voices and configuring debugging (they are handled differently, see below), you can declare the requested option here. It will expand into a dotconf callback and declaration of the variable. (You will later have to actually register these options for Speech Dispatcher in @code{module_load()}) There are currently 4 types of possible configuration options: @itemize @item @code{MOD_OPTION_1_INT(name); /* Set up `int name' */} @item @code{MOD_OPTION_1_STR(name); /* Set up `char* name' */} @item @code{MOD_OPTION_2(name); /* Set up `char *name[2]' */} @item @code{MOD_OPTION_@{2,3@}_HT(name); /* Set up a hash table */} @end itemize @xref{Output Modules Configuration}. For example Flite uses 2 options: @example MOD_OPTION_1_INT(FliteMaxChunkLength); MOD_OPTION_1_STR(FliteDelimiters); @end example Every output module is started in 2 phases: @emph{loading} and @emph{initialization}. The goal of loading is to initialize empty structures for storing settings and declare the DotConf callbacks for parsing configuration files. In the second phase, initialization, all the configuration has been read and the output module can accomplish the rest (check if the synthesizer works, set up threads etc.). You should start with the definition of @code{module_load()}. @example int module_load(void) @{ @end example Then you should initialize the settings tables. These are defined in @file{module_utils.h} and will be used to store the settings received by the @code{SET} command. @example INIT_SETTINGS_TABLES(); @end example Also, define the configuration callbacks for debugging if you use the @code{DBG()} macro. @example REGISTER_DEBUG(); @end example Now you can finally register the options for the configuration file parsing. Just use these macros: @itemize @item MOD_OPTION_1_INT_REG(name, default); /* for integer parameters */ @item MOD_OPTION_1_STR_REG(name, default); /* for string parameters */ @item MOD_OPTION_MORE_REG(name); /* for an array of strings */ @item MOD_OPTION_HT_REG(name); /* for hash tables */ @end itemize Again, an example from Flite: @example MOD_OPTION_1_INT_REG(FliteMaxChunkLength, 300); MOD_OPTION_1_STR_REG(FliteDelimiters, "."); @end example If you want to enable the mechanism for setting voices through AddVoice, use this function (for an example see @code{generic.c}): Example from Festival: @example module_register_settings_voices(); @end example @xref{Output Modules Configuration}. If everything went correctly, the function should return 0, otherwise -1. @example return 0; @} @end example The second phase of starting an output module is handled by: @example int module_init(void) @{ @end example If you use the DBG() macro, you should init debugging on the start of this function. From that moment on, you can use DBG(). Apart from that, the body of this function is entirely up to you. You should do all the necessary initialization of the particular synthesizer. All declared configuration variables and configuration hash tables, together with the definition of voices, are filled with their values (either default or read from configuration), so you can use them already. @example INIT_DEBUG(); DBG("FliteMaxChunkLength = %d\n", FliteMaxChunkLength); DBG("FliteDelimiters = %s\n", FliteDelimiters); @end example This function should return 0 if the module was initialized successfully, or -1 if some failure was encountered. In this case, you should clean up everything, cancel threads, deallocate memory etc.; no more functions of this output module will be touched (except for other tries to load and initialize the module). Example from Flite: @example /* Init flite and register a new voice */ flite_init(); flite_voice = register_cmu_us_kal(); if (flite_voice == NULL)@{ DBG("Couldn't register the basic kal voice.\n"); return -1; @} [...] @end example The third part is opening the audio. This is commanded by the @code{AUDIO} protocol command. If the synthesizer is able to retrieve audio data, it is desirable to open the @code{spd_audio} output according to the requested parameters and then use this method for audio output. Audio initialization can be done as follows: @example int module_audio_init(char **status_info)@{ DBG("Opening audio"); return module_audio_init_spd(status_info); @} @end example If it is impossible to retrieve audio from the synthesizer and the synthesizer itself is used for playback, than the module must still contain this function, but it should just return 0 and do nothing. Now you have to define all the synthesis control functions @code{module_speak}, @code{module_stop} etc. See @ref{Output Module Functions}. At the end, this simple include provides the main() function and all the functionality related to being an output module of Speech Dispatcher (parsing argv[] parameters, communicating on stdin/stdout, ...). It's recommended to study this file carefully and try to understand what exactly it does, as it will be part of the source code of your output module. @example #include "module_main.c" @end example If it doesn't work, it's most likely not your fault. Complain! This manual is not complete and the instructions in this sections aren't either. Get in touch with us and together we can figure out what's wrong, fix it and then warn others in this manual. @node Output Module Functions, Module Utils Functions and Macros, The Skeleton of an Output Module, Output Modules @subsection Output Module Functions @deffn {Output Module Functions} int module_speak (char *data, size_t bytes, EMessageType msgtype) @findex module_speak() This is the function where the actual speech output is produced. It is called every time Speech Dispatcher decides to send a message to synthesis. The data of length @var{bytes} are passed in a NULL terminated string @var{data}. The argument @var{msgtype} defines what type of message it is (different types should be handled differently, if the synthesizer supports it). Each output module should take care of setting the output device to the parameters from msg_settings (defined in module_utils.h) (See SPDMsgSettings in @file{module_utils.h}). However, it is not an error if some of these values are ignored. At least rate, pitch and language should be set correctly. Speed and pitch are values between -100 and 100 included. 0 is the default value that represents normal speech flow. So -100 is the slowest (or lowest) and +100 is the fastest (or highest) speech. The language parameter is given as a null-terminated string containing the name of the language according to RFC 1766 (en, cs, fr, ...). If the requested language is not supported by this synthesizer, it's ok to abort and return 0, because that's an error in user settings. An easy way to set the parameters is using the UPDATE_PARAMETER() and UPDATE_STRING_PARAMETER() macros. @xref{Module Utils Functions and Macros}. Example from festival: @example UPDATE_STRING_PARAMETER(language, festival_set_language); UPDATE_PARAMETER(voice, festival_set_voice); UPDATE_PARAMETER(rate, festival_set_rate); UPDATE_PARAMETER(pitch, festival_set_pitch); UPDATE_PARAMETER(punctuation_mode, festival_set_punctuation_mode); UPDATE_PARAMETER(cap_let_recogn, festival_set_cap_let_recogn); @end example This function should return 0 if it fails and 1 if the delivery to the synthesizer is successful. It should return immediately, because otherwise, it would block stopping, priority handling and other important things in Speech Dispatcher. If there is a need to stay longer, you should create a separate thread or process. This is for example the case of some software synthesizers which use a blocking function (eg. spd_audio_play) or hardware devices that have to send data to output modules at some particular speed. Note that if you use threads for this purpose, you have to set them to ignore all signals. The simplest way to do this is to call @code{set_speaking_thread_parameters()} which is defined in module_utils.c. Call it at the beginning of the thread code. @end deffn @deffn {Output module function} {int module_stop} (void) @findex module_stop() This function should stop the synthesis of the currently spoken message immediately and throw away the rest of the message. This function should return immediately. Speech Dispatcher will not send another command until module_report_event_stop() is called. Note that you cannot call module_report_event_stop() from within the call to module_stop(). The best thing to do is emit the stop event from another thread. It should return 0 on success, -1 otherwise. @end deffn @deffn {Output module function} {size_t module_pause} (void) @findex module_pause() This function should stop speaking on the synthesizer (or sending data to soundcard) just after sending an @code{__spd_} index mark so that Speech Dispatcher knows the position of stop. The pause can wait for a short time until an index mark is reached. However, if it's not possible to determine the exact position, this function should have the same effect as @code{module_stop}. This function should return immediately. Speech Dispatcher will not send another command until module_report_event_pause() is called. Note that you cannot call module_report_event_pause() from within the call to module_pause(). The best thing to do is emit the pause event from another thread. For some software synthesizers, the desired effect can be archieved in this way: When @code{module_speak()} is called, you execute a separate process and pass it the requested message. This process cuts the message into sentences and then runs in a loop and sends the pieces to synthesis. If a signal arrives from @code{module_pause()}, you set a flag and stop the loop at the point where next piece of text would be synthesized. It's not an error if this function is called when the device is not speaking. In this case, it should return 0. Note there is no module_resume() function. The semantics of @code{module_pause()} is the same as @code{module_stop()} except that your module should stop after reaching a @code{__spd_} index mark. Just like @code{module_stop()}, it should discard the rest of the message after pausing. On the next @code{module_speak()} call, Speech Dispatcher will resend the rest of the message after the index mark. @end deffn @node Module Utils Functions and Macros, Index Marks in Output Modules, Output Module Functions, Output Modules @subsection Module Utils Functions and Macros This section describes the various variables, functions and macros that are available in the @file{module_utils.h} file. They are intended to make writing new output modules easier and allow the programmer to reuse existing pieces of code instead of writing everything from scratch. @menu * Initialization Macros and Functions:: * Generic Macros and Functions:: * Functions used by module_main.c:: * Functions for use when talking to synthesizer:: * Multi-process output modules:: * Memory Handling Functions:: @end menu @node Initialization Macros and Functions, Generic Macros and Functions, Module Utils Functions and Macros, Module Utils Functions and Macros @subsubsection Initialization Macros and Functions @deffn {Module Utils macro} INIT_SETTINGS_TABLES () @findex INIT_SETTINGS_TABLES This macro initializes the settings tables where the parameters received with the @code{SET} command are stored. You must call this macro if you want to use the @code{UPDATE_PARAMETER()} and @code{UPDATE_STRING_PARAMETER()} macros. It is intended to be called from inside a function just after the output module starts. @end deffn @subsubsection Debugging Macros @deffn {Module Utils macro} DBG (format, ...) @findex DBG DBG() outputs a debugging message, if the @code{Debug} option in module's configuration is set, to the file specified in configuration ad @code{DebugFile}. The parameter syntax is the same as for the printf() function. In fact, it calls printf() internally. @end deffn @deffn {Module Utils macro} FATAL (text) @findex FATAL Outputs a message specified as @code{text} and calls exit() with the value EXIT_FAILURE. This terminates the whole output module without trying to kill the child processes or freeing other resources other than those that will be freed by the system. It is intended to be used after some severe error has occurred. @end deffn @node Generic Macros and Functions, Functions used by module_main.c, Initialization Macros and Functions, Module Utils Functions and Macros @subsubsection Generic Macros and Functions @deffn {Module Utils macro} UPDATE_PARAMETER (param, setter) @findex UPDATE_PARAMETER Tests if the integer or enum parameter specified in @code{param} (e.g. rate, pitch, cap_let_recogn, ...) changed since the last time when the @code{setter} function was called. If it changed, it calls the function @code{setter} with the new value. (The new value is stored in the msg_settings structure that is created by module_utils.h, which you normally don't have to care about.) The function @code{setter} should be defined as: @example void setter_name(type value); @end example Please look at the @code{SET} command in the communication protocol for the list of all available parameters. @pxref{Communication Protocol for Output Modules}. An example from Festival output module: @verbatim static void festival_set_rate(signed int rate) { assert(rate >= -100 && rate <= +100); festivalSetRate(festival_info, rate); } [...] int module_speak(char *data, size_t bytes, EMessageType msgtype) { [...] UPDATE_PARAMETER(rate, festival_set_rate); UPDATE_PARAMETER(pitch, festival_set_pitch); [...] } @end verbatim @end deffn @deffn {Module Utils macro} UPDATE_STRING_PARAMETER (param, setter) @findex UPDATE_STRING_PARAMETER The same as @code{UPDATE_PARAMETER} except that it works for parameters with a string value. @end deffn @node Functions used by module_main.c, Functions for use when talking to synthesizer, Generic Macros and Functions, Module Utils Functions and Macros @subsubsection Functions used by @file{module_main.c} @deffn {Module Utils function} char* do_speak(void) @findex do_speak Takes care of communication after the @code{SPEAK} command was received. Calls @code{module_speak()} when the full text is received. It returns a response according to the communication protocol. @end deffn @deffn {Module Utils function} char* do_stop(void) @findex do_stop Calls the @code{module_stop()} function of the particular output module. It returns a response according to the communication protocol. @end deffn @deffn {Module Utils function} char* do_pause(void) @findex do_pause Calls the @code{module_pause()} function of the particular output module. It returns a response according to the communication protocol and the value returned by @code{module_pause()}. @end deffn @deffn {Module Utils function} char* do_set() @findex do_set Takes care of communication after the @code{SET} command was received. Doesn't call any particular function of the output module, only sets the values in the settings tables. (You should then call the @code{UPDATE_PARAMETER()} macro in module_speak() to actually set the synthesizer to these values.) It returns a response according to the communication protocol. @end deffn @deffn {Module Utils function} char* do_speaking() @findex do_speaking Calls the @code{module_speaking()} function. It returns a response according to the communication protocol and the value returned by @code{module_speaking()}. @end deffn @deffn {Module Utils function} void do_quit() @findex do_quit Prints the farewell message to the standard output, according to the protocol. Then it calls @code{module_close()}. @end deffn @node Functions for use when talking to synthesizer, Multi-process output modules, Functions used by module_main.c, Module Utils Functions and Macros @subsubsection Functions for use when talking to synthesizer @deffn {Module Utils function} static int module_get_message_part ( const char* message, char* part, unsigned int *pos, size_t maxlen, const char* dividers) @findex module_get_message_part Gets a part of the @code{message} according to the specified @code{dividers}. It scans the text in @code{message} from the byte specified by @code{*pos} and looks for one of the characters specified in @code{dividers} followed by a whitespace character or the terminating NULL byte. If one of them is encountered, the read text is stored in @code{part} and the number of bytes read is returned. If end of @code{message} is reached, the return value is -1. @code{message} is the text to process. It must be a NULL-terminated uni-byte string. @code{part} is a pointer to the place where the output text should be stored. It must contain at least @code{maxlen} bytes of space. @code{maxlen} is the maximum number of bytes that should be written to @code{part}. @code{dividers} is a NULL-terminated uni-byte string containing the punctuation characters where the message should be divided into smaller parts (if they are followed by whitespace). After returning, @code{pos} is the position where the function terminated in processing @code{message}. @end deffn @deffn {Output module function} void module_report_index_mark(char *mark) @findex module_report_index_mark @end deffn @deffn {Output module function} void module_report_event_*() @findex module_report_event_* The @code{module_report_} functions serve for reporting event notifications and index marking events. You should use them whenever you get an event from the synthesizer which is defined in the output module communication protocol. Note that you cannot call these functions from within a call to module_speak(), module_stop(), or module_pause(). The best way to do this is to emit the events from another thread. @end deffn @deffn {Output module function} int module_close(void) @findex module_close This function is called when Speech Dispatcher terminates. The output module should terminate all threads and processes, free all resources, close all sockets etc. Never assume this function is called only when Speech Dispatcher terminates and exit(0) will do the work for you. It's perfectly ok for Speech Dispatcher to load, unload or reload output modules in the middle of its run. @end deffn @node Multi-process output modules, Memory Handling Functions, Functions for use when talking to synthesizer, Module Utils Functions and Macros @subsubsection Multi-process output modules @deffn {Module Utils function} size_t module_parent_wfork ( TModuleDoublePipe dpipe, const char* message, SPDMessageType msgtype, const size_t maxlen, const char* dividers, int *pause_requested) @findex module_parent_wfork It simply sends the data to the child in smaller pieces and waits for confirmation with a single @code{C} character on the pipe from child to parent. @code{dpipe} is a parameter which contains the information necessary for communicating through pipes between the parent and the child and vice-versa. @example typedef struct@{ int pc[2]; /* Parent to child pipe */ int cp[2]; /* Child to parent pipe */ @}TModuleDoublePipe; @end example @code{message} is a pointer to a NULL-terminated string containing the message for synthesis. @code{msgtype} is the type of the message for synthesis. @code{maxlen} is the maximum number of bytes that should be transfered over the pipe. @code{dividers} is a NULL-terminated string containing the punctuation characters at which this function should divide the message into smaller pieces. @code{pause_requested} is a pointer to an integer flag, which is either 0 if no pause request is pending, or 1 if the function should terminate at a convenient place in the message because a pause is requested. In the beginning, it initializes the pipes and then it enters a simple cycle: @enumerate @item Reads a part of the message or an index mark using @code{module_get_message_part()}. @item Looks if there isn't a pending request for pause and handles it. @item Sends the current part of the message to the child using @code{module_parent_dp_write()}. @item Waits until a single character @code{C} comes from the other pipe using @code{module_parent_dp_read()}. @item Repeats the cycle or terminates, if there is no more data. @end enumerate @end deffn @deffn {Module Utils function} int module_parent_wait_continue(TModuleDoublePipe dpipe) @findex module_parent_wait_continue Waits until the character @code{C} (continue) is read from the pipe from child. This function is intended to be run from the parent. @code{dpipe} is the double pipe used for communication between the child and parent. Returns 0 if the character was read or 1 if the pipe was broken before the character could be read. @end deffn @deffn {Module Utils function} void module_parent_dp_init (TModuleDoublePipe dpipe) @findex module_parent_dp_init Initializes pipes (dpipe) in the parent. Currently it only closes the unnecessary ends. @end deffn @deffn {Module Utils function} void module_child_dp_close (TModuleDoublePipe dpipe) @findex module_child_dp_init Initializes pipes (dpipe) in the child. Currently it only closes the unnecessary ends. @end deffn @deffn {Module Utils function} void module_child_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes) @findex module_child_dp_write Writes the specified number of @code{bytes} from @code{msg} to the pipe to the parent. This function is intended, as the prefix says, to be run from the child. Uses the pipes defined in @code{dpipe}. @end deffn @deffn {Module Utils function} void module_parent_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes) @findex module_parent_dp_write Writes the specified number of @code{bytes} from @code{msg} into the pipe to the child. This function is intended, as the prefix says, to be run from the parent. Uses the pipes defined in @code{dpipe}. @end deffn @deffn {Module Utils function} int module_child_dp_read(TModuleDoublePipe dpipe char *msg, size_t maxlen) @findex module_child_dp_read Reads up to @code{maxlen} bytes from the pipe from parent into the buffer @code{msg}. This function is intended, as the prefix says, to be run from the child. Uses the pipes defined in @code{dpipe}. @end deffn @deffn {Module Utils function} int module_parent_dp_read(TModuleDoublePipe dpipe, char *msg, size_t maxlen) @findex module_parent_dp_read Reads up to @code{maxlen} bytes from the pipe from child into the buffer @code{msg}. This function is intended, as the prefix says, to be run from the parent. Uses the pipes defined in @code{dpipe}. @end deffn @deffn {Module Utils function} void module_sigblockall(void) @findex module_sigblockall Blocks all signals. This is intended to be run from the child processes and threads so that their signal handling won't interfere with the parent. @end deffn @deffn {Module Utils function} void module_sigunblockusr(sigset_t *some_signals) @findex module_sigunblockusr Use the set @code{some_signals} to unblock SIGUSR1. @end deffn @deffn {Module Utils function} void module_sigblockusr(sigset_t *some_signals) @findex module_sigblockusr Use the set @code{some_signals} to block SIGUSR1. @end deffn @node Memory Handling Functions, , Multi-process output modules, Module Utils Functions and Macros @subsubsection Memory Handling Functions @deffn {Module Utils function} static void* xmalloc (size_t size) @findex xmalloc The same as the classical @code{malloc()} except that it executes @code{FATAL(``Not enough memory'')} on error. @end deffn @deffn {Module Utils function} static void* xrealloc (void *data, size_t size) @findex xrealloc The same as the classical @code{realloc()} except that it also accepts @code{NULL} as @code{data}. In this case, it behaves as @code{xmalloc}. @end deffn @deffn {Module Utils function} void xfree(void *data) @findex xfree The same as the classical @code{free()} except that it checks if data isn't NULL before calling @code{free()}. @end deffn @node Index Marks in Output Modules, , Module Utils Functions and Macros, Output Modules @subsection Index Marks in Output Modules Output modules need to provide some kind of synchronization and they have to give Speech Dispatcher back some information about what part of the message is currently being said. On the other hand, output modules are not able to tell the exact position in the text because various conversions and message processing take place (sometimes punctuation and spelling substitution, the message needs to be recoded from multibyte to unibyte coding etc.) before the text reaches the synthesizer. For this reason, Speech Dispatcher places so-called index marks in the text it sends to its output modules. They have the form: @example @end example @code{id} is the identifier associated with each index mark. Within a @code{module_speak()} message, each identifer is unique. It consists of the string @code{__spd_} and a counter number. Numbers begin from zero for each message. For example, the fourth index mark within a message looks like @example @end example When an index mark is reached, its identifier should be stored so that the output module is able to tell Speech Dispatcher the identifier of the last index mark. Also, index marks are the best place to stop when the module is requested to pause (although it's ok to stop at some place close by and report the last index mark). Notice that index marks are in SSML format using the @code{mark} tag. @node Download and Contact, Reporting Bugs, Server Programming, Top @chapter Download You can download Speech Dispatcher's latest release source code from @uref{http://www.freebsoft.org/speechd}. There is also information on how to set up anonymous access to our git repository. However, you may prefer to download Speech Dispatcher in a binary package for your system. We don't distribute such packages ourselves. If you run Debian GNU/Linux, it should be in the central repository under the name @code{speech-dispatcher} or @code{speechd}. If you run an rpm-based distribution like RedHat, Mandrake or SuSE Linux, please try to look at @uref{http://www.rpmfind.net/}. If you want to contact us, please look at @uref{http://www.freebsoft.org/contact} or use the email @email{users@@lists.freebsoft.org}. @node Reporting Bugs, How You Can Help, Download and Contact, Top @chapter Reporting Bugs If you believe you found a bug in Speech Dispatcher, we will be very grateful if you let us know about it. Please do it by email on the address @email{speechd@@bugs.freebsoft.org}, but please don't send us messages larger than half a megabyte unless we ask you. To report a bug in a way that is useful for the developers is not as easy as it may seem. Here are some hints that you should follow in order to give us the best information so that we can find and fix the bug easily. First of all, please try to describe the problem as exactly as you can. We prefer raw data over speculations about where the problem may lie. Please try to explain in what situation the bug happens. Even if it's a general bug that happens in many situations, please try to describe at least one case in as much detail, as possible. Also, please specify the versions of programs that you use when the bug happens. This is not only Speech Dispatcher, but also the client application you use (speechd-el, say, etc.) and the synthesizer name and version. If you can reproduce the bug, please send us the log file also. This is very useful, because otherwise, we may not be able to reproduce the bug with our configuration and program versions that differ from yours. Configuration must be set to logging priority at least 4, but best 5, so that it's useful for debugging purposes. You can do so in @file{etc/speech-dispatcher/speechd.conf} by modifying the variable @code{LogLevel}. Also, you may want to modify the log destination with variable @code{LogFile}. After modifying these options, please restart Speech Dispatcher and repeat the situation in which the bug happens. After it happened, please take the log and attach it to the bug report, preferably compressed using @code{gzip}. But note, that when logging with level 5, all the data that come from Speech Dispatcher is also recorded, so make sure there is no sensitive information when you are reproducing the bug. Please make sure you switch back to priority 3 or lower logging, because priority 4 or 5 produces really huge logs. If you are a programmer and you find a bug that is reproducible in SSIP, you can send us the sequence of SSIP commands that lead to the bug (preferably from starting the connection). You can also try to reproduce the bug in a simple test-script under @file{speech-dispatcher/src/tests} in the source tree. Please check @file{speech-dispatcher/src/tests/README} and see the other tests scripts there for an example. When the bug is a SEGMENTATION FAULT, a backtrace from gdb is also valuable, but if you are not familiar with gdb, don't bother with that, we may ask you to do it later. Finally, you may also send us a guess of what you think happens in Speech Dispatcher that causes the bug, but this is usually not very helpful. If you are able to provide additional technical information instead, please do so. @node How You Can Help, Appendices, Reporting Bugs, Top @chapter How You Can Help If you want to contribute to the development of Speech Dispatcher, we will be very happy if you do so. Please contact us on @email{users@@lists.freebsoft.org}. Here is a short, definitively not exhaustive, list of how you can help us and other users. @itemize @item @emph{Donate money:} We are a non-profit organization and we can't work without funding. Brailcom, o.p.s. created Speech Dispatcher, speechd-el and also works on other projects to help blind and visually impaired users of computers. We build on Free Software and GNU/Linux, because we believe this is the right way. But it won't be possible when we have no money. @uref{http://www.freebsoft.org/} @item @emph{Report bugs:} Every user, even if he can't give us money and he is not a programmer, can help us very much by just using our software and telling us about the bugs and inconveniences he encounters. A good user community that reports bugs is a crucial part of development of a good Free Software package. We can't test our software under all circumstances and on all platforms, so each constructive bug report is highly appreciated. You can report bugs in Speech Dispatcher on @email{speechd@@bugs.freebsoft.org}. @item @emph{Write or modify an application to support synthesis:} With Speech Dispatcher, we have provided an interface that allows applications easy access to speech synthesis. However powerful, it's no more than an interface, and it's useless on its own. Now it's time to write the particular client applications, or modify existing applications so that they can support speech synthesis. It is useful if the application needs a specific interface for blind people or if it wants to use speech synthesis for educational or other purposes. @item @emph{Develop new voices and language definitions for Festival:} In the world of Free Software, currently Festival is the most promising interface for Text-to-Speech processing and speech synthesis. It's an extensible and highly configurable platform for developing synthetic voices. If there is a lack of synthetic voices or no voices at all for some language, we believe the wisest solution is to try to develop a voice in Festival. It's certainly not advisable to develop your own synthesizer if the goal is producing a quality voice system in a reasonable time. Festival developers provide nice documentation about how to develop a voice and a lot of tools that help doing this. We found that some language definitions can be constructed by canibalizing the already existing definitions and can be tuned later. As for the voice samples, one can temporarily use the MBROLA project voices. But please note that, although they are downloadable for free (as price), they are not Free Software and it would be wonderful if we could replace them by Free Software alternatives as soon as possible. See @uref{http://www.cstr.ed.ac.uk/projects/festival/}. @item @emph{Help us with this or other Free-b-Soft projects:} Please look at @uref{http://www.freebsoft.org} to find information about our projects. There is a plenty of work to be done for the blind and visually impaired people to make their work with computers easier. @item @emph{Spread the word about Speech Dispatcher and Free Software:} You can help us, and the whole community around Free Software, just by telling your friends about the amazing world of Free Software. It doesn't have to be just about Speech Dispatcher; you can tell them about other projects or about Free Software in general. Remember that Speech Dispatcher could only arise out of understanding of some people of the principles and ideas behind Free Software. And this is mostly the same for the rest of the Free Software world. See @uref{http://www.gnu.org/} for more information about GNU/Linux and Free Software. @end itemize @node Appendices, GNU General Public License, How You Can Help, Top @appendix Appendices @node GNU General Public License, GNU Free Documentation License, Appendices, Top @appendix GNU General Public License @center Version 2, June 1991 @cindex GPL, GNU General Public License @include gpl.texi @node GNU Free Documentation License, Index of Concepts, GNU General Public License, Top @appendix GNU Free Documentation License @center Version 1.2, November 2002 @cindex FDL, GNU Free Documentation License @include fdl.texi @node Index of Concepts, , GNU Free Documentation License, Top @unnumbered Index of Concepts @cindex tail recursion @printindex cp @bye @c LocalWords: texinfo setfilename speechd settitle finalout syncodeindex pg @c LocalWords: setchapternewpage cp fn vr texi dircategory direntry titlepage @c LocalWords: Cerha Hynek Hanke vskip pt filll insertcopying ifnottex dir fd @c LocalWords: API SSIP cindex printf ISA pindex Flite Odmluva FreeTTS TTS CR @c LocalWords: ViaVoice Lite Tcl Zandt wxWindows AWT spd dfn backend findex @c LocalWords: src struct gchar gint const OutputModule intl FDSetElement len @c LocalWords: fdset init flite deffn TFDSetElement var int enum EVoiceType @c LocalWords: sayf ifinfo verbatiminclude ref UTF ccc ddd pxref LF cs conf @c LocalWords: su AddModule DefaultModule xref identd printindex Dectalk GTK @c speechd.texi ends here @c LocalWords: emph soundcard precission archieved succes Dispatcher When speech-dispatcher-0.9.1/doc/fdl.texi0000644000175000017500000005054512435416170014256 00000000000000@display Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @enumerate 0 @item PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document @dfn{free} in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of ``copyleft'', which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. @item APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The ``Document'', below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as ``you''. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A ``Modified Version'' of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A ``Secondary Section'' is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The ``Invariant Sections'' are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The ``Cover Texts'' are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A ``Transparent'' copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not ``Transparent'' is called ``Opaque''. Examples of suitable formats for Transparent copies include plain @sc{ascii} without markup, Texinfo input format, La@TeX{} input format, @acronym{SGML} or @acronym{XML} using a publicly available @acronym{DTD}, and standard-conforming simple @acronym{HTML}, PostScript or @acronym{PDF} designed for human modification. Examples of transparent image formats include @acronym{PNG}, @acronym{XCF} and @acronym{JPG}. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, @acronym{SGML} or @acronym{XML} for which the @acronym{DTD} and/or processing tools are not generally available, and the machine-generated @acronym{HTML}, PostScript or @acronym{PDF} produced by some word processors for output purposes only. The ``Title Page'' means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, ``Title Page'' means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section ``Entitled XYZ'' means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as ``Acknowledgements'', ``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' of such a section when you modify the Document means that it remains a section ``Entitled XYZ'' according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. @item VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. @item COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. @item MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: @enumerate A @item Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. @item List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. @item State on the Title page the name of the publisher of the Modified Version, as the publisher. @item Preserve all the copyright notices of the Document. @item Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. @item Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. @item Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. @item Include an unaltered copy of this License. @item Preserve the section Entitled ``History'', Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled ``History'' in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. @item Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the ``History'' section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. @item For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @item Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. @item Delete any section Entitled ``Endorsements''. Such a section may not be included in the Modified Version. @item Do not retitle any existing section to be Entitled ``Endorsements'' or to conflict in title with any Invariant Section. @item Preserve any Warranty Disclaimers. @end enumerate If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled ``Endorsements'', provided it contains nothing but endorsements of your Modified Version by various parties---for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. @item COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled ``History'' in the various original documents, forming one section Entitled ``History''; likewise combine any sections Entitled ``Acknowledgements'', and any sections Entitled ``Dedications''. You must delete all sections Entitled ``Endorsements.'' @item COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. @item AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. @item TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled ``Acknowledgements'', ``Dedications'', or ``History'', the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @item TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. @item FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See @uref{http://www.gnu.org/copyleft/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. @end enumerate @page @appendixsec ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: @smallexample @group Copyright (C) @var{year} @var{your name}. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end group @end smallexample If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the ``with...Texts.'' line with this: @smallexample @group with the Invariant Sections being @var{list their titles}, with the Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}. @end group @end smallexample If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. @c Local Variables: @c ispell-local-pdict: "ispell-dict" @c End: speech-dispatcher-0.9.1/doc/gpl.texi0000644000175000017500000004352213406251504014265 00000000000000@c The GNU General Public License. @center Version 2, June 1991 @c This file is intended to be included within another document, @c hence no sectioning command or @node. @display Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @heading Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software---to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 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 this service 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. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. @heading TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @enumerate 0 @item This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The ``Program'', below, refers to any such program or work, and a ``work based on the Program'' means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term ``modification''.) Each licensee is addressed as ``you''. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. @item You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. @item You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: @enumerate a @item You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. @item You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. @item If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) @end enumerate These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. @item You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: @enumerate a @item Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, @item Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, @item Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) @end enumerate The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. @item You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. @item You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. @item Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. @item If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. @item If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. @item The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and ``any later version'', you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. @item If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. @iftex @heading NO WARRANTY @end iftex @ifinfo @center NO WARRANTY @end ifinfo @item BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. @item IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. @end enumerate @iftex @heading END OF TERMS AND CONDITIONS @end iftex @ifinfo @center END OF TERMS AND CONDITIONS @end ifinfo @page @heading Appendix: 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 convey the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found. @smallexample @var{one line to give the program's name and a brief idea of what it does.} Copyright (C) @var{yyyy} @var{name of author} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . @end smallexample Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: @smallexample Gnomovision version 69, Copyright (C) @var{year} @var{name of author} Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @end smallexample The hypothetical commands @samp{show w} and @samp{show c} should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than @samp{show w} and @samp{show c}; they could even be mouse-clicks or menu items---whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. Here is a sample; alter the names: @example Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. @var{signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice @end example This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. speech-dispatcher-0.9.1/doc/stamp-10000644000175000017500000000014713465234127014020 00000000000000@set UPDATED 24 September 2010 @set UPDATED-MONTH September 2010 @set EDITION 0.9.1 @set VERSION 0.9.1 speech-dispatcher-0.9.1/doc/version-2.texi0000644000175000017500000000014713465234127015332 00000000000000@set UPDATED 24 September 2010 @set UPDATED-MONTH September 2010 @set EDITION 0.9.1 @set VERSION 0.9.1 speech-dispatcher-0.9.1/doc/stamp-vti0000644000175000017500000000014313465234127014456 00000000000000@set UPDATED 31 January 2019 @set UPDATED-MONTH January 2019 @set EDITION 0.9.1 @set VERSION 0.9.1 speech-dispatcher-0.9.1/doc/version.texi0000644000175000017500000000014313465234127015167 00000000000000@set UPDATED 31 January 2019 @set UPDATED-MONTH January 2019 @set EDITION 0.9.1 @set VERSION 0.9.1 speech-dispatcher-0.9.1/doc/Makefile.am0000644000175000017500000000216313406251474014646 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # info_TEXINFOS = ssip.texi speech-dispatcher.texi spd-say.texi speech-dispatcher-cs.texi EXTRA_DIST = figures speech_dispatcher_TEXINFOS = gpl.texi fdl.texi speech-dispatcher.texi speech_dispatcher_cs_TEXINFOS = gpl.texi fdl.texi speech-dispatcher-cs.texi ssip_TEXINFOS = gpl.texi fdl.texi CLEANFILES = spd-say.info \ speech-dispatcher-cs.info \ speech-dispatcher.info \ ssip.info \ stamp-1 \ stamp-vti \ version-2.texi \ version.texi -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/config/0000755000175000017500000000000013465234514013371 500000000000000speech-dispatcher-0.9.1/config/clients/0000755000175000017500000000000013465234514015032 500000000000000speech-dispatcher-0.9.1/config/clients/Makefile.in0000644000175000017500000004525613465233610017027 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = config/clients ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_clientconf_DATA) \ $(dist_clientconforig_DATA) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(clientconfdir)" \ "$(DESTDIR)$(clientconforigdir)" DATA = $(dist_clientconf_DATA) $(dist_clientconforig_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dist_clientconf_DATA = emacs.conf dist_clientconforig_DATA = emacs.conf all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign config/clients/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign config/clients/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_clientconfDATA: $(dist_clientconf_DATA) @$(NORMAL_INSTALL) @list='$(dist_clientconf_DATA)'; test -n "$(clientconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(clientconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(clientconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(clientconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(clientconfdir)" || exit $$?; \ done uninstall-dist_clientconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_clientconf_DATA)'; test -n "$(clientconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(clientconfdir)'; $(am__uninstall_files_from_dir) install-dist_clientconforigDATA: $(dist_clientconforig_DATA) @$(NORMAL_INSTALL) @list='$(dist_clientconforig_DATA)'; test -n "$(clientconforigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(clientconforigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(clientconforigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(clientconforigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(clientconforigdir)" || exit $$?; \ done uninstall-dist_clientconforigDATA: @$(NORMAL_UNINSTALL) @list='$(dist_clientconforig_DATA)'; test -n "$(clientconforigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(clientconforigdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(clientconfdir)" "$(DESTDIR)$(clientconforigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_clientconfDATA \ install-dist_clientconforigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_clientconfDATA \ uninstall-dist_clientconforigDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_clientconfDATA install-dist_clientconforigDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-dist_clientconfDATA \ uninstall-dist_clientconforigDATA .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/config/clients/emacs.conf0000644000175000017500000000016411447133617016712 00000000000000# Local configuration for emacs BeginClient "emacs:*" # Example: # DefaultPunctuationMode "some" EndClient speech-dispatcher-0.9.1/config/clients/Makefile.am0000644000175000017500000000147413406251150017002 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in dist_clientconf_DATA = emacs.conf dist_clientconforig_DATA = emacs.conf -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/config/modules/0000755000175000017500000000000013465234514015041 500000000000000speech-dispatcher-0.9.1/config/modules/Makefile.in0000644000175000017500000005032613465233610017030 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @pico_support_TRUE@am__append_1 = pico.conf @pico_support_TRUE@am__append_2 = pico.conf @baratinoo_support_TRUE@am__append_3 = baratinoo.conf @baratinoo_support_TRUE@am__append_4 = baratinoo.conf @kali_support_TRUE@am__append_5 = kali.conf @kali_support_TRUE@am__append_6 = kali.conf subdir = config/modules ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_moduleconf_DATA_DIST) \ $(am__dist_moduleconforig_DATA_DIST) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_moduleconf_DATA_DIST = cicero.conf espeak.conf espeak-ng.conf \ festival.conf flite.conf ibmtts.conf ivona.conf \ dtk-generic.conf epos-generic.conf espeak-generic.conf \ espeak-ng-mbrola-generic.conf espeak-mbrola-generic.conf \ llia_phon-generic.conf pico-generic.conf swift-generic.conf \ mary-generic.conf pico.conf baratinoo.conf kali.conf am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(moduleconfdir)" \ "$(DESTDIR)$(moduleconforigdir)" am__dist_moduleconforig_DATA_DIST = cicero.conf espeak.conf \ festival.conf espeak-ng.conf pico.conf baratinoo.conf \ kali.conf DATA = $(dist_moduleconf_DATA) $(dist_moduleconforig_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dist_moduleconf_DATA = cicero.conf espeak.conf espeak-ng.conf \ festival.conf flite.conf ibmtts.conf ivona.conf \ dtk-generic.conf epos-generic.conf espeak-generic.conf \ espeak-ng-mbrola-generic.conf espeak-mbrola-generic.conf \ llia_phon-generic.conf pico-generic.conf swift-generic.conf \ mary-generic.conf $(am__append_1) $(am__append_3) \ $(am__append_5) dist_moduleconforig_DATA = cicero.conf espeak.conf festival.conf \ espeak-ng.conf $(am__append_2) $(am__append_4) $(am__append_6) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign config/modules/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign config/modules/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_moduleconfDATA: $(dist_moduleconf_DATA) @$(NORMAL_INSTALL) @list='$(dist_moduleconf_DATA)'; test -n "$(moduleconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(moduleconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(moduleconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(moduleconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(moduleconfdir)" || exit $$?; \ done uninstall-dist_moduleconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_moduleconf_DATA)'; test -n "$(moduleconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(moduleconfdir)'; $(am__uninstall_files_from_dir) install-dist_moduleconforigDATA: $(dist_moduleconforig_DATA) @$(NORMAL_INSTALL) @list='$(dist_moduleconforig_DATA)'; test -n "$(moduleconforigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(moduleconforigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(moduleconforigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(moduleconforigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(moduleconforigdir)" || exit $$?; \ done uninstall-dist_moduleconforigDATA: @$(NORMAL_UNINSTALL) @list='$(dist_moduleconforig_DATA)'; test -n "$(moduleconforigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(moduleconforigdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(moduleconfdir)" "$(DESTDIR)$(moduleconforigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_moduleconfDATA \ install-dist_moduleconforigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_moduleconfDATA \ uninstall-dist_moduleconforigDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_moduleconfDATA install-dist_moduleconforigDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-dist_moduleconfDATA \ uninstall-dist_moduleconforigDATA .PRECIOUS: Makefile flite.conf ibmtts.conf ivona.conf dtk-generic.conf \ epos-generic.conf espeak-generic.conf \ espeak-ng-mbrola-generic.conf espeak-mbrola-generic.conf \ llia_phon-generic.conf \ pico-generic.conf swift-generic.conf mary-generic.conf -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/config/modules/kali.conf0000644000175000017500000000251213406251412016537 00000000000000# -- Kali parameters -- KaliMaxChunkLength 4999 KaliDelimiters ".?!;" # -- Voices -- # 3 french voices, 2 english voices KaliVoiceParameters "Patrick" # French male 1 #KaliVoiceParameters "Michel" # French male 2 #KaliVoiceParameters "Guillemette" # French female 1 #KaliVoiceParameters "Tom" # English male 1 #KaliVoiceParameters "Rosalind" # English female 2 # -- Rate control -- # Normal rate (0 in speech-dispatcher) KaliNormalRate 5 # -- Volume control -- # Normal volume (0 in speech-dispatcher) KaliNormalVolume 10 # -- Pitch control -- # Normal pitch (0 in speech-dispatcher) KaliNormalPitch 6 # Copyright (C) 2018 RaphaĂŤl POITEVIN # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/baratinoo.conf0000644000175000017500000000410013406251202017565 00000000000000 # Path to the Baratinoo configuration file. Defaults to $BARATINOO_CONFIG_PATH # or XDG_CONFIG_HOME/baratinoo.cfg BaratinooConfigPath "/etc/voxygen/baratinoo.cfg" # Characters to be spoken when punctuation setting is "some" # Encoding is UTF-8. BaratinooPunctuationList "@+_" # Characters that should still influence intonation when punctuation is not "none" # Encoding is UTF-8. BaratinooIntonationList "?!;:,.…" # Characters that should not be spoken when punctuation is "none" # (i.e. Baratinoo would not use them for intonation so we have to explicitly # drop them before giving text to it) # Encoding is UTF-8. BaratinooNoIntonationList "" # Sample rate, in Hz (in the 6000Hz-48000Hz range). Default to 16000Hz which # is the actual voices rate, not requiring resampling. #BaratinooSampleRate 16000 # Minimum rate (-100 in speech-dispatcher) BaratinooMinRate -50 # Normal rate (0 in speech-dispatcher) BaratinooNormalRate 0 # Maximum rate (100 in speech-dispatcher) BaratinooMaxRate 150 # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored # Debug 0 # DebugFile specifies the file where the debugging information # should be stored (note that the log is overwritten each time # the module starts) # DebugFile "/tmp/debug-baratinoo" # Copyright (C) 2017 Colomban Wendling # Copyright (C) 2018 Samuel Thibault # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/pico.conf0000644000175000017500000000143313406251417016557 00000000000000#PicoLingwarePath "/usr/share/pico/lang/" #Debug 1 # Copyright (C) 2010 Andrei Kholodnyi # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/mary-generic.conf0000644000175000017500000000745013406251414020211 00000000000000# The mary-generic output module is based on the generic plugin for Speech # Dispatcher. It means there is no code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Use this config file with the sd_generic output module. # # IMPORTANT: The audio output method relies on an audio playback # utility (play, aplay, paplay for OSS, ALSA or Pulse) # being installed. If this is not the case, consider installing it # or replace the $PLAY_COMMAND string in the GenericExecuteString below # with play, paplay or similar. # # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # This line uses the command curl, so you might need to install # curl if it isn't already installed. # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "curl \"http://localhost:59125/process?INPUT_TEXT=`echo \'$DATA\'| xxd -plain | tr -d '\\n' | sed 's/\\\(..\\\)/%\\\1/g'`&INPUT_TYPE=TEXT&OUTPUT_TYPE=AUDIO&AUDIO=WAVE_FILE&LOCALE=$LANGUAGE&VOICE=$VOICE\" > $TMPDIR/mary-generic.wav && $PLAY_COMMAND $TMPDIR/mary-generic.wav" GenericCmdDependency "curl" # The following three items control punctuation levels None, Some, and All. # Each of these values will be substituted into the $PUNCT variable depending # on the value passed to speech dispatcher from applications. # Note that if an empty string is specified, then $PUNCT will be blank # which is a default situation for espeak. GenericPunctNone "" GenericPunctSome "--punct=\"()[]{};:\"" GenericPunctAll "--punct" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. #GenericStripPunctChars "" # If the language you need to pass in $LANG is different # from the standard ISO language code, you can specify # which string to use instead. If you wish to use # other than ISO charset for the specified language, # you can add it's name (as accepted by iconv) as a # third parameter in doublequotes. GenericLanguage "en" "en_GB" "utf-8" GenericLanguage "de" "de" "utf-8" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. This list will likely not be # up-to-date, please check your mary installation and add the voices # you want to use. AddVoice "en" "MALE1" "dfki-spike" AddVoice "en" "FEMALE1" "dfki-prudence" AddVoice "en" "CHILD_FEMALE" "dfki-poppy" AddVoice "de" "MALE1" "dfki-pavoque-styles" # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored Debug 0 # Copyright (C) 2018 Florian Steinhardt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/swift-generic.conf0000644000175000017500000000712713406251421020374 00000000000000# Swift software output module is based on the generic plugin for Speech # Dispatcher. It means there is no C code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Note that this is not an optimal solution, but # it's reported to work. #Use this config file with the sd_generic output module. # # IMPORTANT: The audio output method relies on an audio playback # utility (play, aplay, paplay for OSS, ALSA or Pulse) # being installed. If this is not the case, consider installing it # or replace the $PLAY_COMMAND string in the GenericExecuteString below # with play, paplay or similar. # # Please note that Swift software is currently *not* Free Software. #It can be purchased at www.cepstral.com. # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "echo \'$DATA\' >/tmp/swift-speak.txt && /opt/swift/bin/swift -p speech/rate=$RATE,speech/pitch/shift=$PITCH,tts/content-type=text/plain,tts/text-encoding=utf-8,config/default-voice=$VOICE -f /tmp/swift-speak.txt -o /tmp/swift-speak.wav&& $PLAY_COMMAND /tmp/swift-speak.wav" GenericCmdDependency "/opt/swift/bin/swift" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # command characters. GenericStripPunctChars "[]" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. AddVoice "en" "MALE1" "David" AddVoice "en" "FEMALE1" "Diane" AddVoice "en" "FEMALE2" "Linda" AddVoice "en" "FEMALE3" "Callie" # These parameters set _rate_ and _pitch_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer GenericRateForceInteger 1 GenericRateAdd 238 GenericPitchAdd 1 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply 262 GenericPitchMultiply 1 # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored # Debug 0 # Copyright (C) 2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/pico-generic.conf0000644000175000017500000000777113406251415020202 00000000000000# pico output module is based on the generic plugin for Speech # Dispatcher. It means there is no code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Use this config file with the sd_generic output module. # # IMPORTANT: The audio output method relies on an audio playback # utility (play, aplay, paplay for OSS, ALSA or Pulse) # being installed. If this is not the case, consider installing it # or replace the $PLAY_COMMAND string in the GenericExecuteString below # with play, paplay or similar. # # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "pico2wave -w $TMPDIR/pico.wav -l $VOICE \'$DATA\' && $PLAY_COMMAND $TMPDIR/pico.wav" GenericCmdDependency "pico2wave" # The following three items control punctuation levels None, Some, and All. # Each of these values will be substituted into the $PUNCT variable depending # on the value passed to speech dispatcher from applications. # Note that if an empty string is specified, then $PUNCT will be blank # which is a default situation for espeak. GenericPunctNone "" GenericPunctSome "--punct=\"()[]{};:\"" GenericPunctAll "--punct" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # GenericStripPunctChars "" # If the language you need to pass in $LANG is different # from the standard ISO language code, you can specify # which string to use instead. If you wish to use # other than ISO charset for the specified language, # you can add it's name (as accepted by iconv) as a # third parameter in doublequotes. GenericLanguage "en" "en" "utf-8" GenericLanguage "de" "de" "utf-8" GenericLanguage "es" "es" "utf-8" GenericLanguage "fr" "fr" "utf-8" GenericLanguage "it" "it" "utf-8" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. This list will likely not be # up-to-date, please check pico documentation and add the voices # you want to use. AddVoice "en" "FEMALE1" "en-US" AddVoice "en" "FEMALE2" "en-GB" AddVoice "de" "FEMALE1" "de-DE" AddVoice "es" "FEMALE1" "es-ES" AddVoice "fr" "FEMALE1" "fr-FR" AddVoice "it" "FEMALE1" "it-IT" # Yes, it's wrong, but this way you at least get something even when configured # (by default) to use a male voice AddVoice "en" "MALE1" "en-US" AddVoice "en" "MALE2" "en-GB" AddVoice "de" "MALE1" "de-DE" AddVoice "es" "MALE1" "es-ES" AddVoice "fr" "MALE1" "fr-FR" AddVoice "it" "MALE1" "it-IT" # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored Debug 0 # Copyright (C) 2014-2018 Samuel Thibault # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/llia_phon-generic.conf0000644000175000017500000000647113406251413021207 00000000000000# llia_phon output module is based on the generic plugin for Speech # Dispatcher. It means there is no C code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. # # WARNING: This is only a preliminary version and needs some more # work to be really useful. We plan to finish it as soon as llia_phon # is fixed in it's CVS. # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "echo \'$DATA\' > $TMPDIR/llia_phon.txt && llia_phon | mbrola --f $PITCH --t $RATE \ -e -I LIAPHON/data/noarch/initfile.lia (directory with the voice) $VOICE \ $TMPDIR/llia_phon.txt -.au | $PLAY_COMMAND -t au - >/dev/null" GenericCmdDependency "llia_phon" GenericCmdDependency "mbrola" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. AddVoice "fr" "male1" "phoneme-file" AddVoice "fr" "male2" "phoneme-file" # These parameters set _rate_ and _pitch_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer GenericRateAdd 100 GenericPitchAdd 100 #GenericVolumeAdd 100 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply -85 GenericPitchMultiply 100 #GenericVolumeMultiply 50 # If the client program can't handle floats, you will have to # use these two options to force integers as the parameters # 1 means force integers, 0 means do nothing (write floats). #GenericRateForceInteger 0 #GenericPitchForceInteger 0 #GenericVolumeForceInteger 0 # Debug turns debugging on or off # Debug 0 # DebugFile specifies the file where the debugging information # should be stored (note that the log is overwritten each time # the module starts) # DebugFile "/tmp/debug-llia-phon-generic" # Copyright (C) 2004-2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/espeak-mbrola-generic.conf0000644000175000017500000001760213406251375021771 00000000000000# Espeak mbrola output module is based on the generic plugin for Speech # Dispatcher. It means there is no code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Use this config file with the sd_generic output module. # # IMPORTANT: The audio output method relies on an audio playback # utility (play, aplay, paplay for OSS, ALSA or Pulse) # being installed. If this is not the case, consider installing it # or replace the $PLAY_COMMAND string in the GenericExecuteString below # with play, paplay or similar. # # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "echo \'$DATA\' | espeak -v mb-$VOICE -s $RATE -p $PITCH $PUNCT -q --stdin --pho | mbrola -v $VOLUME -e /usr/share/mbrola/$VOICE/$VOICE - -.au | $PLAY_COMMAND" GenericCmdDependency "espeak" GenericCmdDependency "mbrola" # The following three items control punctuation levels None, Some, and All. # Each of these values will be substituted into the $PUNCT variable depending # on the value passed to speech dispatcher from applications. # Note that if an empty string is specified, then $PUNCT will be blank # which is a default situation for espeak. GenericPunctNone "" GenericPunctSome "--punct=\"()[]{};:\"" GenericPunctAll "--punct" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # GenericStripPunctChars "" # If the language you need to pass in $LANG is different # from the standard ISO language code, you can specify # which string to use instead. If you wish to use # other than ISO charset for the specified language, # you can add it's name (as accepted by iconv) as a # third parameter in doublequotes. GenericLanguage "af" "af" "utf-8" GenericLanguage "cs" "cs" "utf-8" GenericLanguage "de" "de" "utf-8" GenericLanguage "el" "el" "utf-8" GenericLanguage "en" "en" "utf-8" GenericLanguage "es" "es" "utf-8" GenericLanguage "et" "et" "utf-8" GenericLanguage "fa" "fa" "utf-8" GenericLanguage "fr" "fr" "utf-8" GenericLanguage "hu" "hu" "utf-8" GenericLanguage "hr" "hr" "utf-8" GenericLanguage "id" "id" "utf-8" GenericLanguage "is" "is" "utf-8" GenericLanguage "it" "it" "utf-8" GenericLanguage "la" "la" "utf-8" GenericLanguage "nl" "nl" "utf-8" GenericLanguage "pl" "pl" "utf-8" GenericLanguage "pt" "pt" "utf-8" GenericLanguage "ro" "ro" "utf-8" GenericLanguage "sv" "sv" "utf-8" GenericLanguage "tr" "tr" "utf-8" # Each voice is available if and only if the following files exist. # These files must be listed *before* the voices. VoiceFileDependency "/usr/share/mbrola/$VOICE/$VOICE" VoiceFileDependency "/usr/share/espeak-data/voices/mb/mb-$VOICE" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. This list will likely not be # up-to-date, please check eSpeak documentation and add the voices # you want to use. AddVoice "af" "MALE1" "af1" AddVoice "cs" "MALE1" "cz2" AddVoice "de" "MALE1" "de4" AddVoice "de" "MALE2" "de6" AddVoice "de" "MALE3" "de2" AddVoice "de" "FEMALE1" "de5" AddVoice "de" "FEMALE2" "de7" AddVoice "de" "FEMALE3" "de3" AddVoice "el" "MALE1" "gr1" AddVoice "el" "MALE2" "gr2" AddVoice "en" "MALE1" "en1" AddVoice "en" "MALE2" "us2" AddVoice "en" "MALE3" "us3" AddVoice "en" "FEMALE1" "us1" AddVoice "es" "MALE1" "es1" AddVoice "es" "MALE2" "es2" AddVoice "es" "MALE3" "mx1" AddVoice "es" "MALE4" "mx2" AddVoice "es" "MALE5" "vz1" AddVoice "et" "MALE1" "ee1" AddVoice "fa" "MALE1" "ir1" AddVoice "fa" "FEMALE1" "ir2" AddVoice "fr" "MALE1" "fr1" AddVoice "fr" "FEMALE1" "fr4" AddVoice "hu" "MALE1" "hu1" AddVoice "hr" "MALE1" "cr1" AddVoice "id" "MALE1" "id1" AddVoice "is" "MALE1" "ic1" AddVoice "it" "MALE1" "it3" AddVoice "it" "FEMALE1" "it4" AddVoice "la" "MALE1" "la1" AddVoice "nl" "MALE1" "nl2" AddVoice "pl" "FEMALE1" "pl1" AddVoice "pt" "MALE1" "br1" AddVoice "pt" "MALE2" "br3" AddVoice "pt" "FEMALE1" "pt1" AddVoice "pt" "FEMALE2" "br4" AddVoice "ro" "MALE1" "ro1" AddVoice "sv" "MALE1" "sw1" AddVoice "sv" "FEMALE1" "sw2" AddVoice "tr" "MALE1" "tr1" AddVoice "tr" "FEMALE1" "tr2" # These parameters set _rate_, _pitch_, and _volume_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer # Here's the mapping from SSIP (Speech Dispatcher) to ESpeak (v1.10): # # SSIP Range SSIP Default ESpeak/MBROLA Range ESpeak Default # ----------- ------------ ------------ -------------- # Rate -100 to 100 0 80 to 320 160 # Pitch -100 to 100 0 0 to 99 50 # Volume -100 to 100 0 0 to 2 -- # # The SSIP defaults are actually controlled via DefaultRate, DefaultPitch, and # DefaultVolume in the speechd.conf file. GenericRateAdd 160 GenericPitchAdd 50 GenericVolumeAdd 1 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply 160 GenericPitchMultiply 50 GenericVolumeMultiply 1 # If the client program can't handle floats, you will have to # use these two options to force integers as the parameters # 1 means force integers, 0 means do nothing (write floats). GenericRateForceInteger 1 GenericPitchForceInteger 1 GenericVolumeForceInteger 0 # Note that SSIP rates < -50 are spoken at -50. # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored Debug 0 # Copyright (C) 2008-2010 Brailcom, o.p.s # Copyright (C) 2014 Luke Yelavich # Copyright (C) 2018 Samuel Thibault # Copyright (C) 2018 Didier Spaier # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/espeak-ng-mbrola-generic.conf0000644000175000017500000002236313406251376022374 00000000000000# Espeak mbrola output module is based on the generic plugin for Speech # Dispatcher. It means there is no code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Use this config file with the sd_generic output module. # # IMPORTANT: The audio output method relies on an audio playback # utility (play, aplay, paplay for OSS, ALSA or Pulse) # being installed. If this is not the case, consider installing it # or replace the $PLAY_COMMAND string in the GenericExecuteString below # with play, paplay or similar. # # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "echo \'$DATA\' | espeak-ng -v mb-$VOICE -s $RATE -p $PITCH $PUNCT -q --stdin --pho | mbrola -v $VOLUME -e /usr/share/mbrola/$VOICE/$VOICE - -.au | $PLAY_COMMAND" # Alternatively you can shorten the command like below, which makes it # work directly with any audio playback utility, but then you won't # be able to change the volume from the client application: # GenericExecuteSynth \ # "echo \'$DATA\' | espeak-ng -v mb-$VOICE -s $RATE -p $PITCH $PUNCT -stdin" GenericCmdDependency "espeak-ng" GenericCmdDependency "mbrola" # The following three items control punctuation levels None, Some, and All. # Each of these values will be substituted into the $PUNCT variable depending # on the value passed to speech dispatcher from applications. # Note that if an empty string is specified, then $PUNCT will be blank # which is a default situation for espeak. GenericPunctNone "" GenericPunctSome "--punct=\"()[]{};:\"" GenericPunctAll "--punct" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # GenericStripPunctChars "" # If the language you need to pass in $LANG is different # from the standard ISO language code, you can specify # which string to use instead. If you wish to use # other than ISO charset for the specified language, # you can add it's name (as accepted by iconv) as a # third parameter in doublequotes. # To be completed GenericLanguage "af" "af" "utf-8" GenericLanguage "cs" "cs" "utf-8" GenericLanguage "de" "de" "utf-8" GenericLanguage "el" "el" "utf-8" GenericLanguage "en" "en" "utf-8" GenericLanguage "es" "es" "utf-8" GenericLanguage "et" "et" "utf-8" GenericLanguage "fa" "fa" "utf-8" GenericLanguage "fr" "fr" "utf-8" GenericLanguage "hu" "hu" "utf-8" GenericLanguage "hr" "hr" "utf-8" GenericLanguage "id" "id" "utf-8" GenericLanguage "is" "is" "utf-8" GenericLanguage "it" "it" "utf-8" GenericLanguage "la" "la" "utf-8" GenericLanguage "lt" "lt" "utf-8" GenericLanguage "nl" "nl" "utf-8" GenericLanguage "pl" "pl" "utf-8" GenericLanguage "pt" "pt" "utf-8" GenericLanguage "ro" "ro" "utf-8" GenericLanguage "sv" "sv" "utf-8" GenericLanguage "tr" "tr" "utf-8" # Each voice is available if and only if the following files exist. # These files must be listed *before* the voices. VoiceFileDependency "/usr/share/mbrola/$VOICE/$VOICE" VoiceFileDependency "/usr/share/espeak-ng-data/voices/mb/mb-$VOICE" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. This list will likely not be # up-to-date, please check eSpeak NG documentation and add the voices # you want to use. # All MBROLA voices for which a phoneme translation from espeak-ng to # MBROLA as of 12 October 2018 are listed, some commented with the # rationale to not include them by default. You still can ship or use # the commented voices if you uncomment the corresponding line. # As of Friday 12 October 2018 theses mbrola voices not yet supported # by espeak-ng's phonemes translation to mbrola in git are: # bz1: Breton Female (25.0Mb) Jean Pierre Messager # hb1: Hebrew Male (3.4Mb) Yoram Meron # hb2: Hebrew Female (5.6Mb) Esther Raizen # hn1: Korean Male (9.9Mb) Kyongsok Gim # thus they are not listed below. # The language code in this list is the ISO 639-1 code. AddVoice "af" "MALE1" "af1" AddVoice "ar" "MALE1" "ar1" AddVoice "ar" "MALE2" "ar2" AddVoice "zh" "FEMALE1" "cn1" AddVoice "cs" "FEMALE1" "cz1" AddVoice "cs" "MALE1" "cz2" AddVoice "de" "FEMALE1" "de1" AddVoice "de" "MALE1" "de2" AddVoice "de" "FEMALE2" "de3" AddVoice "de" "MALE2" "de4" AddVoice "de" "FEMALE3" "de5" AddVoice "de" "MALE1" "de6" AddVoice "de" "FEMALE3" "de7" AddVoice "de" "MALE3" "de8" AddVoice "el" "MALE1" "gr1" AddVoice "el" "MALE2" "gr2" AddVoice "en" "MALE1" "en1" AddVoice "en" "FEMALE1" "us1" AddVoice "en" "MALE2" "us2" AddVoice "en" "MALE3" "us3" AddVoice "es" "MALE1" "es1" AddVoice "es" "MALE2" "es2" AddVoice "es" "FEMALE1" "es3" AddVoice "es" "MALE3" "es4" AddVoice "es" "MALE1" "mx1" AddVoice "es" "MALE2" "mx2" AddVoice "es" "MALE1" "vz1" AddVoice "et" "MALE1" "ee1" AddVoice "fa" "MALE1" "ir1" AddVoice "fa" "FEMALE1" "ir2" AddVoice "fr" "MALE1" "ca1" AddVoice "fr" "MALE2" "ca2" AddVoice "fr" "MALE1" "fr1" AddVoice "fr" "FEMALE1" "fr2" AddVoice "fr" "MALE3" "fr3" AddVoice "fr" "FEMALE2" "fr4" AddVoice "fr" "MALE3" "fr5" AddVoice "fr" "MALE3" "fr6" AddVoice "fr" "MALE3" "fr7" AddVoice "hi" "MALE1" "in1" AddVoice "hi" "MALE2" "in2" AddVoice "hu" "MALE1" "hu1" AddVoice "hr" "MALE1" "cr1" AddVoice "id" "MALE1" "id1" AddVoice "is" "MALE1" "ic1" AddVoice "it" "MALE1" "it1" AddVoice "it" "FEMALE1" "it2" AddVoice "it" "MALE2" "it3" AddVoice "it" "FEMALE2" "it4" AddVoice "jp" "MALE1" "jp1" AddVoice "jp" "FEMALE1" "jp2" AddVoice "jp" "FEMALE2" "jp3" AddVoice "la" "MALE1" "la1" AddVoice "lt" "MALE1" "lt1" AddVoice "lt" "MALE2" "lt2" Addvoice "ms" "FEMALE1" "ma1" # nl1 has a very limited set of diphones and is usable only for reading # numbers. Uncomment the next line if you want it. # AddVoice "nl" "CHILD-MALE" "nl1" AddVoice "nl" "MALE1" "nl2" AddVoice "nl" "FEMALE1" "nl3" AddVoice "mi" "MALE1" "nz1" AddVoice "pl" "FEMALE1" "pl1" AddVoice "pt" "MALE1" "br1" AddVoice "pt" "MALE2" "br2" AddVoice "pt" "MALE3" "br3" AddVoice "pt" "FEMALE1" "br4" AddVoice "pt" "FEMALE2" "pt1" AddVoice "ro" "MALE1" "ro1" AddVoice "sw" "MALE1" "sw1" AddVoice "sw" "FEMALE1" "sw2" AddVoice "te" "FEMALE1" "tl1" AddVoice "tr" "MALE1" "tr1" AddVoice "tr" "FEMALE1" "tr2" # These parameters set _rate_, _pitch_, and _volume_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer # Here's the mapping from SSIP (Speech Dispatcher) to ESpeak (v1.10): # # SSIP Range SSIP Default ESpeak/MBROLA Range ESpeak Default # ----------- ------------ ------------ -------------- # Rate -100 to 100 0 80 to 320 160 # Pitch -100 to 100 0 0 to 99 50 # Volume -100 to 100 0 0 to 2 -- # # The SSIP defaults are actually controlled via DefaultRate, DefaultPitch, and # DefaultVolume in the speechd.conf file. GenericRateAdd 160 GenericPitchAdd 50 GenericVolumeAdd 1 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply 160 GenericPitchMultiply 50 GenericVolumeMultiply 1 # If the client program can't handle floats, you will have to # use these two options to force integers as the parameters # 1 means force integers, 0 means do nothing (write floats). GenericRateForceInteger 1 GenericPitchForceInteger 1 GenericVolumeForceInteger 0 # Note that SSIP rates < -50 are spoken at -50. # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored Debug 0 # Copyright (C) 2008-2010 Brailcom, o.p.s # Copyright (C) 2014 Luke Yelavich # Copyright (C) 2018 Samuel Thibault # Copyright (C) 2018 Didier Spaier # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/espeak-generic.conf0000644000175000017500000001331313406251373020510 00000000000000# Espeak output module is based on the generic plugin for Speech # Dispatcher. It means there is no C code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Use this config file with the sd_generic output module. # # IMPORTANT: The audio output method relies on ALSA Player (aplay) # being installed. If this is not the case, consider installing it # or replace the aplay command in the GenericExecuteString below # with play or similar. # # GenericExecuteString to what's the name of this utility on your # system (it might be "speak") # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "echo \'$DATA\' | espeak -w $TMPDIR/espeak.wav -v $VOICE -s $RATE -a $VOLUME -p $PITCH $PUNCT --stdin && $PLAY_COMMAND $TMPDIR/espeak.wav" GenericCmdDependency "espeak" # The following three items control punctuation levels None, Some, and All. # Each of these values will be substituted into the $PUNCT variable depending # on the value passed to speech dispatcher from applications. # Note that if an empty string is specified, then $PUNCT will be blank # which is a default situation for espeak. GenericPunctNone "" GenericPunctSome "--punct=\"()[]{};:\"" GenericPunctAll "--punct" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # GenericStripPunctChars "" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. This list will likely not be # up-to-date, please check eSpeak documentation and add the voices # you want to use. Or better use the native espeak module ('espeak' # not 'espeak-generic') AddVoice "en" "MALE1" "en" AddVoice "en" "MALE2" "en-b" AddVoice "en" "MALE3" "en-d" AddVoice "en" "FEMALE1" "en-f" AddVoice "en" "FEMALE2" "en-fb" AddVoice "en" "FEMALE3" "en-fd" AddVoice "en" "CHILD_MALE" "en-c" AddVoice "en" "CHILD_FEMALE" "en-fc" AddVoice "af" "MALE1" "af" AddVoice "de" "MALE1" "de" AddVoice "eo" "MALE1" "eo" AddVoice "es" "MALE1" "es" AddVoice "fi" "MALE1" "fi" AddVoice "fr" "MALE1" "fr" AddVoice "it" "MALE1" "it" AddVoice "pt" "MALE1" "pt" AddVoice "ro" "MALE1" "ro" # Experimental voices AddVoice "cs" "MALE1" "cs" AddVoice "cy" "MALE1" "cy" AddVoice "el" "MALE1" "el" AddVoice "nl" "MALE1" "nl" AddVoice "no" "MALE1" "no" AddVoice "hi" "MALE1" "hi" AddVoice "pl" "MALE1" "pl" AddVoice "ru" "MALE1" "ru" AddVoice "sv" "MALE1" "sv" AddVoice "vi" "MALE1" "vi" # These parameters set _rate_, _pitch_, and _volume_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer # Here's the mapping from SSIP (Speech Dispatcher) to ESpeak (v1.10): # # SSIP Range SSIP Default ESpeak Range ESpeak Default # ----------- ------------ ------------ -------------- # Rate -100 to 100 0 80 to 320 160 # Pitch -100 to 100 0 0 to 99 50 # Volume -100 to 100 0 0 to 20 10 # # The SSIP defaults are actually controlled via DefaultRate, DefaultPitch, and # DefaultVolume in the speechd.conf file. GenericRateAdd 160 GenericPitchAdd 50 GenericVolumeAdd 10 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply 160 GenericPitchMultiply 50 GenericVolumeMultiply 10 # If the client program can't handle floats, you will have to # use these two options to force integers as the parameters # 1 means force integers, 0 means do nothing (write floats). GenericRateForceInteger 1 GenericPitchForceInteger 1 GenericVolumeForceInteger 1 # Note that SSIP rates < -50 are spoken at -50. # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored Debug 0 # Copyright (C) 2006-2008 Brailcom, o.p.s # Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/epos-generic.conf0000644000175000017500000000745613406251313020213 00000000000000# Epos output module is based on the generic plugin for Speech # Dispatcher. It means there is no C code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. # # WARNING: You will need to either rename the command epos-say in # GenericExecuteString to what's the name of this utility on your # system (it might be "say"), or (better) create a link epos-say # somewhere in your path to the epos's say client. # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANGUAGE, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. GenericExecuteSynth \ "epos-say -o --language $LANGUAGE --voice $VOICE --init_f $PITCH --init_t $RATE \ \'$DATA\' | sed -e /unknown*/d >$TMPDIR/epos-said.wav && play $TMPDIR/epos-said.wav >/dev/null" GenericCmdDependency "epos-say" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # GenericStripPunctChars "~@#$%^&*+=|\\/<>[]_`" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. AddVoice "cs" "male1" "kadlec" AddVoice "sk" "male1" "bob" # If the language you need to pass in $LANG is different # from the standard ISO language code, you can specify # which string to use instead. If you wish to use # other than ISO charset for the specified language, # you can add it's name (as accepted by iconv) as a # third parameter in doublequotes. GenericLanguage "cs" "czech" GenericLanguage "sk" "slovak" # These parameters set _rate_ and _pitch_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer GenericRateAdd 100 GenericPitchAdd 100 #GenericVolumeAdd 100 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply -85 GenericPitchMultiply 100 #GenericVolumeMultiply 50 # If the client program can't handle floats, you will have to # use these two options to force integers as the parameters # 1 means force integers, 0 means do nothing (write floats). #GenericRateForceInteger 0 #GenericPitchForceInteger 0 #GenericVolumeForceInteger 0 # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored # Debug 0 # Copyright (C) 2003-2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/dtk-generic.conf0000644000175000017500000001011013406251306020006 00000000000000# DECTalk software output module is based on the generic plugin for Speech # Dispatcher. It means there is no C code written explicitly for # this plugin, all the specifics are handled in this configuration # and we call a simple command line client to perform the actual # synthesis. Note that this is not an optimal solution, but # it's reported to work. # # Please note that DECTalk software is currently *not* Free Software. # You might want to look at Festival instead. # GenericExecuteSynth is the shell command that should be # executed in order to say some message. This command must # stop saying the message on SIGKILL, otherwise it's useless. # You can use the variables $LANG, $VOICE, $PITCH and $RATE # which will be substituted for the appropriate value (you # can modify this value, see other parameters). # The command can be split into more lines, if necessary, using '\'. # NOTE1: # Users of previous versions of this configuration file need to rename their # DECTalk command-line program back to `say', since speech dispatcher no # longer installs a program with this name. Thus, the reason for # renaming the client in the first place is gone. # NOTE2: # DECTalk software version 4.61 is known to occasionally stop reading, # due to a buffering problem with the `say' program. So far, the only way # I know of to fix this is to upgrade from DECTalk 4.61 to DECTalk 5. GenericExecuteSynth \ "echo \"[:n$VOICE][:ra $RATE][:dv ap $PITCH]\" >$TMPDIR/dtk-speak.txt \ && echo \'$DATA\' | fmt >>$TMPDIR/dtk-speak.txt && say -fi $TMPDIR/dtk-speak.txt" GenericCmdDependency "say" # GenericStripPunctChars is a list (enclosed in doublequotes) of # all the characters that should be replaced by whitespaces in # order not to be badly handled by the output module or misinterpreted # by shell. # We need to strip `[' and `]', as these are DECTalk's # command characters. GenericStripPunctChars "[]" # AddVoice specifies which $VOICE string should be assigned to # each language and symbolic voice name. All the voices you want # to use must be specified here. # NOTE: # There is a multilingual version of DECTalk software, however I # do not have it. Thus, only the US English voices are defined here. # If you know about the other languages, please let us know on # AddVoice "en" "MALE1" "p" AddVoice "en" "MALE2" "h" AddVoice "en" "MALE3" "d" AddVoice "en" "FEMALE1" "b" AddVoice "en" "FEMALE2" "u" AddVoice "en" "FEMALE3" "w" AddVoice "en" "CHILD_MALE" "k" # These parameters set _rate_ and _pitch_ conversion. This is # part of the core of the definition of this generic output # module for this concrete synthesizer, it's not intended to # be modified by common users. # The resulting rate (or pitch) has the form: # (speechd_rate * GenericRateMultiply) + GenericRateAdd # while speechd_rate is a value between -100 (lowest) and +100 (highest) # You have to define some meaningful conversion for each synthesizer # NOTE: # Because DECTalk cannot accept float values, we must force them to be # integers. GenericRateForceInteger 1 GenericPitchForceInteger 1 GenericRateAdd 338 GenericPitchAdd 225 # (These values are multiplied by 100, because DotConf currently # doesn't support floats. So you can write 0.85 as 85 and so on.) GenericRateMultiply 262 GenericPitchMultiply 175 # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored # Debug 0 # Copyright (C) 2004-2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/ivona.conf0000644000175000017500000000314013406251411016730 00000000000000 # Host and port - default values #IvonaServerHost "127.0.0.1" #IvonaServerPort 9123 #Sample Frequency #IvonaSampleFreq 16000 # Debug level - see Festival module configuration Debug 0 # DebugFile specifies the file where the debugging information # should be stored (note that the log is overwritten each time # the module starts) # DebugFile "/tmp/debug-ivona" # IvonaMinCapLet overrides DefaultCapLetRecognition. Set to: # 1 for "icon" - play icon even if default is "none" # 2 for "spell" - spell "capital" even if default is "none" or "icon" IvonaMinCapLet 1 IvonaSoundIconPath "/usr/share/sounds/sound-icons-0.1/" #Ivona Speaker (depends on Ivona version) #Jacek or Ewa for pl, Jennifer for en, Carmen for ro IvonaSpeakerName "Jacek" IvonaSpeakerLanguage "pl" #Delimiters for message splitting #Do not change if not sure! #IvonaDelimiters ".;:,!?" #Punctuation for "some" #IvonaPunctuationSome "()" # Copyright (C) 2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/ibmtts.conf0000644000175000017500000002136513406251410017126 00000000000000 # The number of samples returned by IBM TTS. #IbmttsAudioChunkSize 20000 # -- SSML Support -- # Some version of IBM TTS support SSML. If IbmttsUseSSML # is set to 1, SSML will be used and advanced features like # index marking will be working. If set to 0, all SSML is # deleted from the message prior to sending it to IBM TTS. # By default, SSML support is switched on. # IbmttsUseSSML 1 # -- User dictionaries -- # IBM TTS supports user dictionaries so that you may customize # the pronunciation of words, beginning of words or abbreviations # according to the language. # # IbmttsDictionaryFolder defines the root directory under which you # may add your dictionary files. If several languages are installed, # you may want to create one sub-directory per language. # # Three examples : # # - a single language is installed: # place your files under IbmttsDictionaryFolder # # - two languages are installed, say English and French: # place your files under IbmttsDictionaryFolder in sub-directories en and fr # # - the same language for different regions are installed, say Castilian # Spanish and Mexican Spanish: # place your files in directories es_ES and es_MX # # The directory names are listed below (DIRECTORY NAMES and EXTENDED # DIRECTORY NAMES). # # The name of the dictionary files are: # # - main.dct: main dictionary # - root.dct: roots dictionary # - extension.dct: main extension dictionary # - abbreviation.dct: abbreviation dictionary # # The IBM TTS documentation details the syntax of the user dictionaries. # Basically, it is one line per entry, composed of key, tabulation, value. # # DIRECTORY NAMES # --------------- # de: German # en: English # es: Spanish # fi: Finnish # fr: French # it: Italian # ja: Japanese # pt: Portuguese # zh: Chinese # # EXTENDED DIRECTORY NAMES # ------------------------ # en_GB: British English # en_US: American English # fr_CA: Canadian French # fr_FR: French # pt_BR: Brazilian Portuguese # zh_CN: Mandarin Chinese # zh_TW: Mandarin Taiwanese IbmttsDictionaryFolder "/var/opt/IBM/ibmtts/dict" # -- Abbreviation dictionaries -- # Enable the abbreviation dictionaries. # IbmttsUseAbbreviation 1 # -- SOUND ICONS -- # IBM TTS Synthesizer does not currently support sound icons # (audio files that are played by name when an application requests # a sound icon). If you have installed the free(b)soft sound-icons # package, this is the directory where will they be found. If not # blank, the IBM TTS Output Module will play them if it finds a # file whose name matches the sound icon name. If blank, or no # matching file is found, the name of the sound icon will be spoken. #IbmttsSoundIconFolder "/usr/share/sounds/sound-icons/" # -- DEBUG -- # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored. # TODO: Change this to 0 and comment out for final release. Debug 0 # DebugFile specifies the file where the debugging information # should be stored (note that the log is overwritten each time # the module starts) # DebugFile "/tmp/debug-ibmtts" # -- VOICE PARAMETERS -- # This table provides a mechanism for fine-tuning the voices used for synthesis. # The dialect is chosen by the table above, then adjusted according to these parameters. # The columns are: # Voice Name - See the Speech Dispatcher manual for standard voice names. Use lowercase names. # M/F - Gender. 0 = male. 1 = female. # Br - Breathiness. 0 to 100. 0 is usually used for males, 40 or 50 for females. # Hd Sz - Head Size. 0 to 100. # Pitch Bas - Pitch Baseline. 0 to 100. # Pitch Flc - Pitch Fluctuation. 0 to 100. # Rough - Roughness. 0 to 100 # Speed - Rate. 0 to 100. # Volume is controlled via speechd.conf or SSIP commands. # Application RATE or PITCH commands are relative to the settings here. # For example, if Pitch Bas is 80 below, a PITCH command of -50 would set the # pitch baseline to halfway between 80 and 0, or 40. # All columns must be provided. # Hd -Pitch- # Voice Name M/F Br Sz Bas Flc Rough Speed # -------------- --- --- --- --- --- --- --- #IbmttsVoiceParameters "male1" 0 0 50 65 30 0 50 #IbmttsVoiceParameters "male2" 0 0 86 56 47 0 50 #IbmttsVoiceParameters "male3" 0 0 50 69 34 0 70 #IbmttsVoiceParameters "male3" 0 20 30 61 44 18 50 #IbmttsVoiceParameters "female1" 1 50 50 81 30 0 50 #IbmttsVoiceParameters "female2" 1 40 56 89 35 0 70 #IbmttsVoiceParameters "female3" 1 40 45 68 30 3 50 IbmttsVoiceParameters "child_male" 0 0 35 85 35 0 50 #IbmttsVoiceParameters "child_female" 1 0 22 93 35 0 50 # The table above shows the default mapping. # It shows the default settings in the IBM TTS Engine, as follows: # # SD Voice Name IBM TTS Voice # ------------- ------------- # male1 Adult Male 1 # male2 Adult Male 2 # male3 Adult Male 3 # male3 Elderly Male (uncomment the 2nd "male3" line if you want to use this) # female1 Adult Female 1 # female2 Adult Female 2 # female3 Elderly Female (notice there is no Adult Female 3) # child_male none provided (that is why it is uncommented, by default) # child_female Child # -- KEY NAME SUBSTITUTIONS -- # Maps Speech Dispatcher key names used in SSIP KEY commands to speakable words. # The string in the "SD Key" column occurring anywhere in a KEY command # is replaced with the string in "Spoken". The substitutions occur in the # order listed. "Lang" determines which language the substitution applies # to. # Lang SD Key Spoken # ---- ----------- ----------- IbmttsKeySubstitution "en" "kp--" "keypad minus " IbmttsKeySubstitution "en" "kp-" "keypad " IbmttsKeySubstitution "en" "_" " " IbmttsKeySubstitution "en" "#" "pound " IbmttsKeySubstitution "en" "&" "ampersand " IbmttsKeySubstitution "en" "!" "exclamation mark " IbmttsKeySubstitution "en" "ÂŚ" "pipe " IbmttsKeySubstitution "en" "¤" "currency " IbmttsKeySubstitution "en" "Ø" "capital phi " IbmttsKeySubstitution "en" "ø" "phi " IbmttsKeySubstitution "en" "Ăż" "yummel " IbmttsKeySubstitution "en" "­" "dash " IbmttsKeySubstitution "en" "A" "capital A " IbmttsKeySubstitution "en" "B" "capital B " IbmttsKeySubstitution "en" "C" "capital C " IbmttsKeySubstitution "en" "D" "capital D " IbmttsKeySubstitution "en" "E" "capital E " IbmttsKeySubstitution "en" "F" "capital F " IbmttsKeySubstitution "en" "G" "capital G " IbmttsKeySubstitution "en" "H" "capital H " IbmttsKeySubstitution "en" "I" "capital I " IbmttsKeySubstitution "en" "J" "capital J " IbmttsKeySubstitution "en" "K" "capital K " IbmttsKeySubstitution "en" "L" "capital L " IbmttsKeySubstitution "en" "M" "capital M " IbmttsKeySubstitution "en" "N" "capital N " IbmttsKeySubstitution "en" "O" "capital O " IbmttsKeySubstitution "en" "P" "capital P " IbmttsKeySubstitution "en" "Q" "capital Q " IbmttsKeySubstitution "en" "R" "capital R " IbmttsKeySubstitution "en" "S" "capital S " IbmttsKeySubstitution "en" "T" "capital T " IbmttsKeySubstitution "en" "U" "capital U " IbmttsKeySubstitution "en" "V" "capital V " IbmttsKeySubstitution "en" "W" "capital W " IbmttsKeySubstitution "en" "X" "capital X " IbmttsKeySubstitution "en" "Y" "capital Y " IbmttsKeySubstitution "en" "Z" "capital Z " # Copyright (C) 2006 Gary Cramblitt # Copyright (C) 2007-2008 Brailcom, o.p.s # Copyright (C) 2007 Lukas Loehrer # Copyright (C) 2007-2013 Gilles Casse # Copyright (C) 2010 Christopher Brannon # Copyright (C) 2016 Luke Yelavich # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/flite.conf0000644000175000017500000000214413406251405016725 00000000000000 # See Festival commands comments for information FliteMaxChunkLength 500 FliteDelimiters ".?!;" # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored # Debug 0 # DebugFile specifies the file where the debugging information # should be stored (note that the log is overwritten each time # the module starts) # DebugFile "/tmp/debug-flite" # Copyright (C) 2003-2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/festival.conf0000644000175000017500000000742313406251403017442 00000000000000 # -- FESTIVAL SERVER SETTINGS -- # Address where the Festival server runs (you have to # have a Festival server running, please see documentation). #FestivalServerHost "localhost" #FestivalServerPort 1314 # -- CACHING -- # Festival output module supports a caching mechanism for # repeated events like characters, keys and sound icons # that saves the wavefiles retrieved from the synthesizer # and uses them next time an identical request is issued. # This way, the synthesis is much more responsive when # you type in keys, you spell some word by going over it # with cursor keys, sound icons are faster and so on. # If you wish to enable this caching mechanism, turn # FestivalCacheOn to 1, or switch it off by 0. # FestivalCacheOn 1 # How large should the memmory assigned to output module for # cache should be. Festival will never overcome this limit. # If there are more messages to save, the ones that are least # accessed will be removed from the cache. So if you set this # parameter too low, the module will often have to synthesize # your request (which takes time) instead of just retrieving # it from the cache, but you will save system resources. If you # set it higher, it might make the module more responsive. # The value is given in kilobytes, default is 10 megabytes. # FestivalCacheMaxKBytes 10240 # Normally, the cache pool is common for all voices, rates and # pitches. This means that when for example the key 'r' gets cached, # you change the voice and request the key 'r' again, it will be # retrieved from the cache and you will hear the old 'r' instead of a # new one. By default, it only switches between languages. In most # cases, this isn't a problem for characters, keys and sound icons and # it saves system resources. But if you want to keep separate caches # for different voices (and even rates and pitches), please set the # corresponding parameters to 1. (0 means don't distinguish). # FestivalCacheDistinguishVoices 0 # FestivalCacheDistinguishRate 0 # FestivalCacheDistinguishPitch 0 # -- FESTIVAL PERFORMANCE -- # Switching FestivalReopenSocket to 1 will make the module close the # connection to Festival each time the currently synthesized wavefile # is no longer needed to finish and new text is waiting. This may improve # Festival responsivity on slower machines, but might cause a more network # trafic. Currently, the option is set to 0 by default, because there # is a network problem in Festival socket communication layer that introduces # unnecessary delays that affect the performance heavily in this mode. # Unless your Festival is patched against this bug, switching this on # is not recommended. # FestivalReopenSocket 0 # -- DEBUGING -- # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored Debug 0 # If FestivalDebugSaveOutput is set to 1, it writes the produced sound tracks # to /tmp/debug-festival-*.snd before it says them. You can later browse them # for debugging purposes. They are numbered in order starting from 0. # FestivalDebugSaveOutput 0 # Copyright (C) 2003-2008 Brailcom, o.p.s # Copyright (C) 2007 Gilles Casse # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/espeak-ng.conf0000644000175000017500000000510413412722106017471 00000000000000 # -- SOUND ICONS -- # Espeak does not currently support playing sound icons # (audio files that are played by name when an application requests # a sound icon). If you have installed the free(b)soft sound-icons # package, this is the directory where will they be found. If not # blank, the espeak Output Module will play them if it finds a # file whose name matches the sound icon name. If blank, or no # matching file is found, the name of the sound icon will be spoken. EspeakSoundIconFolder "/usr/share/sounds/sound-icons/" # Volume at which sound icons are played. EspeakSoundIconVolume 0 # -- Punctuation -- # Characters to be spoken when punctuation setting is "some" # Encoding is UTF-8. EspeakPunctuationList "@+_" EspeakCapitalPitchRise 0 # -- Rate control -- # The following options are in words per minute #the same as the -s parameter for the -s option in espeak command line tool. # Minimum rate (-100 in speech-dispatcher) EspeakMinRate 80 # Normal rate (0 in speech-dispatcher) EspeakNormalRate 170 # Maximum rate (100 in speech-dispatcher) EspeakMaxRate 390 # -- Espeak variants -- # Controls whether espeak voice variants are presented in the list of # available voices. A value of 1 will present an espeak voice, plus the # espeak voice with all the available variants. A value of 0 will present # the list of espeak voices only. EspeakListVoiceVariants 0 # -- Internal parameters -- # Number of ms of audio returned by the espeak callback function. EspeakAudioChunkSize 3000 # Maximum number of samples to buffer in playback queue. EspeakAudioQueueMaxSize 441000 # Whether to enable speech indexing EspeakIndexing 1 # Debugging Debug 0 # Copyright (C) 2007 Lukas Loehrer # Copyright (C) 2007-2008 Brailcom, o.p.s # Copyright (C) 2007 Gilles Casse # Copyright (C) 2011 Rui Batista # Copyright (C) 2011-2016 Luke Yelavich # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/espeak.conf0000644000175000017500000000507713412722106017100 00000000000000 # -- SOUND ICONS -- # Espeak does not currently support playing sound icons # (audio files that are played by name when an application requests # a sound icon). If you have installed the free(b)soft sound-icons # package, this is the directory where will they be found. If not # blank, the espeak Output Module will play them if it finds a # file whose name matches the sound icon name. If blank, or no # matching file is found, the name of the sound icon will be spoken. EspeakSoundIconFolder "/usr/share/sounds/sound-icons/" # Volume at which sound icons are played. EspeakSoundIconVolume 0 # -- Punctuation -- # Characters to be spoken when punctuation setting is "some" # Encoding is UTF-8. EspeakPunctuationList "@+_" EspeakCapitalPitchRise 0 # -- Rate control -- # The following options are in words per minute #the same as the -s parameter for the -s option in espeak command line tool. # Minimum rate (-100 in speech-dispatcher) EspeakMinRate 80 # Normal rate (0 in speech-dispatcher) EspeakNormalRate 170 # Maximum rate (100 in speech-dispatcher) EspeakMaxRate 390 # -- Espeak variants -- # Controls whether espeak voice variants are presented in the list of # available voices. A value of 1 will present an espeak voice, plus the # espeak voice with all the available variants. A value of 0 will present # the list of espeak voices only. EspeakListVoiceVariants 0 # -- Internal parameters -- # Number of ms of audio returned by the espeak callback function. EspeakAudioChunkSize 3000 # Maximum number of samples to buffer in playback queue. EspeakAudioQueueMaxSize 441000 # Whether to enable speech indexing EspeakIndexing 1 # Debugging Debug 0 # Copyright (C) 2007 Lukas Loehrer # Copyright (C) 2007-2008 Brailcom, o.p.s # Copyright (C) 2007 Gilles Casse # Copyright (C) 2011 Rui Batista # Copyright (C) 2011 Luke Yelavich # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/cicero.conf0000644000175000017500000000333013406251246017067 00000000000000 # -- CICERO EXECUTABLE AND LOG -- # CiceroExecutable indicates path to the cicero executable (the file called # tts_brltty_es.py in the original distribution of the 0.7 version). You can # create a symbolic link # ln -s your-path/tts_brltty_es.py /usr/bin/cicero or # probably better in /usr/local/bin/cicero and modify the below option # accordingly. #CiceroExecutable "/usr/bin/cicero" # CiceroExecutableLog is the path where logging information of the # original Cicero synthesizer (CiceroExecutable) should be stored. # This should not be confused with the logging of this module/driver # specified in speechd.conf. #CiceroExecutableLog "/var/log/speech-dispatcher/cicero-executable.log" # -- AUDIO OUTPUT -- # Cicero does its own audio output which can't # be influenced from this place. Please see Cicero # documentation # -- DEBUGING AND LOGING -- # Debug turns debugging on or off # See speechd.conf for information where debugging information is stored #Debug 0 # Copyright (C) 2006 Olivier BERT # Copyright (C) 2006 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/modules/Makefile.am0000644000175000017500000000356313406251154017016 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in dist_moduleconf_DATA = cicero.conf espeak.conf espeak-ng.conf festival.conf \ flite.conf ibmtts.conf ivona.conf dtk-generic.conf \ epos-generic.conf espeak-generic.conf \ espeak-ng-mbrola-generic.conf espeak-mbrola-generic.conf \ llia_phon-generic.conf \ pico-generic.conf swift-generic.conf mary-generic.conf dist_moduleconforig_DATA = cicero.conf espeak.conf festival.conf espeak-ng.conf flite.conf ibmtts.conf ivona.conf dtk-generic.conf \ epos-generic.conf espeak-generic.conf \ espeak-ng-mbrola-generic.conf espeak-mbrola-generic.conf \ llia_phon-generic.conf \ pico-generic.conf swift-generic.conf mary-generic.conf if pico_support dist_moduleconf_DATA += pico.conf dist_moduleconforig_DATA += pico.conf endif if baratinoo_support dist_moduleconf_DATA += baratinoo.conf dist_moduleconforig_DATA += baratinoo.conf endif if kali_support dist_moduleconf_DATA += kali.conf dist_moduleconforig_DATA += kali.conf endif -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/config/Makefile.in0000644000175000017500000006145313465233610015363 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = config ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_spdconf_DATA) \ $(dist_spdconforig_DATA) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(spdconfdir)" \ "$(DESTDIR)$(spdconforigdir)" DATA = $(dist_spdconf_DATA) $(dist_spdconforig_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = modules clients dist_spdconf_DATA = speechd.conf dist_spdconforig_DATA = speechd.conf all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign config/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign config/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_spdconfDATA: $(dist_spdconf_DATA) @$(NORMAL_INSTALL) @list='$(dist_spdconf_DATA)'; test -n "$(spdconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(spdconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(spdconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(spdconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(spdconfdir)" || exit $$?; \ done uninstall-dist_spdconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_spdconf_DATA)'; test -n "$(spdconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(spdconfdir)'; $(am__uninstall_files_from_dir) install-dist_spdconforigDATA: $(dist_spdconforig_DATA) @$(NORMAL_INSTALL) @list='$(dist_spdconforig_DATA)'; test -n "$(spdconforigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(spdconforigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(spdconforigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(spdconforigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(spdconforigdir)" || exit $$?; \ done uninstall-dist_spdconforigDATA: @$(NORMAL_UNINSTALL) @list='$(dist_spdconforig_DATA)'; test -n "$(spdconforigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(spdconforigdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(spdconfdir)" "$(DESTDIR)$(spdconforigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_spdconfDATA install-dist_spdconforigDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_spdconfDATA \ uninstall-dist_spdconforigDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_spdconfDATA install-dist_spdconforigDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-dist_spdconfDATA \ uninstall-dist_spdconforigDATA .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/config/speechd.conf0000644000175000017500000003040413435232270015566 00000000000000 # Global configuration for Speech Dispatcher # ========================================== # -----SYSTEM OPTIONS----- # CommunicationMethod specifies the method to be used by Speech Dispatcher to communicate with # its clients. Two basic methods are "unix_socket" and "inet_socket". # # unix_socket -- communication over Unix sockets represented by a file in the # filesystem (see SocketPath below). This method works only locally, but is # prefered for standard session setup, where every user runs his own instance of Speech # Dispatcher to get voice feedback on his own computer. # # inet_socket -- alternatively, you can start Speech Dispatcher on # a TCP port and connect to it via hostname/port. This allows for a more # flexible setup, where you can use Speech Dispatcher over network # from different machines. See also the Port and LocalhostAccessOnly # configuration variables. # # CommunicationMethod "unix_socket" # SocketPath is either "default" or a full path to the filesystem # where the driving Unix socket file should be created in case the # CommunicationMethod is set to "unix_socket". The default is # $XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock where $XDG_RUNTIME_DIR # is the directory specified by the XDG Base Directory Specification. # Do not change this unless you have a reason and know what you are doing. # SocketPath "default" # The Port on which Speech Dispatcher should be available to clients if the "inet_socket" # communication method is used. # Port 6560 # By default, if "inet_socket" communication method is used, the specified port is opened only # for connections coming from localhost. If LocalhostAccessOnly is set to 0 it disables this # access control. It means that the port will be accessible from all computers on the # network. If you turn off this option, please make sure you set up some system rules on what # computers are and are not allowed to access the Speech Dispatcher port. # LocalhostAccessOnly 1 # By default, Speech Dispatcher is configured to shut itself down after a period of # time if no clients are connected. The timeout value is in seconds, and is started when # the last client disconnects. A value of 0 disables the timeout. # Timeout 5 # -----LOGGING CONFIGURATION----- # The LogLevel is a number between 0 and 5 specifying the # verbosity of information to the logfile or screen # 0 means nothing, 5 means everything (not recommended). LogLevel 3 # The LogDir specifies where the Speech Dispatcher logs reside # Specify "stdout" for standard console output # or a custom log directory path. 'default' means # the logs are written to the default destination (e.g. a preconfigured # system directory or the home directory if .speech-dispatcher is present) # DO NOT COMMENT OUT THIS OPTION, leave as "default" for standard logging LogDir "default" #LogDir "/var/log/speech-dispatcher/" #LogDir "stdout" # The CustomLogFile allows logging all messages # regardless of # priority, to the given destination. #CustomLogFile "protocol" "/var/log/speech-dispatcher/speech-dispatcher-protocol.log" # ----- VOICE PARAMETERS ----- # The DefaultRate controls how fast the synthesizer is going to speak. # The value must be between -100 (slowest) and +100 (fastest), default # is 0. # DefaultRate 0 # The DefaultPitch controls the pitch of the synthesized voice. The # value must be between -100 (lowest) and +100 (highest), default is # 0. # DefaultPitch 0 # The DefaultPitchRange controls the pitch range of the synthesized voice. The # value must be between -100 (lowest) and +100 (highest), default is # 0. # DefaultPitchRange 0 # The DefaultVolume controls the default volume of the voice. It is # a value between -100 (softly) and +100 (loudly). Currently, +100 # maps to the default volume of the synthesizer. DefaultVolume 100 # The DefaultVoiceType controls which voice type should be used by # default. Voice types are symbolic names which map to particular # voices provided by the synthesizer according to the output module # configuration. Please see the synthesizer-specific configuration # in etc/speech-dispatcher/modules/ to see which voices are assigned to # different symbolic names. The following symbolic names are # currently supported: MALE1, MALE2, MALE3, FEMALE1, FEMALE2, FEMALE3, # CHILD_MALE, CHILD_FEMALE # DefaultVoiceType "MALE1" # The Default language with which to speak # DefaultLanguage "en" # ----- MESSAGE DISPATCHING CONTROL ----- # The DefaultClientName specifies the name of a client who didn't # introduce himself at the beginning of an SSIP session. # DefaultClientName "unknown:unknown:unknown" # The Default Priority. Use with caution, normally this shouldn't be # changed globally (at this place) # DefaultPriority "text" # The DefaultPauseContext specifies by how many index marks a speech # cursor should return when resuming after a pause. This is roughly # equivalent to the number of sentences before the place of the # execution of pause that will be repeated. # DefaultPauseContext 0 # -----SPELLING/PUNCTUATION/CAPITAL LETTERS CONFIGURATION----- # The DefaultPunctuationMode sets the way dots, comas, exclamation # marks, question marks etc. are interpreted. none: they are ignored # some: some of them are sent to synthesis (see # DefaultPunctuationSome) all: all punctuation marks are sent to # synthesis # DefaultPunctuationMode "none" # Whether to use server-side symbols pre-processing by default. # This controls whether the server should pre-process the messages to insert # the appropriate words or if the output module is responsible for speaking # symbols and punctuation. # DefaultSymbolsPreprocessing 0 # The DefaultCapLetRecognition: if set to "spell", capital letters # should be spelled (e.g. "capital b"), if set to "icon", # capital letters are indicated by inserting a special sound # before them but they should be read normally, it set to "none" # capital letters are not recognized (by default) # DefaultCapLetRecognition "none" # The DefaultSpelling: if set to On, all messages will be spelt # unless set otherwise (this is usually not something you want to do.) # DefaultSpelling Off # ----- AUDIO CONFIGURATION ----------- # -- AUDIO OUTPUT -- # Chooses between the possible sound output systems: # "pulse" - PulseAudio # "alsa" - Advanced Linux Sound System # "oss" - Open Sound System # "nas" - Network Audio System # "libao" - A cross platform audio library # Pulse audio is the default and recommended sound server. OSS and ALSA # are only provided for compatibility with architectures that do not # include Pulse Audio. NAS provides network transparency, but is not # very well tested. libao is a cross platform library with plugins for # different sound systems and provides alternative output for Pulse Audio # and ALSA as well as for other backends. # AudioOutputMethod "pulse" # -- Pulse Audio parameters -- # Pulse audio server name or "default" for the default pulse server #AudioPulseServer "default" #AudioPulseMinLength 1764 # -- ALSA parameters -- # Audio device for ALSA output #AudioALSADevice "default" # -- OSS parameters -- # Audio device for OSS output #AudioOSSDevice "/dev/dsp" # -- NAS parameters -- # Route to the Network Audio System server when NAS # is chosen for the audio output. Note that NAS # server doesn't need to run on your machine, # you can use it also over network (for instance # when working on remote machines). #AudioNASServer "tcp/localhost:5450" # -----OUTPUT MODULES CONFIGURATION----- # Each AddModule line loads an output module. # Syntax: AddModule "name" "binary" "configuration" "logfile" # - name is the name under which you can access this module # - binary is the path to the binary executable of this module, # either relative (to lib/speech-dispatcher-modules/) or absolute # - configuration is the path to the config file of this module, # either relative (to etc/speech-dispatcher/modules/) or absolute #AddModule "espeak" "sd_espeak" "espeak.conf" #AddModule "espeak-ng" "sd_espeak-ng" "espeak-ng.conf" #AddModule "festival" "sd_festival" "festival.conf" #AddModule "flite" "sd_flite" "flite.conf" #AddModule "ivona" "sd_ivona" "ivona.conf" #AddModule "pico" "sd_pico" "pico.conf" #AddModule "espeak-generic" "sd_generic" "espeak-generic.conf" #AddModule "espeak-ng-mbrola-generic" "sd_generic" "espeak-ng-mbrola-generic.conf" #AddModule "espeak-mbrola-generic" "sd_generic" "espeak-mbrola-generic.conf" #AddModule "swift-generic" "sd_generic" "swift-generic.conf" #AddModule "epos-generic" "sd_generic" "epos-generic.conf" #AddModule "dtk-generic" "sd_generic" "dtk-generic.conf" #AddModule "pico-generic" "sd_generic" "pico-generic.conf" #AddModule "ibmtts" "sd_ibmtts" "ibmtts.conf" #AddModule "cicero" "sd_cicero" "cicero.conf" #AddModule "kali" "sd_kali" "kali.conf" #AddModule "mary-generic" "sd_generic" "mary-generic.conf" #AddModule "baratinoo" "sd_baratinoo" "baratinoo.conf" #AddModule "rhvoice" "sd_rhvoice" "rhvoice.conf" #AddModule "voxin" "sd_voxin" "voxin.conf" # DO NOT REMOVE the following line unless you have # a specific reason -- this is the fallback output module # that is only used when no other modules are in use #AddModule "dummy" "sd_dummy" "" # The output module testing doesn't actually connect to anything. It # outputs the requested commands to standard output and reads # responses from stdandard input. This way, Speech Dispatcher's # communication with output modules can be tested easily. # AddModule "testing" # The DefaultModule selects which output module is the default. You # must use one of the names of the modules loaded with AddModule. DefaultModule espeak-ng # The LanguageDefaultModule selects which output modules are prefered # for specified languages. #LanguageDefaultModule "en" "espeak" #LanguageDefaultModule "cs" "festival" #LanguageDefaultModule "es" "festival" # -----CLIENT SPECIFIC CONFIGURATION----- # Here you can include the files with client-specific configuration # for different types of clients. They must contain one or more sections with # this structure: # BeginClient "emacs:*" # DefaultPunctuationMode "some" # ...and/or some other settings # EndClient # The parameter of BeginClient tells Speech Dispatcher which clients # it should apply the settings to (it does glob-style matching, you can use # * to match any number of characters and ? to match one character) # There are some sample client settings Include "clients/*.conf" # The DisableAutoSpawn option will disable the autospawn mechanism. # Thus the server will not start automatically on requests from the clients # DisableAutoSpawn # Copyright (C) 2001-2009 Brailcom, o.p.s # Copyright (C) 2009 Rui Batista # Copyright (C) 2010 Andrei Kholodnyi # Copyright (C) 2010 William Hubbs # Copyright (C) 2010 Trevor Saunders # Copyright (C) 2012 William Jon McCann # Copyright (C) 2014 Rob Whyte # Copyright (C) 2014-2016 Luke Yelavich # Copyright (C) 2014 Hussain Jasim # Copyright (C) 2017 Colomban Wendling # Copyright (C) 2018 RaphaĂŤl POITEVIN # Copyright (C) 2018 Florian Steinhardt # Copyright (C) 2018 Samuel Thibault # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . speech-dispatcher-0.9.1/config/Makefile.am0000644000175000017500000000152213406251124015334 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in SUBDIRS= modules clients dist_spdconf_DATA= speechd.conf dist_spdconforig_DATA= speechd.conf -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/0000755000175000017500000000000013465234514012713 500000000000000speech-dispatcher-0.9.1/src/tests/0000755000175000017500000000000013465234514014055 500000000000000speech-dispatcher-0.9.1/src/tests/sayfortune.sh0000644000175000017500000000200213406253016016513 00000000000000#!/bin/bash # Copyright (C) 2003-2005 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ./sayfortune.sh [topic [rate [pitch]] # e.g.: ./sayfortune.sh # ./sayfortune.sh literature 0 -20 printf "!SET SELF PRIORITY TEXT\n!SET SELF RATE $2\n!SET SELF PITCH $3\n!SPEAK \n `fortune $1` \n.\n S3" > fortune-speechd.tmp ./run_test fortune-speechd.tmp rm fortune-speechd.tmp speech-dispatcher-0.9.1/src/tests/c_api.at0000644000175000017500000000207613406252757015407 00000000000000# c_api.at - libspeechd library tests # # Copyright (C) 2010 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . AT_BANNER([C API]) AT_SETUP([c_api]) AT_KEYWORDS([clibrary]) AT_CHECK([${abs_builddir}/clibrary], [0], [ignore]) AT_KEYWORDS([clibrary2]) AT_CHECK([${abs_builddir}/clibrary2], [0], [ignore]) #AT_KEYWORDS([connection-recovery]) #AT_CHECK([${abs_builddir}/connection-recovery], [0], [ignore]) AT_KEYWORDS([long_message]) AT_CHECK([${abs_builddir}/long_message], [0], [ignore]) AT_CLEANUP speech-dispatcher-0.9.1/src/tests/testsuite.at0000644000175000017500000000143013406253040016340 00000000000000# testsuite.at - main file for autotest based tests # # Copyright (C) 2010 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . AT_INIT AT_COPYRIGHT([Copyright (C) 2010 Brailcom, o.p.s.]) m4_include([c_api.at]) speech-dispatcher-0.9.1/src/tests/yo.wav0000644000175000017500000001067211447133620015143 00000000000000RIFF˛WAVEfmt w+w+dataŽ~~~~~~~~~~~~~~~€€€€€€€€€€~~~~~~~~~~€€€€€€~~~~~~~~~~~~~~~~~~€€€€€€€~~~~~~~~~~~~€€€€~~~~~~~~~~~~~~~~~€€€€~~~~~~~~~~~~~~~~~€~~~~~~~~~~~~~~~~~~~~~€€€€~~~~~~~~~~~~~~€€€~~~~~~~~~~~~~~~~~~~~~~€€€€€€€~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}~~}~€€€€€€€€€€€~~~~~~~~~~~~~€€€€€€€€~~~}}~~~~~~€€€€€€€€€€~~~~~~~~~~~€€€~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~€€€€€~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~}}||||||||||||}}}}}~~~~~~~~~€€€€€€€€‚‚‚‚‚‚ƒƒƒƒƒ‚‚‚‚€}|{yxwvuuuuuvvwxyz{||}~€€€~~~~~~~~€€‚‚‚ƒ„…………††‡‡‡ˆ‰ŠŠ‹Š‡†…wvtomlijmnoqswz{{ƒ…††ˆŠ‰ˆˆ†„ƒ}|{yyxwwxxxyz{|}}€‚ƒ„„……„ƒ‚‚‚‚€{~}z||z{{{{{}~‚‚ƒ„„„„„ƒ‚‚‚‚‚€€~}|}}||||||}||}}}}}}}}}}}}}~~~~~~}}}~~~~€€€€€‚€~~~~~~~~€€€‚‚ƒƒƒ„………††††…„„ƒ~}{wvtrqpppqrsuvx{|}‚ƒ„„„……„„ƒ€}{zyxxwwxyyyz{|}~€‚‚ƒ„…††††††…„ƒ‚‚€€€€‚ƒ„…‡‰‹ŽŽ‡ƒzu{tlnkcbgjjijqwwy€‡Šˆˆ‹ŒŒŠˆ†…ƒ|zzxvuttuvuuwyz|}~€ƒ……‡ˆ‰Š‰ˆ‡†…„‚~~~~€ƒƒƒ…ˆ‰‹ŒŽŽ‰„ƒƒ}tpnjfedbbeijlouz}‚†‰ŒŽŽŽŽŽ‹ˆ†„‚{xusqpnnnoqsuwz~ƒ„‡‰Š‹Œ‹‹ŠŠ‰†…„ƒ‚€€‚‚ƒ…ˆ‹‘”—˜—‘…ƒˆ‚rigd`[UTVX\cfhoz‚†ŠŽ”š›™™˜–“‹„{wsnjhhggghlpsvz~‚†ˆ‰‹ŒŽŒŠˆˆ‡„€~~~~„†‡‰Œ‘”–˜šœ ¤¤ž†p}ŒvSEMWVG # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ This script is used to test VOICE functionality @ in Speech Dispatcher. $ 3 !SET SELF VOICE MALE1 !SPEAK This is the male 1 voice. . $ 3 !SET SELF VOICE MALE2 !SPEAK This is the male 2 voice. . $ 3 !SET SELF VOICE MALE3 !SPEAK This is the male 3 voice. . $ 3 !SET SELF VOICE FEMALE1 !SPEAK This is the female 1 voice. . $ 3 !SET SELF VOICE FEMALE2 !SPEAK This is the female 2 voice. . $ 3 !SET SELF VOICE FEMALE3 !SPEAK This is the female 3 voice. . $ 3 !SET SELF VOICE CHILD_MALE !SPEAK This is the child male voice. . $ 3 !SET SELF VOICE CHILD_FEMALE !SPEAK This is the child female voice. . !QUIT speech-dispatcher-0.9.1/src/tests/stop_and_pause.test0000644000175000017500000000471313406253033017677 00000000000000# Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ Test stop and pause functions in Speech Dispatcher. @ Note that not all synthesizers (output modules) support effective @ stop and pause. If they do not, they should at least not crash @ or mangle the speech. !SET SELF NOTIFICATION ALL ON @ We'll begin by queueing a paragraph, waiting 2 seconds, stopping, @ and then queueing another message. The paragraph contains several @ sentences. If stop is working well, the speech should stop instantly, @ even if in the middle of a sentence. The second message should @ not be prevented from being heard. $4 !SPEAK When in the Course of human events it becomes necessary for one people to dissolve the political bands which have connected them with another and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation. -- United States Declaration of Independence . +BEGIN $2 !STOP SELF $3 !SPEAK The previous stop should not prevent this sentence from being heard. . $3 @ Now we'll queue another request, pause it two seconds later, wait @ 8 seconds, and resume. If working well, the pause should occur on @ a sentence boundary. It is acceptable if it pauses immediately, @ like a stop, but when resumed, it should repeat the last partial @ sentence. $2 !SPEAK Jack and Jill went up the hill to fetch a pail of water. Jack fell down and broke his crown, and Jill came tumbling after. This sentence should not be heard until resumed. . +701 BEGIN !PAUSE SELF +704 PAUSED @ Speaking should now be paused. Resuming in 4 seconds. $4 !RESUME SELF +705 RESUMED +702 END !QUIT @ Tests completed. speech-dispatcher-0.9.1/src/tests/ssml.test0000644000175000017500000000653013406253032015647 00000000000000# Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ Hi, this is a test for SSML support in Speech Dispatcher. @ Note that not all synthesizers (output modules) support SSML. @ If they do not, they should still speak but should not speak any @ of the SSML tags. !SET SELF NOTIFICATION END ON @ We'll begin with a simple message. $4 !SET SELF SSML_MODE ON !SPEAK S S M L or Speech Synthesis Markup Language is an XML language that provides authors of synthesizable content a standard way to control aspects of speech such as pronunciation, volume, pitch, rate, etc. across different synthesis-capable platforms. . +702 END @ If you heard the full message, Speech Dispatcher @ works correctly. $2 @ Now we will try changing the volume in mid-sentence. $2 !SPEAK This sentence starts out normally, but then speaks loudly, and ends very softly. . +702 END @Let's try increasing the speaking rate in mid-sentence. $2 !SPEAK Political language - and with variations this is true of all political parties, from Conservatives to Anarchists - is designed to make lies sound truthful and murder respectable, and to give an appearance of solidity to pure wind. -- George Orwell (1903 - 1950), 1946 . +702 END $2 @ This time, slower in mid-sentence. $2 !SPEAK The secret of staying young is to live honestly, eat slowly, and lie about your age. -- Lucille Ball (1911 - 1989) . +702 END $2 @ How about changing gender in mid-sentence? @ Since most synthesizers do not support changing voices in the middle @ of synthesis, this may not work. $4 !SPEAK Nobody will ever win the Battle of the Sexes. There's just too much fraternizing with the enemy. -- Henry Kissinger (1923 -) . +702 END $2 @ Let's see if a change in speaker's age to 8 years old can be accomplished. $2 !SPEAK Human beings are the only creatures that allow their children to come back home. -- Bill Cosby (1937 - ) . +702 END $2 @ SSML permits sound files to be embedded in speech. @ If this works, you should hear a man say "Yo" (as in hello). $2 !SPEAK He was heard to say . +702 END $2 !QUIT @ If the tests did what was expected, your installation of Speech Dispatcher @ probably works fine. If not, there can be different causes, see @ the documentation -- Troubleshooting. (Note that some synthesizers @ don't support SSML. If everything else worked correctly, this is not a @ fatal problem.). speech-dispatcher-0.9.1/src/tests/spelling.test0000644000175000017500000000314313406253031016502 00000000000000# Copyright (C) 2003 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ Hello, this is a spelling test @ Set parameters and test if Speech Dispatcher works !SET SELF CLIENT_NAME unknown_user:test-spelling:main !SET SELF PRIORITY MESSAGE !SPEAK I'm ok. . @ Try to say something with spelling on: !SET SELF SPELLING ON !SPEAK The most beautiful experience we can have is the mysterious. It is the fundamental emotion which stands at the cradle of true art and true science. -- Albert Einstein (1879-1955) U. S. physicist, born in Germany . $30 @ Turn spelling off !SET SELF SPELLING OFF !SPEAK One thing that makes the adventure of working in our field particularly rewarding, especially in attempting to improve the theory, is that... a chief criterion for the selection of a correct hypothesis... seems to be the criterion of beauty, simplicity, or elegance. -- Murray Gell-Mann (1929- ) U. S. Physicist (Nobel Prize, 1969) . $30 @ Ok, bye... !QUIT speech-dispatcher-0.9.1/src/tests/sound_icons.test0000644000175000017500000000270413406253017017216 00000000000000# Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ This script is used to test SOUND ICON functionality @ in Speech Dispatcher. @ Note that these tests assume you have the free(b)soft @ sound-icons package installed (apt-get install sound-icons). @ We will send a sentence, a sound icon, and another sentence. @ You should hear them in that order. $ 5 !SPEAK When the system is ready for your input, you will hear the following sound. . !SOUND_ICON prompt !SPEAK You may then enter your response. . $8 @ Some more sound icons. $2 !SOUND_ICON start $3 !SOUND_ICON message $4 @ Sound icon names are case sensitive, therefore it is normal @ to hear the name of the icon for the next test. If you do hear the icon, @ that is OK too. $4 !SOUND_ICON PROMPT $2 !QUIT speech-dispatcher-0.9.1/src/tests/punctuation.test0000644000175000017500000000531313406253010017234 00000000000000# Copyright (C) 2003 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ Hello, this is a punctuation test @ Set parameters and test if Speech Dispatcher works !SET SELF CLIENT_NAME unknown_user:test-basic:main !SET SELF PRIORITY MESSAGE !SPEAK I'm ok. . @ Try to say something with all punctuation symbols: !SET SELF PUNCTUATION ALL !SPEAK "I quite agree with you," said the Duchess; "and the moral of that is -- `Be what you would seem to be' -- or, if you'd like it put more simply -- `Never imagine yourself not to be otherwise than what it might appear to others that what you were or might have been was not otherwise than what you had been would have appeared to them to be otherwise.'" -- Lewis Carrol, "Alice in Wonderland" . $30 @ Now only selected symbols (as defined in speechd.conf): !SET SELF PUNCTUATION SOME !SET SELF PUNCTUATION_IMPORTANT ".,;" !SPEAK A famous Lisp Hacker noticed an Undergraduate sitting in front of a Xerox 1108; trying to edit a complex Klone network via a browser. Wanting to help, the Hacker clicked one of the nodes in the network with the mouse, and asked "what do you see?" Very earnestly, the Undergraduate replied "I see a cursor." The Hacker then quickly pressed the boot toggle at the back of the keyboard, while simultaneously hitting the Undergraduate over the head with a thick Interlisp Manual. The Undergraduate was then Enlightened. . $30 @ Switch punctuation off for this message @ This means that you shouldn't hear the names of the punctuation @ symbols ("dot", "coma", etc.), but the intonation, where supported @ by the synthesizer, should be conserved. !SET SELF PUNCTUATION NONE !SPEAK I do not know what I may appear to the world; but to myself I seem to have been only like a boy playing on the seashore, and diverting myself in now and then finding of a smoother pebble or a prettier shell than ordinary, whilst the great ocean of truth lay all undiscovered before me. -- Sir Isaac Newton (1642-1727) English physicist, mathematician. . $20 @ List all tables available for punctuation @ Ok, bye... !QUIT speech-dispatcher-0.9.1/src/tests/pronunciation.test0000644000175000017500000000443413406253007017564 00000000000000# Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ This tests how well the synthesizer handles variations of @ pronunciation. !SPEAK Hints on pronunciation for foreigners. I take it you already know Of tough and bough and cough and dough? Others may stumble, but not you, on hiccough, thorough, laugh and through... Well done! And now you wish, perhaps, To learn of less familiar traps. Beware of heard: a dreadful word That looks like beard and sounds like bird. And dead: it's said like bed not bead - For goodness' sake don't call it deed. Watch out for meat and great and threat (They rhyme with suite and straight and debt!) A moth is not a moth in mother; Nor both in bother, broth in brother; And here is not a match for there, Nor dear and fear, for bear and pear. And then there's dose and rose and lose, (Just look them up), and goose and choose, And cork and work and card and ward, And font and front and word and sword, And do and go and thwart and cart... Come, come! I've hardly made a start. A dreadful language? Man alive! I'd mastered it when I was five! I will teach you in my verse, Words like corps, corks, horse and worse. For this phonetic labyrinth Gives monkey, donkey, ninth and plinth; Wounded, rounded, grieve and sieve; Friend and fiend; alive and live. Query does not rhyme with very, Nor does fury sound like bury. Dies and diet; lord and word, Earth and hearth and clerk and herd; Evil, devil, tomb, bomb, comb; Doll, roll, dull, bull, some and home. Finally - for I've said enough - Through though thorough plough cough tough! While hiccough has the sound of cup... My advice is: give it up! . !QUIT speech-dispatcher-0.9.1/src/tests/priority_progress.test0000644000175000017500000000251013406253005020470 00000000000000# Copyright (C) 2006 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ This is a test for the priority progress $ 1 !SET SELF OUTPUT_MODULE flite !SET SELF PRIORITY MESSAGE !SOUND_ICON start !SET SELF PRIORITY PROGRESS !SPEAK 1 . !SPEAK 2 . !SPEAK 3 . !SPEAK 4 . !SPEAK 5 . !SPEAK 6 . !SPEAK 7 . !SPEAK 8 . !SPEAK 9 . !SPEAK 10 . !SPEAK 11 . !SPEAK 12 . !SPEAK 13 . !SPEAK 15 . !SPEAK 16 . !SPEAK 17 . !SPEAK 18 . !SPEAK 19 . !SPEAK 20 . !SPEAK 21 . !SPEAK 22 . !SPEAK 23 . !SPEAK 24 . !SPEAK 25 . !SPEAK 26 . !SPEAK 27 . !SPEAK 28 . !BLOCK BEGIN !SPEAK "block part one" . !SOUND_ICON prompt !SPEAK "block part two" . !BLOCK END !SET SELF PRIORITY MESSAGE !SPEAK This is the end of test. . $ 15 speech-dispatcher-0.9.1/src/tests/keys.test0000644000175000017500000001652313406253000015642 00000000000000# Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ This test speaks every defined keyboard key name and special character in the latin-1 @ character set using the KEY SSIP command. Useful for output module debugging. @ The pronounced names for characters are in English. @ IMPORTANT: Because of non-English characters in this file be sure to edit it with @ UTF-8 editor! !SPEAK Special Key Names: . !KEY space !KEY underscore !KEY double-quote !SPEAK Auxiliary Keys: . !KEY alt !KEY control !KEY hyper !KEY meta !KEY shift !KEY super !SPEAK Control Character Keys: . !KEY backspace !KEY break !KEY delete !KEY down !KEY end !KEY enter !KEY escape !KEY f1 !KEY f2 !KEY f3 !KEY f4 !KEY f5 !KEY f6 !KEY f7 !KEY f8 !KEY f9 !KEY f10 !KEY f11 !KEY f12 !KEY f13 !KEY f14 !KEY f15 !KEY f16 !KEY f17 !KEY f18 !KEY f19 !KEY f20 !KEY f21 !KEY f22 !KEY f23 !KEY f24 !KEY home !KEY insert !KEY kp-* !KEY kp-+ !KEY kp-- !KEY kp-. !KEY kp-/ !KEY kp-0 !KEY kp-1 !KEY kp-2 !KEY kp-3 !KEY kp-4 !KEY kp-5 !KEY kp-6 !KEY kp-7 !KEY kp-8 !KEY kp-9 !KEY kp-enter !KEY left !KEY menu !KEY next !KEY num-lock !KEY pause !KEY print !KEY prior !KEY return !KEY right !KEY scroll-lock !KEY space !KEY tab !KEY up !KEY window !SPEAK Special characters: . @ U+0021 !SPEAK Exclamation mark: . !KEY ! @ U+0022 !SPEAK Note that Double quote (") is not a valid key. Use "double-quote" instead. . @ !KEY " @ U+0023 !SPEAK Pound, Hash, or Sharp: . !KEY # @ U+0024 !SPEAK Dollar: . !KEY $ @ U+0025 !SPEAK Percent: . !KEY % @ U+0026 !SPEAK Ampersand: . !KEY & @ U+0027 !SPEAK Single quote, right quote, or apostrophe: . !KEY ' @ U+0028 !SPEAK Left parenthesis: . !KEY ( @ U+0029 !SPEAK Right parenthesis: . !KEY ) @ U+002A !SPEAK Asterisk: . !KEY * @ U+002B !SPEAK Plus: . !KEY + @ U+002C !SPEAK Comma: . !KEY , @ U+002D !SPEAK Hyphen: . !KEY - @ U+002E !SPEAK Period or dot: . !KEY . @ U+002F !SPEAK Slash: . !KEY / @ U+003A !SPEAK Colon: . !KEY : @ U+003B !SPEAK Semicolon: . !KEY ; @ U+003C !SPEAK Less than: . !KEY < @ U+003D !SPEAK Equals: . !KEY = @ U+003E !SPEAK Greater than: . !KEY > @ U+003F !SPEAK Question mark: . !KEY ? @ U+0040 !SPEAK At: . !KEY @ @ U+005B !SPEAK Left bracket: . !KEY [ @ U+005C !SPEAK Backslash: . !KEY \ @ U+005D !SPEAK Right bracket: . !KEY ] @ U+005E !SPEAK Caret. . !KEY ^ @ U+005F !SPEAK Note that underscore (_) is not a valid key. Use "underscore" instead. . @ !KEY _ @ U+0060 !SPEAK Backquote, Left quote, or backtick: . !KEY ` @ U+007B !SPEAK Left brace: . !KEY { @ U+007C !SPEAK Vertical bar or pipe: . !KEY | @ U+007D !SPEAK Right brace: . !KEY } @ U+007E !SPEAK Tilde: . !KEY ~ @ U+00A1 !SPEAK Inverted exclamation mark. . !KEY ÂĄ @ U+00A2 !SPEAK Cents: . !KEY ¢ @ U+00A3 !SPEAK British Pounds: . !KEY ÂŁ @ U+00A4 !SPEAK currency. . !KEY ¤ @ U+00A5 !SPEAK yen. . !KEY ÂĽ @ U+00A6 !SPEAK Vertical bar or pipe: . !KEY ÂŚ @ U+00A7 !SPEAK Section sign. . !KEY § @ U+00A8 !SPEAK Copyright: . !KEY Š @ U+00A9 !SPEAK umlaut or dierasis. . !KEY ¨ @ U+00AA !SPEAK Superscript a: . !KEY ÂŞ @ U+00AB !SPEAK German left quote: . !KEY ÂŤ @ U+00AC !SPEAK Optional hyphen: . !KEY ÂŹ @ U+00AD !SPEAK Dash: . !KEY ­ @ U+00AE !SPEAK Trademark: . !KEY ÂŽ @ U+00AF !SPEAK Macron: . !KEY ÂŻ @ U+00B0 !SPEAK Superscript 0, null, or degrees: . !KEY Âş @ U+00B1 !SPEAK Plus or minus: . !KEY Âą @ U+00B2 !SPEAK Superscript 2 or squared: . !KEY ² @ U+00B3 !SPEAK Superscript 3 or cubed: . !KEY Âł @ U+00B4 !SPEAK Acute accent: . !KEY ´ @ U+00B5 !SPEAK Mu or micro: . !KEY Âľ @ U+00B6 !SPEAK pilcrow or paragraph: . !KEY Âś @ U+00B7 !SPEAK Dot: . !KEY ¡ @ U+00B8 !SPEAK Cedilla: . !KEY ¸ @ U+00B9 !SPEAK Superscript 1: . !KEY š @ U+00BA !SPEAK Superscript 0 or degrees: . !KEY Âş @ U+00BB !SPEAK German right quote: . !KEY Âť @ U+00BC !SPEAK One fourth or quarter: . !KEY Âź @ U+00BD !SPEAK One half: . !KEY ½ @ U+00BE !SPEAK Three fourths or 3 quarters: . !KEY ž @ U+00BF !SPEAK inverted question mark: . !KEY Âż @ U+00D7 !SPEAK Times. . !KEY × @ U+00F7 !SPEAK Divide, divided by, or division. . !KEY á !SPEAK Non-English letters: . @ U+00C0 !SPEAK Capital A grav: . !KEY À @ U+00C1 !SPEAK Capital A acute: . !KEY Á @ U+00C2 !SPEAK Capital A circumflex: . !KEY  @ U+00C3 !SPEAK Capital A tilde: . !KEY à @ U+00C4 !SPEAK Capital A umlaut: . !KEY Ä @ U+00C5 !SPEAK Capital A dot: . !KEY Å @ U+00C6 !SPEAK Capital ay e: . !KEY Æ @ U+00C7 !SPEAK Capital C cedilla: . !KEY Ç @ U+00C8 !SPEAK Capital E grav: . !KEY È @ U+00C9 !SPEAK Capital E acute: . !KEY É @ U+00CA !SPEAK Capital E circumflex: . !KEY Ê @ U+00CB !SPEAK Capital E umlaut: . !KEY Ë @ U+00CC !SPEAK Capital I grav: . !KEY Ì @ U+00CD !SPEAK Capital I acute: . !KEY Í @ U+00CE !SPEAK Capital I circumflex: . !KEY Î @ U+00CF !SPEAK Capital I umlaut: . !KEY Ï @ U+00D0 !SPEAK Capital eth: . !KEY Ð @ U+00D1 !SPEAK Capital N tilde or enni: . !KEY Ñ @ U+00D2 !SPEAK Capital O grav: . !KEY Ò @ U+00D3 !SPEAK Capital O acute: . !KEY Ó @ U+00D4 !SPEAK Capital O circumflex: . !KEY Ô @ U+00D5 !SPEAK Capital O tilde: . !KEY Õ @ U+00D6 !SPEAK Capital O umlaut: . !KEY Ö @ U+00D8 !SPEAK Capital Phi or Capital Oh: . !KEY Ø @ U+00D9 !SPEAK Capital U grav: . !KEY Ù @ U+00DA !SPEAK Capital U acute: . !KEY Ú @ U+00DB !SPEAK Capital U circumflex: . !KEY Û @ U+00DC !SPEAK Capital U umlaut: . !KEY Ü @ U+00DD !SPEAK Capital Y acute: . !KEY Ý @ U+00DE !SPEAK thorn: . !KEY Þ @ U+00DF !SPEAK eztset: . !KEY ß @ U+00E0 !SPEAK ay grav: . !KEY Ă  @ U+00E1 !SPEAK ay acute: . !KEY ĂĄ @ U+00E2 !SPEAK ay circumflex: . !KEY â @ U+00E3 !SPEAK ay tilde: . !KEY ĂŁ @ U+00E4 !SPEAK ay umlaut: . !KEY ä @ U+00E5 !SPEAK ay dot: . !KEY ĂĽ @ U+00E6 !SPEAK ay e: . !KEY ĂŚ @ U+00E7 !SPEAK c cedilla: . !KEY ç @ U+00E8 !SPEAK e grav: . !KEY è @ U+00E9 !SPEAK e acute: . !KEY ĂŠ @ U+00EA !SPEAK e circumflex: . !KEY ĂŞ @ U+00EB !SPEAK e umlaut: . !KEY ĂŤ @ U+00EC !SPEAK i grav: . !KEY ĂŹ @ U+00ED !SPEAK i acute: . !KEY Ă­ @ U+00EE !SPEAK i circumflex: . !KEY ĂŽ @ U+00EF !SPEAK i umlaut: . !KEY ĂŻ @ U+00F0 !SPEAK eth: . !KEY ð @ U+00F1 !SPEAK n tilde: . !KEY Ăą @ U+00F2 !SPEAK o grav: . !KEY ò @ U+00F3 !SPEAK o acute: . !KEY Ăł @ U+00F4 !SPEAK o circumflex: . !KEY Ă´ @ U+00F5 !SPEAK o tilde: . !KEY Ăľ @ U+00F6 !SPEAK o umlaut: . !KEY Ăś @ U+00F8 !SPEAK Phi or oh: . !KEY ø @ U+00F9 !SPEAK u grav: . !KEY Ăš @ U+00FA !SPEAK u acute: . !KEY Ăş @ U+00FB !SPEAK u circumflex: . !KEY Ăť @ U+00FC !SPEAK u umlaut: . !KEY Ăź @ U+00FD !SPEAK y acute: . !KEY Ă˝ @ U+00FE !SPEAK Capital thorn: . !KEY Ăž @ U+00FF !SPEAK y umlaut or yummel: . !KEY Ăż !SPEAK Examples of valid key names: . !KEY a !KEY A !KEY shift_a !KEY shift_A !KEY Ăş !KEY $ !KEY enter !KEY shift_kp-enter !KEY control_alt_delete !KEY control !QUIT speech-dispatcher-0.9.1/src/tests/general.test0000644000175000017500000001534213406252776016325 00000000000000# Copyright (C) 2003 Brailcom, o.p.s # Copyright (C) 2006 Gary Cramblitt # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ~5 * @ Welcome, LSM 2003 @ this is a tour through SSIP! @ SSIP stands for Speech Synthesis Internet Protocol, @ It's the actual interface to Speech Dispatcher. ? * @ Introductory examples I @ Let's try our first commands. ? !SET SELF CLIENT_NAME unknown:run_test:main !SET SELF OUTPUT_MODULE flite !SPEAK Hello all, welcome at Libre Software Meeting 2003! . ? * @ Introductory examples II @ Now something more complicated. @ We will switch our output module to Festival. !SET SELF OUTPUT_MODULE festival ? @ Set the voice rate a little bit lower. !SET SELF RATE -20 ? !SPEAK I have often regretted my speech, never my silence. -- Publilius Syrus . ? * @ S S I P --- Basic ideas @ @ * Communication `client library' <--> `Speech Dispatcher' @ @ * Synchronous TCP/IP protocol @ (remote hosts) @ @ * Strict separation between client and the actual synthesis @ (abstract voice names, output module selection, ...) @ @ * Priorities @ @ * All configuration is done by user in Speech Dispatcher @ @ * Multiple connections per client ? * @ S S I P --- Command families @ @ * Speech synthesis / sound output @ (SPEAK, CHAR, KEY, SOUND_ICON) @ @ * Speech output control @ (STOP, CANCEL, PAUSE, RESUME) @ @ * Parameter setting @ (RATE, PITCH, TABLES, VOICE, ...) @ @ * Information retrieval @ (not necessary) @ @ * History of messages @ (very important for visually impaired) ? * @ More examples -- Languages and output modules @ Again the English voice (english is default). !SPEAK I call our world Flatland, not because we call it so, but to make its nature clearer to you, my happy readers, who are privileged to live in Space. Imagine a vast sheet of paper on which straight Lines, Triangles, Squares, Pentagons, Hexagons, and other figures, instead of remaining fixed in their places, move freely about, on or in the surface, but without the power of rising above or sinking below it, very much like shadows--only hard with luminous edges--and you will then have a pretty correct notion of my country and countrymen. Alas, a few years ago, I should have said "my universe:" but now my mind has been opened to higher views of things. (an excerpt from ``Flatland, The romance of many dimensions by Edwin Abbot'') . ? @ Now we can try to set some exotic language ;) ? !SET SELF LANGUAGE cs !SPEAK Ahoj lidi, jak se mĂĄte? JĂĄ se mĂĄm skvěle! VĂ­te, jĂĄ sem straĹĄně ukecanej, ale nikdo si se mnou nechce povĂ­dat. . @ Or another exotic language ? !SET SELF LANGUAGE es !SPEAK Hola, como estais? Alguien habla espanol aqui? Es que es una lengua muy bonita! . !SET SELF LANGUAGE en ? * @ Text processing -- Examples @ When reading books, it's best to just listen to the text, @ but when a visually impaired person wants to edit some @ text, it is handy if there is some recognition of @ the present punctuation characters, capital letters, etc. ? @ This will pronounce all punctuation characters and @ additionally produce a sound before each capital letter. ? !SET SELF PUNCTUATION all !SET SELF CAP_LET_RECOGN icon !SPEAK As I talked to these digital explorers, ranging from those who tamed multimillion-dollar machines in the 1950s to contemporary young wizards who mastered computers in their suburban bedrooms, I found a common element, a common philosophy which seemed tied to the elegantly flowing logic of the computer itself. It was a philosophy of sharing, openness, decentralization, and getting your hands on machines at any cost -- to improve the machines, and to improve the world. This Hacker Ethic is their gift to us: something with value even to those of us with no interest at all in computers. (Hackers, Heroes of the computer revolution, Stevan Levy) . ? !SET SELF PUNCTUATION none !SET SELF CAP_LET_RECOGN none @ Note that we have used an icon to signal capital letters. ? * @ Sound icons --- Basic concepts @ * Symbolic names @ @ * Sound or text for synthesis @ @ * Application specific sound icons @ @ * Different sound tables ? * @ Sound icons --- Examples @ We will try some sound icons to see how they work. ? !SOUND_ICON warning ? !SOUND_ICON endofline ? @ Sound icons can be used in user-machine dialog systems @ (in telephony systems, etc.) ? * @ Priorities --- Examples I @ We will send two messages with different priorities at once. ? !SET SELF PRIORITY NOTIFICATION !SPEAK You can move around this page with cursor keys. . !SET SELF PRIORITY MESSAGE !SPEAK Accept cookie [Y/N/A]? . ? * @ Priorities --- Examples II @ Or take for example this situation, where the user requested @ his application to read some text but then changed his mind. !SET SELF PRIORITY TEXT !SPEAK Ludwig van Beethoven (1770-1827) is widely considered to be one of the pre-eminent classical music figures of the Western world. This German musical genius created numerous works that are firmly entrenched in the repertoire. Except for a weakness in composing vocal and operatic music (to which he himself admitted, notwithstanding a few vocal works like the opera "Fidelio" and the song "Adelaide,"), Beethoven had complete mastery of the artform. . !SPEAK He left his stamp in 9 symphonies, 5 piano concertos, 10 violin sonatas, 32 piano sonatas, numerous string quartets and dozens of other key works. . ? * @ Q U E S T I O N S ? @ Discussed topics: @ * General SSIP ideas @ @ * Configuration is independent of client applications @ @ * Message processing @ @ * Sound icons @ @ * Priorities @ Further topics: @ @ * Synchronous vs. asynchronous protocol (or both?) @ * ? @ * Whatever speech-dispatcher-0.9.1/src/tests/basic.test0000644000175000017500000000621013406252755015760 00000000000000# Copyright (C) 2003 Brailcom, o.p.s # Copyright (C) 2006 Gary Cramblitt # Copyright (C) 2014 Hussain Jasim # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # @ Hi, this is a basic Speech Dispatcher test. @ I've successfully connected to the server @ and now I'm going to try to set my client name @ and priority for the messages. $4 !SET SELF CLIENT_NAME unknown_user:test-basic:main $4 !SET SELF PRIORITY MESSAGE $4 @ Hope it was ok. Now I can try to say something: $8 !SPEAK Hello world, this is Speech Dispatcher speaking. . $2 @ If you heard the full message, Speech Dispatcher @ works correctly. $8 @ Now we will try some settings. $2 @ This message should be said very quickly... $4 !SET SELF RATE +80 !SPEAK You have to run as fast as you can just to stay where you are. If you want to get anywhere, you'll have to run much faster. -- Lewis Carroll . $8 @ ...and this very slowly. $4 !SET SELF RATE -80 !SPEAK There is more to life than increasing its speed. -- Mahatma Gandhi . $8 @ We will keep the rate at this level and try to make the voice @ whisper by increasing its pitch. $4 !SET SELF PITCH 90 !SPEAK Do not believe in miracles -- rely on them. . $8 @ We will keep the pitch at this level and try to increase the pitch range. $4 !SET SELF PITCH_RANGE 75 !SPEAK War has always been the grand sagacity of every spirit which has grown too inward and too profound; its curative power lies even in the wounds one receives. . $8 @ This time, we will return to normal speed, but decrease the pitch. @ Some distortion is probably unavoidable. $4 !SET SELF RATE 0 !SET SELF PITCH -90 !SPEAK I detest that man who hides one thing in the depths of his heart, and speaks for another. -- Homer (800 BC - 700 BC) . $8 @ Let's return to normal but try speaking loudly. @ Since most synthesizers already speak near maximum volume, you may not @ hear any difference. $4 !SET SELF PITCH 0 !SET SELF VOLUME 90 !SPEAK Actions lie louder than words. -- Carolyn Wells . $8 @ And finally, very softly. $4 !SET SELF VOLUME -90 !SPEAK What you do speaks so loud that I cannot hear what you say. -- Ralph Waldo Emerson (1803 - 1882) . $8 !QUIT @ If the tests did what was expected, your installation of Speech Dispatcher @ probably works fine. If not, there can be different causes, see @ the documentation -- Troubleshooting. (Note that some synthesizers @ don't have to support setting of the voice parameters. If everything @ else worked correctly, this is not a fatal problem.). speech-dispatcher-0.9.1/src/tests/spd_set_notifications_all.c0000644000175000017500000001225513423333245021363 00000000000000/* * spd_set_notifications_all.c - test SPD_ALL behaviour * * Copyright (C) 2010 Brailcom, o.p.s. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include "speechd_types.h" #include "libspeechd.h" #define TEST_NAME __FILE__ #define TEST_WAIT_COUNT (100) static int notification_mask; static SPDConnection *spd; static const char *events[] = { "SPD_EVENT_BEGIN", "SPD_EVENT_END", "SPD_EVENT_INDEX_MARK", "SPD_EVENT_CANCEL", "SPD_EVENT_PAUSE", "SPD_EVENT_RESUME" }; /* Callback for Speech Dispatcher notifications */ void notification_cb(size_t msg_id, size_t client_id, SPDNotificationType type) { notification_mask |= (1 << type); printf("notification %s received\n", events[type]); } void index_mark_cb(size_t msg_id, size_t client_id, SPDNotificationType type, char *index_mark) { notification_mask |= (1 << type); printf("notification %s received\n", events[type]); } int main(int argc, char *argv[]) { int result, count; /* Open Speech Dispatcher connection in THREADED mode. */ spd = spd_open(TEST_NAME, __FUNCTION__, NULL, SPD_MODE_THREADED); if (!spd) { printf("Speech-dispatcher: Failed to open connection. \n"); exit(1); } printf("Speech-dispatcher: connection opened. \n"); spd->callback_begin = notification_cb; spd->callback_end = notification_cb; spd->callback_cancel = notification_cb; spd->callback_pause = notification_cb; spd->callback_resume = notification_cb; spd->callback_im = index_mark_cb; /* Ask Speech Dispatcher to notify us about these events. */ result = spd_set_notification_on(spd, SPD_ALL); if (result == -1) { printf("Notification SPD_ALL not set correctly \n"); exit(1); } /* The message is spoken as SSML */ result = spd_set_data_mode(spd, SPD_DATA_SSML); if (result == -1) { printf("Could not set spd_set_data_mode() to SPD_DATA_SSML \n"); exit(1); } result = spd_say(spd, SPD_MESSAGE, " \ S S M L or Speech Synthesis Markup Language is an XML \ language. \ "); if (result == -1) { printf("spd_say() failed. \n"); exit(1); } count = 0; while (~notification_mask & SPD_BEGIN) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_BEGIN wait count exceeded \n"); exit(1); } } result = spd_pause(spd); if (result == -1) { printf("spd_pause() failed. \n"); exit(1); } count = 0; while (~notification_mask & SPD_PAUSE) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_PAUSE wait count exceeded \n"); exit(1); } } result = spd_say(spd, SPD_MESSAGE, " \ S S M L or Speech Synthesis Markup Language is an XML \ language. \ "); if (result == -1) { printf("spd_say() failed. \n"); exit(1); } result = spd_resume(spd); if (result == -1) { printf("spd_resume() failed. \n"); exit(1); } count = 0; while (~notification_mask & SPD_RESUME) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_PAUSE wait count exceeded \n"); exit(1); } } result = spd_say(spd, SPD_MESSAGE, " \ S S M L or Speech Synthesis Markup Language is an XML \ language. \ "); if (result == -1) { printf("spd_say() failed. \n"); exit(1); } count = 0; while (~notification_mask & SPD_INDEX_MARKS) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_INDEX_MARKS wait count exceeded \n"); exit(1); } } count = 0; while (~notification_mask & SPD_END) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_END wait count exceeded \n"); exit(1); } } result = spd_say(spd, SPD_MESSAGE, " \ S S M L or Speech Synthesis Markup Language is an XML \ language. \ "); if (result == -1) { printf("spd_say() failed. \n"); exit(1); } result = spd_cancel(spd); if (result == -1) { printf("spd_cancel() failed. \n"); exit(1); } count = 0; while (~notification_mask & SPD_CANCEL) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_CANCEL wait count exceeded \n"); exit(1); } } printf("All notifications received. \n"); spd_close(spd); printf("Speech-dispatcher: connection closed. \n"); exit(0); } speech-dispatcher-0.9.1/src/tests/spd_cancel_long_message.c0000644000175000017500000003713313423333245020761 00000000000000/* * spd_cancel_long_message.c - test SPD_CANCEL behaviour * * Copyright (C) 2010 Brailcom, o.p.s. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include "speechd_types.h" #include "libspeechd.h" #define TEST_NAME __FILE__ #define TEST_WAIT_COUNT (10) static int notification_mask; static SPDConnection *spd; static const char *events[] = { "SPD_EVENT_BEGIN", "SPD_EVENT_END", "SPD_EVENT_INDEX_MARK", "SPD_EVENT_CANCEL", "SPD_EVENT_PAUSE", "SPD_EVENT_RESUME" }; /* Callback for Speech Dispatcher notifications */ static void notification_cb(size_t msg_id, size_t client_id, SPDNotificationType type) { notification_mask |= (1 << type); printf("notification %s received\n", events[type]); } int main(int argc, char *argv[]) { int result, count; /* Open Speech Dispatcher connection */ spd = spd_open(TEST_NAME, __FUNCTION__, NULL, SPD_MODE_THREADED); if (!spd) { printf("Speech-dispatcher: Failed to open connection. \n"); exit(1); } printf("Speech-dispatcher: connection opened. \n"); spd->callback_cancel = notification_cb; /* Ask Speech Dispatcher to notify us about these events. */ result = spd_set_notification_on(spd, SPD_CANCEL); if (result == -1) { printf("Notification SPD_CANCEL not set correctly \n"); spd_close(spd); exit(1); } /* The message is spoken as TEXT */ result = spd_set_data_mode(spd, SPD_DATA_TEXT); if (result == -1) { printf("Could not set spd_set_data_mode() to SPD_DATA_TEXT \n"); spd_close(spd); exit(1); } printf("Sending a long message \n"); result = spd_say(spd, SPD_MESSAGE, "" " \n" " ALICE'S ADVENTURES IN WONDERLAND by Lewis Carroll.\n" "\n" " CHAPTER I: Down the Rabbit-Hole.\n" "\n" " Alice was beginning to get very tired of sitting by her sister\n" "on the bank, and of having nothing to do: once or twice she had\n" "peeped into the book her sister was reading, but it had no\n" "pictures or conversations in it, `and what is the use of a book,'\n" "thought Alice `without pictures or conversation?'\n" "\n" " So she was considering in her own mind (as well as she could,\n" "for the hot day made her feel very sleepy and stupid), whether\n" "the pleasure of making a daisy-chain would be worth the trouble\n" "of getting up and picking the daisies, when suddenly a White\n" "Rabbit with pink eyes ran close by her.\n" "\n" " There was nothing so VERY remarkable in that; nor did Alice\n" "think it so VERY much out of the way to hear the Rabbit say to\n" "itself, `Oh dear! Oh dear! I shall be late!' (when she thought\n" "it over afterwards, it occurred to her that she ought to have\n" "wondered at this, but at the time it all seemed quite natural);\n" "but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT-\n" "POCKET, and looked at it, and then hurried on, Alice started to\n" "her feet, for it flashed across her mind that she had never\n" "before seen a rabbit with either a waistcoat-pocket, or a watch to\n" "take out of it, and burning with curiosity, she ran across the\n" "field after it, and fortunately was just in time to see it pop\n" "down a large rabbit-hole under the hedge.\n" "\n" " In another moment down went Alice after it, never once\n" "considering how in the world she was to get out again.\n" "\n" " The rabbit-hole went straight on like a tunnel for some way,\n" "and then dipped suddenly down, so suddenly that Alice had not a\n" "moment to think about stopping herself before she found herself\n" "falling down a very deep well.\n" "\n" " Either the well was very deep, or she fell very slowly, for she\n" "had plenty of time as she went down to look about her and to\n" "wonder what was going to happen next. First, she tried to look\n" "down and make out what she was coming to, but it was too dark to\n" "see anything; then she looked at the sides of the well, and\n" "noticed that they were filled with cupboards and book-shelves;\n" "here and there she saw maps and pictures hung upon pegs. She\n" "took down a jar from one of the shelves as she passed; it was\n" "labelled `ORANGE MARMALADE', but to her great disappointment it\n" "was empty: she did not like to drop the jar for fear of killing\n" "somebody, so managed to put it into one of the cupboards as she\n" "fell past it.\n" "\n" " `Well!' thought Alice to herself, `after such a fall as this, I\n" "shall think nothing of tumbling down stairs! How brave they'll\n" "all think me at home! Why, I wouldn't say anything about it,\n" "even if I fell off the top of the house!' (Which was very likely\n" "true.)\n" "\n" " Down, down, down. Would the fall NEVER come to an end! `I\n" "wonder how many miles I've fallen by this time?' she said aloud.\n" "`I must be getting somewhere near the centre of the earth. Let\n" "me see: that would be four thousand miles down, I think--' (for,\n" "you see, Alice had learnt several things of this sort in her\n" "lessons in the schoolroom, and though this was not a VERY good\n" "opportunity for showing off her knowledge, as there was no one to\n" "listen to her, still it was good practice to say it over) `--yes,\n" "that's about the right distance--but then I wonder what Latitude\n" "or Longitude I've got to?' (Alice had no idea what Latitude was,\n" "or Longitude either, but thought they were nice grand words to\n" "say.)\n" "\n" " Presently she began again. `I wonder if I shall fall right\n" "THROUGH the earth! How funny it'll seem to come out among the\n" "people that walk with their heads downward! The Antipathies, I\n" "think--' (she was rather glad there WAS no one listening, this\n" "time, as it didn't sound at all the right word) `--but I shall\n" "have to ask them what the name of the country is, you know.\n" "Please, Ma'am, is this New Zealand or Australia?' (and she tried\n" "to curtsey as she spoke--fancy CURTSEYING as you're falling\n" "through the air! Do you think you could manage it?) `And what\n" "an ignorant little girl she'll think me for asking! No, it'll\n" "never do to ask: perhaps I shall see it written up somewhere.'\n" "\n" " Down, down, down. There was nothing else to do, so Alice soon\n" "began talking again. `Dinah'll miss me very much to-night, I\n" "should think!' (Dinah was the cat.) `I hope they'll remember\n" "her saucer of milk at tea-time. Dinah my dear! I wish you were\n" "down here with me! There are no mice in the air, I'm afraid, but\n" "you might catch a bat, and that's very like a mouse, you know.\n" "But do cats eat bats, I wonder?' And here Alice began to get\n" "rather sleepy, and went on saying to herself, in a dreamy sort of\n" "way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do\n" "bats eat cats?' for, you see, as she couldn't answer either\n" "question, it didn't much matter which way she put it. She felt\n" "that she was dozing off, and had just begun to dream that she\n" "was walking hand in hand with Dinah, and saying to her very\n" "earnestly, `Now, Dinah, tell me the truth: did you ever eat a\n" "bat?' when suddenly, thump! thump! down she came upon a heap of\n" "sticks and dry leaves, and the fall was over.\n" "\n" " Alice was not a bit hurt, and she jumped up on to her feet in a\n" "moment: she looked up, but it was all dark overhead; before her\n" "was another long passage, and the White Rabbit was still in\n" "sight, hurrying down it. There was not a moment to be lost:\n" "away went Alice like the wind, and was just in time to hear it\n" "say, as it turned a corner, `Oh my ears and whiskers, how late\n" "it's getting!' She was close behind it when she turned the\n" "corner, but the Rabbit was no longer to be seen: she found\n" "herself in a long, low hall, which was lit up by a row of lamps\n" "hanging from the roof.\n" "\n" " There were doors all round the hall, but they were all locked;\n" "and when Alice had been all the way down one side and up the\n" "other, trying every door, she walked sadly down the middle,\n" "wondering how she was ever to get out again.\n" "\n" " Suddenly she came upon a little three-legged table, all made of\n" "solid glass; there was nothing on it except a tiny golden key,\n" "and Alice's first thought was that it might belong to one of the\n" "doors of the hall; but, alas! either the locks were too large, or\n" "the key was too small, but at any rate it would not open any of\n" "them. However, on the second time round, she came upon a low\n" "curtain she had not noticed before, and behind it was a little\n" "door about fifteen inches high: she tried the little golden key\n" "in the lock, and to her great delight it fitted!\n" "\n" " Alice opened the door and found that it led into a small\n" "passage, not much larger than a rat-hole: she knelt down and\n" "looked along the passage into the loveliest garden you ever saw.\n" "How she longed to get out of that dark hall, and wander about\n" "among those beds of bright flowers and those cool fountains, but\n" "she could not even get her head though the doorway; `and even if\n" "my head would go through,' thought poor Alice, `it would be of\n" "very little use without my shoulders. Oh, how I wish\n" "I could shut up like a telescope! I think I could, if I only\n" "know how to begin.' For, you see, so many out-of-the-way things\n" "had happened lately, that Alice had begun to think that very few\n" "things indeed were really impossible.\n" "\n" " There seemed to be no use in waiting by the little door, so she\n" "went back to the table, half hoping she might find another key on\n" "it, or at any rate a book of rules for shutting people up like\n" "telescopes: this time she found a little bottle on it, (`which\n" "certainly was not here before,' said Alice,) and round the neck\n" "of the bottle was a paper label, with the words `DRINK ME'\n" "beautifully printed on it in large letters.\n" "\n" " It was all very well to say `Drink me,' but the wise little\n" "Alice was not going to do THAT in a hurry. `No, I'll look\n" "first,' she said, `and see whether it's marked \"poison\" or not';\n" "for she had read several nice little histories about children who\n" "had got burnt, and eaten up by wild beasts and other unpleasant\n" "things, all because they WOULD not remember the simple rules\n" "their friends had taught them: such as, that a red-hot poker\n" "will burn you if you hold it too long; and that if you cut your\n" "finger VERY deeply with a knife, it usually bleeds; and she had\n" "never forgotten that, if you drink much from a bottle marked\n" "`poison,' it is almost certain to disagree with you, sooner or\n" "later.\n" "\n" " However, this bottle was NOT marked `poison,' so Alice ventured\n" "to taste it, and finding it very nice, (it had, in fact, a sort\n" "of mixed flavour of cherry-tart, custard, pine-apple, roast\n" "turkey, toffee, and hot buttered toast,) she very soon finished\n" "it off.\n" "\n" " `What a curious feeling!' said Alice; `I must be shutting up\n" "like a telescope.'\n" "\n" " And so it was indeed: she was now only ten inches high, and\n" "her face brightened up at the thought that she was now the right\n" "size for going though the little door into that lovely garden.\n" "First, however, she waited for a few minutes to see if she was\n" "going to shrink any further: she felt a little nervous about\n" "this; `for it might end, you know,' said Alice to herself, `in my\n" "going out altogether, like a candle. I wonder what I should be\n" "like then?' And she tried to fancy what the flame of a candle is\n" "like after the candle is blown out, for she could not remember\n" "ever having seen such a thing.\n" "\n" " After a while, finding that nothing more happened, she decided\n" "on going into the garden at once; but, alas for poor Alice! when\n" "she got to the door, she found he had forgotten the little golden\n" "key, and when she went back to the table for it, she found she\n" "could not possibly reach it: she could see it quite plainly\n" "through the glass, and she tried her best to climb up one of the\n" "legs of the table, but it was too slippery; and when she had\n" "tired herself out with trying, the poor little thing sat down and\n" "cried.\n" "\n" " `Come, there's no use in crying like that!' said Alice to\n" "herself, rather sharply; `I advise you to leave off this minute!'\n" "She generally gave herself very good advice, (though she very\n" "seldom followed it), and sometimes she scolded herself so\n" "severely as to bring tears into her eyes; and once she remembered\n" "trying to box her own ears for having cheated herself in a game\n" "of croquet she was playing against herself, for this curious\n" "child was very fond of pretending to be two people. `But it's no\n" "use now,' thought poor Alice, `to pretend to be two people! Why,\n" "there's hardly enough of me left to make ONE respectable\n" "person!'\n" "\n" " Soon her eye fell on a little glass box that was lying under\n" "the table: she opened it, and found in it a very small cake, on\n" "which the words `EAT ME' were beautifully marked in currants.\n" "`Well, I'll eat it,' said Alice, `and if it makes me grow larger,\n" "I can reach the key; and if it makes me grow smaller, I can creep\n" "under the door; so either way I'll get into the garden, and I\n" "don't care which happens!'\n" "\n" " She ate a little bit, and said anxiously to herself, `Which\n" "way? Which way?', holding her hand on the top of her head to\n" "feel which way it was growing, and she was quite surprised to\n" "find that she remained the same size: to be sure, this generally\n" "happens when one eats cake, but Alice had got so much into the\n" "way of expecting nothing but out-of-the-way things to happen,\n" "that it seemed quite dull and stupid for life to go on in the\n" "common way.\n" "\n" " So she set to work, and very soon finished off the cake. "); if (result == -1) { printf("spd_say() failed. \n"); spd_close(spd); exit(1); } printf("Wait 5 secs and then cancel it.\n"); sleep(5); result = spd_cancel(spd); if (result == -1) { printf("spd_cancel() failed. \n"); spd_close(spd); exit(1); } count = 0; while (~notification_mask & SPD_CANCEL) { sleep(1); if (count++ == TEST_WAIT_COUNT) { printf("SPD_CANCEL wait count exceeded\n"); spd_close(spd); exit(1); } } printf("Message successfuly canceled.\n"); printf("Speech-dispatcher: connection closed.\n"); exit(0); } speech-dispatcher-0.9.1/src/tests/run_test.c0000644000175000017500000001412513406253014015776 00000000000000 /* * run_test.c - Read a set of Speech Dispatcher commands and try them * * Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: run_test.c,v 1.14 2008-02-08 10:01:08 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #define FATAL(msg) { printf(msg"\n"); exit(1); } int sockk; #ifndef HAVE_STRCASESTR /* Added by Willie Walker - strcasestr is a common but non-standard extension */ char *strcasestr(const char *a, const char *b) { size_t l; char f[3]; snprintf(f, sizeof(f), "%c%c", tolower(*b), toupper(*b)); for (l = strcspn(a, f); l != strlen(a); l += strcspn(a + l + 1, f) + 1) if (strncasecmp(a + l, b, strlen(b)) == 0) return (a + l); return NULL; } #endif /* HAVE_STRCASESTR */ char *send_data(int fd, char *message, int wfr) { char *reply; int bytes; /* TODO: 1000?! */ reply = (char *)malloc(sizeof(char) * 1000); /* write message to the socket */ if (!write(fd, message, strlen(message))) { fprintf(stderr, "send_data filed: %s", strerror(errno)); } /* read reply to the buffer */ if (wfr == 1) { bytes = read(fd, reply, 1000); /* print server reply to as a string */ reply[bytes] = 0; } else { return ""; } return reply; } void wait_for(int fd, char *event) { char *reply; int bytes; printf(" Waiting for: |%s|\n", event); reply = (char *)malloc(sizeof(char) * 1000); reply[0] = 0; while (0 == strcasestr(reply, event)) { bytes = read(fd, reply, 1000); if (bytes > 0) { reply[bytes] = 0; printf(" < %s\n", reply); fflush(NULL); } } free(reply); printf(" Continuing.\n"); fflush(NULL); } /* * set_socket_path: establish the pathname that our Unix socket should * have. If the SPEECHD_SOCKET environment variable is set, then that * will be our pathname. Otherwise, the pathname * is $XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock. */ void set_socket_path(struct sockaddr_un *address) { size_t path_max = sizeof(address->sun_path); const char *path; char *pathcopy = NULL; path = g_getenv("SPEECHD_SOCKET"); if (path == NULL || path[0] == '\0') { pathcopy = g_build_filename(g_get_user_runtime_dir(), "speech-dispatcher", "speechd.sock", NULL); path = pathcopy; } strncpy(address->sun_path, path, path_max - 1); address->sun_path[path_max - 1] = '\0'; g_free(pathcopy); } /* * init: create and connect our Unix-domain socket. * Returns the file descriptor of the socket on success, or -1 on * failure. */ int init(void) { int sockfd; int connect_success; struct sockaddr_un address; set_socket_path(&address); address.sun_family = AF_UNIX; sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd != -1) { connect_success = connect(sockfd, (struct sockaddr *)&address, SUN_LEN(&address)); if (connect_success == -1) { close(sockfd); sockfd = -1; } } return sockfd; } int main(int argc, char *argv[]) { char *line; char *command; char *reply; int i; char *ret; FILE *test_file = NULL; int delays = 1; int indent = 0; if (argc < 2) { printf("No test script specified!\n"); exit(1); } if (!strcmp(argv[1], "stdin")) { test_file = stdin; } else { test_file = fopen(argv[1], "r"); if (test_file == NULL) FATAL("Test file doesn't exist"); } if (argc == 3) { if (!strcmp(argv[2], "fast")) delays = 0; else { printf("Unrecognized parameter\n"); exit(1); } } printf("Start of the test.\n"); printf("==================\n\n"); line = malloc(1024 * sizeof(char)); reply = malloc(4096 * sizeof(char)); sockk = init(); if (sockk == -1) FATAL("Can't connect to Speech Dispatcher"); assert(line != 0); while (1) { ret = fgets(line, 1024, test_file); if (ret == NULL) break; if (strlen(line) <= 1) { printf("\n"); continue; } if (line[0] == '@') { command = (char *)strtok(line, "@\r\n"); if (command == NULL) printf("\n"); else printf(" %s\n", command); continue; } if (line[0] == '!') { command = (char *)strtok(line, "!\r\n"); strcat(command, "\r\n"); if (command == NULL) continue; printf(" >> %s", command); fflush(NULL); reply = send_data(sockk, command, 1); printf(" < %s", reply); fflush(NULL); continue; } if (line[0] == '.') { reply = send_data(sockk, "\r\n.\r\n", 1); printf(" < %s", reply); continue; } if (line[0] == '+') { command = (char *)strtok(&(line[1]), "+\r\n"); wait_for(sockk, command); continue; } if (line[0] == '$') { if (delays) { command = (char *)strtok(&(line[1]), "$\r\n"); sleep(atoi(command)); } continue; } if (line[0] == '^') { if (delays) { command = (char *)strtok(&(line[1]), "$\r\n"); usleep(atol(command)); } continue; } if (line[0] == '~') { command = (char *)strtok(line, "~\r\n"); indent = atoi(command); continue; } if (line[0] == '?') { getc(stdin); continue; } if (line[0] == '*') { int ret = system("clear"); if (ret == -1) FATAL("Could not execute subprocess"); for (i = 0; i <= indent - 1; i++) { printf("\n"); } continue; } if (line[0] == '#') { /* Comment */ continue; } send_data(sockk, line, 0); printf(" >> %s", line); } close(sockk); printf("\n==================\n"); printf("End of the test.\n"); exit(0); } speech-dispatcher-0.9.1/src/tests/long_message.c0000644000175000017500000004671613406253003016607 00000000000000 /* * long_message.c - Two testing messages for Speech Dispatcher test * * Copyright (C) 2001, 2002, 2003 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: long_message.c,v 1.13 2006-07-11 16:12:28 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "speechd_types.h" #include "libspeechd.h" int main() { SPDConnection *sockfd; int ret; printf("Start of the test.\n"); printf("Trying to initialize Speech Dispatcher..."); sockfd = spd_open("test", NULL, NULL, SPD_MODE_SINGLE); if (sockfd == 0) { printf("Speech Dispatcher failed"); exit(1); } printf("OK\n"); ret = spd_cancel(sockfd); if (ret == -1) { printf("spd_cancel failed"); exit(1); } printf("Sending message number 1, text \n"); ret = spd_say(sockfd, SPD_MESSAGE, "" " \n" " ALICE'S ADVENTURES IN WONDERLAND by Lewis Carroll.\n" "\n" " CHAPTER I: Down the Rabbit-Hole.\n" "\n" " Alice was beginning to get very tired of sitting by her sister\n" "on the bank, and of having nothing to do: once or twice she had\n" "peeped into the book her sister was reading, but it had no\n" "pictures or conversations in it, `and what is the use of a book,'\n" "thought Alice `without pictures or conversation?'\n" "\n" " So she was considering in her own mind (as well as she could,\n" "for the hot day made her feel very sleepy and stupid), whether\n" "the pleasure of making a daisy-chain would be worth the trouble\n" "of getting up and picking the daisies, when suddenly a White\n" "Rabbit with pink eyes ran close by her.\n" "\n" " There was nothing so VERY remarkable in that; nor did Alice\n" "think it so VERY much out of the way to hear the Rabbit say to\n" "itself, `Oh dear! Oh dear! I shall be late!' (when she thought\n" "it over afterwards, it occurred to her that she ought to have\n" "wondered at this, but at the time it all seemed quite natural);\n" "but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT-\n" "POCKET, and looked at it, and then hurried on, Alice started to\n" "her feet, for it flashed across her mind that she had never\n" "before seen a rabbit with either a waistcoat-pocket, or a watch to\n" "take out of it, and burning with curiosity, she ran across the\n" "field after it, and fortunately was just in time to see it pop\n" "down a large rabbit-hole under the hedge.\n" "\n" " In another moment down went Alice after it, never once\n" "considering how in the world she was to get out again.\n" "\n" " The rabbit-hole went straight on like a tunnel for some way,\n" "and then dipped suddenly down, so suddenly that Alice had not a\n" "moment to think about stopping herself before she found herself\n" "falling down a very deep well.\n" "\n" " Either the well was very deep, or she fell very slowly, for she\n" "had plenty of time as she went down to look about her and to\n" "wonder what was going to happen next. First, she tried to look\n" "down and make out what she was coming to, but it was too dark to\n" "see anything; then she looked at the sides of the well, and\n" "noticed that they were filled with cupboards and book-shelves;\n" "here and there she saw maps and pictures hung upon pegs. She\n" "took down a jar from one of the shelves as she passed; it was\n" "labelled `ORANGE MARMALADE', but to her great disappointment it\n" "was empty: she did not like to drop the jar for fear of killing\n" "somebody, so managed to put it into one of the cupboards as she\n" "fell past it.\n" "\n" " `Well!' thought Alice to herself, `after such a fall as this, I\n" "shall think nothing of tumbling down stairs! How brave they'll\n" "all think me at home! Why, I wouldn't say anything about it,\n" "even if I fell off the top of the house!' (Which was very likely\n" "true.)\n" "\n" " Down, down, down. Would the fall NEVER come to an end! `I\n" "wonder how many miles I've fallen by this time?' she said aloud.\n" "`I must be getting somewhere near the centre of the earth. Let\n" "me see: that would be four thousand miles down, I think--' (for,\n" "you see, Alice had learnt several things of this sort in her\n" "lessons in the schoolroom, and though this was not a VERY good\n" "opportunity for showing off her knowledge, as there was no one to\n" "listen to her, still it was good practice to say it over) `--yes,\n" "that's about the right distance--but then I wonder what Latitude\n" "or Longitude I've got to?' (Alice had no idea what Latitude was,\n" "or Longitude either, but thought they were nice grand words to\n" "say.)\n" "\n" " Presently she began again. `I wonder if I shall fall right\n" "THROUGH the earth! How funny it'll seem to come out among the\n" "people that walk with their heads downward! The Antipathies, I\n" "think--' (she was rather glad there WAS no one listening, this\n" "time, as it didn't sound at all the right word) `--but I shall\n" "have to ask them what the name of the country is, you know.\n" "Please, Ma'am, is this New Zealand or Australia?' (and she tried\n" "to curtsey as she spoke--fancy CURTSEYING as you're falling\n" "through the air! Do you think you could manage it?) `And what\n" "an ignorant little girl she'll think me for asking! No, it'll\n" "never do to ask: perhaps I shall see it written up somewhere.'\n" "\n" " Down, down, down. There was nothing else to do, so Alice soon\n" "began talking again. `Dinah'll miss me very much to-night, I\n" "should think!' (Dinah was the cat.) `I hope they'll remember\n" "her saucer of milk at tea-time. Dinah my dear! I wish you were\n" "down here with me! There are no mice in the air, I'm afraid, but\n" "you might catch a bat, and that's very like a mouse, you know.\n" "But do cats eat bats, I wonder?' And here Alice began to get\n" "rather sleepy, and went on saying to herself, in a dreamy sort of\n" "way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do\n" "bats eat cats?' for, you see, as she couldn't answer either\n" "question, it didn't much matter which way she put it. She felt\n" "that she was dozing off, and had just begun to dream that she\n" "was walking hand in hand with Dinah, and saying to her very\n" "earnestly, `Now, Dinah, tell me the truth: did you ever eat a\n" "bat?' when suddenly, thump! thump! down she came upon a heap of\n" "sticks and dry leaves, and the fall was over.\n" "\n" " Alice was not a bit hurt, and she jumped up on to her feet in a\n" "moment: she looked up, but it was all dark overhead; before her\n" "was another long passage, and the White Rabbit was still in\n" "sight, hurrying down it. There was not a moment to be lost:\n" "away went Alice like the wind, and was just in time to hear it\n" "say, as it turned a corner, `Oh my ears and whiskers, how late\n" "it's getting!' She was close behind it when she turned the\n" "corner, but the Rabbit was no longer to be seen: she found\n" "herself in a long, low hall, which was lit up by a row of lamps\n" "hanging from the roof.\n" "\n" " There were doors all round the hall, but they were all locked;\n" "and when Alice had been all the way down one side and up the\n" "other, trying every door, she walked sadly down the middle,\n" "wondering how she was ever to get out again.\n" "\n" " Suddenly she came upon a little three-legged table, all made of\n" "solid glass; there was nothing on it except a tiny golden key,\n" "and Alice's first thought was that it might belong to one of the\n" "doors of the hall; but, alas! either the locks were too large, or\n" "the key was too small, but at any rate it would not open any of\n" "them. However, on the second time round, she came upon a low\n" "curtain she had not noticed before, and behind it was a little\n" "door about fifteen inches high: she tried the little golden key\n" "in the lock, and to her great delight it fitted!\n" "\n" " Alice opened the door and found that it led into a small\n" "passage, not much larger than a rat-hole: she knelt down and\n" "looked along the passage into the loveliest garden you ever saw.\n" "How she longed to get out of that dark hall, and wander about\n" "among those beds of bright flowers and those cool fountains, but\n" "she could not even get her head though the doorway; `and even if\n" "my head would go through,' thought poor Alice, `it would be of\n" "very little use without my shoulders. Oh, how I wish\n" "I could shut up like a telescope! I think I could, if I only\n" "know how to begin.' For, you see, so many out-of-the-way things\n" "had happened lately, that Alice had begun to think that very few\n" "things indeed were really impossible.\n" "\n" " There seemed to be no use in waiting by the little door, so she\n" "went back to the table, half hoping she might find another key on\n" "it, or at any rate a book of rules for shutting people up like\n" "telescopes: this time she found a little bottle on it, (`which\n" "certainly was not here before,' said Alice,) and round the neck\n" "of the bottle was a paper label, with the words `DRINK ME'\n" "beautifully printed on it in large letters.\n" "\n" " It was all very well to say `Drink me,' but the wise little\n" "Alice was not going to do THAT in a hurry. `No, I'll look\n" "first,' she said, `and see whether it's marked \"poison\" or not';\n" "for she had read several nice little histories about children who\n" "had got burnt, and eaten up by wild beasts and other unpleasant\n" "things, all because they WOULD not remember the simple rules\n" "their friends had taught them: such as, that a red-hot poker\n" "will burn you if you hold it too long; and that if you cut your\n" "finger VERY deeply with a knife, it usually bleeds; and she had\n" "never forgotten that, if you drink much from a bottle marked\n" "`poison,' it is almost certain to disagree with you, sooner or\n" "later.\n" "\n" " However, this bottle was NOT marked `poison,' so Alice ventured\n" "to taste it, and finding it very nice, (it had, in fact, a sort\n" "of mixed flavour of cherry-tart, custard, pine-apple, roast\n" "turkey, toffee, and hot buttered toast,) she very soon finished\n" "it off.\n" "\n" " `What a curious feeling!' said Alice; `I must be shutting up\n" "like a telescope.'\n" "\n" " And so it was indeed: she was now only ten inches high, and\n" "her face brightened up at the thought that she was now the right\n" "size for going though the little door into that lovely garden.\n" "First, however, she waited for a few minutes to see if she was\n" "going to shrink any further: she felt a little nervous about\n" "this; `for it might end, you know,' said Alice to herself, `in my\n" "going out altogether, like a candle. I wonder what I should be\n" "like then?' And she tried to fancy what the flame of a candle is\n" "like after the candle is blown out, for she could not remember\n" "ever having seen such a thing.\n" "\n" " After a while, finding that nothing more happened, she decided\n" "on going into the garden at once; but, alas for poor Alice! when\n" "she got to the door, she found he had forgotten the little golden\n" "key, and when she went back to the table for it, she found she\n" "could not possibly reach it: she could see it quite plainly\n" "through the glass, and she tried her best to climb up one of the\n" "legs of the table, but it was too slippery; and when she had\n" "tired herself out with trying, the poor little thing sat down and\n" "cried.\n" "\n" " `Come, there's no use in crying like that!' said Alice to\n" "herself, rather sharply; `I advise you to leave off this minute!'\n" "She generally gave herself very good advice, (though she very\n" "seldom followed it), and sometimes she scolded herself so\n" "severely as to bring tears into her eyes; and once she remembered\n" "trying to box her own ears for having cheated herself in a game\n" "of croquet she was playing against herself, for this curious\n" "child was very fond of pretending to be two people. `But it's no\n" "use now,' thought poor Alice, `to pretend to be two people! Why,\n" "there's hardly enough of me left to make ONE respectable\n" "person!'\n" "\n" " Soon her eye fell on a little glass box that was lying under\n" "the table: she opened it, and found in it a very small cake, on\n" "which the words `EAT ME' were beautifully marked in currants.\n" "`Well, I'll eat it,' said Alice, `and if it makes me grow larger,\n" "I can reach the key; and if it makes me grow smaller, I can creep\n" "under the door; so either way I'll get into the garden, and I\n" "don't care which happens!'\n" "\n" " She ate a little bit, and said anxiously to herself, `Which\n" "way? Which way?', holding her hand on the top of her head to\n" "feel which way it was growing, and she was quite surprised to\n" "find that she remained the same size: to be sure, this generally\n" "happens when one eats cake, but Alice had got so much into the\n" "way of expecting nothing but out-of-the-way things to happen,\n" "that it seemed quite dull and stupid for life to go on in the\n" "common way.\n" "\n" " So she set to work, and very soon finished off the cake. "); if (ret == -1) { printf("spd_say failed"); exit(1); } printf("Sending message number 2, code (ugly characters) \n"); ret = spd_say(sockfd, SPD_MESSAGE, "\n" "\n" "int\n" "stop_p3(){\n" " int ret;\n" " ret = stop_priority(3);\n" " return ret;\n" "}\n" "\n" "int\n" "stop_priority(int priority)\n" "{\n" " int num, i;\n" " GList *gl;\n" " GList *queue;\n" " \n" " switch(priority){\n" " case 1: queue = MessageQueue->p1; break;\n" " case 2: queue = MessageQueue->p2; break;\n" " case 3: queue = MessageQueue->p3; break;\n" " default: return -1;\n" " }\n" "\n" " if (queue == NULL) return 0;\n" " \n" " if (highest_priority == priority){\n" " stop_speaking_active_module();\n" " }\n" "\n" " num = g_list_length(queue);\n" " for(i=0;i<=num-1;i++){\n" " gl = g_list_first(queue);\n" " assert(gl != NULL);\n" " assert(gl->data != NULL);\n" " mem_free_message(gl->data);\n" " queue = g_list_delete_link(queue, gl);\n" " msgs_to_say--;\n" " }\n" "\n" " switch(priority){\n" " case 1: MessageQueue->p1 = queue; break;\n" " case 2: MessageQueue->p2 = queue; break;\n" " case 3: MessageQueue->p3 = queue; break;\n" " default: return -1;\n" " }\n" " \n" " return 0;\n" "}\n" "\n" "void\n" "mem_free_message(TSpeechDMessage *msg)\n" "{\n" " free(msg->buf);\n" " free(msg->settings.client_name);\n" " free(msg->settings.language);\n" " free(msg->settings.output_module);\n" " free(msg);\n" "}\n" "\n" "void\n" "mem_free_fdset(TFDSetElement *fdset){\n" " free(fdset->client_name);\n" " free(fdset->language);\n" " free(fdset->output_module);\n" " free(fdset);\n" "}\n" "\n" "void\n" "stop_from_client(int fd){\n" " GList *gl;\n" " int queue = 1;\n" " while(gl = g_list_find_custom(MessageQueue->p1, (int*) fd, p_msg_lc)){\n" " if(gl->data != NULL) mem_free_message(gl->data);\n" " MessageQueue->p1 = g_list_delete_link(MessageQueue->p1, gl);\n" " msgs_to_say--;\n" " }\n" " while(gl = g_list_find_custom(MessageQueue->p2, (int*) fd, p_msg_lc)){\n" " if(gl->data != NULL) mem_free_message(gl->data);\n" " MessageQueue->p2 = g_list_delete_link(MessageQueue->p2, gl);\n" " msgs_to_say--;\n" " } \n" " while(gl = g_list_find_custom(MessageQueue->p3, (int*) fd, p_msg_lc)){\n" " if(gl->data != NULL) mem_free_message(gl->data);\n" " MessageQueue->p3 = g_list_delete_link(MessageQueue->p3, gl);\n" " msgs_to_say--;\n" " } \n" "}\n" "\n" "/* Determines if this messages is to be spoken\n" " * (returns 1) or it's parent client is paused (returns 0).\n" " * Note: If you are wondering why it's reversed (not to speak instead\n" " * of to speak), it's because we also use this function for\n" " * searching through the list. */\n" "gint\n" "message_nto_speak(TSpeechDMessage *elem, gpointer a, gpointer b)\n" "{\n" " TFDSetElement *global_settings;\n" " GList *gl;\n" "\n" " /* Is there something in the body of the message? */\n" " if(elem == NULL) return 0;\n" "\n" " /* Find global settings for this connection. */\n" " gl = g_list_find_custom(fd_settings, (int*) elem->settings.fd, p_fdset_lc_fd);\n" "\n" " if (gl == NULL) return 0;\n" " if (gl == NULL) FATAL(\"Couldn't find settings for active client, internal error.\");\n" " global_settings = gl->data;\n" " \n" " if (!global_settings->paused) return 0;\n" " else return 1;\n" "}\n" " "); if (ret == -1) { printf("spd_say failed"); exit(1); } printf("Trying to close Speech Dispatcher connection..."); spd_close(sockfd); printf("OK\n"); printf("Speech Dispatcher should continue saying both messages...\n"); printf("End of the test.\n"); exit(0); } speech-dispatcher-0.9.1/src/tests/connection-recovery.c0000644000175000017500000000432713406252774020145 00000000000000 /* * connection-recovery.c - Test of connection recovery * * Copyright (C) 2003 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: connection-recovery.c,v 1.1 2008-02-08 10:04:18 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "speechd_types.h" #include #include #include SPDConnection *try_to_reconnect(void) { SPDConnection *conn; while (1) { printf("Trying to reconnect\n"); usleep(1000); conn = spd_open("test", NULL, NULL, SPD_MODE_THREADED); if (conn != NULL) { spd_say(conn, SPD_MESSAGE, "Reconnect succesful"); printf("Reconnect successful\n"); return conn; } } } int main(void) { SPDConnection *conn; int i = 0; int failures = 0; int ret; conn = spd_open("test", NULL, NULL, SPD_MODE_THREADED); if (conn == 0) { printf("Speech Deamon failed"); exit(1); } printf("Connection recovery test \n\n"); printf("This test will keep saying a message 'Testing connection' \n"); printf("until Speech Dispatcher is stopped. Then it output at least\n"); printf ("5 messages about connection failure and will try to reconnect.\n"); printf ("On successful reconnect (after speechd) is started, it will keep\n"); printf("saying 'Testing connection' again until terminated.\n"); fflush(stdout); while (1) { sleep(5); printf("Speaking message %d ", i++); ret = spd_say(conn, SPD_MESSAGE, "Testing connection"); printf("with result %d\n", ret); if (ret == -1) failures++; if (failures >= 5) { spd_close(conn); conn = try_to_reconnect(); failures = 0; } } } speech-dispatcher-0.9.1/src/tests/clibrary2.c0000644000175000017500000000744213406252771016041 00000000000000 /* * clibrary2.c - Testing LIST and associated set functions in Speech Dispatcher * * Copyright (C) 2008 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: clibrary2.c,v 1.1 2008-04-09 11:41:52 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "speechd_types.h" #include "libspeechd.h" int main() { SPDConnection *conn; int i, j, ret; char **modules; char **voices; char *module; char *language; int value; SPDVoiceType voice_type = SPD_CHILD_MALE; SPDVoice **synth_voices; printf("Start of the test.\n"); printf("Trying to initialize Speech Deamon..."); conn = spd_open("say", NULL, NULL, SPD_MODE_SINGLE); if (conn == 0) { printf("Speech Deamon failed"); exit(1); } printf("OK\n"); printf("Trying to get the current output module..."); module = spd_get_output_module(conn); printf("Got module %s\n", module); if (module == NULL) { printf("Can't get current output module\n"); exit(1); } printf("Trying to get the language..."); language = spd_get_language(conn); printf("Got language %s\n", language); if (language == NULL) { printf("Can't get the language\n"); exit(1); } printf("Trying to get the voice rate..."); value = spd_get_voice_rate(conn); printf("Got rate %d\n", value); printf("Trying to get the voice pitch..."); value = spd_get_voice_pitch(conn); printf("Got pitch %d\n", value); printf("Trying to get the current volume..."); value = spd_get_volume(conn); printf("Got volume %d\n", value); printf("Trying to get the current voice type..."); spd_set_voice_type(conn, voice_type); voice_type = spd_get_voice_type(conn); printf("Got voice type %d\n", voice_type); modules = spd_list_modules(conn); if (modules == NULL) { printf("Can't list modules\n"); exit(1); } printf("Available output modules:\n"); for (i = 0;; i++) { if (modules[i] == NULL) break; printf(" %s\n", modules[i]); } voices = spd_list_voices(conn); if (voices == NULL) { printf("Can't list voices\n"); exit(1); } printf("Available symbolic voices:\n"); for (i = 0;; i++) { if (voices[i] == NULL) break; printf(" %s\n", voices[i]); } for (j = 0;; j++) { if (modules[j] == NULL) break; ret = spd_set_output_module(conn, modules[j]); if (ret == -1) { printf("spd_set_output_module failed"); exit(1); } printf("\nListing voices for %s\n", modules[j]); synth_voices = spd_list_synthesis_voices(conn); if (synth_voices == NULL) { printf("Can't list voices\n"); exit(1); } printf("Available synthesis voices:\n"); for (i = 0;; i++) { if (synth_voices[i] == NULL) break; printf(" name: %s language: %s variant: %s\n", synth_voices[i]->name, synth_voices[i]->language, synth_voices[i]->variant); ret = spd_set_synthesis_voice(conn, synth_voices[i]->name); if (ret == -1) { printf("spd_set_synthesis_voice failed"); exit(1); } ret = spd_say(conn, SPD_TEXT, "test"); if (ret == -1) { printf("spd_say failed"); exit(1); } sleep(1); } } printf("Trying to close Speech Dispatcher connection..."); spd_close(conn); printf("OK\n"); printf("End of the test.\n"); exit(0); } speech-dispatcher-0.9.1/src/tests/clibrary.c0000644000175000017500000000626513406252765015764 00000000000000 /* * clibrary.c - Testing the C library for Speech Dispatcher * * Copyright (C) 2003 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: clibrary.c,v 1.6 2006-07-11 16:12:28 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "speechd_types.h" #include "libspeechd.h" int main() { SPDConnection *conn; int i, ret; printf("Start of the test of the test.\n"); printf("Trying to initialize Speech Deamon..."); conn = spd_open("say", NULL, NULL, SPD_MODE_SINGLE); if (conn == 0) { printf("Speech Deamon failed"); exit(1); } printf("OK\n"); printf("Say inviting message\n"); ret = spd_say(conn, SPD_MESSAGE, "Hello, how are you? I'm Speech Deamon"); if (ret == -1) { printf("spd_say failed"); exit(1); } sleep(4); printf("\n"); printf("Try to lower pitch and higher rate...\n"); ret = spd_set_voice_pitch(conn, -20); if (ret == -1) { printf("spd_set_voice_pitch failed"); exit(1); } ret = spd_set_voice_rate(conn, +20); if (ret == -1) { printf("spd_set_voice_rate failed"); exit(1); } printf("...and say something\n"); ret = spd_say(conn, SPD_MESSAGE, "Do you like this voice more?"); if (ret == -1) { printf("spd_say failed"); exit(1); } sleep(4); printf("\n"); printf("Try to lower pitch and raise pitch range and rate...\n"); ret = spd_set_voice_pitch(conn, -20); if (ret == -1) { printf("spd_set_voice_pitch failed"); exit(1); } ret = spd_set_voice_pitch_range(conn, +20); if (ret == -1) { printf("spd_set_voice_pitch_range failed"); exit(1); } ret = spd_set_voice_rate(conn, +20); if (ret == -1) { printf("spd_set_voice_rate failed"); exit(1); } printf("...and say something\n"); ret = spd_say(conn, SPD_MESSAGE, "Do you like this voice more?"); if (ret == -1) { printf("spd_say failed"); exit(1); } sleep(4); printf("Switch punctuation mode to `all'."); printf("\n"); printf("\n"); printf("Keep this pitch, set higher rate and let's test priorities.\n" "Priority progress should choose some messages\n" "to report the progrees and it should allways say\n" "the last message.\n"); sleep(10); ret = spd_set_voice_rate(conn, +90); if (ret == -1) { printf("spd_set_voice_rate failed"); exit(1); } for (i = 0; i <= 100; i++) { printf("%d%% completed\n", i); ret = spd_sayf(conn, SPD_PROGRESS, "%d%% completed", i); if (ret == -1) { printf("spd_sayf failed"); exit(1); } } printf("Trying to close Speech Dispatcher connection..."); spd_close(conn); printf("OK\n"); printf("End of the test.\n"); exit(0); } speech-dispatcher-0.9.1/src/tests/README0000644000175000017500000000647013406252752014663 00000000000000 Available tests: ================ * long_message: Tests the ability of Speech Dispatcher to handle long messages and special characters (the seccond message is a source code). (it uses libspeechd.c) * multiple_messages: Tests how fast can Speech Dispatcher handles messages coming in short intervals for all 3 priorities. It also tests how the priorities influence each other. (it uses libspeechd.c) * run_test (and *.test files) Invoking: run_test {testfile} [fast] [> logfile] A simple program that reads the given script-file (*.test) and executes the SSIP commands inside it. It also outputs the comments from the file on the screen and waits where requested. If an aditional parameter "fast" is specified, that means execute everything without the specified delays. You may find it convenient to redirect the output to some logfile. The script files have the following simple syntax: * Every command begins in the first column and "lasts" till the end of the line is reached. * @ introduces a comentary on the given line * ! denotes an SSIP command that follows without any spaces * $ run_test will wait for the specified time (in seconds) * ^ run_test will wait for the specified time (in microseconds) * ~ sets the indentation (in spaces from left border), it can be used multiple times in different places * + wait for response string. Note, you cannot use this to wait for synchronous replies to commands. Generally, you will use this to wait for notification events (SET SELF NOTIFICATION ALL ON). It will wait for any reply containing the string that follows "+". * ? waits until the user presses a key * * clear screen * Blank lines in the script produce blank lines in the output. * # introduce a comment, completely ignored. In the output, SSIP communication is shifted to the right with respect to the comments. The commands and data the script sends to Speech Dispatcher begin with ">> ", the responses from Speech Dispatcher are introduced by "< ". See basic.test or general.test for an example. yo.wav is Copyright (C) 2006 Gary Cramblitt this file is Copyright (C) 2003 Brailcom, o.p.s Copyright (C) 2006 Gary Cramblitt they are licensed under the following terms: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (file COPYING in the root directory). You should have received a copy of the GNU General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/tests/Makefile.in0000644000175000017500000006711013465233610016043 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ check_PROGRAMS = long_message$(EXEEXT) clibrary$(EXEEXT) \ clibrary2$(EXEEXT) run_test$(EXEEXT) \ connection_recovery$(EXEEXT) spd_cancel_long_message$(EXEEXT) \ spd_set_notifications_all$(EXEEXT) subdir = src/tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am_clibrary_OBJECTS = clibrary.$(OBJEXT) clibrary_OBJECTS = $(am_clibrary_OBJECTS) am__DEPENDENCIES_1 = clibrary_DEPENDENCIES = $(c_api)/libspeechd.la $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_clibrary2_OBJECTS = clibrary2.$(OBJEXT) clibrary2_OBJECTS = $(am_clibrary2_OBJECTS) clibrary2_DEPENDENCIES = $(c_api)/libspeechd.la $(am__DEPENDENCIES_1) am_connection_recovery_OBJECTS = connection-recovery.$(OBJEXT) connection_recovery_OBJECTS = $(am_connection_recovery_OBJECTS) connection_recovery_DEPENDENCIES = $(c_api)/libspeechd.la \ $(am__DEPENDENCIES_1) am_long_message_OBJECTS = long_message.$(OBJEXT) long_message_OBJECTS = $(am_long_message_OBJECTS) long_message_DEPENDENCIES = $(c_api)/libspeechd.la \ $(am__DEPENDENCIES_1) am_run_test_OBJECTS = run_test.$(OBJEXT) run_test_OBJECTS = $(am_run_test_OBJECTS) run_test_DEPENDENCIES = $(c_api)/libspeechd.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am_spd_cancel_long_message_OBJECTS = \ spd_cancel_long_message.$(OBJEXT) spd_cancel_long_message_OBJECTS = \ $(am_spd_cancel_long_message_OBJECTS) spd_cancel_long_message_DEPENDENCIES = $(c_api)/libspeechd.la \ $(am__DEPENDENCIES_1) am_spd_set_notifications_all_OBJECTS = \ spd_set_notifications_all.$(OBJEXT) spd_set_notifications_all_OBJECTS = \ $(am_spd_set_notifications_all_OBJECTS) spd_set_notifications_all_DEPENDENCIES = $(c_api)/libspeechd.la \ $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/clibrary.Po ./$(DEPDIR)/clibrary2.Po \ ./$(DEPDIR)/connection-recovery.Po ./$(DEPDIR)/long_message.Po \ ./$(DEPDIR)/run_test.Po ./$(DEPDIR)/spd_cancel_long_message.Po \ ./$(DEPDIR)/spd_set_notifications_all.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(clibrary_SOURCES) $(clibrary2_SOURCES) \ $(connection_recovery_SOURCES) $(long_message_SOURCES) \ $(run_test_SOURCES) $(spd_cancel_long_message_SOURCES) \ $(spd_set_notifications_all_SOURCES) DIST_SOURCES = $(clibrary_SOURCES) $(clibrary2_SOURCES) \ $(connection_recovery_SOURCES) $(long_message_SOURCES) \ $(run_test_SOURCES) $(spd_cancel_long_message_SOURCES) \ $(spd_set_notifications_all_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ DISTCLEANFILES = atconfig $(TESTSUITE) c_api = $(top_builddir)/src/api/c AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/api/c $(GLIB_CFLAGS) AUTOM4TE = autom4te AUTOTEST = $(AUTOM4TE) --language=autotest TESTSUITE_AT = c_api.at TESTSUITE = ./testsuite long_message_SOURCES = long_message.c long_message_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) clibrary_SOURCES = clibrary.c clibrary_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) clibrary2_SOURCES = clibrary2.c clibrary2_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) connection_recovery_SOURCES = connection-recovery.c connection_recovery_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) spd_cancel_long_message_SOURCES = spd_cancel_long_message.c spd_cancel_long_message_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) spd_set_notifications_all_SOURCES = spd_set_notifications_all.c spd_set_notifications_all_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) run_test_SOURCES = run_test.c run_test_LDADD = $(c_api)/libspeechd.la $(GLIB_LIBS) $(EXTRA_SOCKET_LIBS) EXTRA_DIST = basic.test general.test keys.test priority_progress.test \ pronunciation.test punctuation.test sound_icons.test spelling.test \ ssml.test stop_and_pause.test voices.test yo.wav \ testsuite.at $(TESTSUITE_AT) sayfortune.sh CLEANFILES = package.m4 all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/tests/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clibrary$(EXEEXT): $(clibrary_OBJECTS) $(clibrary_DEPENDENCIES) $(EXTRA_clibrary_DEPENDENCIES) @rm -f clibrary$(EXEEXT) $(AM_V_CCLD)$(LINK) $(clibrary_OBJECTS) $(clibrary_LDADD) $(LIBS) clibrary2$(EXEEXT): $(clibrary2_OBJECTS) $(clibrary2_DEPENDENCIES) $(EXTRA_clibrary2_DEPENDENCIES) @rm -f clibrary2$(EXEEXT) $(AM_V_CCLD)$(LINK) $(clibrary2_OBJECTS) $(clibrary2_LDADD) $(LIBS) connection_recovery$(EXEEXT): $(connection_recovery_OBJECTS) $(connection_recovery_DEPENDENCIES) $(EXTRA_connection_recovery_DEPENDENCIES) @rm -f connection_recovery$(EXEEXT) $(AM_V_CCLD)$(LINK) $(connection_recovery_OBJECTS) $(connection_recovery_LDADD) $(LIBS) long_message$(EXEEXT): $(long_message_OBJECTS) $(long_message_DEPENDENCIES) $(EXTRA_long_message_DEPENDENCIES) @rm -f long_message$(EXEEXT) $(AM_V_CCLD)$(LINK) $(long_message_OBJECTS) $(long_message_LDADD) $(LIBS) run_test$(EXEEXT): $(run_test_OBJECTS) $(run_test_DEPENDENCIES) $(EXTRA_run_test_DEPENDENCIES) @rm -f run_test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(run_test_OBJECTS) $(run_test_LDADD) $(LIBS) spd_cancel_long_message$(EXEEXT): $(spd_cancel_long_message_OBJECTS) $(spd_cancel_long_message_DEPENDENCIES) $(EXTRA_spd_cancel_long_message_DEPENDENCIES) @rm -f spd_cancel_long_message$(EXEEXT) $(AM_V_CCLD)$(LINK) $(spd_cancel_long_message_OBJECTS) $(spd_cancel_long_message_LDADD) $(LIBS) spd_set_notifications_all$(EXEEXT): $(spd_set_notifications_all_OBJECTS) $(spd_set_notifications_all_DEPENDENCIES) $(EXTRA_spd_set_notifications_all_DEPENDENCIES) @rm -f spd_set_notifications_all$(EXEEXT) $(AM_V_CCLD)$(LINK) $(spd_set_notifications_all_OBJECTS) $(spd_set_notifications_all_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clibrary.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clibrary2.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection-recovery.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/long_message.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_test.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spd_cancel_long_message.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spd_set_notifications_all.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool clean-local \ mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/clibrary.Po -rm -f ./$(DEPDIR)/clibrary2.Po -rm -f ./$(DEPDIR)/connection-recovery.Po -rm -f ./$(DEPDIR)/long_message.Po -rm -f ./$(DEPDIR)/run_test.Po -rm -f ./$(DEPDIR)/spd_cancel_long_message.Po -rm -f ./$(DEPDIR)/spd_set_notifications_all.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/clibrary.Po -rm -f ./$(DEPDIR)/clibrary2.Po -rm -f ./$(DEPDIR)/connection-recovery.Po -rm -f ./$(DEPDIR)/long_message.Po -rm -f ./$(DEPDIR)/run_test.Po -rm -f ./$(DEPDIR)/spd_cancel_long_message.Po -rm -f ./$(DEPDIR)/spd_set_notifications_all.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool clean-local \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # The `:;' works around a redirected compound command bash exit status bug. package.m4: Makefile :;{ \ echo '# Signature of the current package.' && \ echo 'm4_define([AT_PACKAGE_NAME], [$(PACKAGE_NAME)])' && \ echo 'm4_define([AT_PACKAGE_TARNAME], [$(PACKAGE_TARNAME)])' && \ echo 'm4_define([AT_PACKAGE_VERSION], [$(PACKAGE_VERSION)])' && \ echo 'm4_define([AT_PACKAGE_STRING], [$(PACKAGE_STRING)])' && \ echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])' && \ echo 'm4_define([AT_PACKAGE_URL], [$(PACKAGE_URL)])'; \ } > $@-t mv $@-t $@ atconfig: $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/tests/$@ $(TESTSUITE): package.m4 testsuite.at $(TESTSUITE_AT) $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at mv $@.tmp $@ clean-local: test ! -f $(TESTSUITE) || $(SHELL) $(TESTSUITE) --clean rm -f *.tmp rm -f -r autom4te.cache # Run the test suite on the *installed* tree. testinstall: atconfig $(TESTSUITE) $(SHELL) $(TESTSUITE) AUTOTEST_PATH="$(bindir)" $(TESTSUITEFLAGS) -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/tests/Makefile.am0000644000175000017500000000637413406252746016045 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in DISTCLEANFILES = atconfig $(TESTSUITE) c_api = $(top_builddir)/src/api/c AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/api/c $(GLIB_CFLAGS) # The `:;' works around a redirected compound command bash exit status bug. package.m4: Makefile :;{ \ echo '# Signature of the current package.' && \ echo 'm4_define([AT_PACKAGE_NAME], [$(PACKAGE_NAME)])' && \ echo 'm4_define([AT_PACKAGE_TARNAME], [$(PACKAGE_TARNAME)])' && \ echo 'm4_define([AT_PACKAGE_VERSION], [$(PACKAGE_VERSION)])' && \ echo 'm4_define([AT_PACKAGE_STRING], [$(PACKAGE_STRING)])' && \ echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])' && \ echo 'm4_define([AT_PACKAGE_URL], [$(PACKAGE_URL)])'; \ } > $@-t mv $@-t $@ atconfig: $(top_builddir)/config.status cd $(top_builddir) && ./config.status src/tests/$@ AUTOM4TE = autom4te AUTOTEST = $(AUTOM4TE) --language=autotest TESTSUITE_AT = c_api.at TESTSUITE = ./testsuite $(TESTSUITE): package.m4 testsuite.at $(TESTSUITE_AT) $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at mv $@.tmp $@ check_PROGRAMS = long_message clibrary clibrary2 run_test connection_recovery \ spd_cancel_long_message spd_set_notifications_all long_message_SOURCES = long_message.c long_message_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) clibrary_SOURCES = clibrary.c clibrary_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) clibrary2_SOURCES = clibrary2.c clibrary2_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) connection_recovery_SOURCES = connection-recovery.c connection_recovery_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) spd_cancel_long_message_SOURCES = spd_cancel_long_message.c spd_cancel_long_message_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) spd_set_notifications_all_SOURCES = spd_set_notifications_all.c spd_set_notifications_all_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) run_test_SOURCES = run_test.c run_test_LDADD = $(c_api)/libspeechd.la $(GLIB_LIBS) $(EXTRA_SOCKET_LIBS) EXTRA_DIST= basic.test general.test keys.test priority_progress.test \ pronunciation.test punctuation.test sound_icons.test spelling.test \ ssml.test stop_and_pause.test voices.test yo.wav \ testsuite.at $(TESTSUITE_AT) sayfortune.sh clean-local: test ! -f $(TESTSUITE) || $(SHELL) $(TESTSUITE) --clean rm -f *.tmp rm -f -r autom4te.cache # Run the test suite on the *installed* tree. testinstall: atconfig $(TESTSUITE) $(SHELL) $(TESTSUITE) AUTOTEST_PATH="$(bindir)" $(TESTSUITEFLAGS) CLEANFILES = package.m4 -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/clients/0000755000175000017500000000000013465234514014354 500000000000000speech-dispatcher-0.9.1/src/clients/spdsend/0000755000175000017500000000000013465234514016014 500000000000000speech-dispatcher-0.9.1/src/clients/spdsend/common.c0000644000175000017500000000355213406252336017372 00000000000000/* common.c -- Common parts of the client and the server Author: Milan Zamazal */ /* Copyright (C) 2004 Brailcom, o.p.s. COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "spdsend.h" const long CONNECTION_ID_MIN = 1; const long CONNECTION_ID_MAX = 1000; const int EXIT_OK = 0; const int EXIT_ERROR = 1; extern Success write_data(Stream s, const void *buffer, size_t size) { int written; for (; size > 0; size -= written, buffer += written) { written = write(s, buffer, size); if (written < 0) return ERROR; } return OK; } extern int read_data(Stream s, void *buffer, size_t max_size) { size_t nread = 0; ssize_t n; while (nread < max_size) { n = read(s, buffer, max_size); if (n < 0) return NONE; if (n == 0) break; nread += n; buffer += n; max_size -= n; } return nread; } extern Success forward_data(Stream from, Stream to, bool closep) { const size_t buffer_size = 4096; char buffer[buffer_size]; ssize_t n; while ((n = read(from, buffer, buffer_size)) > 0) { if (write_data(to, buffer, n) == ERROR) return ERROR; } if (closep) shutdown(to, SHUT_WR); return (n == NONE ? ERROR : OK); } speech-dispatcher-0.9.1/src/clients/spdsend/client.c0000644000175000017500000000475013406252333017356 00000000000000/* client.c -- Client part of spdsend Author: Milan Zamazal */ /* Copyright (C) 2004 Brailcom, o.p.s. COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include "spdsend.h" #include #include #include static Success send_header(Stream s, Action action, Connection_Id id) { if (write_data(s, &action, sizeof(Action)) == OK && write_data(s, &id, sizeof(Connection_Id)) == OK) return OK; else return ERROR; } #define SEND_HEADER(action) \ if (send_header (s, action, id) == ERROR) \ return ERROR static Success send_open_header(Stream s, const char *host, int port) { int hostlen = strlen(host); Action action = A_OPEN; if (write_data(s, &action, sizeof(Action)) == OK && write_data(s, &port, sizeof(int)) == OK && write_data(s, &hostlen, sizeof(int)) == OK && write_data(s, host, hostlen) == OK) return OK; else return ERROR; } static Connection_Id read_reply(Stream s) { Result result; Connection_Id id; if (read_data(s, &result, sizeof(Result)) != sizeof(Result)) return NONE; if (result != OK_CODE) return NONE; if (read_data(s, &id, sizeof(Connection_Id)) != sizeof(Connection_Id)) return NONE; return id; } /* External functions */ extern Success open_connection(Stream s, const char *host, int port) { if (send_open_header(s, host, port) == ERROR) return ERROR; { Connection_Id id = read_reply(s); if (id == NONE) return ERROR; printf("%d\n", id); } return OK; } extern Success close_connection(Stream s, Connection_Id id) { SEND_HEADER(A_CLOSE); return (read_reply(s) == OK ? OK : ERROR); } extern Success send_command(Stream s, Connection_Id id) { SEND_HEADER(A_DATA); if (read_reply(s) == NONE) return ERROR; if (forward_data(0, s, TRUE) == OK && forward_data(s, 1, FALSE) == OK) return OK; else return ERROR; } speech-dispatcher-0.9.1/src/clients/spdsend/server.c0000644000175000017500000002271713406252341017410 00000000000000/* server.c -- Server part of spdsend Author: Milan Zamazal */ /* Copyright (C) 2004 Brailcom, o.p.s. COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include "spdsend.h" #ifndef USE_THREADS #define USE_THREADS 1 #endif #include #include #include #include #if USE_THREADS #include #endif #include #include #include #include #include #include #include #include #include #ifndef HAVE_GETLINE /* * Added by Willie Walker - getline was a GNU libc extension, later adopted * in the POSIX.1-2008 standard, but not yet found on all systems. */ ssize_t getline(char **lineptr, size_t * n, FILE * f); #endif /* Utilities */ static void system_error(const char *message) { perror(message); exit(1); } /* Connection management */ Stream *connections; #if USE_THREADS pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER; #endif static Stream get_connection(Connection_Id id) { if (id < CONNECTION_ID_MIN || id >= CONNECTION_ID_MAX) return NONE; return connections[id]; } static void set_connection(Connection_Id id, Stream s) { #if USE_THREADS pthread_mutex_lock(&connections_mutex); #endif connections[id] = s; #if USE_THREADS pthread_mutex_unlock(&connections_mutex); #endif } static Connection_Id new_connection(Stream s) { #if USE_THREADS pthread_mutex_lock(&connections_mutex); #endif int id; for (id = CONNECTION_ID_MIN; id < CONNECTION_ID_MAX && connections[id] != NONE; id++) ; if (id >= CONNECTION_ID_MAX) { #if USE_THREADS pthread_mutex_unlock(&connections_mutex); #endif return NONE; } connections[id] = s; #if USE_THREADS pthread_mutex_unlock(&connections_mutex); #endif return id; } static Connection_Id do_open_connection(const char *host, int port) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return NONE; { struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(port); { struct hostent *hostinfo; hostinfo = gethostbyname(host); if (hostinfo == NULL) { close(sock); return NONE; } name.sin_addr = *(struct in_addr *)hostinfo->h_addr; } if (connect(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { close(sock); return NONE; } { int arg = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &arg, sizeof(int)); } } { Connection_Id id = new_connection(sock); if (id == NONE) close(sock); return id; } } static Success do_close_connection(Connection_Id id) { Stream c = get_connection(id); if (c == NONE) return ERROR; close(c); set_connection(id, NONE); return OK; } static Success do_send_data(Connection_Id id, Stream from, Stream to, Success(*forwarder) (Stream, Stream, bool)) { int sock = get_connection(id); if (sock == NONE) return ERROR; if (from == NONE) from = sock; else if (to == NONE) to = sock; { Success result = ((*forwarder) (from, to, FALSE)); if (result != OK) do_close_connection(id); return result; } } /* Processing requests */ /* Protocol: Client request: First comes the action code, of the type Action. If Action is A_OPEN, the following data follows: int port, int strlen(hostname), hostname Else: Connection_Id Then, if Action is A_DATA, the SSIP lines follow. Server answer: The result code, of the type Result. If Result is OK, Connection_Id follows. Additionally, if Action is A_DATA, SSIP reply follows. */ static Success report(Stream s, Result code) { return write_data(s, &code, sizeof(Result)); } static Success report_ok(Stream s, Connection_Id id) { if (report(s, OK_CODE) == OK && write_data(s, &id, sizeof(Connection_Id)) == OK) return OK; else return ERROR; } static Success report_error(Stream s) { return report(s, ER_CODE); } static Connection_Id read_id(Stream s) { Connection_Id id; if (read_data(s, &id, sizeof(Connection_Id)) == ERROR) return NONE; return id; } static Success forward_ssip_answer(Stream from, Stream to, bool _closep) { int result = OK; FILE *f = fdopen(from, "r"); size_t line_size = 256; char *line = malloc(line_size); if (line == NULL) system_error("memory allocation"); while (1) { int n = getline(&line, &line_size, f); if (n < 0 || write_data(to, line, n) == ERROR) { result = ERROR; break; } if (n > 3 && line[3] == ' ') break; } free(line); return result; } static void process_open(Stream s) { Connection_Id id; int port; int hostlen; if (read_data(s, &port, sizeof(int)) != sizeof(int)) { report_error(s); return; } if (read_data(s, &hostlen, sizeof(int)) != sizeof(int)) { report_error(s); return; } { char *host = malloc(hostlen + 1); if (host == NULL) system_error("memory allocation"); if (read_data(s, host, hostlen) != hostlen) { free(host); report_error(s); return; } host[hostlen] = '\0'; id = do_open_connection(host, port); free(host); } if (id == NONE) report_error(s); else report_ok(s, id); } static void process_close(Stream s) { Connection_Id id = read_id(s); if (id != NONE && do_close_connection(id) == OK) report_ok(s, id); else report_error(s); } static void process_data(Stream s) { Connection_Id id = read_id(s); if (id != NONE) report_ok(s, id); else report_error(s); if (do_send_data(id, s, NONE, forward_data) == OK) do_send_data(id, NONE, s, forward_ssip_answer); } static void process_request(Stream s) { Action action; if (read_data(s, &action, sizeof(Action)) == NONE) return; if (action == A_OPEN) process_open(s); else if (action == A_CLOSE) process_close(s); else if (action == A_DATA) process_data(s); else report_error(s); close(s); } #if USE_THREADS static void *process_request_thread(void *s) { Stream s_deref = *((Stream *) s); free(s); pthread_detach(pthread_self()); process_request(s_deref); return NULL; } #endif /* Starting the server */ static const char *login_name() { return getpwuid(getuid())->pw_name; } static const char *server_socket_name() { char *name; if (asprintf(&name, "/tmp/spdsend-server.%s", login_name()) < 0) system_error("memory allocation"); return name; } static void serve() { struct sockaddr_un name; int sock; size_t size; const char *filename = server_socket_name(); sock = socket(PF_LOCAL, SOCK_STREAM, 0); if (sock < 0) system_error("socket creation"); name.sun_family = AF_LOCAL; strncpy(name.sun_path, filename, sizeof(name.sun_path)); name.sun_path[sizeof(name.sun_path) - 1] = '\0'; size = (offsetof(struct sockaddr_un, sun_path) + strlen(name.sun_path) + 1); if (bind(sock, (struct sockaddr *)&name, size) < 0) system_error("bind"); if (listen(sock, LISTEN_QUEUE_LENGTH) < 0) system_error("listen"); while (1) { struct sockaddr_un client_address; socklen_t client_address_len = sizeof(client_address); Stream *s = malloc(sizeof(Stream)); if (s == NULL) system_error("memory allocation"); *s = accept(sock, (struct sockaddr *)&client_address, &client_address_len); if (*s < 0) { free(s); break; } { #if USE_THREADS pthread_t tid; if (pthread_create(&tid, NULL, &process_request_thread, s)) #endif { process_request(*s); free(s); } } } close(sock); } static void daemonize() { int ret = 0; if (fork() != 0) exit(0); setsid(); signal(SIGHUP, SIG_IGN); if (fork() != 0) exit(0); if ((ret = chdir("/")) != 0) fputs("server.c:daemonize: could not chdir", stderr); exit(1); umask(0); { int i; for (i = 0; i < 4; i++) close(i); } } static void init_connections() { connections = malloc(CONNECTION_ID_MAX * sizeof(Connection_Id)); if (connections == NULL) system_error("memory allocation"); { int i; for (i = CONNECTION_ID_MIN; i < CONNECTION_ID_MAX; i++) connections[i] = NONE; } #if USE_THREADS pthread_mutex_init(&connections_mutex, NULL); #endif } static void start_server() { const char *socket_name = server_socket_name(); unlink(socket_name); { int pid = fork(); if (pid == -1) system_error("fork"); if (pid == 0) { daemonize(); init_connections(); serve(); unlink(socket_name); exit(0); } else sleep(1); } } static int connect_server() { struct sockaddr_un name; int sock = socket(AF_LOCAL, SOCK_STREAM, 0); int name_size; if (sock < 0) return NONE; name.sun_family = AF_LOCAL; strncpy(name.sun_path, server_socket_name(), sizeof(name.sun_path)); name.sun_path[sizeof(name.sun_path) - 1] = '\0'; name_size = (offsetof(struct sockaddr_un, sun_path) + strlen(name.sun_path) + 1); if (connect(sock, (struct sockaddr *)&name, name_size) < 0) { close(sock); return NONE; } else return sock; } /* External functions */ Stream open_server() { Stream s; s = connect_server(); if (s == NONE) { start_server(); s = connect_server(); } if (s == NONE) return NONE; return s; } speech-dispatcher-0.9.1/src/clients/spdsend/spdsend.c0000644000175000017500000000657013406252345017545 00000000000000/* spdsend.c -- Send SSIP commands to Speech Dispatcher Author: Milan Zamazal */ /* Copyright (C) 2004 Brailcom, o.p.s. COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "spdsend.h" const char *const SPDSEND_VERSION = "0.0.0"; #ifndef HAVE_GETLINE /* * Added by Willie Walker - getline was a GNU libc extension, later adopted * in the POSIX.1-2008 standard, but not yet found on all systems. */ #define BUFFER_LEN 256 ssize_t getline(char **lineptr, size_t * n, FILE * f) { int ch; size_t m = 0; ssize_t buf_len = 0; char *buf = NULL; char *p = NULL; if (errno != 0) { errno = 0; } while ((ch = getc(f)) != EOF) { if (errno != 0) return -1; if (m++ >= buf_len) { buf_len += BUFFER_LEN; buf = (char *)realloc(buf, buf_len + 1); if (buf == NULL) { return -1; } p = buf + buf_len - BUFFER_LEN; } *p = ch; p++; if (ch == '\n') break; } if (m == 0) { return -1; } else { *p = '\0'; *lineptr = buf; *n = m; return m; } } #endif /* HAVE_GETLINE */ static void usage(const char *const message) { if (message != NULL) fprintf(stderr, "spdsend: %s\n", message); fprintf(stderr, "usage: spdsend { --open SERVER PORT | --close ID | --send ID }\n"); exit(EXIT_ERROR); } static long string_to_number(const char *string, long low_limit, long high_limit) { char *tailptr; errno = 0; long int number = strtol(string, &tailptr, 0); if (errno || *tailptr || number < low_limit || number > high_limit) usage("Invalid parameter"); return number; } int main(int argc, char **argv) { if (argc < 2) usage("Invalid number of arguments"); { const char *const action = argv[1]; Success(*function) (Stream, Connection_Id); Connection_Id conn_id; char *host; int port; if (!strcmp(action, "--version")) { printf("spdsend %s\n", SPDSEND_VERSION); exit(EXIT_OK); } const int action_is_open = strcmp(action, "--open") == 0; if (action_is_open) { if (argc != 4) usage("Invalid number of arguments"); host = argv[2]; port = string_to_number(argv[3], 0, 65535); } else { if (argc != 3) usage("Invalid number of arguments"); conn_id = string_to_number(argv[2], CONNECTION_ID_MIN, CONNECTION_ID_MAX); if (!strcmp(action, "--close")) function = close_connection; else if (!strcmp(action, "--send")) function = send_command; else usage("Invalid option"); } { Stream server = open_server(); if (server == NONE) return EXIT_ERROR; { int result = (action_is_open ? open_connection(server, host, port) : function(server, conn_id)); return (result == OK ? EXIT_OK : EXIT_ERROR); } } } } speech-dispatcher-0.9.1/src/clients/spdsend/spdsend.h0000644000175000017500000000341413423333245017542 00000000000000/* Declarations for spdsend Author: Milan Zamazal */ /* Copyright (C) 2004 Brailcom, o.p.s. COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __SPDSEND_H #define __SPDSEND_H #define _GNU_SOURCE #include /* Configuration */ #ifndef LISTEN_QUEUE_LENGTH #define LISTEN_QUEUE_LENGTH 100 #endif /* Types */ typedef enum { FALSE, TRUE } bool; typedef int Stream; typedef int Connection_Id; typedef enum { OK, ERROR } Success; #define NONE -1 /* common.c */ extern Success write_data(Stream s, const void *buffer, size_t size); extern int read_data(Stream s, void *buffer, size_t max_size); extern Success forward_data(Stream from, Stream to, bool closep); typedef enum { A_OPEN, A_CLOSE, A_DATA } Action; typedef enum { OK_CODE, ER_CODE } Result; extern const long CONNECTION_ID_MIN; extern const long CONNECTION_ID_MAX; extern const int EXIT_OK; extern const int EXIT_ERROR; /* server.c */ extern Stream open_server(); /* client.c */ extern Success open_connection(Stream server, const char *host, int port); extern Success close_connection(Stream server, Connection_Id id); extern Success send_command(Stream server, Connection_Id id); #endif speech-dispatcher-0.9.1/src/clients/spdsend/README0000644000175000017500000000300313424443611016603 00000000000000This is a simple command line client to Speech Dispatcher. It may be useful in programs, which don't want to use direct socket communication with Speech Dispatcher for some reason. To compile the program, just run `make'. To install it, run `make install'. The following operations are supported: $ spdsend --open HOST PORT Open new connection to Speech Dispatcher running at HOST:PORT and print the connection identifier on the standard output. $ spdsend --close CONNECTION Close the given Speech Dispatcher CONNECTION. $ spdsend --send CONNECTION Read an SSIP command from standard input, forward it to Speech Dispatcher CONNECTION and print the answer on the standard output. You can send your bug reports, patches, suggestions, etc. to the mailing list speechd-discuss@nongnu.org . -- Milan Zamazal Copyright (C) 2004-2006 Brailcom, o.p.s This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (file COPYING in the root directory). You should have received a copy of the GNU General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/clients/spdsend/Makefile.in0000644000175000017500000005627013465233610020007 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = spdsend$(EXEEXT) subdir = src/clients/spdsend ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_spdsend_OBJECTS = spdsend.$(OBJEXT) server.$(OBJEXT) \ client.$(OBJEXT) common.$(OBJEXT) spdsend_OBJECTS = $(am_spdsend_OBJECTS) am__DEPENDENCIES_1 = spdsend_DEPENDENCIES = $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/client.Po ./$(DEPDIR)/common.Po \ ./$(DEPDIR)/server.Po ./$(DEPDIR)/spdsend.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(spdsend_SOURCES) DIST_SOURCES = $(spdsend_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ spdsend_SOURCES = spdsend.h spdsend.c server.c client.c common.c spdsend_LDADD = $(EXTRA_SOCKET_LIBS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/clients/spdsend/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/clients/spdsend/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list spdsend$(EXEEXT): $(spdsend_OBJECTS) $(spdsend_DEPENDENCIES) $(EXTRA_spdsend_DEPENDENCIES) @rm -f spdsend$(EXEEXT) $(AM_V_CCLD)$(LINK) $(spdsend_OBJECTS) $(spdsend_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdsend.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/client.Po -rm -f ./$(DEPDIR)/common.Po -rm -f ./$(DEPDIR)/server.Po -rm -f ./$(DEPDIR)/spdsend.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/client.Po -rm -f ./$(DEPDIR)/common.Po -rm -f ./$(DEPDIR)/server.Po -rm -f ./$(DEPDIR)/spdsend.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/clients/spdsend/Makefile.am0000644000175000017500000000156213406252322017764 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in bin_PROGRAMS = spdsend spdsend_SOURCES = spdsend.h spdsend.c server.c client.c common.c spdsend_LDADD = $(EXTRA_SOCKET_LIBS) -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/clients/say/0000755000175000017500000000000013465234514015150 500000000000000speech-dispatcher-0.9.1/src/clients/say/options.h0000644000175000017500000000423513406252312016727 00000000000000/* * options.h - Defines possible command line options * * Copyright (C) 2003 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: options.h,v 1.10 2006-07-11 16:12:27 hanke Exp $ */ #include #include "speechd_types.h" signed int rate; signed int pitch; signed int pitch_range; signed int volume; int list_output_modules; char *output_module; char *sound_icon; char *language; char *voice_type; char *punctuation_mode; char *priority; int pipe_mode; SPDDataMode ssml_mode; int spelling; int wait_till_end; int stop_previous; int cancel_previous; int list_synthesis_voices; char *synthesis_voice; char *application_name; char *connection_name; static struct option long_options[] = { {"rate", 1, 0, 'r'}, {"pitch", 1, 0, 'p'}, {"pitch-range", 1, 0, 'R'}, {"volume", 1, 0, 'i'}, {"output-module", 1, 0, 'o'}, {"list-output-modules", no_argument, 0, 'O'}, {"sound-icon", required_argument, 0, 'I'}, {"language", 1, 0, 'l'}, {"voice-type", 1, 0, 't'}, {"list-synthesis-voices", no_argument, 0, 'L'}, {"synthesis-voice", required_argument, 0, 'y'}, {"punctuation-mode", 1, 0, 'm'}, {"spelling", 0, 0, 's'}, {"ssml", 0, 0, 'x'}, {"pipe-mode", 0, 0, 'e'}, {"priority", 1, 0, 'P'}, {"application-name", 1, 0, 'N'}, {"connection-name", 1, 0, 'n'}, {"wait", 0, 0, 'w'}, {"stop", 1, 0, 'S'}, {"cancel", no_argument, 0, 'C'}, {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; static char *short_options = "r:p:R:i:l:o:OI:t:Ly:m:sxeP:N:n:wSCvh"; int options_parse(int argc, char *argv[]); void options_print_version(); void options_print_help(char *argv[]); speech-dispatcher-0.9.1/src/clients/say/options.c0000644000175000017500000001613513406252306016727 00000000000000/* * options.c - Parse and process possible command line options * * Copyright (C) 2003 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: options.c,v 1.9 2006-07-11 16:12:26 hanke Exp $ */ /* NOTE: Be careful not to include options.h, we would get repetitive initializations warnings */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "options.h" #include void options_print_help(char *argv[]) { assert(argv); assert(argv[0]); printf(_("send text-to-speech output request to speech-dispatcher\n\n")); printf(_("Usage: %s [options] \"some text\"\n\n"), argv[0]); printf(_("Options:\n")); printf(" -r, --rate "); printf(_("Set the rate of the speech\n")); printf(" "); printf(_("(between %+d and %+d, default: %d)\n"), -100, 100, 0); printf(" -p, --pitch "); printf(_("Set the pitch of the speech\n")); printf(" "); printf(_("(between %+d and %+d, default: %d)\n"), -100, 100, 0); printf(" -R, --pitch-range "); printf(_("Set the pitch range of the speech\n")); printf(" "); printf(_("(between %+d and %+d, default: %d)\n"), -100, 100, 0); printf(" -i, --volume "); printf(_("Set the volume (intensity) of the speech\n")); printf(" "); printf(_("(between %+d and %+d, default: %d)\n"), -100, 100, 0); printf(" -o, --output-module "); printf(_("Set the output module\n")); printf(" -O, --list-output-modules "); printf(_("Get the list of output modules\n")); printf(" -I, --sound-icon "); printf(_("Play the sound icon\n")); printf(" -l, --language "); printf(_("Set the language (ISO code)\n")); printf(" -t, --voice-type "); printf(_("Set the preferred voice type\n")); printf(" (male1, male2, male3, female1, female2\n" " female3, child_male, child_female)\n"); printf(" -L, --list-synthesis-voices "); printf(_("Get the list of synthesis voices\n")); printf(" -y, --synthesis-voice "); printf(_("Set the synthesis voice\n")); printf(" -m, --punctuation-mode "); printf(_("Set the punctuation mode %s\n"), "(none, some, all)"); printf(" -s, --spelling "); printf(_("Spell the message\n")); printf(" -x, --ssml "); printf(_("Set SSML mode on (default: off)\n")); printf("\n"); printf(" -e, --pipe-mode "); printf(_("Pipe from stdin to stdout plus Speech Dispatcher\n")); printf(" -P, --priority "); printf(_("Set priority of the message ")); printf("(important, message,\n" "%stext, notification, progress;", " "); printf(_("default: %s)\n"), "text"); printf(" -N, --application-name "); printf(_("Set the application name used to establish\n" "%sthe connection to specified string value\n"), " "); printf(" "); printf(_("(default: %s)\n"), "spd-say"); printf(" -n, --connection-name "); printf(_("Set the connection name used to establish\n" "%sthe connection to specified string value\n"), " "); printf(" "); printf(_("(default: %s)\n"), "main"); printf("\n"); printf(" -w, --wait "); printf(_("Wait till the message is spoken or discarded\n")); printf(" -S, --stop "); printf(_("Stop speaking the message being spoken\n")); printf(" -C, --cancel "); printf(_("Cancel all messages\n")); printf("\n"); printf(" -v, --version "); printf(_("Print version and copyright info\n")); printf(" -h, --help "); printf(_("Print this info\n")); printf("\n"); printf(_("Please report bugs to %s\n\n"), PACKAGE_BUGREPORT); } void options_print_version() { printf("spd-say " VERSION "\n"); printf(_("Copyright (C) %d-%d Brailcom, o.p.s.\n" "This is free software; you can redistribute it and/or modify it\n" "under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2, or (at your option)\n" "any later version. Please see COPYING for more details.\n\n"), 2002, 2012); } #define OPT_SET_INT(param) \ val = strtol(optarg, &tail_ptr, 10); \ if(tail_ptr != optarg){ \ param = val; \ }else{ \ printf(_("Syntax error or bad parameter!\n")); \ options_print_help(argv); \ exit(1); \ } #define OPT_SET_STR(param) \ if(optarg != NULL){ \ if (param) \ free(param); \ param = (char*) strdup(optarg); \ }else{ \ printf(_("Missing argument!\n")); \ options_print_help(argv); \ exit(1); \ } int options_parse(int argc, char *argv[]) { char *tail_ptr; int c_opt; int option_index; int val; assert(argc > 0); assert(argv); while (1) { option_index = 0; c_opt = getopt_long(argc, argv, short_options, long_options, &option_index); if (c_opt == -1) break; switch (c_opt) { case 'r': OPT_SET_INT(rate); break; case 'p': OPT_SET_INT(pitch); break; case 'R': OPT_SET_INT(pitch_range); break; case 'i': OPT_SET_INT(volume); break; case 'l': OPT_SET_STR(language); break; case 'o': OPT_SET_STR(output_module); break; case 'O': list_output_modules = 1; break; case 'I': OPT_SET_STR(sound_icon); break; case 't': OPT_SET_STR(voice_type); break; case 'L': list_synthesis_voices = 1; break; case 'y': OPT_SET_STR(synthesis_voice); break; case 'm': OPT_SET_STR(punctuation_mode); break; case 's': spelling = 1; break; case 'e': pipe_mode = 1; break; case 'P': OPT_SET_STR(priority); break; case 'x': ssml_mode = SPD_DATA_SSML; break; case 'N': OPT_SET_STR(application_name); break; case 'n': OPT_SET_STR(connection_name); break; case 'w': wait_till_end = 1; break; case 'S': stop_previous = 1; break; case 'C': cancel_previous = 1; break; case 'v': options_print_version(argv); exit(0); break; case 'h': options_print_help(argv); exit(0); break; default: printf(_("Unrecognized option\n")); options_print_help(argv); exit(1); } } return 0; } #undef SPD_OPTION_SET_INT speech-dispatcher-0.9.1/src/clients/say/say.c0000644000175000017500000002055313406252317016031 00000000000000 /* * say.c - Super-simple Speech Dispatcher client * * Copyright (C) 2001, 2002, 2003, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: say.c,v 1.16 2007-05-03 09:43:12 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include /* * Since this client is built as part of the Speech Dispatcher source * tree, we must include speechd_types.h directly. * Clients built outside the speech dispatcher source tree should not do * this. */ #include #include #include "options.h" #include #include #define MAX_LINELEN 16384 sem_t semaphore; /* Callback for Speech Dispatcher notifications */ void end_of_speech(size_t msg_id, size_t client_id, SPDNotificationType type) { sem_post(&semaphore); } int main(int argc, char **argv) { SPDConnection *conn; SPDPriority spd_priority; int err; char *error; int msg_arg_required = 0; int ret; int option_ret; char *line; /* initialize i18n support */ i18n_init(); rate = -101; pitch = -101; pitch_range = -101; volume = -101; language = NULL; voice_type = NULL; punctuation_mode = NULL; spelling = -2; ssml_mode = SPD_DATA_TEXT; wait_till_end = 0; stop_previous = 0; cancel_previous = 0; list_synthesis_voices = 0; list_output_modules = 0; synthesis_voice = NULL; pipe_mode = 0; priority = NULL; application_name = NULL; connection_name = NULL; option_ret = options_parse(argc, argv); /* Check if the text to say or options are specified in the argument */ msg_arg_required = (pipe_mode != 1) && (stop_previous != 1) && (cancel_previous != 1) && (list_synthesis_voices != 1) && (list_output_modules != 1) && (sound_icon == NULL); if ((optind >= argc) && msg_arg_required) { options_print_help(argv); return 1; } /* Open a connection to Speech Dispatcher */ conn = spd_open2(application_name ? application_name : "spd-say", connection_name ? connection_name : "main", NULL, SPD_MODE_THREADED, NULL, 1, &error); if (conn == NULL) { fprintf(stderr, "Failed to connect to Speech Dispatcher:\n%s\n", error); exit(1); } if (stop_previous) spd_stop_all(conn); if (cancel_previous) spd_cancel_all(conn); /* Set the desired parameters */ if (language != NULL) { if (spd_set_language(conn, language)) printf("Invalid language!\n"); } else { char *locale = strdup(setlocale(LC_MESSAGES, NULL)); char *underscore = index(locale, '_'); if (underscore) *underscore = 0; if (spd_set_language(conn, locale)) printf("Invalid language %s!\n", locale); free(locale); } if (output_module != NULL) if (spd_set_output_module(conn, output_module)) printf("Invalid output module!\n"); if (list_output_modules) { char **list; int i; list = spd_list_modules(conn); if (list != NULL) { printf("OUTPUT MODULES\n"); for (i = 0; list[i]; i++) { printf("%s\n", list[i]); } } else { printf("Output modules not found.\n"); } } if (voice_type != NULL) { if (!strcmp(voice_type, "male1")) { if (spd_set_voice_type(conn, SPD_MALE1)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "male2")) { if (spd_set_voice_type(conn, SPD_MALE2)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "male3")) { if (spd_set_voice_type(conn, SPD_MALE3)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "female1")) { if (spd_set_voice_type(conn, SPD_FEMALE1)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "female2")) { if (spd_set_voice_type(conn, SPD_FEMALE2)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "female3")) { if (spd_set_voice_type(conn, SPD_FEMALE3)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "child_male")) { if (spd_set_voice_type(conn, SPD_CHILD_MALE)) printf("Can't set this voice!\n"); } else if (!strcmp(voice_type, "child_female")) { if (spd_set_voice_type(conn, SPD_CHILD_FEMALE)) printf("Can't set this voice!\n"); } else { printf("Invalid voice\n"); } } if (list_synthesis_voices) { SPDVoice **list; int i; list = spd_list_synthesis_voices(conn); if (list != NULL) { printf("%25s%25s%25s\n", "NAME", "LANGUAGE", "VARIANT"); for (i = 0; list[i]; i++) { printf("%25s%25s%25s\n", list[i]->name, list[i]->language, list[i]->variant); } } else { printf("Failed to get voice list.\n"); } } if (synthesis_voice != NULL) if (spd_set_synthesis_voice(conn, synthesis_voice)) printf("Failed to set synthesis voice!\n"); if (ssml_mode == SPD_DATA_SSML) if (spd_set_data_mode(conn, ssml_mode)) printf("Failed to set SSML mode.\n"); if (rate != -101) if (spd_set_voice_rate(conn, rate)) printf("Invalid rate!\n"); if (pitch != -101) if (spd_set_voice_pitch(conn, pitch)) printf("Invalid pitch!\n"); if (pitch_range != -101) if (spd_set_voice_pitch_range(conn, pitch_range)) printf("Invalid pitch range!\n"); if (volume != -101) if (spd_set_volume(conn, volume)) printf("Invalid volume!\n"); if (spelling == 1) if (spd_set_spelling(conn, SPD_SPELL_ON)) printf("Can't set spelling to on!\n"); if (punctuation_mode != NULL) { if (!strcmp(punctuation_mode, "none")) { if (spd_set_punctuation(conn, SPD_PUNCT_NONE)) printf("Can't set this punctuation mode!\n"); } else if (!strcmp(punctuation_mode, "some")) { if (spd_set_punctuation(conn, SPD_PUNCT_SOME)) printf("Can't set this punctuation mode!\n"); } else if (!strcmp(punctuation_mode, "all")) { if (spd_set_punctuation(conn, SPD_PUNCT_ALL)) printf("Can't set this punctuation mode!\n"); } else { printf("Invalid punctuation mode.\n"); } } /* Set default priority... */ if (1 == pipe_mode) spd_priority = SPD_MESSAGE; else spd_priority = SPD_TEXT; /* ...and look if it wasn't overriden */ if (priority != NULL) { if (!strcmp(priority, "important")) spd_priority = SPD_IMPORTANT; else if (!strcmp(priority, "message")) spd_priority = SPD_MESSAGE; else if (!strcmp(priority, "text")) spd_priority = SPD_TEXT; else if (!strcmp(priority, "notification")) spd_priority = SPD_NOTIFICATION; else if (!strcmp(priority, "progress")) spd_priority = SPD_PROGRESS; else { printf("Invalid priority.\n"); } } if (sound_icon != NULL) if (spd_sound_icon(conn, spd_priority, sound_icon)) printf("Invalid sound_icon!\n"); if (wait_till_end) { ret = sem_init(&semaphore, 0, 0); if (ret < 0) { fprintf(stderr, "Can't initialize semaphore: %s", strerror(errno)); return 0; } /* Notify when the message is canceled or the speech terminates */ conn->callback_end = end_of_speech; conn->callback_cancel = end_of_speech; spd_set_notification_on(conn, SPD_END); spd_set_notification_on(conn, SPD_CANCEL); } /* In pipe mode, read from stdin, write to stdout, and also to Speech Dispatcher. */ if (pipe_mode == 1) { line = (char *)malloc(MAX_LINELEN); while (NULL != fgets(line, MAX_LINELEN, stdin)) { fputs(line, stdout); if (0 == strncmp(line, "!-!", 3)) { /* Remove EOL */ line[strlen(line) - 1] = 0; spd_execute_command(conn, line + 3); } else { spd_say(conn, spd_priority, line); if (wait_till_end) sem_wait(&semaphore); } } free(line); } else { /* Say the message with priority "text" */ /* Or do nothing in case of -C or -S with no message. */ if (optind < argc) { err = spd_sayf(conn, spd_priority, (char *)argv[optind]); if (err == -1) { fprintf(stderr, "Speech Dispatcher failed to say message"); exit(1); } /* Wait till the callback is called */ if (wait_till_end) sem_wait(&semaphore); } } /* Close the connection */ spd_close(conn); return 0; } speech-dispatcher-0.9.1/src/clients/say/Makefile.in0000644000175000017500000007316413465233610017144 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = spd-say$(EXEEXT) subdir = src/clients/say ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am_spd_say_OBJECTS = spd_say-say.$(OBJEXT) spd_say-options.$(OBJEXT) spd_say_OBJECTS = $(am_spd_say_OBJECTS) am__DEPENDENCIES_1 = spd_say_DEPENDENCIES = $(c_api)/libspeechd.la $(am__DEPENDENCIES_1) \ $(top_builddir)/src/common/libcommon.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/spd_say-options.Po \ ./$(DEPDIR)/spd_say-say.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(spd_say_SOURCES) DIST_SOURCES = $(spd_say_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(dist_man1_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ inc_local = -I$(top_srcdir)/include -I$(top_srcdir)/src/api/c c_api = $(top_builddir)/src/api/c spd_say_CPPFLAGS = $(inc_local) $(GLIB_CFLAGS) spd_say_SOURCES = say.c options.c options.h spd_say_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) $(top_builddir)/src/common/libcommon.la @HAVE_HELP2MAN_TRUE@dist_man1_MANS = \ @HAVE_HELP2MAN_TRUE@ spd-say.1 CLEANFILES = $(dist_man1_MANS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/clients/say/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/clients/say/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list spd-say$(EXEEXT): $(spd_say_OBJECTS) $(spd_say_DEPENDENCIES) $(EXTRA_spd_say_DEPENDENCIES) @rm -f spd-say$(EXEEXT) $(AM_V_CCLD)$(LINK) $(spd_say_OBJECTS) $(spd_say_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spd_say-options.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spd_say-say.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< spd_say-say.o: say.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spd_say-say.o -MD -MP -MF $(DEPDIR)/spd_say-say.Tpo -c -o spd_say-say.o `test -f 'say.c' || echo '$(srcdir)/'`say.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/spd_say-say.Tpo $(DEPDIR)/spd_say-say.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='say.c' object='spd_say-say.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spd_say-say.o `test -f 'say.c' || echo '$(srcdir)/'`say.c spd_say-say.obj: say.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spd_say-say.obj -MD -MP -MF $(DEPDIR)/spd_say-say.Tpo -c -o spd_say-say.obj `if test -f 'say.c'; then $(CYGPATH_W) 'say.c'; else $(CYGPATH_W) '$(srcdir)/say.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/spd_say-say.Tpo $(DEPDIR)/spd_say-say.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='say.c' object='spd_say-say.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spd_say-say.obj `if test -f 'say.c'; then $(CYGPATH_W) 'say.c'; else $(CYGPATH_W) '$(srcdir)/say.c'; fi` spd_say-options.o: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spd_say-options.o -MD -MP -MF $(DEPDIR)/spd_say-options.Tpo -c -o spd_say-options.o `test -f 'options.c' || echo '$(srcdir)/'`options.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/spd_say-options.Tpo $(DEPDIR)/spd_say-options.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='spd_say-options.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spd_say-options.o `test -f 'options.c' || echo '$(srcdir)/'`options.c spd_say-options.obj: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spd_say-options.obj -MD -MP -MF $(DEPDIR)/spd_say-options.Tpo -c -o spd_say-options.obj `if test -f 'options.c'; then $(CYGPATH_W) 'options.c'; else $(CYGPATH_W) '$(srcdir)/options.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/spd_say-options.Tpo $(DEPDIR)/spd_say-options.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='spd_say-options.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(spd_say_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spd_say-options.obj `if test -f 'options.c'; then $(CYGPATH_W) 'options.c'; else $(CYGPATH_W) '$(srcdir)/options.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(dist_man1_MANS) @$(NORMAL_INSTALL) @list1='$(dist_man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(dist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/spd_say-options.Po -rm -f ./$(DEPDIR)/spd_say-say.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/spd_say-options.Po -rm -f ./$(DEPDIR)/spd_say-say.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-man uninstall-man1 .PRECIOUS: Makefile @HAVE_HELP2MAN_TRUE@spd-say.1: spd-say$(EXEEXT) @HAVE_HELP2MAN_TRUE@ LC_ALL=C help2man --output=$@ ./$< -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/clients/say/spd-say.10000644000175000017500000000556613465234512016544 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.8. .TH SPD-SAY "1" "May 2019" "spd-say 0.9.1" "User Commands" .SH NAME spd-say \- manual page for spd-say 0.9.1 .SH SYNOPSIS .B spd-say [\fI\,options\/\fR] \fI\,"some text"\/\fR .SH DESCRIPTION send text\-to\-speech output request to speech\-dispatcher .SH OPTIONS .TP \fB\-r\fR, \fB\-\-rate\fR Set the rate of the speech (between \fB\-100\fR and +100, default: 0) .TP \fB\-p\fR, \fB\-\-pitch\fR Set the pitch of the speech (between \fB\-100\fR and +100, default: 0) .TP \fB\-R\fR, \fB\-\-pitch\-range\fR Set the pitch range of the speech (between \fB\-100\fR and +100, default: 0) .TP \fB\-i\fR, \fB\-\-volume\fR Set the volume (intensity) of the speech (between \fB\-100\fR and +100, default: 0) .TP \fB\-o\fR, \fB\-\-output\-module\fR Set the output module .TP \fB\-O\fR, \fB\-\-list\-output\-modules\fR Get the list of output modules .TP \fB\-I\fR, \fB\-\-sound\-icon\fR Play the sound icon .TP \fB\-l\fR, \fB\-\-language\fR Set the language (ISO code) .TP \fB\-t\fR, \fB\-\-voice\-type\fR Set the preferred voice type (male1, male2, male3, female1, female2 female3, child_male, child_female) .TP \fB\-L\fR, \fB\-\-list\-synthesis\-voices\fR Get the list of synthesis voices .TP \fB\-y\fR, \fB\-\-synthesis\-voice\fR Set the synthesis voice .TP \fB\-m\fR, \fB\-\-punctuation\-mode\fR Set the punctuation mode (none, some, all) .TP \fB\-s\fR, \fB\-\-spelling\fR Spell the message .TP \fB\-x\fR, \fB\-\-ssml\fR Set SSML mode on (default: off) .TP \fB\-e\fR, \fB\-\-pipe\-mode\fR Pipe from stdin to stdout plus Speech Dispatcher .TP \fB\-P\fR, \fB\-\-priority\fR Set priority of the message (important, message, text, notification, progress;default: text) .TP \fB\-N\fR, \fB\-\-application\-name\fR Set the application name used to establish the connection to specified string value (default: spd\-say) .TP \fB\-n\fR, \fB\-\-connection\-name\fR Set the connection name used to establish the connection to specified string value (default: main) .TP \fB\-w\fR, \fB\-\-wait\fR Wait till the message is spoken or discarded .TP \fB\-S\fR, \fB\-\-stop\fR Stop speaking the message being spoken .TP \fB\-C\fR, \fB\-\-cancel\fR Cancel all messages .TP \fB\-v\fR, \fB\-\-version\fR Print version and copyright info .TP \fB\-h\fR, \fB\-\-help\fR Print this info .PP Please report bugs to speechd\-discuss@nongnu.org .SH COPYRIGHT Copyright \(co 2002\-2012 Brailcom, o.p.s. .br This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Please see COPYING for more details. .SH "SEE ALSO" The full documentation for .B spd-say is maintained as a Texinfo manual. If the .B info and .B spd-say programs are properly installed at your site, the command .IP .B info spd-say .PP should give you access to the complete manual. speech-dispatcher-0.9.1/src/clients/say/Makefile.am0000644000175000017500000000230113406252267017120 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in inc_local = -I$(top_srcdir)/include -I$(top_srcdir)/src/api/c c_api = $(top_builddir)/src/api/c bin_PROGRAMS = spd-say spd_say_CPPFLAGS = $(inc_local) $(GLIB_CFLAGS) spd_say_SOURCES = say.c options.c options.h spd_say_LDADD = $(c_api)/libspeechd.la $(EXTRA_SOCKET_LIBS) $(top_builddir)/src/common/libcommon.la if HAVE_HELP2MAN spd-say.1: spd-say$(EXEEXT) LC_ALL=C help2man --output=$@ ./$< dist_man1_MANS = \ spd-say.1 endif CLEANFILES = $(dist_man1_MANS) -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/clients/Makefile.in0000644000175000017500000005262413465233610016346 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/clients ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = say spdsend all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/clients/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/clients/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/clients/Makefile.am0000644000175000017500000000141213406252264016323 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in SUBDIRS= say spdsend -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/api/0000755000175000017500000000000013465234514013464 500000000000000speech-dispatcher-0.9.1/src/api/python/0000755000175000017500000000000013465234514015005 500000000000000speech-dispatcher-0.9.1/src/api/python/speechd_config/0000755000175000017500000000000013465234514017745 500000000000000speech-dispatcher-0.9.1/src/api/python/speechd_config/config.py.in0000644000175000017500000010165413406252215022111 00000000000000# config.py - A simple dialog based tool for basic configuration of # Speech Dispatcher and problem diagnostics. # # Copyright (C) 2008, 2010 Brailcom, o.p.s. # 2016 Sebastian Humenda # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import argparse import datetime import fileinput import gettext import locale import os import shutil import shlex import socket import sys import time from xdg import BaseDirectory # Locale/gettext configuration locale.setlocale(locale.LC_ALL, '') gettext.bindtextdomain ("@GETTEXT_PACKAGE@", "@localedir@") gettext.textdomain("@GETTEXT_PACKAGE@") _ = gettext.gettext # Configuration and sound data paths from . import paths # two globals use_espeak_synthesis = False dont_ask = False def report(msg): """Output information messages for the user on stdout and if desired, by espeak synthesis""" print(msg) if use_espeak_synthesis: os.system("espeak %s" % shlex.quote(msg)) def input_audio_icon(): """Produce a sound for the event 'input requested' used in question()""" if use_espeak_synthesis: os.system("espeak \"Type in\"") def question(text, default): """Ask a simple question and suggest the default value""" while 1: if isinstance(default, bool): if default: default_str = "yes" else: default_str = "no" else: default_str = str(default) report(text + " ["+default_str+"] :") input_audio_icon() if not dont_ask: str_inp = input(">") # On plain enter, return default if dont_ask or (len(str_inp) == 0): return default # If a value was typed, check it and convert it elif isinstance(default, bool): if str_inp in ["yes","y", "Y", "true","t", "1"]: return True elif str_inp in ["no", "n", "N", "false", "f", "0"]: return False else: report ("Unknown answer (type 'yes' or 'no')") continue elif isinstance(default, int): return int(str_inp) elif isinstance(default, str): return str_inp else: raise TypeError("Invalid type for the default value") def question_with_suggested_answers(text, default, suggest): """Ask a question with suggested answers. If the answer typed is not in 'suggest', the user is notified and given an opportunity to correct his choice""" reply = question(text, default) while reply not in suggest: report(_("""The value you have chosen is not among the suggested values. You have chosen '%s'.""" % reply)) report(_("The suggested values are " + str(suggest))) correct = question(_("Do you want to correct your answer?"), True) if correct: reply = question(text, default) else: return reply return reply def question_with_required_answers(text, default, required): """Ask a question and repeat it until the answer typed in is in 'required'""" reply = question(text, default) while reply not in required: report(_("You have chosen '%s'. Please choose one of %s" % (reply, str(required)))) reply = question(text, default) return reply def setup_argparse(): """Set up an argparser instance with all the options accepted.""" parser = argparse.ArgumentParser( description=_('A simple tool for basic configuration of Speech Dispatcher and problem diagnostics')) parser.add_argument('-u', '--create-user-conf', dest='create_user_configuration', action="store_true", default=False, help=_("Create Speech Dispatcher configuration for the given user")) parser.add_argument('-c', '--config-basic-settings-user', dest='config_basic_settings_user', action="store_true", default=False, help=_("Configure basic settings in user configuration")) parser.add_argument('-C', '--config-basic-settings-system', dest='config_basic_settings_system', action="store_true", default=False, help=_("Configure basic settings in system-wide configuration")) parser.add_argument('-d', '--diagnostics', dest='diagnostics', action="store_true", default=False, help=_("Diagnose problems with the current setup")) parser.add_argument('-s', '--test-spd-say', dest='test_spd_say', action="store_true", default=False, help=_("Test connection to Speech Dispatcher using spd-say")) parser.add_argument('--test-festival', dest='test_festival', action="store_true", default=False, help=_("Test whether Festival works as a server")) parser.add_argument('--test-espeak', dest='test_espeak', action="store_true", default=False, help=_("Test whether Espeak works as a standalone binary")) parser.add_argument('--test-alsa', dest='test_alsa', action="store_true", default=False, help=_("Test ALSA audio output")) parser.add_argument('--test-pulse', dest='test_pulse', action="store_true", default=False, help=_("Test Pulse Audio output")) parser.add_argument('-e', '--espeak', dest='use_espeak_synthesis', action="store_true", default=use_espeak_synthesis, help=_("Use espeak to synthesize messages")) parser.add_argument('-n', '--dont-ask', dest='dont_ask', action="store_true", default=False, help=_("Do not ask any questions, always use default values")) parser.add_argument('-D', '--debug', dest='debug', action="store_true", default=False, help=_("Debug a problem and generate a report")) parser.add_argument('--version', dest='version', action="store_true", help=_("Print version and copyright info")) return parser class Tests: """Tests of functionality of Speech Dispatcher and its dependencies and methods for determination of proper paths""" def __init__(self): self.festival_socket = None def version(self): """Print version and copyright info""" report("spd-conf @VERSION@\n") report(_("""Copyright (C) %d-%d Brailcom, o.p.s. This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Please see COPYING for more details.\n\n""") % \ (2002, 2012)) def user_conf_dir(self): """Return user configuration directory""" return os.path.join(BaseDirectory.xdg_config_home, "speech-dispatcher") def system_conf_dir(self): """Determine system configuration directory""" return paths.SPD_CONF_PATH def user_conf_dir_exists(self): """Determine whether user configuration directory exists""" return os.path.exists(self.user_conf_dir()) def festival_connect(self, host="localhost", port=1314): """ Try to connect to festival and determine whether it is possible. On success self.festival_socket is initialized with the openned socket. """ self.festival_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: self.festival_socket.connect((socket.gethostbyname(host), port)) except socket.error as e: (num, reson) = e.args report(_("""ERROR: It was not possible to connect to Festival on the given host and port. Connection failed with error %d : %s .""" % (num, reson))) report(_("""Hint: Most likely, your Festival server is not running now or not at the default port %d. Try /etc/init.d/festival start or run 'festival --server' from the command line.""" % port)) return False return True def festival_with_freebsoft_utils(self): """Test whether festival works and contains working festival-freebsoft-utils. """ if not self.festival_socket: if not self.festival_connect(): return False self.festival_socket.send(bytes("(require 'speech-dispatcher)\n", "ascii")) reply = str(self.festival_socket.recv(1024)) if "LP" in reply: report(_("Festival contains freebsoft-utils.")) return True else: report(_("""ERROR: Your Festival server is working but it doesn't seem to load festival-freebsoft-utils. You need to install festival-freebsoft-utils to be able to use Festival with Speech Dispatcher.""")) return False def python_speechd_in_path(self): """Try whether python speechd library is installed.""" import importlib try: importlib.import_module('speechd') except ImportError: report(_("""Python can't find the Speech Dispatcher library. Is it installed? This won't prevent Speech Dispatcher to work, but no Python applications like Orca will be able to use it. Search for package like python-speechd, download and install it""")) return False return True def audio_try_play(self, type): """Try to play a sound through the standard playback utility for the given audio method.""" wavfile = os.path.join(paths.SPD_SOUND_DATA_PATH,"test.wav") binary = None if type == 'alsa': binary = 'aplay' elif type == 'pulse': binary = "paplay" else: raise NotImplementedError("Test for this audio system is not implemented") if not shutil.which(binary): report(_("""%s selected, but %s not installed. This might be a false warning, but most likely sound is not working.""" % (type, binary))) reply = question(_("Are you sure that %s audio is working?" % type), False) return reply cmd = '%s %s' % (binary, wavfile) if os.system(cmd): report(_("Can't play audio via\n %s" % cmd)) report(_("""Your audio doesn't seem to work, please fix audio first or choose a different method.""")) return False reply = question(_("Did you hear the sound?"), True) if not reply: report(_("""Please examine the above output from the sound playback utility. If everything seems right, are you sure your audio is loud enough and not muted in the mixer? Please fix your audio system first or choose a different audio output method in configuration.""")) return False else: report(_("Audio output '%s' works" % type)) return True def test_spd_say(self): """Test Speech Dispatcher using spd_say""" report(_("Testing Speech Dispatcher using spd_say")) while True: if os.system("spd-say -P important \"Speech Dispatcher works\""): report(_("""Can't execute the spd-say binary, it is very likely that Speech Dispatcher is not installed.""")) return False hearing_test = question(_("Did you hear the message about Speech Dispatcher working?"), True) if hearing_test: report(_("Speech Dispatcher is installed and working!")) return True else: report(_("Speech Dispatcher is installed but there is some problem")) return False def test_festival(self): """Test whether Festival works as a server""" report(_("Testing whether Festival works as a server")) ret = self.festival_with_freebsoft_utils() if not ret: report(_("Festival server is not working.")) return False else: report(_("Festival server seems to work correctly")) return True def test_espeak(self): """Test the espeak utility""" report(_("Testing whether Espeak works")) if shutil.which('espeak'): report(_("Espeak is installed")) return True else: report(_("""Can't execute the espeak binary, it is likely that espeak is not installed.""")) return False def test_alsa(self): """Test ALSA sound output""" report(_("Testing ALSA sound output")) return self.audio_try_play(type='alsa') def test_pulse(self): """Test Pulse Audio sound output""" report(_("Testing PULSE sound output")) return self.audio_try_play(type='pulse') def diagnostics(self, speechd_running = True, output_modules=None, audio_output=None): """Perform a complete diagnostics""" working_modules = [] working_audio = [] if speechd_running: # Test whether Speech Dispatcher works if self.test_spd_say(): spd_say_working = True skip = question(_("Speech Dispatcher works. Do you want to skip other tests?"), True) if skip: return {'spd_say_working': True} else: spd_say_working = False else: spd_say_working = False if not spd_say_working: if not question(_(""" Speech Dispatcher isn't running or we can't connect to it (see above), do you want to proceed with other tests? (They can help to determine what is wrong)"""), True): return {'spd_say_working': False} def decide_to_test(identifier, name, listing): """Ask the user whether to test a specific capability.""" if not listing: return False elif identifier in listing and \ question(_("Do you want to test the %s now?" % name), True): return True else: return False if decide_to_test('festival', "Festival synthesizer", output_modules): if self.test_festival(): working_modules += ["festival"] if decide_to_test('espeak', "Espeak synthesizer", output_modules): if self.test_espeak(): working_modules += ["espeak"] if decide_to_test('alsa', "ALSA sound system", audio_output): if self.test_alsa(): working_audio += ["alsa"] if decide_to_test('pulse', "Pulse Audio sound system", audio_output): if self.test_pulse(): working_audio += ["pulse"] report(_("Testing whether Python Speech Dispatcher library is in path and importable")) python_speechd_working = self.python_speechd_in_path() return {'spd_say_working': spd_say_working, 'audio': working_audio, 'synthesizers': working_modules, 'python_speechd' : python_speechd_working} def write_diagnostics_results(self, results): """Write out diagnostics results using report()""" report(_(""" Diagnostics results:""")) if 'spd_say_working' in results: if results['spd_say_working']: report(_("Speech Dispatcher is working")) else: report(_("Speech Dispatcher not working through spd-say")) if 'synthesizers' in results: report(_("Synthesizers that were tested and seem to work: %s") % str(results['synthesizers'])) if 'audio' in results: report(_("Audio systems that were tested and seem to work: %s") % str(results['audio'])) if 'python_speechd' in results: if(results['python_speechd']): report(_("Python Speech Dispatcher module is importable")) else: report(_("""Python Speech Dispatcher module not importable. Either not installed or not in path.""")) report(_("End of diagnostics results")) def user_configuration_seems_complete(self): """Decide if the user configuration seems reasonably complete""" if not os.path.exists(os.path.join(self.user_conf_dir(), "speechd.conf")): return False if not len(os.listdir(self.user_conf_dir())) > 2: return False if not os.path.exists(os.path.join(self.user_conf_dir(), "modules")): return False if not os.path.exists(os.path.join(self.user_conf_dir(), "clients")): return False return True def debug_and_report(self, type = None): """Start Speech Dispatcher in debugging mode, collect the debugging output and offer to send it to the developers""" report(_("Starting collecting debugging output, configuration and logfiles")) if not type: type = question_with_required_answers(_(""" Do you want to debug 'system' or 'user' Speech Dispatcher?"""), 'user', ['user', 'system']) # Try to kill running Speech Dispatcher reply = question(_("""It is necessary to kill the currently running Speech Dispatcher processes. Do you want to do it now?"""), True) if reply: os.system("killall speech-dispatcher") # Attempt to workaround the psmisc 22.15 bug with 16 char max process names os.system("killall speech-dispatch") else: report(_(""" You decided not to kill running Speech Dispatcher processes. Please make sure your Speech Dispatcher is not running now.""")) reply = question(_("Is your Speech Dispatcher not running now?"), True) if not reply: report(_("Can't continue, please stop your Speech Dispatcher and try again")) time.sleep(2) # All debugging files are written to TMPDIR/speech-dispatcher/ if 'TMPDIR' in os.environ: tmpdir = os.environ['TMPDIR'] else: tmpdir = "/tmp/" debugdir_path = os.path.join(tmpdir, "speechd-debug") date = datetime.date.today() debugarchive_path = os.path.join(tmpdir, "speechd-debug-%d-%d-%d.tar.gz" % (date.day, date.month, date.year)) # Start Speech Dispatcher with debugging enabled if type == 'user': report(_("Speech Dispatcher will be started now in debugging mode")) speechd_started = not os.system("speech-dispatcher -D") configure_directory = self.user_conf_dir() else: report(_("Warning: You must be root or under sudo to do this.") ) report(_(""" Please start your system Speech Dispatcher now with parameter '-D'""")) reply = question(_("Is your Speech Dispatcher running now?"), True) if reply: speechd_started = True else: report(_("Can't continue")) configure_directory = self.system_conf_dir() time.sleep(2) if not speechd_started: reply = question(_("Speech Dispatcher failed to start, continuing anyway?"), False) report(_("Trying to speak some messages")) ret = os.system("spd-say \"Speech Dispatcher debugging 1\"") if not ret: os.system("spd-say \"Speech Dispatcher debugging 2\"") os.system("spd-say \"Speech Dispatcher debugging 3\"") else: report(_("Can't test Speech Dispatcher connection, can't connect")) report(_("Please wait (about 5 seconds)")) time.sleep(5) report(_("Collecting debugging output and your configuration information") ) os.system("umask 077") os.system("tar -cz %s %s > %s" % (debugdir_path, configure_directory, debugarchive_path)) os.system("killall speech-dispatcher") # Attempt to workaround the psmisc 22.15 bug with 16 char max process names os.system("killall speech-dispatch") os.system("rm -rf %s" % debugdir_path) report(_(""" Please send %s to speechd@bugs.freebsoft.org with a short description of what you did. We will get in touch with you soon and suggest a solution.""" % debugarchive_path)) class Configure: """Setup user configuration and/or set basic options in user/system configuration""" default_output_module = None default_language = None default_audio_method = None def __init__(self, test): self.test = test def remove_user_configuration(self): """Remove user configuration tree""" shutil.rmtree(self.test.user_conf_dir()) def options_substitute(self, configfile, options): """Substitute the given options with given values. Arguments: configfile -- the file path of the configuration file as a string options -- a list of tuples (option_name, value)""" # Parse config file in-place and replace the desired options+values for line in fileinput.input(configfile, inplace=True, backup=".bak"): # Check if the current line contains any of the desired options for opt, value in options.items(): if opt in line: # Now count unknown words and try to judge if this is # real configuration or just a comment unknown = 0 for word in line.split(): if word =='#' or word == '\t': continue elif word == opt: # If a foreign word went before our option identifier, # we are not in code but in comments if unknown != 0: unknown = 2 break else: unknown += 1 # Only consider the line as the actual code when the keyword # is followed by exactly one word value. Otherwise consider this # line as plain comment and leave intact if unknown == 1: # Convert value into string representation in spd_val if isinstance(value, bool): if value: spd_val = "1" elif not value: spd_val = "2" elif isinstance(value, int): spd_val = str(value) else: spd_val = str(value) print(opt + " " + spd_val) break else: print(line, end=' ') def create_user_configuration(self): """Create user configuration in the standard location""" # Ask before touching things that we do not have to! if self.test.user_conf_dir_exists(): if self.test.user_configuration_seems_complete(): reply = question(_("""User configuration already exists. Do you want to rewrite it with a new one?"""), False) if not reply: report(_("Keeping configuration intact and continuing with settings.")) return else: self.remove_user_configuration() else: reply = question(_("""User configuration already exists, but it seems to be incomplete. Do you want to keep it?"""), False) if not reply: self.remove_user_configuration() else: report(_("Keeping configuration intact and aborting.")) return # Copy the original intact configuration files # creating a conf/ subdirectory shutil.copytree(paths.SPD_CONF_ORIG_PATH, self.test.user_conf_dir()) report(_("User configuration created in %s" % self.test.user_conf_dir())) def configure_basic_settings(self, type='user'): """Ask for basic settings and rewrite them in the configuration file""" if type == 'user': report(_("Configuring user settings for Speech Dispatcher")) elif type == 'system': report(_("Warning: You must be root or under sudo to do this.")) report(_("Configuring system settings for Speech Dispatcher")) else: raise ValueError("Invalid configuration type") # Now determine the most important config option self.default_output_module = question_with_suggested_answers( "Default output module", "espeak-ng", ["espeak-ng", "espeak", "festival", "flite", "ivona", "pico", "espeak-generic", "espeak-ng-mbrola-generic", "espeak-mbrola-generic", "swift-generic", "epos-generic", "dtk-generic", "pico-generic", "ibmtts", "cicero", "kali", "mary-generic", "baratinoo"]) self.default_language = question( "Default language (two-letter iso language code like \"en\" or \"cs\")", "en") self.default_audio_method = question_with_suggested_answers( "Default audio output method", "pulse", ["pulse", "libao", "alsa", "oss", "pulse,alsa"]) default_speech_rate = question( _("Default speech rate (on the scale of -100..100, 0 is default, 50 is faster, -50 is slower)"), "0") default_speech_pitch = question( _("Default speech pitch (on the scale of -100..100, 0 is default, 50 is higher, -50 is lower)"), "0") default_speech_pitch_range = question( _("Default speech pitch range (on the scale of -100..100, 0 is default, 50 is higher, -50 is lower)"), "0") # Substitute given configuration options if type == 'user': configfile = os.path.join(self.test.user_conf_dir(), "speechd.conf") elif type == 'system': configfile = os.path.join(self.test.system_conf_dir(), "speechd.conf") self.options_substitute(configfile, {"DefaultModule": self.default_output_module, "DefaultLanguage": self.default_language, "AudioOutputMethod": self.default_audio_method, "DefaultRate": default_speech_rate, "DefaultPitch": default_speech_pitch, "DefaultPitchRange": default_speech_pitch_range, }) if type == 'user': setup_autostart = question( _("""Do you want to have Speech Dispatcher automatically started from ~/.config/autostart ? This is usually not necessary, most applications will start Speech Dispatcher automatically."""), False) if setup_autostart: os.system("""cp %s ~/.config/autostart/""" % os.path.join(paths.SPD_DESKTOP_CONF_PATH, "speechd.desktop")) report(_(""" Configuration written to %s Basic configuration now complete. You might still need to fine tune it by manually editing the configuration file above. Especially if you need to use special audio settings, non-standard synthesizer ports etc.""" % configfile)) def speechd_start_user(self): """Start Speech Dispatcher in user-mode""" report(_("Starting Speech Dispatcher in user-mode")) err = os.system("speech-dispatcher") if err: report(_("Can't start Speech Dispatcher. Exited with status %d" % err)) reply = question(_("""Perhaps this is because your Speech Dispatcher is already running. Do you want to kill all running Speech Dispatchers and try again?"""), True) if reply: os.system("killall speech-dispatcher") # Attempt to workaround the psmisc 22.15 bug with 16 char max process names os.system("killall speech-dispatch") err = os.system("speech-dispatcher") if err: report(_("Can't start Speech Dispatcher")) return False else: return False return True def speechd_start_system(self): """Start Speech Dispatcher in system-mode""" report(_("Warning: You must be root or under sudo to do this.") ) report(_("Starting Speech Dispatcher in system-mode")) reply = question(_("Is your system using an /etc/init.d/speech-dispatcher script?"), True) if reply: report(_("Stopping Speech Dispatcher in case any is running already")) os.system("/etc/init.d/speech-dispatcher stop") report(_("Starting Speech Dispatcher via /etc/init.d/speech-dispatcher")) ret = os.system("/etc/init.d/speech-dispatcher start") if ret: report(_("Can't start Speech Dispatcher. Exited with status %d" % ret)) return False else: report(_("""Do not know how to start system Speech Dispatcher, you have to start it manually to continue.""")) reply = question(_("Have you started Speech Dispatcher now?"), True) if not reply: report(_("Can't continue")) return False return True def complete_config(self): """Create a complete configuration, run diagnosis and if necessary, debugging""" speechd_type = question_with_required_answers( _("Do you want to create/setup a 'user' or 'system' configuration"), 'user', ['user', 'system']) if speechd_type == 'user': self.create_user_configuration() self.configure_basic_settings(type='user') elif speechd_type == 'system': self.configure_basic_settings(type='system') else: raise ValueError("Invalid configuration type") reply = question(_("Do you want to start/restart Speech Dispatcher now and run some tests?"), True) if not reply: report(_("Your configuration is now done but not tested")) return else: if speechd_type == 'user': started = self.speechd_start_user() elif speechd_type == 'system': started = self.speechd_start_system() if not started: report(_("Your Speech Dispatcher is not running")) result = self.test.diagnostics(speechd_running = started, audio_output=[self.default_audio_method], output_modules=[self.default_output_module]) self.test.write_diagnostics_results(result) if not started: reply = question(_("Do you want to run debugging now and send a request for help to the developers?"), False) if reply: self.test.debug_and_report(type=speechd_type) # Basic objects def main(): options = setup_argparse() options = options.parse_args() test = Tests() configure = Configure(test) # that should possibly be refactored, test should not be passed if not options.version: report(_("\nSpeech Dispatcher configuration tool\n")) if options.create_user_configuration: # Check for and/or create basic user configuration configure.create_user_configuration() reply = question(_("Do you want to continue with basic settings?"), True) if reply: configure.configure_basic_settings(type='user') elif options.config_basic_settings_user: configure.configure_basic_settings(type='user') elif options.config_basic_settings_system: configure.configure_basic_settings(type='system') elif options.test_festival: test.test_festival() elif options.test_spd_say: test.test_spd_say() elif options.test_espeak: test.test_espeak() elif options.test_alsa: test.audio_try_play(type='alsa') elif options.test_pulse: test.audio_try_play(type='pulse') elif options.diagnostics: ret = test.diagnostics() test.write_diagnostics_results(ret) elif options.debug: test.debug_and_report() elif options.version: test.version() else: reply = question(_("Do you want to setup a completely new configuration?"), True) if reply: configure.complete_config() else: reply = question(_("Do you want to run diagnosis of problems?"), True) if reply: ret=test.diagnostics() test.write_diagnostics_results(ret) else: report(_("""Please run this command again and select what you want to do or read the quick help available through '-h' or '--help'.""")) if __name__ == "__main__": sys.exit(main()) speech-dispatcher-0.9.1/src/api/python/speechd_config/speechd.desktop.in0000644000175000017500000000163213406252220023267 00000000000000# Copyright (C) 2008 Brailcom, o.p.s # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . [Desktop Entry] Type=Application Encoding=UTF-8 Version=1.0 Name=Speech Dispatcher Comment=Interface to Text to Speech services TryExec=speech-dispatcher Exec=speech-dispatcher X-GNOME-Autostart-enabled=true X-GNOME-Autostart-Phase=Initialization speech-dispatcher-0.9.1/src/api/python/speechd_config/paths.py.in0000644000175000017500000000022611447133617021763 00000000000000SPD_CONF_ORIG_PATH="@spdconforigdir@" SPD_CONF_PATH="@spdconfdir@" SPD_SOUND_DATA_PATH="@snddatadir@" SPD_DESKTOP_CONF_PATH="@spddesktopconforigdir@" speech-dispatcher-0.9.1/src/api/python/speechd_config/README0000644000175000017500000000134713406252210020536 00000000000000test.wav is Copyright (C) 2008 Brailcom, o.p.s and is licensed under the following terms: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (file COPYING in the root directory). You should have received a copy of the GNU General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/api/python/speechd_config/Makefile.in0000644000175000017500000006643113465233610021740 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/api/python/speechd_config ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_bin_SCRIPTS) \ $(speechd_python_PYTHON) $(dist_snddata_DATA) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(speechd_pythondir)" \ "$(DESTDIR)$(speechd_pythondir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(snddatadir)" SCRIPTS = $(dist_bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile) am__pep3147_tweak = \ sed -e 's|\.py$$||' -e 's|[^/]*$$|&.*.pyc\n&.*.pyo|' py_compile = $(top_srcdir)/py-compile man1dir = $(mandir)/man1 NROFF = nroff MANS = $(dist_man1_MANS) DATA = $(desktop_DATA) $(dist_snddata_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.in \ $(top_srcdir)/py-compile README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dist_snddata_DATA = test.wav DESKTOP_FILES = speechd.desktop.in desktop_DATA = $(DESKTOP_FILES:.desktop.in=.desktop) desktopdir = $(spddesktopconforigdir) CLEANFILES = $(desktop_DATA) paths.py config.py speechd.desktop \ $(dist_man1_MANS) dist_bin_SCRIPTS = spd-conf speechd_pythondir = $(pyexecdir)/speechd_config speechd_python_PYTHON = __init__.py nodist_speechd_python_PYTHON = config.py paths.py paths_edit = sed \ -e "s:[@]spdconforigdir[@]:$(spdconforigdir):" \ -e "s:[@]spdconfdir[@]:$(spdconfdir):" \ -e "s:[@]snddatadir[@]:$(snddatadir):" \ -e "s:[@]spddesktopconforigdir[@]:$(spddesktopconforigdir):" config_edit = sed \ -e "s:[@]GETTEXT_PACKAGE[@]:$(GETTEXT_PACKAGE):" \ -e "s:[@]VERSION[@]:$(VERSION):" \ -e "s:[@]localedir[@]:$(localedir):" EXTRA_DIST = paths.py.in speechd.desktop.in config.py.in @HAVE_HELP2MAN_TRUE@dist_man1_MANS = \ @HAVE_HELP2MAN_TRUE@ spd-conf.1 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/api/python/speechd_config/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/api/python/speechd_config/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nodist_speechd_pythonPYTHON: $(nodist_speechd_python_PYTHON) @$(NORMAL_INSTALL) @list='$(nodist_speechd_python_PYTHON)'; dlist=; list2=; test -n "$(speechd_pythondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(speechd_pythondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(speechd_pythondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ if test -f $$b$$p; then \ $(am__strip_dir) \ dlist="$$dlist $$f"; \ list2="$$list2 $$b$$p"; \ else :; fi; \ done; \ for file in $$list2; do echo $$file; done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(speechd_pythondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(speechd_pythondir)" || exit $$?; \ done || exit $$?; \ if test -n "$$dlist"; then \ $(am__py_compile) --destdir "$(DESTDIR)" \ --basedir "$(speechd_pythondir)" $$dlist; \ else :; fi uninstall-nodist_speechd_pythonPYTHON: @$(NORMAL_UNINSTALL) @list='$(nodist_speechd_python_PYTHON)'; test -n "$(speechd_pythondir)" || list=; \ py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$py_files" || exit 0; \ dir='$(DESTDIR)$(speechd_pythondir)'; \ pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ st=0; \ for files in "$$py_files" "$$pyc_files" "$$pyo_files"; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done; \ dir='$(DESTDIR)$(speechd_pythondir)/__pycache__'; \ echo "$$py_files" | $(am__pep3147_tweak) | $(am__base_list) | \ while read files; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done || exit $$?; \ exit $$st install-speechd_pythonPYTHON: $(speechd_python_PYTHON) @$(NORMAL_INSTALL) @list='$(speechd_python_PYTHON)'; dlist=; list2=; test -n "$(speechd_pythondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(speechd_pythondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(speechd_pythondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ if test -f $$b$$p; then \ $(am__strip_dir) \ dlist="$$dlist $$f"; \ list2="$$list2 $$b$$p"; \ else :; fi; \ done; \ for file in $$list2; do echo $$file; done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(speechd_pythondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(speechd_pythondir)" || exit $$?; \ done || exit $$?; \ if test -n "$$dlist"; then \ $(am__py_compile) --destdir "$(DESTDIR)" \ --basedir "$(speechd_pythondir)" $$dlist; \ else :; fi uninstall-speechd_pythonPYTHON: @$(NORMAL_UNINSTALL) @list='$(speechd_python_PYTHON)'; test -n "$(speechd_pythondir)" || list=; \ py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$py_files" || exit 0; \ dir='$(DESTDIR)$(speechd_pythondir)'; \ pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ st=0; \ for files in "$$py_files" "$$pyc_files" "$$pyo_files"; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done; \ dir='$(DESTDIR)$(speechd_pythondir)/__pycache__'; \ echo "$$py_files" | $(am__pep3147_tweak) | $(am__base_list) | \ while read files; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done || exit $$?; \ exit $$st install-man1: $(dist_man1_MANS) @$(NORMAL_INSTALL) @list1='$(dist_man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(dist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-desktopDATA: $(desktop_DATA) @$(NORMAL_INSTALL) @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(desktopdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(desktopdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(desktopdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(desktopdir)" || exit $$?; \ done uninstall-desktopDATA: @$(NORMAL_UNINSTALL) @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(desktopdir)'; $(am__uninstall_files_from_dir) install-dist_snddataDATA: $(dist_snddata_DATA) @$(NORMAL_INSTALL) @list='$(dist_snddata_DATA)'; test -n "$(snddatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(snddatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(snddatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(snddatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(snddatadir)" || exit $$?; \ done uninstall-dist_snddataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_snddata_DATA)'; test -n "$(snddatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(snddatadir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(MANS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(speechd_pythondir)" "$(DESTDIR)$(speechd_pythondir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(snddatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-desktopDATA install-dist_snddataDATA \ install-man install-nodist_speechd_pythonPYTHON \ install-speechd_pythonPYTHON install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-dist_binSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-desktopDATA uninstall-dist_binSCRIPTS \ uninstall-dist_snddataDATA uninstall-man \ uninstall-nodist_speechd_pythonPYTHON \ uninstall-speechd_pythonPYTHON uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-desktopDATA install-dist_binSCRIPTS \ install-dist_snddataDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-nodist_speechd_pythonPYTHON install-pdf install-pdf-am \ install-ps install-ps-am install-speechd_pythonPYTHON \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-desktopDATA \ uninstall-dist_binSCRIPTS uninstall-dist_snddataDATA \ uninstall-man uninstall-man1 \ uninstall-nodist_speechd_pythonPYTHON \ uninstall-speechd_pythonPYTHON .PRECIOUS: Makefile speechd.desktop: speechd.desktop.in $(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@ paths.py: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(paths_edit) $${srcdir}$@.in > $@ config.py: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(config_edit) $${srcdir}$@.in > $@ $(abs_builddir)/__init__.py: ln -s $(srcdir)/__init__.py . paths.py: $(srcdir)/paths.py.in @HAVE_HELP2MAN_TRUE@spd-conf.1: config.py paths.py $(abs_builddir)/__init__.py @HAVE_HELP2MAN_TRUE@ LC_ALL=C PYTHONPATH=$(builddir)/.. PYTHONDONTWRITEBYTECODE=1 help2man -N --output=$@ $(srcdir)/spd-conf -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/api/python/speechd_config/spd-conf.10000644000175000017500000000350013465234512021454 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.8. .TH SPD-CONF "1" "May 2019" "spd-conf 0.9.1" "User Commands" .SH NAME spd-conf \- manual page for spd-conf 0.9.1 .SH DESCRIPTION usage: spd\-conf [\-h] [\-u] [\-c] [\-C] [\-d] [\-s] [\-\-test\-festival] .IP [\-\-test\-espeak] [\-\-test\-alsa] [\-\-test\-pulse] [\-e] [\-n] [\-D] [\-\-version] .PP A simple tool for basic configuration of Speech Dispatcher and problem diagnostics .SS "optional arguments:" .TP \fB\-h\fR, \fB\-\-help\fR show this help message and exit .TP \fB\-u\fR, \fB\-\-create\-user\-conf\fR Create Speech Dispatcher configuration for the given user .TP \fB\-c\fR, \fB\-\-config\-basic\-settings\-user\fR Configure basic settings in user configuration .TP \fB\-C\fR, \fB\-\-config\-basic\-settings\-system\fR Configure basic settings in system\-wide configuration .TP \fB\-d\fR, \fB\-\-diagnostics\fR Diagnose problems with the current setup .TP \fB\-s\fR, \fB\-\-test\-spd\-say\fR Test connection to Speech Dispatcher using spd\-say .TP \fB\-\-test\-festival\fR Test whether Festival works as a server .TP \fB\-\-test\-espeak\fR Test whether Espeak works as a standalone binary .TP \fB\-\-test\-alsa\fR Test ALSA audio output .TP \fB\-\-test\-pulse\fR Test Pulse Audio output .TP \fB\-e\fR, \fB\-\-espeak\fR Use espeak to synthesize messages .TP \fB\-n\fR, \fB\-\-dont\-ask\fR Do not ask any questions, always use default values .TP \fB\-D\fR, \fB\-\-debug\fR Debug a problem and generate a report .TP \fB\-\-version\fR Print version and copyright info .SH COPYRIGHT Copyright \(co 2002\-2012 Brailcom, o.p.s. .br This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Please see COPYING for more details. speech-dispatcher-0.9.1/src/api/python/speechd_config/test.wav0000644000175000017500000004200211447133617021361 00000000000000RIFFúCWAVEfmt €>}dataÖC`˙kGţ†_˙Ţýđ'ţDFcýE¤ýs˙ŻťüaŒœC‹ şŻúúmń†ëÓř÷ýŰýd <*ěűa݆˙–ü*ÝüŽů< Çď l´‚öńň(ööL÷]ţ“ţ°űœř0ýÍ 7äţČĺţ|îqď ňœěüŹĽB"˛ÎÖ*ýü’˙;˙řö˙÷6Ě) 'řBíÉçńë:đŘřJ]ÍuşýŃďŤň€ôŁęécěpéěěĽF ˆ\)&f„ ő€ľ–° wĄČÓ LŒ’ öý÷ôňçŒáýá×ç“öuÍ ˆý Éűaě^čÄä÷äqě ńrńĎűíjHŽŠw´sĺý„ ˙ß÷ŻúůŽţ ç Ď "Qű‚ëCÜÝŻâłí ţ ÎS# qűlňÇî'íŤďŔó^őřCš ? zg#JŃ.üŠ./+ţŐú#ú}őtţż ľ XgžůCäœ×_ŮÍŕGď˜@N7ÂđÉé!ĺ×ĺœí>ňŤńHús‰b”!„vĆۢFQ˙xrű€úÖ? ‰ŽţdôWătá/çŠď!ü¨ ŇdxŘ ŕů;ďĆí‡ěaď‚ôŤó%óĚýĚí‰p"AqE*,űŘ˙H؇˙ýłőyüOç í˙dűíŽápâ_ę˘ösŘ?lJĄśńˇííˆëłďÍó†ďöó(: Ł ö!ęąŘý)P~˙˙ůůwů." qęaůĆęcâHâ[ěčřňŃ$zń űů‡ďLíöę˘ěĐńnđî4ůĽ6‘(uRĹ[ýVţ[$TţýS÷ŃůâţÁËđŠţ†őSéă[é˛ő1˙U Čóhő,ďtě:éí9ň îžđĐý­Ů Z!C#Ž]s KţB˝ýňü ř1őËúŰž˙.ţCđeä'âvě"řc`Ąć˝ŇLô!đűęĄč+î|đ îh÷ÜVjô# í4 X÷˙ ۇý°ýŕ÷ţř#DË ÄĐ`ü÷ě¨ăćěń€űIÇK úňŐëćˆčDďĎíwđ–üŽĹ•T šmüâ˙]TţÉý~ůąôŰůŤâö Śöé äŽěc÷uUňŰîœř8ń,é{ć íńƒđ?ů­şŃS"/í́ ß ˙@=jýžü#ö°őçűŤ–k{ţOď:ĺ_ćˆńCúd °R )üNóˇë ä˙ä\ërëPîůĽţŞUˇjçAx˙ŚžĎobýFř­űű” } …túní%çîiřą Š¤O ƒůdňéEăŠç˛ëëČňžü1# š–bi˙WüĂYÍńů}ůëţnŻĚ&ŁQópč%čŰńđřh› ŇËM [ý‡őŞď›ç4ç'íçěžď‚úň˙gĂ p=6Œ˙ý_Y§0Aůąű™ßÁ śüEîuć¤ëYôŢű˛Œ@ć2řĄóŠěŕĺüč&ě8ę—đÝůĄý˘ XŔčč ŞÂ˙t3Iť™űńřDýźĂ­ R>öŹéęć/ďöˇ. %ęţ8řňDę)č™ízí°îařŢýźg t5Ő>Î˙ŮţÔýţl÷Eůůţ ćHý¸ď]ć°éĎńIů'" űÚ'oů¸ó ěžĺ é'íěëzňáű‰ţ= GÜÇ+. ÷–Ĺžž˙nü-ů1ý‚\uĐ ˝ÄůřěáčŰďeös˙¨ VŻP/÷yńXéQćoëłě'î7÷RüŐ˙ '†Áᶝ˙ú2Ą°ýžůDú˙ýIóîŹ˙Żňč ëhňŕřŽ& Ď! ůü“÷ ńęëŽďřîąó™űŽýńůq(.ţóYŕťýú˜ü•¨l "múíç*íŽó%ü, đ’ůeô›ěmé÷íěîáďű÷´üů˙3Äłł " —€4ţůx„úƒúřţ%¤ZV76óýçAéqđđöŽ đĆ˝rü ÷­đŢéhëbďšîqó;ű?ýw#ë( Đ t°˙|aß[SýĘůaüSC ł úíbçdíłó'üÝŇ „¨Œůqô×ěËéPîCď'đřĂüţ˙ě,1J­á ‡îëc”úŤú˙#”@2,kóčĎéäđH÷¨ Đq‰…ü?÷ńbęęëĐď*ďßózűjýšÍ`ĐPš _Î˙Ÿ]ŕ[týúüp@ űşúqíčŕíôfüĐś Ě*•˛ů´ô=íOęĐî¸ď’đbřîü#ĐŽżřeŽ u âęZ¸úÔú(˙" &Ąóűč]ęFńŒ÷żß ?‹üe÷SńŰęZěđ„ď8ôŠűŠý¤mŃ_ćB ,Ď˙Š3Ň9ký(úŽülćҝúŤí„čHîRô–üĐŠ płeÉůßô‹íÄę;ďđăđ“řüü#’=™a U—îĘÔBÄúîú<˙ \űءókéŕę›ńË÷ȸGó”üz÷ŠńGëżěođŢď|ôĆűĄý 6í„ô Ń˙qˇhý?úÄütű¸ł…úőíéłîôąüžb RGŘůőçí5ë˘ďjđ4ńżř ý0^ŠŔ/¤, <‘Ółž.ÝúűB˙í<Ńšę˙ÜóŮégëűńřׇú"Ś•üŸ÷ČńĆë:í¨đ(đÚôčűŽýŻŚœœ ćŕ˙căŤůbýZúĺüŰŒbúAî–é#ďÖôÓü°> Äç ęůDő6î˘ëđČđńőř$ý;%üCĘCď(Ž˝Ÿčú2űP˙̨\â˙ôIęÝëMňPřěnˇ´eĄüÍ÷ ň*ěŻíń„đ)ő üÂýŞ1˙žC żŢ˙Gş•ĎVývúőüwĂs[4ú‰îę‰ďőý¨ c| řţůwő‘îě_đ#ńňń#ů0ýDŕhť]ół ’ąv„ôáú•űőţ r.˙`ómë>ěkóř°œÓ w2ßü—ůÍň—íżřyů´ěîxęîśľ— sŃ ď `ţ¨şđţýT÷Ţř• kĘý!ňßxŢć§ëÁřŇo W đ ôüƒ÷óýŢAߙăqߒúVoä+5YÓńŢ7ţrĽúém 1 6 % Ů]řŢđPńđí‰íNń#óüąňú§˙OńMć)äیĺ¤ůK€:ó ›ł{¤8 ~öÜސňTăŸŢ†ĺEóÓç {Ćű#äxŰÄÜáÓîÍúJ7 'ň6 "!ŕôBűš%üÓŒĄŸ9xł2řđčçŢĺVěĘ÷2 ëCŹŁ ÜúňîĂáuŰ â˛çöD ƒ$ 3lŮ­Vő*ďbôańdírďóz˙Ľ˜€ 8÷#ă Ţ÷ăů™aô!]_ýĆě'ëěéhîů•ôň!őĄńř]4’KŞ AłýCö/îççńÂüű"ű”ú~ď[ďvúéţV3'! [b =öňčíśéIđCňLů ń  ˜űřűôŃôóZ  ýeůÂđűĘđ¨í˜ä8Ő;Ř$čĎő_ Ł*š0)'ľ ţ›ńŒěŽďOö‰ô>ôéúsüL 1$t#ćŤ "÷ďň‘ďsńÁóżö5Ň‘üńŠŢ°ĐŚÔ+ĺçó˝ą{X –jŇýŸú‚ţŠ÷íîCýÂţ(E#dťT5~  ýÝüîlĺčí{ůţy\!űŮňĽî˜ńGů[Ľ  ďëóĺ`éŐćRő Duß!ú#""'ÍÚ ĹŁţţUü‹ţ™ü üç 9ŕółęÇáŮQâcö>źś$ón =őďâŔÜŹÚFŢĘă(č™ô[,>223œ&â!c!ĺ ]¸@ű(óöú@†×˝ ąű ĺ~ŮÜŰéýP&Ădň*ó‘â¤áUâVۢĺ>ňKöR Ć´Ýŕ6ü Œ [Sů6ůF˙–C ˝žíöźęĂéqô;I ŤŘ 9ŕř4î…íě¨ňĄ˙üú}÷@űžúvÄŚ YçŁü•ýçh]L 0×Ć â ° ţąíŮäŚč=ô5¤Ë ęő(äœŇ$ÓXßläfň™ ˜%?Ó Ľń đ;÷Dö›řüúŮö ­1$ß ň\ç{ňýA¨Rœţäü÷<í„ę í›äěޢç ńĄ~}+Ţ ÜüŔűšřOň î|ěČî^ř/ě döúNâÚ Řďô žýČó˜ć9â•ëđUôFc÷ ä Śę…0M žź:ř€ô2řĐůýa˙+řšë­äéůřĚ >˘] Ą{ýôŚď…č€ěýě“é§ň¸ů â%“ŕ}ô!ö4űý9ŰţQv ó Ő+ţżęóېßxčjólĎdS Ő*ůŹď đ¨íĄîűm˙B 6ăY!z  B #ű"ďCíŢ÷zô˘ ř Ň˙¤ëŕĺ“ëţńlű“ Ęrůkóűěéľóżö”ô&ţ"›l> ŇsŐ ˝˙ĐřĐHüź‚…‰ ¸÷Öëôë+ő8B ˜ čk yúňî'ęáéâöérë­ő3Ľ ‡!Ç–‰ R\üW÷ýv<ą I üFéKâCéóÚ †I Aűűň…čŤć‡éČéÂń(řÎý;ů%D˙¨_ćç´úţťtćÓc˙ßďˇčîsőńý@ %žRů]őíóěœđîeóšůjü tÓB•\BdűSýZä0 ł$ˇďżćJëóóËţn"ü^ř<ň~é"čžíYîĽôňülđY!B žd˙Gč$_Őú†ţTƒS × !ń9čůëŐóÍý¸Řűrű3ö‚íę™íěŠđ ůšü ąŠ^b)†Il˙˜řÓů‡ŕ`­ …‹ô+ęŰěŃóĆüŽfŇ~ pű[őéě˘éď"ďkó‰űWýĄ ĐÜ­zÎqMM?ĐůZůj˙ć;ŮQ>ógčĐëő‘ţŰřż’ .ü÷ŕî&ężîNîYń(úŠýH v‰üüăBţrsä‰ü×üŇÄţfC§ňXçÂčQđ|úťu D#2˙ ůńđ°ę@î8ďňuúyý&k‚|ťĘ'  ‹ůţřę˜ 2÷YéKéŽď řYí 2 Qý'÷ńŹě‰đMńóűú)ý¨eĹô,=V§B˛#ýĄúw˙ÄČ’g÷Të€ëó,űĽ L Hüűő6ď°čí)ďęđűq˙ЏCz]Ą Ÿ›Ň‹™Düún¸[ 4T÷Đč¸çďLřD ô*ˇ÷ÔđŐč"ë˛íŘîőöXű›AÄ2ź. .<ŠÔýnúš˙VN$DÜúíÔęzđ‚÷ŢÓ˜ [lůô!íťîăďxďŘöRú’Uš’ ˏžŠ{˙ČúŐţ p˝ÉRűŒěCéÁďRř,’ Ř@ń˙uö6ńúéQě…đńHů1ţlSן [m “h˙šüĎ g~ üÍîcęÔď~÷^qDY:Aúőběúëî•íAőűľ*_ }+ §ƒ÷E.Xý–řýb€ő Ó É˙6ńŽëäď˜ö>ň;ď™;ůTôśě7íńđđ!÷ëűƒţj Ż˝O0 ďYŕ€”ţřűJs>ţđëJń„řR‰ 3°íú öÔíÝěđxď…őQü B˜Ő8 „˙ĽXÎkcü<ţň:JFhýšď|čÇěŇôKţPŒŇîÂü˛÷éîiěŢđÚđ›őWüžţa ÜŐkěÍlœţJůžűęÎ9 } .ň‡éHěŽň÷űŇ dűŚ÷ńÖîœň1ňôőüUţ hÖ +ŞĹCňď&ű8űö˙úoq<’ôCě´ďÓőýĺ Ą&ú[őîĄë3đČđ1ö(ţţ˙ô ůA‹ŇűĽŁˆüRűLüqYŢq•~ň5éíëOóŢüDQ g üžö˘î˙é€îďýń!ú5ýiĂtăŻŘöCŹŠ_üĂűŕ‹Ź•÷öÄě‚íĘňŞů! ÚĄ ÷ýdů-óÍíCđ&đřńŘř=ű™6¨¨ŻGÔüĎëü!ű€ 0ˆ˝öřë íÝóŰűÍŮ s iű>öŠđňë‰đAň˛ôAüĄýw›ô  Ý ˙+LÖŽ2˙]ýVšű/ůœíDí9ó"úźN É o˙ŤůóěííďŕđüřŢü~s‹†Ÿ˙Ղ>žűDúŸ˙§H? Ë’ű[ď{íň9úM9 o! ŰţŞř‹óľí~đňó`ů_ű,éF™›ß Îg5p ü„ř}ým[Ť‹ú§ď ď‡ôeűŃh ëŕ âřů§ôäí<ďUńôńzůdýMš&x %ą˙0łŽ˙˙äűćţ˜6Jú˛í%ë5ń‚řœ• ĆŒjűźő îĂďźňxň.ůśüAüÔď Q˛“T1ýúéţ›ůQZüZďúęQďeö(˙V„ • çMű;řňđMńô5ó~řŤüaŕXď Ř (śQU˙âů üęŕńí‰ţŚňŽîpň°÷f˙ ä 7 XŰř˝ôjîŃî¤ňôKúŞţ Ľ‡Đ:Đ čâOc Ž˙zűeţŮt’=üxđňë˛đ řz:ŚˆC:úőRîîŻńIńŠö]üS˙á †űtp ęR×1łiÔű'ýżgMK_ťő˛ďŞńňő¨üŞĂ Š âeýŸúńósńěóó3öěúý­ú…   ďg_(e>üÜýYRŁľ˙‚öąń•ôců‡˙ݝ äÝúšř?ôˇó2÷Í÷ úŔýkţ;H Y f)˙M¤Ś/?˙ž˙ pąžZZůKôŘőůěýĎQ „ţZűöóAőýő řvý˙›T ÂtUţţ˙˛rJ˙úüšý,­8öë üęö+÷˜úíţÎ[éfßý=ü†ůŰ÷ďůčůYúMüŽüÝ”]sLD bŤ ˙ üTüćţ\šœÜHýěú?űDý$ŰÄYQ˙…ýűŔřôůŤú"üÚţÓ˙eľ8Œ3˙9Ą—ô˙`ţv˙-÷˙!d˙íű6ů?ú1üčţŠ”ŤßšţsüxűŸüľüNý™ţľţö•hDEÝ˙'˙ ţäţ=˙°ţ^˙"ŤíBžý˙ú›úěű`ýęţŇ\ŻÝmEôţJ˙˙mţ;˙-"& ąd֐ `pŚżţJýÁýűţÔ˙ôb›ż˙Řţ9ţţ#˙D˙˙˙_ţŐýčýaýSţ<ĺC† 5Ďs’´P*ŠVß<“~˙Uţfý‘ü ýŻţMđ’C˙uý%üýügü˜˙ôý ţpÇ–. ÜĂú ţ­>ýĐř•úsýîůüÍé &íýý{÷îkíTńÄů ŰŹ ­ Ćľ¸e_y čó)đ3úš÷ńŠô•ů%÷œôöCúĎü3ůqřaţţ}ű°ýŽÔÇô  –ˇ˜üĂ F ö÷î/ůů´ěŃĺ’éËěKďôĽü?íüDűü ýŔ EÚ¸›âq ú?Ąö”ĂůČęźé+ě5ěyđ×÷#]şűXô!óLö ýâüţ[ O˙Ě Âöţó†Śôhű "žďˇčhęëříó{ţpő˙ń÷ăţM Y tCMţ„•ß˙Ćöz +ţŢůşUłó˛ĺVĺĺéć#íO÷¸s.ý1ů‰űŽ&-|ů€ řţSp!  óV’o üO 'úÔâwŢőâçî—őVgţÓ÷Wůˆ˙ˆŘ˙çŸîü‰„ŽźőHúeź óöůJëŕ™äęÜńŻřׯ )ďűd÷F÷Žűů.ňrů* ďĐďŰnú÷ú 7ůó[řôétęČęFí¤ň~ú|`ńúźôčň¤ő/÷‘óřq Ľ Ŕ{âk1ô§0> í5 …jdę.éĚěăíŘďžő3 üőiôöř/őŕő?mĎŇ {"@Fůă˙WŒÁ— _L!őřęë—č çôéö\ţűőďjď„ńË÷eř‡őŐüŢ 1Mh5 Ţ]TŠ Í ‹Źů]çnćrç'çŘčlô€üĐń+đ,ďŃńSôąńö(ô ťDd&XůV`G˜ ô)2?ďzëťë^éçöëÖř›ůŸđśîPď4ňŇö5ő*ôo˙dY {2 Ţ!>űÓ: C 1Z ôětî‡ě˛çˆéz÷Fý,ôĄđ6ńó<řůŐ÷íţč”mڎw$kţ†{ ’ő­Cţ’îĂí‡íŮč¨ć ńéűöżď×î‡đůśýŢú)ü aţČ$!]&˙, ŠĄ Yw ą,ěÉç|čUç„ćÔď2ţ-ýčőăóńń˙ő#üšűÂú& Ę.$lăř­ţÔćX ö‰ëąę’č–ăľĺĽň÷ońlďđxôŠúëüŃüŤ)Ç ăgfpg0SxkćřLěĆíâďÂíwěĘôÍúô ďîüď[÷îüţľ ť yTĄř Řű¸ >= ń 2|4đŠëĐëęNĺę×őÂőĎńçńó ůŽ3˙ůRË ÔýH Ă,ú# moWö”JóŠęŚé0ęĽčJëG÷Tű´öôÚđ°ňwúyţ›üé_É˝ýŠRUEŃ}fô źúď–îXď/í€ë…ô†űœöCóňňňhřëýţ˘ýi ŞĽ řň Ç -i ;Ú•ý Ö ýďžíăđ“ň<đ‡ôIüŚř—ó6ňŞń…öý˙ŹüYúÇ–Šü~"Ť ŃÁƒ˙>ôÖëÂęÁëÉčdęáôsö*óűóĽó~öüţĚĹ˙Č: =4á„ t’1'„ °!ř'îxěäî´î÷ěüô/úHöäóPńxđőőľüüéüš ›äŕYkü hň ٸ -Şó@îFîWí¤ęgńÇú(úň÷Żőň?ôˇůű˙řs" HÓ;áĽ3ă `˙1î \önî đKó`đaňjű>ű‰ő)ňđóňžúľ˙&ţˆĹĆ8Sţĺ˙ŞĹ÷7Š ţkńżíđQîě%őXůéőŁô”ň1óAú%)˙~ý 7QŠu\ő so zŒ/ţě (şňëíOđ ńî˙óĚűúž÷“őMóöŞűPý űçÖä ĂŚ M—ČmŮę Ůoő%íí>ď^ě:ďů űüůż÷6ô^őţů'ýŕű>0-˜Ěą]G{ŻŽ_ýG1 űĆńń˛ô˛ńSďŻöúIöŐó™ńňiř ˙î˙Ô˙Ď B ąÓ˝• Óţç%A ˇ}|óUě4í)î•ëÇńšú¸ůŻö.óń4ő›üu˙ýůcy ę(\=ŮŠ Çš ˝´öňîfîNđ îđzřůÔőžôýňÜô&űSýşţ3 Mv¤E@[QrżKŁé Ĺ âűÂńŮďŢń)đ.îěőŚű_ů/÷†ôěó÷–úňůĎúĄ üyg mţj°=|ü‰ xőň—ô†ő•ń{őˆü¨ú"÷Ďôóňöőü[˙1ý7S 7} đTĐ˙ÜŤÜ žR- Ĺ–ö™îšíđ…íďˇůţű(ř,öŸóřô7üäŃ˙¨ZŮ劯›3(… ć 7 ň ôý”óôî4ďśíěôú“÷jöŽôFôöůB8˙ţóďăhß5 ¸T ä Žr¤ ˙QňţíBđń^ď/ő-ýăúćö ôń3ôşůbű@úÓHĽ A|ű1ň— Č˙˙ Ž÷ ńPň]őÎń}ńÝřúÜögő=ôŰö+ýţ˙‹ü˙ƒ mÚćC‘Ř[ť˙ K } Ýýkóđrńmďœíˇőíúř"övóCňôöYţr˙a˙ € i‰F# ¨ţBîI˙O öG÷hńbń đîóuűűzřĎő9ôK÷ýü˙ˆü‚k Ô!ţÔŠúž Uď ugŸ Ăöűď¨đşňńÔóňűPý6ú÷Cô×őúÂýČűjţĹ ý›WQ‡˙_ ˘ óž˙˛ Ń ˜üüńđďĂňŁń?đF÷ŽűůröQő-÷¤ű|ä˙KţJlýŸ #Ž ůţ Ÿ˙ôć őIđăń(ógđÄóÄůň÷yôLňşńQő°üáŰţ<€lBL ÷ %Űő8 hŰô JůVňŠđMđűěŤîË÷íúmůžřQ÷˜÷Žúľýďú>üŕ0 ÄHťÁ‰ˇD I ýĂóÍđĂňűńşđç÷óüRúÚö?óŐň"÷KüíüƒýÇT(•ƒžŞ'ţ°Ýžţ Ţ şÂöĺńó°őóŰöLýűj÷tőő~ř3ţ×˙Iü4Ă ź A … Îëž € ţ ˝€ůkňŔńďô§ň‡ňú*űN÷żő]ôöţűš4˙Ď˙ ˝/™šýyŸ ŠÎW / zü°ňÓîčďďî÷őoűAúFúřř,řYű˙ęýÓü]ĽšŢ˙" ąX ={ ęţF˙[’ ÷Žó}őëőžń§ôŚú_ůV÷¸ődôi÷ůű›ý˝ý‰lR -P zlŕÁ ü ˙fa $úťóŻň[őmô}ő¤ülţüÝů+÷­÷?űÍý8üđýt +šAb|ď? PZżäĎţj÷ýôJöşő?ôĽřqűOř*öxő§ö*űáą~ <!˙^pݧ˙ľ} ´9\U {9úĽöÂöröĎôs÷Óű`üëűhűűüĽýOý űţUŃ#ąUý ŔŚ7 Ě€Żƒ)ü-úÇúnű´ů}ůłüÂýäüóűęúűzü§ý ý˙ä/zvx ? Ş sýJ˙kĚíűô÷Œ÷łůűśú‰ýŔC,ţâüîü›ýŽ˙ń˙˙?Ę/šű- *î˙ą:Ő˙Gý3¤B˙ďü`űBúsř€řăúSű@úMú!ű‚üz3{öŁDs;éCm‹ś<oýkúşůćůäůoűœţ1E˙űý‚ýřüÜüýúüWý„ߟWŠ"řpÚĆÄ^ţţ9ţîýšţnţýŘüýCýšýTţK˙0}Üţƒýůţ8˙J˙ʆŤ’˙YV‘ Â@˙žţfţ&˙{˝˙ˇ˙ô2‹˙2˙UţÖýMţ0ţ˙„ËŠČHţýSţ‘ţÔý{˙–cď°ů˙w˙˙ýŃüĎý‚ţ%ţÇýyýäýe˙ž”—pkO˙šţTŔh€˛ó˙&˙¤˙›ţ‚ý°üĚü*üÝüŰ˙ +›/ú˙—˙Ţţĺţň˙Ě˙E˙•‘ŠÔ˙ůJĎ+îäPfţÎý\ýŢű_üŒýţÚţçţŞ˙Xe&M˙Á˙  ,~âÎ˙zÍ:˙o˙o˙‰ýzü›üqýŐ˙I­ °˙’ý’üfýţŇţ*˙5˙vę>ľÖeÎw˙CŁ´˙˙§ÄA…‚˙šţý1ű2ű[üý˛ýŽţĚ˙CQý}ĂĽ˙!9ŤCŽ&1Ű˙ŕţ’ýGüôűhý ˙Ŕ˙˙˙+˙'ţäý'ţŁţ×ţÇ˙ĎŻ˙$˙5cţEKÄű6öG˙đţlţCţ5˙ť˙U˙šţńţ˛˙ő˙­˙ţĺý–ţ+˙˙MÜ2çd%&˝ý‡üţZţý+ý€ýŕţÁpC[Ž˙ˇţc˙ő˙gôţ6×g‘6ýîýG˙´˙Á˙ńia—˙4ţwüüÍűŠűÎü‰ý˘ýďţ<l1ZCÖ@V$”^ĂÇߥ˙­ţ˜˙Ž˙ÎţÂţĘţŮţ˙ýîünýżý]ý“ý.ţ‹ţçţ*˙ôţ$"Oöpä‘$ËöœpNƒ˙xţ6ýrüü_ý˙ČźÄ˙čţLţ­ü˙űţý‰˙ś˙*‹Ô #{Rţš˙…d˙0ţVýŕý×˙ŞíŸfţŤüÓü:ţ˜˙â˜ś˙Ň˙ŤSŞţeţŻ˙Á˙˙€ ˛,áţ’ţűý}ý ýmýiý­ýţ˙â˙†RŇ˙)3Q]Éíć$2ţ)ţź˙xś˙ęţi˙(ŢţÎýŮţ˙÷ţŔ˙ű˙hgz˙ěţóţó˙"˙x˙r\˙Íţć¨Ë‰˙Uýšüňü:ý÷ü–ýÂţ, =Äđ-˙Aţ%˙)ý˙A?)y}˙‚üĎüÔţ˙Šţ˙¨˙ő˙ś˙R˙8˙äţ‰ţ˛ý8ý‚ţx˙ç5Ó—&kńböoŕ˙ą˙˙H˙˙z\é˙Pýü{üśüĹýěţ˜˙źţ2ý7ýwýŕýy˙<+Ü}ďUÜ! eěţŃţ¸ţţýHý‰ýĐü7ýţ$˙—7K, ˙p˙Đţýţx|p˙Â5ŽŰCŮę4˙ëţ˙˙ŐţĂý4ţ)˙˝˙÷˙Ô˙Ř˙űţŽýpüşüV˙SWt-4úţ ˙`˙˛ýîü˙ ˙ăţÝ˙'›-ä˙{ţ˙ň˙q4&ťţ&;Z)ńĺŐÝţU˙M˙Sţţiýoýýý•˙~˙ ˙ĄţŠţ”˙îß{ aşyO9dvg˙Lţ;˙ĽIb›ţHýĘűÔú;ü!ýgý‡ţ˙?$,ęŁýz…˙Ą˙Ł‘h˙”\Ů$҇.ţ›üýŇýĂţţţă˙Œ_˙­ţ ţXýíýXţký!ýŮţîŽ ËüÂÚÍgŔţ˙ ˙ĚţCţkţÄţ–˙¸˙ÜţÖţ˙˙˙A˙¨q‡g˙˙—˙ž˙˙ř˙‡}–wŤ—x”W\–-­˙‡ţFý%ýţoţţTţTýČüýLţ ĆŞÁO{ŘŘ|˙–ţZ‚F˙8˙éäqĺP•˙­ýü¸ý×ţüţ˙Îţu˙ÉâA˝˙Ą˙˙ŚýSýr˙óË5asvP~A˙lýŠýAţžţš˙ß´„˘˙-˙đ˙JĎ˙Rţţ*˙’y´‚ţŤ˙Ĺ˙–ţ9˙U)Îţeýýůü¸ýÎţO˙Đ˙ę˙b˙ş˙ ¸tg÷ŕ1ĺá˙GöéÔ˙˙P˙]˙ŽţŚţU˙‹˙U˙˙‚ţŒý÷üRüÓűrüPýpţë˙9Ž—Q OjŢĹĄ %˙ý˙ľ?˙˙˜˙Ěţ˙üű7űý ţ?˙`5˙­ý„ýÔţ“ţÎý'˙d}-išôF™Äٲ˙ŚţAţSţľţČţf˙Ç˙Q˙Iţý{ý˛ţ^˙.˙R˙XÂť˙´˙‚ľ6˙Ű˙ĂT˙˙œ"˙‚ţFţH˙\ '2x˙˙˙ ŕ%˙­ţĘ˙ź˙ß˙d~żY$Ď˙ţáüDţž˙‰˙;˙[˙ě˙„ž˙E˙y˙…ţâýńýňýźţ™˙Ż˙p:°#ĺěţk˙ýŢqS˙ťýţüěüürűý,ţ ˙ýUi#3‚˙‚˙§Â„˙ßţˆč憴"Ң˙hÉ~˙Ůţœ˙Yć˙vţűýäý<ýŠý˝ýŔý$˙Ŕ˙Ż˙'$=ÉĘ[w13×˙’ţj˙šă˙Kţ9ý|üżüţŃ˙$Ąś˛ŹţZţŃţlţsţÝţá˙ě˙süügÍŽ őţĄ˙SÄ˙ ˙Ž˙c˙ţWţ’ţ“ý0üřű)ü@ý(˙€Ňţ”Îy˙ÝTÔ˙Á˙SSžgŮ.A˙˙2˙Wţ&ýýÍýWţ.˙É˙5÷cVţOýsţÓ˙Á˙ˇ˙Ă87B˙ě˙ma'…˘š˙ţ˙ósŠ˙;˙0˙~˙›˙h˙m˙˜˙¨˙ ˙#˙Ü(†˙‘˙jăÚĺQ›˙Z˙ÁţˆüüŚü÷ü!ţą˙čO“…uÎ˙ô˙_y–arű˙_ëł$ý§˙ ý;ýD˙űóĘ Ě˙ńýĘüaü~ü€üvüşüMý”ţŐ¤€­UŒP‚ŁömÜč ţůüQýŠý,ý‹ý7˙ě˙˙Œţaţmţ˙˙üýšţ+ü˙ŮHč6›qśZőz-]˙Šţ!˙˙T˙ŁţČý:ý_ý0ţćţÄ˙(ŠÔ˙ţ˝ţ˙ţĹţ3Ĺá[ƒŁ˛pĹţţ4ţ¤ţ§ţ÷ţY5ş˙˙Ęţ%ţVţ‹ţ˙~üü¨wčU˙ôţ˙8ţý,˙§}Ś9 TuţţŔţXţţ×ýýŇýr˙=ř tí§˙ň˙ŕë!Ú|’ľ˙˙ž˙G˙bţýÎýVţ›ýšý›˙1Ú˙"ľ˙Ž˙<"•˙˙˙R˙œ˙›_Ż˙Š˙ej ŸFđš˙2ţ0ţtýÖü{ýÜýâý‰ţäţČ˙§$B¨˙ŠŠCăV.Ľ˙_˙:˙‚ý&ü€ü´ýĘţá˙˝ŠĽ˙~ţ2ý„ý“ţ ˙v˙-ęr\Rꉚńţ˛ţô˙ľGű˙XŃ˙Şý$üžüýIý&ţˆţF˙ě˙˙<˙ë˙:ǘs~a€ĄQ§r¤w˙#˙ąţéýRý˛ý¸ţ˙÷ţ`ţ˘ýwţË˙˝˙Ą˙ń0ĂÍţŠ˙ƒ˙KţI˙-=\:A&žĂ˙’˙ţţČţ9˙ˆ˙V˙ťţ˜ţţţÂ˙śŰĽ˙Yţfţ¤ţ@ţţ˙=ćY‘lţ.ý;ţjţýŮüœýŚţ!xMNƒ˙U˙ĺ˙•ä˙ł˙Ëéúăă˙ČţÉ˙2J˙f˙Vä"˝ţeţţaý˘üřüĐý˜ýýýO˙–˙â˙곀ˆÔĹ‘űƒa˝ĽÁíx˙˘ţL˙I˙ˇţíţČ˙1˙nýTý]ýÇü(ýĎýţ }Ă˙'ČŐTž b]˛Š]Ż]Ľ%˙OţýÖüSýkţ4˙¤˙H_q˙d˙y˙ţIýIţ%˙˙ţ‚˙<˜űĐţ€P˙Ů˙I*˙‘ý-ýţ§ţi˙3ŹnëţĘý€ýHţŕ?1ŢK˙÷˙ˆČ^˙$óĐ˙ź˙o‹ƒ˙Ď˙Ţ˙Źţlţţ´ý‚ýţţ™ţź˙ˇ˙Ťţ—˙ÉiULŸô@kŚţ{ţ‰˙ů˙m˙Ôţď˙ŘţĘţ‰ţpţđţI˙ľ˙pé˙Í˙úXă˙ ˙Ç˙Ĺ˙šţćţĺüƒě™Ňă˙‘ýłü‘ýŽýĄýĹţ8˙ô˙ĺŻyĚş6ž˙Ş˙—2 ˙âYĚë2Řť˙€ýĽýéţ)˙‡ţţz˙˙ţ˙Ä˙$˙ ˙–ţ?ţŁţ˙0ö0ädqĆ*ő@ŕBóţL˙ÓŐ˙7ţ°ý+ţÎýÖý˙•˙J˙†ţ]ýűüRý÷ý\ţ'˙Łçˇ*ąB¨ö"HĘÇ˙Đţđţ†˙_˙iţÄý<ý’üÁüŚýĚţ[÷ƒŮ˙<™ţýŢţXŽ˙B˙Eˆ<p%œÝĄ˙¸ţ˙ţ_˙Ŕţˆţ˙8˙G˙v˙­˙ ˙S˙ŻţňýţŽ˙™fف€ľ8=ń˙}ţ˙ýF˙u˙öţO˙“˙š˙—˙Ś˙ÚWـŔ˙ťţëţ<ŠĂçĘĄ˙mţyŰîűF—e`ţ˙K˙=ţĺýőýĽţčţţŘţ]ů˙R˙A˙˛ţ¨ţą˙4žzœóĹ‚gVĺ˙˙Š˙ý¨ę˙&˙žţľýćüGý’ýśý]ţďţę˙ĚY2íN~T˙ŕ˙f$Ł˙¨˙ ďÇ#'óţĽý˝ýłţ/˙Ÿ˙™S˙šţ^ţţłţW˙ ˙üţŒ˙nü#•€˛ŠzŒ˙}˙}˙ ˙|ţnţ˙ţ˙|ţâţ‘˙˙°˙ę˙ú˙`×K‡˙Ţ˙‚˙ŕţţ˙áXĄ ĹUâ˙g Ć˙ˆ˙Ó˙­˙•ţ‡ţU˙2˙Ăţ˘ţňý;ýĂý˝ţ'˙Ťůf(+˙O˙s€ç˙Ž˙§ŸK^ ˙uţžţÄţÓţŸţ“ţI˙_EţACş˙;ţţ?œÉż˛2“aœÂ˙uţ,ţĂţ0˙ŕ˙ęÖMâ˙M˙b˙đ˙†œ˙P˙ *Ř˙#şĄé˙ Ž˙ü˙ĐvČţ—ý˜ý‘ýnýlţĘ˙ƒÝßHӆpU9›ĽxѲM´˙ĺţ˙Ďţoţ™ţT˙EOĹ˙P˙ŻţÔý(ýýQýĐýňţu˙î˙˜1ŇwnÖڞ˙!ĐWĐ˙…˙N˙`ţ/ý;ýŇýeţ ˙Ť˙A+J1âţŕţĺ˙#˙WţÁ˙29œNM‘Š!v&˙xţđţ˙x˙*ŕ˙ ˙<ţŇýPţG˙7N~.‘.˙b˙šĐ%üéÉ˙ Vćâ˙ ˙hţşţýţ)˙Ţ˙Ü˙Â˙ď˙ƒ>E˙Ś˙7™˙ż˙Ę˙ńŽÚţ™ýŚţF˙ęţîţ ˙?0;ě˙%˙Tţzţ€ţËţp˙†˙˙Ă"ß"jy$˙ö˙ýˇćî:˙•ţiţÂţhţ=ţŽţÄţL˙2nîôR.ÁŠ“˙\˙ŒÁú˙F%*wkŸ˙š˙Ő˙˙M˙˙nţˆţ”ţÜţ˙xÝńuăË ÎRű¨˙3ź˙ôţţăý%ţUţu˙Óűňy”˙@˙0˙2˙;˙˝˙sJŔ˙ŘŠ4gvot˙Ł˙NJ˙˙“˙Ń˙†˙š˙çţéýźý ţ‚ţZ˙;‘Ä}|Dԕ˙ń˙ç?T:0y˙q˙ź˙’˙!˙Řţ¨ţŰţ+˙\˙Î˙0=§˙˙Ş˙[ú˙Ď˙(‰ů˙[˙ĺ˙ +ýnÝ˙;2ó˙ř˙đ˙ ˙…˙t˙‰˙™˙Ö˙6$<‘-H˙k˙}€3!ÚkiĚ˙ą˙˙ ţ˝ýîýPţŚţ#˙nvWـ!Ö˙*Ca"ÎÂ˙‡żҸŢý˙˛ţƒţˆ˙č˙ć˙w˙ąţtţ˜ţMţúýDţŸţ˙[â§Ľf]çÔŘő˙…ĹZš˝Ń˙ˇţTţśţ˙#˙b˙ˇ˙š˙˙ąţżţăţq˙ę˙†˙Ë˙‡BÁ!Eń î@QŁç˙Š˙d˙Ť˙š˙5˙˙žţ–ţÓţG˙í˙ŁF˛˙Č˙B˙­ţ$˙_önšâqă˙+˙äţĹţ˙ ˙Ęţż˙ž¤t6ą˙˙ďţL˙’˙ŸkđŞ"RZ|˙ű˙bu˙Ęţm˙?e7^x˘˙V˙˛˙q˙˙ŠţxţÄţ|˙ţ˙Ş˘óĹ˙|sŢ7ÂIźţ˙Ö˙Ď˙}˙<˙˙:˙ˆ˙|˙ž˙Ţ˙ż˙˛˙}˙ť˙3k#:CÓ˙Ü˙¨śŰ˙˙Đ˙ˆ-šő˙W˙4˙ ˙ćţP˙s˙K˙c˙r˙ô˙–ş›eL9ě˙Ř˙i6ß}  ˙éţ¤ţŠţ ˙‡˙ą˙'Š<Ú˙{˙B˙^˙p˙ł˙â˙*&‰Ëpď7‹ë‰ˇ˙p˙â˙ň˙´˙š˙â˙ř˙y˙ďţ˙7˙1˙E˙x˙ž˙ź˙§˙˙‚˙+ş6;yĆK0ŻDPUď˙ˇ˙œ˙†˙‚˙x˙—˙˙s˙a˙˙ěţP˙×˙7NŁýOƒ˙ě˙,r˙<˙É˙2;[ ‰e¨˙”˙ž˙Č˙Ň˙h˙R˙˙ě˙9a%Ű˙Š˙X˙:˙ń˙ó ÉňîR~˙O˙“˙D˙ćţčţöţp˙ô˙‹Ůoű˙î˙ň˙—Ę=LîľĹ˙Ť˙Hv ŕ˙f`–˙A˙,˙3˙b˙2˙3˙z˙X˙Q˙˛˙Ţ˙â˙!ŕ˙~A˙™ďŒ%˘ý‰í˙Ż˙˛˙€˙g˙ž˙ć˙+í˙|˙D˙ßţ§ţČţôţT˙é˙?]Đ%ż'0œ^×˙"¤`"¨ĚKŮ˙W˙ůţîţ˙¤˙đ˙ĺ˙ů˙â˙˛˙Á˙Ć˙˙ˆ˙×˙Ž˙m˙ş˙Ž_ăi'ě˙9…˙˙äţ*˙s˙‚˙÷˙x.“˙R˙i˙¨˙ú˙E‚ŐĘ–˙ň˙w´˙PŹG%h†9É˙•˙Á˙á˙Â˙Ž˙g˙B˙;˙S˙‹˙ˇ˙Ť˙W˙˙bŐÁO, p›˙Á˙ă˙ç˙Ç˙Á˙/ý˙ô˙ľ˙˙ą˙ľ˙Ř˙ů˙ !,QVŐ˙ő˙ď˙Ź˙Ŕ˙1d[z„Mů˙ ˙}˙ƒ˙†˙›˙Î˙÷˙27ă˙ť˙ wV>~ý˙›˙Ŕ˙ä˙Ä˙ą˙Ŕ˙Ë˙ľ˙”˙ž˙É˙ć˙Ű˙Á˙Ę˙â˙ö˙4^hšv %‡q)1T7ň˙č˙ ž˙†˙|˙˘˙Â˙Ń˙ô˙ó˙Ź˙w˙y˙t˙Œ˙Ť˙˝˙ xV€űŢf=\b2;!Î˙ł˙Ę˙ă˙ď˙â˙Í˙Ž˙N˙\˙{˙Ź˙ţ˙Gg=! Ě˙˙Ř˙ŕ˙Ă˙ t~lŚŠIý˙â˙Ň˙Ó˙Ç˙ž˙č˙ô˙Ţ˙Ö˙Ü˙ć˙Ö˙Ă˙Ă˙č˙$÷˙A|Cü˙9 Ä˙É˙Ú˙Ă˙â˙Ô˙Ř˙ß˙É˙ď˙0/ţ˙â˙é˙*ecę˙ş˙D-†.É˙Î˙Á˙„˙v˙‡˙­˙Ř˙×˙ü˙/â˙Ă˙Ž˙ł˙Ú˙ň˙ű˙+e]I“Âo í˙Ú˙;ć˙Â˙ś˙•˙…˙’˙o˙h˙Š˙Ÿ˙ď˙Yqcha+ó˙P3Í˙ă˙DH*fˆ/Ă˙•˙—˙­˙Í˙ó˙+ Ď˙Ľ˙‡˙ˆ˙š˙Ô˙Ú˙ř˙%5"2—E(z‰*ú˙í˙¸˙ ˙ ˙°˙´˙’˙Š˙Â˙ń˙ű˙9(ô˙é˙ń˙Â˙]3"‹šlţ˙č˙Ĺ˙Ć˙Ý˙Ű˙Ň˙â˙ô˙ç˙Đ˙¨˙v˙b˙x˙¤˙Ě˙|łx_ŽIŃ˙Ő˙ő˙ ?P$ţ˙÷˙Ö˙Ň˙ö˙ö˙ů˙÷˙ú˙˙˙ú˙ů˙˙˙˙˙ţ˙ú˙ú˙ú˙ű˙˙˙ű˙ü˙˙˙˙˙ţ˙speech-dispatcher-0.9.1/src/api/python/speechd_config/__init__.py0000644000175000017500000000131113406252213021761 00000000000000# Copyright (C) 2008 Brailcom, o.p.s. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from speechd_config.config import * speech-dispatcher-0.9.1/src/api/python/speechd_config/spd-conf0000755000175000017500000000175613406252216021327 00000000000000#!/usr/bin/env python3 # Helper script to be put in /usr/bin/ or a similar location # calling the appropriate python tool # Copyright (C) 2008-2011 Brailcom, o.p.s # Copyright (C) 2012 Christopher Brannon # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more details (file # COPYING in the root directory). # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import speechd_config if __name__=='__main__': import sys sys.exit(speechd_config.main()) speech-dispatcher-0.9.1/src/api/python/speechd_config/Makefile.am0000644000175000017500000000433613406252204021716 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in dist_snddata_DATA = test.wav DESKTOP_FILES = speechd.desktop.in desktop_DATA = $(DESKTOP_FILES:.desktop.in=.desktop) desktopdir = $(spddesktopconforigdir) CLEANFILES = $(desktop_DATA) speechd.desktop: speechd.desktop.in $(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@ dist_bin_SCRIPTS = spd-conf speechd_pythondir = $(pyexecdir)/speechd_config speechd_python_PYTHON = __init__.py nodist_speechd_python_PYTHON = config.py paths.py paths_edit = sed \ -e "s:[@]spdconforigdir[@]:$(spdconforigdir):" \ -e "s:[@]spdconfdir[@]:$(spdconfdir):" \ -e "s:[@]snddatadir[@]:$(snddatadir):" \ -e "s:[@]spddesktopconforigdir[@]:$(spddesktopconforigdir):" config_edit = sed \ -e "s:[@]GETTEXT_PACKAGE[@]:$(GETTEXT_PACKAGE):" \ -e "s:[@]VERSION[@]:$(VERSION):" \ -e "s:[@]localedir[@]:$(localedir):" paths.py: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(paths_edit) $${srcdir}$@.in > $@ config.py: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(config_edit) $${srcdir}$@.in > $@ $(abs_builddir)/__init__.py: ln -s $(srcdir)/__init__.py . paths.py: $(srcdir)/paths.py.in CLEANFILES += paths.py config.py speechd.desktop EXTRA_DIST = paths.py.in speechd.desktop.in config.py.in if HAVE_HELP2MAN spd-conf.1: config.py paths.py $(abs_builddir)/__init__.py LC_ALL=C PYTHONPATH=$(builddir)/.. PYTHONDONTWRITEBYTECODE=1 help2man -N --output=$@ $(srcdir)/spd-conf dist_man1_MANS = \ spd-conf.1 endif CLEANFILES += $(dist_man1_MANS) -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/api/python/speechd/0000755000175000017500000000000013465234514016420 500000000000000speech-dispatcher-0.9.1/src/api/python/speechd/paths.py.in0000644000175000017500000000005511447133617020436 00000000000000SPD_SPAWN_CMD = "@bindir@/speech-dispatcher" speech-dispatcher-0.9.1/src/api/python/speechd/Makefile.in0000644000175000017500000005144113465233610020406 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/api/python/speechd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(speechd_python_PYTHON) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile) am__installdirs = "$(DESTDIR)$(speechd_pythondir)" \ "$(DESTDIR)$(speechd_pythondir)" am__pep3147_tweak = \ sed -e 's|\.py$$||' -e 's|[^/]*$$|&.*.pyc\n&.*.pyo|' py_compile = $(top_srcdir)/py-compile am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/py-compile DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ speechd_pythondir = $(pyexecdir)/speechd speechd_python_PYTHON = __init__.py _test.py client.py nodist_speechd_python_PYTHON = paths.py edit = sed \ -e 's:@bindir[@]:$(bindir):g' CLEANFILES = paths.py EXTRA_DIST = paths.py.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/api/python/speechd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/api/python/speechd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nodist_speechd_pythonPYTHON: $(nodist_speechd_python_PYTHON) @$(NORMAL_INSTALL) @list='$(nodist_speechd_python_PYTHON)'; dlist=; list2=; test -n "$(speechd_pythondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(speechd_pythondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(speechd_pythondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ if test -f $$b$$p; then \ $(am__strip_dir) \ dlist="$$dlist $$f"; \ list2="$$list2 $$b$$p"; \ else :; fi; \ done; \ for file in $$list2; do echo $$file; done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(speechd_pythondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(speechd_pythondir)" || exit $$?; \ done || exit $$?; \ if test -n "$$dlist"; then \ $(am__py_compile) --destdir "$(DESTDIR)" \ --basedir "$(speechd_pythondir)" $$dlist; \ else :; fi uninstall-nodist_speechd_pythonPYTHON: @$(NORMAL_UNINSTALL) @list='$(nodist_speechd_python_PYTHON)'; test -n "$(speechd_pythondir)" || list=; \ py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$py_files" || exit 0; \ dir='$(DESTDIR)$(speechd_pythondir)'; \ pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ st=0; \ for files in "$$py_files" "$$pyc_files" "$$pyo_files"; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done; \ dir='$(DESTDIR)$(speechd_pythondir)/__pycache__'; \ echo "$$py_files" | $(am__pep3147_tweak) | $(am__base_list) | \ while read files; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done || exit $$?; \ exit $$st install-speechd_pythonPYTHON: $(speechd_python_PYTHON) @$(NORMAL_INSTALL) @list='$(speechd_python_PYTHON)'; dlist=; list2=; test -n "$(speechd_pythondir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(speechd_pythondir)'"; \ $(MKDIR_P) "$(DESTDIR)$(speechd_pythondir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ if test -f $$b$$p; then \ $(am__strip_dir) \ dlist="$$dlist $$f"; \ list2="$$list2 $$b$$p"; \ else :; fi; \ done; \ for file in $$list2; do echo $$file; done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(speechd_pythondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(speechd_pythondir)" || exit $$?; \ done || exit $$?; \ if test -n "$$dlist"; then \ $(am__py_compile) --destdir "$(DESTDIR)" \ --basedir "$(speechd_pythondir)" $$dlist; \ else :; fi uninstall-speechd_pythonPYTHON: @$(NORMAL_UNINSTALL) @list='$(speechd_python_PYTHON)'; test -n "$(speechd_pythondir)" || list=; \ py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$py_files" || exit 0; \ dir='$(DESTDIR)$(speechd_pythondir)'; \ pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ st=0; \ for files in "$$py_files" "$$pyc_files" "$$pyo_files"; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done; \ dir='$(DESTDIR)$(speechd_pythondir)/__pycache__'; \ echo "$$py_files" | $(am__pep3147_tweak) | $(am__base_list) | \ while read files; do \ $(am__uninstall_files_from_dir) || st=$$?; \ done || exit $$?; \ exit $$st tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: for dir in "$(DESTDIR)$(speechd_pythondir)" "$(DESTDIR)$(speechd_pythondir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nodist_speechd_pythonPYTHON \ install-speechd_pythonPYTHON install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nodist_speechd_pythonPYTHON \ uninstall-speechd_pythonPYTHON .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-nodist_speechd_pythonPYTHON install-pdf install-pdf-am \ install-ps install-ps-am install-speechd_pythonPYTHON \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am \ uninstall-nodist_speechd_pythonPYTHON \ uninstall-speechd_pythonPYTHON .PRECIOUS: Makefile paths.py: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(edit) $${srcdir}$@.in > $@ paths.py: $(srcdir)/paths.py.in -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/api/python/speechd/client.py0000644000175000017500000013300213406252200020152 00000000000000# Copyright (C) 2003-2008 Brailcom, o.p.s. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . """Python API to Speech Dispatcher Basic Python client API to Speech Dispatcher is provided by the 'SSIPClient' class. This interface maps directly to available SSIP commands and logic. A more convenient interface is provided by the 'Speaker' class. """ #TODO: Blocking variants for speak, char, key, sound_icon. import socket, sys, os, subprocess, time, tempfile try: import threading except: import dummy_threading as threading from . import paths class CallbackType(object): """Constants describing the available types of callbacks""" INDEX_MARK = 'index_marks' """Index mark events are reported when the place they were included into the text by the client application is reached when speaking them""" BEGIN = 'begin' """The begin event is reported when Speech Dispatcher starts actually speaking the message.""" END = 'end' """The end event is reported after the message has terminated and there is no longer any sound from it being produced""" CANCEL = 'cancel' """The cancel event is reported when a message is canceled either on request of the user, because of prioritization of messages or due to an error""" PAUSE = 'pause' """The pause event is reported after speaking of a message was paused. It no longer produces any audio.""" RESUME = 'resume' """The resume event is reported right after speaking of a message was resumed after previous pause.""" class SSIPError(Exception): """Common base class for exceptions during SSIP communication.""" class SSIPCommunicationError(SSIPError): """Exception raised when trying to operate on a closed connection.""" _additional_exception = None def __init__(self, description=None, original_exception=None, **kwargs): self._original_exception = original_exception self._description = description super(SSIPError, self).__init__(**kwargs) def original_exception(self): """Return the original exception if any If this exception is secondary, being caused by a lower level exception, return this original exception, otherwise None""" return self._original_exception def set_additional_exception(self, exception): """Set an additional exception See method additional_exception(). """ self._additional_exception = exception def additional_exception(self): """Return an additional exception Additional exceptions araise from failed attempts to resolve the former problem""" return self._additional_exception def description(self): """Return error description""" return self._description def __str__(self): msgs = [] if self.description(): msgs.append(self.description()) if self.original_exception: msgs.append("Original error: " + str(self.original_exception())) if self.additional_exception: msgs.append("Additional error: " + str(self.additional_exception())) return "\n".join(msgs) class SSIPResponseError(Exception): def __init__(self, code, msg, data): Exception.__init__(self, "%s: %s" % (code, msg)) self._code = code self._msg = msg self._data = data def code(self): """Return the server response error code as integer number.""" return self._code def msg(self): """Return server response error message as string.""" return self._msg class SSIPCommandError(SSIPResponseError): """Exception raised on error response after sending command.""" def command(self): """Return the command string which resulted in this error.""" return self._data class SSIPDataError(SSIPResponseError): """Exception raised on error response after sending data.""" def data(self): """Return the data which resulted in this error.""" return self._data class SpawnError(Exception): """Indicates failure in server autospawn.""" class CommunicationMethod(object): """Constants describing the possible methods of connection to server.""" UNIX_SOCKET = 'unix_socket' """Unix socket communication using a filesystem path""" INET_SOCKET = 'inet_socket' """Inet socket communication using a host and port""" class _SSIP_Connection(object): """Implemantation of low level SSIP communication.""" _NEWLINE = b"\r\n" _END_OF_DATA_MARKER = b'.' _END_OF_DATA_MARKER_ESCAPED = b'..' _END_OF_DATA = _NEWLINE + _END_OF_DATA_MARKER + _NEWLINE _END_OF_DATA_ESCAPED = _NEWLINE + _END_OF_DATA_MARKER_ESCAPED + _NEWLINE # Constants representing \r\n. and \r\n.. _RAW_DOTLINE = _NEWLINE + _END_OF_DATA_MARKER _ESCAPED_DOTLINE = _NEWLINE + _END_OF_DATA_MARKER_ESCAPED _CALLBACK_TYPE_MAP = {700: CallbackType.INDEX_MARK, 701: CallbackType.BEGIN, 702: CallbackType.END, 703: CallbackType.CANCEL, 704: CallbackType.PAUSE, 705: CallbackType.RESUME, } def __init__(self, communication_method, socket_path, host, port): """Init connection: open the socket to server, initialize buffers, launch a communication handling thread. """ if communication_method == CommunicationMethod.UNIX_SOCKET: socket_family = socket.AF_UNIX socket_connect_args = socket_path elif communication_method == CommunicationMethod.INET_SOCKET: assert host and port socket_family = socket.AF_INET socket_connect_args = (socket.gethostbyname(host), port) else: raise ValueError("Unsupported communication method") try: self._socket = socket.socket(socket_family, socket.SOCK_STREAM) self._socket.connect(socket_connect_args) except socket.error as ex: raise SSIPCommunicationError("Can't open socket using method " + communication_method, original_exception = ex) self._buffer = b"" self._com_buffer = [] self._callback = None self._ssip_reply_semaphore = threading.Semaphore(0) self._communication_thread = \ threading.Thread(target=self._communication, kwargs={}, name="SSIP client communication thread") self._communication_thread.start() def close(self): """Close the server connection, destroy the communication thread.""" # Read-write shutdown here is necessary, otherwise the socket.recv() # function in the other thread won't return at last on some platforms. try: self._socket.shutdown(socket.SHUT_RDWR) except socket.error: pass self._socket.close() # Wait for the other thread to terminate self._communication_thread.join() def _communication(self): """Handle incomming socket communication. Listens for all incomming communication on the socket, dispatches events and puts all other replies into self._com_buffer list in the already parsed form as (code, msg, data). Each time a new item is appended to the _com_buffer list, the corresponding semaphore 'self._ssip_reply_semaphore' is incremented. This method is designed to run in a separate thread. The thread can be interrupted by closing the socket on which it is listening for reading.""" while True: try: code, msg, data = self._recv_message() except IOError: # If the socket has been closed, exit the thread sys.exit() if code//100 != 7: # This is not an index mark nor an event self._com_buffer.append((code, msg, data)) self._ssip_reply_semaphore.release() continue # Ignore the event if no callback function has been registered. if self._callback is not None: type = self._CALLBACK_TYPE_MAP[code] if type == CallbackType.INDEX_MARK: kwargs = {'index_mark': data[2]} else: kwargs = {} # Get message and client ID of the event msg_id, client_id = map(int, data[:2]) self._callback(msg_id, client_id, type, **kwargs) def _readline(self): """Read one whole line from the socket. Blocks until the line delimiter ('_NEWLINE') is read. """ pointer = self._buffer.find(self._NEWLINE) while pointer == -1: try: d = self._socket.recv(1024) except: raise IOError if len(d) == 0: raise IOError self._buffer += d pointer = self._buffer.find(self._NEWLINE) line = self._buffer[:pointer] self._buffer = self._buffer[pointer+len(self._NEWLINE):] return line.decode('utf-8') def _recv_message(self): """Read server response or a callback and return the triplet (code, msg, data).""" data = [] c = None while True: line = self._readline() assert len(line) >= 4, "Malformed data received from server!" code, sep, text = line[:3], line[3], line[4:] assert code.isalnum() and (c is None or code == c) and \ sep in ('-', ' '), "Malformed data received from server!" if sep == ' ': msg = text return int(code), msg, tuple(data) data.append(text) def _recv_response(self): """Read server response from the communication thread and return the triplet (code, msg, data).""" # TODO: This check is dumb but seems to work. The main thread # hangs without it, when the Speech Dispatcher connection is lost. if not self._communication_thread.isAlive(): raise SSIPCommunicationError self._ssip_reply_semaphore.acquire() # The list is sorted, read the first item response = self._com_buffer[0] del self._com_buffer[0] return response def send_command(self, command, *args): """Send SSIP command with given arguments and read server response. Arguments can be of any data type -- they are all stringified before being sent to the server. Returns a triplet (code, msg, data), where 'code' is a numeric SSIP response code as an integer, 'msg' is an SSIP rsponse message as string and 'data' is a tuple of strings (all lines of response data) when a response contains some data. 'SSIPCommandError' is raised in case of non 2xx return code. See SSIP documentation for more information about server responses and codes. 'IOError' is raised when the socket was closed by the remote side. """ if __debug__: if command in ('SET', 'CANCEL', 'STOP',): assert args[0] in (Scope.SELF, Scope.ALL) \ or isinstance(args[0], int) cmd = ' '.join((command,) + tuple(map(str, args))) try: self._socket.send(cmd.encode('utf-8') + self._NEWLINE) except socket.error: raise SSIPCommunicationError("Speech Dispatcher connection lost.") code, msg, data = self._recv_response() if code//100 != 2: raise SSIPCommandError(code, msg, cmd) return code, msg, data def send_data(self, data): """Send multiline data and read server response. Returned value is the same as for 'send_command()' method. 'SSIPDataError' is raised in case of non 2xx return code. See SSIP documentation for more information about server responses and codes. 'IOError' is raised when the socket was closed by the remote side. """ data = data.encode('utf-8') # Escape the end-of-data marker even if present at the beginning # The start of the string is also the start of a line. if data.startswith(self._END_OF_DATA_MARKER): l = len(self._END_OF_DATA_MARKER) data = self._END_OF_DATA_MARKER_ESCAPED + data[l:] # Escape the end of data marker at the start of each subsequent # line. We can do that by simply replacing \r\n. with \r\n.., # since the start of a line is immediately preceded by \r\n, # when the line is not the beginning of the string. data = data.replace(self._RAW_DOTLINE, self._ESCAPED_DOTLINE) try: self._socket.send(data + self._END_OF_DATA) except socket.error: raise SSIPCommunicationError("Speech Dispatcher connection lost.") code, msg, response_data = self._recv_response() if code//100 != 2: raise SSIPDataError(code, msg, data) return code, msg, response_data def set_callback(self, callback): """Register a callback function for handling asynchronous events. Arguments: callback -- a callable object (function) which will be called to handle asynchronous events (arguments described below). Passing `None' results in removing the callback function and ignoring events. Just one callback may be registered. Attempts to register a second callback will result in the former callback being replaced. The callback function must accept three positional arguments ('message_id', 'client_id', 'event_type') and an optional keyword argument 'index_mark' (when INDEX_MARK events are turned on). Note, that setting the callback function doesn't turn the events on. The user is responsible to turn them on by sending the appropriate `SET NOTIFICATION' command. """ self._callback = callback class _CallbackHandler(object): """Internal object which handles callbacks.""" def __init__(self, client_id): self._client_id = client_id self._callbacks = {} self._lock = threading.Lock() def __call__(self, msg_id, client_id, type, **kwargs): if client_id != self._client_id: # TODO: does that ever happen? return self._lock.acquire() try: try: callback, event_types = self._callbacks[msg_id] except KeyError: pass else: if event_types is None or type in event_types: callback(type, **kwargs) if type in (CallbackType.END, CallbackType.CANCEL): del self._callbacks[msg_id] finally: self._lock.release() def add_callback(self, msg_id, callback, event_types): self._lock.acquire() try: self._callbacks[msg_id] = (callback, event_types) finally: self._lock.release() class Scope(object): """An enumeration of valid SSIP command scopes. The constants of this class should be used to specify the 'scope' argument for the 'Client' methods. """ SELF = 'self' """The command (mostly a setting) applies to current connection only.""" ALL = 'all' """The command applies to all current Speech Dispatcher connections.""" class Priority(object): """An enumeration of valid SSIP message priorities. The constants of this class should be used to specify the 'priority' argument for the 'Client' methods. For more information about message priorities and their interaction, see the SSIP documentation. """ IMPORTANT = 'important' TEXT = 'text' MESSAGE = 'message' NOTIFICATION = 'notification' PROGRESS = 'progress' class PunctuationMode(object): """Constants for selecting a punctuation mode. The mode determines which characters should be read. """ ALL = 'all' """Read all punctuation characters.""" NONE = 'none' """Don't read any punctuation character at all.""" SOME = 'some' """Only the user-defined punctuation characters are read. The set of characters is specified in Speech Dispatcher configuration. """ class DataMode(object): """Constants specifying the type of data contained within messages to be spoken. """ TEXT = 'text' """Data is plain text.""" SSML = 'ssml' """Data is SSML (Speech Synthesis Markup Language).""" class SSIPClient(object): """Basic Speech Dispatcher client interface. This class provides a Python interface to Speech Dispatcher functionality over an SSIP connection. The API maps directly to available SSIP commands. Each connection to Speech Dispatcher is represented by one instance of this class. Many commands take the 'scope' argument, thus it is shortly documented here. It is either one of 'Scope' constants or a number of connection. By specifying the connection number, you are applying the command to a particular connection. This feature is only meant to be used by Speech Dispatcher control application, however. More datails can be found in Speech Dispatcher documentation. """ DEFAULT_HOST = '127.0.0.1' """Default host for server connections.""" DEFAULT_PORT = 6560 """Default port number for server connections.""" DEFAULT_SOCKET_PATH = "speech-dispatcher/speechd.sock" """Default name of the communication unix socket""" def __init__(self, name, component='default', user='unknown', address=None, autospawn=None, # Deprecated -> host=None, port=None, method=None, socket_path=None): """Initialize the instance and connect to the server. Arguments: name -- client identification string component -- connection identification string. When one client opens multiple connections, this can be used to identify each of them. user -- user identification string (user name). When multi-user acces is expected, this can be used to identify their connections. address -- server address as specified in Speech Dispatcher documentation (e.g. "unix:/run/user/joe/speech-dispatcher/speechd.sock" or "inet:192.168.0.85:6561") autospawn -- a flag to specify whether the library should try to start the server if it determines its not already running or not Deprecated arguments: method -- communication method to use, one of the constants defined in class CommunicationMethod socket_path -- for CommunicationMethod.UNIX_SOCKET, socket path in filesystem. By default, this is $XDG_RUNTIME_DIR/speech-dispatcher/speechd.sock where $XDG_RUNTIME_DIR is determined using the XDG Base Directory Specification. host -- for CommunicationMethod.INET_SOCKET, server hostname or IP address as a string. If None, the default value is taken from SPEECHD_HOST environment variable (if it exists) or from the DEFAULT_HOST attribute of this class. port -- for CommunicationMethod.INET_SOCKET method, server port as number or None. If None, the default value is taken from SPEECHD_PORT environment variable (if it exists) or from the DEFAULT_PORT attribute of this class. For more information on client identification strings see Speech Dispatcher documentation. """ _home = os.path.expanduser("~") _runtime_dir = os.environ.get('XDG_RUNTIME_DIR', os.environ.get('XDG_CACHE_HOME', os.path.join(_home, '.cache'))) _sock_path = os.path.join(_runtime_dir, self.DEFAULT_SOCKET_PATH) # Resolve connection parameters: connection_args = {'communication_method': CommunicationMethod.UNIX_SOCKET, 'socket_path': _sock_path, 'host': self.DEFAULT_HOST, 'port': self.DEFAULT_PORT, } # Respect address method argument and SPEECHD_ADDRESS environemt variable _address = address or os.environ.get("SPEECHD_ADDRESS") if _address: connection_args.update(self._connection_arguments_from_address(_address)) # Respect the old (deprecated) key arguments and environment variables # TODO: Remove this section in 0.8 release else: # Read the environment variables env_speechd_host = os.environ.get("SPEECHD_HOST") try: env_speechd_port = int(os.environ.get("SPEECHD_PORT")) except: env_speechd_port = None env_speechd_socket_path = os.environ.get("SPEECHD_SOCKET") # Prefer old (deprecated) function arguments, but if # not specified and old (deprecated) environment variable # is set, use the value of the environment variable if method: connection_args['method'] = method if port: connection_args['port'] = port elif env_speechd_port: connection_args['port'] = env_speechd_port if socket_path: connection_args['socket_path'] = socket_path elif env_speechd_socket_path: connection_args['socket_path'] = env_speechd_socket_path self._connect_with_autospawn(connection_args, autospawn) self._initialize_connection(user, name, component) def _connect_with_autospawn(self, connection_args, autospawn): """Establish new connection (and/or autospawn server)""" try: self._conn = _SSIP_Connection(**connection_args) except SSIPCommunicationError as ce: # Suppose server might not be running, try the autospawn mechanism if autospawn != False: # Autospawn is however not guaranteed to start the server. The server # will decide, based on it's configuration, whether to honor the request. try: self._server_spawn(connection_args) except SpawnError as se: ce.set_additional_exception(se) raise ce self._conn = _SSIP_Connection(**connection_args) else: raise def _initialize_connection(self, user, name, component): """Initialize connection -- Set client name, get id, register callbacks etc.""" full_name = '%s:%s:%s' % (user, name, component) self._conn.send_command('SET', Scope.SELF, 'CLIENT_NAME', full_name) code, msg, data = self._conn.send_command('HISTORY', 'GET', 'CLIENT_ID') self._client_id = int(data[0]) self._callback_handler = _CallbackHandler(self._client_id) self._conn.set_callback(self._callback_handler) for event in (CallbackType.INDEX_MARK, CallbackType.BEGIN, CallbackType.END, CallbackType.CANCEL, CallbackType.PAUSE, CallbackType.RESUME): self._conn.send_command('SET', 'self', 'NOTIFICATION', event, 'on') def _connection_arguments_from_address(self, address): """Parse a Speech Dispatcher address line and return a dictionary of connection arguments""" connection_args = {} address_params = address.split(":") try: _method = address_params[0] except: raise SSIPCommunicationErrror("Wrong format of server address") connection_args['communication_method'] = _method if _method == CommunicationMethod.UNIX_SOCKET: try: connection_args['socket_path'] = address_params[1] except IndexError: pass # The additional parameters was not set, let's stay with defaults elif _method == CommunicationMethod.INET_SOCKET: try: connection_args['host'] = address_params[1] connection_args['port'] = int(address_params[2]) except ValueError: # Failed conversion to int raise SSIPCommunicationError("Third parameter of inet_socket address must be a port number") except IndexError: pass # The additional parameters was not set, let's stay with defaults else: raise SSIPCommunicationError("Unknown communication method in address."); return connection_args def __del__(self): """Close the connection""" self.close() def _server_spawn(self, connection_args): """Attempts to spawn the speech-dispatcher server.""" # Check whether we are not connecting to a remote host # TODO: This is a hack. inet sockets specific code should # belong to _SSIPConnection. We do not however have an _SSIPConnection # yet. if connection_args['communication_method'] == 'inet_socket': addrinfos = socket.getaddrinfo(connection_args['host'], connection_args['port']) # Check resolved addrinfos for presence of localhost ip_addresses = [addrinfo[4][0] for addrinfo in addrinfos] localhost=False for ip in ip_addresses: if ip.startswith("127.") or ip == "::1": connection_args['host'] = ip localhost=True if not localhost: # The hostname didn't resolve on localhost in neither case, # do not spawn server on localhost... raise SpawnError( "Can't start server automatically (autospawn), requested address %s " "resolves on %s which seems to be a remote host. You must start the " "server manually or choose another connection address." % (connection_args['host'], str(ip_addresses),)) if os.path.exists(paths.SPD_SPAWN_CMD): connection_params = [] for param, value in connection_args.items(): if param not in ["host",]: connection_params += ["--"+param.replace("_","-"), str(value)] server = subprocess.Popen([paths.SPD_SPAWN_CMD, "--spawn"]+connection_params, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout_reply, stderr_reply = server.communicate() retcode = server.wait() if retcode != 0: raise SpawnError("Server refused to autospawn, stating this reason: %s" % (stderr_reply,)) return server.pid else: raise SpawnError("Can't find Speech Dispatcher spawn command %s" % (paths.SPD_SPAWN_CMD,)) def set_priority(self, priority): """Set the priority category for the following messages. Arguments: priority -- one of the 'Priority' constants. """ assert priority in (Priority.IMPORTANT, Priority.MESSAGE, Priority.TEXT, Priority.NOTIFICATION, Priority.PROGRESS), priority self._conn.send_command('SET', Scope.SELF, 'PRIORITY', priority) def set_data_mode(self, value): """Set the data mode for further speech commands. Arguments: value - one of the constants defined by the DataMode class. """ if value == DataMode.SSML: ssip_val = 'on' elif value == DataMode.TEXT: ssip_val = 'off' else: raise ValueError( 'Value "%s" is not one of the constants from the DataMode class.' % \ value) self._conn.send_command('SET', Scope.SELF, 'SSML_MODE', ssip_val) def speak(self, text, callback=None, event_types=None): """Say given message. Arguments: text -- message text to be spoken. This may be either a UTF-8 encoded byte string or a Python unicode string. callback -- a callback handler for asynchronous event notifications. A callable object (function) which accepts one positional argument `type' and one keyword argument `index_mark'. See below for more details. event_types -- a tuple of event types for which the callback should be called. Each item must be one of `CallbackType' constants. None (the default value) means to handle all event types. This argument is irrelevant when `callback' is not used. The callback function will be called whenever one of the events occurs. The event type will be passed as argument. Its value is one of the `CallbackType' constants. In case of an index mark event, additional keyword argument `index_mark' will be passed and will contain the index mark identifier as specified within the text. The callback function should not perform anything complicated and is not allowed to issue any further SSIP client commands. An attempt to do so would lead to a deadlock in SSIP communication. This method is non-blocking; it just sends the command, given message is queued on the server and the method returns immediately. """ self._conn.send_command('SPEAK') result = self._conn.send_data(text) if callback: msg_id = int(result[2][0]) # TODO: Here we risk, that the callback arrives earlier, than we # add the item to `self._callback_handler'. Such a situation will # lead to the callback being ignored. self._callback_handler.add_callback(msg_id, callback, event_types) return result def char(self, char): """Say given character. Arguments: char -- a character to be spoken. Either a Python unicode string or a UTF-8 encoded byte string. This method is non-blocking; it just sends the command, given message is queued on the server and the method returns immediately. """ self._conn.send_command('CHAR', char.replace(' ', 'space')) def key(self, key): """Say given key name. Arguments: key -- the key name (as defined in SSIP); string. This method is non-blocking; it just sends the command, given message is queued on the server and the method returns immediately. """ self._conn.send_command('KEY', key) def sound_icon(self, sound_icon): """Output given sound_icon. Arguments: sound_icon -- the name of the sound icon as defined by SSIP; string. This method is non-blocking; it just sends the command, given message is queued on the server and the method returns immediately. """ self._conn.send_command('SOUND_ICON', sound_icon) def cancel(self, scope=Scope.SELF): """Immediately stop speaking and discard messages in queues. Arguments: scope -- see the documentation of this class. """ self._conn.send_command('CANCEL', scope) def stop(self, scope=Scope.SELF): """Immediately stop speaking the currently spoken message. Arguments: scope -- see the documentation of this class. """ self._conn.send_command('STOP', scope) def pause(self, scope=Scope.SELF): """Pause speaking and postpone other messages until resume. This method is non-blocking. However, speaking can continue for a short while even after it's called (typically to the end of the sentence). Arguments: scope -- see the documentation of this class. """ self._conn.send_command('PAUSE', scope) def resume(self, scope=Scope.SELF): """Resume speaking of the currently paused messages. This method is non-blocking. However, speaking can continue for a short while even after it's called (typically to the end of the sentence). Arguments: scope -- see the documentation of this class. """ self._conn.send_command('RESUME', scope) def list_output_modules(self): """Return names of all active output modules as a tuple of strings.""" code, msg, data = self._conn.send_command('LIST', 'OUTPUT_MODULES') return data def list_synthesis_voices(self): """Return names of all available voices for the current output module. Returns a tuple of tripplets (name, language, dialect). 'name' is a string, 'language' is an ISO 639-1 Alpha-2 language code and 'dialect' is a string. Language and dialect may be None. """ try: code, msg, data = self._conn.send_command('LIST', 'SYNTHESIS_VOICES') except SSIPCommandError: return () def split(item): name, lang, dialect = tuple(item.rsplit('\t', 3)) return (name, lang or None, dialect or None) return tuple([split(item) for item in data]) def set_language(self, language, scope=Scope.SELF): """Switch to a particular language for further speech commands. Arguments: language -- two letter language code according to RFC 1766 as string. scope -- see the documentation of this class. """ assert isinstance(language, str) and len(language) == 2 self._conn.send_command('SET', scope, 'LANGUAGE', language) def get_language(self): """Get the current language.""" code, msg, data = self._conn.send_command('GET', 'LANGUAGE') if data: return data[0] return None def set_output_module(self, name, scope=Scope.SELF): """Switch to a particular output module. Arguments: name -- module (string) as returned by 'list_output_modules()'. scope -- see the documentation of this class. """ self._conn.send_command('SET', scope, 'OUTPUT_MODULE', name) def get_output_module(self): """Get the current output module.""" code, msg, data = self._conn.send_command('GET', 'OUTPUT_MODULE') if data: return data[0] return None def set_pitch(self, value, scope=Scope.SELF): """Set the pitch for further speech commands. Arguments: value -- integer value within the range from -100 to 100, with 0 corresponding to the default pitch of the current speech synthesis output module, lower values meaning lower pitch and higher values meaning higher pitch. scope -- see the documentation of this class. """ assert isinstance(value, int) and -100 <= value <= 100, value self._conn.send_command('SET', scope, 'PITCH', value) def get_pitch(self): """Get the current pitch.""" code, msg, data = self._conn.send_command('GET', 'PITCH') if data: return data[0] return None def set_pitch_range(self, value, scope=Scope.SELF): """Set the pitch range for further speech commands. Arguments: value -- integer value within the range from -100 to 100, with 0 corresponding to the default pitch range of the current speech synthesis output module, lower values meaning lower pitch range and higher values meaning higher pitch range. scope -- see the documentation of this class. """ assert isinstance(value, int) and -100 <= value <= 100, value self._conn.send_command('SET', scope, 'PITCH_RANGE', value) def set_rate(self, value, scope=Scope.SELF): """Set the speech rate (speed) for further speech commands. Arguments: value -- integer value within the range from -100 to 100, with 0 corresponding to the default speech rate of the current speech synthesis output module, lower values meaning slower speech and higher values meaning faster speech. scope -- see the documentation of this class. """ assert isinstance(value, int) and -100 <= value <= 100 self._conn.send_command('SET', scope, 'RATE', value) def get_rate(self): """Get the current speech rate (speed).""" code, msg, data = self._conn.send_command('GET', 'RATE') if data: return data[0] return None def set_volume(self, value, scope=Scope.SELF): """Set the speech volume for further speech commands. Arguments: value -- integer value within the range from -100 to 100, with 100 corresponding to the default speech volume of the current speech synthesis output module, lower values meaning softer speech. scope -- see the documentation of this class. """ assert isinstance(value, int) and -100 <= value <= 100 self._conn.send_command('SET', scope, 'VOLUME', value) def get_volume(self): """Get the speech volume.""" code, msg, data = self._conn.send_command('GET', 'VOLUME') if data: return data[0] return None def set_punctuation(self, value, scope=Scope.SELF): """Set the punctuation pronounciation level. Arguments: value -- one of the 'PunctuationMode' constants. scope -- see the documentation of this class. """ assert value in (PunctuationMode.ALL, PunctuationMode.SOME, PunctuationMode.NONE), value self._conn.send_command('SET', scope, 'PUNCTUATION', value) def set_spelling(self, value, scope=Scope.SELF): """Toogle the spelling mode or on off. Arguments: value -- if 'True', all incomming messages will be spelled instead of being read as normal words. 'False' switches this behavior off. scope -- see the documentation of this class. """ assert value in [True, False] if value == True: self._conn.send_command('SET', scope, 'SPELLING', "on") else: self._conn.send_command('SET', scope, 'SPELLING', "off") def set_cap_let_recogn(self, value, scope=Scope.SELF): """Set capital letter recognition mode. Arguments: value -- one of 'none', 'spell', 'icon'. None means no signalization of capital letters, 'spell' means capital letters will be spelled with a syntetic voice and 'icon' means that the capital-letter icon will be prepended before each capital letter. scope -- see the documentation of this class. """ assert value in ("none", "spell", "icon") self._conn.send_command('SET', scope, 'CAP_LET_RECOGN', value) def set_voice(self, value, scope=Scope.SELF): """Set voice by a symbolic name. Arguments: value -- one of the SSIP symbolic voice names: 'MALE1' .. 'MALE3', 'FEMALE1' ... 'FEMALE3', 'CHILD_MALE', 'CHILD_FEMALE' scope -- see the documentation of this class. Symbolic voice names are mapped to real synthesizer voices in the configuration of the output module. Use the method 'set_synthesis_voice()' if you want to work with real voices. """ assert isinstance(value, str) and \ value.lower() in ("male1", "male2", "male3", "female1", "female2", "female3", "child_male", "child_female") self._conn.send_command('SET', scope, 'VOICE_TYPE', value) def set_synthesis_voice(self, value, scope=Scope.SELF): """Set voice by its real name. Arguments: value -- voice name as returned by 'list_synthesis_voices()' scope -- see the documentation of this class. """ self._conn.send_command('SET', scope, 'SYNTHESIS_VOICE', value) def set_pause_context(self, value, scope=Scope.SELF): """Set the amount of context when resuming a paused message. Arguments: value -- a positive or negative value meaning how many chunks of data after or before the pause should be read when resume() is executed. scope -- see the documentation of this class. """ assert isinstance(value, int) self._conn.send_command('SET', scope, 'PAUSE_CONTEXT', value) def set_debug(self, val): """Switch debugging on and off. When switched on, debugging files will be created in the chosen destination (see set_debug_destination()) for Speech Dispatcher and all its running modules. All logging information will then be written into these files with maximal verbosity until switched off. You should always first call set_debug_destination. The intended use of this functionality is to switch debuging on for a period of time while the user will repeat the behavior and then send the logs to the appropriate bug-reporting place. Arguments: val -- a boolean value determining whether debugging is switched on or off scope -- see the documentation of this class. """ assert isinstance(val, bool) if val == True: ssip_val = "ON" else: ssip_val = "OFF" self._conn.send_command('SET', scope.ALL, 'DEBUG', ssip_val) def set_debug_destination(self, path): """Set debug destination. Arguments: path -- path (string) to the directory where debuging files will be created scope -- see the documentation of this class. """ assert isinstance(val, string) self._conn.send_command('SET', scope.ALL, 'DEBUG_DESTINATION', val) def block_begin(self): """Begin an SSIP block. See SSIP documentation for more details about blocks. """ self._conn.send_command('BLOCK', 'BEGIN') def block_end(self): """Close an SSIP block. See SSIP documentation for more details about blocks. """ self._conn.send_command('BLOCK', 'END') def close(self): """Close the connection to Speech Dispatcher.""" if hasattr(self, '_conn'): self._conn.close() del self._conn class Client(SSIPClient): """A DEPRECATED backwards-compatible API. This Class is provided only for backwards compatibility with the prevoius unofficial API. It will be removed in future versions. Please use either 'SSIPClient' or 'Speaker' interface instead. As deprecated, the API is no longer documented. """ def __init__(self, name=None, client=None, **kwargs): name = name or client or 'python' super(Client, self).__init__(name, **kwargs) def say(self, text, priority=Priority.MESSAGE): self.set_priority(priority) self.speak(text) def char(self, char, priority=Priority.TEXT): self.set_priority(priority) super(Client, self).char(char) def key(self, key, priority=Priority.TEXT): self.set_priority(priority) super(Client, self).key(key) def sound_icon(self, sound_icon, priority=Priority.TEXT): self.set_priority(priority) super(Client, self).sound_icon(sound_icon) class Speaker(SSIPClient): """Extended Speech Dispatcher Interface. This class provides an extended intercace to Speech Dispatcher functionality and tries to hide most of the lower level details of SSIP (such as a more sophisticated handling of blocks and priorities and advanced event notifications) under a more convenient API. Please note that the API is not yet stabilized and thus is subject to change! Please contact the authors if you plan using it and/or if you have any suggestions. Well, in fact this class is currently not implemented at all. It is just a draft. The intention is to hide the SSIP details and provide a generic interface practical for screen readers. """ # Deprecated but retained for backwards compatibility # This class was introduced in 0.7 but later renamed to CommunicationMethod class ConnectionMethod(object): """Constants describing the possible methods of connection to server. Retained for backwards compatibility but DEPRECATED. See CommunicationMethod.""" UNIX_SOCKET = 'unix_socket' """Unix socket communication using a filesystem path""" INET_SOCKET = 'inet_socket' """Inet socket communication using a host and port""" speech-dispatcher-0.9.1/src/api/python/speechd/_test.py0000644000175000017500000001173313406252170020026 00000000000000#!/usr/bin/env python # Copyright (C) 2003, 2006, 2007 Brailcom, o.p.s. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . import unittest import time from .client import PunctuationMode, CallbackType, SSIPClient, Scope, Speaker class _SSIPClientTest(unittest.TestCase): def setUp(self): self._client = SSIPClient('test') self._client.set_language('en') self._client.set_rate(30) def tearDown(self): self._client.close() class AutomaticTest(_SSIPClientTest): """A set of tests which may be evaluated automatically. Please put all tests which require a user to listen to their output to the VoiceTest below. """ def test_callbacks(self): # TODO: This needs to be fixed. There is no guarantee that # the message will start in one second nor is there any # guarantee that it will start at all. It can be interrupted # by other applications etc. Also there is no guarantee that # the cancel will arrive on time and the end callback will be # received on time. Also the combination cancel/end does not have # to work as expected and SD and the interface can still be ok. # -- Hynek Hanke self._client.set_output_module('flite') called = {CallbackType.BEGIN: [], CallbackType.CANCEL: [], CallbackType.END: []} self._client.speak("This message should get interrupted. It is " "hopefully long enough to last more than 1 second.", callback=lambda type: called[type].append('msg1')) self._client.speak("This second message should not be spoken at all.", callback=lambda type: called[type].append('msg2')) time.sleep(1) self._client.cancel() self._client.speak("Hi.", callback=lambda type: called[type].append('msg3')) # Wait for pending events... time.sleep(3) started, canceled, ended = [called[t] for t in (CallbackType.BEGIN, CallbackType.CANCEL, CallbackType.END)] assert started == ['msg1', 'msg3'] and ended == ['msg3'] and \ 'msg1' in canceled and 'msg2' in canceled and \ 'msg3' not in canceled, \ (called, "This failure only indicates a possible error. The test " "depends on proper timing and results may warry depending " "on the used output module and other conditions. See the " "code of this test method if you want to investigate " "further.") class VoiceTest(_SSIPClientTest): """This set of tests requires a user to listen to it. The success or failure of the tests defined here can not be detected automatically. """ def test_escapes(self): c = self._client c.speak("Testing data escapes:") c.set_punctuation(PunctuationMode.ALL) c.speak(".") c.speak("Marker at the end.\r\n.\r\n") c.speak(".\r\nMarker at the beginning.") def test_voice_properties(self): c = self._client c.speak("Testing voice properties:") c.set_pitch(-100) c.speak("I am fat Billy") c.set_pitch(100) c.speak("I am slim Willy") c.set_pitch(0) c.set_rate(100) c.speak("I am quick Dick.") c.set_rate(-80) c.speak("I am slow Joe.") c.set_rate(0) c.set_pitch(100) c.set_volume(-50) c.speak("I am quiet Mariette.") c.set_volume(100) c.speak("I am noisy Daisy.") def test_other_commands(self): c = self._client c.speak("Testing other commands:") c.char("a") c.key("shift_b") c.sound_icon("empty") def test_lists(self): c = self._client for module in c.list_output_modules(): c.set_output_module(module) print("**", module) c.speak(module +"using default voice") for name, lang, dialect in c.list_synthesis_voices(): print(" -", module, name, lang, dialect) c.set_synthesis_voice(name) c.speak(module +" using voice "+ name) if __name__ == '__main__': unittest.main() speech-dispatcher-0.9.1/src/api/python/speechd/__init__.py0000644000175000017500000000133013406252157020444 00000000000000# Copyright (C) 2001, 2002 Brailcom, o.p.s. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . from .client import * speech-dispatcher-0.9.1/src/api/python/speechd/Makefile.am0000644000175000017500000000215513406252151020367 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in speechd_pythondir = $(pyexecdir)/speechd speechd_python_PYTHON = __init__.py _test.py client.py nodist_speechd_python_PYTHON = paths.py edit = sed \ -e 's:@bindir[@]:$(bindir):g' paths.py: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(edit) $${srcdir}$@.in > $@ paths.py: $(srcdir)/paths.py.in CLEANFILES = paths.py EXTRA_DIST = paths.py.in -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/api/python/README0000644000175000017500000000200513424443425015600 00000000000000This is a Python interface to SSIP. Full range of SSIP commands is implemented including callback handling. See the section "Python API" in Speech Dispatcher documentation for more information. If you have any questions, suggestions, etc., feel free to contact us at the mailing list . -- Tomas Cerha Copyright (C) 2008 Brailcom, o.p.s This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/api/python/Makefile.in0000644000175000017500000005265713465233610017005 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/api/python ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = speechd speechd_config all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/api/python/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/api/python/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/api/python/Makefile.am0000644000175000017500000000142313406252141016750 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in SUBDIRS = speechd speechd_config -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/api/c/0000755000175000017500000000000013465234514013706 500000000000000speech-dispatcher-0.9.1/src/api/c/libspeechd_version.h.in0000644000175000017500000000221313406252020020234 00000000000000/* * libspeechd_version.h - Shared library for easy access to Speech Dispatcher functions (header) * * Copyright (C) 2001, 2002, 2003, 2004 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1, or (at your option) * any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: libspeechd.h,v 1.29 2008-07-30 09:47:00 hanke Exp $ */ #ifndef _LIBSPEECHD_VERSION_H #define _LIBSPEECHD_VERSION_H #define LIBSPEECHD_MAJOR_VERSION @LIBSPEECHD_MAJOR_VERSION@ #define LIBSPEECHD_MINOR_VERSION @LIBSPEECHD_MINOR_VERSION@ #define LIBSPEECHD_MICRO_VERSION @LIBSPEECHD_MICRO_VERSION@ #endif /* ifndef _LIBSPEECHD_VERSION_H */ speech-dispatcher-0.9.1/src/api/c/libspeechd.c0000644000175000017500000014626313406252007016100 00000000000000/* libspeechd.c - Shared library for easy acces to Speech Dispatcher functions * * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1, or (at your option) * any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: libspeechd.c,v 1.37 2008-12-23 09:15:32 pdm Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This is needed because speechd_types.h is in a different location in * the source tree's include directory than it will be when it is * installed on the user's system. */ #include #include #include "libspeechd.h" /* Comment/uncomment to switch debugging on/off */ // #define LIBSPEECHD_DEBUG 1 /* Unless there is an fatal error, it doesn't print anything */ #define SPD_FATAL(msg) { printf("Fatal error (libspeechd) [%s:%d]:"msg, __FILE__, __LINE__); fflush(stdout); exit(EXIT_FAILURE); } /* -------------- Private functions headers ------------------------*/ #ifdef LIBSPEECHD_DEBUG static FILE *spd_debug = NULL; #endif static int spd_set_priority(SPDConnection * connection, SPDPriority priority); static char *escape_dot(const char *text); static int isanum(char *str); static char *get_reply(SPDConnection * connection); static int get_err_code(char *reply); static char *get_param_str(char *reply, int num, int *err); static int get_param_int(char *reply, int num, int *err); static int ret_ok(char *reply); static void SPD_DBG(char *format, ...); static void *spd_events_handler(void *); const int range_low = -100; const int range_high = 100; pthread_mutex_t spd_logging_mutex; struct SPDConnection_threaddata { pthread_t events_thread; pthread_cond_t cond_reply_ready; pthread_mutex_t mutex_reply_ready; pthread_cond_t cond_reply_ack; pthread_mutex_t mutex_reply_ack; }; /* * Added by Willie Walker - strndup and getline were GNU libc extensions * that were adopted in the POSIX.1-2008 standard, but are not yet found * on all systems. */ #ifndef HAVE_STRNDUP char *strndup(const char *s, size_t n) { size_t nAvail; char *p; if (!s) return 0; if (strlen(s) > n) nAvail = n + 1; else nAvail = strlen(s) + 1; p = malloc(nAvail); memcpy(p, s, nAvail); p[nAvail - 1] = '\0'; return p; } #endif /* HAVE_STRNDUP */ #ifndef HAVE_GETLINE #define BUFFER_LEN 256 ssize_t getline(char **lineptr, size_t * n, FILE * f) { int ch; size_t m = 0; ssize_t buf_len = 0; char *buf = NULL; char *p = NULL; if (errno != 0) { SPD_DBG("getline: errno came in as %d!!!\n", errno); errno = 0; } while ((ch = getc(f)) != EOF) { if (errno != 0) return -1; if (m++ >= buf_len) { buf_len += BUFFER_LEN; buf = (char *)realloc(buf, buf_len + 1); if (buf == NULL) { SPD_DBG("buf==NULL"); return -1; } p = buf + buf_len - BUFFER_LEN; } *p = ch; p++; if (ch == '\n') break; } if (m == 0) { SPD_DBG("getline: m=%d!", m); return -1; } else { *p = '\0'; *lineptr = buf; *n = m; return m; } } #endif /* HAVE_GETLINE */ /* --------------------- Public functions ------------------------- */ #define SPD_REPLY_BUF_SIZE 65536 /* Determine address for the unix socket */ static char *_get_default_unix_socket_name(void) { GString *socket_filename; char *h; const char *rundir = g_get_user_runtime_dir(); socket_filename = g_string_new(""); g_string_printf(socket_filename, "%s/speech-dispatcher/speechd.sock", rundir); // Do not return glib string, but glibc string... h = strdup(socket_filename->str); g_string_free(socket_filename, 1); return h; } void SPDConnectionAddress__free(SPDConnectionAddress * address) { if (!address) return; free(address->unix_socket_name); free(address->inet_socket_host); free(address->dbus_bus); free(address); } SPDConnectionAddress *spd_get_default_address(char **error) { const gchar *env_address = g_getenv("SPEECHD_ADDRESS"); gchar **pa; /* parsed address */ SPDConnectionAddress *address = malloc(sizeof(SPDConnectionAddress)); address->unix_socket_name = NULL; address->inet_socket_host = NULL; address->dbus_bus = NULL; if (env_address == NULL) { // Default method = unix sockets address->method = SPD_METHOD_UNIX_SOCKET; address->unix_socket_name = _get_default_unix_socket_name(); } else { pa = g_strsplit(env_address, ":", 0); assert(pa); if (!g_strcmp0(pa[0], "unix_socket") || pa[0] == NULL) { // Unix sockets address->method = SPD_METHOD_UNIX_SOCKET; if (pa[1] == NULL) { address->unix_socket_name = _get_default_unix_socket_name(); } else { address->unix_socket_name = strdup(pa[1]); } } else if (!g_strcmp0(pa[0], "inet_socket")) { // Inet sockets address->method = SPD_METHOD_INET_SOCKET; if (pa[1] == NULL) { address->inet_socket_host = strdup("127.0.0.1"); address->inet_socket_port = 6560; } else { address->inet_socket_host = strdup(pa[1]); if (pa[2] == NULL) { address->inet_socket_port = SPEECHD_DEFAULT_PORT; } else { address->inet_socket_port = atoi(pa[2]); } } } else { // Unknown or unsupported method requested *error = strdup ("Unknown or unsupported communication method"); SPDConnectionAddress__free(address); address = NULL; } g_strfreev(pa); } return address; } static void _init_debug(void) { #ifdef LIBSPEECHD_DEBUG if (!spd_debug) { spd_debug = fopen("/tmp/libspeechd.log", "w"); if (spd_debug == NULL) SPD_FATAL("COULDN'T ACCES FILE INTENDED FOR DEBUG"); if (pthread_mutex_init(&spd_logging_mutex, NULL)) { fprintf(stderr, "Mutex initialization failed"); fflush(stderr); exit(1); } SPD_DBG("Debugging started"); } #endif /* LIBSPEECHD_DEBUG */ } /* Opens a new Speech Dispatcher connection. * Returns socket file descriptor of the created connection * or -1 if no connection was opened. */ SPDConnection *spd_open(const char *client_name, const char *connection_name, const char *user_name, SPDConnectionMode mode) { char *error; int autospawn = 1; SPDConnection *conn; conn = spd_open2(client_name, connection_name, user_name, mode, NULL, autospawn, &error); if (!conn) { _init_debug(); assert(error); SPD_DBG("Could not connect to Speech Dispatcher: %s", error); free(error); } return conn; } #define MAX_IP_SIZE 16+1 /* TODO: This only works in IPV4 */ static char *resolve_host(char *host_name_or_ip, int *is_localhost, gchar ** error) { struct addrinfo *addr_result; int err; char *resolve_buffer = malloc(MAX_IP_SIZE * sizeof(char)); const char *resolved_ip = NULL; char *ip; *error = NULL; struct sockaddr_in *addr_in; if (resolve_buffer == NULL) { *error = g_strdup("Failed to allocate memory."); return NULL; } err = getaddrinfo(host_name_or_ip, 0, NULL, &addr_result); if (err) { *error = g_strdup_printf("Can't resolve address %d due to error %s:", err, gai_strerror(err)); free(resolve_buffer); return NULL; } /* Take the first address returned as we are only interested in host ip */ addr_in = (struct sockaddr_in *)addr_result->ai_addr; resolved_ip = inet_ntop(AF_INET, &(addr_in->sin_addr.s_addr), resolve_buffer, MAX_IP_SIZE); if (resolved_ip == NULL) { *error = g_strdup_printf ("Could not convert address, due to the following error: %s", strerror(errno)); freeaddrinfo(addr_result); free(resolve_buffer); return NULL; } if (!strncmp(resolved_ip, "127.", 4)) { *is_localhost = 1; /* In case of local addresses, use 127.0.0.1 which is guaranteed to be local and the server listens on it */ free(resolve_buffer); ip = strdup("127.0.0.1"); } else { *is_localhost = 0; ip = resolve_buffer; } freeaddrinfo(addr_result); return ip; } static int spawn_server(SPDConnectionAddress * address, int is_localhost, gchar ** spawn_error) { gchar *speechd_cmd[16]; gchar *stderr_output; gboolean spawn_ok; GError *gerror = NULL; int exit_status; int i; if ((address->method == SPD_METHOD_INET_SOCKET) && (!is_localhost)) { *spawn_error = g_strdup ("Spawn failed, the given network address doesn't seem to be on localhost"); return 1; } speechd_cmd[0] = g_strdup(SPD_SPAWN_CMD); speechd_cmd[1] = g_strdup("--spawn"); speechd_cmd[2] = g_strdup("--communication-method"); if (address->method == SPD_METHOD_INET_SOCKET) { speechd_cmd[3] = g_strdup("inet_socket"); speechd_cmd[4] = g_strdup("--port"); speechd_cmd[5] = g_strdup_printf("%d", address->inet_socket_port); speechd_cmd[6] = NULL; } else if (address->method == SPD_METHOD_UNIX_SOCKET) { speechd_cmd[3] = g_strdup("unix_socket"); speechd_cmd[4] = g_strdup("--socket-path"); speechd_cmd[5] = g_strdup_printf("%s", address->unix_socket_name); speechd_cmd[6] = NULL; } else assert(0); spawn_ok = g_spawn_sync(NULL, (gchar **) speechd_cmd, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL, NULL, NULL, NULL, &stderr_output, &exit_status, &gerror); for (i = 0; speechd_cmd[i] != NULL; i++) g_free(speechd_cmd[i]); if (!spawn_ok) { *spawn_error = g_strdup_printf("Autospawn failed. Spawn error %d: %s", gerror->code, gerror->message); return 1; } else { if (exit_status) { *spawn_error = g_strdup_printf ("Autospawn failed. Speech Dispatcher refused to start with error code, " "stating this as a reason: %s", stderr_output); return 1; } else { *spawn_error = NULL; return 0; } } assert(0); } SPDConnection *spd_open2(const char *client_name, const char *connection_name, const char *user_name, SPDConnectionMode mode, SPDConnectionAddress * address, int autospawn, char **error_result) { SPDConnection *connection = NULL; SPDConnectionAddress *defaultAddress = NULL; char *set_client_name = NULL; char *conn_name = NULL; char *usr_name = NULL; int ret; char tcp_no_delay = 1; /* Autospawn related */ int spawn_err; gchar *spawn_report; char *host_ip; int is_localhost = 1; struct sockaddr_in address_inet; struct sockaddr_un address_unix; struct sockaddr *sock_address; size_t sock_address_len; _init_debug(); if (client_name == NULL) { *error_result = strdup("ERROR: Client name not specified"); SPD_DBG(*error_result); return NULL; } if (user_name == NULL) { usr_name = strdup((char *)g_get_user_name()); } else usr_name = strdup(user_name); if (connection_name == NULL) conn_name = strdup("main"); else conn_name = strdup(connection_name); if (address == NULL) { char *err = NULL; defaultAddress = spd_get_default_address(&err); address = defaultAddress; if (!address) { assert(err); *error_result = err; SPD_DBG(*error_result); goto out; } } /* Connect to server using the selected method */ connection = malloc(sizeof(SPDConnection)); if (address->method == SPD_METHOD_INET_SOCKET) { gchar *resolve_error; host_ip = resolve_host(address->inet_socket_host, &is_localhost, &resolve_error); if (host_ip == NULL) { *error_result = strdup(resolve_error); g_free(resolve_error); free(connection); connection = NULL; goto out; } address_inet.sin_addr.s_addr = inet_addr(host_ip); free(host_ip); address_inet.sin_port = htons(address->inet_socket_port); address_inet.sin_family = AF_INET; connection->socket = socket(AF_INET, SOCK_STREAM, 0); sock_address = (struct sockaddr *)&address_inet; sock_address_len = sizeof(address_inet); } else if (address->method == SPD_METHOD_UNIX_SOCKET) { /* Create the unix socket */ address_unix.sun_family = AF_UNIX; strncpy(address_unix.sun_path, address->unix_socket_name, sizeof(address_unix.sun_path)); address_unix.sun_path[sizeof(address_unix.sun_path) - 1] = '\0'; connection->socket = socket(AF_UNIX, SOCK_STREAM, 0); sock_address = (struct sockaddr *)&address_unix; sock_address_len = SUN_LEN(&address_unix); } else SPD_FATAL("Unsupported connection method for spd_open2()"); if (connection->socket < 0) { free(connection); connection = NULL; goto out; } ret = connect(connection->socket, sock_address, sock_address_len); if (ret == -1) { /* Suppose server might not be running, try to autospawn (autostart) it */ if (autospawn) { spawn_err = spawn_server(address, is_localhost, &spawn_report); if (!spawn_err) spawn_report = g_strdup("Server successfully autospawned"); ret = connect(connection->socket, sock_address, sock_address_len); } else { spawn_report = g_strdup("Autospawn disabled"); } if (ret == -1) { if (address->method == SPD_METHOD_INET_SOCKET) *error_result = g_strdup_printf ("Error: Can't connect to %s on port %d using inet sockets: %s. " "Autospawn: %s", address->inet_socket_host, address->inet_socket_port, strerror(errno), spawn_report); else if (address->method == SPD_METHOD_UNIX_SOCKET) *error_result = g_strdup_printf ("Error: Can't connect to unix socket %s: %s. Autospawn: %s", address->unix_socket_name, strerror(errno), spawn_report); else assert(0); SPD_DBG(*error_result); close(connection->socket); free(connection); connection = NULL; goto out; } g_free(spawn_report); } if (address->method == SPD_METHOD_INET_SOCKET) setsockopt(connection->socket, IPPROTO_TCP, TCP_NODELAY, &tcp_no_delay, sizeof(int)); connection->callback_begin = NULL; connection->callback_end = NULL; connection->callback_im = NULL; connection->callback_pause = NULL; connection->callback_resume = NULL; connection->callback_cancel = NULL; connection->mode = mode; /* Create a stream from the socket */ connection->stream = fdopen(connection->socket, "r"); if (!connection->stream) SPD_FATAL("Can't create a stream for socket, fdopen() failed."); /* Switch to line buffering mode */ ret = setvbuf(connection->stream, NULL, _IONBF, SPD_REPLY_BUF_SIZE); if (ret) SPD_FATAL("Can't set buffering, setvbuf failed."); pthread_mutex_init(&connection->ssip_mutex, NULL); if (mode == SPD_MODE_THREADED) { SPD_DBG ("Initializing threads, condition variables and mutexes..."); connection->td = malloc(sizeof(*connection->td)); pthread_cond_init(&connection->td->cond_reply_ready, NULL); pthread_mutex_init(&connection->td->mutex_reply_ready, NULL); pthread_cond_init(&connection->td->cond_reply_ack, NULL); pthread_mutex_init(&connection->td->mutex_reply_ack, NULL); ret = pthread_create(&connection->td->events_thread, NULL, spd_events_handler, connection); if (ret != 0) { *error_result = strdup("Thread initialization failed"); SPD_DBG(*error_result); fclose(connection->stream); close(connection->socket); free(connection); connection = NULL; goto out; } } /* By now, the connection is created and operational */ set_client_name = g_strdup_printf("SET SELF CLIENT_NAME \"%s:%s:%s\"", usr_name, client_name, conn_name); ret = spd_execute_command_wo_mutex(connection, set_client_name); out: free(usr_name); free(conn_name); free(set_client_name); SPDConnectionAddress__free(defaultAddress); return connection; } #define RET(r) \ { \ pthread_mutex_unlock(&connection->ssip_mutex); \ return r; \ } /* Close a Speech Dispatcher connection */ void spd_close(SPDConnection * connection) { pthread_mutex_lock(&connection->ssip_mutex); if (connection->mode == SPD_MODE_THREADED) { pthread_cancel(connection->td->events_thread); pthread_mutex_destroy(&connection->td->mutex_reply_ready); pthread_mutex_destroy(&connection->td->mutex_reply_ack); pthread_cond_destroy(&connection->td->cond_reply_ready); pthread_cond_destroy(&connection->td->cond_reply_ack); pthread_join(connection->td->events_thread, NULL); connection->mode = SPD_MODE_SINGLE; free(connection->td); } /* close the socket */ close(connection->socket); pthread_mutex_unlock(&connection->ssip_mutex); pthread_mutex_destroy(&connection->ssip_mutex); free(connection); } /* Helper functions for spd_say. */ static inline int spd_say_prepare(SPDConnection * connection, SPDPriority priority, const char *text, char **escaped_text) { int ret = 0; SPD_DBG("Text to say is: %s", text); /* Insure that there is no escape sequence in the text */ *escaped_text = escape_dot(text); /* Caller is now responsible for escaped_text. */ if (*escaped_text == NULL) { /* Out of memory. */ SPD_DBG("spd_say could not allocate memory."); ret = -1; } else { /* Set priority */ SPD_DBG("Setting priority"); ret = spd_set_priority(connection, priority); if (!ret) { /* Start the data flow */ SPD_DBG("Sending SPEAK"); ret = spd_execute_command_wo_mutex(connection, "speak"); if (ret) { SPD_DBG("Error: Can't start data flow!"); } } } return ret; } static inline int spd_say_sending(SPDConnection * connection, const char *text) { int msg_id = -1; int err = 0; char *reply = NULL; char *pret = NULL; /* Send data */ SPD_DBG("Sending data"); pret = spd_send_data_wo_mutex(connection, text, SPD_NO_REPLY); if (pret == NULL) { SPD_DBG("Can't send data wo mutex"); } else { /* Terminate data flow */ SPD_DBG("Terminating data flow"); err = spd_execute_command_with_reply(connection, "\r\n.", &reply); if (err) { SPD_DBG("Can't terminate data flow"); } else { msg_id = get_param_int(reply, 1, &err); if (err < 0) { SPD_DBG ("Can't determine SSIP message unique ID parameter."); msg_id = -1; } } } free(reply); free(pret); return msg_id; } /* Say TEXT with priority PRIORITY. * Returns msg_uid on success, -1 otherwise. */ int spd_say(SPDConnection * connection, SPDPriority priority, const char *text) { char *escaped_text = NULL; int msg_id = -1; int prepare_failed = 0; if (text != NULL) { pthread_mutex_lock(&connection->ssip_mutex); prepare_failed = spd_say_prepare(connection, priority, text, &escaped_text); if (!prepare_failed) msg_id = spd_say_sending(connection, escaped_text); free(escaped_text); pthread_mutex_unlock(&connection->ssip_mutex); } else { SPD_DBG("spd_say called with a NULL argument for "); } SPD_DBG("Returning from spd_say"); return msg_id; } /* The same as spd_say, accepts also formated strings */ int spd_sayf(SPDConnection * connection, SPDPriority priority, const char *format, ...) { static int ret; va_list args; char *buf; if (format == NULL) return -1; /* Print the text to buffer */ va_start(args, format); buf = g_strdup_vprintf(format, args); va_end(args); /* Send the buffer to Speech Dispatcher */ ret = spd_say(connection, priority, buf); free(buf); return ret; } int spd_stop(SPDConnection * connection) { return spd_execute_command(connection, "STOP SELF"); } int spd_stop_all(SPDConnection * connection) { return spd_execute_command(connection, "STOP ALL"); } int spd_stop_uid(SPDConnection * connection, int target_uid) { static char command[16]; sprintf(command, "STOP %d", target_uid); return spd_execute_command(connection, command); } int spd_cancel(SPDConnection * connection) { return spd_execute_command(connection, "CANCEL SELF"); } int spd_cancel_all(SPDConnection * connection) { return spd_execute_command(connection, "CANCEL ALL"); } int spd_cancel_uid(SPDConnection * connection, int target_uid) { static char command[16]; sprintf(command, "CANCEL %d", target_uid); return spd_execute_command(connection, command); } int spd_pause(SPDConnection * connection) { return spd_execute_command(connection, "PAUSE SELF"); } int spd_pause_all(SPDConnection * connection) { return spd_execute_command(connection, "PAUSE ALL"); } int spd_pause_uid(SPDConnection * connection, int target_uid) { char command[16]; sprintf(command, "PAUSE %d", target_uid); return spd_execute_command(connection, command); } int spd_resume(SPDConnection * connection) { return spd_execute_command(connection, "RESUME SELF"); } int spd_resume_all(SPDConnection * connection) { return spd_execute_command(connection, "RESUME ALL"); } int spd_resume_uid(SPDConnection * connection, int target_uid) { static char command[16]; sprintf(command, "RESUME %d", target_uid); return spd_execute_command(connection, command); } int spd_key(SPDConnection * connection, SPDPriority priority, const char *key_name) { char *command_key; int ret; if (key_name == NULL) return -1; pthread_mutex_lock(&connection->ssip_mutex); ret = spd_set_priority(connection, priority); if (ret) RET(-1); command_key = g_strdup_printf("KEY %s", key_name); ret = spd_execute_command_wo_mutex(connection, command_key); free(command_key); if (ret) RET(-1); pthread_mutex_unlock(&connection->ssip_mutex); return 0; } int spd_char(SPDConnection * connection, SPDPriority priority, const char *character) { static char command[16]; int ret; if (character == NULL) return -1; if (strlen(character) > 6) return -1; pthread_mutex_lock(&connection->ssip_mutex); ret = spd_set_priority(connection, priority); if (ret) RET(-1); sprintf(command, "CHAR %s", character); ret = spd_execute_command_wo_mutex(connection, command); if (ret) RET(-1); pthread_mutex_unlock(&connection->ssip_mutex); return 0; } int spd_wchar(SPDConnection * connection, SPDPriority priority, wchar_t wcharacter) { static char command[16]; char character[8]; int ret; pthread_mutex_lock(&connection->ssip_mutex); ret = wcrtomb(character, wcharacter, NULL); if (ret <= 0) RET(-1); ret = spd_set_priority(connection, priority); if (ret) RET(-1); assert(character != NULL); sprintf(command, "CHAR %s", character); ret = spd_execute_command_wo_mutex(connection, command); if (ret) RET(-1); pthread_mutex_unlock(&connection->ssip_mutex); return 0; } int spd_sound_icon(SPDConnection * connection, SPDPriority priority, const char *icon_name) { char *command; int ret; if (icon_name == NULL) return -1; pthread_mutex_lock(&connection->ssip_mutex); ret = spd_set_priority(connection, priority); if (ret) RET(-1); command = g_strdup_printf("SOUND_ICON %s", icon_name); ret = spd_execute_command_wo_mutex(connection, command); free(command); if (ret) RET(-1); pthread_mutex_unlock(&connection->ssip_mutex); return 0; } // Set functions for Punctuation int spd_w_set_punctuation(SPDConnection * connection, SPDPunctuation type, const char *who) { char command[32]; int ret; if (type == SPD_PUNCT_ALL) sprintf(command, "SET %s PUNCTUATION all", who); if (type == SPD_PUNCT_NONE) sprintf(command, "SET %s PUNCTUATION none", who); if (type == SPD_PUNCT_SOME) sprintf(command, "SET %s PUNCTUATION some", who); ret = spd_execute_command(connection, command); return ret; } int spd_set_punctuation(SPDConnection * connection, SPDPunctuation type) { return spd_w_set_punctuation(connection, type, SPD_SELF); } int spd_set_punctuation_all(SPDConnection * connection, SPDPunctuation type) { return spd_w_set_punctuation(connection, type, SPD_ALLCLIENTS); } int spd_set_punctuation_uid(SPDConnection * connection, SPDPunctuation type, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_punctuation(connection, type, who); } // Set functions for Capital Letters int spd_w_set_capital_letters(SPDConnection * connection, SPDCapitalLetters type, const char *who) { char command[64]; int ret; if (type == SPD_CAP_NONE) sprintf(command, "SET %s CAP_LET_RECOGN none", who); if (type == SPD_CAP_SPELL) sprintf(command, "SET %s CAP_LET_RECOGN spell", who); if (type == SPD_CAP_ICON) sprintf(command, "SET %s CAP_LET_RECOGN icon", who); ret = spd_execute_command(connection, command); return ret; } int spd_set_capital_letters(SPDConnection * connection, SPDCapitalLetters type) { return spd_w_set_capital_letters(connection, type, SPD_SELF); } int spd_set_capital_letters_all(SPDConnection * connection, SPDCapitalLetters type) { return spd_w_set_capital_letters(connection, type, SPD_ALLCLIENTS); } int spd_set_capital_letters_uid(SPDConnection * connection, SPDCapitalLetters type, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_capital_letters(connection, type, who); } // Set functions for Spelling int spd_w_set_spelling(SPDConnection * connection, SPDSpelling type, const char *who) { char command[32]; int ret; if (type == SPD_SPELL_ON) sprintf(command, "SET %s SPELLING on", who); if (type == SPD_SPELL_OFF) sprintf(command, "SET %s SPELLING off", who); ret = spd_execute_command(connection, command); return ret; } int spd_set_spelling(SPDConnection * connection, SPDSpelling type) { return spd_w_set_spelling(connection, type, SPD_SELF); } int spd_set_spelling_all(SPDConnection * connection, SPDSpelling type) { return spd_w_set_spelling(connection, type, SPD_ALLCLIENTS); } int spd_set_spelling_uid(SPDConnection * connection, SPDSpelling type, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_spelling(connection, type, who); } int spd_set_data_mode(SPDConnection * connection, SPDDataMode mode) { char command[32]; int ret; if (mode == SPD_DATA_TEXT) sprintf(command, "SET SELF SSML_MODE off"); if (mode == SPD_DATA_SSML) sprintf(command, "SET SELF SSML_MODE on"); ret = spd_execute_command(connection, command); return ret; } // Set functions for Voice type int spd_w_set_voice_type(SPDConnection * connection, SPDVoiceType type, const char *who) { static char command[64]; switch (type) { case SPD_MALE1: sprintf(command, "SET %s VOICE_TYPE MALE1", who); break; case SPD_MALE2: sprintf(command, "SET %s VOICE_TYPE MALE2", who); break; case SPD_MALE3: sprintf(command, "SET %s VOICE_TYPE MALE3", who); break; case SPD_FEMALE1: sprintf(command, "SET %s VOICE_TYPE FEMALE1", who); break; case SPD_FEMALE2: sprintf(command, "SET %s VOICE_TYPE FEMALE2", who); break; case SPD_FEMALE3: sprintf(command, "SET %s VOICE_TYPE FEMALE3", who); break; case SPD_CHILD_MALE: sprintf(command, "SET %s VOICE_TYPE CHILD_MALE", who); break; case SPD_CHILD_FEMALE: sprintf(command, "SET %s VOICE_TYPE CHILD_FEMALE", who); break; default: return -1; } return spd_execute_command(connection, command); } int spd_set_voice_type(SPDConnection * connection, SPDVoiceType type) { return spd_w_set_voice_type(connection, type, SPD_SELF); } int spd_set_voice_type_all(SPDConnection * connection, SPDVoiceType type) { return spd_w_set_voice_type(connection, type, SPD_ALLCLIENTS); } int spd_set_voice_type_uid(SPDConnection * connection, SPDVoiceType type, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_voice_type(connection, type, who); } // Set function for Voice type SPDVoiceType spd_get_voice_type(SPDConnection * connection) { char *command; SPDVoiceType ret; int err; char *reply = NULL; command = g_strdup_printf("GET voice_type"); spd_execute_command_with_reply(connection, command, &reply); free(command); ret = get_param_int(reply, 1, &err); free(reply); return ret; } static int spd_w_set_command_int(SPDConnection * connection, const char *ssip_name, signed int val, const char *who) { static char command[64]; // NOTE: if any new int ssip_name are added that don't use -100 - 100 as their // range, these values will need to become parameters (or the new ssip_name) // methods will need to call a different helper method. if (val < range_low || val > range_high) return -1; sprintf(command, "SET %s %s %d", who, ssip_name, val); return spd_execute_command(connection, command); } static int spd_get_command_int(SPDConnection * connection, const char *ssip_name) { char *command; int ret = 0; int err; char *reply = NULL; command = g_strdup_printf("GET %s", ssip_name); spd_execute_command_with_reply(connection, command, &reply); free(command); ret = get_param_int(reply, 1, &err); free(reply); return ret; } static int spd_w_set_command_str(SPDConnection * connection, const char *ssip_name, const char *str, const char *who) { char *command; int ret; if (str == NULL) return -1; command = g_strdup_printf("SET %s %s %s", who, ssip_name, str); ret = spd_execute_command(connection, command); free(command); return ret; } static char *spd_get_command_str(SPDConnection * connection, const char *ssip_name) { char *command; char *ret = NULL; int err; char *reply = NULL; command = g_strdup_printf("GET %s", ssip_name); spd_execute_command_with_reply(connection, command, &reply); free(command); ret = get_param_str(reply, 1, &err); free(reply); return ret; } // Set functions for rate int spd_set_voice_rate(SPDConnection * connection, signed int rate) { return spd_w_set_command_int(connection, SPD_RATE, rate, SPD_SELF); } int spd_set_voice_rate_all(SPDConnection * connection, signed int rate) { return spd_w_set_command_int(connection, SPD_RATE, rate, SPD_ALLCLIENTS); } int spd_set_voice_rate_uid(SPDConnection * connection, signed int rate, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_int(connection, SPD_RATE, rate, who); } // Get function for rate int spd_get_voice_rate(SPDConnection * connection) { return spd_get_command_int(connection, SPD_RATE); } // Set functions for pitch int spd_set_voice_pitch(SPDConnection * connection, signed int pitch) { return spd_w_set_command_int(connection, SPD_PITCH, pitch, SPD_SELF); } int spd_set_voice_pitch_all(SPDConnection * connection, signed int pitch) { return spd_w_set_command_int(connection, SPD_PITCH, pitch, SPD_ALLCLIENTS); } int spd_set_voice_pitch_uid(SPDConnection * connection, signed int pitch, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_int(connection, SPD_PITCH, pitch, who); } // Get function for pitch int spd_get_voice_pitch(SPDConnection * connection) { return spd_get_command_int(connection, SPD_PITCH); } // Set functions for pitch_range int spd_set_voice_pitch_range(SPDConnection * connection, signed int pitch_range) { return spd_w_set_command_int(connection, SPD_PITCH_RANGE, pitch_range, SPD_SELF); } int spd_set_voice_pitch_range_all(SPDConnection * connection, signed int pitch_range) { return spd_w_set_command_int(connection, SPD_PITCH, pitch_range, SPD_ALLCLIENTS); } int spd_set_voice_pitch_range_uid(SPDConnection * connection, signed int pitch_range, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_int(connection, SPD_PITCH, pitch_range, who); } // Set functions for volume int spd_set_volume(SPDConnection * connection, signed int volume) { return spd_w_set_command_int(connection, SPD_VOLUME, volume, SPD_SELF); } int spd_set_volume_all(SPDConnection * connection, signed int volume) { return spd_w_set_command_int(connection, SPD_VOLUME, volume, SPD_ALLCLIENTS); } int spd_set_volume_uid(SPDConnection * connection, signed int volume, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_int(connection, SPD_VOLUME, volume, who); } // Get function for volume int spd_get_volume(SPDConnection * connection) { return spd_get_command_int(connection, SPD_VOLUME); } // Set functions for language int spd_set_language(SPDConnection * connection, const char *language) { return spd_w_set_command_str(connection, SPD_LANGUAGE, language, SPD_SELF); } int spd_set_language_all(SPDConnection * connection, const char *language) { return spd_w_set_command_str(connection, SPD_LANGUAGE, language, SPD_ALLCLIENTS); } int spd_set_language_uid(SPDConnection * connection, const char *language, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_str(connection, SPD_LANGUAGE, language, who); } // Get function for language char *spd_get_language(SPDConnection * connection) { return spd_get_command_str(connection, SPD_LANGUAGE); } // Set functions for output_module int spd_set_output_module(SPDConnection * connection, const char *output_module) { return spd_w_set_command_str(connection, SPD_OUTPUT_MODULE, output_module, SPD_SELF); } int spd_set_output_module_all(SPDConnection * connection, const char *output_module) { return spd_w_set_command_str(connection, SPD_OUTPUT_MODULE, output_module, SPD_ALLCLIENTS); } int spd_set_output_module_uid(SPDConnection * connection, const char *output_module, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_str(connection, SPD_OUTPUT_MODULE, output_module, who); } // Get function for output_module char *spd_get_output_module(SPDConnection * connection) { return spd_get_command_str(connection, SPD_OUTPUT_MODULE); } // Set functions for synthesis_voice int spd_set_synthesis_voice(SPDConnection * connection, const char *voice_name) { return spd_w_set_command_str(connection, SPD_SYNTHESIS_VOICE, voice_name, SPD_SELF); } int spd_set_synthesis_voice_all(SPDConnection * connection, const char *voice_name) { return spd_w_set_command_str(connection, SPD_SYNTHESIS_VOICE, voice_name, SPD_ALLCLIENTS); } int spd_set_synthesis_voice_uid(SPDConnection * connection, const char *voice_name, unsigned int uid) { char who[8]; sprintf(who, "%d", uid); return spd_w_set_command_str(connection, SPD_SYNTHESIS_VOICE, voice_name, who); } int spd_set_notification_on(SPDConnection * connection, SPDNotification notification) { if (connection->mode == SPD_MODE_THREADED) return spd_set_notification(connection, notification, "on"); else return -1; } int spd_set_notification_off(SPDConnection * connection, SPDNotification notification) { if (connection->mode == SPD_MODE_THREADED) return spd_set_notification(connection, notification, "off"); else return -1; } #define NOTIFICATION_SET(val, ssip_val) \ if (notification & val){ \ sprintf(command, "SET SELF NOTIFICATION "ssip_val" %s", state);\ ret = spd_execute_command_wo_mutex(connection, command);\ if (ret < 0) RET(-1);\ } int spd_set_notification(SPDConnection * connection, SPDNotification notification, const char *state) { static char command[64]; int ret; if (connection->mode != SPD_MODE_THREADED) return -1; if (state == NULL) { SPD_DBG("Requested state is NULL"); return -1; } if (strcmp(state, "on") && strcmp(state, "off")) { SPD_DBG("Invalid argument for spd_set_notification: %s", state); return -1; } pthread_mutex_lock(&connection->ssip_mutex); NOTIFICATION_SET(SPD_INDEX_MARKS, "index_marks"); NOTIFICATION_SET(SPD_BEGIN, "begin"); NOTIFICATION_SET(SPD_END, "end"); NOTIFICATION_SET(SPD_CANCEL, "cancel"); NOTIFICATION_SET(SPD_PAUSE, "pause"); NOTIFICATION_SET(SPD_RESUME, "resume"); NOTIFICATION_SET(SPD_ALL, "all"); pthread_mutex_unlock(&connection->ssip_mutex); return 0; } #undef NOTIFICATION_SET /* spd_list_modules retrieves information about the available output modules. The return value is a null-terminated array of strings containing output module names. */ char **spd_list_modules(SPDConnection * connection) { char **available_modules; available_modules = spd_execute_command_with_list_reply(connection, "LIST OUTPUT_MODULES"); return available_modules; } void free_spd_modules(char **modules) { int i = 0; while (modules != NULL && modules[i] != NULL) { free(modules[i]); ++i; } free(modules); } char **spd_list_voices(SPDConnection * connection) { char **voices; voices = spd_execute_command_with_list_reply(connection, "LIST VOICES"); return voices; } SPDVoice **spd_list_synthesis_voices(SPDConnection * connection) { char **svoices_str; SPDVoice **svoices; int i, num_items; svoices_str = spd_execute_command_with_list_reply(connection, "LIST SYNTHESIS_VOICES"); if (svoices_str == NULL) return NULL; for (i = 0;; i++) if (svoices_str[i] == NULL) break; num_items = i; svoices = (SPDVoice **) malloc((num_items + 1) * sizeof(SPDVoice *)); for (i = 0; i <= num_items; i++) { const char delimiters[] = "\t"; char *running; if (svoices_str[i] == NULL) break; running = svoices_str[i]; svoices[i] = (SPDVoice *) malloc(sizeof(SPDVoice)); svoices[i]->name = strsep(&running, delimiters); svoices[i]->language = strsep(&running, delimiters); svoices[i]->variant = strsep(&running, delimiters); assert(svoices[i]->name != NULL); } free(svoices_str); svoices[num_items] = NULL; return svoices; } void free_spd_voices(SPDVoice ** voices) { int i = 0; while (voices != NULL && voices[i] != NULL) { free(voices[i]->name); free(voices[i]); ++i; } free(voices); } char **spd_execute_command_with_list_reply(SPDConnection * connection, char *command) { char *reply = NULL; char *line; int err; int max_items = 50; char **result; int i; spd_execute_command_with_reply(connection, command, &reply); if (!ret_ok(reply)) { if (reply != NULL) free(reply); return NULL; } result = malloc((max_items + 1) * sizeof(char *)); for (i = 0;; i++) { line = get_param_str(reply, i + 1, &err); if ((err) || (line == NULL)) break; result[i] = line; if (i >= max_items - 2) { max_items *= 2; result = realloc(result, max_items * sizeof(char *)); } } result[i] = NULL; free(reply); return result; } //int //spd_get_client_list(SPDConnection *connection, char **client_names, int *client_ids, int* active){ // SPD_DBG("spd_get_client_list: History is not yet implemented."); // return -1; // //} int spd_get_message_list_fd(SPDConnection * connection, int target, int *msg_ids, char **client_names) { SPD_DBG("spd_get_client_list: History is not yet implemented."); return -1; #if 0 sprintf(command, "HISTORY GET MESSAGE_LIST %d 0 20\r\n", target); reply = spd_send_data(fd, command, 1); /* header_ok = parse_response_header(reply); if(header_ok != 1){ free(reply); return -1; } */ for (count = 0;; count++) { record = (char *)parse_response_data(reply, count + 1); if (record == NULL) break; record_int = get_rec_int(record, 0); msg_ids[count] = record_int; record_str = (char *)get_rec_str(record, 1); assert(record_str != NULL); client_names[count] = record_str; } return count; #endif } int spd_execute_command(SPDConnection * connection, char *command) { char *reply; int ret; pthread_mutex_lock(&connection->ssip_mutex); ret = spd_execute_command_with_reply(connection, command, &reply); if (ret) { SPD_DBG("Can't execute command in spd_execute_command"); } free(reply); pthread_mutex_unlock(&connection->ssip_mutex); return ret; } int spd_execute_command_wo_mutex(SPDConnection * connection, char *command) { char *reply; int ret; SPD_DBG("Executing command wo_mutex"); ret = spd_execute_command_with_reply(connection, command, &reply); if (ret) SPD_DBG ("Can't execute command in spd_execute_command_wo_mutex"); free(reply); return ret; } int spd_execute_command_with_reply(SPDConnection * connection, char *command, char **reply) { char *buf; int r; SPD_DBG("Inside execute_command_with_reply"); buf = g_strdup_printf("%s\r\n", command); *reply = spd_send_data_wo_mutex(connection, buf, SPD_WAIT_REPLY); free(buf); buf = NULL; if (*reply == NULL) { SPD_DBG ("Can't send data wo mutex in spd_execute_command_with_reply"); return -1; } r = ret_ok(*reply); if (!r) return -1; else return 0; } char *spd_send_data(SPDConnection * connection, const char *message, int wfr) { char *reply; pthread_mutex_lock(&connection->ssip_mutex); if (connection->stream == NULL) RET(NULL); reply = spd_send_data_wo_mutex(connection, message, wfr); if (reply == NULL) { SPD_DBG("Can't send data wo mutex in spd_send_data"); RET(NULL); } pthread_mutex_unlock(&connection->ssip_mutex); return reply; } char *spd_send_data_wo_mutex(SPDConnection * connection, const char *message, int wfr) { char *reply; int bytes; SPD_DBG("Inside spd_send_data_wo_mutex"); if (connection->stream == NULL) return NULL; if (connection->mode == SPD_MODE_THREADED) { /* Make sure we don't get the cond_reply_ready signal before we are in cond_wait() */ pthread_mutex_lock(&connection->td->mutex_reply_ready); } /* write message to the socket */ SPD_DBG("Writing to socket"); if (!write(connection->socket, message, strlen(message))) { SPD_DBG("Can't write to socket: %s", strerror(errno)); if (connection->mode == SPD_MODE_THREADED) pthread_mutex_unlock(&connection->td->mutex_reply_ready); return NULL; } SPD_DBG("Written to socket"); SPD_DBG(">> : |%s|", message); /* read reply to the buffer */ if (wfr) { if (connection->mode == SPD_MODE_THREADED) { /* Wait until the reply is ready */ SPD_DBG ("Waiting for cond_reply_ready in spd_send_data_wo_mutex"); pthread_cond_wait(&connection->td->cond_reply_ready, &connection->td->mutex_reply_ready); SPD_DBG("Condition for cond_reply_ready satisfied"); pthread_mutex_unlock(&connection->td->mutex_reply_ready); SPD_DBG ("Reading the reply in spd_send_data_wo_mutex threaded mode"); /* Read the reply */ if (connection->reply != NULL) { reply = connection->reply; connection->reply = NULL; } else { SPD_DBG ("Error: Can't read reply, broken socket in spd_send_data."); return NULL; } bytes = strlen(reply); if (bytes == 0) { free(reply); SPD_DBG("Error: Empty reply, broken socket."); return NULL; } /* Signal the reply has been read */ pthread_mutex_lock(&connection->td->mutex_reply_ack); pthread_cond_signal(&connection->td->cond_reply_ack); pthread_mutex_unlock(&connection->td->mutex_reply_ack); } else { reply = get_reply(connection); } if (reply != NULL) SPD_DBG("<< : |%s|\n", reply); } else { if (connection->mode == SPD_MODE_THREADED) pthread_mutex_unlock(&connection->td->mutex_reply_ready); SPD_DBG("<< : no reply expected"); return strdup("NO REPLY"); } if (reply == NULL) SPD_DBG ("Reply from get_reply is NULL in spd_send_data_wo_mutex"); SPD_DBG("Returning from spd_send_data_wo_mutex"); return reply; } /* --------------------- Internal functions ------------------------- */ static int spd_set_priority(SPDConnection * connection, SPDPriority priority) { static char p_name[16]; static char command[64]; switch (priority) { case SPD_IMPORTANT: strcpy(p_name, "IMPORTANT"); break; case SPD_MESSAGE: strcpy(p_name, "MESSAGE"); break; case SPD_TEXT: strcpy(p_name, "TEXT"); break; case SPD_NOTIFICATION: strcpy(p_name, "NOTIFICATION"); break; case SPD_PROGRESS: strcpy(p_name, "PROGRESS"); break; default: SPD_DBG("Error: Can't set priority! Incorrect value."); return -1; } sprintf(command, "SET SELF PRIORITY %s", p_name); return spd_execute_command_wo_mutex(connection, command); } static char *get_reply(SPDConnection * connection) { GString *str; char *line = NULL; size_t N = 0; int bytes; char *reply; gboolean errors = FALSE; str = g_string_new(""); /* Wait for activity on the socket, when there is some, read all the message line by line */ do { bytes = getline(&line, &N, connection->stream); if (bytes == -1) { SPD_DBG ("Error: Can't read reply, broken socket in get_reply!"); if (connection->stream != NULL) fclose(connection->stream); connection->stream = NULL; errors = TRUE; } else { g_string_append(str, line); } /* terminate if we reached the last line (without '-' after numcode) */ } while (!errors && !((strlen(line) < 4) || (line[3] == ' '))); free(line); /* getline allocates with malloc. */ if (errors) { /* Free the GString and its character data, and return NULL. */ g_string_free(str, TRUE); reply = NULL; } else { /* The resulting message received from the socket is stored in reply */ reply = str->str; /* Free the GString, but not its character data. */ g_string_free(str, FALSE); } return reply; } static void *spd_events_handler(void *conn) { char *reply; int reply_code; SPDConnection *connection = conn; while (1) { /* Read the reply/event (block if none is available) */ SPD_DBG("Getting reply in spd_events_handler"); reply = get_reply(connection); if (reply == NULL) { SPD_DBG("ERROR: BROKEN SOCKET"); reply_code = -1; } else { SPD_DBG("<< : |%s|\n", reply); reply_code = get_err_code(reply); } if ((reply_code >= 700) && (reply_code < 800)) { int msg_id; int client_id; int err; SPD_DBG("Callback detected: %s", reply); /* This is an index mark */ /* Extract message id */ msg_id = get_param_int(reply, 1, &err); if (err < 0) { SPD_DBG ("Bad reply from Speech Dispatcher: %s (code %d)", reply, err); free(reply); break; } client_id = get_param_int(reply, 2, &err); if (err < 0) { SPD_DBG ("Bad reply from Speech Dispatcher: %s (code %d)", reply, err); free(reply); break; } /* Decide if we want to call a callback */ if ((reply_code == 701) && (connection->callback_begin)) connection->callback_begin(msg_id, client_id, SPD_EVENT_BEGIN); if ((reply_code == 702) && (connection->callback_end)) connection->callback_end(msg_id, client_id, SPD_EVENT_END); if ((reply_code == 703) && (connection->callback_cancel)) connection->callback_cancel(msg_id, client_id, SPD_EVENT_CANCEL); if ((reply_code == 704) && (connection->callback_pause)) connection->callback_pause(msg_id, client_id, SPD_EVENT_PAUSE); if ((reply_code == 705) && (connection->callback_resume)) connection->callback_resume(msg_id, client_id, SPD_EVENT_RESUME); if ((reply_code == 700) && (connection->callback_im)) { char *im; int err; im = get_param_str(reply, 3, &err); if ((err < 0) || (im == NULL)) { SPD_DBG ("Broken reply from Speech Dispatcher: %s", reply); free(reply); break; } /* Call the callback */ connection->callback_im(msg_id, client_id, SPD_EVENT_INDEX_MARK, im); free(im); } free(reply); } else { /* This is a protocol reply */ pthread_mutex_lock(&connection->td->mutex_reply_ready); /* Prepare the reply to the reply buffer in connection */ if (reply != NULL) { connection->reply = reply; } else { SPD_DBG("Connection reply is NULL"); connection->reply = NULL; pthread_mutex_unlock(&connection->td->mutex_reply_ready); break; } /* Signal the reply is available on the condition variable */ /* this order is correct and necessary */ pthread_cond_signal(&connection->td->cond_reply_ready); pthread_mutex_lock(&connection->td->mutex_reply_ack); pthread_mutex_unlock(&connection->td->mutex_reply_ready); /* Wait until it has bean read */ pthread_cond_wait(&connection->td->cond_reply_ack, &connection->td->mutex_reply_ack); pthread_mutex_unlock(&connection->td->mutex_reply_ack); /* Continue */ } } /* In case of broken socket, we must still signal reply ready */ if (connection->reply == NULL) { SPD_DBG("Signalling reply ready after communication failure"); if (connection->stream != NULL) fclose(connection->stream); connection->stream = NULL; pthread_cond_signal(&connection->td->cond_reply_ready); pthread_exit(0); } return 0; /* to please gcc */ } static int ret_ok(char *reply) { int err; if (reply == NULL) return -1; err = get_err_code(reply); if ((err >= 100) && (err < 300)) return 1; if (err >= 300) return 0; SPD_FATAL("Internal error during communication."); } static char *get_param_str(char *reply, int num, int *err) { int i; char *tptr; char *pos; char *pos_begin; char *pos_end; char *rep; assert(err != NULL); if (num < 1) { *err = -1; return NULL; } pos = reply; for (i = 0; i <= num - 2; i++) { pos = strstr(pos, "\r\n"); if (pos == NULL) { *err = -2; return NULL; } pos += 2; } if (strlen(pos) < 4) return NULL; *err = strtol(pos, &tptr, 10); if (*err >= 300 && *err <= 399) return NULL; if ((*tptr != '-') || (tptr != pos + 3)) { *err = -3; return NULL; } pos_begin = pos + 4; pos_end = strstr(pos_begin, "\r\n"); if (pos_end == NULL) { *err = -4; return NULL; } rep = (char *)strndup(pos_begin, pos_end - pos_begin); *err = 0; return rep; } static int get_param_int(char *reply, int num, int *err) { char *rep_str; char *tptr; int ret; rep_str = get_param_str(reply, num, err); if (rep_str == NULL) { /* err is already set to the error return code, just return */ return 0; } ret = strtol(rep_str, &tptr, 10); if (*tptr != '\0') { /* this is not a number */ *err = -3; free(rep_str); return 0; } free(rep_str); return ret; } static int get_err_code(char *reply) { char err_code[4]; int err; if (reply == NULL) return -1; SPD_DBG("spd_send_data: reply: %s\n", reply); err_code[0] = reply[0]; err_code[1] = reply[1]; err_code[2] = reply[2]; err_code[3] = '\0'; SPD_DBG("ret_ok: err_code: |%s|\n", err_code); if (isanum(err_code)) { err = atoi(err_code); } else { SPD_DBG("ret_ok: not a number\n"); return -1; } return err; } /* isanum() tests if the given string is a number, * returns 1 if yes, 0 otherwise. */ static int isanum(char *str) { int i; if (str == NULL) return 0; for (i = 0; i <= strlen(str) - 1; i++) { if (!isdigit(str[i])) return 0; } return 1; } /* * escape_dot: Replace . with .. at the start of lines. * @text: text to escape * @Returns: An allocated string, containing the escaped text. */ static char *escape_dot(const char *text) { size_t orig_len = 0; const char *orig_end; char *result = NULL; char *result_ptr; static const char *ESCAPED_DOTLINE = "\r\n.."; static const size_t ESCAPED_DOTLINELEN = 4; static const size_t DOTLINELEN = 3; if (text == NULL) return NULL; orig_len = strlen(text); orig_end = text + orig_len; result = malloc((orig_len * 2 + 1) * sizeof(char)); if (result == NULL) return NULL; result_ptr = result; /* We're over-allocating. Even if we replaced every character * in text with "..", the length of the escaped string can be no more * than orig_len * 2. We could tighten that upper bound with * a little more work. */ if ((orig_len >= 1) && (text[0] == '.')) { *(result_ptr++) = '.'; *(result_ptr++) = '.'; text += 1; } while (text < orig_end) { if ((text[0] == '\r') && (text[1] == '\n') && (text[2] == '.')) { memcpy(result_ptr, ESCAPED_DOTLINE, ESCAPED_DOTLINELEN); result_ptr += ESCAPED_DOTLINELEN; text += DOTLINELEN; } else { *(result_ptr++) = *(text++); } } *result_ptr = '\0'; return result; } #ifdef LIBSPEECHD_DEBUG static void SPD_DBG(char *format, ...) { va_list args; pthread_mutex_lock(&spd_logging_mutex); va_start(args, format); vfprintf(spd_debug, format, args); va_end(args); fprintf(spd_debug, "\n"); fflush(spd_debug); pthread_mutex_unlock(&spd_logging_mutex); } #else /* LIBSPEECHD_DEBUG */ static void SPD_DBG(char *format, ...) { } #endif /* LIBSPEECHD_DEBUG */ speech-dispatcher-0.9.1/src/api/c/Makefile.in0000644000175000017500000006527713465233610015710 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/api/c ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(spdinclude_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(spdincludedir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libspeechd_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_libspeechd_la_OBJECTS = libspeechd_la-libspeechd.lo libspeechd_la_OBJECTS = $(am_libspeechd_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libspeechd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libspeechd_la_CFLAGS) \ $(CFLAGS) $(libspeechd_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/libspeechd_la-libspeechd.Plo am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libspeechd_la_SOURCES) DIST_SOURCES = $(libspeechd_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(spdinclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ spdinclude_HEADERS = libspeechd.h libspeechd_version.h inc_local = -I$(top_srcdir)/include/ BUILT_SOURCES = libspeechd_version.h lib_LTLIBRARIES = libspeechd.la libspeechd_la_SOURCES = libspeechd.c libspeechd_la_CFLAGS = $(ERROR_CFLAGS) libspeechd_la_CPPFLAGS = $(inc_local) -D_GNU_SOURCE $(GLIB_CFLAGS) -DSPD_SPAWN_CMD=\""$(prefix)/bin/speech-dispatcher"\" libspeechd_la_LDFLAGS = -version-info $(LIB_SPD_CURRENT):$(LIB_SPD_REVISION):$(LIB_SPD_AGE) libspeechd_la_LIBADD = $(GLIB_LIBS) CLEANFILES = libspeechd_version.h EXTRA_DIST = libspeechd_version.h.in edit_version = sed \ -e 's:[@]LIBSPEECHD_MAJOR_VERSION[@]:$(MAJOR_VERSION):' \ -e 's:[@]LIBSPEECHD_MINOR_VERSION[@]:$(MINOR_VERSION):' \ -e 's:[@]LIBSPEECHD_MICRO_VERSION[@]:$(MICRO_VERSION):' all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/api/c/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/api/c/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libspeechd.la: $(libspeechd_la_OBJECTS) $(libspeechd_la_DEPENDENCIES) $(EXTRA_libspeechd_la_DEPENDENCIES) $(AM_V_CCLD)$(libspeechd_la_LINK) -rpath $(libdir) $(libspeechd_la_OBJECTS) $(libspeechd_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libspeechd_la-libspeechd.Plo@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libspeechd_la-libspeechd.lo: libspeechd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libspeechd_la_CPPFLAGS) $(CPPFLAGS) $(libspeechd_la_CFLAGS) $(CFLAGS) -MT libspeechd_la-libspeechd.lo -MD -MP -MF $(DEPDIR)/libspeechd_la-libspeechd.Tpo -c -o libspeechd_la-libspeechd.lo `test -f 'libspeechd.c' || echo '$(srcdir)/'`libspeechd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libspeechd_la-libspeechd.Tpo $(DEPDIR)/libspeechd_la-libspeechd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libspeechd.c' object='libspeechd_la-libspeechd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libspeechd_la_CPPFLAGS) $(CPPFLAGS) $(libspeechd_la_CFLAGS) $(CFLAGS) -c -o libspeechd_la-libspeechd.lo `test -f 'libspeechd.c' || echo '$(srcdir)/'`libspeechd.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-spdincludeHEADERS: $(spdinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(spdinclude_HEADERS)'; test -n "$(spdincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(spdincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(spdincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(spdincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(spdincludedir)" || exit $$?; \ done uninstall-spdincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(spdinclude_HEADERS)'; test -n "$(spdincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(spdincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(spdincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/libspeechd_la-libspeechd.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-spdincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libspeechd_la-libspeechd.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-spdincludeHEADERS .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am \ install-spdincludeHEADERS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \ uninstall-spdincludeHEADERS .PRECIOUS: Makefile libspeechd_version.h: $(srcdir)/libspeechd_version.h.in libspeechd_version.h: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(edit_version) $${srcdir}$@.in > $@ -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/api/c/libspeechd_version.h0000644000175000017500000000207513465234511017647 00000000000000/* * libspeechd_version.h - Shared library for easy access to Speech Dispatcher functions (header) * * Copyright (C) 2001, 2002, 2003, 2004 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1, or (at your option) * any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: libspeechd.h,v 1.29 2008-07-30 09:47:00 hanke Exp $ */ #ifndef _LIBSPEECHD_VERSION_H #define _LIBSPEECHD_VERSION_H #define LIBSPEECHD_MAJOR_VERSION #define LIBSPEECHD_MINOR_VERSION #define LIBSPEECHD_MICRO_VERSION #endif /* ifndef _LIBSPEECHD_VERSION_H */ speech-dispatcher-0.9.1/src/api/c/libspeechd.h0000644000175000017500000002124013406252013016065 00000000000000/* * libspeechd.h - Shared library for easy acces to Speech Dispatcher functions (header) * * Copyright (C) 2001, 2002, 2003, 2004 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1, or (at your option) * any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: libspeechd.h,v 1.29 2008-07-30 09:47:00 hanke Exp $ */ #ifndef _LIBSPEECHD_H #define _LIBSPEECHD_H #include #include #include #include "libspeechd_version.h" #include "speechd_types.h" /* *INDENT-OFF* */ #ifdef __cplusplus extern "C" { #endif /* *INDENT-ON* */ /* Speech Dispatcher's default port for inet communication */ #define SPEECHD_DEFAULT_PORT 6560 /* Arguments for spd_send_data() */ #define SPD_WAIT_REPLY 1 /* Wait for reply */ #define SPD_NO_REPLY 0 /* No reply requested */ /* --------------------- Public data types ------------------------ */ typedef enum { SPD_MODE_SINGLE = 0, SPD_MODE_THREADED = 1 } SPDConnectionMode; typedef enum { SPD_METHOD_UNIX_SOCKET = 0, SPD_METHOD_INET_SOCKET = 1, } SPDConnectionMethod; typedef struct { SPDConnectionMethod method; char *unix_socket_name; char *inet_socket_host; int inet_socket_port; char *dbus_bus; } SPDConnectionAddress; void SPDConnectionAddress__free(SPDConnectionAddress * address); typedef void (*SPDCallback) (size_t msg_id, size_t client_id, SPDNotificationType state); typedef void (*SPDCallbackIM) (size_t msg_id, size_t client_id, SPDNotificationType state, char *index_mark); typedef struct { /* PUBLIC */ SPDCallback callback_begin; SPDCallback callback_end; SPDCallback callback_cancel; SPDCallback callback_pause; SPDCallback callback_resume; SPDCallbackIM callback_im; /* PRIVATE */ int socket; FILE *stream; SPDConnectionMode mode; pthread_mutex_t ssip_mutex; struct SPDConnection_threaddata *td; char *reply; } SPDConnection; /* -------------- Public functions --------------------------*/ /* Opening and closing Speech Dispatcher connection */ SPDConnectionAddress *spd_get_default_address(char **error); SPDConnection *spd_open(const char *client_name, const char *connection_name, const char *user_name, SPDConnectionMode mode); SPDConnection *spd_open2(const char *client_name, const char *connection_name, const char *user_name, SPDConnectionMode mode, SPDConnectionAddress * address, int autospawn, char **error_result); void spd_close(SPDConnection * connection); /* Speaking */ int spd_say(SPDConnection * connection, SPDPriority priority, const char *text); int spd_sayf(SPDConnection * connection, SPDPriority priority, const char *format, ...); /* Speech flow */ int spd_stop(SPDConnection * connection); int spd_stop_all(SPDConnection * connection); int spd_stop_uid(SPDConnection * connection, int target_uid); int spd_cancel(SPDConnection * connection); int spd_cancel_all(SPDConnection * connection); int spd_cancel_uid(SPDConnection * connection, int target_uid); int spd_pause(SPDConnection * connection); int spd_pause_all(SPDConnection * connection); int spd_pause_uid(SPDConnection * connection, int target_uid); int spd_resume(SPDConnection * connection); int spd_resume_all(SPDConnection * connection); int spd_resume_uid(SPDConnection * connection, int target_uid); /* Characters and keys */ int spd_key(SPDConnection * connection, SPDPriority priority, const char *key_name); int spd_char(SPDConnection * connection, SPDPriority priority, const char *character); int spd_wchar(SPDConnection * connection, SPDPriority priority, wchar_t wcharacter); /* Sound icons */ int spd_sound_icon(SPDConnection * connection, SPDPriority priority, const char *icon_name); /* Setting parameters */ int spd_set_voice_type(SPDConnection *, SPDVoiceType type); int spd_set_voice_type_all(SPDConnection *, SPDVoiceType type); int spd_set_voice_type_uid(SPDConnection *, SPDVoiceType type, unsigned int uid); SPDVoiceType spd_get_voice_type(SPDConnection *); int spd_set_synthesis_voice(SPDConnection *, const char *voice_name); int spd_set_synthesis_voice_all(SPDConnection *, const char *voice_name); int spd_set_synthesis_voice_uid(SPDConnection *, const char *voice_name, unsigned int uid); int spd_set_data_mode(SPDConnection * connection, SPDDataMode mode); int spd_set_notification_on(SPDConnection * connection, SPDNotification notification); int spd_set_notification_off(SPDConnection * connection, SPDNotification notification); int spd_set_notification(SPDConnection * connection, SPDNotification notification, const char *state); int spd_set_voice_rate(SPDConnection * connection, signed int rate); int spd_set_voice_rate_all(SPDConnection * connection, signed int rate); int spd_set_voice_rate_uid(SPDConnection * connection, signed int rate, unsigned int uid); int spd_get_voice_rate(SPDConnection * connection); int spd_set_voice_pitch(SPDConnection * connection, signed int pitch); int spd_set_voice_pitch_all(SPDConnection * connection, signed int pitch); int spd_set_voice_pitch_uid(SPDConnection * connection, signed int pitch, unsigned int uid); int spd_get_voice_pitch(SPDConnection * connection); int spd_set_voice_pitch_range(SPDConnection * connection, signed int pitch_range); int spd_set_voice_pitch_range_all(SPDConnection * connection, signed int pitch_range); int spd_set_voice_pitch_range_uid(SPDConnection * connection, signed int pitch_range, unsigned int uid); int spd_set_volume(SPDConnection * connection, signed int volume); int spd_set_volume_all(SPDConnection * connection, signed int volume); int spd_set_volume_uid(SPDConnection * connection, signed int volume, unsigned int uid); int spd_get_volume(SPDConnection * connection); int spd_set_punctuation(SPDConnection * connection, SPDPunctuation type); int spd_set_punctuation_all(SPDConnection * connection, SPDPunctuation type); int spd_set_punctuation_uid(SPDConnection * connection, SPDPunctuation type, unsigned int uid); int spd_set_capital_letters(SPDConnection * connection, SPDCapitalLetters type); int spd_set_capital_letters_all(SPDConnection * connection, SPDCapitalLetters type); int spd_set_capital_letters_uid(SPDConnection * connection, SPDCapitalLetters type, unsigned int uid); int spd_set_spelling(SPDConnection * connection, SPDSpelling type); int spd_set_spelling_all(SPDConnection * connection, SPDSpelling type); int spd_set_spelling_uid(SPDConnection * connection, SPDSpelling type, unsigned int uid); int spd_set_language(SPDConnection * connection, const char *language); int spd_set_language_all(SPDConnection * connection, const char *language); int spd_set_language_uid(SPDConnection * connection, const char *language, unsigned int uid); char *spd_get_language(SPDConnection * connection); int spd_set_output_module(SPDConnection * connection, const char *output_module); int spd_set_output_module_all(SPDConnection * connection, const char *output_module); int spd_set_output_module_uid(SPDConnection * connection, const char *output_module, unsigned int uid); int spd_get_client_list(SPDConnection * connection, char **client_names, int *client_ids, int *active); int spd_get_message_list_fd(SPDConnection * connection, int target, int *msg_ids, char **client_names); char **spd_list_modules(SPDConnection * connection); void free_spd_modules(char **); char *spd_get_output_module(SPDConnection * connection); char **spd_list_voices(SPDConnection * connection); SPDVoice **spd_list_synthesis_voices(SPDConnection * connection); void free_spd_voices(SPDVoice ** voices); char **spd_execute_command_with_list_reply(SPDConnection * connection, char *command); /* Direct SSIP communication */ int spd_execute_command(SPDConnection * connection, char *command); int spd_execute_command_with_reply(SPDConnection * connection, char *command, char **reply); int spd_execute_command_wo_mutex(SPDConnection * connection, char *command); char *spd_send_data(SPDConnection * connection, const char *message, int wfr); char *spd_send_data_wo_mutex(SPDConnection * connection, const char *message, int wfr); /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* __cplusplus */ /* *INDENT-ON* */ #endif /* ifndef _LIBSPEECHD_H */ speech-dispatcher-0.9.1/src/api/c/Makefile.am0000644000175000017500000000325113406252000015644 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in spdinclude_HEADERS = libspeechd.h libspeechd_version.h inc_local = -I$(top_srcdir)/include/ BUILT_SOURCES = libspeechd_version.h lib_LTLIBRARIES = libspeechd.la libspeechd_la_SOURCES = libspeechd.c libspeechd_la_CFLAGS = $(ERROR_CFLAGS) libspeechd_la_CPPFLAGS = $(inc_local) -D_GNU_SOURCE $(GLIB_CFLAGS) -DSPD_SPAWN_CMD=\""$(prefix)/bin/speech-dispatcher"\" libspeechd_la_LDFLAGS = -version-info $(LIB_SPD_CURRENT):$(LIB_SPD_REVISION):$(LIB_SPD_AGE) libspeechd_la_LIBADD = $(GLIB_LIBS) libspeechd_version.h: $(srcdir)/libspeechd_version.h.in CLEANFILES = libspeechd_version.h EXTRA_DIST = libspeechd_version.h.in libspeechd_version.h: Makefile rm -f $@ srcdir=; \ test -f ./$@.in || srcdir=$(srcdir)/; \ $(edit_version) $${srcdir}$@.in > $@ edit_version = sed \ -e 's:[@]LIBSPEECHD_MAJOR_VERSION[@]:$(MAJOR_VERSION):' \ -e 's:[@]LIBSPEECHD_MINOR_VERSION[@]:$(MINOR_VERSION):' \ -e 's:[@]LIBSPEECHD_MICRO_VERSION[@]:$(MICRO_VERSION):' -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/api/guile/0000755000175000017500000000000013424443423014565 500000000000000speech-dispatcher-0.9.1/src/api/guile/README0000644000175000017500000000212713424443423015367 00000000000000This is a Guile interface to SSIP. It is in an experimental state now and is expected to be significantly reworked before first official release. To compile it, run `make'. libspeechd and guile libraries and headers files must be installed to get compiled the C part of the interface. If you have any questions, suggestions, etc., feel free to contact us at the mailing list . -- Milan Zamazal Copyright (C) 2004-2007 Brailcom, o.p.s This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/api/guile/gssip.c0000644000175000017500000002362713406252116016005 00000000000000/* SSIP Guile interface */ /* Copyright (C) 2004 Brailcom, o.p.s. Author: Milan Zamazal COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include "gssip.h" #define ASSIGN_VAR(var, pos, checker, setter) \ SCM_ASSERT (SCM_##checker##P (var), var, SCM_ARG##pos, FUNC_NAME); \ c_##var = SCM_##setter (var) #define ASSIGN_INT(var, pos) ASSIGN_VAR (var, pos, INUM, INUM) #define ASSIGN_STRING(var, pos) ASSIGN_VAR (var, pos, STRING, STRING_CHARS) #define ASSIGN_SYMBOL(var, pos) ASSIGN_VAR (var, pos, SYMBOL, SYMBOL_CHARS) #define ASSIGN_CONNECTION() ASSIGN_INT (connection, 1); #define ASSIGN_PRIORITY() c_priority = assign_priority (priority, FUNC_NAME) #define RETURN_SUCCESS(value) return ((value) ? SCM_BOOL_F : SCM_BOOL_T) static SPDPriority assign_priority(SCM priority, const char *func_name) { char *c_priority; SCM_ASSERT(SCM_SYMBOLP(priority), priority, SCM_ARG3, func_name); c_priority = SCM_SYMBOL_CHARS(priority); { const int invalid_priority = -1000; int int_priority = ((!strcmp(c_priority, "important")) ? SPD_IMPORTANT : (!strcmp(c_priority, "message")) ? SPD_MESSAGE : (!strcmp(c_priority, "text")) ? SPD_TEXT : (!strcmp(c_priority, "notification")) ? SPD_NOTIFICATION : (!strcmp(c_priority, "progress")) ? SPD_PROGRESS : invalid_priority); if (int_priority == invalid_priority) scm_wrong_type_arg(func_name, SCM_ARG3, priority); return int_priority; } } /* SSIP connection opening/closing functions */ SCM_DEFINE(ssip_open, "%ssip-open", 3, 0, 0, (SCM user, SCM client, SCM component), "Open new SSIP connection and return its identifier.") #define FUNC_NAME s_ssip_open { char *c_user, *c_client, *c_component; ASSIGN_STRING(user, 1); ASSIGN_STRING(client, 2); ASSIGN_STRING(component, 3); { int connection = spd_open(c_client, c_component, c_user); return (connection ? SCM_MAKINUM(connection) : SCM_EOL); } } #undef FUNC_NAME SCM_DEFINE(ssip_close, "%ssip-close", 1, 0, 0, (SCM connection), "Close the given SSIP connection.") #define FUNC_NAME s_ssip_close { int c_connection; ASSIGN_CONNECTION(); spd_close(c_connection); return SCM_UNSPECIFIED; } #undef FUNC_NAME /* Speech output functions */ #define SSIP_OUTPUT_DECL(name, sname) \ SCM_DEFINE (ssip_say_##name, "%ssip-say-" sname, 3, 0, 0, \ (SCM connection, SCM text, SCM priority), \ "Say " sname " on CONNECTION with PRIORITY and return whether it succeeded.") #define SSIP_OUTPUT_BODY(spd_func) \ { \ int c_connection; \ char *c_text; \ SPDPriority c_priority; \ ASSIGN_CONNECTION (); \ ASSIGN_STRING (text, 2); \ ASSIGN_PRIORITY (); \ RETURN_SUCCESS (spd_func (c_connection, c_priority, c_text)); \ } #define FUNC_NAME s_ssip_say_text SSIP_OUTPUT_DECL(text, "text") SSIP_OUTPUT_BODY(spd_say) #undef FUNC_NAME #define FUNC_NAME s_ssip_say_character SSIP_OUTPUT_DECL(character, "character") SSIP_OUTPUT_BODY(spd_char) #undef FUNC_NAME #define FUNC_NAME s_ssip_say_key SSIP_OUTPUT_DECL(key, "key") SSIP_OUTPUT_BODY(spd_key) #undef FUNC_NAME #define FUNC_NAME s_ssip_say_icon SSIP_OUTPUT_DECL(icon, "icon") SSIP_OUTPUT_BODY(spd_sound_icon) #undef FUNC_NAME /* Speech output management functions */ #define SSIP_CONTROL_DECL(name, sname) \ SCM_DEFINE (ssip_##name, "%ssip-" sname, 2, 0, 0, \ (SCM connection, SCM id), \ sname "speaking and return whether it succeeded.") #define SSIP_CONTROL_BODY(name) \ { \ int c_connection; \ int result_code; \ ASSIGN_CONNECTION (); \ if (SCM_INUMP (id)) \ result_code = spd_stop_uid (c_connection, SCM_INUM (id)); \ else if (id == SCM_EOL) \ result_code = spd_stop (c_connection); \ else if (SCM_SYMBOLP (id) \ && (! strcmp (SCM_SYMBOL_CHARS (id), "t"))) \ result_code = spd_stop_all (c_connection); \ else \ scm_wrong_type_arg (FUNC_NAME, SCM_ARG2, id); \ RETURN_SUCCESS (result_code); \ } #define FUNC_NAME s_ssip_stop SSIP_CONTROL_DECL(stop, "stop") SSIP_CONTROL_BODY(stop) #undef FUNC_NAME #define FUNC_NAME s_ssip_cancel SSIP_CONTROL_DECL(cancel, "cancel") SSIP_CONTROL_BODY(cancel) #undef FUNC_NAME #define FUNC_NAME s_ssip_pause SSIP_CONTROL_DECL(pause, "pause") SSIP_CONTROL_BODY(pause) #undef FUNC_NAME #define FUNC_NAME s_ssip_resume SSIP_CONTROL_DECL(resume, "resume") SSIP_CONTROL_BODY(resume) #undef FUNC_NAME /* Speech parameters functions */ #define SSIP_SET_DECL(name, sname) \ SCM_DEFINE (ssip_set_##name, "%ssip-set-" sname, 2, 0, 0, \ (SCM connection, SCM value), \ "Set " sname " for CONNECTION.") #define SSIP_PROCESS_SET_ARGS(type, type_f) \ int c_connection; \ type c_value; \ ASSIGN_CONNECTION (); \ ASSIGN_##type_f (value, 2); #define SSIP_SET_STRING_BODY(name) \ { \ SSIP_PROCESS_SET_ARGS (char *, STRING); \ RETURN_SUCCESS (spd_set_##name (c_connection, c_value)); \ } #define SSIP_SET_INT_BODY(name) \ { \ SSIP_PROCESS_SET_ARGS (int, INT); \ SCM_ASSERT ((-100 <= c_value && c_value <= 100), value, SCM_ARG2, \ FUNC_NAME); \ RETURN_SUCCESS (spd_set_##name (c_connection, c_value)); \ } #define FUNC_NAME s_ssip_set_language SSIP_SET_DECL(language, "language") SSIP_SET_STRING_BODY(language) #undef FUNC_NAME #define FUNC_NAME s_ssip_set_output_module SSIP_SET_DECL(output_module, "output-module") SSIP_SET_STRING_BODY(output_module) #undef FUNC_NAME #define FUNC_NAME s_ssip_set_rate SSIP_SET_DECL(rate, "rate") SSIP_SET_INT_BODY(voice_rate) #undef FUNC_NAME #define FUNC_NAME s_ssip_set_pitch SSIP_SET_DECL(pitch, "pitch") SSIP_SET_INT_BODY(voice_pitch) #undef FUNC_NAME #define FUNC_NAME s_ssip_set_pitch_range SSIP_SET_DECL(pitch_range, "pitch_range") SSIP_SET_INT_BODY(voice_pitch_range) #undef FUNC_NAME #define FUNC_NAME s_ssip_set_volume SSIP_SET_DECL(volume, "volume") SSIP_SET_INT_BODY(volume) #undef FUNC_NAME #define FUNC_NAME s_ssip_set_voice SSIP_SET_DECL(voice, "voice") { SSIP_PROCESS_SET_ARGS(char *, STRING); { char *command; int result_code; if (asprintf(&command, "SET self VOICE %s", c_value) < 0) scm_memory_error(FUNC_NAME); result_code = spd_execute_command(c_connection, command); free(command); RETURN_SUCCESS(result_code); } } #undef FUNC_NAME #define FUNC_NAME s_ssip_set_punctuation_mode SSIP_SET_DECL(punctuation_mode, "punctuation-mode") { SSIP_PROCESS_SET_ARGS(char *, SYMBOL); { SPDPunctuation mode; if (!strcmp(c_value, "none")) mode = SPD_PUNCT_NONE; else if (!strcmp(c_value, "some")) mode = SPD_PUNCT_SOME; else if (!strcmp(c_value, "all")) mode = SPD_PUNCT_ALL; else scm_wrong_type_arg(FUNC_NAME, SCM_ARG2, value); RETURN_SUCCESS(spd_set_punctuation(c_connection, mode)); } } #undef FUNC_NAME #define FUNC_NAME s_ssip_set_spelling_mode SSIP_SET_DECL(spelling_mode, "spelling-mode") { SSIP_PROCESS_SET_ARGS(char *, SYMBOL); { SPDSpelling mode; if (!strcmp(c_value, "on")) mode = SPD_SPELL_ON; else if (!strcmp(c_value, "off")) mode = SPD_SPELL_OFF; else scm_wrong_type_arg(FUNC_NAME, SCM_ARG2, value); RETURN_SUCCESS(spd_set_spelling(c_connection, mode)); } } #undef FUNC_NAME /* Raw SSIP commands */ SCM_DEFINE(ssip_raw_command, "%ssip-raw-command", 2, 0, 0, (SCM connection, SCM command), "Send raw COMMAND to CONNECTION and return whether it succeeded.") #define FUNC_NAME s_ssip_raw_command { int c_connection; char *c_command; ASSIGN_CONNECTION(); ASSIGN_STRING(command, 2); RETURN_SUCCESS(spd_execute_command(c_connection, c_command)); } #undef FUNC_NAME /* Define the Scheme bindings */ void init_gssip() { #include "gssip.x" } speech-dispatcher-0.9.1/src/api/guile/Makefile0000644000175000017500000000323013406252077016146 00000000000000# Makefile for speechd-guile # Copyright (C) 2004 Brailcom, o.p.s. # # Author: Milan Zamazal # # COPYRIGHT NOTICE # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . prefix = /usr/local INSTALL_PATH = $(prefix)/share/guile/site CC = gcc CFLAGS = -g -Wall INSTALL_PROGRAM = install -m 755 INSTALL_DATA = install -m 644 PROGRAM = gssip .PHONY: all install install-strip uninstall clean distclean mostlyclean \ maintainer-clean TAGS info dvi dist check all: $(PROGRAM).so $(PROGRAM).scm $(PROGRAM).so: $(PROGRAM).c $(PROGRAM).x $(PROGRAM).h $(CC) $(CFLAGS) -shared -fPIC -o $@ $(PROGRAM).c -lguile -lspeechd %.x: %.c guile-snarf -o $@ $< %.scm: %.scm.in sed 's/%%path%%/$(subst /,\/,$(INSTALL_PATH))/' $< > $@ install: all mkdir -p $(INSTALL_PATH) $(INSTALL_PROGRAM) $(PROGRAM).so $(INSTALL_PATH) $(INSTALL_DATA) $(PROGRAM).scm $(INSTALL_PATH) install-strip: $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install uninstall: mostlyclean: rm -f *.scm *.so *.x clean: mostlyclean distclean: clean maintainer-clean: distclean TAGS: info: dvi: dist: check: speech-dispatcher-0.9.1/src/api/guile/gssip.scm.in0000644000175000017500000000524113406264224016745 00000000000000;;; SSIP interface ;; Copyright (C) 2004 Brailcom, o.p.s. ;; Author: Milan Zamazal ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ;; for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . (load-extension "%%path%%/gssip" "init_gssip") (define (ssip-open host port user client component) (%ssip-open user client component)) (define (ssip-close connection) (%ssip-close connection)) (define (ssip-say-text connection text priority) (%ssip-say-text connection text priority)) (define (ssip-say-character connection character priority) (%ssip-say-character connection character priority)) (define (ssip-say-key connection key priority) (%ssip-say-key connection key priority)) (define (ssip-say-icon connection sound priority) (%ssip-say-icon connection sound priority)) (define (ssip-stop connection id) (%ssip-stop connection id)) (define (ssip-cancel connection id) (%ssip-cancel connection id)) (define (ssip-pause connection id) (%ssip-pause connection id)) (define (ssip-resume connection id) (%ssip-resume connection id)) (define (ssip-set-language connection language) (%ssip-set-language connection language)) (define (ssip-set-output-module connection output-module) (%ssip-set-output-module connection output-module)) (define (ssip-set-rate connection rate) (%ssip-set-rate connection rate)) (define (ssip-set-pitch connection pitch) (%ssip-set-pitch connection pitch)) (define (ssip-set-pitch-range connection pitch_range) (%ssip-set-pitch-range connection pitch-range)) (define (ssip-set-volume connection volume) (%ssip-set-volume connection volume)) (define (ssip-set-voice connection voice) (%ssip-set-voice connection voice)) (define (ssip-set-punctuation-mode connection mode) (%ssip-set-punctuation-mode connection mode)) (define (ssip-set-spelling-mode connection mode) (%ssip-set-spelling-mode connection mode)) (define (ssip-block connection priority function) (%ssip-say-text connection "" priority) (%ssip-raw-command connection "BLOCK BEGIN") (catch #t (function) (lambda (key . args))) (%ssip-raw-command connection "BLOCK END")) (provide 'gssip) speech-dispatcher-0.9.1/src/api/guile/gssip.h0000644000175000017500000000152413423333245016004 00000000000000/* SSIP Guile support */ /* Copyright (C) 2004 Brailcom, o.p.s. Author: Milan Zamazal COPYRIGHT NOTICE This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef __GSSIP_H #define __GSSIP_H void init_gssip(); #endif speech-dispatcher-0.9.1/src/api/cl/0000755000175000017500000000000013424443421014054 500000000000000speech-dispatcher-0.9.1/src/api/cl/README0000644000175000017500000000237013424443421014656 00000000000000This is a simple Common Lisp interface to Speech Dispatcher through the Speech Synthesis Interface Protocol (SSIP). Currently, there is no documentation, read the sources. The simplest use can be as follows: (asdf:operate-on-system 'asdf:load-op :ssip) (ssip:say-text "Hello, world!") It works with CLisp and SBCL, but it should be easy to port to other systems, just add the support to sysdep.lisp. Feel free to contact us with any questions regarding the Common Lisp interface at the Speech Dispatcher mailing list . -- Milan Zamazal Copyright (C) 2004-2006 Brailcom, o.p.s This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/api/cl/configuration.lisp0000644000175000017500000000447713406252036017550 00000000000000;;; Configuration variables ;; Author: Milan Zamazal ;; Copyright (C) 2004 Brailcom, o.p.s. ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as published by ;; the Free Software Foundation; either version 2.1 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 Lesser General Public License ;; for more details. ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program. If not, see . (in-package :ssip) (defvar *host* "localhost" "Name of the default host running speechd to connect to.") (defvar *port* (or (ignore-errors (car (read-from-string (getenv "SPEECHD_PORT")))) 6560) "Default port of speechd.") (defvar *default-text-priority* :text "Default Speech Dispatcher priority of sent texts.") (defvar *default-sound-priority* :message "Default Speech Dispatcher priority of sent sound icons.") (defvar *default-char-priority* :notification "Default Speech Dispatcher priority of sent single letters.") (defvar *connection-parameters* '() "Alist of connection names and their parameters. Each element of the list is of the form (CONNECTION-NAME . PARAMETERS), where CONNECTION-NAME is a connection name as expected to be in `speechd-client-name' and PARAMETERS is a property list with the pairs of parameter identifiers and parameter values. Valid parameter names are the following symbols: language, message-priority, punctuation-mode, capital-character-mode, voice, rate, pitch, pitch_range, output-module. See the corresponding speechd-set-* functions for valid parameter values. If the symbol t is specified as the connection name, the element defines default connection parameters if no connection specification applies. Only one such an element is allowed in the whole alist. The message-priority parameter has a special meaning: It overrides priority of all messages sent through the connection. You must reopen the connections to apply the changes to this variable.") speech-dispatcher-0.9.1/src/api/cl/ssip.lisp0000644000175000017500000005245113406252062015651 00000000000000;;; Speech Synthesis Interface Protocol (SSIP) interface ;; Author: Milan Zamazal ;; Copyright (C) 2004 Brailcom, o.p.s. ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as published by ;; the Free Software Foundation; either version 2.1 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 Lesser General Public License ;; for more details. ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program. If not, see . ;;; Note: This library was ported from the Elisp library, so don't wonder much ;;; about elispisms found here... (in-package :ssip) ;;; Exported variables (defvar *application-name* "lisp" "String defining current application name.") (defvar *client-name* "default" "String defining current client name. This variable's value defines which connection is used when communicating via SSIP, each connection has its own client name. Usually, you select the proper client (connection) by assigning a value to this variable locally through `let'.") (defvar *language* nil "If non-nil, it is an RFC 1766 language code, as a string. If text is read and this variable is non-nil, the text is read in the given language.") (defvar *spell* nil "If non-nil, any spoken text is spelled.") ;;; Internal constants and configuration variables (defparameter +version+ "$Id: ssip.lisp,v 1.3 2006-02-17 13:18:55 pdm Exp $" "Version stamp of the source file. Useful only for diagnosing problems.") (defvar *language-codes* '(("czech" . "cs") ("english" . "en") ("french" . "fr") ("german" . "de")) "Mapping of LANG values to language ISO codes.") (defvar *default-voice* "male1") (defvar *default-language* (or (cdr (assoc (getenv "LANG") *language-codes* :test #'string=)) "en")) (defparameter +parameter-names+ '((client-name . "CLIENT_NAME") (language . "LANGUAGE") (message-priority . "PRIORITY") (punctuation-mode . "PUNCTUATION") (pause-context . "PAUSE_CONTEXT") (capital-character-mode . "CAP_LET_RECOGN") (voice . "VOICE") (rate . "RATE") (pitch . "PITCH") (pitch_range . "PITCH_RANGE") (spelling-mode . "SPELLING") (output-module . "OUTPUT_MODULE") )) (defparameter +list-parameter-names+ '((voices . "VOICES"))) (defparameter +parameter-value-mappings+ '((message-priority (:important . "IMPORTANT") (:message . "MESSAGE") (:text . "TEXT") (:notification . "NOTIFICATION") (:progress . "PROGRESS") ) (punctuation-mode (:none . "none") (:some . "some") (:all . "all")) (capital-character-mode (:none . "none") (:spell . "spell") (:icon . "icon")) (spelling-mode (t . "on") (nil . "off")))) (defparameter +volatile-parameters+ '(output-module)) (defparameter +punctuation-modes+ '(("none" . none) ("some" . some) ("all" . all))) (defparameter +capital-character-modes+ '(("none" . none) ("spell" . spell) ("icon" . icon))) ;;; Internal variables (defstruct connection name host port (failure-p nil) stream (paused-p nil) (in-block nil) (transaction-state nil) (parameters ()) (forced-priority nil) (last-command nil)) (defstruct request string (transaction-state '(nil nil))) (defvar *connections* (make-hash-table :test #'equal) "Hash table mapping client names to `connection' instances.") (defvar *connection* nil "Current connection.") ;;; Utilities (defmacro iterate-clients (&rest body) `(maphash #'(lambda (*client-name* _) (declare (ignore _)) ,@body) *connections*)) (defmacro iterate-connections (&rest body) `(maphash #'(lambda (_ *connection*) (declare (ignore _)) ,@body) *connections*)) (defun connection-names () "Return the list of all present connection names." (let ((names '())) (iterate-clients (push *client-name* names)) names)) (defmacro with-current-connection (&rest body) `(let ((*connection* (get-connection))) ,@body)) (defmacro with-connection-setting (var value &rest body) (let ((accessor (intern (concat "CONNECTION-" (symbol-name var)))) (orig-value (gensym))) `(let ((,orig-value (,accessor *connection*))) (setf (,accessor *connection*) ,value) (unwind-protect (progn ,@body) (setf (,accessor *connection*) ,orig-value))))) (defmacro with-connection-parameters (parameters &rest body) (let (($parameters (gensym)) ($orig-parameters (gensym)) ($cparameters (gensym)) ($p (gensym)) ($v (gensym)) ($orig-v (gensym)) ($pv (gensym))) `(let* ((,$parameters ,parameters) (,$orig-parameters ())) (unwind-protect (progn (while ,$parameters (let* ((,$p (first ,$parameters)) (,$v (second ,$parameters)) (,$cparameters (connection-parameters *connection*)) (,$orig-v (plist-get ,$cparameters ,$p))) (when (and (not (equal ,$v ,$orig-v)) (or ,$v (not (member ,$p '(language))))) (when (plist-member ,$cparameters ,$p) (push (cons ,$p ,$orig-v) ,$orig-parameters)) (set-parameter ,$p ,$v))) (setq ,$parameters (nthcdr 2 ,$parameters))) ,@body) (dolist (,$pv ,$orig-parameters) (set-parameter (car ,$pv) (cdr ,$pv))))))) ;;; Process management functions (defun get-connection (&optional (name *client-name*) (create-if-needed t)) (or (gethash name *connections*) (and create-if-needed (let ((*client-name* name)) (open-connection))))) (defun close-connection-stream (connection) (let ((stream (connection-stream connection))) (when stream (ignore-errors (close-network-stream stream))) (setf (connection-stream connection) nil))) (defun open-connection (&optional host port &key quiet force-reopen) "Open SSIP connection to given HOST and PORT. If the connection corresponding to the current `*client-name*' value already exists, close it and reopen again, with the same connection parameters. The optional arguments HOST and PORT identify the speechd server location differing from the values of `speechd-host' and `speechd-port'. If the key argument QUIET is non-nil, don't report failures and quit silently. If the key argument FORCE-REOPEN is non-nil, try to reopen an existent connection even if it previously failed. Return the opened connection on success, nil otherwise." (let ((connection (gethash *client-name* *connections*))) (let ((host (or host *host*)) (port (or port *port*))) (when connection (close-connection connection) (setq host (connection-host connection) port (connection-port connection))) (let* ((name *client-name*) (default-parameters (append (cdr (assoc *client-name* *connection-parameters* :test #'string=)) (cdr (assoc t *connection-parameters*)))) (parameters (if connection (append (connection-parameters connection) default-parameters) default-parameters)) (stream (when (or (not connection) (not (connection-failure-p connection)) force-reopen) (ignore-errors (open-network-stream host port))))) (when (and (not stream) (not quiet)) (error "Connection to SSIP failed")) (setq connection (make-connection :name name :host host :port port :stream stream :failure-p (not stream))) (setf (gethash name *connections*) connection) (when stream (set-connection-name name) (setq parameters (append parameters (list 'language *default-language* 'voice *default-voice*))) (let ((already-set '(client-name))) (while parameters (destructuring-bind (parameter value . next) parameters (unless (member parameter already-set) (push parameter already-set) (set-parameter parameter value)) (setq parameters next))))) (let ((priority (and connection (plist-get default-parameters 'message-priority)))) (when priority (set-parameter 'message-priority priority) (setf (connection-forced-priority connection) t))))) connection)) (defun close-connection (&optional (name *client-name*)) "Close speechd connection named NAME." (let ((connection (get-connection name nil))) (when connection (close-connection-stream connection) (remhash name *connections*)))) (defun reopen-connection () "Close and open again all the connections to speechd." (iterate-clients (open-connection :quiet t :force-reopen t))) (defun running-p () "Return non-nil, if the current speechd client name process is running." (let ((connection (get-connection))) (and connection (connection-stream connection)))) ;;; Process communication functions (defun permanent-connection-failure (connection) (close-connection-stream connection) (setf (connection-failure-p connection) t (connection-paused-p connection) nil (connection-transaction-state connection) nil (connection-parameters connection) ())) (defun send-string (string) (with-current-connection (let ((stream (connection-stream *connection*))) (when stream (unwind-protect (format stream "~A" string) (when (not (running-p)) (permanent-connection-failure *connection*))))))) (defun process-request (request) (with-current-connection ;; Ensure proper transaction state (let* ((state-spec (request-transaction-state request)) (required-state (first state-spec)) (new-state (second state-spec))) (labels ((check-state (reopen-if-needed) (let ((current-state (connection-transaction-state *connection*))) (when (and (not (eq current-state required-state)) (not (eq current-state new-state))) (cond ((and (eq required-state 'in-data) (not (eq new-state nil))) (send-data-begin)) ((eq required-state nil) (send-data-end)))) (setq current-state (connection-transaction-state *connection*)) (if (and reopen-if-needed (not (eq current-state required-state)) (not (eq current-state new-state)) (not (connection-failure-p *connection*))) (progn (open-connection) (setq *connection* (get-connection)) (check-state nil)) (eq current-state required-state))))) ;; Continue only if the state can be set properly after reopen, ;; otherwise give up and ignore the request completely. ;; This also works for the "." command when in non-data state. (when (check-state t) (send-string (request-string request)) ;; Read command answer (unless (equal state-spec '(in-data in-data)) (destructuring-bind (answer-line . data-lines) (loop with stream = (connection-stream *connection*) for line = (read-line stream) for lines = (list line) then (cons line lines) while (and (> (length line) 3) (char= (char line 3) #\-)) finally (return lines)) (let* ((code (subseq answer-line 0 3)) (answer (subseq answer-line 4)) (success (member (char code 0) '(#\1 #\2))) (data (and success (mapcar #'(lambda (line) (subseq line 4)) data-lines)))) (when success (setf (connection-transaction-state *connection*) new-state)) (list success data code answer))))))))) (defun send-request (request) (with-current-connection (process-request request))) (defparameter +block-commands+ '(("speak") ("sound_icon") ("char") ("key") ("quit") ("block" ("end")) ("set" ("self" ("rate" "pitch" "pitch_range" "voice" "language"))))) (defun block-command-p (command &optional allowed) (unless allowed (setq allowed +block-commands+)) (let* ((match (assoc (first command) allowed :test #'string-equal)) (rest-allowed (cdr match))) (and match (or (not rest-allowed) (block-command-p (rest command) rest-allowed))))) (defun send-command (command &optional (transaction-state '(nil nil))) (unless (listp command) (setq command (list command))) (with-current-connection (setf (connection-last-command *connection*) command) (when (or (not (connection-in-block *connection*)) (block-command-p command)) (send-request (make-request :string (format nil "~{~A~^ ~}~A~A" command #\Return #\Linefeed) :transaction-state transaction-state))))) (defun send-data-begin () (send-command "SPEAK" '(nil in-data))) (defun send-data (text) (let ((text* text)) (flet ((send (string) (unless (string= string "") (send-request (make-request :string string :transaction-state '(in-data in-data)))))) (loop with eol = (format nil "~A~A" #\Return #\Linefeed) for length = (length text*) for nlpos = (or (position #\Linefeed text*) length) for dotted = (and (> (length text*) 0) (char= (char text* 0) #\.)) until (string= text* "") do (progn (when dotted (send ".")) (send (subseq text* 0 nlpos)) (send eol) (setq text* (subseq text* (min (1+ nlpos) length)))))))) (defun send-data-end () (send-command "." '(in-data nil))) ;;; Value retrieval functions (defun list-values (parameter) (second (send-command (list "LIST" (cdr (assoc parameter +list-parameter-names+)))))) ;;; Parameter setting functions (defun convert-numeric (number) (cond ((< number -100) -100) ((> number 100) 100) (t number))) (defun transform-parameter-value (parameter value) (cond ((stringp value) value) ((integerp value) (format nil "~D" (convert-numeric value))) ((symbolp value) (cdr (assoc value (cdr (assoc parameter +parameter-value-mappings+))))))) (defun set-parameter (parameter value) (with-current-connection (let* ((plist (connection-parameters *connection*)) (orig-value (if (plist-member plist parameter) (plist-get plist parameter) 'unknown))) (when (or (member parameter +volatile-parameters+) (and (not (equal orig-value value)) (or (not (eq parameter 'message-priority)) (not (connection-forced-priority *connection*))))) (let ((answer (send-command (let ((p (cdr (assoc parameter +parameter-names+))) (v (transform-parameter-value parameter value))) (unless p (error "Invalid parameter name: `~A'" parameter)) (unless v (error "Invalid parameter value: ~A=~A" parameter value)) (list "SET" "self" p v))))) (setq *connection* (get-connection)) (when (first answer) (setf (connection-parameters *connection*) (plist-put (connection-parameters *connection*) parameter value)))))))) (defun set-connection-name (name) (set-parameter 'client-name (format nil "~A:~A:~A" (user-login-name) *application-name* name))) (defun set-language (language) "Set language of the current client connection to LANGUAGE. Language must be an RFC 1766 language code, as a string." (set-parameter 'language language) (setq *language* language)) ;;; Blocks (defmacro with-block (parameters &rest body) "Set PARAMETERS and enclose BODY by an SSIP block. Before invoking BODY, the BLOCK BEGIN command is sent, and the BLOCK END command is sent afterwards. PARAMETERS is a property list defining parameters to be set before sending the BLOCK BEGIN command. The property-value pairs correspond to the arguments of the `set-parameter' function." `(with-current-connection (with-connection-parameters ,parameters (if (and *connection* (connection-in-block *connection*)) (progn ,@body) (let ((block-connection *connection*)) (send-command '("BLOCK BEGIN")) (unwind-protect (progn (with-current-connection (when *connection* (setf (connection-in-block *connection*) t))) ,@body) (let ((*connection* block-connection)) (when *connection* (setf (connection-in-block *connection*) nil) (let ((*client-name* (connection-name *connection*))) (send-command '("BLOCK END"))))))))))) ;;; Speaking functions (defun say-text (text &key (priority *default-text-priority*)) "Speak the given TEXT, represented by a string. The key argument `priority' defines the priority of the message and must be one of the symbols `important', `message', `text', `notification' or `progress'." (set-parameter 'message-priority priority) (unless (string= text "") (send-data-begin) (send-data text) (send-data-end))) (defun say-sound (name &key (priority *default-sound-priority*)) "Play an auditory icon. NAME is the name of the icon, any string acceptable by speechd. The key argument `priority' defines the priority of the message and must be one of the symbols `important', `message', `text', `notification' or `progress'." (set-parameter 'message-priority priority) (send-command (list "SOUND_ICON" name))) (defun say-char (char &key (priority *default-char-priority*)) "Speak the given CHAR, any UTF-8 character. The key argument `priority' defines the priority of the message and must be one of the symbols `important', `message', `text', `notification' or `progress'." (set-parameter 'message-priority priority) (with-current-connection (with-connection-parameters `(language ,*language*) (send-command (list "CHAR" (format nil "~A" (case char (? "space") (?\n "linefeed") (t (format nil "~A" char))))))))) ;;; Control functions (defun control-command (command all &optional repeatable) (cond ((not all) (when (or repeatable (not (equal (first (connection-last-command (get-connection))) command))) (send-command (list command "self")))) ((numberp all) (iterate-clients (control-command command nil))) (t (send-command (list command "all"))))) (defun cancel (&optional all) "Stop speaking all the messages sent through the current client so far. If the universal argument is given, stop speaking messages of all clients. If a numeric argument is given, stop speaking messages of all current Emacs session clients." (control-command "CANCEL" all)) (defun stop (&optional all) "Stop speaking the currently spoken message (if any) of this client. If the optional argument ALL is non-nil, stop speaking the currently spoken messages of all clients." (control-command "STOP" all t)) (defun pause (&optional all) "Pause speaking in the current client. If the optional argument ALL is non-nil, pause speaking in all clients." (if all (iterate-connections (setf (connection-paused-p *connection*) t)) (setf (connection-paused-p (get-connection)) t)) (control-command "PAUSE" (not (not all)))) (defun resume (&optional all) "Resume previously stopped speaking in the current client. If the optional argument ALL is non-nil, resume speaking messages of all clients." (when (or all (connection-paused-p (get-connection))) (control-command "RESUME" (not (not all))) (if all (setf (connection-paused-p (get-connection)) nil) (iterate-connections (setf (connection-paused-p *connection*) nil))))) speech-dispatcher-0.9.1/src/api/cl/ssip.asd0000644000175000017500000000164013406252056015446 00000000000000;; Copyright (C) 2004 Brailcom, o.p.s. ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ;; for more details. ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program. If not, see . (in-package :asdf) (defsystem :ssip :depends-on (:regex #+SBCL :sb-bsd-sockets) :components ((:file "package") (:file "sysdep") (:file "elisp") (:file "configuration") (:file "ssip")) :serial t) speech-dispatcher-0.9.1/src/api/cl/package.lisp0000644000175000017500000000223213406252052016255 00000000000000;;; Package definition ;; Author: Milan Zamazal ;; Copyright (C) 2004 Brailcom, o.p.s. ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as published by ;; the Free Software Foundation; either version 2.1 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 Lesser General Public License ;; for more details. ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program. If not, see . (in-package :cl-user) (defpackage :ssip (:use :cl) (:export ;; configuration.lisp #:*application-name* #:*client-name* #:*language* #:*spell* ;; ssip.lisp #:connection-names #:set-language #:open-connection #:close-connection #:reopen-connection #:say-text #:say-sound #:say-char #:cancel #:stop #:pause #:resume )) speech-dispatcher-0.9.1/src/api/cl/sysdep.lisp0000644000175000017500000000301113406252066016172 00000000000000;;; System dependent functions ;; Author: Milan Zamazal ;; Copyright (C) 2004 Brailcom, o.p.s. ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as published by ;; the Free Software Foundation; either version 2.1 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 Lesser General Public License ;; for more details. ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program. If not, see . (in-package :ssip) (defun getenv (var) #+SBCL (sb-ext:posix-getenv var) #+CLISP (ext:getenv var)) #+CLISP (defparameter +encoding+ (ext:make-encoding :charset 'charset:utf-8 :line-terminator :unix)) (defun open-network-stream (host port) #+CLISP (socket:socket-connect port host :external-format +encoding+) #+SBCL (let ((s (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))) (sb-bsd-sockets:socket-connect s (sb-bsd-sockets:host-ent-address (sb-bsd-sockets:get-host-by-name host)) port) (sb-bsd-sockets:socket-make-stream s :input t :output t :buffering :none)) ) (defun close-network-stream (stream) #+(or SBCL CLISP) (close stream)) speech-dispatcher-0.9.1/src/api/cl/elisp.lisp0000644000175000017500000000307113406252044016001 00000000000000;;; Elisp compatibility functions ;; Author: Milan Zamazal ;; Copyright (C) 2004 Brailcom, o.p.s. ;; COPYRIGHT NOTICE ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as published by ;; the Free Software Foundation; either version 2.1 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 Lesser General Public License ;; for more details. ;; You should have received a copy of the GNU Lesser General Public License ;; along with this program. If not, see . (in-package :ssip) (defmacro while (condition &body body) `(loop while ,condition do (progn ,@body))) (defun plist-get-internal (plist prop) (cond ((null plist) nil) ((eq (car plist) prop) (cdr plist)) (t (plist-get-internal (nthcdr 2 plist) prop)))) (defun plist-get (plist prop) (first (plist-get-internal plist prop))) (defun plist-member (plist prop) (not (null (plist-get-internal plist prop)))) (defun plist-put (plist prop val) (let ((value (plist-get-internal plist prop))) (if value (progn (rplaca value val) plist) (list* prop val plist)))) (defun user-login-name () (or (getenv "LOGNAME") (getenv "USER"))) (defun concat (&rest args) (apply #'concatenate 'string args)) speech-dispatcher-0.9.1/src/api/Makefile.in0000644000175000017500000005271213465233610015454 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_PYTHON_TRUE@am__append_1 = python subdir = src/api ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = c python am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = c $(am__append_1) EXTRA_DIST = cl guile all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/api/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/api/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/api/Makefile.am0000644000175000017500000000147613406251776015454 00000000000000# # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ## Process this file with automake to produce Makefile.in SUBDIRS= c if HAVE_PYTHON SUBDIRS += python endif EXTRA_DIST = cl guile -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/modules/0000755000175000017500000000000013465234513014362 500000000000000speech-dispatcher-0.9.1/src/modules/mluvitko.c0000644000175000017500000000372113406252516016321 00000000000000/* * mluvitko.c - Speechd module for mluvitko (czech software synthetizer) * * Copyright (C) 2001 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Tomas Cerha */ #ifdef HAVE_CONFIG_H #include #endif #define VERSION "0.0.1" #include #include #include "module.h" gint mluvitko_write(const gchar * data, gint len); gint mluvitko_stop(void); gint mluvitko_pause(void); gint mluvitko_release(void); /* fill the module_info structure with pointers to this modules functions */ OutputModule modinfo = { "mluvitko", "Czech software synthesizer", NULL, /* filename */ mluvitko_write, mluvitko_stop, mluvitko_pause, mluvitko_release }; /* entry point of this module */ OutputModule *module_init(void) { printf("mluvitko: init_module()\n"); /*modinfo.name = g_strdup("mluvitko"), modinfo.description = g_strdup_printf("Czech software synthesizer, version %s",VERSION); */ return &modinfo; } /* module operations */ gint mluvitko_write(const gchar * data, gint len) { int i; printf("mluvitko: write()\n"); for (i = 0; i < len; i++) { printf("%c ", data[i]); } printf("\n"); return len; } gint mluvitko_stop(void) { printf("mluvitko: stop()\n"); return 1; } gint mluvitko_pause(void) { printf("mluvitko: pause()\n"); return 1; } gint mluvitko_release(void) { printf("mluvitko: release()\n"); return 1; } speech-dispatcher-0.9.1/src/modules/eci.h0000644000175000017500000003472713430032457015223 00000000000000/* * Copyright (c) 2005, 2006, IBM Corp. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of IBM Corp. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * * eci.h APIs for IBM Text To Speech * */ #ifndef __ECI_H #define __ECI_H #ifndef MOTIF typedef int Boolean; #endif #define ECITrue 1 #define ECIFalse 0 #ifndef ECIFNDECLARE typedef signed long ECIint32; #ifdef _MSC_VER #ifdef _WIN32_WCE typedef char ECIsystemChar; #define ECIFNDECLARE __stdcall #elif defined _WIN32 #include typedef _TCHAR ECIsystemChar; #define ECIFNDECLARE __stdcall #endif #elif defined __TURBOC__ #ifdef __WIN32__ #include #define ECIFNDECLARE __stdcall typedef _TCHAR ECIsystemChar; #endif #else #define ECIFNDECLARE typedef char ECIsystemChar; #endif #endif #ifndef NULL_ECI_HAND #define NULL_ECI_HAND 0 #endif #define ECI_PRESET_VOICES 8 #define ECI_USER_DEFINED_VOICES 8 #define ECI_VOICE_NAME_LENGTH 30 #define ECI_NOERROR 0x00000000 #define ECI_SYSTEMERROR 0x00000001 #define ECI_MEMORYERROR 0x00000002 #define ECI_MODULELOADERROR 0x00000004 #define ECI_DELTAERROR 0x00000008 #define ECI_SYNTHERROR 0x00000010 #define ECI_DEVICEERROR 0x00000020 #define ECI_DICTERROR 0x00000040 #define ECI_PARAMETERERROR 0x00000080 #define ECI_SYNTHESIZINGERROR 0x00000100 #define ECI_DEVICEBUSY 0x00000200 #define ECI_SYNTHESISPAUSED 0x00000400 #define ECI_REENTRANTCALL 0x00000800 #define ECI_ROMANIZERERROR 0x00001000 #define ECI_SYNTHESIZING 0x00002000 #define eciPhonemeLength (4) #ifdef __cplusplus extern "C" { #endif typedef void* ECIHand; typedef const void* ECIInputText; enum ECIParam { eciSynthMode, eciInputType, eciTextMode, eciDictionary, eciSampleRate = 5, eciWantPhonemeIndices = 7, eciRealWorldUnits, eciLanguageDialect, eciNumberMode, eciWantWordIndex = 12, eciNumDeviceBlocks, eciSizeDeviceBlocks, eciNumPrerollDeviceBlocks, eciSizePrerollDeviceBlocks, eciNumParams }; enum ECIVoiceParam { eciGender, eciHeadSize, eciPitchBaseline, eciPitchFluctuation, eciRoughness, eciBreathiness, eciSpeed, eciVolume, eciNumVoiceParams }; enum ECIDictError { DictNoError, DictFileNotFound, DictOutOfMemory, DictInternalError, DictNoEntry, DictErrLookUpKey, DictAccessError, DictInvalidVolume }; enum ECIVoiceError { VoiceNoError, VoiceSystemError, VoiceNotRegisteredError, VoiceInvalidFileFormatError }; typedef void* ECIDictHand; #define NULL_DICT_HAND 0 enum ECIDictVolume { eciMainDict = 0, eciRootDict = 1, eciAbbvDict = 2, eciMainDictExt = 3 }; enum ECILanguageDialect { NODEFINEDCODESET = 0x00000000, eciGeneralAmericanEnglish = 0x00010000, eciBritishEnglish = 0x00010001, eciCastilianSpanish = 0x00020000, eciMexicanSpanish = 0x00020001, eciStandardFrench = 0x00030000, eciCanadianFrench = 0x00030001, eciStandardGerman = 0x00040000, eciStandardItalian = 0x00050000, eciMandarinChinese = 0x00060000, eciMandarinChineseGB = eciMandarinChinese, eciMandarinChinesePinYin = 0x00060100, eciMandarinChineseUCS = 0x00060800, eciTaiwaneseMandarin = 0x00060001, eciTaiwaneseMandarinBig5 = eciTaiwaneseMandarin, eciTaiwaneseMandarinZhuYin = 0x00060101, eciTaiwaneseMandarinPinYin = 0x00060201, eciTaiwaneseMandarinUCS = 0x00060801, eciBrazilianPortuguese = 0x00070000, eciStandardJapanese = 0x00080000, eciStandardJapaneseSJIS = eciStandardJapanese, eciStandardJapaneseUCS = 0x00080800, eciStandardFinnish = 0x00090000, eciStandardKorean = 0x000A0000, eciStandardKoreanUHC = eciStandardKorean, eciStandardKoreanUCS = 0x000A0800, eciStandardCantonese = 0x000B0000, eciStandardCantoneseGB = eciStandardCantonese, eciStandardCantoneseUCS = 0x000B0800, eciHongKongCantonese = 0x000B0001, eciHongKongCantoneseBig5 = eciHongKongCantonese, eciHongKongCantoneseUCS = 0x000B0801, eciStandardDutch = 0x000C0000, eciStandardNorwegian = 0x000D0000, eciStandardSwedish = 0x000E0000, eciStandardDanish = 0x000F0000, eciStandardReserved = 0x00100000, eciStandardThai = 0x00110000, eciStandardThaiTIS = eciStandardThai }; enum ECIPartOfSpeech { eciUndefinedPOS = 0, eciFutsuuMeishi = 1, eciKoyuuMeishi, eciSahenMeishi, eciMingCi }; #if defined(WIN32) #pragma pack(push, 1) #elif defined(UNDER_CE) && (defined(MIPS) || defined(SH3)) #pragma pack(push, 4) #endif typedef struct { union { unsigned char sz[eciPhonemeLength+1]; unsigned short wsz[eciPhonemeLength+1]; } phoneme; enum ECILanguageDialect eciLanguageDialect; unsigned char mouthHeight; unsigned char mouthWidth; unsigned char mouthUpturn; unsigned char jawOpen; unsigned char teethUpperVisible; unsigned char teethLowerVisible; unsigned char tonguePosn; unsigned char lipTension; } ECIMouthData; typedef struct ECIVoiceAttrib { int eciSampleRate; enum ECILanguageDialect languageID; } ECIVoiceAttrib; #if defined(WIN32) || ( defined(UNDER_CE) && (defined(MIPS) || defined(SH3)) ) #pragma pack(pop) #endif enum ECIMessage { eciWaveformBuffer, eciPhonemeBuffer, eciIndexReply, eciPhonemeIndexReply, eciWordIndexReply, eciStringIndexReply, eciAudioIndexReply, eciSynthesisBreak }; enum ECICallbackReturn { eciDataNotProcessed, eciDataProcessed, eciDataAbort }; typedef enum ECICallbackReturn (*ECICallback)(ECIHand hEngine, enum ECIMessage Msg, long lParam, void *pData); #if defined(_WIN32) || defined(_Windows) enum ECIDialogBox { eciGeneralDB, eciAboutDB, eciVoicesDB, eciReadingDB, eciMainDictionaryDB, eciRootDictionaryDB, eciNumDialogBoxes }; #endif #ifdef __cplusplus } #endif #ifdef __cplusplus extern "C" { #endif ECIHand ECIFNDECLARE eciNew(void); ECIHand ECIFNDECLARE eciNewEx(enum ECILanguageDialect Value); int ECIFNDECLARE eciGetAvailableLanguages(enum ECILanguageDialect *aLanguages, int *nLanguages); ECIHand ECIFNDECLARE eciDelete(ECIHand hEngine); Boolean ECIFNDECLARE eciReset(ECIHand hEngine); Boolean ECIFNDECLARE eciIsBeingReentered(ECIHand hEngine); void ECIFNDECLARE eciVersion(char *pBuffer); int ECIFNDECLARE eciProgStatus(ECIHand hEngine); void ECIFNDECLARE eciErrorMessage(ECIHand hEngine, void* buffer); void ECIFNDECLARE eciClearErrors(ECIHand hEngine); Boolean ECIFNDECLARE eciTestPhrase(ECIHand hEngine); Boolean ECIFNDECLARE eciSpeakText(ECIInputText pText, Boolean bAnnotationsInTextPhrase); Boolean ECIFNDECLARE eciSpeakTextEx(ECIInputText pText, Boolean bAnnotationsInTextPhrase, enum ECILanguageDialect Value); int ECIFNDECLARE eciGetParam(ECIHand hEngine, enum ECIParam Param); int ECIFNDECLARE eciSetParam(ECIHand hEngine, enum ECIParam Param, int iValue); int ECIFNDECLARE eciGetDefaultParam(enum ECIParam parameter); int ECIFNDECLARE eciSetDefaultParam(enum ECIParam parameter, int value); Boolean ECIFNDECLARE eciCopyVoice(ECIHand hEngine, int iVoiceFrom, int iVoiceTo); Boolean ECIFNDECLARE eciGetVoiceName(ECIHand hEngine, int iVoice, void *pBuffer); Boolean ECIFNDECLARE eciSetVoiceName(ECIHand hEngine, int iVoice, const void *pBuffer); int ECIFNDECLARE eciGetVoiceParam(ECIHand hEngine, int iVoice, enum ECIVoiceParam Param); int ECIFNDECLARE eciSetVoiceParam(ECIHand hEngine, int iVoice, enum ECIVoiceParam Param, int iValue); Boolean ECIFNDECLARE eciAddText(ECIHand hEngine, ECIInputText pText); Boolean ECIFNDECLARE eciInsertIndex(ECIHand hEngine, int iIndex); Boolean ECIFNDECLARE eciSynthesize(ECIHand hEngine); Boolean ECIFNDECLARE eciSynthesizeFile(ECIHand hEngine, const void *pFilename); Boolean ECIFNDECLARE eciClearInput(ECIHand hEngine); Boolean ECIFNDECLARE eciGeneratePhonemes(ECIHand hEngine, int iSize, void *pBuffer); int ECIFNDECLARE eciGetIndex(ECIHand hEngine); Boolean ECIFNDECLARE eciStop(ECIHand hEngine); Boolean ECIFNDECLARE eciSpeaking(ECIHand hEngine); Boolean ECIFNDECLARE eciSynchronize(ECIHand hEngine); Boolean ECIFNDECLARE eciSetOutputBuffer(ECIHand hEngine, int iSize, short *psBuffer); Boolean ECIFNDECLARE eciSetOutputFilename(ECIHand hEngine, const void *pFilename); Boolean ECIFNDECLARE eciSetOutputDevice(ECIHand hEngine, int iDevNum); Boolean ECIFNDECLARE eciPause(ECIHand hEngine, Boolean On); void ECIFNDECLARE eciRegisterCallback(ECIHand hEngine, ECICallback Callback, void *pData); ECIDictHand ECIFNDECLARE eciNewDict(ECIHand hEngine); ECIDictHand ECIFNDECLARE eciGetDict(ECIHand hEngine); enum ECIDictError ECIFNDECLARE eciSetDict(ECIHand hEngine, ECIDictHand hDict); ECIDictHand ECIFNDECLARE eciDeleteDict(ECIHand hEngine, ECIDictHand hDict); enum ECIDictError ECIFNDECLARE eciLoadDict(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pFilename); enum ECIDictError ECIFNDECLARE eciSaveDict(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pFilename); enum ECIDictError ECIFNDECLARE eciUpdateDict(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pKey, ECIInputText pTranslationValue); enum ECIDictError ECIFNDECLARE eciDictFindFirst(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText *ppKey, ECIInputText *ppTranslationValue); enum ECIDictError ECIFNDECLARE eciDictFindNext(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText *ppKey, ECIInputText *ppTranslationValue); const char *ECIFNDECLARE eciDictLookup(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pKey); enum ECIDictError ECIFNDECLARE eciUpdateDictA(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pKey, ECIInputText pTranslationValue, enum ECIPartOfSpeech PartOfSpeech); enum ECIDictError ECIFNDECLARE eciDictFindFirstA(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText *ppKey, ECIInputText *ppTranslationValue, enum ECIPartOfSpeech *pPartOfSpeech); enum ECIDictError ECIFNDECLARE eciDictFindNextA(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText *ppKey, ECIInputText *ppTranslationValue, enum ECIPartOfSpeech *pPartOfSpeech); enum ECIDictError ECIFNDECLARE eciDictLookupA(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pKey, ECIInputText *ppTranslationValue, enum ECIPartOfSpeech *pPartOfSpeech); #define eciDictFindFirst(eciHandle, dictHandle, dictVolume, ppkey, pptranslation) \ eciDictFindFirst((eciHandle), (dictHandle), (dictVolume), (ECIInputText *) (ppkey), (ECIInputText *) (pptranslation)) #define eciDictFindNext(eciHandle, dictHandle, dictVolume, ppkey, pptranslation) \ eciDictFindNext((eciHandle), (dictHandle), (dictVolume), (ECIInputText *) (ppkey), (ECIInputText *) (pptranslation)) enum ECIVoiceError ECIFNDECLARE eciRegisterVoice(ECIHand eciHand, int voiceNumber, void *vData, ECIVoiceAttrib *vAttrib); enum ECIVoiceError ECIFNDECLARE eciUnregisterVoice(ECIHand eciHand, int voiceNumber, ECIVoiceAttrib *vAttrib, void **vData); #ifndef __ECIFILTER_H #define __ECIFILTER_H typedef void *ECIFilterHand; #define NULL_FILTER_HAND 0 /*typedef*/ enum ECIFilterError { FilterNoError, FilterFileNotFound, FilterOutOfMemory, FilterInternalError, FilterAccessError }; enum ECIFilterError ECIFNDECLARE eciDeactivateFilter(ECIHand eciHandle, ECIFilterHand pFilter); #ifdef __cplusplus ECIFilterHand ECIFNDECLARE eciNewFilter(ECIHand eciHandle, unsigned int filterNum = 0, Boolean bGlobal = false); #else ECIFilterHand ECIFNDECLARE eciNewFilter(ECIHand eciHandle, unsigned int filterNum, Boolean bGlobal); #endif enum ECIFilterError ECIFNDECLARE eciActivateFilter(ECIHand eciHandle, ECIFilterHand whichFilterHand); ECIFilterHand ECIFNDECLARE eciDeleteFilter(ECIHand eciHandle, ECIFilterHand whichFilterHand); enum ECIFilterError ECIFNDECLARE eciUpdateFilter(ECIHand eciHandle, ECIFilterHand whichFilterHand, ECIInputText key, ECIInputText translation); enum ECIFilterError ECIFNDECLARE eciGetFilteredText(ECIHand eciHandle, ECIFilterHand whichFilterHand, ECIInputText input, ECIInputText *filteredText); #endif #ifdef __cplusplus } #endif #endif speech-dispatcher-0.9.1/src/modules/ibmtts_shim.c0000644000175000017500000000550113430032457016764 00000000000000/* * ibmtts_shim.c - Shim for IBM TTS (Voxin) * to be able to build the ibmtts module without the IBM TTS SDK. * * Copyright (C) 2019 Samuel Thibault * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "eci.h" #include ECIHand ECIFNDECLARE eciNew(void) { assert(0); } int ECIFNDECLARE eciGetAvailableLanguages(enum ECILanguageDialect *aLanguages, int *nLanguages) { assert(0); } ECIHand ECIFNDECLARE eciDelete(ECIHand hEngine) { assert(0); } void ECIFNDECLARE eciVersion(char *pBuffer) { assert(0); } void ECIFNDECLARE eciErrorMessage(ECIHand hEngine, void* buffer) { assert(0); } int ECIFNDECLARE eciGetParam(ECIHand hEngine, enum ECIParam Param) { assert(0); } int ECIFNDECLARE eciSetParam(ECIHand hEngine, enum ECIParam Param, int iValue) { assert(0); } Boolean ECIFNDECLARE eciGetVoiceName(ECIHand hEngine, int iVoice, void *pBuffer) { assert(0); } Boolean ECIFNDECLARE eciCopyVoice(ECIHand hEngine, int iVoiceFrom, int iVoiceTo) { assert(0); } int ECIFNDECLARE eciGetVoiceParam(ECIHand hEngine, int iVoice, enum ECIVoiceParam Param) { assert(0); } int ECIFNDECLARE eciSetVoiceParam(ECIHand hEngine, int iVoice, enum ECIVoiceParam Param, int iValue) { assert(0); } Boolean ECIFNDECLARE eciAddText(ECIHand hEngine, ECIInputText pText) { assert(0); } Boolean ECIFNDECLARE eciInsertIndex(ECIHand hEngine, int iIndex) { assert(0); } Boolean ECIFNDECLARE eciSynthesize(ECIHand hEngine) { assert(0); } Boolean ECIFNDECLARE eciStop(ECIHand hEngine) { assert(0); } Boolean ECIFNDECLARE eciSynchronize(ECIHand hEngine) { assert(0); } Boolean ECIFNDECLARE eciSetOutputBuffer(ECIHand hEngine, int iSize, short *psBuffer) { assert(0); } void ECIFNDECLARE eciRegisterCallback(ECIHand hEngine, ECICallback Callback, void *pData) { assert(0); } ECIDictHand ECIFNDECLARE eciNewDict(ECIHand hEngine) { assert(0); } ECIDictHand ECIFNDECLARE eciGetDict(ECIHand hEngine) { assert(0); } enum ECIDictError ECIFNDECLARE eciSetDict(ECIHand hEngine, ECIDictHand hDict) { assert(0); } ECIDictHand ECIFNDECLARE eciDeleteDict(ECIHand hEngine, ECIDictHand hDict) { assert(0); } enum ECIDictError ECIFNDECLARE eciLoadDict(ECIHand hEngine, ECIDictHand hDict, enum ECIDictVolume DictVol, ECIInputText pFilename) { assert(0); } speech-dispatcher-0.9.1/src/modules/kali_KAnalyse_shim.cpp0000644000175000017500000000162313406252475020541 00000000000000/* * kali_KAnalyse_shim.c - Shim for Kali * to be able to build the Kali module without the Kali SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include extern "C" { bool initAnalyse(void) { assert(0); } bool quitteAnalyse(void) { assert(0); } } speech-dispatcher-0.9.1/src/modules/kali_KParle_shim.cpp0000644000175000017500000000161513406252503020201 00000000000000/* * kali_KParle_shim.c - Shim for Kali * to be able to build the Kali module without the Kali SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include extern "C" { bool initParle(void) { assert(0); } bool quitteParle(void) { assert(0); } } speech-dispatcher-0.9.1/src/modules/kali_KTrans_shim.cpp0000644000175000017500000000161513406252506020230 00000000000000/* * kali_KTrans_shim.c - Shim for Kali * to be able to build the Kali module without the Kali SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include extern "C" { bool initTrans(void) { assert(0); } bool quitteTrans(void) { assert(0); } } speech-dispatcher-0.9.1/src/modules/kali_KGlobal_shim.cpp0000644000175000017500000000162013406252500020327 00000000000000/* * kali_KGlobal_shim.c - Shim for Kali * to be able to build the Kali module without the Kali SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include extern "C" { bool initGlobal(void) { assert(0); } bool quitteGlobal(void) { assert(0); } } speech-dispatcher-0.9.1/src/modules/kali_Kali_shim.cpp0000644000175000017500000000421013406252510017673 00000000000000/* * kali_Kali_shim.c - Shim for Kali * to be able to build the Kali module without the Kali SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include extern "C" { bool initKali(void) { assert(0); } const AudioTrackKali *GetBufMultiKaliStd(short nK) { assert(0); } void SetSortieBufMultiKaliStd(short nK, bool sortieBuf) { assert(0); } void SetSortieSonMultiKaliStd(short nK, bool sortieSon) { assert(0); } short GetDebitDefautKaliStd(void) { assert(0); } short GetDebitMinKaliStd(void) { assert(0); } short GetDebitMaxKaliStd(void) { assert(0); } void SetDebitKali(short debit) { assert(0); } short GetVolumeDefautKaliStd(void) { assert(0); } short GetVolumeMinKaliStd(void) { assert(0); } short GetVolumeMaxKaliStd(void) { assert(0); } void SetVolumeKali(short volume) { assert(0); } short GetHauteurDefautKaliStd(void) { assert(0); } short GetHauteurMinKaliStd(void) { assert(0); } short GetHauteurMaxKaliStd(void) { assert(0); } void SetHauteurKali(short hauteur) { assert(0); } void SetModeLectureKali(short modeLecture) { assert(0); } short GetNLangueVoixKaliStd(short nVoix) { assert(0); } char *GetNomLangueKali(short nLangue, char *nomLangue) { assert(0); } void SetLangueKali(short nLangue) { assert(0); } short GetNbVoixKali(void) { assert(0); } char *GetNomVoixKali(short nVoix, char *nomVoix) { assert(0); } void SetVoixKali(short nVoix) { assert(0); } short MessageKali(unsigned char* texte) { assert(0); } short QueryIndexKali(void) { assert(0); } } speech-dispatcher-0.9.1/src/modules/README.baratinoo0000644000175000017500000000216313406252401017130 00000000000000IMPORTANT INFORMATION ON THE BARATINOO MODULE --------------------------------------------- The Baratinoo engine library (libbaratinoo) does NOT provide ABI stability. This is mitigated in the baratinoo module code using both static and dynamic compatibility strategies. Before hacking on anything *USING* or *RELATED* to the Baratinoo API, carefully read the "Baratinoo API" section in the module source code, baratinoo.c. Copyright (C) 2018 Colomban Wendling This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (file COPYING in the root directory). You should have received a copy of the GNU General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/modules/baratinoo_shim.c0000644000175000017500000000563213406252417017450 00000000000000/* * baratinoo.h - Shim for Baratinoo (VoxyGen) * to be able to build the Baratinoo module without the Baratinoo SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "baratinoo_compat.h" #include BARATINOO_INIT_RETURN BCinitlib(BaratinooTraceCB traceCB) { assert(0); } const char *BCgetBaratinooVersion(void) { assert(0); } const const BaratinooVersionStruct *BCgetBaratinooVersionStruct(void) { assert(0); } void BCterminatelib(void) { assert(0); } BCengine BCnew(const void *privatedata) { assert(0); } void BCdelete(BCengine engine) { assert(0); } void BCinit(BCengine engine, const char *config) { assert(0); } int BCgetNumberOfVoices(BCengine engine) { assert(0); } BaratinooVoiceInfo BCgetVoiceInfo(BCengine engine, int voiceNumber) { assert(0); } BARATINOOC_STATE BCgetState(BCengine engine) { assert(0); } void BCsetWantedEvent(BCengine engine, BARATINOO_EVENT_TYPE type) { assert(0); } BARATINOOC_STATE BCprocessLoop(BCengine engine, int count) { assert(0); } BaratinooEvent BCgetEvent(BCengine engine) { assert(0); } BARATINOOC_STATE BCpurge(BCengine engine) { assert(0); } /* IO */ BCoutputSignalBuffer BCoutputSignalBufferNew(BARATINOO_SIGNAL_CODING coding, int frequency) { assert(0); } void BCoutputTextBufferSetInEngine(BCoutputSignalBuffer outputSignalBuffer, BCengine engine) { assert(0); } int BCoutputSignalBufferIsError(BCoutputSignalBuffer outputSignalBuffer) { assert(0); } char *BCoutputSignalBufferGetSignalBuffer(BCoutputSignalBuffer outputSignalBuffer) { assert(0); } int BCoutputSignalBufferGetSignalLength(BCoutputSignalBuffer outputSignalBuffer) { assert(0); } void BCoutputSignalBufferResetSignal(BCoutputSignalBuffer outputSignalBuffer) { assert(0); } void BCoutputSignalBufferDeleteSignal(void *signal) { assert(0); } void BCoutputSignalBufferDelete(BCoutputSignalBuffer outputSignalBuffer) { assert(0); } BCinputTextBuffer BCinputTextBufferNew(BARATINOO_PARSING parsing, BARATINOO_TEXT_ENCODING encoding, int voiceIndex, char *voiceModules) { assert(0); } BARATINOOC_STATE BCinputTextBufferSetInEngine(BCinputTextBuffer inputTextBuffer, BCengine engine) { assert(0); } int BCinputTextBufferInit(BCinputTextBuffer inputTextBuffer, const char *text) { assert(0); } void BCinputTextBufferDelete(BCinputTextBuffer inputTextBuffer) { assert(0); } speech-dispatcher-0.9.1/src/modules/pico.c0000644000175000017500000003705213406252560015404 00000000000000/* * pico.c - Speech Dispatcher SVOX pico output module * * A SVOX pico output module * * Copyright (C) 2010 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1, or (at your option) * any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "spd_audio.h" #include #include "module_utils.h" #define MODULE_NAME "pico" #define MODULE_VERSION "0.1" DECLARE_DEBUG(); #define MAX_OUTBUF_SIZE (128) #define PICO_MEM_SIZE (10000000) #define PICO_VOICE_SPEED_MIN (20) #define PICO_VOICE_SPEED_MAX (500) #define PICO_VOICE_SPEED_DEFAULT (100) #define PICO_VOICE_PITCH_MIN (50) #define PICO_VOICE_PITCH_MAX (200) #define PICO_VOICE_PITCH_DEFAULT (100) #define PICO_VOICE_VOLUME_MIN (0) #define PICO_VOICE_VOLUME_MAX (500) #define PICO_VOICE_VOLUME_DEFAULT (100) static pico_System picoSystem; static pico_Resource picoTaResource; static pico_Resource picoSgResource; static pico_Engine picoEngine; static pico_Char *picoInp; static const char *PICO_LINGWARE_PATH = "/usr/share/pico/lang/"; static const int PICO_SAMPLE_RATE = 16000; static const char *picoInternalTaLingware[] = { "en-US_ta.bin", "en-GB_ta.bin", "de-DE_ta.bin", "es-ES_ta.bin", "fr-FR_ta.bin", "it-IT_ta.bin" }; static const char *picoInternalSgLingware[] = { "en-US_lh0_sg.bin", "en-GB_kh0_sg.bin", "de-DE_gl0_sg.bin", "es-ES_zl0_sg.bin", "fr-FR_nk0_sg.bin", "it-IT_cm0_sg.bin" }; static const SPDVoice pico_voices[] = { {"samantha", "en", "en-US"}, {"serena", "en", "en-GB"}, {"sabrina", "de", "de-DE"}, {"isabel", "es", "es-ES"}, {"virginie", "fr", "fr-FR"}, {"silvia", "it", "it-IT"} }; static const SPDVoice *pico_voices_list[] = { &pico_voices[0], &pico_voices[1], &pico_voices[2], &pico_voices[3], &pico_voices[4], &pico_voices[5], NULL }; static GThread *pico_play_thread; static sem_t pico_play_semaphore; static sem_t pico_idle_semaphore; enum states { STATE_IDLE, STATE_PLAY, STATE_PAUSE, STATE_STOP, STATE_CLOSE }; static enum states pico_state; /* Module configuration options */ MOD_OPTION_1_STR(PicoLingwarePath) static int pico_set_rate(signed int value) { int speed; if (value < 0) speed = PICO_VOICE_SPEED_MIN + (value - (-100)) * (PICO_VOICE_SPEED_DEFAULT - PICO_VOICE_SPEED_MIN) / (0 - (-100)); else speed = PICO_VOICE_SPEED_DEFAULT + (value - 0) * (PICO_VOICE_SPEED_MAX - PICO_VOICE_SPEED_DEFAULT) / (100 - 0); return speed; } static int pico_set_volume(signed int value) { int volume; volume = PICO_VOICE_VOLUME_MIN + (value - (-100)) * (PICO_VOICE_VOLUME_DEFAULT - PICO_VOICE_VOLUME_MIN) / (100 - (-100)); return volume; } static int pico_set_pitch(signed int value) { int pitch; if (value < 0) pitch = PICO_VOICE_PITCH_MIN + (value - (-100)) * (PICO_VOICE_PITCH_DEFAULT - PICO_VOICE_PITCH_MIN) / (0 - (-100)); else pitch = PICO_VOICE_PITCH_DEFAULT + (value - 0) * (PICO_VOICE_PITCH_MAX - PICO_VOICE_PITCH_DEFAULT) / (100 - 0); return pitch; } static int pico_process_tts(void) { pico_Int16 bytes_sent, bytes_recv, text_remaining, out_data_type; int ret, getstatus; short outbuf[MAX_OUTBUF_SIZE]; pico_Retstring outMessage; AudioTrack track; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) AudioFormat format = SPD_AUDIO_BE; #else AudioFormat format = SPD_AUDIO_LE; #endif pico_Char *buf = picoInp; text_remaining = strlen((const char *)buf) + 1; DBG(MODULE_NAME " Text: %s\n", picoInp); /* synthesis loop */ while (text_remaining) { /* Feed the text into the engine. */ if ((ret = pico_putTextUtf8(picoEngine, buf, text_remaining, &bytes_sent))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot put Text (%i): %s\n", ret, outMessage); return -1; } text_remaining -= bytes_sent; buf += bytes_sent; do { /* Retrieve the samples and add them to the buffer. SVOX pico TTS sample rate is 16K */ getstatus = pico_getData(picoEngine, (void *)outbuf, MAX_OUTBUF_SIZE, &bytes_recv, &out_data_type); if ((getstatus != PICO_STEP_BUSY) && (getstatus != PICO_STEP_IDLE)) { pico_getSystemStatusMessage(picoSystem, getstatus, outMessage); DBG(MODULE_NAME "Cannot get Data (%i): %s\n", getstatus, outMessage); return -1; } if (bytes_recv) { track.num_samples = bytes_recv / 2; track.samples = (short *)g_memdup((gconstpointer) outbuf, bytes_recv); track.num_channels = 1; track.sample_rate = PICO_SAMPLE_RATE; track.bits = 16; DBG(MODULE_NAME ": Sending %i samples to audio.", track.num_samples); if (module_tts_output(track, format) < 0) { DBG(MODULE_NAME "Can't play track for unknown reason."); return -1; } } if (g_atomic_int_get(&pico_state) != STATE_PLAY) { text_remaining = 0; break; } } while (PICO_STEP_BUSY == getstatus); } g_free(picoInp); picoInp = NULL; return 0; } /* Playback thread. */ static gpointer pico_play_func(gpointer nothing) { DBG(MODULE_NAME ": Playback thread starting"); set_speaking_thread_parameters(); while (g_atomic_int_get(&pico_state) != STATE_CLOSE) { sem_wait(&pico_play_semaphore); if (g_atomic_int_get(&pico_state) != STATE_PLAY) continue; DBG(MODULE_NAME ": Sending to TTS engine"); module_report_event_begin(); if (0 != pico_process_tts()) { DBG(MODULE_NAME ": ERROR in TTS"); } if (g_atomic_int_get(&pico_state) == STATE_PLAY) { module_report_event_end(); g_atomic_int_set(&pico_state, STATE_IDLE); } if (g_atomic_int_get(&pico_state) == STATE_STOP) { module_report_event_stop(); g_atomic_int_set(&pico_state, STATE_IDLE); sem_post(&pico_idle_semaphore); } if (g_atomic_int_get(&pico_state) == STATE_PAUSE) { module_report_event_pause(); g_atomic_int_set(&pico_state, STATE_IDLE); sem_post(&pico_idle_semaphore); } DBG(MODULE_NAME ": state %d", pico_state); } return 0; } /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); MOD_OPTION_1_INT_REG(Debug, 0); MOD_OPTION_1_STR_REG(PicoLingwarePath, PICO_LINGWARE_PATH); return 0; } int pico_init_voice(int voice_index) { int ret; pico_Retstring outMessage; pico_Char picoTaFileName[PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE]; pico_Char picoSgFileName[PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE]; pico_Char picoTaResourceName[PICO_MAX_RESOURCE_NAME_SIZE]; pico_Char picoSgResourceName[PICO_MAX_RESOURCE_NAME_SIZE]; /* Load the text analysis Lingware resource file. */ strcpy((char *)picoTaFileName, PicoLingwarePath); strcat((char *)picoTaFileName, (const char *)picoInternalTaLingware[voice_index]); if ((ret = pico_loadResource(picoSystem, picoTaFileName, &picoTaResource))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot load TA Lingware resource file (%i): %s\n", ret, outMessage); return -1; } /* Load the signal generation Lingware resource file. */ strcpy((char *)picoSgFileName, PicoLingwarePath); strcat((char *)picoSgFileName, (const char *)picoInternalSgLingware[voice_index]); if ((ret = pico_loadResource(picoSystem, picoSgFileName, &picoSgResource))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot load SG Lingware resource file (%i): %s\n", ret, outMessage); return -1; } /* Get the text analysis resource name. */ if ((ret = pico_getResourceName(picoSystem, picoTaResource, (char *)picoTaResourceName))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot get TA resource name (%i): %s\n", ret, outMessage); return -1; } /* Get the signal generation resource name. */ if ((ret = pico_getResourceName(picoSystem, picoSgResource, (char *)picoSgResourceName))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot get SG resource name (%i): %s\n", ret, outMessage); return -1; } /* Create a voice definition. */ if ((ret = pico_createVoiceDefinition(picoSystem, (const pico_Char *) pico_voices[voice_index].name))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot create voice definition (%i): %s\n", ret, outMessage); return -1; } /* Add the text analysis resource to the voice. */ if ((ret = pico_addResourceToVoiceDefinition(picoSystem, (const pico_Char *) pico_voices [voice_index].name, picoTaResourceName))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot add TA resource to the voice (%i): %s\n", ret, outMessage); return -1; } /* Add the signal generation resource to the voice. */ if ((ret = pico_addResourceToVoiceDefinition(picoSystem, (const pico_Char *) pico_voices [voice_index].name, picoSgResourceName))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot add SG resource to the voice (%i): %s\n", ret, outMessage); return -1; } return 0; } int module_init(char **status_info) { int ret, i; pico_Retstring outMessage; void *pmem; GError *error = NULL; sem_init(&pico_play_semaphore, 0, 0); sem_init(&pico_idle_semaphore, 0, 0); if ((pico_play_thread = g_thread_try_new(NULL, (GThreadFunc) pico_play_func, NULL, &error)) == NULL) { *status_info = g_strdup_printf(MODULE_NAME "Failed to create a play thread : %s\n", error->message); DBG(MODULE_NAME ": %s", *status_info); g_error_free(error); return -1; } pmem = g_malloc(PICO_MEM_SIZE); if ((ret = pico_initialize(pmem, PICO_MEM_SIZE, &picoSystem))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); *status_info = g_strdup_printf(MODULE_NAME ": Cannot initialize (%i): %s\n", ret, outMessage); g_free(pmem); return -1; } /* load resource for all language, probably need only one */ for (i = 0; i < sizeof(pico_voices) / sizeof(SPDVoice); i++) { if (0 != pico_init_voice(i)) { g_free(pmem); *status_info = g_strdup_printf(MODULE_NAME ": fail init voice (%s)\n", pico_voices[i].name); return -1; } } /* Create a new Pico engine, english default */ if ((ret = pico_newEngine(picoSystem, (const pico_Char *)pico_voices[0].name, &picoEngine))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); *status_info = g_strdup_printf(MODULE_NAME ": Cannot create a new pico engine (%i): %s\n", ret, outMessage); return -1; } *status_info = g_strdup(MODULE_NAME ": Initialized successfully."); g_atomic_int_set(&pico_state, STATE_IDLE); return 0; } SPDVoice **module_list_voices(void) { return (SPDVoice **)pico_voices_list; } void pico_set_synthesis_voice(char *voice_name) { int ret; pico_Retstring outMessage; /* Create a new Pico engine, english default */ if ((ret = pico_disposeEngine(picoSystem, &picoEngine))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot dispose pico engine (%i): %s\n", ret, outMessage); return; } /* Create a new Pico engine, english default */ if ((ret = pico_newEngine(picoSystem, (const pico_Char *)voice_name, &picoEngine))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot create a new pico engine (%i): %s\n", ret, outMessage); /* Try to fallback to english */ if ((ret = pico_newEngine(picoSystem, (const pico_Char *)pico_voices[0].name, &picoEngine))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot create default english pico engine (%i): %s\n", ret, outMessage); return; } return; } return; } static void pico_set_language(char *lang) { int i; /* get voice name based on language */ for (i = 0; i < sizeof(pico_voices) / sizeof(SPDVoice); i++) { if (!strcmp(pico_voices[i].language, lang)) { pico_set_synthesis_voice(pico_voices[i].name); return; } } return; } int module_speak(char *data, size_t bytes, SPDMessageType msgtype) { int value; static pico_Char *tmp; if (g_atomic_int_get(&pico_state) != STATE_IDLE) { DBG(MODULE_NAME ": module still speaking state = %d", pico_state); return 0; } /* Setting speech parameters. */ UPDATE_STRING_PARAMETER(voice.name, pico_set_synthesis_voice); /* UPDATE_PARAMETER(voice_type, pico_set_voice); */ UPDATE_STRING_PARAMETER(voice.language, pico_set_language); picoInp = (pico_Char *) module_strip_ssml(data); value = pico_set_rate(msg_settings.rate); if (PICO_VOICE_SPEED_DEFAULT != value) { tmp = picoInp; picoInp = (pico_Char *) g_strdup_printf("%s", value, tmp); g_free(tmp); } value = pico_set_volume(msg_settings.volume); if (PICO_VOICE_VOLUME_DEFAULT != value) { tmp = picoInp; picoInp = (pico_Char *) g_strdup_printf("%s", value, tmp); g_free(tmp); } value = pico_set_pitch(msg_settings.pitch); if (PICO_VOICE_PITCH_DEFAULT != value) { tmp = picoInp; picoInp = (pico_Char *) g_strdup_printf("%s", value, tmp); g_free(tmp); } /* switch (msgtype) { case SPD_MSGTYPE_CHAR: case SPD_MSGTYPE_KEY: case SPD_MSGTYPE_TEXT: case SPD_MSGTYPE_SOUND_ICON: default: DBG(MODULE_NAME ": msgtype = %d", msgtype); break; } */ g_atomic_int_set(&pico_state, STATE_PLAY); sem_post(&pico_play_semaphore); return bytes; } int module_stop(void) { pico_Status ret; pico_Retstring outMessage; if (g_atomic_int_get(&pico_state) != STATE_PLAY) { DBG(MODULE_NAME ": STOP called when not in PLAY state"); return -1; } g_atomic_int_set(&pico_state, STATE_STOP); sem_wait(&pico_idle_semaphore); /* reset Pico engine. */ if ((ret = pico_resetEngine(picoEngine, PICO_RESET_SOFT))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot reset pico engine (%i): %s\n", ret, outMessage); return -1; } return 0; } size_t module_pause(void) { pico_Status ret; pico_Retstring outMessage; if (g_atomic_int_get(&pico_state) != STATE_PLAY) { DBG(MODULE_NAME ": PAUSE called when not in PLAY state"); return -1; } g_atomic_int_set(&pico_state, STATE_PAUSE); sem_wait(&pico_idle_semaphore); /* reset Pico engine. */ if ((ret = pico_resetEngine(picoEngine, PICO_RESET_SOFT))) { pico_getSystemStatusMessage(picoSystem, ret, outMessage); DBG(MODULE_NAME "Cannot reset pico engine (%i): %s\n", ret, outMessage); return -1; } return 0; } int module_close(void) { g_atomic_int_set(&pico_state, STATE_CLOSE); sem_post(&pico_play_semaphore); g_thread_join(pico_play_thread); if (picoSystem) { pico_terminate(&picoSystem); picoSystem = NULL; } sem_destroy(&pico_idle_semaphore); sem_destroy(&pico_play_semaphore); return 0; } speech-dispatcher-0.9.1/src/modules/kali.cpp0000644000175000017500000002524713406252472015737 00000000000000 /* * kali.cpp - Speech Dispatcher backend for Kali * * Copyright (C)2016 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: kali.c,v 1.59 2008-06-09 10:38:02 hanke Exp $ */ #include #include #include #include extern "C" { #ifdef HAVE_CONFIG_H #include #endif #include #include "spd_audio.h" #include #include "module_utils.h" } #define MODULE_NAME "kali" #define MODULE_VERSION "0.0" #define DEBUG_MODULE 1 DECLARE_DEBUG(); /* Thread and process control */ static int kali_speaking = 0; static pthread_t kali_speak_thread; static sem_t kali_semaphore; static char **kali_message; static SPDMessageType kali_message_type; static int kali_position = 0; static int kali_pause_requested = 0; signed int kali_volume = 0; SPDVoice **kali_voice_list = NULL; /* Internal functions prototypes */ static void kali_set_rate(signed int rate); static void kali_set_pitch(signed int pitch); static void kali_set_volume(signed int volume); static void kali_set_punctuation_mode(SPDPunctuation punct); static void kali_set_voice(char *voice); static SPDVoice **kali_get_voices(); static void *_kali_speak(void *); int kali_stop = 0; MOD_OPTION_1_INT(KaliMaxChunkLength); MOD_OPTION_1_STR(KaliDelimiters); MOD_OPTION_1_INT(KaliNormalRate); MOD_OPTION_1_INT(KaliNormalVolume); MOD_OPTION_1_INT(KaliNormalPitch); MOD_OPTION_1_STR(KaliVoiceParameters); /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); MOD_OPTION_1_INT_REG(KaliMaxChunkLength, 4999); MOD_OPTION_1_STR_REG(KaliDelimiters, "."); MOD_OPTION_1_INT_REG(KaliNormalRate, 70); MOD_OPTION_1_INT_REG(KaliNormalVolume, 10); MOD_OPTION_1_INT_REG(KaliNormalPitch, 6); MOD_OPTION_1_STR_REG(KaliVoiceParameters, "Patrick"); return 0; } #define ABORT(msg) g_string_append(info, msg); \ DBG("FATAL ERROR:", info->str); \ *status_info = info->str; \ g_string_free(info, 0); \ return -1; int module_init(char **status_info) { int ret; GString *info; DBG("Module init"); INIT_INDEX_MARKING(); *status_info = NULL; info = g_string_new(""); /* Init kali and register a new voice */ initGlobal(); initParle(); initTrans(); initAnalyse(); initKali(); SetSortieSonMultiKaliStd(0, false); //sound output SetSortieBufMultiKaliStd(0, true); //Buffer output SetDebitKali(KaliNormalRate); SetVolumeKali(KaliNormalVolume); SetHauteurKali(KaliNormalPitch); kali_voice_list = kali_get_voices(); kali_set_voice(KaliVoiceParameters); DBG("KaliMaxChunkLength = %d\n", KaliMaxChunkLength); DBG("KaliDelimiters = %s\n", KaliDelimiters); kali_message = (char **)g_malloc(sizeof(char *)); *kali_message = NULL; sem_init(&kali_semaphore, 0, 0); DBG("Kali: creating new thread for kali_speak\n"); kali_speaking = 0; ret = pthread_create(&kali_speak_thread, NULL, _kali_speak, NULL); if (ret != 0) { DBG("Kali: thread failed\n"); *status_info = g_strdup("The module couldn't initialize threads " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return -1; } *status_info = g_strdup("Kali initialized successfully."); return 0; } #undef ABORT SPDVoice **module_list_voices(void) { return kali_voice_list; } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { DBG("write()\n"); if (kali_speaking) { DBG("Speaking when requested to write"); return 0; } DBG("Requested data: |%s|\n", data); if (*kali_message != NULL) { g_free(*kali_message); *kali_message = NULL; } *kali_message = module_strip_ssml(data); kali_message_type = SPD_MSGTYPE_TEXT; /* Setting voice */ UPDATE_PARAMETER(rate, kali_set_rate); UPDATE_PARAMETER(volume, kali_set_volume); UPDATE_PARAMETER(pitch, kali_set_pitch); UPDATE_PARAMETER(punctuation_mode, kali_set_punctuation_mode); UPDATE_STRING_PARAMETER(voice.name, kali_set_voice); kali_set_voice(msg_settings.voice.name); /* Send semaphore signal to the speaking thread */ kali_speaking = 1; sem_post(&kali_semaphore); DBG("Kali: leaving write() normally\n\r"); return bytes; } int module_stop(void) { int ret; DBG("kali: stop()\n"); kali_stop = 1; if (module_audio_id) { DBG("Stopping audio"); ret = spd_audio_stop(module_audio_id); if (ret != 0) DBG("WARNING: Non 0 value from spd_audio_stop: %d", ret); } return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (kali_speaking) { DBG("Kali doesn't support pause, stopping\n"); module_stop(); return -1; } else { return 0; } } int module_close(void) { DBG("kali: close()\n"); DBG("Stopping speech"); if (kali_speaking) { module_stop(); } quitteAnalyse(); quitteTrans(); quitteParle(); quitteGlobal(); DBG("Terminating threads"); if (module_terminate_thread(kali_speak_thread) != 0) return -1; sem_destroy(&kali_semaphore); return 0; } /* Internal functions */ void *_kali_speak(void *nothing) { AudioTrack track; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) AudioFormat format = SPD_AUDIO_BE; #else AudioFormat format = SPD_AUDIO_LE; #endif const AudioTrackKali *wav; unsigned int pos; char *buf; int bytes; int ret; DBG("kali: speaking thread starting.......\n"); set_speaking_thread_parameters(); while (1) { sem_wait(&kali_semaphore); DBG("Semaphore on\n"); kali_stop = 0; kali_speaking = 1; /* TODO: free(buf) */ buf = (char *)g_malloc((KaliMaxChunkLength + 1) * sizeof(char)); pos = 0; module_report_event_begin(); while (1) { if (kali_stop) { DBG("Stop in child, terminating"); kali_speaking = 0; module_report_event_stop(); break; } bytes = module_get_message_part(*kali_message, buf, &pos, KaliMaxChunkLength, KaliDelimiters); if (bytes < 0) { DBG("End of message"); kali_speaking = 0; module_report_event_end(); break; } buf[bytes] = 0; DBG("Returned %d bytes from get_part\n", bytes); DBG("Text to synthesize is '%s'\n", buf); if (kali_pause_requested && (current_index_mark != -1)) { DBG("Pause requested in parent, position %d\n", current_index_mark); kali_pause_requested = 0; kali_position = current_index_mark; break; } if (bytes > 0) { DBG("Speaking in child..."); DBG("Trying to synthesize text"); MessageKali((unsigned char *)buf); while (QueryIndexKali() > 0) ; wav = (const AudioTrackKali *) GetBufMultiKaliStd(0); if (wav == NULL) { DBG("Stop in child, terminating"); kali_speaking = 0; module_report_event_stop(); break; } track.num_samples = wav->num_samples; track.num_channels = wav->num_channels; track.sample_rate = wav->sample_rate; track.bits = wav->bits; track.samples = (signed short *)wav->samples; DBG("Got %d samples", track.num_samples); if (track.samples != NULL) { if (kali_stop) { DBG("Stop in child, terminating"); kali_speaking = 0; module_report_event_stop(); break; } DBG("Playing part of the message"); ret = module_tts_output(track, format); if (ret < 0) DBG("ERROR: failed to play the track"); if (kali_stop) { DBG("Stop in child, terminating (s)"); kali_speaking = 0; module_report_event_stop(); break; } } } else if (bytes == -1) { DBG("End of data in speaking thread"); kali_speaking = 0; module_report_event_end(); break; } else { kali_speaking = 0; module_report_event_end(); break; } if (kali_stop) { DBG("Stop in child, terminating"); kali_speaking = 0; module_report_event_stop(); break; } } kali_stop = 0; g_free(buf); } kali_speaking = 0; DBG("kali: speaking thread ended.......\n"); pthread_exit(NULL); } static void kali_set_rate(signed int rate) { short speed; assert(rate >= -100 && rate <= +100); if (rate < 0) speed = GetDebitDefautKaliStd() - rate * (GetDebitMinKaliStd() - GetDebitDefautKaliStd()) / 100; else speed = GetDebitDefautKaliStd() + rate * (GetDebitMaxKaliStd() - GetDebitDefautKaliStd()) / 100; SetDebitKali(speed); } static void kali_set_volume(signed int volume) { short vol; assert(volume >= -100 && volume <= +100); if (volume < 0) vol = GetVolumeDefautKaliStd() - volume * (GetVolumeMinKaliStd() - GetVolumeDefautKaliStd()) / 100; else vol = GetVolumeDefautKaliStd() + volume * (GetVolumeMaxKaliStd() - GetVolumeDefautKaliStd()) / 100; SetVolumeKali(vol); } static void kali_set_pitch(signed int pitch) { short ptch; assert(pitch >= -100 && pitch <= +100); if (pitch < 0) ptch = GetHauteurDefautKaliStd() - pitch * (GetHauteurMinKaliStd() - GetHauteurDefautKaliStd()) / 100; else ptch = GetHauteurDefautKaliStd() + pitch * (GetHauteurMaxKaliStd() - GetHauteurDefautKaliStd()) / 100; SetHauteurKali(ptch); } void kali_set_punctuation_mode(SPDPunctuation punct) { switch (punct) { case SPD_PUNCT_NONE: SetModeLectureKali(0); break; case SPD_PUNCT_SOME: SetModeLectureKali(1); break; case SPD_PUNCT_ALL: SetModeLectureKali(2); break; default: break; } } static void kali_set_voice(char *voice) { short i, nlang; char *v = voice; if (v == NULL) v = KaliVoiceParameters; for (i = 0; kali_voice_list[i] != NULL; i++) { if (strcasecmp(kali_voice_list[i]->name, v) == 0) { nlang = GetNLangueVoixKaliStd(i + 1); SetLangueKali(nlang); SetVoixKali(i + 1); break; } } } static SPDVoice **kali_get_voices() { short i; SPDVoice **result = NULL; short num_voices; char *voice; short nlang; char *language; num_voices = GetNbVoixKali(); DBG("Kali: %d voices total.", num_voices); voice = (char *)g_malloc(12); language = (char *)g_malloc(9); result = g_new0(SPDVoice *, num_voices); for (i = 0; i < num_voices; i++) { result[i] = g_new0(SPDVoice, 1); GetNomVoixKali(i + 1, voice); result[i]->name = (char *)g_strdup(voice); nlang = GetNLangueVoixKaliStd(i + 1); GetNomLangueKali(nlang, language); result[i]->language = (char *)g_strdup(language); result[i]->variant = NULL; } result[i] = NULL; g_free(voice); g_free(language); return result; } speech-dispatcher-0.9.1/src/modules/ivona_client.h0000644000175000017500000000243113406252466017127 00000000000000/* * ivona_client.h - Declarations from ivona_client.c * * Copyright (C) Bohdan R. Rau 2008 * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef IVONA_CLIENT_H #define IVONA_CLIENT_H /* A constant, used in both ivona.c and ivona_client.c */ #define IVONA_CACHE_MAX_STRLEN 11 int ivona_init_sock(char *host, int port); int ivona_send_string(char *to_say); char *ivona_get_wave_fd(int fd, int *nsamples, int *offset); char *ivona_get_wave(char *to_say, int *nsamples, int *offset); void play_icon(char *path, char *name); void ivona_init_cache(void); void ivona_store_wave_in_cache(char *to_say, char *wave, int nsamples); char *ivona_get_wave_from_cache(char *to_say, int *nsamples); #endif speech-dispatcher-0.9.1/src/modules/ivona_client.c0000644000175000017500000001311213406252463017115 00000000000000 /* * ivona_client.c - Speech Dispatcher backend for Ivona (IVO Software) * * Copyright (C) Bohdan R. Rau 2008 * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "module_utils.h" #include "ivona_client.h" static struct sockaddr_in sinadr; char *ivona_get_wave_from_cache(char *to_say, int *nsamples); void ivona_store_wave_in_cache(char *to_say, char *wave, int nsamples); int ivona_init_sock(char *host, int port) { if (!inet_aton(host, &sinadr.sin_addr)) { struct hostent *h = gethostbyname(host); if (!h) return -1; memcpy(&sinadr.sin_addr, h->h_addr, sizeof(struct in_addr)); endhostent(); } sinadr.sin_family = AF_INET; sinadr.sin_port = htons(port); return 0; } #define BASE_WAVE_SIZE 65536 #define STEP_WAVE_SIZE 32768 int ivona_send_string(char *to_say) { int fd; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return -1; if (connect(fd, (struct sockaddr *)&sinadr, sizeof(sinadr)) < 0) { close(fd); return -1; } write(fd, to_say, strlen(to_say)); write(fd, "\n", 1); return fd; } char *ivona_get_wave_fd(int fd, int *nsamples, int *offset) { int got, i; char *ivona_wave; int wave_size; int wave_length; short *w; wave_size = BASE_WAVE_SIZE; wave_length = 0; ivona_wave = g_malloc(wave_size); for (;;) { if (wave_size < wave_length + 8192) { ivona_wave = g_realloc(ivona_wave, wave_size + STEP_WAVE_SIZE); wave_size += STEP_WAVE_SIZE; } DBG("Have place for %d bytes", wave_size - wave_length); got = read(fd, ivona_wave + wave_length, wave_size - wave_length); DBG("Wave part at %d size %d", wave_length, got); if (got <= 0) break; wave_length += got; } close(fd); w = (short *)ivona_wave; for (i = wave_length / 2 - 1; i >= 0; i--) if (w[i]) break; if (i < 100) { g_free(ivona_wave); return NULL; } DBG("Trimmed %d samples at end", wave_length / 2 - i - 1); *nsamples = i + 1; for (i = 0; i < *nsamples; i++) if (w[i]) break; DBG("Should trim %d bytes at start", i); *offset = i; (*nsamples) -= i; return ivona_wave; } /* static char *ivona_get_wave_from_cache(char *to_say,int *nsamples); void ivona_store_wave_in_cache(char *to_say,char *wave,int nsamples); */ char *ivona_get_wave(char *to_say, int *nsamples, int *offset) { int fd; char *s; s = ivona_get_wave_from_cache(to_say, nsamples); if (s) { *offset = 0; return s; } fd = ivona_send_string(to_say); if (fd < 0) return NULL; s = ivona_get_wave_fd(fd, nsamples, offset); if (s) ivona_store_wave_in_cache(to_say, s + 2 * (*offset), *nsamples); return s; } /* Plays the specified audio file - from ibmtts/espeak module */ void play_icon(char *path, char *name) { char *buf = g_strdup_printf("%s/%s", path, name); module_play_file(buf); g_free(buf); } #define IVONA_CACHE_SIZE 256 #define IVONA_CACHE_MAX_SAMPLES 65536 static int ivona_cache_count; static struct ivona_cache { struct ivona_cache *succ, *pred; int count; char str[16]; int samples; char *wave; } ica_head, ica_tail, icas[IVONA_CACHE_SIZE]; void ivona_init_cache(void) { ica_head.pred = &ica_tail; ica_tail.succ = &ica_head; } void ica_tohead(struct ivona_cache *ica) { if (ica->pred) ica->pred->succ = ica->succ; if (ica->succ) ica->succ->pred = ica->pred; ica->pred = ica_head.pred; ica->pred->succ = ica; ica->succ = &ica_head; ica_head.pred = ica; } static struct ivona_cache *find_min_count(void) { int cnt = 0x7fffffff; struct ivona_cache *ica, *found; found = NULL; int i; for (ica = ica_tail.succ, i = 0; i < IVONA_CACHE_SIZE / 2 && ica->samples; ica = ica->succ) { if (ica->count < cnt) { cnt = ica->count; found = ica; } } if (found) { for (ica = ica_tail.succ; ica->samples; ica = ica->succ) { if (ica->count > 1) ica->count--; } } return found; } void ivona_store_wave_in_cache(char *str, char *wave, int samples) { struct ivona_cache *ica; if (strlen(str) > IVONA_CACHE_MAX_STRLEN) return; if (ivona_cache_count < IVONA_CACHE_SIZE) { ica = &icas[ivona_cache_count++]; } else { ica = find_min_count(); if (!ica) return; g_free(ica->wave); } ica->count = 1; ica->wave = g_malloc(samples * 2); memcpy(ica->wave, wave, samples * 2); ica->samples = samples; strcpy(ica->str, str); ica_tohead(ica); DBG("Stored cache %s", str); } char *ivona_get_wave_from_cache(char *to_say, int *samples) { struct ivona_cache *ica; if (strlen(to_say) > IVONA_CACHE_MAX_STRLEN) return NULL; for (ica = ica_tail.succ; ica && ica->samples; ica = ica->succ) { DBG("Cache cmp '%s'='%s'", ica->str, to_say); if (!strcmp(ica->str, to_say)) { char *wave = g_malloc(ica->samples * 2); memcpy(wave, ica->wave, ica->samples * 2); *samples = ica->samples; ica->count++; ica_tohead(ica); return wave; } } return NULL; } speech-dispatcher-0.9.1/src/modules/ivona.c0000644000175000017500000003211513406252460015560 00000000000000 /* * ivona.c - Speech Dispatcher backend for Ivona (IVO Software) * * Copyright (C) 2001, 2002, 2003, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: ivona.c,v 1.3 2008-06-27 12:29:32 hanke Exp $ */ /* this file is strictly based on flite.c */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "spd_audio.h" #include #include "module_utils.h" #include "ivona_client.h" #include #define MODULE_NAME "ivona" #define MODULE_VERSION "0.2" #define DEBUG_MODULE 1 DECLARE_DEBUG(); /* Thread and process control */ static int ivona_speaking = 0; static pthread_t ivona_speak_thread; static sem_t ivona_semaphore; static char **ivona_message; static SPDMessageType ivona_message_type; signed int ivona_volume = 0; signed int ivona_cap_mode = 0; int ivona_punct_mode = 0; /* Internal functions prototypes */ static int ivona_get_msgpart(struct dumbtts_conf *conf, SPDMessageType type, char **msg, char *icon, char **buf, int *len, int cap_mode, char *delimeters, int punct_mode, char *punct_some); static void ivona_set_volume(signed int volume); static void ivona_set_punctuation_mode(SPDPunctuation punct_mode); static void ivona_set_cap_let_recogn(SPDCapitalLetters cap_mode); static void *_ivona_speak(void *); int ivona_stop = 0; MOD_OPTION_1_STR(IvonaDelimiters); MOD_OPTION_1_STR(IvonaPunctuationSome); MOD_OPTION_1_INT(IvonaMinCapLet); MOD_OPTION_1_STR(IvonaSoundIconPath); MOD_OPTION_1_STR(IvonaServerHost); MOD_OPTION_1_INT(IvonaServerPort); MOD_OPTION_1_INT(IvonaSampleFreq); MOD_OPTION_1_STR(IvonaSpeakerLanguage); MOD_OPTION_1_STR(IvonaSpeakerName); static struct dumbtts_conf *ivona_conf; /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); MOD_OPTION_1_STR_REG(IvonaDelimiters, ".;:,!?"); MOD_OPTION_1_INT_REG(IvonaMinCapLet, 0); MOD_OPTION_1_STR_REG(IvonaSoundIconPath, "/usr/share/sound/sound-icons/"); MOD_OPTION_1_STR_REG(IvonaServerHost, "127.0.0.1"); MOD_OPTION_1_INT_REG(IvonaServerPort, 9123); MOD_OPTION_1_INT_REG(IvonaSampleFreq, 16000); MOD_OPTION_1_STR_REG(IvonaSpeakerLanguage, "pl"); MOD_OPTION_1_STR_REG(IvonaSpeakerName, "Jacek"); MOD_OPTION_1_STR_REG(IvonaPunctuationSome, "()"); ivona_init_cache(); return 0; } #define ABORT(msg) g_string_append(info, msg); \ DBG("FATAL ERROR:", info->str); \ *status_info = info->str; \ g_string_free(info, 0); \ return -1; int module_init(char **status_info) { int ret; GString *info; DBG("Module init"); *status_info = NULL; info = g_string_new(""); /* Init Ivona */ if (ivona_init_sock(IvonaServerHost, IvonaServerPort)) { DBG("Couldn't init socket parameters"); *status_info = g_strdup("Can't initialize socket. " "Check server host/port."); return -1; } ivona_conf = dumbtts_TTSInit(IvonaSpeakerLanguage); DBG("IvonaDelimiters = %s\n", IvonaDelimiters); ivona_message = g_malloc(sizeof(char *)); *ivona_message = NULL; sem_init(&ivona_semaphore, 0, 0); DBG("Ivona: creating new thread for ivona_speak\n"); ivona_speaking = 0; ret = pthread_create(&ivona_speak_thread, NULL, _ivona_speak, NULL); if (ret != 0) { DBG("Ivona: thread failed\n"); *status_info = g_strdup("The module couldn't initialize threads " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return -1; } *status_info = g_strdup("Ivona initialized successfully."); return 0; } #undef ABORT static SPDVoice voice_jacek; static SPDVoice *voice_ivona[] = { &voice_jacek, NULL }; SPDVoice **module_list_voices(void) { voice_jacek.name = IvonaSpeakerName; voice_jacek.language = IvonaSpeakerLanguage; return voice_ivona; } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { DBG("write()\n"); if (ivona_speaking) { DBG("Speaking when requested to write"); return 0; } DBG("Requested data: |%s|\n", data); if (*ivona_message != NULL) { g_free(*ivona_message); *ivona_message = NULL; } *ivona_message = module_strip_ssml(data); ivona_message_type = msgtype; if ((msgtype == SPD_MSGTYPE_TEXT) && (msg_settings.spelling_mode == SPD_SPELL_ON)) ivona_message_type = SPD_MSGTYPE_SPELL; /* Setting voice */ UPDATE_PARAMETER(volume, ivona_set_volume); UPDATE_PARAMETER(cap_let_recogn, ivona_set_cap_let_recogn); UPDATE_PARAMETER(punctuation_mode, ivona_set_punctuation_mode); /* Send semaphore signal to the speaking thread */ ivona_speaking = 1; sem_post(&ivona_semaphore); DBG("Ivona: leaving write() normally\n\r"); return bytes; } int module_stop(void) { int ret; DBG("ivona: stop()\n"); ivona_stop = 1; if (module_audio_id) { DBG("Stopping audio"); ret = spd_audio_stop(module_audio_id); if (ret != 0) DBG("WARNING: Non 0 value from spd_audio_stop: %d", ret); } return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (ivona_speaking) { DBG("Ivona doesn't support pause, stopping\n"); module_stop(); return -1; } else { return 0; } } int module_close(void) { DBG("ivona: close()\n"); DBG("Stopping speech"); if (ivona_speaking) { module_stop(); } DBG("Terminating threads"); if (module_terminate_thread(ivona_speak_thread) != 0) return -1; sem_destroy(&ivona_semaphore); return 0; } /* Internal functions */ static int get_unichar(char **str) { wchar_t wc; int n; wc = *(*str)++ & 255; if ((wc & 0xe0) == 0xc0) { wc &= 0x1f; n = 1; } else if ((wc & 0xf0) == 0xe0) { wc &= 0x0f; n = 2; } else if ((wc & 0xf8) == 0xf0) { wc &= 0x07; n = 3; } else if ((wc & 0xfc) == 0xf8) { wc &= 0x03; n = 4; } else if ((wc & 0xfe) == 0xfc) { wc &= 0x01; n = 5; } else return wc; while (n--) { if ((**str & 0xc0) != 0x80) { wc = '?'; break; } wc = (wc << 6) | ((*(*str)++) & 0x3f); } return wc; } static int ivona_get_msgpart(struct dumbtts_conf *conf, SPDMessageType type, char **msg, char *icon, char **buf, int *len, int cap_mode, char *delimeters, int punct_mode, char *punct_some) { int rc; int isicon; int n, bytes; unsigned int pos; wchar_t wc; char xbuf[1024]; if (!*msg) return 1; if (!**msg) return 1; isicon = 0; icon[0] = 0; if (*buf) **buf = 0; DBG("Ivona message %s type %d\n", *msg, type); switch (type) { case SPD_MSGTYPE_SOUND_ICON: if (strlen(*msg) < 63) { strcpy(icon, *msg); rc = 0; } else { rc = 1; } *msg = NULL; return rc; case SPD_MSGTYPE_SPELL: wc = get_unichar(msg); if (!wc) { *msg = NULL; return 1; } n = dumbtts_WCharString(conf, wc, *buf, *len, cap_mode, &isicon); if (n > 0) { *len = n + 128; *buf = g_realloc(*buf, *len); n = dumbtts_WCharString(conf, wc, *buf, *len, cap_mode, &isicon); } if (n) { *msg = NULL; return 1; } if (isicon) strcpy(icon, "capital"); return 0; case SPD_MSGTYPE_KEY: case SPD_MSGTYPE_CHAR: if (type == SPD_MSGTYPE_KEY) { n = dumbtts_KeyString(conf, *msg, *buf, *len, cap_mode, &isicon); } else { n = dumbtts_CharString(conf, *msg, *buf, *len, cap_mode, &isicon); } DBG("Got n=%d", n); if (n > 0) { *len = n + 128; *buf = g_realloc(*buf, *len); if (type == SPD_MSGTYPE_KEY) { n = dumbtts_KeyString(conf, *msg, *buf, *len, cap_mode, &isicon); } else { n = dumbtts_CharString(conf, *msg, *buf, *len, cap_mode, &isicon); } } *msg = NULL; if (!n && isicon) strcpy(icon, "capital"); return n; case SPD_MSGTYPE_TEXT: pos = 0; bytes = module_get_message_part(*msg, xbuf, &pos, 1023, delimeters); DBG("Got bytes %d, %s", bytes, xbuf); if (bytes <= 0) { *msg = NULL; return 1; } *msg += pos; xbuf[bytes] = 0; n = dumbtts_GetString(conf, xbuf, *buf, *len, punct_mode, punct_some, ",.;:!?"); if (n > 0) { *len = n + 128; *buf = g_realloc(*buf, *len); n = dumbtts_GetString(conf, xbuf, *buf, *len, punct_mode, punct_some, ",.;:!?"); } if (n) { *msg = NULL; return 1; } DBG("Returning to Ivona |%s|", *buf); return 0; default: *msg = NULL; DBG("Unknown message type\n"); return 1; } } void *_ivona_speak(void *nothing) { AudioTrack track; char *buf; int len; char *msg, *audio; char icon[64]; int samples, offset; int fd; char *next_audio; int next_samples, next_offset; char next_icon[64]; char next_cache[16]; DBG("ivona: speaking thread starting.......\n"); set_speaking_thread_parameters(); while (1) { sem_wait(&ivona_semaphore); DBG("Semaphore on\n"); ivona_stop = 0; ivona_speaking = 1; module_report_event_begin(); msg = *ivona_message; DBG("To say: %s\n", msg); buf = NULL; len = 0; fd = -1; audio = NULL; next_audio = NULL; next_icon[0] = 0; while (1) { if (ivona_stop) { DBG("Stop in child, terminating"); ivona_speaking = 0; module_report_event_stop(); break; } audio = NULL; if (next_audio) { audio = next_audio; samples = next_samples; offset = next_offset; strcpy(icon, next_icon); next_audio = NULL; DBG("Got wave from next_audio"); } else if (fd >= 0) { audio = ivona_get_wave_fd(fd, &samples, &offset); strcpy(icon, next_icon); if (audio && next_cache[0]) { ivona_store_wave_in_cache(next_cache, audio + 2 * offset, samples); } fd = -1; DBG("Got wave from fd"); } else if (next_icon[0]) { strcpy(icon, next_icon); DBG("Got icon"); } if (!audio && !icon[0]) { if (!msg || !*msg || ivona_get_msgpart(ivona_conf, ivona_message_type, &msg, icon, &buf, &len, ivona_cap_mode, IvonaDelimiters, ivona_punct_mode, IvonaPunctuationSome)) { ivona_speaking = 0; if (ivona_stop) module_report_event_stop(); else module_report_event_end(); break; } if (buf && *buf) { audio = ivona_get_wave(buf, &samples, &offset); DBG("Got wave from direct"); } } /* tu mamy audio albo icon, mozna gadac */ if (ivona_stop) { DBG("Stop in child, terminating"); ivona_speaking = 0; module_report_event_stop(); break; } next_icon[0] = 0; if (msg && *msg) { if (!ivona_get_msgpart (ivona_conf, ivona_message_type, &msg, next_icon, &buf, &len, ivona_cap_mode, IvonaDelimiters, ivona_punct_mode, IvonaPunctuationSome)) { if (buf && *buf) { next_offset = 0; next_audio = ivona_get_wave_from_cache (buf, &next_samples); if (!next_audio) { DBG("Sending %s to ivona", buf); next_cache[0] = 0; if (strlen(buf) <= IVONA_CACHE_MAX_STRLEN) strcpy (next_cache, buf); fd = ivona_send_string (buf); } } } } if (ivona_stop) { DBG("Stop in child, terminating"); ivona_speaking = 0; module_report_event_stop(); break; } if (icon[0]) { play_icon(IvonaSoundIconPath, icon); if (ivona_stop) { ivona_speaking = 0; module_report_event_stop(); break; } icon[0] = 0; } if (audio) { track.num_samples = samples; track.num_channels = 1; track.sample_rate = IvonaSampleFreq; track.bits = 16; track.samples = ((short *)audio) + offset; DBG("Got %d samples", track.num_samples); module_tts_output(track, SPD_AUDIO_LE); g_free(audio); audio = NULL; } if (ivona_stop) { ivona_speaking = 0; module_report_event_stop(); break; } } ivona_stop = 0; g_free(buf); g_free(audio); g_free(next_audio); if (fd >= 0) close(fd); fd = -1; audio = NULL; next_audio = NULL; } ivona_speaking = 0; DBG("Ivona: speaking thread ended.......\n"); pthread_exit(NULL); } static void ivona_set_volume(signed int volume) { assert(volume >= -100 && volume <= +100); ivona_volume = volume; } static void ivona_set_cap_let_recogn(SPDCapitalLetters cap_mode) { ivona_cap_mode = 0; switch (cap_mode) { case SPD_CAP_SPELL: ivona_cap_mode = 2; break; case SPD_CAP_ICON: ivona_cap_mode = 1; break; case SPD_CAP_NONE: ivona_cap_mode = 0; break; } if (ivona_cap_mode < IvonaMinCapLet) { ivona_cap_mode = IvonaMinCapLet; } } static void ivona_set_punctuation_mode(SPDPunctuation punct_mode) { ivona_punct_mode = 1; switch (punct_mode) { case SPD_PUNCT_ALL: ivona_punct_mode = 2; break; case SPD_PUNCT_SOME: ivona_punct_mode = 1; break; case SPD_PUNCT_NONE: ivona_punct_mode = 0; break; } } speech-dispatcher-0.9.1/src/modules/ibmtts.c0000644000175000017500000016063013430032457015751 00000000000000/* * ibmtts.c - Speech Dispatcher backend for IBM TTS * * Copyright (C) 2006, 2007 Brailcom, o.p.s. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * @author Gary Cramblitt (original author) * * $Id: ibmtts.c,v 1.30 2008-06-30 14:34:02 gcasse Exp $ */ /* This output module operates with four threads: The main thread called from Speech Dispatcher (module_*()). A synthesis thread that accepts messages, parses them, and forwards them to the IBM TTS via the Eloquence Command Interface (ECI). This thread receives audio and index mark callbacks from IBM TTS and queues them into a playback queue. See _ibmtts_synth(). A playback thread that acts on entries in the playback queue, either sending them to the audio output module (module_tts_output()), or emitting Speech Dispatcher events. See _ibmtts_play(). A thread which is used to stop or pause the synthesis and playback threads. See _ibmtts_stop_or_pause(). Semaphores and mutexes are used to mediate between the 4 threads. TODO: - Support list_synthesis_voices() - Limit amout of waveform data synthesised in advance. - Use SSML mark feature of ibmtts instead of handcrafted parsing. */ #ifdef HAVE_CONFIG_H #include #endif /* System includes. */ #include #include #include /* IBM Eloquence Command Interface. */ #include /* Speech Dispatcher includes. */ #include "spd_audio.h" #include #include "module_utils.h" typedef enum { IBMTTS_FALSE, IBMTTS_TRUE } TIbmttsBool; typedef enum { FATAL_ERROR = -1, OK = 0, ERROR = 1 } TIbmttsSuccess; /* TODO: These defines are in src/server/index_marking.h, but including that file here causes a redefinition error on FATAL macro in speechd.h. */ #define SD_MARK_BODY_LEN 6 #define SD_MARK_BODY "__spd_" #define SD_MARK_HEAD "" #define SD_MARK_HEAD_ONLY "data.list[0]); \ if (NULL != cmd->data.list[1]) \ new_item->arg2 = g_strdup(cmd->data.list[1]); \ else \ new_item->arg2 = NULL; \ if (NULL != cmd->data.list[2]) \ new_item->arg3 = g_strdup(cmd->data.list[2]); \ else \ new_item->arg3 = NULL; \ dll = g_hash_table_lookup(name, new_key); \ dll = g_list_append(dll, new_item); \ g_hash_table_insert(name, new_key, dll); \ return NULL; \ } /* Load a double-linked list from config file. */ #define MOD_OPTION_HT_DLL_REG(name) \ name = g_hash_table_new(g_str_hash, g_str_equal); \ module_dc_options = module_add_config_option(module_dc_options, \ &module_num_dc_options, #name, \ ARG_LIST, name ## _cb, NULL, 0); /* Define a hash table mapping a string to 7 integer values. */ #define MOD_OPTION_6_INT_HT(name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ typedef struct{ \ int arg1; \ int arg2; \ int arg3; \ int arg4; \ int arg5; \ int arg6; \ int arg7; \ }T ## name; \ GHashTable *name; \ \ DOTCONF_CB(name ## _cb) \ { \ T ## name *new_item; \ char* new_key; \ new_item = (T ## name *) g_malloc(sizeof(T ## name)); \ if (cmd->data.list[0] == NULL) return NULL; \ new_key = g_strdup(cmd->data.list[0]); \ new_item->arg1 = (int) strtol(cmd->data.list[1], NULL, 10); \ new_item->arg2 = (int) strtol(cmd->data.list[2], NULL, 10); \ new_item->arg3 = (int) strtol(cmd->data.list[3], NULL, 10); \ new_item->arg4 = (int) strtol(cmd->data.list[4], NULL, 10); \ new_item->arg5 = (int) strtol(cmd->data.list[5], NULL, 10); \ new_item->arg6 = (int) strtol(cmd->data.list[6], NULL, 10); \ new_item->arg7 = (int) strtol(cmd->data.list[7], NULL, 10); \ g_hash_table_insert(name, new_key, new_item); \ return NULL; \ } /* Thread and process control. */ static pthread_t ibmtts_synth_thread; static pthread_t ibmtts_play_thread; static pthread_t ibmtts_stop_or_pause_thread; static sem_t ibmtts_synth_semaphore; static sem_t ibmtts_play_semaphore; static sem_t ibmtts_stop_or_pause_semaphore; static pthread_mutex_t ibmtts_synth_suspended_mutex; static pthread_mutex_t ibmtts_play_suspended_mutex; static pthread_mutex_t ibmtts_stop_or_pause_suspended_mutex; static TIbmttsBool ibmtts_thread_exit_requested = IBMTTS_FALSE; static TIbmttsBool ibmtts_stop_synth_requested = IBMTTS_FALSE; static TIbmttsBool ibmtts_stop_play_requested = IBMTTS_FALSE; static TIbmttsBool ibmtts_pause_requested = IBMTTS_FALSE; /* Current message from Speech Dispatcher. */ static char **ibmtts_message; static SPDMessageType ibmtts_message_type; /* ECI */ static ECIHand eciHandle = NULL_ECI_HAND; static int eci_sample_rate = 0; /* ECI sends audio back in chunks to this buffer. The smaller the buffer, the higher the overhead, but the better the index mark resolution. */ typedef signed short int TEciAudioSamples; static TEciAudioSamples *audio_chunk; /* For some reason, these were left out of eci.h. */ typedef enum { eciTextModeDefault = 0, eciTextModeAlphaSpell = 1, eciTextModeAllSpell = 2, eciIRCSpell = 3 } ECITextMode; /* The playback queue. */ typedef enum { IBMTTS_QET_AUDIO, /* Chunk of audio. */ IBMTTS_QET_INDEX_MARK, /* Index mark event. */ IBMTTS_QET_SOUND_ICON, /* A Sound Icon */ IBMTTS_QET_BEGIN, /* Beginning of speech. */ IBMTTS_QET_END /* Speech completed. */ } EPlaybackQueueEntryType; typedef struct { long num_samples; TEciAudioSamples *audio_chunk; } TPlaybackQueueAudioChunk; typedef struct { EPlaybackQueueEntryType type; union { long markId; TPlaybackQueueAudioChunk audio; char *sound_icon_filename; } data; } TPlaybackQueueEntry; static GSList *playback_queue = NULL; static pthread_mutex_t playback_queue_mutex; /* A lookup table for index mark name given integer id. */ GHashTable *ibmtts_index_mark_ht = NULL; #define IBMTTS_MSG_END_MARK 0 pthread_mutex_t sound_stop_mutex; /* When a voice is set, this is the baseline pitch of the voice. SSIP PITCH commands then adjust relative to this. */ int ibmtts_voice_pitch_baseline; /* When a voice is set, this the default speed of the voice. SSIP RATE commands then adjust relative to this. */ int ibmtts_voice_speed; /* Expected input encoding for current language dialect. */ static char *ibmtts_input_encoding = "cp1252"; /* list of voices */ static SPDVoice **ibmtts_voice_list = NULL; static int *ibmtts_voice_index = NULL; /* Internal function prototypes for main thread. */ static void ibmtts_set_language(char *lang); static void ibmtts_set_voice(SPDVoiceType voice); static char *ibmtts_voice_enum_to_str(SPDVoiceType voice); static void ibmtts_set_language_and_voice(char *lang, SPDVoiceType voice, char *dialect); static void ibmtts_set_synthesis_voice(char *); static void ibmtts_set_rate(signed int rate); static void ibmtts_set_pitch(signed int pitch); static void ibmtts_set_punctuation_mode(SPDPunctuation punct_mode); static void ibmtts_set_volume(signed int pitch); /* locale_index_atomic stores the current index of the eciLocales array. The main thread writes this information, the synthesis thread reads it. */ static gint locale_index_atomic; /* Internal function prototypes for synthesis thread. */ static char *ibmtts_extract_mark_name(char *mark); static char *ibmtts_next_part(char *msg, char **mark_name); static int ibmtts_replace(char *from, char *to, GString * msg); static void ibmtts_subst_keys_cb(gpointer data, gpointer user_data); static char *ibmtts_subst_keys(char *key); static char *ibmtts_search_for_sound_icon(const char *icon_name); static TIbmttsBool ibmtts_add_sound_icon_to_playback_queue(char *filename); static void ibmtts_load_user_dictionary(); static enum ECICallbackReturn eciCallback(ECIHand hEngine, enum ECIMessage msg, long lparam, void *data); /* Internal function prototypes for playback thread. */ static TIbmttsBool ibmtts_add_audio_to_playback_queue(TEciAudioSamples * audio_chunk, long num_samples); static TIbmttsBool ibmtts_add_mark_to_playback_queue(long markId); static TIbmttsBool ibmtts_add_flag_to_playback_queue(EPlaybackQueueEntryType type); static void ibmtts_delete_playback_queue_entry(TPlaybackQueueEntry * playback_queue_entry); static TIbmttsBool ibmtts_send_to_audio(TPlaybackQueueEntry * playback_queue_entry); /* Miscellaneous internal function prototypes. */ static TIbmttsBool is_thread_busy(pthread_mutex_t * suspended_mutex); static void ibmtts_log_eci_error(); static void ibmtts_clear_playback_queue(); static void alloc_voice_list(); static void free_voice_list(); /* The synthesis thread start routine. */ static void *_ibmtts_synth(void *); /* The playback thread start routine. */ static void *_ibmtts_play(void *); /* The stop_or_pause start routine. */ static void *_ibmtts_stop_or_pause(void *); /* Module configuration options. */ MOD_OPTION_1_INT(IbmttsUseSSML); MOD_OPTION_1_STR(IbmttsPunctuationList); MOD_OPTION_1_INT(IbmttsUseAbbreviation); MOD_OPTION_1_STR(IbmttsDictionaryFolder); MOD_OPTION_1_INT(IbmttsAudioChunkSize); MOD_OPTION_1_STR(IbmttsSoundIconFolder); MOD_OPTION_6_INT_HT(IbmttsVoiceParameters, gender, breathiness, head_size, pitch_baseline, pitch_fluctuation, roughness, speed); MOD_OPTION_3_STR_HT_DLL(IbmttsKeySubstitution, lang, key, newkey); typedef struct _eciLocale { char *name; char *lang; char *dialect; enum ECILanguageDialect langID; char *charset; } eciLocale, *eciLocaleList; static eciLocale eciLocales[] = { { "American_English", "en", "US", eciGeneralAmericanEnglish, "ISO-8859-1"}, {"British_English", "en", "GB", eciBritishEnglish, "ISO-8859-1"}, {"Castilian_Spanish", "es", "ES", eciCastilianSpanish, "ISO-8859-1"}, {"Mexican_Spanish", "es", "MX", eciMexicanSpanish, "ISO-8859-1"}, {"French", "fr", "FR", eciStandardFrench, "ISO-8859-1"}, {"Canadian_French", "ca", "FR", eciCanadianFrench, "ISO-8859-1"}, {"German", "de", "DE", eciStandardGerman, "ISO-8859-1"}, {"Italian", "it", "IT", eciStandardItalian, "ISO-8859-1"}, {"Mandarin_Chinese", "zh", "CN", eciMandarinChinese, "GBK"}, {"Mandarin_Chinese GB", "zh", "CN_GB", eciMandarinChineseGB, "GBK"}, { "Mandarin_Chinese PinYin", "zh", "CN_PinYin", eciMandarinChinesePinYin, "GBK"}, {"Mandarin_Chinese UCS", "zh", "CN_UCS", eciMandarinChineseUCS, "UCS2"}, {"Taiwanese_Mandarin", "zh", "TW", eciTaiwaneseMandarin, "BIG5"}, { "Taiwanese_Mandarin Big 5", "zh", "TW_Big5", eciTaiwaneseMandarinBig5, "BIG5"}, { "Taiwanese_Mandarin ZhuYin", "zh", "TW_ZhuYin", eciTaiwaneseMandarinZhuYin, "BIG5"}, { "Taiwanese_Mandarin PinYin", "zh", "TW_PinYin", eciTaiwaneseMandarinPinYin, "BIG5"}, { "Taiwanese_Mandarin UCS", "zh", "TW_UCS", eciTaiwaneseMandarinUCS, "UCS2"}, { "Brazilian_Portuguese", "pt", "BR", eciBrazilianPortuguese, "ISO-8859-1"}, {"Japanese", "ja", "JP", eciStandardJapanese, "SJIS"}, {"Japanese_SJIS", "ja", "JP_SJIS", eciStandardJapaneseSJIS, "SJIS"}, {"Japanese_UCS", "ja", "JP_UCS", eciStandardJapaneseUCS, "UCS2"}, {"Finnish", "fi", "FI", eciStandardFinnish, "ISO-8859-1"}, {"Korean", "ko", "KR", eciStandardKorean, "UHC"}, {"Korean_UHC", "ko", "KR_UHC", eciStandardKoreanUHC, "UHC"}, {"Korean_UCS", "ko", "KR_UCS", eciStandardKoreanUCS, "UCS2"}, {"Cantonese", "zh", "HK", eciStandardCantonese, "GBK"}, {"Cantonese_GB", "zh", "HK_GB", eciStandardCantoneseGB, "GBK"}, {"Cantonese_UCS", "zh", "HK_UCS", eciStandardCantoneseUCS, "UCS2"}, {"HongKong_Cantonese", "zh", "HK", eciHongKongCantonese, "BIG5"}, { "HongKong_Cantonese Big 5", "zh", "HK_BIG5", eciHongKongCantoneseBig5, "BIG5"}, { "HongKong_Cantonese UCS", "zh", "HK_UCS", eciHongKongCantoneseUCS, "UCS-2"}, {"Dutch", "nl", "BE", eciStandardDutch, "ISO-8859-1"}, {"Norwegian", "no", "NO", eciStandardNorwegian, "ISO-8859-1"}, {"Swedish", "sv", "SE", eciStandardSwedish, "ISO-8859-1"}, {"Danish", "da", "DK", eciStandardDanish, "ISO-8859-1"}, {"Reserved", "en", "US", eciStandardReserved, "ISO-8859-1"}, {"Thai", "th", "TH", eciStandardThai, "TIS-620"}, {"ThaiTIS", "th", "TH_TIS", eciStandardThaiTIS, "TIS-620"}, {NULL, 0, NULL} }; #define MAX_NB_OF_LANGUAGES (sizeof(eciLocales)/sizeof(eciLocales[0]) - 1) /* dictionary_filename: its index corresponds to the ECIDictVolume enumerate */ static char *dictionary_filenames[] = { "main.dct", "root.dct", "abbreviation.dct", "extension.dct" }; #define NB_OF_DICTIONARY_FILENAMES (sizeof(dictionary_filenames)/sizeof(dictionary_filenames[0])) /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); MOD_OPTION_1_INT_REG(IbmttsUseSSML, 1); MOD_OPTION_1_INT_REG(IbmttsUseAbbreviation, 1); MOD_OPTION_1_STR_REG(IbmttsPunctuationList, "()?"); MOD_OPTION_1_STR_REG(IbmttsDictionaryFolder, "/var/opt/IBM/ibmtts/dict"); MOD_OPTION_1_INT_REG(IbmttsAudioChunkSize, 20000); MOD_OPTION_1_STR_REG(IbmttsSoundIconFolder, "/usr/share/sounds/sound-icons/"); /* Register voices. */ module_register_settings_voices(); /* Register voice parameters */ MOD_OPTION_HT_REG(IbmttsVoiceParameters); /* Register key substitutions. */ MOD_OPTION_HT_DLL_REG(IbmttsKeySubstitution); return OK; } int module_init(char **status_info) { int ret; char ibmVersion[20]; int ibm_sample_rate; DBG("Ibmtts: Module init()."); INIT_INDEX_MARKING(); *status_info = NULL; ibmtts_thread_exit_requested = IBMTTS_FALSE; /* Report versions. */ eciVersion(ibmVersion); DBG("Ibmtts: IBM TTS Output Module version %s, IBM TTS Engine version %s", MODULE_VERSION, ibmVersion); /* Setup IBM TTS engine. */ DBG("Ibmtts: Creating ECI instance."); eciHandle = eciNew(); if (NULL_ECI_HAND == eciHandle) { DBG("Ibmtts: Could not create ECI instance.\n"); *status_info = g_strdup("Could not create ECI instance. " "Is the IBM TTS engine installed?"); return FATAL_ERROR; } /* Get ECI audio sample rate. */ ibm_sample_rate = eciGetParam(eciHandle, eciSampleRate); switch (ibm_sample_rate) { case 0: eci_sample_rate = 8000; break; case 1: eci_sample_rate = 11025; break; case 2: eci_sample_rate = 22050; break; default: DBG("Ibmtts: Invalid audio sample rate returned by ECI = %i", ibm_sample_rate); } /* Allocate a chunk for ECI to return audio. */ audio_chunk = (TEciAudioSamples *) g_malloc((IbmttsAudioChunkSize) * sizeof(TEciAudioSamples)); DBG("Ibmtts: Registering ECI callback."); eciRegisterCallback(eciHandle, eciCallback, NULL); DBG("Ibmtts: Registering an ECI audio buffer."); if (!eciSetOutputBuffer(eciHandle, IbmttsAudioChunkSize, audio_chunk)) { DBG("Ibmtts: Error registering ECI audio buffer."); ibmtts_log_eci_error(); } eciSetParam(eciHandle, eciDictionary, !IbmttsUseAbbreviation); /* enable annotations */ eciSetParam(eciHandle, eciInputType, 1); /* load possibly the ssml filter */ eciAddText(eciHandle, " `gfa1 "); /* load possibly the punctuation filter */ eciAddText(eciHandle, " `gfa2 "); ibmtts_set_punctuation_mode(msg_settings.punctuation_mode); alloc_voice_list(); /* These mutexes are locked when the corresponding threads are suspended. */ pthread_mutex_init(&ibmtts_synth_suspended_mutex, NULL); pthread_mutex_init(&ibmtts_play_suspended_mutex, NULL); /* This mutex is used to hold a stop request until audio actually stops. */ pthread_mutex_init(&sound_stop_mutex, NULL); /* This mutex mediates access to the playback queue between the synthesis and playback threads. */ pthread_mutex_init(&playback_queue_mutex, NULL); DBG("Ibmtts: ImbttsAudioChunkSize = %d", IbmttsAudioChunkSize); ibmtts_message = g_malloc(sizeof(char *)); *ibmtts_message = NULL; DBG("Ibmtts: Creating new thread for stop or pause."); sem_init(&ibmtts_stop_or_pause_semaphore, 0, 0); ret = pthread_create(&ibmtts_stop_or_pause_thread, NULL, _ibmtts_stop_or_pause, NULL); if (0 != ret) { DBG("Ibmtts: stop or pause thread creation failed."); *status_info = g_strdup ("The module couldn't initialize stop or pause thread. " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return FATAL_ERROR; } DBG("Ibmtts: Creating new thread for playback."); sem_init(&ibmtts_play_semaphore, 0, 0); ret = pthread_create(&ibmtts_play_thread, NULL, _ibmtts_play, NULL); if (0 != ret) { DBG("Ibmtts: play thread creation failed."); *status_info = g_strdup("The module couldn't initialize play thread. " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return FATAL_ERROR; } DBG("Ibmtts: Creating new thread for IBM TTS synthesis."); sem_init(&ibmtts_synth_semaphore, 0, 0); ret = pthread_create(&ibmtts_synth_thread, NULL, _ibmtts_synth, NULL); if (0 != ret) { DBG("Ibmtts: synthesis thread creation failed."); *status_info = g_strdup("The module couldn't initialize synthesis thread. " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return FATAL_ERROR; } *status_info = g_strdup("Ibmtts: Initialized successfully."); return OK; } SPDVoice **module_list_voices(void) { DBG("Ibmtts: %s", __FUNCTION__); return ibmtts_voice_list; } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { DBG("Ibmtts: module_speak()."); if (is_thread_busy(&ibmtts_synth_suspended_mutex) || is_thread_busy(&ibmtts_play_suspended_mutex) || is_thread_busy(&ibmtts_stop_or_pause_suspended_mutex)) { DBG("Ibmtts: Already synthesizing when requested to synthesize (module_speak)."); return IBMTTS_FALSE; } DBG("Ibmtts: Type: %d, bytes: %lu, requested data: |%s|\n", msgtype, (unsigned long)bytes, data); g_free(*ibmtts_message); *ibmtts_message = NULL; if (!g_utf8_validate(data, bytes, NULL)) { DBG("Ibmtts: Input is not valid utf-8."); /* Actually, we should just fail here, but let's assume input is latin-1 */ *ibmtts_message = g_convert(data, bytes, "utf-8", "iso-8859-1", NULL, NULL, NULL); if (*ibmtts_message == NULL) { DBG("Ibmtts: Fallback conversion to utf-8 failed."); return FALSE; } } else { *ibmtts_message = g_strndup(data, bytes); } ibmtts_message_type = msgtype; if ((msgtype == SPD_MSGTYPE_TEXT) && (msg_settings.spelling_mode == SPD_SPELL_ON)) ibmtts_message_type = SPD_MSGTYPE_SPELL; /* Setting speech parameters. */ UPDATE_STRING_PARAMETER(voice.language, ibmtts_set_language); UPDATE_PARAMETER(voice_type, ibmtts_set_voice); UPDATE_STRING_PARAMETER(voice.name, ibmtts_set_synthesis_voice); UPDATE_PARAMETER(rate, ibmtts_set_rate); UPDATE_PARAMETER(volume, ibmtts_set_volume); UPDATE_PARAMETER(pitch, ibmtts_set_pitch); UPDATE_PARAMETER(punctuation_mode, ibmtts_set_punctuation_mode); /* TODO: Handle these in _ibmtts_synth() ? UPDATE_PARAMETER(cap_let_recogn, festival_set_cap_let_recogn); */ if (!IbmttsUseSSML) { /* Strip all SSML */ char *tmp = *ibmtts_message; *ibmtts_message = module_strip_ssml(*ibmtts_message); g_free(tmp); /* Convert input to suitable encoding for current language dialect */ tmp = g_convert_with_fallback(*ibmtts_message, -1, ibmtts_input_encoding, "utf-8", "?", NULL, &bytes, NULL); if (tmp != NULL) { g_free(*ibmtts_message); *ibmtts_message = tmp; } } /* Send semaphore signal to the synthesis thread */ sem_post(&ibmtts_synth_semaphore); DBG("Ibmtts: Leaving module_speak() normally."); return TRUE; } int module_stop(void) { DBG("Ibmtts: module_stop()."); if ((is_thread_busy(&ibmtts_synth_suspended_mutex) || is_thread_busy(&ibmtts_play_suspended_mutex)) && !is_thread_busy(&ibmtts_stop_or_pause_suspended_mutex)) { /* Request both synth and playback threads to stop what they are doing (if anything). */ ibmtts_stop_synth_requested = IBMTTS_TRUE; ibmtts_stop_play_requested = IBMTTS_TRUE; /* Wake the stop_or_pause thread. */ sem_post(&ibmtts_stop_or_pause_semaphore); } return OK; } size_t module_pause(void) { /* The semantics of module_pause() is the same as module_stop() except that processing should continue until the next index mark is reached before stopping. Note that although IBM TTS offers an eciPause function, we cannot make use of it because Speech Dispatcher doesn't have a module_resume function. Instead, Speech Dispatcher resumes by calling module_speak from the last index mark reported in the text. */ DBG("Ibmtts: module_pause()."); /* Request playback thread to pause. Note we cannot stop synthesis or playback until end of sentence or end of message is played. */ ibmtts_pause_requested = IBMTTS_TRUE; /* Wake the stop_or_pause thread. */ sem_post(&ibmtts_stop_or_pause_semaphore); return OK; } int module_close(void) { DBG("Ibmtts: close()."); if (is_thread_busy(&ibmtts_synth_suspended_mutex) || is_thread_busy(&ibmtts_play_suspended_mutex)) { DBG("Ibmtts: Stopping speech"); module_stop(); } DBG("Ibmtts: De-registering ECI callback."); eciRegisterCallback(eciHandle, NULL, NULL); DBG("Ibmtts: Destroying ECI instance."); eciDelete(eciHandle); eciHandle = NULL_ECI_HAND; /* Free buffer for ECI audio. */ g_free(audio_chunk); /* Request each thread exit and wait until it exits. */ DBG("Ibmtts: Terminating threads"); ibmtts_thread_exit_requested = IBMTTS_TRUE; sem_post(&ibmtts_synth_semaphore); sem_post(&ibmtts_play_semaphore); sem_post(&ibmtts_stop_or_pause_semaphore); if (0 != pthread_join(ibmtts_synth_thread, NULL)) return -1; if (0 != pthread_join(ibmtts_play_thread, NULL)) return -1; if (0 != pthread_join(ibmtts_stop_or_pause_thread, NULL)) return -1; ibmtts_clear_playback_queue(); /* Free index mark lookup table. */ if (ibmtts_index_mark_ht) { g_hash_table_destroy(ibmtts_index_mark_ht); ibmtts_index_mark_ht = NULL; } free_voice_list(); sem_destroy(&ibmtts_synth_semaphore); sem_destroy(&ibmtts_play_semaphore); sem_destroy(&ibmtts_stop_or_pause_semaphore); return 0; } /* Internal functions */ /* Return true if the thread is busy, i.e., suspended mutex is not locked. */ static TIbmttsBool is_thread_busy(pthread_mutex_t * suspended_mutex) { if (EBUSY == pthread_mutex_trylock(suspended_mutex)) return IBMTTS_FALSE; else { pthread_mutex_unlock(suspended_mutex); return IBMTTS_TRUE; } } /* Given a string containing an index mark in the form , returns some_name. Calling routine is responsible for freeing returned string. If an error occurs, returns NULL. */ static char *ibmtts_extract_mark_name(char *mark) { if ((SD_MARK_HEAD_ONLY_LEN + SD_MARK_TAIL_LEN + 1) > strlen(mark)) return NULL; mark = mark + SD_MARK_HEAD_ONLY_LEN; char *tail = strstr(mark, SD_MARK_TAIL); if (NULL == tail) return NULL; return (char *)g_strndup(mark, tail - mark); } /* Returns the portion of msg up to, but not including, the next index mark, or end of msg if no index mark is found. If msg begins with and index mark, returns the entire index mark clause () and returns the mark name. If msg does not begin with an index mark, mark_name will be NULL. If msg is empty, returns a zero-length string (not NULL). Caller is responsible for freeing both returned string and mark_name (if not NULL). */ /* TODO: This routine needs to be more tolerant of custom index marks with spaces. */ /* TODO: Should there be a MaxChunkLength? Delimiters? */ static char *ibmtts_next_part(char *msg, char **mark_name) { char *mark_head = strstr(msg, SD_MARK_HEAD_ONLY); if (NULL == mark_head) return (char *)g_strndup(msg, strlen(msg)); else if (mark_head == msg) { *mark_name = ibmtts_extract_mark_name(mark_head); if (NULL == *mark_name) return strcat((char *) g_strndup(msg, SD_MARK_HEAD_ONLY_LEN), ibmtts_next_part(msg + SD_MARK_HEAD_ONLY_LEN, mark_name)); else return (char *)g_strndup(msg, SD_MARK_HEAD_ONLY_LEN + strlen(*mark_name) + SD_MARK_TAIL_LEN); } else return (char *)g_strndup(msg, mark_head - msg); } /* Stop or Pause thread. */ static void *_ibmtts_stop_or_pause(void *nothing) { DBG("Ibmtts: Stop or pause thread starting.......\n"); /* Block all signals to this thread. */ set_speaking_thread_parameters(); while (!ibmtts_thread_exit_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&ibmtts_stop_or_pause_semaphore)) { pthread_mutex_lock (&ibmtts_stop_or_pause_suspended_mutex); sem_wait(&ibmtts_stop_or_pause_semaphore); pthread_mutex_unlock (&ibmtts_stop_or_pause_suspended_mutex); if (ibmtts_thread_exit_requested) break; } DBG("Ibmtts: Stop or pause semaphore on."); /* The following is a hack. The condition should never be true, but sometimes it is true for unclear reasons. */ if (!(ibmtts_stop_synth_requested || ibmtts_pause_requested)) continue; if (ibmtts_stop_synth_requested) { /* Stop synthesis (if in progress). */ if (eciHandle) { DBG("Ibmtts: Stopping synthesis."); eciStop(eciHandle); } /* Stop any audio playback (if in progress). */ if (module_audio_id) { pthread_mutex_lock(&sound_stop_mutex); DBG("Ibmtts: Stopping audio."); int ret = spd_audio_stop(module_audio_id); if (0 != ret) DBG("Ibmtts: WARNING: Non 0 value from spd_audio_stop: %d", ret); pthread_mutex_unlock(&sound_stop_mutex); } } DBG("Ibmtts: Waiting for synthesis thread to suspend."); while (is_thread_busy(&ibmtts_synth_suspended_mutex)) g_usleep(100); DBG("Ibmtts: Waiting for playback thread to suspend."); while (is_thread_busy(&ibmtts_play_suspended_mutex)) g_usleep(100); DBG("Ibmtts: Clearing playback queue."); ibmtts_clear_playback_queue(); DBG("Ibmtts: Clearing index mark lookup table."); if (ibmtts_index_mark_ht) { g_hash_table_destroy(ibmtts_index_mark_ht); ibmtts_index_mark_ht = NULL; } if (ibmtts_stop_synth_requested) module_report_event_stop(); else module_report_event_pause(); ibmtts_stop_synth_requested = IBMTTS_FALSE; ibmtts_stop_play_requested = IBMTTS_FALSE; ibmtts_pause_requested = IBMTTS_FALSE; DBG("Ibmtts: Stop or pause completed."); } DBG("Ibmtts: Stop or pause thread ended.......\n"); pthread_exit(NULL); } static int process_text_mark(char *part, int part_len, char *mark_name) { /* Handle index marks. */ if (NULL != mark_name) { /* Assign the mark name an integer number and store in lookup table. */ int *markId = (int *)g_malloc(sizeof(int)); *markId = 1 + g_hash_table_size(ibmtts_index_mark_ht); g_hash_table_insert(ibmtts_index_mark_ht, markId, mark_name); if (!eciInsertIndex(eciHandle, *markId)) { DBG("Ibmtts: Error sending index mark to synthesizer."); ibmtts_log_eci_error(); /* Try to keep going. */ } else DBG("Ibmtts: Index mark |%s| (id %i) sent to synthesizer.", mark_name, *markId); /* If pause is requested, skip over rest of message, but synthesize what we have so far. */ if (ibmtts_pause_requested) { DBG("Ibmtts: Pause requested in synthesis thread."); return 1; } return 0; } /* Handle normal text. */ if (part_len > 0) { DBG("Ibmtts: Returned %d bytes from get_part.", part_len); DBG("Ibmtts: Text to synthesize is |%s|\n", part); DBG("Ibmtts: Sending text to synthesizer."); if (!eciAddText(eciHandle, part)) { DBG("Ibmtts: Error sending text."); ibmtts_log_eci_error(); return 2; } return 0; } /* Handle end of text. */ DBG("Ibmtts: End of data in synthesis thread."); /* Add index mark for end of message. This also makes sure the callback gets called at least once */ eciInsertIndex(eciHandle, IBMTTS_MSG_END_MARK); DBG("Ibmtts: Trying to synthesize text."); if (!eciSynthesize(eciHandle)) { DBG("Ibmtts: Error synthesizing."); ibmtts_log_eci_error(); return 2;; } /* Audio and index marks are returned in eciCallback(). */ DBG("Ibmtts: Waiting for synthesis to complete."); if (!eciSynchronize(eciHandle)) { DBG("Ibmtts: Error waiting for synthesis to complete."); ibmtts_log_eci_error(); return 2; } DBG("Ibmtts: Synthesis complete."); return 3; } /* Synthesis thread. */ static void *_ibmtts_synth(void *nothing) { char *pos = NULL; char *part = NULL; int part_len = 0; int ret; DBG("Ibmtts: Synthesis thread starting.......\n"); /* Block all signals to this thread. */ set_speaking_thread_parameters(); /* Allocate a place for index mark names to be placed. */ char *mark_name = NULL; while (!ibmtts_thread_exit_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&ibmtts_synth_semaphore)) { pthread_mutex_lock(&ibmtts_synth_suspended_mutex); sem_wait(&ibmtts_synth_semaphore); pthread_mutex_unlock(&ibmtts_synth_suspended_mutex); if (ibmtts_thread_exit_requested) break; } DBG("Ibmtts: Synthesis semaphore on."); /* This table assigns each index mark name an integer id for fast lookup when ECI returns the integer index mark event. */ if (ibmtts_index_mark_ht) g_hash_table_destroy(ibmtts_index_mark_ht); ibmtts_index_mark_ht = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); pos = *ibmtts_message; ibmtts_load_user_dictionary(); switch (ibmtts_message_type) { case SPD_MSGTYPE_TEXT: eciSetParam(eciHandle, eciTextMode, eciTextModeDefault); break; case SPD_MSGTYPE_SOUND_ICON: /* IBM TTS does not support sound icons. If we can find a sound icon file, play that, otherwise speak the name of the sound icon. */ part = ibmtts_search_for_sound_icon(*ibmtts_message); if (NULL != part) { ibmtts_add_flag_to_playback_queue (IBMTTS_QET_BEGIN); ibmtts_add_sound_icon_to_playback_queue(part); part = NULL; ibmtts_add_flag_to_playback_queue (IBMTTS_QET_END); /* Wake up the audio playback thread, if not already awake. */ if (!is_thread_busy (&ibmtts_play_suspended_mutex)) sem_post(&ibmtts_play_semaphore); continue; } else eciSetParam(eciHandle, eciTextMode, eciTextModeDefault); break; case SPD_MSGTYPE_CHAR: eciSetParam(eciHandle, eciTextMode, eciTextModeAllSpell); break; case SPD_MSGTYPE_KEY: /* Map unspeakable keys to speakable words. */ DBG("Ibmtts: Key from Speech Dispatcher: |%s|", pos); pos = ibmtts_subst_keys(pos); DBG("Ibmtts: Key to speak: |%s|", pos); g_free(*ibmtts_message); *ibmtts_message = pos; eciSetParam(eciHandle, eciTextMode, eciTextModeDefault); break; case SPD_MSGTYPE_SPELL: if (SPD_PUNCT_NONE != msg_settings.punctuation_mode) eciSetParam(eciHandle, eciTextMode, eciTextModeAllSpell); else eciSetParam(eciHandle, eciTextMode, eciTextModeAlphaSpell); break; } ibmtts_add_flag_to_playback_queue(IBMTTS_QET_BEGIN); while (TRUE) { if (ibmtts_stop_synth_requested) { DBG("Ibmtts: Stop in synthesis thread, terminating."); break; } /* TODO: How to map these msg_settings to ibm tts? ESpellMode spelling_mode; SPELLING_ON already handled in module_speak() ECapLetRecogn cap_let_recogn; RECOGN_NONE = 0, RECOGN_SPELL = 1, RECOGN_ICON = 2 */ part = ibmtts_next_part(pos, &mark_name); if (NULL == part) { DBG("Ibmtts: Error getting next part of message."); /* TODO: What to do here? */ break; } part_len = strlen(part); pos += part_len; ret = process_text_mark(part, part_len, mark_name); g_free(part); part = NULL; mark_name = NULL; if (ret == 1) pos += strlen(pos); else if (ret > 1) break; } } DBG("Ibmtts: Synthesis thread ended.......\n"); pthread_exit(NULL); } static void ibmtts_set_rate(signed int rate) { /* Setting rate to midpoint is too fast. An eci value of 50 is "normal". See chart on pg 38 of the ECI manual. */ assert(rate >= -100 && rate <= +100); int speed; /* Possible ECI range is 0 to 250. */ /* Map rate -100 to 100 onto speed 0 to 140. */ if (rate < 0) /* Map -100 to 0 onto 0 to ibmtts_voice_speed */ speed = ((float)(rate + 100) * ibmtts_voice_speed) / (float)100; else /* Map 0 to 100 onto ibmtts_voice_speed to 140 */ speed = (((float)rate * (140 - ibmtts_voice_speed)) / (float)100) + ibmtts_voice_speed; assert(speed >= 0 && speed <= 140); int ret = eciSetVoiceParam(eciHandle, 0, eciSpeed, speed); if (-1 == ret) { DBG("Ibmtts: Error setting rate %i.", speed); ibmtts_log_eci_error(); } else DBG("Ibmtts: Rate set to %i.", speed); } static void ibmtts_set_volume(signed int volume) { /* Setting volume to midpoint makes speech too soft. An eci value of 90 to 100 is "normal". See chart on pg 38 of the ECI manual. TODO: Rather than setting volume in the synth, maybe control volume on playback? */ assert(volume >= -100 && volume <= +100); int vol; /* Possible ECI range is 0 to 100. */ if (volume < 0) /* Map -100 to 0 onto 0 to 90 */ vol = (((float)volume + 100) * 90) / (float)100; else /* Map 0 to 100 onto 90 to 100 */ vol = ((float)(volume * 10) / (float)100) + 90; assert(vol >= 0 && vol <= 100); int ret = eciSetVoiceParam(eciHandle, 0, eciVolume, vol); if (-1 == ret) { DBG("Ibmtts: Error setting volume %i.", vol); ibmtts_log_eci_error(); } else DBG("Ibmtts: Volume set to %i.", vol); } static void ibmtts_set_pitch(signed int pitch) { /* Setting pitch to midpoint is to low. eci values between 65 and 89 are "normal". See chart on pg 38 of the ECI manual. */ assert(pitch >= -100 && pitch <= +100); int pitchBaseline; /* Possible range 0 to 100. */ if (pitch < 0) /* Map -100 to 0 onto 0 to ibmtts_voice_pitch_baseline */ pitchBaseline = ((float)(pitch + 100) * ibmtts_voice_pitch_baseline) / (float)100; else /* Map 0 to 100 onto ibmtts_voice_pitch_baseline to 100 */ pitchBaseline = (((float)pitch * (100 - ibmtts_voice_pitch_baseline)) / (float)100) + ibmtts_voice_pitch_baseline; assert(pitchBaseline >= 0 && pitchBaseline <= 100); int ret = eciSetVoiceParam(eciHandle, 0, eciPitchBaseline, pitchBaseline); if (-1 == ret) { DBG("Ibmtts: Error setting pitch %i.", pitchBaseline); ibmtts_log_eci_error(); } else DBG("Ibmtts: Pitch set to %i.", pitchBaseline); } static void ibmtts_set_punctuation_mode(SPDPunctuation punct_mode) { const char *fmt = "`Pf%d%s"; char *msg = NULL; int real_punct_mode = 0; switch (punct_mode) { case SPD_PUNCT_NONE: real_punct_mode = 0; break; case SPD_PUNCT_SOME: real_punct_mode = 2; break; case SPD_PUNCT_ALL: real_punct_mode = 1; break; } msg = g_strdup_printf(fmt, real_punct_mode, IbmttsPunctuationList); eciAddText(eciHandle, msg); g_free(msg); } static char *ibmtts_voice_enum_to_str(SPDVoiceType voice) { /* TODO: Would be better to move this to module_utils.c. */ char *voicename; switch (voice) { case SPD_MALE1: voicename = g_strdup("male1"); break; case SPD_MALE2: voicename = g_strdup("male2"); break; case SPD_MALE3: voicename = g_strdup("male3"); break; case SPD_FEMALE1: voicename = g_strdup("female1"); break; case SPD_FEMALE2: voicename = g_strdup("female2"); break; case SPD_FEMALE3: voicename = g_strdup("female3"); break; case SPD_CHILD_MALE: voicename = g_strdup("child_male"); break; case SPD_CHILD_FEMALE: voicename = g_strdup("child_female"); break; default: voicename = g_strdup("no voice"); break; } return voicename; } /* Given a language, dialect and SD voice codes sets the IBM voice */ static void ibmtts_set_language_and_voice(char *lang, SPDVoiceType voice, char *variant) { char *variant_name = variant; char *voicename = ibmtts_voice_enum_to_str(voice); int eciVoice; int ret = -1; int i = 0; int j = 0; DBG("Ibmtts: %s, lang=%s, voice=%d, dialect=%s", __FUNCTION__, lang, (int)voice, variant ? variant : NULL); SPDVoice **v = ibmtts_voice_list; assert(v); if (variant_name) { for (i = 0; v[i]; i++) { DBG("%d. variant=%s", i, v[i]->variant); if (!strcmp(v[i]->variant, variant_name)) { j = ibmtts_voice_index[i]; ret = eciSetParam(eciHandle, eciLanguageDialect, eciLocales[j].langID); DBG("Ibmtts: set langID=0x%x (ret=%d)", eciLocales[j].langID, ret); ibmtts_input_encoding = eciLocales[j].charset; break; } } } else { for (i = 0; v[i]; i++) { DBG("%d. language=%s", i, v[i]->language); if (!strcmp(v[i]->language, lang)) { j = ibmtts_voice_index[i]; variant_name = v[i]->name; ret = eciSetParam(eciHandle, eciLanguageDialect, eciLocales[j].langID); DBG("Ibmtts: set langID=0x%x (ret=%d)", eciLocales[j].langID, ret); ibmtts_input_encoding = eciLocales[j].charset; break; } } } if (-1 == ret) { DBG("Ibmtts: Unable to set language"); ibmtts_log_eci_error(); } else { g_atomic_int_set(&locale_index_atomic, j); } /* Set voice parameters (if any are defined for this voice.) */ TIbmttsVoiceParameters *params = g_hash_table_lookup(IbmttsVoiceParameters, voicename); if (NULL == params) { DBG("Ibmtts: Setting default VoiceParameters for voice %s", voicename); switch (voice) { case SPD_MALE1: eciVoice = 1; break; /* Adult Male 1 */ case SPD_MALE2: eciVoice = 4; break; /* Adult Male 2 */ case SPD_MALE3: eciVoice = 5; break; /* Adult Male 3 */ case SPD_FEMALE1: eciVoice = 2; break; /* Adult Female 1 */ case SPD_FEMALE2: eciVoice = 6; break; /* Adult Female 2 */ case SPD_FEMALE3: eciVoice = 7; break; /* Elderly Female 1 */ case SPD_CHILD_MALE: eciVoice = 3; break; /* Child */ case SPD_CHILD_FEMALE: eciVoice = 3; break; /* Child */ default: eciVoice = 1; break; /* Adult Male 1 */ } ret = eciCopyVoice(eciHandle, eciVoice, 0); if (-1 == ret) DBG("Ibmtts: ERROR: Setting default voice parameters (voice %i).", eciVoice); } else { DBG("Ibmtts: Setting custom VoiceParameters for voice %s", voicename); ret = eciSetVoiceParam(eciHandle, 0, eciGender, params->gender); if (-1 == ret) DBG("Ibmtts: ERROR: Setting gender %i", params->gender); ret = eciSetVoiceParam(eciHandle, 0, eciBreathiness, params->breathiness); if (-1 == ret) DBG("Ibmtts: ERROR: Setting breathiness %i", params->breathiness); ret = eciSetVoiceParam(eciHandle, 0, eciHeadSize, params->head_size); if (-1 == ret) DBG("Ibmtts: ERROR: Setting head size %i", params->head_size); ret = eciSetVoiceParam(eciHandle, 0, eciPitchBaseline, params->pitch_baseline); if (-1 == ret) DBG("Ibmtts: ERROR: Setting pitch baseline %i", params->pitch_baseline); ret = eciSetVoiceParam(eciHandle, 0, eciPitchFluctuation, params->pitch_fluctuation); if (-1 == ret) DBG("Ibmtts: ERROR: Setting pitch fluctuation %i", params->pitch_fluctuation); ret = eciSetVoiceParam(eciHandle, 0, eciRoughness, params->roughness); if (-1 == ret) DBG("Ibmtts: ERROR: Setting roughness %i", params->roughness); ret = eciSetVoiceParam(eciHandle, 0, eciSpeed, params->speed); if (-1 == ret) DBG("Ibmtts: ERROR: Setting speed %i", params->speed); } g_free(voicename); /* Retrieve the baseline pitch and speed of the voice. */ ibmtts_voice_pitch_baseline = eciGetVoiceParam(eciHandle, 0, eciPitchBaseline); if (-1 == ibmtts_voice_pitch_baseline) DBG("Ibmtts: Cannot get pitch baseline of voice."); ibmtts_voice_speed = eciGetVoiceParam(eciHandle, 0, eciSpeed); if (-1 == ibmtts_voice_speed) DBG("Ibmtts: Cannot get speed of voice."); } static void ibmtts_set_voice(SPDVoiceType voice) { if (msg_settings.voice.language) { ibmtts_set_language_and_voice(msg_settings.voice.language, voice, NULL); } } static void ibmtts_set_language(char *lang) { ibmtts_set_language_and_voice(lang, msg_settings.voice_type, NULL); } /* sets the IBM voice according to its name. */ static void ibmtts_set_synthesis_voice(char *synthesis_voice) { int i = 0; if (synthesis_voice == NULL) { return; } DBG("Ibmtts: %s, synthesis voice=%s", __FUNCTION__, synthesis_voice); for (i = 0; i < MAX_NB_OF_LANGUAGES; i++) { if (!strcasecmp(eciLocales[i].name, synthesis_voice)) { ibmtts_set_language_and_voice(eciLocales[i].lang, msg_settings.voice_type, eciLocales[i].dialect); break; } } } static void ibmtts_log_eci_error() { /* TODO: This routine is not working. Not sure why. */ char buf[100]; eciErrorMessage(eciHandle, buf); DBG("Ibmtts: ECI Error Message: %s", buf); } /* IBM TTS calls back here when a chunk of audio is ready or an index mark has been reached. The good news is that it returns the audio up to each index mark or when the audio buffer is full. */ static enum ECICallbackReturn eciCallback(ECIHand hEngine, enum ECIMessage msg, long lparam, void *data) { /* This callback is running in the same thread as called eciSynchronize(), i.e., the _ibmtts_synth() thread. */ /* If module_stop was called, discard any further callbacks until module_speak is called. */ if (ibmtts_stop_synth_requested || ibmtts_stop_play_requested) return eciDataProcessed; switch (msg) { case eciWaveformBuffer: DBG("Ibmtts: %ld audio samples returned from IBM TTS.", lparam); /* Add audio to output queue. */ ibmtts_add_audio_to_playback_queue(audio_chunk, lparam); /* Wake up the audio playback thread, if not already awake. */ if (!is_thread_busy(&ibmtts_play_suspended_mutex)) sem_post(&ibmtts_play_semaphore); return eciDataProcessed; break; case eciIndexReply: DBG("Ibmtts: Index mark id %ld returned from IBM TTS.", lparam); if (lparam == IBMTTS_MSG_END_MARK) { ibmtts_add_flag_to_playback_queue(IBMTTS_QET_END); } else { /* Add index mark to output queue. */ ibmtts_add_mark_to_playback_queue(lparam); } /* Wake up the audio playback thread, if not already awake. */ if (!is_thread_busy(&ibmtts_play_suspended_mutex)) sem_post(&ibmtts_play_semaphore); return eciDataProcessed; break; default: return eciDataProcessed; } } /* Adds a chunk of pcm audio to the audio playback queue. */ static TIbmttsBool ibmtts_add_audio_to_playback_queue(TEciAudioSamples * audio_chunk, long num_samples) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); if (NULL == playback_queue_entry) return IBMTTS_FALSE; playback_queue_entry->type = IBMTTS_QET_AUDIO; playback_queue_entry->data.audio.num_samples = (int)num_samples; int wlen = sizeof(TEciAudioSamples) * num_samples; playback_queue_entry->data.audio.audio_chunk = (TEciAudioSamples *) g_malloc(wlen); memcpy(playback_queue_entry->data.audio.audio_chunk, audio_chunk, wlen); pthread_mutex_lock(&playback_queue_mutex); playback_queue = g_slist_append(playback_queue, playback_queue_entry); pthread_mutex_unlock(&playback_queue_mutex); return IBMTTS_TRUE; } /* Adds an Index Mark to the audio playback queue. */ static TIbmttsBool ibmtts_add_mark_to_playback_queue(long markId) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); if (NULL == playback_queue_entry) return IBMTTS_FALSE; playback_queue_entry->type = IBMTTS_QET_INDEX_MARK; playback_queue_entry->data.markId = markId; pthread_mutex_lock(&playback_queue_mutex); playback_queue = g_slist_append(playback_queue, playback_queue_entry); pthread_mutex_unlock(&playback_queue_mutex); return IBMTTS_TRUE; } /* Adds a begin or end flag to the playback queue. */ static TIbmttsBool ibmtts_add_flag_to_playback_queue(EPlaybackQueueEntryType type) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); if (NULL == playback_queue_entry) return IBMTTS_FALSE; playback_queue_entry->type = type; pthread_mutex_lock(&playback_queue_mutex); playback_queue = g_slist_append(playback_queue, playback_queue_entry); pthread_mutex_unlock(&playback_queue_mutex); return IBMTTS_TRUE; } /* Add a sound icon to the playback queue. */ static TIbmttsBool ibmtts_add_sound_icon_to_playback_queue(char *filename) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); if (NULL == playback_queue_entry) return IBMTTS_FALSE; playback_queue_entry->type = IBMTTS_QET_SOUND_ICON; playback_queue_entry->data.sound_icon_filename = filename; pthread_mutex_lock(&playback_queue_mutex); playback_queue = g_slist_append(playback_queue, playback_queue_entry); pthread_mutex_unlock(&playback_queue_mutex); return IBMTTS_TRUE; } /* Deletes an entry from the playback audio queue, freeing memory. */ static void ibmtts_delete_playback_queue_entry(TPlaybackQueueEntry * playback_queue_entry) { switch (playback_queue_entry->type) { case IBMTTS_QET_AUDIO: g_free(playback_queue_entry->data.audio.audio_chunk); break; case IBMTTS_QET_SOUND_ICON: g_free(playback_queue_entry->data.sound_icon_filename); break; default: break; } g_free(playback_queue_entry); } /* Erases the entire playback queue, freeing memory. */ static void ibmtts_clear_playback_queue() { pthread_mutex_lock(&playback_queue_mutex); while (NULL != playback_queue) { TPlaybackQueueEntry *playback_queue_entry = playback_queue->data; ibmtts_delete_playback_queue_entry(playback_queue_entry); playback_queue = g_slist_remove(playback_queue, playback_queue->data); } playback_queue = NULL; pthread_mutex_unlock(&playback_queue_mutex); } /* Sends a chunk of audio to the audio player and waits for completion or error. */ static TIbmttsBool ibmtts_send_to_audio(TPlaybackQueueEntry * playback_queue_entry) { AudioTrack track; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) AudioFormat format = SPD_AUDIO_BE; #else AudioFormat format = SPD_AUDIO_LE; #endif int ret; track.num_samples = playback_queue_entry->data.audio.num_samples; track.num_channels = 1; track.sample_rate = eci_sample_rate; track.bits = 16; track.samples = playback_queue_entry->data.audio.audio_chunk; if (track.samples == NULL) return IBMTTS_TRUE; DBG("Ibmtts: Sending %i samples to audio.", track.num_samples); ret = module_tts_output(track, format); if (ret < 0) { DBG("ERROR: Can't play track for unknown reason."); return IBMTTS_FALSE; } DBG("Ibmtts: Sent to audio."); return IBMTTS_TRUE; } /* Playback thread. */ static void *_ibmtts_play(void *nothing) { int markId; char *mark_name; TPlaybackQueueEntry *playback_queue_entry = NULL; DBG("Ibmtts: Playback thread starting.......\n"); /* Block all signals to this thread. */ set_speaking_thread_parameters(); while (!ibmtts_thread_exit_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&ibmtts_play_semaphore)) { pthread_mutex_lock(&ibmtts_play_suspended_mutex); sem_wait(&ibmtts_play_semaphore); pthread_mutex_unlock(&ibmtts_play_suspended_mutex); } /* DBG("Ibmtts: Playback semaphore on."); */ while (!ibmtts_stop_play_requested && !ibmtts_thread_exit_requested) { pthread_mutex_lock(&playback_queue_mutex); if (NULL != playback_queue) { playback_queue_entry = playback_queue->data; playback_queue = g_slist_remove(playback_queue, playback_queue->data); } pthread_mutex_unlock(&playback_queue_mutex); if (NULL == playback_queue_entry) break; switch (playback_queue_entry->type) { case IBMTTS_QET_AUDIO: ibmtts_send_to_audio(playback_queue_entry); break; case IBMTTS_QET_INDEX_MARK: /* Look up the index mark integer id in lookup table to find string name and emit that name. */ markId = playback_queue_entry->data.markId; mark_name = g_hash_table_lookup(ibmtts_index_mark_ht, &markId); if (NULL == mark_name) { DBG("Ibmtts: markId %d returned by IBM TTS not found in lookup table.", markId); } else { DBG("Ibmtts: reporting index mark |%s|.", mark_name); module_report_index_mark(mark_name); DBG("Ibmtts: index mark reported."); /* If pause requested, wait for an end-of-sentence index mark. */ if (ibmtts_pause_requested) { if (0 == strncmp(mark_name, SD_MARK_BODY, SD_MARK_BODY_LEN)) { DBG("Ibmtts: Pause requested in playback thread. Stopping."); ibmtts_stop_play_requested = IBMTTS_TRUE; } } } break; case IBMTTS_QET_SOUND_ICON: module_play_file(playback_queue_entry-> data.sound_icon_filename); break; case IBMTTS_QET_BEGIN: module_report_event_begin(); break; case IBMTTS_QET_END: module_report_event_end(); break; } ibmtts_delete_playback_queue_entry (playback_queue_entry); playback_queue_entry = NULL; } if (ibmtts_stop_play_requested) DBG("Ibmtts: Stop or pause in playback thread."); } DBG("Ibmtts: Playback thread ended.......\n"); pthread_exit(NULL); } /* Replaces all occurrences of "from" with "to" in msg. Returns count of replacements. */ static int ibmtts_replace(char *from, char *to, GString * msg) { int count = 0; int pos; int from_len = strlen(from); int to_len = strlen(to); char *p = msg->str; while (NULL != (p = strstr(p, from))) { pos = p - msg->str; g_string_erase(msg, pos, from_len); g_string_insert(msg, pos, to); p = msg->str + pos + to_len; ++count; } return count; } static void ibmtts_subst_keys_cb(gpointer data, gpointer user_data) { TIbmttsKeySubstitution *key_subst = data; GString *msg = user_data; ibmtts_replace(key_subst->key, key_subst->newkey, msg); } /* Given a Speech Dispatcher !KEY key sequence, replaces unspeakable or incorrectly spoken keys or characters with speakable ones. The subsitutions come from the KEY NAME SUBSTITUTIONS section of the config file. Caller is responsible for freeing returned string. */ static char *ibmtts_subst_keys(char *key) { GString *tmp = g_string_sized_new(30); g_string_append(tmp, key); GList *keyTable = g_hash_table_lookup(IbmttsKeySubstitution, msg_settings.voice.language); if (keyTable) g_list_foreach(keyTable, ibmtts_subst_keys_cb, tmp); /* Hyphen hangs IBM TTS */ if (0 == strcmp(tmp->str, "-")) g_string_assign(tmp, "hyphen"); return g_string_free(tmp, FALSE); } /* Given a sound icon name, searches for a file to play and if found returns the filename. Returns NULL if none found. Caller is responsible for freeing the returned string. */ /* TODO: These current assumptions should be dealt with: Sound icon files are in a single directory (IbmttsSoundIconFolder). The name of each icon is symlinked to a .wav file. If you have installed the free(b)soft sound-icons package under Debian, then these assumptions are true, but what about other distros and OSes? */ static char *ibmtts_search_for_sound_icon(const char *icon_name) { char *fn = NULL; if (0 == strlen(IbmttsSoundIconFolder)) return fn; GString *filename = g_string_new(IbmttsSoundIconFolder); filename = g_string_append(filename, icon_name); if (g_file_test(filename->str, G_FILE_TEST_EXISTS)) fn = filename->str; /* else { filename = g_string_assign(filename, g_utf8_strdown(filename->str, -1)); if (g_file_test(filename->str, G_FILE_TEST_EXISTS)) fn = filename->str; } */ /* * if the file was found, the pointer *fn points to the character data * of the string filename. In this situation the string filename must be * freed but its character data must be preserved. * If the file is not found, the pointer *fn contains NULL. In this * situation the string filename must be freed, including its character * data. */ g_string_free(filename, (fn == NULL)); return fn; } void alloc_voice_list() { enum ECILanguageDialect aLanguage[MAX_NB_OF_LANGUAGES]; int nLanguages = MAX_NB_OF_LANGUAGES; int i = 0; if (eciGetAvailableLanguages(aLanguage, &nLanguages)) return; ibmtts_voice_list = g_malloc((nLanguages + 1) * sizeof(SPDVoice *)); ibmtts_voice_index = g_malloc((nLanguages + 1) * sizeof(SPDVoice *)); if (!ibmtts_voice_list) return; DBG("Ibmtts: nLanguages=%d/%lu", nLanguages, (unsigned long)MAX_NB_OF_LANGUAGES); for (i = 0; i < nLanguages; i++) { /* look for the language name */ int j; ibmtts_voice_list[i] = g_malloc(sizeof(SPDVoice)); DBG("Ibmtts: aLanguage[%d]=0x%08x", i, aLanguage[i]); for (j = 0; j < MAX_NB_OF_LANGUAGES; j++) { DBG("Ibmtts: eciLocales[%d].langID=0x%08x", j, eciLocales[j].langID); if (eciLocales[j].langID == aLanguage[i]) { ibmtts_voice_list[i]->name = eciLocales[j].name; ibmtts_voice_list[i]->language = eciLocales[j].lang; ibmtts_voice_list[i]->variant = eciLocales[j].dialect; ibmtts_voice_index[i] = j; DBG("Ibmtts: alloc_voice_list %s", ibmtts_voice_list[i]->name); break; } } assert(j < MAX_NB_OF_LANGUAGES); } ibmtts_voice_list[nLanguages] = NULL; DBG("Ibmtts: LEAVE %s", __func__); } static void free_voice_list() { int i = 0; if (ibmtts_voice_index) { g_free(ibmtts_voice_index); ibmtts_voice_index = NULL; } if (!ibmtts_voice_list) return; for (i = 0; ibmtts_voice_list[i]; i++) { g_free(ibmtts_voice_list[i]); } g_free(ibmtts_voice_list); ibmtts_voice_list = NULL; } static void ibmtts_load_user_dictionary() { GString *dirname = NULL; GString *filename = NULL; int i = 0; int dictionary_is_present = 0; static guint old_index = MAX_NB_OF_LANGUAGES; guint new_index; const char *language = NULL; const char *region = NULL; ECIDictHand eciDict = eciGetDict(eciHandle); new_index = g_atomic_int_get(&locale_index_atomic); if (new_index >= MAX_NB_OF_LANGUAGES) { DBG("Ibmtts: %s, unexpected index (0x%x)", __FUNCTION__, new_index); return; } if (old_index == new_index) { DBG("Ibmtts: LEAVE %s, no change", __FUNCTION__); return; } language = eciLocales[new_index].lang; region = eciLocales[new_index].dialect; /* Fix locale name for French Canadian */ if (!strcmp(language, "ca") && !strcmp(region, "FR")) { language = "fr"; region = "CA"; } if (eciDict) { DBG("Ibmtts: delete old dictionary"); eciDeleteDict(eciHandle, eciDict); } eciDict = eciNewDict(eciHandle); if (eciDict) { old_index = new_index; } else { old_index = MAX_NB_OF_LANGUAGES; DBG("Ibmtts: can't create new dictionary"); return; } /* Look for the dictionary directory */ dirname = g_string_new(NULL); g_string_printf(dirname, "%s/%s_%s", IbmttsDictionaryFolder, language, region); if (!g_file_test(dirname->str, G_FILE_TEST_IS_DIR)) { g_string_printf(dirname, "%s/%s", IbmttsDictionaryFolder, language); if (!g_file_test(dirname->str, G_FILE_TEST_IS_DIR)) { g_string_printf(dirname, "%s", IbmttsDictionaryFolder); if (!g_file_test(dirname->str, G_FILE_TEST_IS_DIR)) { DBG("Ibmtts: %s is not a directory", dirname->str); return; } } } DBG("Ibmtts: Looking in dictionary directory %s", dirname->str); filename = g_string_new(NULL); for (i = 0; i < NB_OF_DICTIONARY_FILENAMES; i++) { g_string_printf(filename, "%s/%s", dirname->str, dictionary_filenames[i]); if (g_file_test(filename->str, G_FILE_TEST_EXISTS)) { enum ECIDictError error = eciLoadDict(eciHandle, eciDict, i, filename->str); if (!error) { dictionary_is_present = 1; DBG("Ibmtts: %s dictionary loaded", filename->str); } else { DBG("Ibmtts: Can't load %s dictionary (%d)", filename->str, error); } } else { DBG("Ibmtts: No %s dictionary", filename->str); } } g_string_free(filename, TRUE); g_string_free(dirname, TRUE); if (dictionary_is_present) { eciSetDict(eciHandle, eciDict); } } speech-dispatcher-0.9.1/src/modules/generic.c0000644000175000017500000004337013414521774016073 00000000000000 /* * generic.c - Speech Dispatcher generic output module * * Copyright (C) 2001, 2002, 2003, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: generic.c,v 1.30 2008-07-30 09:15:51 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "module_utils.h" #define MODULE_NAME "generic" #define MODULE_VERSION "0.2" DECLARE_DEBUG() /* Thread and process control */ static int generic_speaking = 0; static pthread_t generic_speak_thread; static pid_t generic_pid; static sem_t generic_semaphore; static char **generic_message; static SPDMessageType generic_message_type; static int generic_position = 0; static int generic_pause_requested = 0; static char *execute_synth_str1; static char *execute_synth_str2; /* Internal functions prototypes */ static void *get_ht_option(GHashTable * hash_table, const char *key); static void *_generic_speak(void *); static void _generic_child(TModuleDoublePipe dpipe, const size_t maxlen); static void generic_child_close(TModuleDoublePipe dpipe); void generic_set_rate(signed int rate); void generic_set_pitch(signed int pitch); void generic_set_pitch_range(signed int pitch_range); void generic_set_voice(SPDVoiceType voice); void generic_set_synthesis_voice(char *name); void generic_set_language(char *language); void generic_set_volume(signed int volume); void generic_set_punct(SPDPunctuation punct); /* Fill the module_info structure with pointers to this modules functions */ MOD_OPTION_1_STR(GenericExecuteSynth) MOD_OPTION_1_STR(GenericCmdDependency) MOD_OPTION_1_INT(GenericMaxChunkLength) MOD_OPTION_1_STR(GenericDelimiters) MOD_OPTION_1_STR(GenericPunctNone) MOD_OPTION_1_STR(GenericPunctSome) MOD_OPTION_1_STR(GenericPunctAll) MOD_OPTION_1_STR(GenericStripPunctChars) MOD_OPTION_1_STR(GenericRecodeFallback) MOD_OPTION_1_INT(GenericRateAdd) MOD_OPTION_1_FLOAT(GenericRateMultiply) MOD_OPTION_1_INT(GenericRateForceInteger) MOD_OPTION_1_INT(GenericPitchAdd) MOD_OPTION_1_FLOAT(GenericPitchMultiply) MOD_OPTION_1_INT(GenericPitchForceInteger) MOD_OPTION_1_INT(GenericPitchRangeAdd) MOD_OPTION_1_FLOAT(GenericPitchRangeMultiply) MOD_OPTION_1_INT(GenericPitchRangeForceInteger) MOD_OPTION_1_INT(GenericVolumeAdd) MOD_OPTION_1_FLOAT(GenericVolumeMultiply) MOD_OPTION_1_INT(GenericVolumeForceInteger) MOD_OPTION_3_HT(GenericLanguage, code, name, charset) static char generic_msg_pitch_str[16]; static char generic_msg_pitch_range_str[16]; static char generic_msg_rate_str[16]; static char generic_msg_volume_str[16]; static char *generic_msg_voice_str = NULL; static TGenericLanguage *generic_msg_language = NULL; static char *generic_msg_punct_str; /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); MOD_OPTION_1_STR_REG(GenericExecuteSynth, ""); MOD_OPTION_1_STR_REG(GenericCmdDependency, ""); REGISTER_DEBUG(); MOD_OPTION_1_INT_REG(GenericMaxChunkLength, 300); MOD_OPTION_1_STR_REG(GenericDelimiters, "."); MOD_OPTION_1_STR_REG(GenericStripPunctChars, ""); MOD_OPTION_1_STR_REG(GenericRecodeFallback, "?"); MOD_OPTION_1_INT_REG(GenericRateAdd, 0); MOD_OPTION_1_FLOAT_REG(GenericRateMultiply, 1); MOD_OPTION_1_INT_REG(GenericRateForceInteger, 0); MOD_OPTION_1_INT_REG(GenericPitchAdd, 0); MOD_OPTION_1_FLOAT_REG(GenericPitchMultiply, 1); MOD_OPTION_1_INT_REG(GenericPitchForceInteger, 0); MOD_OPTION_1_INT_REG(GenericPitchRangeAdd, 0); MOD_OPTION_1_FLOAT_REG(GenericPitchRangeMultiply, 1); MOD_OPTION_1_INT_REG(GenericPitchRangeForceInteger, 0); MOD_OPTION_1_INT_REG(GenericVolumeAdd, 0); MOD_OPTION_1_FLOAT_REG(GenericVolumeMultiply, 1); MOD_OPTION_1_INT_REG(GenericVolumeForceInteger, 0); MOD_OPTION_HT_REG(GenericLanguage); MOD_OPTION_1_STR_REG(GenericPunctNone, ""); MOD_OPTION_1_STR_REG(GenericPunctSome, ""); MOD_OPTION_1_STR_REG(GenericPunctAll, ""); module_register_available_voices(); module_register_settings_voices(); return 0; } int module_init(char **status_info) { int ret; *status_info = NULL; DBG("GenericMaxChunkLength = %d\n", GenericMaxChunkLength); DBG("GenericDelimiters = %s\n", GenericDelimiters); DBG("GenericExecuteSynth = %s\n", GenericExecuteSynth); DBG("GenericCmdDependency = %s\n", GenericCmdDependency); generic_msg_language = (TGenericLanguage *) g_malloc(sizeof(TGenericLanguage)); generic_msg_language->code = g_strdup("en"); generic_msg_language->charset = g_strdup("iso-8859-1"); generic_msg_language->name = g_strdup("english"); generic_message = g_malloc(sizeof(char *)); sem_init(&generic_semaphore, 0, 0); DBG("Generic: creating new thread for generic_speak\n"); generic_speaking = 0; ret = pthread_create(&generic_speak_thread, NULL, _generic_speak, NULL); if (ret != 0) { DBG("Generic: thread failed\n"); *status_info = g_strdup("The module couldn't initialize threads" "This can be either an internal problem or an" "architecture problem. If you are sure your architecture" "supports threads, please report a bug."); return -1; } *status_info = g_strdup("Everything ok so far."); return 0; } SPDVoice **module_list_voices(void) { return module_list_registered_voices(); } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { char *tmp; DBG("speak()\n"); if (generic_speaking) { DBG("Speaking when requested to write"); return 0; } UPDATE_STRING_PARAMETER(voice.name, generic_set_synthesis_voice); UPDATE_STRING_PARAMETER(voice.language, generic_set_language); UPDATE_PARAMETER(voice_type, generic_set_voice); UPDATE_PARAMETER(punctuation_mode, generic_set_punct); UPDATE_PARAMETER(pitch, generic_set_pitch); UPDATE_PARAMETER(pitch_range, generic_set_pitch_range); UPDATE_PARAMETER(rate, generic_set_rate); UPDATE_PARAMETER(volume, generic_set_volume); /* Set the appropriate charset */ assert(generic_msg_language != NULL); if (generic_msg_language->charset != NULL) { DBG("Recoding from UTF-8 to %s...", generic_msg_language->charset); tmp = (char *)g_convert_with_fallback(data, bytes, generic_msg_language->charset, "UTF-8", GenericRecodeFallback, NULL, NULL, NULL); } else { DBG("Warning: Preferred charset not specified, recoding to iso-8859-1"); tmp = (char *)g_convert_with_fallback(data, bytes, "iso-8859-2", "UTF-8", GenericRecodeFallback, NULL, NULL, NULL); } if (tmp == NULL) return -1; if (msgtype == SPD_MSGTYPE_TEXT) *generic_message = module_strip_ssml(tmp); else *generic_message = g_strdup(tmp); g_free(tmp); module_strip_punctuation_some(*generic_message, GenericStripPunctChars); generic_message_type = SPD_MSGTYPE_TEXT; DBG("Requested data: |%s|\n", data); /* Send semaphore signal to the speaking thread */ generic_speaking = 1; sem_post(&generic_semaphore); DBG("Generic: leaving write() normally\n\r"); return bytes; } int module_stop(void) { DBG("generic: stop()\n"); if (generic_speaking && generic_pid != 0) { DBG("generic: stopping process group pid %d\n", generic_pid); kill(-generic_pid, SIGKILL); } return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (generic_speaking) { DBG("Sending request to pause to child\n"); generic_pause_requested = 1; DBG("paused at byte: %d", generic_position); return 0; } else { return -1; } } char *module_is_speaking(void) { return NULL; } int module_close(void) { DBG("generic: close()\n"); if (generic_speaking) { module_stop(); } if (module_terminate_thread(generic_speak_thread) != 0) return -1; sem_destroy(&generic_semaphore); return 0; } /* Internal functions */ static void *get_ht_option(GHashTable * hash_table, const char *key) { void *option; assert(key != NULL); option = g_hash_table_lookup(hash_table, key); if (option == NULL) DBG("Requested option by key %s not found.\n", key); return option; } /* Replace all occurances of 'token' in 'sting' with 'data' */ char *string_replace(char *string, const char *token, const char *data) { char *p; char *str1; char *str2; char *new; char *mstring; mstring = g_strdup(string); while (1) { /* Split the string in two parts, ommit the token */ p = strstr(mstring, token); if (p == NULL) { return mstring; } *p = 0; str1 = mstring; str2 = p + (strlen(token)); /* Put it together, replacing token with data */ new = g_strdup_printf("%s%s%s", str1, data, str2); g_free(mstring); mstring = new; } } void *_generic_speak(void *nothing) { TModuleDoublePipe module_pipe; int ret; int status; DBG("generic: speaking thread starting.......\n"); set_speaking_thread_parameters(); while (1) { sem_wait(&generic_semaphore); DBG("Semaphore on\n"); ret = pipe(module_pipe.pc); if (ret != 0) { DBG("Can't create pipe pc\n"); generic_speaking = 0; continue; } ret = pipe(module_pipe.cp); if (ret != 0) { DBG("Can't create pipe cp\n"); close(module_pipe.pc[0]); close(module_pipe.pc[1]); generic_speaking = 0; continue; } module_report_event_begin(); /* Create a new process so that we could send it signals */ generic_pid = fork(); switch (generic_pid) { case -1: DBG("Can't say the message. fork() failed!\n"); close(module_pipe.pc[0]); close(module_pipe.pc[1]); close(module_pipe.cp[0]); close(module_pipe.cp[1]); generic_speaking = 0; continue; case 0:{ char *e_string; char *p; char *tmpdir, *homedir; const char *helper; const char *play_command = NULL; helper = getenv("TMPDIR"); if (helper) tmpdir = g_strdup(helper); else tmpdir = g_strdup("/tmp"); helper = g_get_home_dir(); if (helper) homedir = g_strdup(helper); else homedir = g_strdup("UNKNOWN_HOME_DIRECTORY"); play_command = spd_audio_get_playcmd(module_audio_id); if (play_command == NULL) { DBG("This audio backend has no default play command; using \"play\"\n"); play_command = "play"; } /* Set this process as a process group leader (so that SIGKILL is also delivered to the child processes created by system()) */ if (setpgid(0, 0) == -1) DBG("Can't set myself as project group leader!"); e_string = g_strdup(GenericExecuteSynth); e_string = string_replace(e_string, "$PLAY_COMMAND", play_command); e_string = string_replace(e_string, "$TMPDIR", tmpdir); g_free(tmpdir); e_string = string_replace(e_string, "$HOMEDIR", homedir); g_free(homedir); e_string = string_replace(e_string, "$PITCH", generic_msg_pitch_str); e_string = string_replace(e_string, "$PITCH_RANGE", generic_msg_pitch_range_str); e_string = string_replace(e_string, "$RATE", generic_msg_rate_str); e_string = string_replace(e_string, "$VOLUME", generic_msg_volume_str); e_string = string_replace(e_string, "$LANGUAGE", generic_msg_language->name); e_string = string_replace(e_string, "$PUNCT", generic_msg_punct_str); if (generic_msg_voice_str != NULL) e_string = string_replace(e_string, "$VOICE", generic_msg_voice_str); else e_string = string_replace(e_string, "$VOICE", "no_voice"); /* Cut it into two strings */ p = strstr(e_string, "$DATA"); if (p == NULL) exit(1); *p = 0; execute_synth_str1 = g_strdup(e_string); execute_synth_str2 = g_strdup(p + (strlen("$DATA"))); g_free(e_string); /* execute_synth_str1 se sem musi nejak dostat */ DBG("Starting child...\n"); _generic_child(module_pipe, GenericMaxChunkLength); } break; default: /* This is the parent. Send data to the child. */ generic_position = module_parent_wfork(module_pipe, *generic_message, generic_message_type, GenericMaxChunkLength, GenericDelimiters, &generic_pause_requested); DBG("Waiting for child..."); waitpid(generic_pid, &status, 0); generic_speaking = 0; // Report CANCEL if the process was signal-terminated // and END if it terminated normally if (WIFSIGNALED(status)) module_report_event_stop(); else module_report_event_end(); DBG("child terminated -: status:%d signal?:%d signal number:%d.\n", WIFEXITED(status), WIFSIGNALED(status), WTERMSIG(status)); } } generic_speaking = 0; DBG("generic: speaking thread ended.......\n"); pthread_exit(NULL); } void _generic_child(TModuleDoublePipe dpipe, const size_t maxlen) { char *text; sigset_t some_signals; int bytes; char *command; GString *message; int i; int ret; sigfillset(&some_signals); module_sigunblockusr(&some_signals); module_child_dp_init(dpipe); DBG("Entering child loop\n"); while (1) { /* Read the waiting data */ text = g_malloc((maxlen + 1) * sizeof(char)); bytes = module_child_dp_read(dpipe, text, maxlen); DBG("read %d bytes in child", bytes); if (bytes == 0) { g_free(text); generic_child_close(dpipe); } text[bytes] = 0; DBG("text read is: |%s|\n", text); /* Escape any quotes */ message = g_string_new(""); for (i = 0; i <= bytes - 1; i++) { if (text[i] == '\'') message = g_string_append(message, "'\\''"); else { g_string_append_printf(message, "%c", text[i]); } } DBG("child: escaped text is |%s|", message->str); command = g_malloc((strlen(message->str) + strlen(execute_synth_str1) + strlen(execute_synth_str2) + 8) * sizeof(char)); if (strlen(message->str) != 0) { sprintf(command, "%s%s%s", execute_synth_str1, message->str, execute_synth_str2); DBG("child: synth command = |%s|", command); DBG("Speaking in child..."); module_sigblockusr(&some_signals); { ret = system(command); DBG("Executed shell command returned with %d", ret); } } module_sigunblockusr(&some_signals); g_free(command); g_free(text); g_string_free(message, 1); DBG("child->parent: ok, send more data"); module_child_dp_write(dpipe, "C", 1); } } static void generic_child_close(TModuleDoublePipe dpipe) { DBG("child: Pipe closed, exiting, closing pipes..\n"); module_child_dp_close(dpipe); DBG("Child ended...\n"); exit(0); } void generic_set_pitch(int pitch) { float hpitch; hpitch = ((float)pitch) * GenericPitchMultiply + GenericPitchAdd; if (!GenericPitchForceInteger) { snprintf(generic_msg_pitch_str, 15, "%.2f", hpitch); } else { snprintf(generic_msg_pitch_str, 15, "%d", (int)hpitch); } } void generic_set_pitch_range(int pitch_range) { float hpitch_range; hpitch_range = ((float)pitch_range) * GenericPitchRangeMultiply + GenericPitchRangeAdd; if (!GenericPitchRangeForceInteger) { snprintf(generic_msg_pitch_range_str, 15, "%.2f", hpitch_range); } else { snprintf(generic_msg_pitch_range_str, 15, "%d", (int)hpitch_range); } } void generic_set_rate(int rate) { float hrate; hrate = ((float)rate) * GenericRateMultiply + GenericRateAdd; if (!GenericRateForceInteger) { snprintf(generic_msg_rate_str, 15, "%.2f", hrate); } else { snprintf(generic_msg_rate_str, 15, "%d", (int)hrate); } } void generic_set_volume(int volume) { float hvolume; DBG("Volume: %d", volume); hvolume = ((float)volume) * GenericVolumeMultiply + GenericVolumeAdd; DBG("HVolume: %f", hvolume); if (!GenericVolumeForceInteger) { snprintf(generic_msg_volume_str, 15, "%.2f", hvolume); } else { snprintf(generic_msg_volume_str, 15, "%d", (int)hvolume); } } void generic_set_language(char *lang) { generic_msg_language = (TGenericLanguage *) get_ht_option(GenericLanguage, lang); if (generic_msg_language == NULL) { DBG("Language %s not found in the configuration file, using defaults.", lang); generic_msg_language = (TGenericLanguage *) g_malloc(sizeof(TGenericLanguage)); generic_msg_language->code = g_strdup(lang); generic_msg_language->charset = NULL; generic_msg_language->name = g_strdup(lang); } if (generic_msg_language->name == NULL) { DBG("Language name for %s not found in the configuration file.", lang); generic_msg_language = (TGenericLanguage *) g_malloc(sizeof(TGenericLanguage)); generic_msg_language->code = g_strdup("en"); generic_msg_language->charset = g_strdup("iso-8859-1"); generic_msg_language->name = g_strdup("english"); } generic_set_voice(msg_settings.voice_type); } void generic_set_voice(SPDVoiceType voice) { if (generic_msg_voice_str != NULL) return; assert(generic_msg_language); generic_msg_voice_str = module_getvoice(generic_msg_language->code, voice); if (generic_msg_voice_str == NULL) { DBG("Invalid voice type specified or no voice available!"); } } void generic_set_synthesis_voice(char *name) { assert(msg_settings.voice.name); if (module_existsvoice(msg_settings.voice.name)) generic_msg_voice_str = msg_settings.voice.name; } void generic_set_punct(SPDPunctuation punct) { if (punct == SPD_PUNCT_NONE) { generic_msg_punct_str = g_strdup((char *)GenericPunctNone); return; } else if (punct == SPD_PUNCT_SOME) { generic_msg_punct_str = g_strdup((char *)GenericPunctSome); return; } else if (punct == SPD_PUNCT_ALL) { generic_msg_punct_str = g_strdup((char *)GenericPunctAll); return; } else { DBG("ERROR: Unknown punctuation setting, ignored"); } } speech-dispatcher-0.9.1/src/modules/flite.c0000644000175000017500000002226413406252443015554 00000000000000 /* * flite.c - Speech Dispatcher backend for Flite (Festival Lite) * * Copyright (C) 2001, 2002, 2003, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: flite.c,v 1.59 2008-06-09 10:38:02 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "spd_audio.h" #include #include "module_utils.h" #define MODULE_NAME "flite" #define MODULE_VERSION "0.5" #define DEBUG_MODULE 1 DECLARE_DEBUG(); /* Thread and process control */ static int flite_speaking = 0; static pthread_t flite_speak_thread; static sem_t flite_semaphore; static char **flite_message; static SPDMessageType flite_message_type; static int flite_position = 0; static int flite_pause_requested = 0; signed int flite_volume = 0; /* Internal functions prototypes */ static void flite_set_rate(signed int rate); static void flite_set_pitch(signed int pitch); static void flite_set_volume(signed int pitch); static void flite_strip_silence(AudioTrack *); static void *_flite_speak(void *); /* Voice */ cst_voice *flite_voice; int flite_stop = 0; MOD_OPTION_1_INT(FliteMaxChunkLength); MOD_OPTION_1_STR(FliteDelimiters); /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); MOD_OPTION_1_INT_REG(FliteMaxChunkLength, 300); MOD_OPTION_1_STR_REG(FliteDelimiters, "."); return 0; } #define ABORT(msg) g_string_append(info, msg); \ DBG("FATAL ERROR:", info->str); \ *status_info = info->str; \ g_string_free(info, 0); \ return -1; int module_init(char **status_info) { int ret; DBG("Module init"); INIT_INDEX_MARKING(); *status_info = NULL; /* Init flite and register a new voice */ flite_init(); #ifdef HAVE_REGISTER_CMU_US_KAL16 cst_voice *register_cmu_us_kal16(); /* This isn't declared in any headers. */ flite_voice = register_cmu_us_kal16(); #else cst_voice *register_cmu_us_kal(); flite_voice = register_cmu_us_kal(); #endif /* HAVE_REGISTER_CMU_US_KAL16 */ if (flite_voice == NULL) { DBG("Couldn't register the basic kal voice.\n"); *status_info = g_strdup("Can't register the basic kal voice. " "Currently only kal is supported. Seems your FLite " "installation is incomplete."); return -1; } DBG("FliteMaxChunkLength = %d\n", FliteMaxChunkLength); DBG("FliteDelimiters = %s\n", FliteDelimiters); flite_message = g_malloc(sizeof(char *)); *flite_message = NULL; sem_init(&flite_semaphore, 0, 0); DBG("Flite: creating new thread for flite_speak\n"); flite_speaking = 0; ret = pthread_create(&flite_speak_thread, NULL, _flite_speak, NULL); if (ret != 0) { DBG("Flite: thread failed\n"); *status_info = g_strdup("The module couldn't initialize threads " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return -1; } *status_info = g_strdup("Flite initialized successfully."); return 0; } #undef ABORT SPDVoice **module_list_voices(void) { return NULL; } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { DBG("write()\n"); if (flite_speaking) { DBG("Speaking when requested to write"); return 0; } DBG("Requested data: |%s|\n", data); if (*flite_message != NULL) { g_free(*flite_message); *flite_message = NULL; } *flite_message = module_strip_ssml(data); flite_message_type = SPD_MSGTYPE_TEXT; /* Setting voice */ UPDATE_PARAMETER(rate, flite_set_rate); UPDATE_PARAMETER(volume, flite_set_volume); UPDATE_PARAMETER(pitch, flite_set_pitch); /* Send semaphore signal to the speaking thread */ flite_speaking = 1; sem_post(&flite_semaphore); DBG("Flite: leaving write() normally\n\r"); return bytes; } int module_stop(void) { int ret; DBG("flite: stop()\n"); flite_stop = 1; if (module_audio_id) { DBG("Stopping audio"); ret = spd_audio_stop(module_audio_id); if (ret != 0) DBG("WARNING: Non 0 value from spd_audio_stop: %d", ret); } return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (flite_speaking) { DBG("Flite doesn't support pause, stopping\n"); module_stop(); return -1; } else { return 0; } } int module_close(void) { DBG("flite: close()\n"); DBG("Stopping speech"); if (flite_speaking) { module_stop(); } DBG("Terminating threads"); if (module_terminate_thread(flite_speak_thread) != 0) return -1; g_free(flite_voice); sem_destroy(&flite_semaphore); return 0; } /* Internal functions */ void flite_strip_silence(AudioTrack * track) { assert(track->bits == 16); unsigned i; float silence_limit = 0.001; while (track->num_samples >= track->num_channels) { for (i = 0; i < track->num_channels; i++) if (abs(track->samples[i]) >= silence_limit * (1L<<(track->bits-1))) goto stripped_head; track->samples += track->num_channels; track->num_samples -= track->num_channels; } stripped_head: while (track->num_samples >= track->num_channels) { for (i = 0; i < track->num_channels; i++) if (abs(track->samples[track->num_samples - i - 1]) >= silence_limit * (1L<<(track->bits-1))) goto stripped_tail; track->num_samples -= track->num_channels; } stripped_tail: ; } void *_flite_speak(void *nothing) { AudioTrack track; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) AudioFormat format = SPD_AUDIO_BE; #else AudioFormat format = SPD_AUDIO_LE; #endif cst_wave *wav; unsigned int pos; char *buf; int bytes; int ret; DBG("flite: speaking thread starting.......\n"); set_speaking_thread_parameters(); while (1) { sem_wait(&flite_semaphore); DBG("Semaphore on\n"); flite_stop = 0; flite_speaking = 1; /* TODO: free(buf) */ buf = (char *)g_malloc((FliteMaxChunkLength + 1) * sizeof(char)); pos = 0; module_report_event_begin(); while (1) { if (flite_stop) { DBG("Stop in child, terminating"); flite_speaking = 0; module_report_event_stop(); break; } bytes = module_get_message_part(*flite_message, buf, &pos, FliteMaxChunkLength, FliteDelimiters); if (bytes < 0) { DBG("End of message"); flite_speaking = 0; module_report_event_end(); break; } buf[bytes] = 0; DBG("Returned %d bytes from get_part\n", bytes); DBG("Text to synthesize is '%s'\n", buf); if (flite_pause_requested && (current_index_mark != -1)) { DBG("Pause requested in parent, position %d\n", current_index_mark); flite_pause_requested = 0; flite_position = current_index_mark; break; } if (bytes > 0) { DBG("Speaking in child..."); DBG("Trying to synthesize text"); wav = flite_text_to_wave(buf, flite_voice); if (wav == NULL) { DBG("Stop in child, terminating"); flite_speaking = 0; module_report_event_stop(); break; } track.num_samples = wav->num_samples; track.num_channels = wav->num_channels; track.sample_rate = wav->sample_rate; track.bits = 16; track.samples = wav->samples; flite_strip_silence(&track); DBG("Got %d samples", track.num_samples); if (track.samples != NULL) { if (flite_stop) { DBG("Stop in child, terminating"); flite_speaking = 0; module_report_event_stop(); delete_wave(wav); break; } DBG("Playing part of the message"); ret = module_tts_output(track, format); if (ret < 0) DBG("ERROR: failed to play the track"); if (flite_stop) { DBG("Stop in child, terminating (s)"); flite_speaking = 0; module_report_event_stop(); delete_wave(wav); break; } } delete_wave(wav); } else if (bytes == -1) { DBG("End of data in speaking thread"); flite_speaking = 0; module_report_event_end(); break; } else { flite_speaking = 0; module_report_event_end(); break; } if (flite_stop) { DBG("Stop in child, terminating"); flite_speaking = 0; module_report_event_stop(); break; } } flite_stop = 0; g_free(buf); } flite_speaking = 0; DBG("flite: speaking thread ended.......\n"); pthread_exit(NULL); } static void flite_set_rate(signed int rate) { float stretch = 1; assert(rate >= -100 && rate <= +100); if (rate < 0) stretch -= ((float)rate) / 50; if (rate > 0) stretch -= ((float)rate) / 175; feat_set_float(flite_voice->features, "duration_stretch", stretch); } static void flite_set_volume(signed int volume) { assert(volume >= -100 && volume <= +100); flite_volume = volume; } static void flite_set_pitch(signed int pitch) { float f0; assert(pitch >= -100 && pitch <= +100); f0 = (((float)pitch) * 0.8) + 100; feat_set_float(flite_voice->features, "int_f0_target_mean", f0); } speech-dispatcher-0.9.1/src/modules/festival_client.h0000644000175000017500000001320413377211050017617 00000000000000/*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* Copyright (c) 1999 University of Edinburgh, UK */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ /* */ /* Client end of Festival server API (in C) designed specifically for */ /* Galaxy Communicator use, though might be of use for other things */ /* */ /*=======================================================================*/ #ifndef _FESTIVAL_CLIENT_H_ #define _FESTIVAL_CLIENT_H_ #define FESTIVAL_DEFAULT_SERVER_HOST "localhost" #define FESTIVAL_DEFAULT_SERVER_PORT 1314 #define FESTIVAL_DEFAULT_TEXT_MODE "fundamental" int festival_connection_crashed; typedef struct FT_Info { int encoding; char *server_host; int server_port; char *text_mode; int server_fd; } FT_Info; typedef struct FT_Wave { int num_samples; int sample_rate; short *samples; } FT_Wave; void delete_FT_Wave(FT_Wave * wave); void delete_FT_Info(FT_Info * info); #define SWAPSHORT(x) ((((unsigned)x) & 0xff) << 8 | \ (((unsigned)x) & 0xff00) >> 8) #define SWAPINT(x) ((((unsigned)x) & 0xff) << 24 | \ (((unsigned)x) & 0xff00) << 8 | \ (((unsigned)x) & 0xff0000) >> 8 | \ (((unsigned)x) & 0xff000000) >> 24) /* Sun, HP, SGI Mips, M68000 */ #define FAPI_BIG_ENDIAN (((char *)&fapi_endian_loc)[0] == 0) /* Intel, Alpha, DEC Mips, Vax */ #define FAPI_LITTLE_ENDIAN (((char *)&fapi_endian_loc)[0] != 0) #define FEST_SEND_CMD(format) \ do { \ FILE *fd; \ char *str; \ fd = fdopen(dup(info->server_fd),"wb"); \ if (fd != NULL){ \ str = g_strdup(format"\n"); \ fputs(str, fd); \ DBG("-> Festival: |%s|", str); \ g_free(str); \ fclose(fd); \ }else{ \ DBG("Can't open connection"); \ } \ } while (0) #define FEST_SEND_CMDA(format, args...) \ do { \ FILE *fd; \ char *str; \ fd = fdopen(dup(info->server_fd),"wb"); \ if (fd != NULL){ \ str = g_strdup_printf(format"\n", args); \ fputs(str, fd); \ DBG("-> Festival: |%s|", str); \ g_free(str); \ fclose(fd); \ }else{ \ DBG("Can't open connection"); \ } \ } while (0) /*****************************************************************/ /* Public functions to interface */ /*****************************************************************/ /* If called with NULL will attempt to access using defaults */ FT_Info *festivalOpen(FT_Info * info); int festivalClose(FT_Info * info); int festivalStringToWaveRequest(FT_Info * info, const char *text); int festivalSoundIcon(FT_Info * info, const char *text); int festivalCharacter(FT_Info * info, const char *text); int festivalKey(FT_Info * info, const char *text); int festivalSpell(FT_Info * info, const char *text); FT_Wave *festivalStringToWaveGetData(FT_Info * info); FT_Info *festivalDefaultInfo(); void festivalEmptySocket(FT_Info * info); int save_FT_Wave_snd(FT_Wave * wave, const char *filename); FT_Wave *festivalGetDataMulti(FT_Info * info, char **callback, int *stop_flag, int stop_by_close); int festival_check_info(FT_Info * info, char *fnname); char **lisp_list_get_vect(char *expr); int festival_read_response(FT_Info * info, char **expr); #endif speech-dispatcher-0.9.1/src/modules/festival_client.c0000644000175000017500000005206313377211050017620 00000000000000/*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* Copyright (c) 1999 University of Edinburgh, UK */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /* Modified: Hynek Hanke (hanke@brailcom.org) (2003-2005) */ /*-----------------------------------------------------------------------*/ /* */ /* Client end of Festival server API in C designed specifically formerly */ /* for Galaxy Communicator use, but rewritten to suit Speech Dispatcher */ /* needs. Please look also at the original festival_client.c library */ /* that can be found in festival/examples/festival_client.c -- it will */ /* be probably more up-to-date. */ /* */ /* This can be also compiled as a stand-alone program for testing */ /* purposes: */ /* gcc -o festival_client -DSTANDALONE festival_client.c */ /* and run as: */ /* ./festival_client */ /* This creates a file test.snd, containing the synthesized waveform */ /* You can run for example: */ /* play test.snd */ /* to hear the message */ /*=======================================================================*/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include /* I'm including my local .h, not the Alan's one! */ #include "festival_client.h" #include "module_utils.h" /* For testing endianness */ int fapi_endian_loc = 1; static char *socket_receive_file_to_buff(int fd, int *size); /* --- MANAGING FT STRUCTURES --- */ void delete_FT_Wave(FT_Wave * wave) { if (wave != 0) { if (wave->samples != 0) g_free(wave->samples); g_free(wave); } } int save_FT_Wave_snd(FT_Wave * wave, const char *filename) { FILE *fd; struct { unsigned int magic; /* magic number */ unsigned int hdr_size; /* size of this header */ int data_size; /* length of data (optional) */ unsigned int encoding; /* data encoding format */ unsigned int sample_rate; /* samples per second */ unsigned int channels; /* number of interleaved channels */ } header; short sw_short; int i; if ((filename == 0) || (strcmp(filename, "stdout") == 0) || (strcmp(filename, "-") == 0)) fd = stdout; else if ((fd = fopen(filename, "wb")) == NULL) { fprintf(stderr, "save_FT_Wave: can't open file \"%s\" for writing\n", filename); return -1; } header.magic = (unsigned int)0x2e736e64; header.hdr_size = sizeof(header); header.data_size = 2 * wave->num_samples; header.encoding = 3; /* short */ header.sample_rate = wave->sample_rate; header.channels = 1; if (FAPI_LITTLE_ENDIAN) { /* snd is always sparc/68000 byte order */ header.magic = SWAPINT(header.magic); header.hdr_size = SWAPINT(header.hdr_size); header.data_size = SWAPINT(header.data_size); header.encoding = SWAPINT(header.encoding); header.sample_rate = SWAPINT(header.sample_rate); header.channels = SWAPINT(header.channels); } /* write header */ if (fwrite(&header, sizeof(header), 1, fd) != 1) return -1; if (FAPI_BIG_ENDIAN) fwrite(wave->samples, sizeof(short), wave->num_samples, fd); else { /* have to swap */ for (i = 0; i < wave->num_samples; i++) { sw_short = SWAPSHORT(wave->samples[i]); fwrite(&sw_short, sizeof(short), 1, fd); } } if (fd != stdout) fclose(fd); return 0; } void delete_FT_Info(FT_Info * info) { if (info != 0) g_free(info); } /* --- FESTIVAL REPLY PARSING --- */ static int nist_get_param_int(char *hdr, char *field, int def_val) { char *p; int val; if (((p = strstr(hdr, field)) != NULL) && (strncmp(" -i ", p + strlen(field), 4) == 0)) { sscanf(p + strlen(field) + 4, "%d", &val); return val; } else return def_val; } static int nist_require_swap(char *hdr) { char *p; char *field = "sample_byte_format"; if ((p = strstr(hdr, field)) != NULL) { if (((strncmp(" -s2 01", p + strlen(field), 7) == 0) && FAPI_BIG_ENDIAN) || ((strncmp(" -s2 10", p + strlen(field), 7) == 0) && FAPI_LITTLE_ENDIAN)) return 1; } return 0; /* if unknown assume native byte order */ } /* --- FESTIVAL SOCKET MANIPULATION --- */ /* Return an FD to a remote server */ static int festival_socket_open(const char *host, int port) { struct sockaddr_in serv_addr; struct hostent *serverhost; int fd; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { fprintf(stderr, "festival_client: can't get socket\n"); return -1; } memset(&serv_addr, 0, sizeof(serv_addr)); if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) { /* its a name rather than an ipnum */ serverhost = gethostbyname(host); if (serverhost == (struct hostent *)0) { fprintf(stderr, "festival_client: gethostbyname failed\n"); return -1; } memmove(&serv_addr.sin_addr, serverhost->h_addr, serverhost->h_length); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { fprintf(stderr, "festival_client: connect to server failed\n"); return -1; } return fd; } /* Receive file (probably a waveform file) from socket using */ /* Festival key stuff technique, but long winded I know, sorry */ /* but will receive any file without closing the stream or */ /* using OOB data */ static char *socket_receive_file_to_buff(int fd, int *size) { static char *file_stuff_key = "ft_StUfF_key"; /* must == Festival's key */ char *buff; int bufflen; int n, k, i; char c; if (fd < 0) return NULL; bufflen = 1024; buff = (char *)g_malloc(bufflen); *size = 0; for (k = 0; file_stuff_key[k] != '\0';) { n = read(fd, &c, 1); if (n <= 0) { DBG("ERROR: FESTIVAL CLOSED CONNECTION (1)"); close(fd); festival_connection_crashed = 1; g_free(buff); return NULL; /* hit stream eof before end of file */ } if ((*size) + k + 1 >= bufflen) { /* +1 so you can add a NULL if you want */ bufflen += bufflen / 4; buff = (char *)g_realloc(buff, bufflen); } if (file_stuff_key[k] == c) k++; else if ((c == 'X') && (file_stuff_key[k + 1] == '\0')) { /* It looked like the key but wasn't */ for (i = 0; i < k; i++, (*size)++) buff[*size] = file_stuff_key[i]; k = 0; /* omit the stuffed 'X' */ } else { for (i = 0; i < k; i++, (*size)++) buff[*size] = file_stuff_key[i]; k = 0; buff[*size] = c; (*size)++; } } return buff; } static char *client_accept_s_expr(int fd) { /* Read s-expression from server, as a char * */ char *expr; int filesize; if (fd < 0) return NULL; expr = socket_receive_file_to_buff(fd, &filesize); expr[filesize] = '\0'; return expr; } static FT_Wave *client_accept_waveform(int fd, int *stop_flag, int stop_by_close) { /* Read waveform from server */ char *wavefile; int filesize; int num_samples, sample_rate, i; FT_Wave *wave; if (fd < 0) return NULL; wavefile = socket_receive_file_to_buff(fd, &filesize); if (wavefile == NULL) return NULL; wave = NULL; /* I know this is NIST file and its an error if it isn't */ if (filesize >= 1024) { /* If this doesn't work, probably you forgot to set the output file type to NIST ! by Parameter.set */ num_samples = nist_get_param_int(wavefile, "sample_count", 1); sample_rate = nist_get_param_int(wavefile, "sample_rate", 16000); if ((num_samples * sizeof(short)) + 1024 == filesize) { wave = (FT_Wave *) g_malloc(sizeof(FT_Wave)); DBG("Number of samples from festival: %d", num_samples); wave->num_samples = num_samples; wave->sample_rate = sample_rate; if (num_samples != 0) { wave->samples = (short *)g_malloc(num_samples * sizeof(short)); memmove(wave->samples, wavefile + 1024, num_samples * sizeof(short)); if (nist_require_swap(wavefile)) for (i = 0; i < num_samples; i++) wave->samples[i] = SWAPSHORT(wave->samples[i]); } else { wave->samples = NULL; } } } g_free(wavefile); return wave; } int festival_get_ack(FT_Info ** info, char *ack) { int read_bytes; int n; if (*info == NULL) return -1; if ((*info)->server_fd < 0) return -1; for (n = 0; n < 3;) { read_bytes = read((*info)->server_fd, ack + n, 3 - n); if (read_bytes <= 0) { /* WARNING: This is a very strange situation but it happens often, I don't really know why??? */ DBG("ERROR: FESTIVAL CLOSED CONNECTION (2)"); close((*info)->server_fd); festival_connection_crashed = 1; return -1; } n += read_bytes; } ack[3] = '\0'; return 0; } int festival_read_response(FT_Info * info, char **expr) { char buf[4]; char *r; DBG("Com: Reading response"); if (info == NULL) return 1; if (info->server_fd < 0) return 1; if (festival_get_ack(&info, buf)) return 1; buf[3] = 0; DBG("<- Festival: |%s|", buf); if (!strcmp(buf, "ER\n")) { if (expr != NULL) *expr = NULL; return 1; } else { if (expr != NULL) { *expr = client_accept_s_expr(info->server_fd); } else { r = client_accept_s_expr(info->server_fd); if (r != NULL) g_free(r); } } if (festival_get_ack(&info, buf)) return 1; DBG("<- Festival: |%s|", buf); return 0; } int festival_accept_any_response(FT_Info * info) { char ack[4]; int r; char *expr; DBG("Com: Accepting any response"); do { if ((r = festival_get_ack(&info, ack))) return r; DBG("<- Festival: |%s|", ack); if (strcmp(ack, "WV\n") == 0) { /* receive a waveform */ client_accept_waveform(info->server_fd, NULL, 0); } else if (strcmp(ack, "LP\n") == 0) { /* receive an s-expr */ expr = client_accept_s_expr(info->server_fd); if (expr != NULL) g_free(expr); } else if (strcmp(ack, "ER\n") == 0) { /* server got an error */ /* This message ER is returned even if it was because there was no sound produced, for this reason, the warning is disabled */ /* fprintf(stderr,"festival_client: server returned error\n"); */ break; } } while (strcmp(ack, "OK\n") != 0); return 0; } /* --- HELPER FUNCTIONS --- */ int festival_check_info(FT_Info * info, char *fnname) { assert(fnname != NULL); if ((info == NULL) || (info->server_fd == -1)) { DBG("%s called with info = NULL or server_fd == -1\n", fnname); return -1; } return 0; } /***********************************************************************/ /* Public Functions to this API */ /***********************************************************************/ /* Opens a connection to Festival server (which must be running) * and returns it's identification in new FT_Info */ FT_Info *festivalOpen(FT_Info * info) { char *resp; int ret; DBG("Opening socket fo Festival server"); festival_connection_crashed = 0; if (info == 0) info = festivalDefaultInfo(); info->server_fd = festival_socket_open(info->server_host, info->server_port); if (info->server_fd == -1) { delete_FT_Info(info); festival_connection_crashed = 1; return NULL; } FEST_SEND_CMD("(require 'speech-dispatcher)"); ret = festival_read_response(info, &resp); if (ret || resp == NULL || strcmp(resp, "t\n")) { DBG("ERROR: Can't load speech-dispatcher module into Festival." "Reason: %s", resp); return NULL; } g_free(resp); FEST_SEND_CMD("(Parameter.set 'Wavefiletype 'nist)\n"); ret = festival_read_response(info, &resp); if (ret || resp == NULL || strcmp(resp, "nist\n")) { DBG("ERROR: Can't set Wavefiletype to nist in Festival. Reason: %s", resp); return NULL; } g_free(resp); return info; } int festival_speak_command(FT_Info * info, char *command, const char *text, int symbol, int resp) { FILE *fd; const char *p; char *str; int ret; if (festival_check_info(info, "festival_speak_command") == -1) return -1; if (command == NULL) return -1; if (text == NULL) return -1; DBG("(festival_speak_command): %s", text); /* Opens a stream associated to the socket */ fd = fdopen(dup(info->server_fd), "wb"); /* Send the command and data */ if (symbol == 0) str = g_strdup_printf("(%s \"", command); else str = g_strdup_printf("(%s '", command); fputs(str, fd); /* Copy text over to server, escaping any quotes */ for (p = text; p && (*p != '\0'); p++) { if ((*p == '"') || (*p == '\\')) putc('\\', fd); putc(*p, fd); } if (symbol == 0) fprintf(fd, "\")\n"); else fprintf(fd, ")\n"); DBG("-> Festival: escaped text is %s", text); DBG("-> Festival: |%sthe text is displayed above\")|", str); g_free(str); /* Close the stream (but not the socket) */ fclose(fd); DBG("Resources freed"); if (resp) { ret = festival_read_response(info, NULL); if (ret) { DBG("ERROR: Festival reported error in speak command);"); return -1; } } return 0; } #define FEST_SPEAK_CMD(name, cmd, symbol, resp) \ int \ name(FT_Info *info, const char *text) \ { \ return festival_speak_command(info, cmd, text, symbol, resp); \ } /* Sends a TEXT to Festival server for synthesis. Doesn't * wait for reply (see festivalStringToWaveGetData()). * Please make sure that the socket is empty before calling * this command -- otherwise, you would get another message * in response. * Returns 0 if everything is ok, -1 otherwise. */ FEST_SPEAK_CMD(festivalStringToWaveRequest, "speechd-speak-ssml", 0, 1) FEST_SPEAK_CMD(festivalSpell, "speechd-spell", 0, 1) FEST_SPEAK_CMD(festivalSoundIcon, "speechd-sound-icon", 1, 0) FEST_SPEAK_CMD(festivalCharacter, "speechd-character", 0, 0) FEST_SPEAK_CMD(festivalKey, "speechd-key", 0, 0) /* Reads the wavefile sent back after festivalStringToWaveRequest() * has been called. This function blocks until all the data is * available. Note that for longer messages this can be quite long * on some slower machines. */ FT_Wave *festivalStringToWaveGetData(FT_Info * info) { FT_Wave *wave = NULL; char ack[5]; /* Read back info from server */ /* This assumes only one waveform will come back, also LP is unlikely */ do { if (festival_get_ack(&info, ack)) return NULL; DBG("<- Festival: %s", ack); if (strcmp(ack, "WV\n") == 0) { wave = client_accept_waveform(info->server_fd, NULL, 0); } else if (strcmp(ack, "LP\n") == 0) { client_accept_s_expr(info->server_fd); } else if (strcmp(ack, "ER\n") == 0) { // fprintf(stderr,"festival_client: server returned error\n"); break; } } while (strcmp(ack, "OK\n") != 0); return wave; } FT_Wave *festivalGetDataMulti(FT_Info * info, char **callback, int *stop_flag, int stop_by_close) { FT_Wave *wave = NULL; char ack[5]; char *resp = NULL; FILE *fd; if (festival_check_info(info, "festival_speak_command") == -1) { return NULL; } /* Read back info from server */ /* This assumes only one waveform will come back */ wave = NULL; *callback = NULL; DBG("Stop by close mode : %d", stop_by_close); DBG("-> Festival: (speechd-next)"); fd = fdopen(dup(info->server_fd), "wb"); fprintf(fd, "(speechd-next)\n"); fflush(fd); fclose(fd); do { if (festival_get_ack(&info, ack)) { DBG("Get ack failed"); return NULL; } DBG("<- Festival: %s", ack); if (strcmp(ack, "WV\n") == 0) { wave = client_accept_waveform(info->server_fd, stop_flag, stop_by_close); } else if (strcmp(ack, "LP\n") == 0) { if (resp != NULL) g_free(resp); resp = client_accept_s_expr(info->server_fd); if (resp == NULL) { DBG("ERROR: Something wrong in communication with Festival, s_expr = NULL"); return NULL; } if (strlen(resp) != 0) resp[strlen(resp) - 1] = 0; DBG("<- Festival: |%s|", resp); if (!strcmp(resp, "nil")) { DBG("festival_client: end of samples\n"); g_free(resp); wave = NULL; resp = NULL; } } else if (strcmp(ack, "ER\n") == 0) { DBG("festival_client: server returned error\n"); return NULL; } } while (strcmp(ack, "OK\n") != 0); if (resp) { if ((strlen(resp) > 0) && (resp[0] != '#')) *callback = resp; else g_free(resp); } return wave; } /* Closes the Festival server socket connection */ int festivalClose(FT_Info * info) { if (info == 0) return 0; if (info->server_fd != -1) { FILE *fd; fd = fdopen(dup(info->server_fd), "wb"); if (fd != NULL) { fprintf(fd, "(quit)\n"); fclose(fd); } close(info->server_fd); } return 0; } /* --- INFORMATION RETRIEVAL COMMANDS --- */ char **lisp_list_get_vect(char *expr) { size_t len; char *helper; gchar **vect; size_t i, j; len = strlen(expr); helper = g_malloc(sizeof(char) * (len + 1)); //Remove parenthesis j = 0; for (i = 0; i < len; i++) { if ((expr[i] != '(') && (expr[i] != ')')) { helper[j] = expr[i]; j++; } } helper[j] = '\0'; // Split into a vector of atoms vect = g_strsplit(helper, " ", 0); return vect; } char *vect_read_item(char **vect, char *field) { int i; for (i = 0;; i++) { if (vect[i] == NULL) return NULL; else { if (!strcmp(vect[i], field)) { if (vect[i + 1] != NULL) return vect[i + 1]; else return NULL; } } } } FT_Info *festivalDefaultInfo() { FT_Info *info; info = (FT_Info *) g_malloc(sizeof(FT_Info)); info->server_host = FESTIVAL_DEFAULT_SERVER_HOST; info->server_port = FESTIVAL_DEFAULT_SERVER_PORT; info->text_mode = FESTIVAL_DEFAULT_TEXT_MODE; info->server_fd = -1; return info; } /* For testing purposes, this library can be compiled as * a standalone program, please see the introduction at * the beginning of this file */ #ifdef STANDALONE int main(int argc, char **argv) { char *server = 0; int port = -1; char *text = 0; char *output = 0; char *mode = 0; int i; FT_Info *info; FT_Wave *wave; printf("Welcome to Festival client library for Speech Dispatcher\n"); info = festivalDefaultInfo(); if (server != 0) info->server_host = FESTIVAL_DEFAULT_SERVER_HOST; if (port != -1) info->server_port = FESTIVAL_DEFAULT_SERVER_PORT; if (mode != 0) info->text_mode = FESTIVAL_DEFAULT_TEXT_MODE; info = festivalOpen(info); if (info == 0) { printf("Can't open connection to festival server!\n"); exit(1); } if (info->server_fd <= 0) { printf("Can't open connection to festival server!\n"); exit(1); } festivalStringToWaveRequest(info, "Hi, how are you? I'm Festival! And who are you?"); wave = festivalStringToWaveGetData(info); if (wave != 0) { save_FT_Wave_snd(wave, "test.snd"); } else { printf("Wave null! Festival server doesn't work properly.\n"); exit(1); } festivalClose(info); printf("The synthesized text should have been written to test.snd\n"); return 0; } #endif speech-dispatcher-0.9.1/src/modules/festival.c0000644000175000017500000007211713406252440016265 00000000000000/* * festival.c - Speech Dispatcher backend for Festival * * Copyright (C) 2003, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: festival.c,v 1.82 2008-06-09 10:33:38 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "fdsetconv.h" #include "festival_client.h" #include "module_utils.h" #define MODULE_NAME "festival" #define MODULE_VERSION "0.5" DECLARE_DEBUG() /* Thread and process control */ static pthread_t festival_speak_thread; static sem_t festival_semaphore; static int festival_speaking = 0; static int festival_pause_requested = 0; static char **festival_message; static SPDMessageType festival_message_type; signed int festival_volume = 0; int festival_stop_request = 0; int festival_stop = 0; int festival_process_pid = 0; FT_Info *festival_info = NULL; SPDVoice **festival_voice_list = NULL; enum { FCT_SOCKET = 0, FCT_LOCAL = 1, } FestivalComType; struct { int pipe_in[2]; int pipe_out[2]; int pid; } module_p; #define COM_SOCKET ((FestivalComType == FCT_SOCKET) ? 1 : 0) #define COM_LOCAL ((FestivalComType == FCT_LOCAL) ? 1 : 0) /* --- SETTINGS COMMANDS --- */ #define FEST_SET_STR(name, fest_param) \ int \ name(FT_Info *info, char *param, char **resp) \ { \ char *r; \ int ret; \ char *f; \ if (festival_check_info(info, #name)) return -1; \ if (param == NULL){ \ FEST_SEND_CMD("("fest_param" nil)"); \ }else{ \ f = g_ascii_strdown(param, -1); \ FEST_SEND_CMDA("("fest_param" \"%s\")", f); \ g_free(f); \ } \ ret = festival_read_response(info, &r); \ if (ret != 0) return -1; \ if (r != NULL){ \ if (resp != NULL) \ *resp = r; \ else \ g_free(r); \ } \ return ret; \ } #define FEST_SET_SYMB(name, fest_param) \ int \ name(FT_Info *info, char *param) \ { \ char *f = NULL; \ if (festival_check_info(info, #name)) return -1; \ if (param == NULL) return -1; \ FEST_SEND_CMDA("("fest_param" '%s)", f = g_ascii_strdown(param, -1)); \ g_free(f); \ return festival_read_response(info, NULL); \ } #define FEST_SET_INT(name, fest_param) \ int \ name(FT_Info *info, int param) \ { \ if (festival_check_info(info, #name)) return -1; \ FEST_SEND_CMDA("("fest_param" %d)", param); \ return festival_read_response(info, NULL); \ } FEST_SET_SYMB(FestivalSetMultiMode, "speechd-enable-multi-mode") FEST_SET_INT(FestivalSetRate, "speechd-set-rate") FEST_SET_INT(FestivalSetPitch, "speechd-set-pitch") FEST_SET_SYMB(FestivalSetPunctuationMode, "speechd-set-punctuation-mode") FEST_SET_STR(FestivalSetCapLetRecogn, "speechd-set-capital-character-recognition-mode") FEST_SET_STR(FestivalSetLanguage, "speechd-set-language") FEST_SET_STR(FestivalSetVoice, "speechd-set-voice") FEST_SET_SYMB(FestivalSetSynthesisVoice, "speechd-set-festival-voice") /* Internal functions prototypes */ static SPDVoice **festivalGetVoices(FT_Info * info); void *_festival_speak(void *); void festival_parent_clean(); void festival_set_rate(signed int rate); void festival_set_pitch(signed int pitch); void festival_set_voice(SPDVoiceType voice); void festival_set_synthesis_voice(char *synthesis_voice); void festival_set_language(char *language); void festival_set_punctuation_mode(SPDPunctuation punct); void festival_set_cap_let_recogn(SPDCapitalLetters recogn); void festival_set_volume(signed int volume); int init_festival_standalone(); int init_festival_socket(); int is_text(SPDMessageType msg_type); MOD_OPTION_1_INT(FestivalComunicationType) MOD_OPTION_1_INT(FestivalMaxChunkLength) MOD_OPTION_1_STR(FestivalDelimiters) MOD_OPTION_1_STR(FestivalServerHost) MOD_OPTION_1_STR(FestivalStripPunctChars) MOD_OPTION_1_INT(FestivalServerPort) MOD_OPTION_1_INT(FestivalPitchDeviation) MOD_OPTION_1_INT(FestivalDebugSaveOutput) MOD_OPTION_1_STR(FestivalRecodeFallback) MOD_OPTION_1_INT(FestivalCacheOn) MOD_OPTION_1_INT(FestivalCacheMaxKBytes) MOD_OPTION_1_INT(FestivalCacheDistinguishVoices) MOD_OPTION_1_INT(FestivalCacheDistinguishRate) MOD_OPTION_1_INT(FestivalCacheDistinguishPitch) MOD_OPTION_1_INT(FestivalReopenSocket) typedef struct { size_t size; GHashTable *caches; GList *cache_counter; } TCache; typedef struct { time_t start; int count; size_t size; GHashTable *p_caches; char *key; } TCounterEntry; typedef struct { TCounterEntry *p_counter_entry; FT_Wave *fwave; } TCacheEntry; TCache FestivalCache; int cache_init(); int cache_reset(); int cache_insert(char *key, SPDMessageType msgtype, FT_Wave * value); FT_Wave *cache_lookup(const char *key, SPDMessageType msgtype, int add_counter); pthread_mutex_t sound_output_mutex; /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); MOD_OPTION_1_INT_REG(FestivalComunicationType, 0); MOD_OPTION_1_STR_REG(FestivalServerHost, "localhost"); MOD_OPTION_1_INT_REG(FestivalServerPort, 1314); MOD_OPTION_1_INT_REG(FestivalDebugSaveOutput, 0); MOD_OPTION_1_STR_REG(FestivalRecodeFallback, "?"); MOD_OPTION_1_INT_REG(FestivalCacheOn, 1); MOD_OPTION_1_INT_REG(FestivalCacheMaxKBytes, 5120); MOD_OPTION_1_INT_REG(FestivalCacheDistinguishVoices, 0); MOD_OPTION_1_INT_REG(FestivalCacheDistinguishRate, 0); MOD_OPTION_1_INT_REG(FestivalCacheDistinguishPitch, 0); /* TODO: Maybe switch this option to 1 when the bug with the 40ms delay in Festival is fixed */ MOD_OPTION_1_INT_REG(FestivalReopenSocket, 0); return 0; } #define ABORT(msg) g_string_append(info, msg); \ *status_info = info->str; \ g_string_free(info, 0); \ return -1; int module_init(char **status_info) { int ret; GString *info; info = g_string_new(""); DBG("module_init()"); INIT_INDEX_MARKING(); /* Initialize appropriate communication mechanism */ FestivalComType = FestivalComunicationType; if (COM_SOCKET) { g_string_append(info, "Communicating with Festival through a socket. "); ret = init_festival_socket(); if (ret == -1) { ABORT ("Can't connect to Festival server. Check your configuration " "in etc/speech-dispatcher/modules/festival.conf for the specified host and port " "and check if Festival is really running there, e.g. with telnet. " "Please see documentation for more info."); } else if (ret == -2) { ABORT("Connect to the Festival server was successful, " "but I got disconnected immediately. This is most likely " "because of authorization problems. Check the variable " "server_access_list in etc/festival.scm and consult documentation " "for more information."); } } if (COM_LOCAL) { g_string_append(info, "Communicating with Festival through a local child process."); if (init_festival_standalone()) { ABORT ("Local connect to Festival failed for unknown reasons."); } } /* Get festival voice list */ festival_voice_list = festivalGetVoices(festival_info); /* Initialize global variables */ festival_message = (char **)g_malloc(sizeof(char *)); *festival_message = NULL; /* Initialize festival_speak thread to handle communication with festival in a separate thread (to be faster in communication with Speech Dispatcher) */ sem_init(&festival_semaphore, 0, 0); DBG("Festival: creating new thread for festival_speak\n"); festival_speaking = 0; ret = pthread_create(&festival_speak_thread, NULL, _festival_speak, NULL); if (ret != 0) { DBG("Festival: thread failed\n"); g_string_append(info, "The module couldn't initialize threads" "This can be either an internal problem or an" "architecture problem. If you are sure your architecture" "supports threads, please report a bug."); *status_info = info->str; g_string_free(info, 0); return -1; } pthread_mutex_init(&sound_output_mutex, NULL); *status_info = info->str; g_string_free(info, 0); return 0; } #undef ABORT SPDVoice **module_list_voices(void) { return festival_voice_list; } int module_speak(char *data, size_t bytes, SPDMessageType msgtype) { int ret; DBG("module_speak()\n"); if (data == NULL) return -1; if (festival_speaking) { DBG("Speaking when requested to write\n"); return -1; } festival_stop_request = 0; festival_message_type = msgtype; if ((msgtype == SPD_MSGTYPE_TEXT) && (msg_settings.spelling_mode == SPD_SPELL_ON)) festival_message_type = SPD_MSGTYPE_SPELL; /* If the connection crashed or language or voice change, we will need to set all the parameters again */ if (COM_SOCKET) { if (festival_connection_crashed) { DBG("Recovering after a connection loss"); CLEAN_OLD_SETTINGS_TABLE(); festival_info = festivalOpen(festival_info); if (festival_info) festival_connection_crashed = 0; else { DBG("Can't recover. Not possible to open connection to Festival."); return -1; } ret = FestivalSetMultiMode(festival_info, "t"); if (ret != 0) return -1; } } /* If the voice was changed, re-set all the parameters */ // TODO: Handle synthesis_voice change too if ((msg_settings.voice_type != msg_settings_old.voice_type) || ((msg_settings.voice.language != NULL) && (msg_settings_old.voice.language != NULL) && (strcmp (msg_settings.voice.language, msg_settings_old.voice.language)))) { DBG("Cleaning old settings table"); CLEAN_OLD_SETTINGS_TABLE(); } /* Setting voice parameters */ DBG("Updating parameters"); UPDATE_STRING_PARAMETER(voice.language, festival_set_language); UPDATE_PARAMETER(voice_type, festival_set_voice); UPDATE_STRING_PARAMETER(voice.name, festival_set_synthesis_voice); UPDATE_PARAMETER(rate, festival_set_rate); UPDATE_PARAMETER(pitch, festival_set_pitch); UPDATE_PARAMETER(volume, festival_set_volume); UPDATE_PARAMETER(punctuation_mode, festival_set_punctuation_mode); UPDATE_PARAMETER(cap_let_recogn, festival_set_cap_let_recogn); if (festival_connection_crashed) { DBG("ERROR: Festival connection not working!"); return -1; } DBG("Requested data: |%s| \n", data); g_free(*festival_message); *festival_message = g_strdup(data); if (*festival_message == NULL) { DBG("Error: Copying data unsuccessful."); return -1; } /* Send semaphore signal to the speaking thread */ festival_speaking = 1; sem_post(&festival_semaphore); DBG("Festival: leaving write() normally\n\r"); return bytes; } int module_stop(void) { DBG("stop()\n"); if (festival_speaking) { /* if(COM_SOCKET) */ if (0) { if (festival_info != 0) if ((festival_info->server_fd != -1) && FestivalReopenSocket) { /* TODO: Maybe use shutdown here? */ close(festival_info->server_fd); festival_info->server_fd = -1; festival_connection_crashed = 1; DBG("festival socket closed by module_stop()"); } } if (COM_LOCAL) { DBG("festival local stopped by sending SIGINT"); /* TODO: Write this function for local communication */ // festival_stop_local(); } if (!festival_stop) { pthread_mutex_lock(&sound_output_mutex); festival_stop = 1; if (festival_speaking && module_audio_id) { spd_audio_stop(module_audio_id); } pthread_mutex_unlock(&sound_output_mutex); } } return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (festival_speaking) { DBG("Sending request for pause to child\n"); festival_pause_requested = 1; DBG("Signalled to pause"); return 0; } else { return -1; } } int module_close(void) { DBG("festival: close()\n"); DBG("Stopping the module"); while (festival_speaking) { module_stop(); usleep(50); } // DBG("festivalClose()"); // festivalClose(festival_info); DBG("Terminating threads"); if (festival_speak_thread) module_terminate_thread(festival_speak_thread); if (festival_info) delete_FT_Info(festival_info); /* TODO: Solve this */ // DBG("Removing junk files in tmp/"); // system("rm -f /tmp/est* 2> /dev/null"); sem_destroy(&festival_semaphore); return 0; } /* Internal functions */ #define CLEAN_UP(code, im) \ { \ if(!wave_cached) if (fwave) delete_FT_Wave(fwave); \ pthread_mutex_lock(&sound_output_mutex); \ festival_stop = 0; \ festival_speaking = 0; \ pthread_mutex_unlock(&sound_output_mutex); \ im(); \ goto sem_wait; \ } #define CLP(code, im) \ { \ pthread_mutex_lock(&sound_output_mutex); \ festival_stop = 0; \ festival_speaking = 0; \ pthread_mutex_unlock(&sound_output_mutex); \ im(); \ goto sem_wait; \ } static SPDVoice **festivalGetVoices(FT_Info * info) { char *reply; char **voices; char *lang; char *variant; int i, j; int num_voices = 0; SPDVoice **result; FEST_SEND_CMD("(apply append (voice-list-language-codes))"); festival_read_response(info, &reply); if (reply == NULL) { DBG("ERROR: Invalid reply for voice-list"); return NULL; } /* Remove trailing newline */ reply[strlen(reply) - 1] = 0; DBG("Voice list reply: |%s|", reply); voices = lisp_list_get_vect(reply); if (voices == NULL) { DBG("ERROR: Can't parse voice listing reply into vector"); return NULL; } /* Compute number of voices */ for (i = 0;; i++, num_voices++) if (voices[i] == NULL) break; num_voices /= 3; result = g_malloc((num_voices + 1) * sizeof(SPDVoice *)); for (i = 0, j = 0;; j++) { if (voices[i] == NULL) break; else if (strlen(voices[i]) == 0) continue; else { result[j] = g_malloc(sizeof(SPDVoice)); result[j]->name = voices[i]; lang = voices[i + 1]; if ((lang != NULL) && (strcmp(lang, "nil"))) result[j]->language = g_strdup(lang); else result[j]->language = NULL; variant = voices[i + 2]; if ((variant != NULL) && (strcmp(variant, "nil"))) result[j]->variant = g_strdup(variant); else result[j]->variant = NULL; i += 3; } } result[j] = NULL; return result; } int festival_send_to_audio(FT_Wave * fwave) { AudioTrack track; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) AudioFormat format = SPD_AUDIO_BE; #else AudioFormat format = SPD_AUDIO_LE; #endif int ret = 0; if (fwave->samples == NULL) return 0; track.num_samples = fwave->num_samples; track.num_channels = 1; track.sample_rate = fwave->sample_rate; track.bits = 16; track.samples = fwave->samples; DBG("Sending to audio"); ret = module_tts_output(track, format); if (ret < 0) DBG("ERROR: Can't play track for unknown reason."); DBG("Sent to audio."); return 0; } void *_festival_speak(void *nothing) { int ret; int bytes; int wave_cached; FT_Wave *fwave; int debug_count = 0; int r; int terminate = 0; char *callback; DBG("festival: speaking thread starting.......\n"); cache_init(); set_speaking_thread_parameters(); while (1) { sem_wait: sem_wait(&festival_semaphore); DBG("Semaphore on, speaking\n"); festival_stop = 0; festival_speaking = 1; wave_cached = 0; fwave = NULL; terminate = 0; bytes = strlen(*festival_message); module_report_event_begin(); DBG("Going to synthesize: |%s|", *festival_message); if (bytes > 0) { if (!is_text(festival_message_type)) { /* it is a raw text */ DBG("Cache mechanisms..."); fwave = cache_lookup(*festival_message, festival_message_type, 1); if (fwave != NULL) { wave_cached = 1; if (fwave->num_samples != 0) { if (FestivalDebugSaveOutput) { char filename_debug [256]; sprintf(filename_debug, "/tmp/debug-festival-%d.snd", debug_count++); save_FT_Wave_snd(fwave, filename_debug); } festival_send_to_audio(fwave); if (!festival_stop) { CLEAN_UP(0, module_report_event_end); } else { CLEAN_UP(0, module_report_event_stop); } } else { CLEAN_UP(0, module_report_event_end); } } } /* Set multi-mode for appropriate kind of events */ if (is_text(festival_message_type)) { /* it is a raw text */ ret = FestivalSetMultiMode(festival_info, "t"); if (ret != 0) CLP(0, module_report_event_stop); } else { /* it is some kind of event */ ret = FestivalSetMultiMode(festival_info, "nil"); if (ret != 0) CLP(0, module_report_event_stop); } switch (festival_message_type) { case SPD_MSGTYPE_TEXT: r = festivalStringToWaveRequest(festival_info, *festival_message); break; case SPD_MSGTYPE_SOUND_ICON: r = festivalSoundIcon(festival_info, *festival_message); break; case SPD_MSGTYPE_CHAR: r = festivalCharacter(festival_info, *festival_message); break; case SPD_MSGTYPE_KEY: r = festivalKey(festival_info, *festival_message); break; case SPD_MSGTYPE_SPELL: r = festivalSpell(festival_info, *festival_message); break; default: r = -1; } if (r < 0) { DBG("Couldn't process the request to say the object."); CLP(0, module_report_event_stop); } } while (1) { wave_cached = 0; DBG("Retrieving data\n"); /* (speechd-next) */ if (is_text(festival_message_type)) { if (festival_stop) { DBG("Module stopped 1"); CLEAN_UP(0, module_report_event_stop); } DBG("Getting data in multi mode"); fwave = festivalGetDataMulti(festival_info, &callback, &festival_stop_request, FestivalReopenSocket); if (callback != NULL) { if ((festival_pause_requested) && (!strncmp (callback, INDEX_MARK_BODY, INDEX_MARK_BODY_LEN))) { DBG("Pause requested, pausing."); module_report_index_mark (callback); g_free(callback); festival_pause_requested = 0; CLEAN_UP(0, module_report_event_pause); } else { module_report_index_mark (callback); g_free(callback); continue; } } } else { /* is event */ DBG("Getting data in single mode"); fwave = festivalStringToWaveGetData(festival_info); terminate = 1; callback = NULL; } if (fwave == NULL) { DBG("End of sound samples, terminating this message..."); CLEAN_UP(0, module_report_event_end); } if (festival_message_type == SPD_MSGTYPE_CHAR || festival_message_type == SPD_MSGTYPE_KEY || festival_message_type == SPD_MSGTYPE_SOUND_ICON) { DBG("Storing record for %s in cache\n", *festival_message); /* cache_insert takes care of not inserting the same message again */ cache_insert(g_strdup(*festival_message), festival_message_type, fwave); wave_cached = 1; } if (festival_stop) { DBG("Module stopped 2"); CLEAN_UP(0, module_report_event_stop); } if (fwave->num_samples != 0) { DBG("Sending message to audio: %lu bytes\n", (long unsigned)((fwave->num_samples) * sizeof(short))); if (FestivalDebugSaveOutput) { char filename_debug[256]; sprintf(filename_debug, "/tmp/debug-festival-%d.snd", debug_count++); save_FT_Wave_snd(fwave, filename_debug); } DBG("Playing sound samples"); festival_send_to_audio(fwave); if (!wave_cached) delete_FT_Wave(fwave); DBG("End of playing sound samples"); } if (terminate) { DBG("Ok, end of samples, returning"); CLP(0, module_report_event_end); } if (festival_stop) { DBG("Module stopped 3"); CLP(0, module_report_event_stop); } } } festival_stop = 0; festival_speaking = 0; DBG("festival: speaking thread ended.......\n"); pthread_exit(NULL); } int is_text(SPDMessageType msg_type) { if (msg_type == SPD_MSGTYPE_TEXT || msg_type == SPD_MSGTYPE_SPELL) return 1; else return 0; } void festival_set_language(char *language) { FestivalSetLanguage(festival_info, language, NULL); g_free(festival_voice_list); festival_voice_list = festivalGetVoices(festival_info); } void festival_set_voice(SPDVoiceType voice) { char *voice_name; voice_name = EVoice2str(voice); FestivalSetVoice(festival_info, voice_name, NULL); g_free(voice_name); } void festival_set_synthesis_voice(char *voice_name) { FestivalSetSynthesisVoice(festival_info, voice_name); } void festival_set_rate(signed int rate) { FestivalSetRate(festival_info, rate); } void festival_set_pitch(signed int pitch) { FestivalSetPitch(festival_info, pitch); } void festival_set_volume(signed int volume) { festival_volume = volume; } void festival_set_punctuation_mode(SPDPunctuation punct) { char *punct_mode; punct_mode = EPunctMode2str(punct); FestivalSetPunctuationMode(festival_info, punct_mode); g_free(punct_mode); } void festival_set_cap_let_recogn(SPDCapitalLetters recogn) { char *recogn_mode; if (recogn == SPD_CAP_NONE) recogn_mode = NULL; else recogn_mode = ECapLetRecogn2str(recogn); FestivalSetCapLetRecogn(festival_info, recogn_mode, NULL); g_free(recogn_mode); } /* --- Cache related functions --- */ void cache_destroy_entry(gpointer data) { TCacheEntry *entry = data; g_free(entry->fwave); g_free(entry); } void cache_destroy_table_entry(gpointer data) { g_hash_table_destroy(data); } void cache_free_counter_entry(gpointer data, gpointer user_data) { g_free(((TCounterEntry *) data)->key); g_free(data); } int cache_init() { if (FestivalCacheOn == 0) return 0; FestivalCache.size = 0; FestivalCache.caches = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, cache_destroy_table_entry); FestivalCache.cache_counter = NULL; DBG("Cache: initialized"); return 0; } int cache_destroy() { g_hash_table_destroy(FestivalCache.caches); g_list_foreach(FestivalCache.cache_counter, cache_free_counter_entry, NULL); g_list_free(FestivalCache.cache_counter); return 0; } int cache_reset() { /* TODO: it could free everything in the cache and go from start, but currently it isn't called by anybody */ return 0; } /* Compare two cache entries according to their score (how many times the entry was requested divided by the time it exists in the database) */ gint cache_counter_comp(gconstpointer a, gconstpointer b) { const TCounterEntry *A = a; const TCounterEntry *B = b; time_t t; float ret; t = time(NULL); ret = (((float)A->count / (float)(t - A->start)) - ((float)B->count / (float)(t - B->start))); if (ret > 0) return -1; if (ret == 0) return 0; if (ret < 0) return 1; return 0; } /* List scores of all entries in the cache*/ void cache_debug_foreach_list_score(gpointer a, gpointer user) { const TCounterEntry *A = a; DBG("key: %s -> score %f (count: %d, dtime: %d)", A->key, ((float)A->count / (float)(time(NULL) - A->start)), (int)A->count, (int)(time(NULL) - A->start)); } /* Remove 1/3 of the least used (according to cache_counter_comp) entries (measured by size) */ int cache_clean(size_t new_element_size) { size_t req_size; GList *gl; TCounterEntry *centry; DBG("Cache: cleaning, cache size %lu kbytes (>max %d).", (unsigned long)(FestivalCache.size / 1024), FestivalCacheMaxKBytes); req_size = 2 * FestivalCache.size / 3; FestivalCache.cache_counter = g_list_sort(FestivalCache.cache_counter, cache_counter_comp); g_list_foreach(FestivalCache.cache_counter, cache_debug_foreach_list_score, NULL); while ((FestivalCache.size + new_element_size) > req_size) { gl = g_list_last(FestivalCache.cache_counter); if (gl == NULL) break; if (gl->data == NULL) { DBG("Error: Cache: gl->data in cache_clean is NULL, but shouldn't be."); return -1; } centry = gl->data; FestivalCache.size -= centry->size; DBG("Cache: Removing element with key '%s'", centry->key); if (FestivalCache.size < 0) { DBG("Error: Cache: FestivalCache.size < 0, this shouldn't be."); return -1; } /* Remove the data itself from the hash table */ g_hash_table_remove(centry->p_caches, centry->key); /* Remove the associated entry in the counter list */ cache_free_counter_entry(centry, NULL); FestivalCache.cache_counter = g_list_delete_link(FestivalCache.cache_counter, gl); } return 0; } /* Generate a key for searching between the different hash tables */ char *cache_gen_key(SPDMessageType type) { char *key; char ktype; int kpitch = 0, krate = 0, kvoice = 0; if (msg_settings.voice.language == NULL) return NULL; DBG("v, p, r = %d %d %d", FestivalCacheDistinguishVoices, FestivalCacheDistinguishPitch, FestivalCacheDistinguishRate); if (FestivalCacheDistinguishVoices) kvoice = msg_settings.voice_type; if (FestivalCacheDistinguishPitch) kpitch = msg_settings.pitch; if (FestivalCacheDistinguishRate) krate = msg_settings.rate; if (type == SPD_MSGTYPE_CHAR) ktype = 'c'; else if (type == SPD_MSGTYPE_KEY) ktype = 'k'; else if (type == SPD_MSGTYPE_SOUND_ICON) ktype = 's'; else { DBG("Invalid message type for cache_gen_key()"); return NULL; } key = g_strdup_printf("%c_%s_%d_%d_%d", ktype, msg_settings.voice.language, kvoice, krate, kpitch); return key; } /* Insert one entry into the cache */ int cache_insert(char *key, SPDMessageType msgtype, FT_Wave * fwave) { GHashTable *cache; TCacheEntry *entry; TCounterEntry *centry; char *key_table; if (FestivalCacheOn == 0) return 0; if (key == NULL) return -1; if (fwave == NULL) return -1; /* Check if the entry isn't present already */ if (cache_lookup(key, msgtype, 0) != NULL) return 0; key_table = cache_gen_key(msgtype); DBG("Cache: Inserting wave with key:'%s' into table '%s'", key, key_table); /* Clean less used cache entries if the size would exceed max. size */ if ((FestivalCache.size + fwave->num_samples * sizeof(short)) > (FestivalCacheMaxKBytes * 1024)) if (cache_clean(fwave->num_samples * sizeof(short)) != 0) return -1; /* Select the right table according to language, voice, etc. or create a new one */ cache = g_hash_table_lookup(FestivalCache.caches, key_table); if (cache == NULL) { cache = g_hash_table_new(g_str_hash, g_str_equal); g_hash_table_insert(FestivalCache.caches, key_table, cache); } else { g_free(key_table); } /* Fill the CounterEntry structure that will later allow us to remove the less used entries from cache */ centry = (TCounterEntry *) g_malloc(sizeof(TCounterEntry)); centry->start = time(NULL); centry->count = 1; centry->size = fwave->num_samples * sizeof(short); centry->p_caches = cache; centry->key = g_strdup(key); FestivalCache.cache_counter = g_list_append(FestivalCache.cache_counter, centry); entry = (TCacheEntry *) g_malloc(sizeof(TCacheEntry)); entry->p_counter_entry = centry; entry->fwave = fwave; FestivalCache.size += centry->size; g_hash_table_insert(cache, g_strdup(key), entry); return 0; } /* Retrieve wave from the cache */ FT_Wave *cache_lookup(const char *key, SPDMessageType msgtype, int add_counter) { GHashTable *cache; TCacheEntry *entry; char *key_table; if (FestivalCacheOn == 0) return NULL; if (key == NULL) return NULL; key_table = cache_gen_key(msgtype); if (add_counter) DBG("Cache: looking up a wave with key '%s' in '%s'", key, key_table); if (key_table == NULL) return NULL; cache = g_hash_table_lookup(FestivalCache.caches, key_table); g_free(key_table); if (cache == NULL) return NULL; entry = g_hash_table_lookup(cache, key); if (entry == NULL) return NULL; entry->p_counter_entry->count++; DBG("Cache: corresponding wave found: %s", key); return entry->fwave; } int init_festival_standalone() { int ret; int fr; if ((pipe(module_p.pipe_in) != 0) || (pipe(module_p.pipe_out) != 0)) { DBG("Can't open pipe! Module not loaded."); return -1; } DBG("Starting Festival as a child process"); fr = fork(); switch (fr) { case -1: DBG("ERROR: Can't fork! Module not loaded."); return -1; case 0: ret = dup2(module_p.pipe_in[0], 0); close(module_p.pipe_in[0]); close(module_p.pipe_in[1]); ret = dup2(module_p.pipe_out[1], 1); close(module_p.pipe_out[1]); close(module_p.pipe_out[0]); /* TODO: fix festival hardcoded path */ if (execlp("festival", "", (char *)0) == -1) exit(1); default: festival_process_pid = fr; close(module_p.pipe_in[0]); close(module_p.pipe_out[1]); usleep(100); /* So that the other child has at least time to fail with the execlp */ ret = waitpid(module_p.pid, NULL, WNOHANG); if (ret != 0) { DBG("Can't execute festival. Bad filename in configuration?"); return -1; } return 0; } assert(0); } int init_festival_socket() { int r; /* Init festival and register a new voice */ festival_info = festivalDefaultInfo(); festival_info->server_host = FestivalServerHost; festival_info->server_port = FestivalServerPort; festival_info = festivalOpen(festival_info); if (festival_info == NULL) return -1; r = FestivalSetMultiMode(festival_info, "t"); if (r != 0) return -2; DBG("FestivalServerHost = %s\n", FestivalServerHost); DBG("FestivalServerPort = %d\n", FestivalServerPort); return 0; } int stop_festival_local() { if (festival_process_pid > 0) kill(festival_process_pid, SIGINT); return 0; } speech-dispatcher-0.9.1/src/modules/espeak-ng.c0000644000175000017500000011204013412722106016306 00000000000000 /* * espeak.c - Speech Dispatcher backend for espeak * * Copyright (C) 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * @author Lukas Loehrer * Based on ibmtts.c. * * $Id: espeak.c,v 1.11 2008-10-15 17:04:36 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif /* < Includes*/ /* System includes. */ #include #include #include /* espeak header file */ #include #ifndef ESPEAK_API_REVISION #define ESPEAK_API_REVISION 1 #endif /* Speech Dispatcher includes. */ #include "spd_audio.h" #include #include "module_utils.h" /* > */ /* < Basic definitions*/ #define MODULE_NAME "espeak-ng" #define DBG_MODNAME "Espeak-ng:" #define MODULE_VERSION "0.1" #define DEBUG_MODULE 1 DECLARE_DEBUG() #define DBG_WARN(e, msg) do { \ if (Debug && !(e)) { \ DBG(DBG_MODNAME " Warning: " msg); \ } \ } while (0) typedef enum { FATAL_ERROR = -1, OK = 0, ERROR = 1 } TEspeakSuccess; typedef enum { IDLE, BEFORE_SYNTH, BEFORE_PLAY, SPEAKING } TEspeakState; typedef enum { ESPEAK_PAUSE_OFF, ESPEAK_PAUSE_REQUESTED, ESPEAK_PAUSE_MARK_REPORTED } TEspeakPauseState; /* > */ /* < Thread and process control. */ static TEspeakState espeak_state = IDLE; static pthread_mutex_t espeak_state_mutex; static pthread_t espeak_play_thread; static pthread_t espeak_stop_or_pause_thread; static sem_t espeak_stop_or_pause_semaphore; static pthread_mutex_t espeak_stop_or_pause_suspended_mutex; static sem_t espeak_play_semaphore; static pthread_mutex_t espeak_play_suspended_mutex; static gboolean espeak_close_requested = FALSE; static TEspeakPauseState espeak_pause_state = ESPEAK_PAUSE_OFF; static gboolean espeak_stop_requested = FALSE; /* > */ static int espeak_sample_rate = 0; static SPDVoice **espeak_voice_list = NULL; static const espeak_VOICE **espeak_variants = NULL; /* < The playback queue. */ typedef enum { ESPEAK_QET_AUDIO, /* Chunk of audio. */ ESPEAK_QET_INDEX_MARK, /* Index mark event. */ ESPEAK_QET_SOUND_ICON, /* A Sound Icon */ ESPEAK_QET_BEGIN, /* Beginning of speech. */ ESPEAK_QET_END /* Speech completed. */ } EPlaybackQueueEntryType; typedef struct { long num_samples; short *audio_chunk; } TPlaybackQueueAudioChunk; typedef struct { EPlaybackQueueEntryType type; union { char *markId; TPlaybackQueueAudioChunk audio; char *sound_icon_filename; } data; } TPlaybackQueueEntry; static GSList *playback_queue = NULL; static int playback_queue_size = 0; /* Number of audio frames currently in queue */ static pthread_mutex_t playback_queue_mutex; pthread_cond_t playback_queue_condition; /* When a voice is set, this is the baseline pitch of the voice. SSIP PITCH commands then adjust relative to this. */ static int espeak_voice_pitch_baseline = 50; /* When a voice is set, this is the baseline pitch range of the voice. SSIP PITCH range commands then adjust relative to this. */ static int espeak_voice_pitch_range_baseline = 50; /* */ /* < Module configuration options*/ MOD_OPTION_1_STR(EspeakPunctuationList) MOD_OPTION_1_INT(EspeakCapitalPitchRise) MOD_OPTION_1_INT(EspeakMinRate) MOD_OPTION_1_INT(EspeakNormalRate) MOD_OPTION_1_INT(EspeakMaxRate) MOD_OPTION_1_INT(EspeakListVoiceVariants) MOD_OPTION_1_INT(EspeakIndexing) MOD_OPTION_1_INT(EspeakAudioChunkSize) MOD_OPTION_1_INT(EspeakAudioQueueMaxSize) MOD_OPTION_1_STR(EspeakSoundIconFolder) MOD_OPTION_1_INT(EspeakSoundIconVolume) /* > */ /* < Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); /* Options */ MOD_OPTION_1_INT_REG(EspeakAudioChunkSize, 2000); MOD_OPTION_1_INT_REG(EspeakAudioQueueMaxSize, 20 * 22050); MOD_OPTION_1_STR_REG(EspeakSoundIconFolder, "/usr/share/sounds/sound-icons/"); MOD_OPTION_1_INT_REG(EspeakSoundIconVolume, 0); MOD_OPTION_1_INT_REG(EspeakMinRate, 80); MOD_OPTION_1_INT_REG(EspeakNormalRate, 170); MOD_OPTION_1_INT_REG(EspeakMaxRate, 390); MOD_OPTION_1_STR_REG(EspeakPunctuationList, "@/+-_"); MOD_OPTION_1_INT_REG(EspeakCapitalPitchRise, 800); MOD_OPTION_1_INT_REG(EspeakIndexing, 1); MOD_OPTION_1_INT_REG(EspeakListVoiceVariants, 0); if (EspeakCapitalPitchRise == 1 || EspeakCapitalPitchRise == 2) { EspeakCapitalPitchRise = 0; } return OK; } int module_init(char **status_info) { int ret; const char *espeak_version; DBG(DBG_MODNAME " Module init()."); INIT_INDEX_MARKING(); *status_info = NULL; /* Report versions. */ espeak_version = espeak_Info(NULL); DBG(DBG_MODNAME " espeak Output Module version %s, espeak Engine version %s", MODULE_VERSION, espeak_version); /* %s", EspeakSoundIconFolder, data, data); result = espeak_Synth(msg, strlen(msg) + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL); g_free(msg); break; } case SPD_MSGTYPE_CHAR:{ wchar_t wc = 0; if (bytes == 1) { // ASCII wc = (wchar_t) data[0]; } else if (bytes == 5 && (0 == strncmp(data, "space", bytes))) { wc = (wchar_t) 0x20; } else { gsize bytes_out; gchar *tmp = g_convert(data, -1, "wchar_t", "utf-8", NULL, &bytes_out, NULL); if (tmp != NULL && bytes_out == sizeof(wchar_t)) { wchar_t *wc_ptr = (wchar_t *) tmp; wc = wc_ptr[0]; } else { DBG(DBG_MODNAME " Failed to convert utf-8 to wchar_t, or not exactly one utf-8 character given."); } g_free(tmp); } char *msg = g_strdup_printf ("&#%ld;", (long)wc); result = espeak_Synth(msg, strlen(msg) + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL); g_free(msg); break; } case SPD_MSGTYPE_KEY:{ /* TODO: Convert unspeakable keys to speakable form */ char *msg = g_strdup_printf ("%s", data); result = espeak_Synth(msg, strlen(msg) + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL); g_free(msg); break; } case SPD_MSGTYPE_SPELL: /* TODO: Not sure what to do here... */ break; } pthread_mutex_unlock(&espeak_state_mutex); if (result != EE_OK) { return FALSE; } DBG(DBG_MODNAME " Leaving module_speak() normally."); return bytes; } int module_stop(void) { DBG(DBG_MODNAME " module_stop()."); pthread_mutex_lock(&espeak_state_mutex); if (espeak_state != IDLE && !espeak_stop_requested && !is_thread_busy(&espeak_stop_or_pause_suspended_mutex)) { DBG(DBG_MODNAME " stopping..."); espeak_stop_requested = TRUE; /* Wake the stop_or_pause thread. */ sem_post(&espeak_stop_or_pause_semaphore); } else { DBG(DBG_MODNAME " Cannot stop now."); } pthread_mutex_unlock(&espeak_state_mutex); return OK; } size_t module_pause(void) { DBG(DBG_MODNAME " module_pause()."); pthread_mutex_lock(&espeak_state_mutex); if (espeak_pause_state == ESPEAK_PAUSE_OFF && !espeak_stop_requested) { espeak_pause_state = ESPEAK_PAUSE_REQUESTED; } pthread_mutex_unlock(&espeak_state_mutex); return OK; } int module_close(void) { DBG(DBG_MODNAME " close()."); DBG(DBG_MODNAME " Terminating threads"); espeak_stop_requested = TRUE; espeak_close_requested = TRUE; pthread_mutex_lock(&playback_queue_mutex); pthread_cond_broadcast(&playback_queue_condition); pthread_mutex_unlock(&playback_queue_mutex); sem_post(&espeak_play_semaphore); sem_post(&espeak_stop_or_pause_semaphore); /* Give threads a chance to quit on their own terms. */ g_usleep(25000); /* Make sure threads have really exited */ pthread_cancel(espeak_play_thread); pthread_cancel(espeak_stop_or_pause_thread); DBG("Joining play thread."); pthread_join(espeak_play_thread, NULL); DBG("Joinging stop thread."); pthread_join(espeak_stop_or_pause_thread, NULL); DBG(DBG_MODNAME " terminating synthesis."); espeak_Terminate(); DBG("Freeing resources."); espeak_clear_playback_queue(); espeak_free_voice_list(); pthread_mutex_destroy(&espeak_state_mutex); pthread_mutex_destroy(&espeak_play_suspended_mutex); pthread_mutex_destroy(&espeak_stop_or_pause_suspended_mutex); pthread_mutex_destroy(&playback_queue_mutex); pthread_cond_destroy(&playback_queue_condition); sem_destroy(&espeak_play_semaphore); sem_destroy(&espeak_stop_or_pause_semaphore); return 0; } /* > */ /* < Internal functions */ /* Return true if the thread is busy, i.e., suspended mutex is not locked. */ static gboolean is_thread_busy(pthread_mutex_t * suspended_mutex) { if (EBUSY == pthread_mutex_trylock(suspended_mutex)) return FALSE; else { pthread_mutex_unlock(suspended_mutex); return TRUE; } } static void espeak_state_reset() { espeak_state = IDLE; espeak_pause_state = ESPEAK_PAUSE_OFF; espeak_stop_requested = FALSE; } /* Stop or Pause thread. */ static void *_espeak_stop_or_pause(void *nothing) { int ret; DBG(DBG_MODNAME " Stop or pause thread starting......."); /* Block all signals to this thread. */ set_speaking_thread_parameters(); while (!espeak_close_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&espeak_stop_or_pause_semaphore)) { pthread_mutex_lock (&espeak_stop_or_pause_suspended_mutex); sem_wait(&espeak_stop_or_pause_semaphore); pthread_mutex_unlock (&espeak_stop_or_pause_suspended_mutex); } DBG(DBG_MODNAME " Stop or pause semaphore on."); if (espeak_close_requested) break; if (!espeak_stop_requested) { /* This sometimes happens after wake-up from suspend-to-disk. */ DBG(DBG_MODNAME " Warning: spurious wake-up of stop thread."); continue; } pthread_mutex_lock(&playback_queue_mutex); pthread_cond_broadcast(&playback_queue_condition); pthread_mutex_unlock(&playback_queue_mutex); if (module_audio_id) { DBG(DBG_MODNAME " Stopping audio."); ret = spd_audio_stop(module_audio_id); DBG_WARN(ret == 0, "spd_audio_stop returned non-zero value."); while (is_thread_busy(&espeak_play_suspended_mutex)) { ret = spd_audio_stop(module_audio_id); DBG_WARN(ret == 0, "spd_audio_stop returned non-zero value."); g_usleep(5000); } } else { while (is_thread_busy(&espeak_play_suspended_mutex)) { g_usleep(5000); } } DBG(DBG_MODNAME " Waiting for synthesis to stop."); ret = espeak_Cancel(); DBG_WARN(ret == EE_OK, DBG_MODNAME " error in espeak_Cancel()."); DBG(DBG_MODNAME " Clearing playback queue."); espeak_clear_playback_queue(); int save_pause_state = espeak_pause_state; pthread_mutex_lock(&espeak_state_mutex); espeak_state_reset(); pthread_mutex_unlock(&espeak_state_mutex); if (save_pause_state == ESPEAK_PAUSE_MARK_REPORTED) { module_report_event_pause(); } else { module_report_event_stop(); } DBG(DBG_MODNAME " Stop or pause thread ended.......\n"); } pthread_exit(NULL); } static void espeak_set_rate(signed int rate) { assert(rate >= -100 && rate <= +100); int speed; int normal_rate = EspeakNormalRate, max_rate = EspeakMaxRate, min_rate = EspeakMinRate; if (rate < 0) speed = normal_rate + (normal_rate - min_rate) * rate / 100; else speed = normal_rate + (max_rate - normal_rate) * rate / 100; espeak_ERROR ret = espeak_SetParameter(espeakRATE, speed, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting rate %i.", speed); } else { DBG(DBG_MODNAME " Rate set to %i.", speed); } } static void espeak_set_volume(signed int volume) { assert(volume >= -100 && volume <= +100); int vol; vol = volume + 100; espeak_ERROR ret = espeak_SetParameter(espeakVOLUME, vol, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting volume %i.", vol); } else { DBG(DBG_MODNAME " Volume set to %i.", vol); } } static void espeak_set_pitch(signed int pitch) { assert(pitch >= -100 && pitch <= +100); int pitchBaseline; /* Possible range 0 to 100. */ if (pitch < 0) { pitchBaseline = ((float)(pitch + 100) * espeak_voice_pitch_baseline) / (float)100; } else { pitchBaseline = (((float)pitch * (100 - espeak_voice_pitch_baseline)) / (float)100) + espeak_voice_pitch_baseline; } assert(pitchBaseline >= 0 && pitchBaseline <= 100); espeak_ERROR ret = espeak_SetParameter(espeakPITCH, pitchBaseline, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting pitch %i.", pitchBaseline); } else { DBG(DBG_MODNAME " Pitch set to %i.", pitchBaseline); } } static void espeak_set_pitch_range(signed int pitch_range) { assert(pitch_range >= -100 && pitch_range <= +100); int pitchRangeBaseline; /* Possible range 0 to 100. */ if (pitch_range < 0) { pitchRangeBaseline = ((float)(pitch_range + 100) * espeak_voice_pitch_range_baseline) / (float)100; } else { pitchRangeBaseline = (((float)pitch_range * (100 - espeak_voice_pitch_range_baseline)) / (float)100) + espeak_voice_pitch_range_baseline; } assert(pitchRangeBaseline >= 0 && pitchRangeBaseline <= 100); espeak_ERROR ret = espeak_SetParameter(espeakRANGE, pitchRangeBaseline, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting pitch range %i.", pitchRangeBaseline); } else { DBG(DBG_MODNAME " Pitch range set to %i.", pitchRangeBaseline); } } static void espeak_set_punctuation_mode(SPDPunctuation punct_mode) { espeak_PUNCT_TYPE espeak_punct_mode = espeakPUNCT_SOME; switch (punct_mode) { case SPD_PUNCT_ALL: espeak_punct_mode = espeakPUNCT_ALL; break; case SPD_PUNCT_SOME: espeak_punct_mode = espeakPUNCT_SOME; break; case SPD_PUNCT_NONE: espeak_punct_mode = espeakPUNCT_NONE; break; } espeak_ERROR ret = espeak_SetParameter(espeakPUNCTUATION, espeak_punct_mode, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Failed to set punctuation mode."); } else { DBG("Set punctuation mode."); } } static void espeak_set_cap_let_recogn(SPDCapitalLetters cap_mode) { int espeak_cap_mode = 0; switch (cap_mode) { case SPD_CAP_NONE: espeak_cap_mode = EspeakCapitalPitchRise; break; case SPD_CAP_SPELL: espeak_cap_mode = 2; break; case SPD_CAP_ICON: espeak_cap_mode = 1; break; } espeak_ERROR ret = espeak_SetParameter(espeakCAPITALS, espeak_cap_mode, 1); if (ret != EE_OK) { DBG(DBG_MODNAME " Failed to set capitals mode."); } else { DBG("Set capitals mode."); } } /* Given a language code and SD voice code, sets the espeak voice. */ static void espeak_set_language_and_voice(char *lang, SPDVoiceType voice_code) { DBG(DBG_MODNAME " set_language_and_voice %s %d", lang, voice_code); espeak_ERROR ret; unsigned char overlay = 0; switch (voice_code) { case SPD_MALE1: overlay = 0; break; case SPD_MALE2: overlay = 1; break; case SPD_MALE3: overlay = 2; break; case SPD_FEMALE1: overlay = 11; break; case SPD_FEMALE2: overlay = 12; break; case SPD_FEMALE3: overlay = 13; break; case SPD_CHILD_MALE: overlay = 4; break; case SPD_CHILD_FEMALE: overlay = 14; break; default: overlay = 0; break; } char *name = g_strdup_printf("%s+%d", lang, overlay); DBG(DBG_MODNAME " set_language_and_voice name=%s", name); ret = espeak_SetVoiceByName(name); if (ret != EE_OK) { DBG(DBG_MODNAME " Error selecting language %s", name); } else { DBG(DBG_MODNAME " Successfully set voice to \"%s\"", name); } g_free(name); } static void espeak_set_voice(SPDVoiceType voice) { assert(msg_settings.voice.language); espeak_set_language_and_voice(msg_settings.voice.language, voice); } static void espeak_set_language(char *lang) { espeak_set_language_and_voice(lang, msg_settings.voice_type); } static void espeak_set_synthesis_voice(char *synthesis_voice) { gchar *voice_name = NULL; gchar *variant_name = NULL; gchar **voice_split = NULL; gchar **identifier = NULL; gchar *variant_file = NULL; int i = 0; /* Espeak-ng can accept the full voice name as the voice, but will * only accept the file name of the variant to use, which can be * found in the identifier member of the variant list, which * itself is of type espeak_VOICE */ if (synthesis_voice != NULL) { if (g_strstr_len(synthesis_voice, -1, "+") != NULL) { voice_split = g_strsplit(synthesis_voice, "+", 2); voice_name = voice_split[0]; variant_name = voice_split[1]; g_free(voice_split); for (i = 0; espeak_variants[i] != NULL; i++) { identifier = g_strsplit(espeak_variants[i]->identifier, "/", 2); if (g_strcmp0(espeak_variants[i]->name, variant_name) == 0) { if (identifier[1] != NULL) variant_file = g_strdup(identifier[1]); } else if (g_strcmp0(identifier[1], variant_name) == 0) { variant_file = g_strdup(variant_name); } g_strfreev(identifier); identifier = NULL; } if (variant_file != NULL) { g_free(synthesis_voice); synthesis_voice = g_strdup_printf("%s+%s", voice_name, variant_file); g_free(variant_file); } else { DBG(DBG_MODNAME " Cannot find the variant file name for the given variant."); } g_free(voice_name); g_free(variant_name); } espeak_ERROR ret = espeak_SetVoiceByName(synthesis_voice); if (ret != EE_OK) { DBG(DBG_MODNAME " Failed to set synthesis voice to %s.", synthesis_voice); } } } /* Callbacks */ static gboolean espeak_send_audio_upto(short *wav, int *sent, int upto) { assert(*sent >= 0); assert(upto >= 0); int numsamples = upto - (*sent); if (wav == NULL || numsamples == 0) { return TRUE; } short *start = wav + (*sent); gboolean result = espeak_add_audio_to_playback_queue(start, numsamples); *sent = upto; return result; } static int synth_callback(short *wav, int numsamples, espeak_EVENT * events) { /* Number of samples sent in current message. */ static int numsamples_sent_msg = 0; /* Number of samples already sent during this call to the callback. */ int numsamples_sent = 0; pthread_mutex_lock(&espeak_state_mutex); if (espeak_state == BEFORE_SYNTH) { numsamples_sent_msg = 0; espeak_state = BEFORE_PLAY; espeak_add_flag_to_playback_queue(ESPEAK_QET_BEGIN); /* Wake up playback thread */ sem_post(&espeak_play_semaphore); } pthread_mutex_unlock(&espeak_state_mutex); if (espeak_stop_requested) { return 1; } /* Process events and audio data */ while (events->type != espeakEVENT_LIST_TERMINATED) { /* Enqueue audio upto event */ switch (events->type) { case espeakEVENT_MARK: if (!EspeakIndexing) break; case espeakEVENT_PLAY:{ /* Convert ms position to samples */ gint64 pos_msg = events->audio_position; pos_msg = pos_msg * espeak_sample_rate / 1000; /* Convert position in message to position in current chunk */ int upto = (int)CLAMP(pos_msg - numsamples_sent_msg, 0, numsamples); /* This is just for safety */ espeak_send_audio_upto(wav, &numsamples_sent, upto); break; } default: break; } /* Process actual event */ switch (events->type) { case espeakEVENT_MARK: if (EspeakIndexing) espeak_add_mark_to_playback_queue(events->id.name); break; case espeakEVENT_PLAY: espeak_add_sound_icon_to_playback_queue(events-> id.name); break; case espeakEVENT_MSG_TERMINATED: // This event never has any audio in the same callback espeak_add_flag_to_playback_queue(ESPEAK_QET_END); break; default: break; } if (espeak_stop_requested) { return 1; } events++; } espeak_send_audio_upto(wav, &numsamples_sent, numsamples); numsamples_sent_msg += numsamples; return 0; } static int uri_callback(int type, const char *uri, const char *base) { int result = 1; if (type == 1) { /* Audio icon */ if (g_file_test(uri, G_FILE_TEST_EXISTS)) { result = 0; } } return result; } static TPlaybackQueueEntry *playback_queue_pop() { TPlaybackQueueEntry *result = NULL; pthread_mutex_lock(&playback_queue_mutex); while (!espeak_stop_requested && playback_queue == NULL) { pthread_cond_wait(&playback_queue_condition, &playback_queue_mutex); } if (!espeak_stop_requested) { result = (TPlaybackQueueEntry *) playback_queue->data; playback_queue = g_slist_remove(playback_queue, playback_queue->data); if (result->type == ESPEAK_QET_AUDIO) { playback_queue_size -= result->data.audio.num_samples; pthread_cond_signal(&playback_queue_condition); } } pthread_mutex_unlock(&playback_queue_mutex); return result; } static gboolean playback_queue_push(TPlaybackQueueEntry * entry) { pthread_mutex_lock(&playback_queue_mutex); playback_queue = g_slist_append(playback_queue, entry); if (entry->type == ESPEAK_QET_AUDIO) { playback_queue_size += entry->data.audio.num_samples; } pthread_cond_signal(&playback_queue_condition); pthread_mutex_unlock(&playback_queue_mutex); return TRUE; } /* Adds a chunk of pcm audio to the audio playback queue. Waits until there is enough space in the queue. */ static gboolean espeak_add_audio_to_playback_queue(short *audio_chunk, int num_samples) { pthread_mutex_lock(&playback_queue_mutex); while (!espeak_stop_requested && playback_queue_size > EspeakAudioQueueMaxSize) { pthread_cond_wait(&playback_queue_condition, &playback_queue_mutex); } pthread_mutex_unlock(&playback_queue_mutex); if (espeak_stop_requested) { return FALSE; } TPlaybackQueueEntry *playback_queue_entry = g_new(TPlaybackQueueEntry, 1); playback_queue_entry->type = ESPEAK_QET_AUDIO; playback_queue_entry->data.audio.num_samples = num_samples; gint nbytes = sizeof(short) * num_samples; playback_queue_entry->data.audio.audio_chunk = (short *)g_memdup((gconstpointer) audio_chunk, nbytes); playback_queue_push(playback_queue_entry); return TRUE; } /* Adds an Index Mark to the audio playback queue. */ static gboolean espeak_add_mark_to_playback_queue(const char *markId) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); playback_queue_entry->type = ESPEAK_QET_INDEX_MARK; playback_queue_entry->data.markId = g_strdup(markId); return playback_queue_push(playback_queue_entry); } /* Adds a begin or end flag to the playback queue. */ static gboolean espeak_add_flag_to_playback_queue(EPlaybackQueueEntryType type) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); playback_queue_entry->type = type; return playback_queue_push(playback_queue_entry); } /* Add a sound icon to the playback queue. */ static gboolean espeak_add_sound_icon_to_playback_queue(const char *filename) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); playback_queue_entry->type = ESPEAK_QET_SOUND_ICON; playback_queue_entry->data.sound_icon_filename = g_strdup(filename); return playback_queue_push(playback_queue_entry); } /* Deletes an entry from the playback audio queue, freeing memory. */ static void espeak_delete_playback_queue_entry(TPlaybackQueueEntry * playback_queue_entry) { switch (playback_queue_entry->type) { case ESPEAK_QET_AUDIO: g_free(playback_queue_entry->data.audio.audio_chunk); break; case ESPEAK_QET_INDEX_MARK: g_free(playback_queue_entry->data.markId); break; case ESPEAK_QET_SOUND_ICON: g_free(playback_queue_entry->data.sound_icon_filename); break; default: break; } g_free(playback_queue_entry); } /* Erases the entire playback queue, freeing memory. */ static void espeak_clear_playback_queue() { pthread_mutex_lock(&playback_queue_mutex); while (NULL != playback_queue) { TPlaybackQueueEntry *playback_queue_entry = playback_queue->data; espeak_delete_playback_queue_entry(playback_queue_entry); playback_queue = g_slist_remove(playback_queue, playback_queue->data); } playback_queue = NULL; playback_queue_size = 0; pthread_mutex_unlock(&playback_queue_mutex); } /* Sends a chunk of audio to the audio player and waits for completion or error. */ static gboolean espeak_send_to_audio(TPlaybackQueueEntry * playback_queue_entry) { int ret = 0; AudioTrack track; track.num_samples = playback_queue_entry->data.audio.num_samples; track.num_channels = 1; track.sample_rate = espeak_sample_rate; track.bits = 16; track.samples = playback_queue_entry->data.audio.audio_chunk; DBG(DBG_MODNAME " Sending %i samples to audio.", track.num_samples); ret = module_tts_output(track, SPD_AUDIO_LE); if (ret < 0) { DBG("ERROR: Can't play track for unknown reason."); return FALSE; } DBG(DBG_MODNAME " Sent to audio."); return TRUE; } /* Playback thread. */ static void *_espeak_play(void *nothing) { char *markId; TPlaybackQueueEntry *playback_queue_entry = NULL; DBG(DBG_MODNAME " Playback thread starting......."); /* Block all signals to this thread. */ set_speaking_thread_parameters(); while (!espeak_close_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&espeak_play_semaphore)) { pthread_mutex_lock(&espeak_play_suspended_mutex); sem_wait(&espeak_play_semaphore); pthread_mutex_unlock(&espeak_play_suspended_mutex); } DBG(DBG_MODNAME " Playback semaphore on."); if (espeak_close_requested) break; if (espeak_state < BEFORE_PLAY) { /* This can happen after wake-up from suspend-to-disk */ DBG(DBG_MODNAME " Warning: Spurious wake of of playback thread."); continue; } while (1) { gboolean finished = FALSE; playback_queue_entry = playback_queue_pop(); if (playback_queue_entry == NULL) { DBG(DBG_MODNAME " playback thread detected stop."); break; } switch (playback_queue_entry->type) { case ESPEAK_QET_AUDIO: espeak_send_to_audio(playback_queue_entry); break; case ESPEAK_QET_INDEX_MARK: markId = playback_queue_entry->data.markId; DBG(DBG_MODNAME " reporting index mark |%s|.", markId); module_report_index_mark(markId); DBG(DBG_MODNAME " index mark reported."); pthread_mutex_lock(&espeak_state_mutex); if (espeak_state == SPEAKING && espeak_pause_state == ESPEAK_PAUSE_REQUESTED && !is_thread_busy (&espeak_stop_or_pause_suspended_mutex) && g_str_has_prefix(markId, "__spd_")) { DBG(DBG_MODNAME " Pause requested in playback thread. Stopping."); espeak_stop_requested = TRUE; espeak_pause_state = ESPEAK_PAUSE_MARK_REPORTED; sem_post (&espeak_stop_or_pause_semaphore); finished = TRUE; } pthread_mutex_unlock(&espeak_state_mutex); break; case ESPEAK_QET_SOUND_ICON: module_play_file(playback_queue_entry-> data.sound_icon_filename); break; case ESPEAK_QET_BEGIN:{ gboolean report_begin = FALSE; pthread_mutex_lock(&espeak_state_mutex); if (espeak_state == BEFORE_PLAY) { espeak_state = SPEAKING; report_begin = TRUE; } pthread_mutex_unlock (&espeak_state_mutex); if (report_begin) module_report_event_begin(); break; } case ESPEAK_QET_END: pthread_mutex_lock(&espeak_state_mutex); DBG(DBG_MODNAME " playback thread got END from queue."); if (espeak_state == SPEAKING) { if (!espeak_stop_requested) { DBG(DBG_MODNAME " playback thread reporting end."); espeak_state = IDLE; espeak_pause_state = ESPEAK_PAUSE_OFF; } finished = TRUE; } pthread_mutex_unlock(&espeak_state_mutex); if (finished) module_report_event_end(); break; } espeak_delete_playback_queue_entry (playback_queue_entry); if (finished) break; } } DBG(DBG_MODNAME " Playback thread ended......."); return 0; } static SPDVoice **espeak_list_synthesis_voices() { SPDVoice **result = NULL; SPDVoice *voice = NULL; SPDVoice *vo = NULL; const espeak_VOICE **espeak_voices = NULL; const espeak_VOICE *v = NULL; espeak_VOICE *variant_spec; GQueue *voice_list = NULL; GQueue *variant_list = NULL; GList *voice_list_iter = NULL; GList *variant_list_iter = NULL; const gchar *first_lang = NULL; gchar *lang = NULL; gchar *variant = NULL; gchar *dash = NULL; gchar *vname = NULL; int numvoices = 0; int numvariants = 0; int totalvoices = 0; int i = 0; espeak_voices = espeak_ListVoices(NULL); voice_list = g_queue_new(); for (i = 0; espeak_voices[i] != NULL; i++) { v = espeak_voices[i]; if (!g_str_has_prefix(v->identifier, "mb/")) { /* Not an mbrola voice */ voice = g_new0(SPDVoice, 1); voice->name = g_strdup(v->name); first_lang = v->languages + 1; lang = NULL; variant = NULL; if (g_utf8_validate(first_lang, -1, NULL)) { dash = g_utf8_strchr(first_lang, -1, '-'); if (dash != NULL) { /* There is probably a variant string (like en-uk) */ lang = g_strndup(first_lang, dash - first_lang); variant = g_strdup(g_utf8_next_char(dash)); } else { lang = g_strdup(first_lang); } } else { DBG(DBG_MODNAME " Not a valid utf8 string: %s", first_lang);; } voice->language = lang; voice->variant = variant; g_queue_push_tail(voice_list, voice); } } numvoices = g_queue_get_length(voice_list); DBG(DBG_MODNAME " %d voices total.", numvoices); variant_spec = g_new0(espeak_VOICE, 1); variant_spec->languages = "variant"; espeak_variants = espeak_ListVoices(variant_spec); g_free(variant_spec); if (EspeakListVoiceVariants) { variant_list = g_queue_new(); for (i = 0; espeak_variants[i] != NULL; i++) { v = espeak_variants[i]; vname = g_strdup(v->name); g_queue_push_tail(variant_list, vname); } numvariants = g_queue_get_length(variant_list); DBG(DBG_MODNAME " %d variants total.", numvariants); } totalvoices = (numvoices * numvariants) + numvoices; result = g_new0(SPDVoice *, totalvoices + 1); voice_list_iter = g_queue_peek_head_link(voice_list); for (i = 0; i < totalvoices; i++) { result[i] = voice_list_iter->data; if (variant_list && !g_queue_is_empty(variant_list)) { vo = voice_list_iter->data; variant_list_iter = g_queue_peek_head_link(variant_list); while (variant_list_iter != NULL && variant_list_iter->data != NULL) { voice = g_new0(SPDVoice, 1); voice->name = g_strdup_printf("%s+%s", vo->name, (char *)variant_list_iter->data); voice->language = g_strdup(vo->language); voice->variant = g_strdup(vo->variant); result[++i] = voice; variant_list_iter = variant_list_iter->next; } } voice_list_iter = voice_list_iter->next; } if (voice_list != NULL) g_queue_free(voice_list); if (variant_list != NULL) g_queue_free_full(variant_list, (GDestroyNotify)g_free); result[i] = NULL; DBG(DBG_MODNAME " %d usable voices.", totalvoices); return result; } static void espeak_free_voice_list() { if (espeak_voice_list != NULL) { int i; for (i = 0; espeak_voice_list[i] != NULL; i++) { g_free(espeak_voice_list[i]->name); g_free(espeak_voice_list[i]->language); g_free(espeak_voice_list[i]->variant); g_free(espeak_voice_list[i]); } g_free(espeak_voice_list); espeak_voice_list = NULL; } } static TEspeakSuccess espeak_set_punctuation_list_from_utf8(const gchar * punct) { TEspeakSuccess result = ERROR; wchar_t *wc_punct = (wchar_t *) g_convert(punct, -1, "wchar_t", "utf-8", NULL, NULL, NULL); if (wc_punct != NULL) { espeak_ERROR ret = espeak_SetPunctuationList(wc_punct); if (ret == EE_OK) result = OK; g_free(wc_punct); } return result; } /* > */ /* local variables: */ /* folded-file: t */ /* c-basic-offset: 4 */ /* end: */ speech-dispatcher-0.9.1/src/modules/espeak.c0000644000175000017500000010737313412722106015721 00000000000000 /* * espeak.c - Speech Dispatcher backend for espeak * * Copyright (C) 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * @author Lukas Loehrer * Based on ibmtts.c. * * $Id: espeak.c,v 1.11 2008-10-15 17:04:36 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif /* < Includes*/ /* System includes. */ #include #include #include /* espeak header file */ #include #ifndef ESPEAK_API_REVISION #define ESPEAK_API_REVISION 1 #endif /* Speech Dispatcher includes. */ #include "spd_audio.h" #include #include "module_utils.h" /* > */ /* < Basic definitions*/ #define MODULE_NAME "espeak" #define DBG_MODNAME "Espeak:" #define MODULE_VERSION "0.1" #define DEBUG_MODULE 1 DECLARE_DEBUG() #define DBG_WARN(e, msg) do { \ if (Debug && !(e)) { \ DBG(DBG_MODNAME " Warning: " msg); \ } \ } while (0) typedef enum { FATAL_ERROR = -1, OK = 0, ERROR = 1 } TEspeakSuccess; typedef enum { IDLE, BEFORE_SYNTH, BEFORE_PLAY, SPEAKING } TEspeakState; typedef enum { ESPEAK_PAUSE_OFF, ESPEAK_PAUSE_REQUESTED, ESPEAK_PAUSE_MARK_REPORTED } TEspeakPauseState; /* > */ /* < Thread and process control. */ static TEspeakState espeak_state = IDLE; static pthread_mutex_t espeak_state_mutex; static pthread_t espeak_play_thread; static pthread_t espeak_stop_or_pause_thread; static sem_t espeak_stop_or_pause_semaphore; static pthread_mutex_t espeak_stop_or_pause_suspended_mutex; static sem_t espeak_play_semaphore; static pthread_mutex_t espeak_play_suspended_mutex; static gboolean espeak_close_requested = FALSE; static TEspeakPauseState espeak_pause_state = ESPEAK_PAUSE_OFF; static gboolean espeak_stop_requested = FALSE; /* > */ static int espeak_sample_rate = 0; static SPDVoice **espeak_voice_list = NULL; /* < The playback queue. */ typedef enum { ESPEAK_QET_AUDIO, /* Chunk of audio. */ ESPEAK_QET_INDEX_MARK, /* Index mark event. */ ESPEAK_QET_SOUND_ICON, /* A Sound Icon */ ESPEAK_QET_BEGIN, /* Beginning of speech. */ ESPEAK_QET_END /* Speech completed. */ } EPlaybackQueueEntryType; typedef struct { long num_samples; short *audio_chunk; } TPlaybackQueueAudioChunk; typedef struct { EPlaybackQueueEntryType type; union { char *markId; TPlaybackQueueAudioChunk audio; char *sound_icon_filename; } data; } TPlaybackQueueEntry; static GSList *playback_queue = NULL; static int playback_queue_size = 0; /* Number of audio frames currently in queue */ static pthread_mutex_t playback_queue_mutex; pthread_cond_t playback_queue_condition; /* When a voice is set, this is the baseline pitch of the voice. SSIP PITCH commands then adjust relative to this. */ static int espeak_voice_pitch_baseline = 50; /* When a voice is set, this is the baseline pitch range of the voice. SSIP PITCH range commands then adjust relative to this. */ static int espeak_voice_pitch_range_baseline = 50; /* */ /* < Module configuration options*/ MOD_OPTION_1_STR(EspeakPunctuationList) MOD_OPTION_1_INT(EspeakCapitalPitchRise) MOD_OPTION_1_INT(EspeakMinRate) MOD_OPTION_1_INT(EspeakNormalRate) MOD_OPTION_1_INT(EspeakMaxRate) MOD_OPTION_1_INT(EspeakListVoiceVariants) MOD_OPTION_1_INT(EspeakIndexing) MOD_OPTION_1_INT(EspeakAudioChunkSize) MOD_OPTION_1_INT(EspeakAudioQueueMaxSize) MOD_OPTION_1_STR(EspeakSoundIconFolder) MOD_OPTION_1_INT(EspeakSoundIconVolume) /* > */ /* < Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); /* Options */ MOD_OPTION_1_INT_REG(EspeakAudioChunkSize, 2000); MOD_OPTION_1_INT_REG(EspeakAudioQueueMaxSize, 20 * 22050); MOD_OPTION_1_STR_REG(EspeakSoundIconFolder, "/usr/share/sounds/sound-icons/"); MOD_OPTION_1_INT_REG(EspeakSoundIconVolume, 0); MOD_OPTION_1_INT_REG(EspeakMinRate, 80); MOD_OPTION_1_INT_REG(EspeakNormalRate, 170); MOD_OPTION_1_INT_REG(EspeakMaxRate, 390); MOD_OPTION_1_STR_REG(EspeakPunctuationList, "@/+-_"); MOD_OPTION_1_INT_REG(EspeakCapitalPitchRise, 800); MOD_OPTION_1_INT_REG(EspeakIndexing, 1); MOD_OPTION_1_INT_REG(EspeakListVoiceVariants, 0); if (EspeakCapitalPitchRise == 1 || EspeakCapitalPitchRise == 2) { EspeakCapitalPitchRise = 0; } return OK; } int module_init(char **status_info) { int ret; const char *espeak_version; DBG(DBG_MODNAME " Module init()."); INIT_INDEX_MARKING(); *status_info = NULL; /* Report versions. */ espeak_version = espeak_Info(NULL); DBG(DBG_MODNAME " espeak Output Module version %s, espeak Engine version %s", MODULE_VERSION, espeak_version); /* %s", EspeakSoundIconFolder, data, data); result = espeak_Synth(msg, strlen(msg) + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL); g_free(msg); break; } case SPD_MSGTYPE_CHAR:{ wchar_t wc = 0; if (bytes == 1) { // ASCII wc = (wchar_t) data[0]; } else if (bytes == 5 && (0 == strncmp(data, "space", bytes))) { wc = (wchar_t) 0x20; } else { gsize bytes_out; gchar *tmp = g_convert(data, -1, "wchar_t", "utf-8", NULL, &bytes_out, NULL); if (tmp != NULL && bytes_out == sizeof(wchar_t)) { wchar_t *wc_ptr = (wchar_t *) tmp; wc = wc_ptr[0]; } else { DBG(DBG_MODNAME " Failed to convert utf-8 to wchar_t, or not exactly one utf-8 character given."); } g_free(tmp); } char *msg = g_strdup_printf ("&#%ld;", (long)wc); result = espeak_Synth(msg, strlen(msg) + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL); g_free(msg); break; } case SPD_MSGTYPE_KEY:{ /* TODO: Convert unspeakable keys to speakable form */ char *msg = g_strdup_printf ("%s", data); result = espeak_Synth(msg, strlen(msg) + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL); g_free(msg); break; } case SPD_MSGTYPE_SPELL: /* TODO: Not sure what to do here... */ break; } pthread_mutex_unlock(&espeak_state_mutex); if (result != EE_OK) { return FALSE; } DBG(DBG_MODNAME " Leaving module_speak() normally."); return bytes; } int module_stop(void) { DBG(DBG_MODNAME " module_stop()."); pthread_mutex_lock(&espeak_state_mutex); if (espeak_state != IDLE && !espeak_stop_requested && !is_thread_busy(&espeak_stop_or_pause_suspended_mutex)) { DBG(DBG_MODNAME " stopping..."); espeak_stop_requested = TRUE; /* Wake the stop_or_pause thread. */ sem_post(&espeak_stop_or_pause_semaphore); } else { DBG(DBG_MODNAME " Cannot stop now."); } pthread_mutex_unlock(&espeak_state_mutex); return OK; } size_t module_pause(void) { DBG(DBG_MODNAME " module_pause()."); pthread_mutex_lock(&espeak_state_mutex); if (espeak_pause_state == ESPEAK_PAUSE_OFF && !espeak_stop_requested) { espeak_pause_state = ESPEAK_PAUSE_REQUESTED; } pthread_mutex_unlock(&espeak_state_mutex); return OK; } int module_close(void) { DBG(DBG_MODNAME " close()."); DBG(DBG_MODNAME " Terminating threads"); espeak_stop_requested = TRUE; espeak_close_requested = TRUE; pthread_mutex_lock(&playback_queue_mutex); pthread_cond_broadcast(&playback_queue_condition); pthread_mutex_unlock(&playback_queue_mutex); sem_post(&espeak_play_semaphore); sem_post(&espeak_stop_or_pause_semaphore); /* Give threads a chance to quit on their own terms. */ g_usleep(25000); /* Make sure threads have really exited */ pthread_cancel(espeak_play_thread); pthread_cancel(espeak_stop_or_pause_thread); DBG("Joining play thread."); pthread_join(espeak_play_thread, NULL); DBG("Joinging stop thread."); pthread_join(espeak_stop_or_pause_thread, NULL); DBG(DBG_MODNAME " terminating synthesis."); espeak_Terminate(); DBG("Freeing resources."); espeak_clear_playback_queue(); espeak_free_voice_list(); pthread_mutex_destroy(&espeak_state_mutex); pthread_mutex_destroy(&espeak_play_suspended_mutex); pthread_mutex_destroy(&espeak_stop_or_pause_suspended_mutex); pthread_mutex_destroy(&playback_queue_mutex); pthread_cond_destroy(&playback_queue_condition); sem_destroy(&espeak_play_semaphore); sem_destroy(&espeak_stop_or_pause_semaphore); return 0; } /* > */ /* < Internal functions */ /* Return true if the thread is busy, i.e., suspended mutex is not locked. */ static gboolean is_thread_busy(pthread_mutex_t * suspended_mutex) { if (EBUSY == pthread_mutex_trylock(suspended_mutex)) return FALSE; else { pthread_mutex_unlock(suspended_mutex); return TRUE; } } static void espeak_state_reset() { espeak_state = IDLE; espeak_pause_state = ESPEAK_PAUSE_OFF; espeak_stop_requested = FALSE; } /* Stop or Pause thread. */ static void *_espeak_stop_or_pause(void *nothing) { int ret; DBG(DBG_MODNAME " Stop or pause thread starting......."); /* Block all signals to this thread. */ set_speaking_thread_parameters(); while (!espeak_close_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&espeak_stop_or_pause_semaphore)) { pthread_mutex_lock (&espeak_stop_or_pause_suspended_mutex); sem_wait(&espeak_stop_or_pause_semaphore); pthread_mutex_unlock (&espeak_stop_or_pause_suspended_mutex); } DBG(DBG_MODNAME " Stop or pause semaphore on."); if (espeak_close_requested) break; if (!espeak_stop_requested) { /* This sometimes happens after wake-up from suspend-to-disk. */ DBG(DBG_MODNAME " Warning: spurious wake-up of stop thread."); continue; } pthread_mutex_lock(&playback_queue_mutex); pthread_cond_broadcast(&playback_queue_condition); pthread_mutex_unlock(&playback_queue_mutex); if (module_audio_id) { DBG(DBG_MODNAME " Stopping audio."); ret = spd_audio_stop(module_audio_id); DBG_WARN(ret == 0, "spd_audio_stop returned non-zero value."); while (is_thread_busy(&espeak_play_suspended_mutex)) { ret = spd_audio_stop(module_audio_id); DBG_WARN(ret == 0, "spd_audio_stop returned non-zero value."); g_usleep(5000); } } else { while (is_thread_busy(&espeak_play_suspended_mutex)) { g_usleep(5000); } } DBG(DBG_MODNAME " Waiting for synthesis to stop."); ret = espeak_Cancel(); DBG_WARN(ret == EE_OK, DBG_MODNAME " error in espeak_Cancel()."); DBG(DBG_MODNAME " Clearing playback queue."); espeak_clear_playback_queue(); int save_pause_state = espeak_pause_state; pthread_mutex_lock(&espeak_state_mutex); espeak_state_reset(); pthread_mutex_unlock(&espeak_state_mutex); if (save_pause_state == ESPEAK_PAUSE_MARK_REPORTED) { module_report_event_pause(); } else { module_report_event_stop(); } DBG(DBG_MODNAME " Stop or pause thread ended.......\n"); } pthread_exit(NULL); } static void espeak_set_rate(signed int rate) { assert(rate >= -100 && rate <= +100); int speed; int normal_rate = EspeakNormalRate, max_rate = EspeakMaxRate, min_rate = EspeakMinRate; if (rate < 0) speed = normal_rate + (normal_rate - min_rate) * rate / 100; else speed = normal_rate + (max_rate - normal_rate) * rate / 100; espeak_ERROR ret = espeak_SetParameter(espeakRATE, speed, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting rate %i.", speed); } else { DBG(DBG_MODNAME " Rate set to %i.", speed); } } static void espeak_set_volume(signed int volume) { assert(volume >= -100 && volume <= +100); int vol; vol = volume + 100; espeak_ERROR ret = espeak_SetParameter(espeakVOLUME, vol, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting volume %i.", vol); } else { DBG(DBG_MODNAME " Volume set to %i.", vol); } } static void espeak_set_pitch(signed int pitch) { assert(pitch >= -100 && pitch <= +100); int pitchBaseline; /* Possible range 0 to 100. */ if (pitch < 0) { pitchBaseline = ((float)(pitch + 100) * espeak_voice_pitch_baseline) / (float)100; } else { pitchBaseline = (((float)pitch * (100 - espeak_voice_pitch_baseline)) / (float)100) + espeak_voice_pitch_baseline; } assert(pitchBaseline >= 0 && pitchBaseline <= 100); espeak_ERROR ret = espeak_SetParameter(espeakPITCH, pitchBaseline, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting pitch %i.", pitchBaseline); } else { DBG(DBG_MODNAME " Pitch set to %i.", pitchBaseline); } } static void espeak_set_pitch_range(signed int pitch_range) { assert(pitch_range >= -100 && pitch_range <= +100); int pitchRangeBaseline; /* Possible range 0 to 100. */ if (pitch_range < 0) { pitchRangeBaseline = ((float)(pitch_range + 100) * espeak_voice_pitch_range_baseline) / (float)100; } else { pitchRangeBaseline = (((float)pitch_range * (100 - espeak_voice_pitch_range_baseline)) / (float)100) + espeak_voice_pitch_range_baseline; } assert(pitchRangeBaseline >= 0 && pitchRangeBaseline <= 100); espeak_ERROR ret = espeak_SetParameter(espeakRANGE, pitchRangeBaseline, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Error setting pitch range %i.", pitchRangeBaseline); } else { DBG(DBG_MODNAME " Pitch range set to %i.", pitchRangeBaseline); } } static void espeak_set_punctuation_mode(SPDPunctuation punct_mode) { espeak_PUNCT_TYPE espeak_punct_mode = espeakPUNCT_SOME; switch (punct_mode) { case SPD_PUNCT_ALL: espeak_punct_mode = espeakPUNCT_ALL; break; case SPD_PUNCT_SOME: espeak_punct_mode = espeakPUNCT_SOME; break; case SPD_PUNCT_NONE: espeak_punct_mode = espeakPUNCT_NONE; break; } espeak_ERROR ret = espeak_SetParameter(espeakPUNCTUATION, espeak_punct_mode, 0); if (ret != EE_OK) { DBG(DBG_MODNAME " Failed to set punctuation mode."); } else { DBG("Set punctuation mode."); } } static void espeak_set_cap_let_recogn(SPDCapitalLetters cap_mode) { int espeak_cap_mode = 0; switch (cap_mode) { case SPD_CAP_NONE: espeak_cap_mode = EspeakCapitalPitchRise; break; case SPD_CAP_SPELL: espeak_cap_mode = 2; break; case SPD_CAP_ICON: espeak_cap_mode = 1; break; } espeak_ERROR ret = espeak_SetParameter(espeakCAPITALS, espeak_cap_mode, 1); if (ret != EE_OK) { DBG(DBG_MODNAME " Failed to set capitals mode."); } else { DBG("Set capitals mode."); } } /* Given a language code and SD voice code, sets the espeak voice. */ static void espeak_set_language_and_voice(char *lang, SPDVoiceType voice_code) { DBG(DBG_MODNAME " set_language_and_voice %s %d", lang, voice_code); espeak_ERROR ret; unsigned char overlay = 0; switch (voice_code) { case SPD_MALE1: overlay = 0; break; case SPD_MALE2: overlay = 1; break; case SPD_MALE3: overlay = 2; break; case SPD_FEMALE1: overlay = 11; break; case SPD_FEMALE2: overlay = 12; break; case SPD_FEMALE3: overlay = 13; break; case SPD_CHILD_MALE: overlay = 4; break; case SPD_CHILD_FEMALE: overlay = 14; break; default: overlay = 0; break; } char *name = g_strdup_printf("%s+%d", lang, overlay); DBG(DBG_MODNAME " set_language_and_voice name=%s", name); ret = espeak_SetVoiceByName(name); if (ret != EE_OK) { DBG(DBG_MODNAME " Error selecting language %s", name); } else { DBG(DBG_MODNAME " Successfully set voice to \"%s\"", name); } g_free(name); } static void espeak_set_voice(SPDVoiceType voice) { assert(msg_settings.voice.language); espeak_set_language_and_voice(msg_settings.voice.language, voice); } static void espeak_set_language(char *lang) { espeak_set_language_and_voice(lang, msg_settings.voice_type); } static void espeak_set_synthesis_voice(char *synthesis_voice) { if (synthesis_voice != NULL) { espeak_ERROR ret = espeak_SetVoiceByName(synthesis_voice); if (ret != EE_OK) { DBG(DBG_MODNAME " Failed to set synthesis voice to %s.", synthesis_voice); } } } /* Callbacks */ static gboolean espeak_send_audio_upto(short *wav, int *sent, int upto) { assert(*sent >= 0); assert(upto >= 0); int numsamples = upto - (*sent); if (wav == NULL || numsamples == 0) { return TRUE; } short *start = wav + (*sent); gboolean result = espeak_add_audio_to_playback_queue(start, numsamples); *sent = upto; return result; } static int synth_callback(short *wav, int numsamples, espeak_EVENT * events) { /* Number of samples sent in current message. */ static int numsamples_sent_msg = 0; /* Number of samples already sent during this call to the callback. */ int numsamples_sent = 0; pthread_mutex_lock(&espeak_state_mutex); if (espeak_state == BEFORE_SYNTH) { numsamples_sent_msg = 0; espeak_state = BEFORE_PLAY; espeak_add_flag_to_playback_queue(ESPEAK_QET_BEGIN); /* Wake up playback thread */ sem_post(&espeak_play_semaphore); } pthread_mutex_unlock(&espeak_state_mutex); if (espeak_stop_requested) { return 1; } /* Process events and audio data */ while (events->type != espeakEVENT_LIST_TERMINATED) { /* Enqueue audio upto event */ switch (events->type) { case espeakEVENT_MARK: if (!EspeakIndexing) break; case espeakEVENT_PLAY:{ /* Convert ms position to samples */ gint64 pos_msg = events->audio_position; pos_msg = pos_msg * espeak_sample_rate / 1000; /* Convert position in message to position in current chunk */ int upto = (int)CLAMP(pos_msg - numsamples_sent_msg, 0, numsamples); /* This is just for safety */ espeak_send_audio_upto(wav, &numsamples_sent, upto); break; } default: break; } /* Process actual event */ switch (events->type) { case espeakEVENT_MARK: if (EspeakIndexing) espeak_add_mark_to_playback_queue(events->id.name); break; case espeakEVENT_PLAY: espeak_add_sound_icon_to_playback_queue(events-> id.name); break; case espeakEVENT_MSG_TERMINATED: // This event never has any audio in the same callback espeak_add_flag_to_playback_queue(ESPEAK_QET_END); break; default: break; } if (espeak_stop_requested) { return 1; } events++; } espeak_send_audio_upto(wav, &numsamples_sent, numsamples); numsamples_sent_msg += numsamples; return 0; } static int uri_callback(int type, const char *uri, const char *base) { int result = 1; if (type == 1) { /* Audio icon */ if (g_file_test(uri, G_FILE_TEST_EXISTS)) { result = 0; } } return result; } static TPlaybackQueueEntry *playback_queue_pop() { TPlaybackQueueEntry *result = NULL; pthread_mutex_lock(&playback_queue_mutex); while (!espeak_stop_requested && playback_queue == NULL) { pthread_cond_wait(&playback_queue_condition, &playback_queue_mutex); } if (!espeak_stop_requested) { result = (TPlaybackQueueEntry *) playback_queue->data; playback_queue = g_slist_remove(playback_queue, playback_queue->data); if (result->type == ESPEAK_QET_AUDIO) { playback_queue_size -= result->data.audio.num_samples; pthread_cond_signal(&playback_queue_condition); } } pthread_mutex_unlock(&playback_queue_mutex); return result; } static gboolean playback_queue_push(TPlaybackQueueEntry * entry) { pthread_mutex_lock(&playback_queue_mutex); playback_queue = g_slist_append(playback_queue, entry); if (entry->type == ESPEAK_QET_AUDIO) { playback_queue_size += entry->data.audio.num_samples; } pthread_cond_signal(&playback_queue_condition); pthread_mutex_unlock(&playback_queue_mutex); return TRUE; } /* Adds a chunk of pcm audio to the audio playback queue. Waits until there is enough space in the queue. */ static gboolean espeak_add_audio_to_playback_queue(short *audio_chunk, int num_samples) { pthread_mutex_lock(&playback_queue_mutex); while (!espeak_stop_requested && playback_queue_size > EspeakAudioQueueMaxSize) { pthread_cond_wait(&playback_queue_condition, &playback_queue_mutex); } pthread_mutex_unlock(&playback_queue_mutex); if (espeak_stop_requested) { return FALSE; } TPlaybackQueueEntry *playback_queue_entry = g_new(TPlaybackQueueEntry, 1); playback_queue_entry->type = ESPEAK_QET_AUDIO; playback_queue_entry->data.audio.num_samples = num_samples; gint nbytes = sizeof(short) * num_samples; playback_queue_entry->data.audio.audio_chunk = (short *)g_memdup((gconstpointer) audio_chunk, nbytes); playback_queue_push(playback_queue_entry); return TRUE; } /* Adds an Index Mark to the audio playback queue. */ static gboolean espeak_add_mark_to_playback_queue(const char *markId) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); playback_queue_entry->type = ESPEAK_QET_INDEX_MARK; playback_queue_entry->data.markId = g_strdup(markId); return playback_queue_push(playback_queue_entry); } /* Adds a begin or end flag to the playback queue. */ static gboolean espeak_add_flag_to_playback_queue(EPlaybackQueueEntryType type) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); playback_queue_entry->type = type; return playback_queue_push(playback_queue_entry); } /* Add a sound icon to the playback queue. */ static gboolean espeak_add_sound_icon_to_playback_queue(const char *filename) { TPlaybackQueueEntry *playback_queue_entry = (TPlaybackQueueEntry *) g_malloc(sizeof(TPlaybackQueueEntry)); playback_queue_entry->type = ESPEAK_QET_SOUND_ICON; playback_queue_entry->data.sound_icon_filename = g_strdup(filename); return playback_queue_push(playback_queue_entry); } /* Deletes an entry from the playback audio queue, freeing memory. */ static void espeak_delete_playback_queue_entry(TPlaybackQueueEntry * playback_queue_entry) { switch (playback_queue_entry->type) { case ESPEAK_QET_AUDIO: g_free(playback_queue_entry->data.audio.audio_chunk); break; case ESPEAK_QET_INDEX_MARK: g_free(playback_queue_entry->data.markId); break; case ESPEAK_QET_SOUND_ICON: g_free(playback_queue_entry->data.sound_icon_filename); break; default: break; } g_free(playback_queue_entry); } /* Erases the entire playback queue, freeing memory. */ static void espeak_clear_playback_queue() { pthread_mutex_lock(&playback_queue_mutex); while (NULL != playback_queue) { TPlaybackQueueEntry *playback_queue_entry = playback_queue->data; espeak_delete_playback_queue_entry(playback_queue_entry); playback_queue = g_slist_remove(playback_queue, playback_queue->data); } playback_queue = NULL; playback_queue_size = 0; pthread_mutex_unlock(&playback_queue_mutex); } /* Sends a chunk of audio to the audio player and waits for completion or error. */ static gboolean espeak_send_to_audio(TPlaybackQueueEntry * playback_queue_entry) { int ret = 0; AudioTrack track; track.num_samples = playback_queue_entry->data.audio.num_samples; track.num_channels = 1; track.sample_rate = espeak_sample_rate; track.bits = 16; track.samples = playback_queue_entry->data.audio.audio_chunk; DBG(DBG_MODNAME " Sending %i samples to audio.", track.num_samples); ret = module_tts_output(track, SPD_AUDIO_LE); if (ret < 0) { DBG("ERROR: Can't play track for unknown reason."); return FALSE; } DBG(DBG_MODNAME " Sent to audio."); return TRUE; } /* Playback thread. */ static void *_espeak_play(void *nothing) { char *markId; TPlaybackQueueEntry *playback_queue_entry = NULL; DBG(DBG_MODNAME " Playback thread starting......."); /* Block all signals to this thread. */ set_speaking_thread_parameters(); while (!espeak_close_requested) { /* If semaphore not set, set suspended lock and suspend until it is signaled. */ if (0 != sem_trywait(&espeak_play_semaphore)) { pthread_mutex_lock(&espeak_play_suspended_mutex); sem_wait(&espeak_play_semaphore); pthread_mutex_unlock(&espeak_play_suspended_mutex); } DBG(DBG_MODNAME " Playback semaphore on."); if (espeak_close_requested) break; if (espeak_state < BEFORE_PLAY) { /* This can happen after wake-up from suspend-to-disk */ DBG(DBG_MODNAME " Warning: Spurious wake of of playback thread."); continue; } while (1) { gboolean finished = FALSE; playback_queue_entry = playback_queue_pop(); if (playback_queue_entry == NULL) { DBG(DBG_MODNAME " playback thread detected stop."); break; } switch (playback_queue_entry->type) { case ESPEAK_QET_AUDIO: espeak_send_to_audio(playback_queue_entry); break; case ESPEAK_QET_INDEX_MARK: markId = playback_queue_entry->data.markId; DBG(DBG_MODNAME " reporting index mark |%s|.", markId); module_report_index_mark(markId); DBG(DBG_MODNAME " index mark reported."); pthread_mutex_lock(&espeak_state_mutex); if (espeak_state == SPEAKING && espeak_pause_state == ESPEAK_PAUSE_REQUESTED && !is_thread_busy (&espeak_stop_or_pause_suspended_mutex) && g_str_has_prefix(markId, "__spd_")) { DBG(DBG_MODNAME " Pause requested in playback thread. Stopping."); espeak_stop_requested = TRUE; espeak_pause_state = ESPEAK_PAUSE_MARK_REPORTED; sem_post (&espeak_stop_or_pause_semaphore); finished = TRUE; } pthread_mutex_unlock(&espeak_state_mutex); break; case ESPEAK_QET_SOUND_ICON: module_play_file(playback_queue_entry-> data.sound_icon_filename); break; case ESPEAK_QET_BEGIN:{ gboolean report_begin = FALSE; pthread_mutex_lock(&espeak_state_mutex); if (espeak_state == BEFORE_PLAY) { espeak_state = SPEAKING; report_begin = TRUE; } pthread_mutex_unlock (&espeak_state_mutex); if (report_begin) module_report_event_begin(); break; } case ESPEAK_QET_END: pthread_mutex_lock(&espeak_state_mutex); DBG(DBG_MODNAME " playback thread got END from queue."); if (espeak_state == SPEAKING) { if (!espeak_stop_requested) { DBG(DBG_MODNAME " playback thread reporting end."); espeak_state = IDLE; espeak_pause_state = ESPEAK_PAUSE_OFF; } finished = TRUE; } pthread_mutex_unlock(&espeak_state_mutex); if (finished) module_report_event_end(); break; } espeak_delete_playback_queue_entry (playback_queue_entry); if (finished) break; } } DBG(DBG_MODNAME " Playback thread ended......."); return 0; } static SPDVoice **espeak_list_synthesis_voices() { SPDVoice **result = NULL; SPDVoice *voice = NULL; SPDVoice *vo = NULL; const espeak_VOICE **espeak_voices = NULL; const espeak_VOICE **espeak_variants = NULL; espeak_VOICE *variant_spec = NULL; const espeak_VOICE *v = NULL; GQueue *voice_list = NULL; GQueue *variant_list = NULL; GList *voice_list_iter = NULL; GList *variant_list_iter = NULL; const gchar *first_lang = NULL; gchar *lang = NULL; gchar *variant = NULL; gchar *dash = NULL; gchar *vname = NULL; int numvoices = 0; int numvariants = 0; int totalvoices = 0; int i = 0; espeak_voices = espeak_ListVoices(NULL); voice_list = g_queue_new(); for (i = 0; espeak_voices[i] != NULL; i++) { v = espeak_voices[i]; if (!g_str_has_prefix(v->identifier, "mb/")) { /* Not an mbrola voice */ voice = g_new0(SPDVoice, 1); voice->name = g_strdup(v->name); first_lang = v->languages + 1; lang = NULL; variant = NULL; if (g_utf8_validate(first_lang, -1, NULL)) { dash = g_utf8_strchr(first_lang, -1, '-'); if (dash != NULL) { /* There is probably a variant string (like en-uk) */ lang = g_strndup(first_lang, dash - first_lang); variant = g_strdup(g_utf8_next_char(dash)); } else { lang = g_strdup(first_lang); } } else { DBG(DBG_MODNAME " Not a valid utf8 string: %s", first_lang);; } voice->language = lang; voice->variant = variant; g_queue_push_tail(voice_list, voice); } } numvoices = g_queue_get_length(voice_list); DBG(DBG_MODNAME " %d voices total.", numvoices); if (EspeakListVoiceVariants) { variant_spec = g_new0(espeak_VOICE, 1); variant_spec->languages = "variant"; espeak_variants = espeak_ListVoices(variant_spec); variant_list = g_queue_new(); for (i = 0; espeak_variants[i] != NULL; i++) { v = espeak_variants[i]; vname = g_strdup(v->name); g_queue_push_tail(variant_list, vname); } numvariants = g_queue_get_length(variant_list); DBG(DBG_MODNAME " %d variants total.", numvariants); } totalvoices = (numvoices * numvariants) + numvoices; result = g_new0(SPDVoice *, totalvoices + 1); voice_list_iter = g_queue_peek_head_link(voice_list); for (i = 0; i < totalvoices; i++) { result[i] = voice_list_iter->data; if (variant_list && !g_queue_is_empty(variant_list)) { vo = voice_list_iter->data; variant_list_iter = g_queue_peek_head_link(variant_list); while (variant_list_iter != NULL && variant_list_iter->data != NULL) { voice = g_new0(SPDVoice, 1); voice->name = g_strdup_printf("%s+%s", vo->name, (char *)variant_list_iter->data); voice->language = g_strdup(vo->language); voice->variant = g_strdup(vo->variant); result[++i] = voice; variant_list_iter = variant_list_iter->next; } } voice_list_iter = voice_list_iter->next; } if (voice_list != NULL) g_queue_free(voice_list); if (variant_list != NULL) g_queue_free_full(variant_list, (GDestroyNotify)g_free); if (variant_spec != NULL) g_free(variant_spec); result[i] = NULL; DBG(DBG_MODNAME " %d usable voices.", totalvoices); return result; } static void espeak_free_voice_list() { if (espeak_voice_list != NULL) { int i; for (i = 0; espeak_voice_list[i] != NULL; i++) { g_free(espeak_voice_list[i]->name); g_free(espeak_voice_list[i]->language); g_free(espeak_voice_list[i]->variant); g_free(espeak_voice_list[i]); } g_free(espeak_voice_list); espeak_voice_list = NULL; } } static TEspeakSuccess espeak_set_punctuation_list_from_utf8(const gchar * punct) { TEspeakSuccess result = ERROR; wchar_t *wc_punct = (wchar_t *) g_convert(punct, -1, "wchar_t", "utf-8", NULL, NULL, NULL); if (wc_punct != NULL) { espeak_ERROR ret = espeak_SetPunctuationList(wc_punct); if (ret == EE_OK) result = OK; g_free(wc_punct); } return result; } /* > */ /* local variables: */ /* folded-file: t */ /* c-basic-offset: 4 */ /* end: */ speech-dispatcher-0.9.1/src/modules/module_utils_addvoice.c0000644000175000017500000001453513465234024021016 00000000000000/* * module_utils_addvoice.c - Functionality for the DotConf AddVoice feature * * Copyright (C) 2001, 2002, 2003, 2006, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: module_utils_addvoice.c,v 1.5 2007-07-29 23:43:33 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "module_utils.h" GHashTable *module_voice_table = NULL; static int nbvoices=0; static int nbpaths=0; static SPDVoice *generic_voices; static SPDVoice **generic_voices_list; static char **dependency_paths; typedef struct { char *male1; char *male2; char *male3; char *female1; char *female2; char *female3; char *child_male; char *child_female; } SPDVoiceDef; DOTCONF_CB(VoiceFileDependency_cb) { dependency_paths = (char **)g_realloc(dependency_paths, (nbpaths + 1) * sizeof *dependency_paths); dependency_paths[nbpaths] = g_strdup(cmd->data.str); ++nbpaths; return NULL; } DOTCONF_CB(AddVoice_cb) { int i=0; GRegex *regex; SPDVoiceDef *voices; char *language = cmd->data.list[0]; char *symbolic; char *voicename = cmd->data.list[2]; char *key; SPDVoiceDef *value; if (language == NULL) { DBG("Missing language.\n"); return NULL; } if (cmd->data.list[1] == NULL) { DBG("Missing symbolic name.\n"); return NULL; } if (voicename == NULL) { DBG("Missing voice name for %s\n", cmd->data.list[0]); return NULL; } if (module_voice_table == NULL) { return NULL; } symbolic = (char *)g_ascii_strup(cmd->data.list[1], strlen(cmd->data.list[1])); voices = g_hash_table_lookup(module_voice_table, language); if (voices == NULL) { key = (char *)g_strdup(language); value = (SPDVoiceDef *) g_malloc(sizeof(SPDVoiceDef)); value->male1 = NULL; value->male2 = NULL; value->male3 = NULL; value->female1 = NULL; value->female2 = NULL; value->female3 = NULL; value->child_male = NULL; value->child_female = NULL; g_hash_table_insert(module_voice_table, key, value); voices = value; } regex = g_regex_new("[$]VOICE", 0, 0, NULL); for (i = 0; i < nbpaths; i++) { char *new_dependency_path = g_regex_replace_literal(regex, dependency_paths[i], -1, 0, cmd->data.list[2], 0, NULL); if (! g_file_test(new_dependency_path, G_FILE_TEST_EXISTS)) { g_free(new_dependency_path); g_regex_unref(regex); return NULL; } g_free(new_dependency_path); } g_regex_unref(regex); if (!strcmp(symbolic, "MALE1")) voices->male1 = g_strdup(voicename); else if (!strcmp(symbolic, "MALE2")) voices->male2 = g_strdup(voicename); else if (!strcmp(symbolic, "MALE3")) voices->male3 = g_strdup(voicename); else if (!strcmp(symbolic, "FEMALE1")) voices->female1 = g_strdup(voicename); else if (!strcmp(symbolic, "FEMALE2")) voices->female2 = g_strdup(voicename); else if (!strcmp(symbolic, "FEMALE3")) voices->female3 = g_strdup(voicename); else if (!strcmp(symbolic, "CHILD_MALE")) voices->child_male = g_strdup(voicename); else if (!strcmp(symbolic, "CHILD_FEMALE")) voices->child_female = g_strdup(voicename); else { DBG("Unrecognized voice name in configuration\n"); return NULL; } generic_voices = (SPDVoice *)g_realloc(generic_voices, (nbvoices+1) * sizeof(SPDVoice)); generic_voices_list = (SPDVoice **)g_realloc(generic_voices_list, (nbvoices+2) * sizeof(SPDVoice *)); generic_voices[nbvoices].name = g_strdup(cmd->data.list[2]); generic_voices[nbvoices].language = g_strdup(cmd->data.list[0]); generic_voices[nbvoices].variant = g_strdup(cmd->data.list[1]);; for (i = 0; i < nbvoices+1; i++) generic_voices_list[i] = &generic_voices[i]; generic_voices_list[nbvoices+1] = NULL; ++nbvoices; return NULL; } void module_register_available_voices(void) { module_dc_options = module_add_config_option(module_dc_options, &module_num_dc_options, "VoiceFileDependency", ARG_STR, VoiceFileDependency_cb, NULL, 0); } void module_register_settings_voices(void) { module_voice_table = g_hash_table_new(g_str_hash, g_str_equal); module_dc_options = module_add_config_option(module_dc_options, &module_num_dc_options, "AddVoice", ARG_LIST, AddVoice_cb, NULL, 0); } gboolean module_existsvoice(char *voicename) { int i; if (!nbvoices) return FALSE; for (i = 0; generic_voices_list[i] != NULL; i++) { if (strcasecmp(generic_voices[i].name, voicename) == 0) return TRUE; } return FALSE; } SPDVoice **module_list_registered_voices(void) { return (SPDVoice **)generic_voices_list; } char *module_getvoice(char *language, SPDVoiceType voice) { SPDVoiceDef *voices; char *ret; if (module_voice_table == NULL) { DBG("Can't get voice because voicetable is NULL\n"); return NULL; } voices = g_hash_table_lookup(module_voice_table, language); if (voices == NULL) { DBG("There are no voices in the table for language=%s\n", language); return NULL; } switch (voice) { case SPD_MALE1: ret = voices->male1; break; case SPD_MALE2: ret = voices->male2; break; case SPD_MALE3: ret = voices->male3; break; case SPD_FEMALE1: ret = voices->female1; break; case SPD_FEMALE2: ret = voices->female2; break; case SPD_FEMALE3: ret = voices->female3; break; case SPD_CHILD_MALE: ret = voices->child_male; break; case SPD_CHILD_FEMALE: ret = voices->child_female; break; default: printf("Unknown voice"); return NULL; } if (ret == NULL) ret = voices->male1; if (ret == NULL) ret = voices->female1; if (ret == NULL) ret = voices->male2; if (ret == NULL) ret = voices->female2; if (ret == NULL) ret = voices->male3; if (ret == NULL) ret = voices->female3; if (ret == NULL) ret = voices->child_male; if (ret == NULL) ret = voices->child_female; if (ret == NULL) fprintf(stderr, "No voice available for this output module!"); return ret; } speech-dispatcher-0.9.1/src/modules/dummy.c0000644000175000017500000001353213406252426015603 00000000000000 /* * dummy.c - Speech Dispatcher dummy output module * * A simplific output module that just tries to play an * an error message in various ways. * * Copyright (C) 2008 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * $Id: dummy.c,v 1.3 2008-06-09 10:32:00 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "module_utils.h" #define MODULE_NAME "dummy" #define MODULE_VERSION "0.1" //#define Debug 0 /* Thread and process control */ static int dummy_speaking = 0; static pthread_t dummy_speak_thread; static pid_t dummy_pid; static sem_t dummy_semaphore; /* Internal functions prototypes */ static void *_dummy_speak(void *); static void _dummy_child(); /* Fill the module_info structure with pointers to this modules functions */ /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); return 0; } int module_init(char **status_info) { int ret; *status_info = NULL; sem_init(&dummy_semaphore, 0, 0); DBG("Dummy: creating new thread for dummy_speak\n"); dummy_speaking = 0; ret = pthread_create(&dummy_speak_thread, NULL, _dummy_speak, NULL); if (ret != 0) { DBG("Dummy: thread failed\n"); *status_info = g_strdup("The module couldn't initialize threads" "This can be either an internal problem or an" "architecture problem. If you are sure your architecture" "supports threads, please report a bug."); return -1; } *status_info = g_strdup("Everything ok so far."); DBG("Ok, now debugging"); return 0; } SPDVoice **module_list_voices(void) { return NULL; } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { DBG("speak()\n"); if (dummy_speaking) { DBG("Speaking when requested to write"); return 0; } DBG("Requested data: |%s|\n", data); /* Send semaphore signal to the speaking thread */ dummy_speaking = 1; sem_post(&dummy_semaphore); DBG("Dummy: leaving write() normally\n\r"); return bytes; } int module_stop(void) { DBG("dummy: stop(), dummy_speaking=%d, dummy_pid=%d\n", dummy_speaking, dummy_pid); if (dummy_speaking && dummy_pid) { DBG("dummy: stopping process group pid %d\n", dummy_pid); kill(-dummy_pid, SIGKILL); } DBG("Already stopped, no action"); return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (dummy_speaking) { DBG("Dummy module can't pause\n"); return 0; } else { return -1; } } char *module_is_speaking(void) { return NULL; } int module_close(void) { DBG("dummy: close()\n"); if (dummy_speaking) { module_stop(); } if (module_terminate_thread(dummy_speak_thread) != 0) return -1; sem_destroy(&dummy_semaphore); return 0; } /* Internal functions */ void *_dummy_speak(void *nothing) { int status; DBG("dummy: speaking thread starting.......\n"); set_speaking_thread_parameters(); while (1) { sem_wait(&dummy_semaphore); DBG("Semaphore on\n"); module_report_event_begin(); /* Create a new process so that we could send it signals */ dummy_pid = fork(); switch (dummy_pid) { case -1: DBG("Can't say the message. fork() failed!\n"); dummy_speaking = 0; continue; case 0:{ /* Set this process as a process group leader (so that SIGKILL is also delivered to the child processes created by system()) */ if (setpgid(0, 0) == -1) DBG("Can't set myself as project group leader!"); DBG("Starting child...\n"); _dummy_child(); } break; default: /* This is the parent. Send data to the child. */ DBG("Waiting for child..."); waitpid(dummy_pid, &status, 0); dummy_speaking = 0; DBG("Child exited"); // Report CANCEL if the process was signal-terminated // and END if it terminated normally if (WIFSIGNALED(status)) module_report_event_stop(); else module_report_event_end(); DBG("child terminated -: status:%d signal?:%d signal number:%d.\n", WIFEXITED(status), WIFSIGNALED(status), WTERMSIG(status)); } } dummy_speaking = 0; DBG("dummy: speaking thread ended.......\n"); pthread_exit(NULL); } void _dummy_child() { sigset_t some_signals; int ret; char *try1, *try2, *try3; sigfillset(&some_signals); module_sigunblockusr(&some_signals); DBG("Entering child loop\n"); /* Read the waiting data */ try1 = g_strdup("play " DATADIR "/dummy-message.wav > /dev/null 2> /dev/null"); try2 = g_strdup("aplay " DATADIR "/dummy-message.wav > /dev/null 2> /dev/null"); try3 = g_strdup("paplay -n speech-dispatcher " DATADIR "/dummy-message.wav > /dev/null 2> /dev/null"); DBG("child: synth commands = |%s|%s|%s|", try1, try2, try3); DBG("Speaking in child..."); module_sigblockusr(&some_signals); ret = system(try1); DBG("Executed shell command '%s' returned with %d", try1, ret); if ((ret != 0)) { DBG("Execution failed, trying seccond command"); ret = system(try2); DBG("Executed shell command '%s' returned with %d", try1, ret); if ((ret != 0)) { DBG("Execution failed, trying third command"); ret = system(try3); DBG("Executed shell command '%s' returned with %d", try1, ret); if ((ret != 0) && (ret != 256)) { DBG("Failed, giving up."); } } } module_sigunblockusr(&some_signals); g_free(try1); g_free(try2); g_free(try3); DBG("Done, exiting from child."); exit(0); } speech-dispatcher-0.9.1/src/modules/cicero.c0000644000175000017500000002345213417454630015721 00000000000000/* * cicero.c - Speech Dispatcher backend for Cicero French TTS engine * * Copyright (C) 2006 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * @author: Olivier BERT */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "module_utils.h" #define MODULE_NAME "cicero" #define MODULE_VERSION "0.3" // #define DEBUG_MODULE 1 DECLARE_DEBUG() static int initialized = 0; /* Thread and process control */ static int cicero_speaking = 0; static pthread_t cicero_speaking_thread; static sem_t cicero_semaphore; static char **cicero_message; static SPDMessageType cicero_message_type; static int cicero_position = 0; static int cicero_pause_requested = 0; signed int cicero_volume = 0; static unsigned int CiceroMaxChunkLength = 500; /* Internal functions prototypes */ static void cicero_set_rate(signed int rate); static void *_cicero_speak(void *); int cicero_stop = 0; /* ** Config file options */ //MOD_OPTION_1_STR(CiceroWrapper); MOD_OPTION_1_STR(CiceroExecutable) MOD_OPTION_1_STR(CiceroExecutableLog) /* ** Pipes to cicero */ static int fd1[2], fd2[2]; /* ** Some internal functions */ static long int millisecondsBetween(const struct timeval *from, const struct timeval *to) { return ((to->tv_sec - from->tv_sec) * 1000) + ((to->tv_usec - from->tv_usec) / 1000); } long int millisecondsSince(const struct timeval *from) { struct timeval now; gettimeofday(&now, NULL); return millisecondsBetween(from, &now); } static int hasTimedOut(int milliseconds) { static struct timeval start = { 0, 0 }; if (milliseconds) return millisecondsSince(&start) >= milliseconds; gettimeofday(&start, NULL); return 1; } static void mywrite(int fd, const void *buf, int len) { char *pos = (char *)buf; int w; if (fd < 0) return; hasTimedOut(0); do { if ((w = write(fd, pos, len)) < 0) { if (errno == EINTR || errno == EAGAIN) continue; else if (errno == EPIPE) { DBG("Broken pipe\n"); } else perror("Pipe write"); return; } pos += w; len -= w; } while (len && !hasTimedOut(600)); if (len) fprintf(stderr, "Pipe write timed out"); } /* Public functions */ int module_load(void) { INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); MOD_OPTION_1_STR_REG(CiceroExecutable, "/usr/bin/cicero"); MOD_OPTION_1_STR_REG(CiceroExecutableLog, "/var/log/speech-dispatcher/cicero-executable.log"); return 0; } int module_init(char **status_info) { int ret; int stderr_redirect; DBG("Module init\n"); if (access(CiceroExecutable, X_OK) != 0) { DBG("ERROR: can not reach executable %s", CiceroExecutable); return -1; } (void)signal(SIGPIPE, SIG_IGN); DBG("call the pipe system call\n"); if (pipe(fd1) < 0 || pipe(fd2) < 0) { DBG("Error pipe()\n"); return -1; } DBG("Call fork system call\n"); stderr_redirect = open(CiceroExecutableLog, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (stderr_redirect == -1) { DBG("ERROR: Opening debug file for Cicero binary failed: (error=%d) %s", stderr_redirect, strerror(errno)); } else { DBG("Cicero synthesizer logging to file %s", CiceroExecutableLog); } switch (fork()) { case -1:{ DBG("Error fork()\n"); return -1; } case 0:{ if (dup2(fd2[0], 0) < 0 /* stdin */ || dup2(fd1[1], 1) < 0) { /* stdout */ DBG("Error dup2()\n"); exit(1); } if (stderr_redirect >= 0) { if (dup2(stderr_redirect, 2) < 0) DBG("ERROR: Couldn't redirect stderr, not logging for Cicero synthesizer."); } /*close(2); close(fd2[1]); close(fd1[0]); */ int i = 0; for (i = 3; i < 256; i++) close(i); (void)signal(SIGPIPE, SIG_IGN); execl(CiceroExecutable, CiceroExecutable, (void *)NULL); DBG("Error execl()\n"); exit(1); } default:{ if (stderr_redirect >= 0) close(stderr_redirect); close(fd1[1]); close(fd2[0]); if (fcntl(fd2[1], F_SETFL, O_NDELAY) < 0 || fcntl(fd1[0], F_SETFL, O_NDELAY) < 0) { DBG("Error fcntl()\n"); return -1; } } } cicero_message = g_malloc(sizeof(char *)); *cicero_message = NULL; sem_init(&cicero_semaphore, 0, 0); DBG("Cicero: creating new thread for cicero_tracking\n"); cicero_speaking = 0; ret = pthread_create(&cicero_speaking_thread, NULL, _cicero_speak, NULL); if (ret != 0) { DBG("Cicero: thread failed\n"); *status_info = g_strdup("The module couldn't initialize threads " "This can be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return -1; } *status_info = g_strdup("Cicero initialized successfully."); initialized = 1; return 0; } SPDVoice **module_list_voices(void) { return NULL; } int module_speak(gchar * data, size_t bytes, SPDMessageType msgtype) { DBG("Module speak\n"); /* The following should not happen */ if (cicero_speaking) { DBG("Speaking when requested to write"); return 0; } DBG("Requested data: |%s|\n", data); if (*cicero_message != NULL) { g_free(*cicero_message); *cicero_message = NULL; } *cicero_message = module_strip_ssml(data); cicero_message_type = SPD_MSGTYPE_TEXT; /* Setting voice */ /* UPDATE_PARAMETER(voice, cicero_set_voice); */ UPDATE_PARAMETER(rate, cicero_set_rate); /* UPDATE_PARAMETER(pitch, cicero_set_pitch); */ /* Send semaphore signal to the speaking thread */ cicero_speaking = 1; sem_post(&cicero_semaphore); DBG("Cicero: leaving module_speak() normally\n\r"); return bytes; } int module_stop(void) { unsigned char c = 1; DBG("cicero: stop()\n"); cicero_stop = 1; mywrite(fd2[1], &c, 1); return 0; } size_t module_pause(void) { DBG("pause requested\n"); if (cicero_speaking) { DBG("Pause not supported by cicero\n"); cicero_pause_requested = 1; module_stop(); return -1; } cicero_pause_requested = 0; return 0; } int module_close(void) { DBG("cicero: close()\n"); if (cicero_speaking) { module_stop(); } if (!initialized) return 0; if (module_terminate_thread(cicero_speaking_thread) != 0) return -1; sem_destroy(&cicero_semaphore); initialized = 0; return 0; } /* Internal functions */ void *_cicero_speak(void *nothing) { char stop_code = 1; unsigned int pos = 0, inx = 0, len = 0; int flag = 0; int bytes; int ret; char buf[CiceroMaxChunkLength], l[5], b[2]; struct pollfd ufds = { fd1[0], POLLIN | POLLPRI, 0 }; DBG("cicero: speaking thread starting.......\n"); set_speaking_thread_parameters(); while (1) { sem_wait(&cicero_semaphore); DBG("Semaphore on\n"); len = strlen(*cicero_message); cicero_stop = 0; cicero_speaking = 1; cicero_position = 0; pos = 0; module_report_event_begin(); while (1) { flag = 0; if (cicero_stop) { DBG("Stop in thread, terminating"); cicero_speaking = 0; module_report_event_stop(); break; } if (pos >= len) { /* end of text */ DBG("End of text in speaking thread\n"); module_report_event_end(); cicero_speaking = 0; break; } DBG("Call get_parts: pos=%d, msg=\"%s\" \n", pos, *cicero_message); bytes = module_get_message_part(*cicero_message, buf, &pos, CiceroMaxChunkLength, ".;?!"); DBG("Returned %d bytes from get_part\n", bytes); if (bytes < 0) { DBG("ERROR: Can't get message part, terminating"); cicero_speaking = 0; module_report_event_stop(); break; } buf[bytes] = 0; DBG("Text to synthesize is '%s'\n", buf); if (bytes > 0) { DBG("Speaking ..."); DBG("Trying to synthesize text"); l[0] = 4; /* say code for UTF-8 data */ l[1] = bytes >> 8; l[2] = bytes & 0xFF; l[3] = 0, l[4] = 0; mywrite(fd2[1], &stop_code, 1); mywrite(fd2[1], l, 5); mywrite(fd2[1], buf, bytes); cicero_position = 0; while (1) { ret = poll(&ufds, 1, 60); if (ret) DBG("poll() system call returned %d, events=%d\n", ret, ufds.events); if (ret < 0) { perror("poll"); module_report_event_stop(); flag = 1; cicero_speaking = 0; break; } if (ret > 0) safe_read(fd1[0], b, 2); if (cicero_stop) { cicero_speaking = 0; module_report_event_stop(); flag = 1; break; } if (ret == 0) continue; inx = (b[0] << 8 | b[1]); DBG("Tracking: index=%u, bytes=%d\n", inx, bytes); if (inx == bytes) { cicero_speaking = 0; break; } else { if (inx) cicero_position = inx; } } } else { cicero_speaking = 0; break; } if (flag) break; } cicero_stop = 0; } cicero_speaking = 0; DBG("cicero: tracking thread ended.......\n"); pthread_exit(NULL); } static void cicero_set_rate(signed int rate) { const float spkRateTable[] = { 0.3333, 0.3720, 0.4152, 0.4635, 0.5173, 0.5774, 0.6444, 0.7192, 0.8027, 0.8960, 1.0000, 1.1161, 1.2457, 1.3904, 1.5518, 1.7320, 1.9332, 2.1577, 2.4082, 2.6879, 3.0000 }; float expand; rate -= 100; rate = abs(rate); rate /= 10; expand = spkRateTable[rate]; unsigned char *p = (unsigned char *)&expand; unsigned char l[5]; l[0] = 3; l[1] = p[3]; l[2] = p[2]; l[3] = p[1]; l[4] = p[0]; mywrite(fd2[1], l, 5); } speech-dispatcher-0.9.1/src/modules/module_utils.h0000644000175000017500000002776413406252542017175 00000000000000/* * module_utils.h - Module utilities * Functions to help writing output modules for Speech Dispatcher * Copyright (C) 2003, 2004, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: module_utils.h,v 1.22 2008-06-27 12:29:21 hanke Exp $ */ #ifndef __MODULE_UTILS_H #define __MODULE_UTILS_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spd_audio.h" typedef struct SPDMarks { unsigned num; unsigned allocated; unsigned *samples; char **names; gboolean stop; } SPDMarks; int log_level; AudioID *module_audio_id; SPDMsgSettings msg_settings; SPDMsgSettings msg_settings_old; int current_index_mark; int Debug; FILE *CustomDebugFile; configfile_t *configfile; configoption_t *module_dc_options; int module_num_dc_options; const char *module_name; #define CLEAN_OLD_SETTINGS_TABLE() do { \ msg_settings_old.rate = -101;\ msg_settings_old.pitch = -101;\ msg_settings_old.pitch_range = -101;\ msg_settings_old.volume = -101;\ msg_settings_old.punctuation_mode = (SPDPunctuation) -1;\ msg_settings_old.spelling_mode = (SPDSpelling) -1;\ msg_settings_old.cap_let_recogn = (SPDCapitalLetters) -1;\ msg_settings_old.voice_type = (SPDVoiceType) -1;\ msg_settings_old.voice.name = NULL;\ msg_settings_old.voice.language = NULL; \ } while (0) #define INIT_SETTINGS_TABLES() do { \ module_name = MODULE_NAME; \ module_dc_options = NULL;\ msg_settings.rate = 0;\ msg_settings.pitch = 0;\ msg_settings.pitch_range = 0;\ msg_settings.volume = 0;\ msg_settings.punctuation_mode = SPD_PUNCT_NONE;\ msg_settings.spelling_mode = SPD_SPELL_OFF;\ msg_settings.cap_let_recogn = SPD_CAP_NONE;\ msg_settings.voice_type = SPD_MALE1;\ msg_settings.voice.name = NULL;\ msg_settings.voice.language = NULL;\ CLEAN_OLD_SETTINGS_TABLE(); \ } while (0) #define DBG(arg...) do { \ if (Debug){ \ time_t t; \ struct timeval tv; \ char *tstr; \ t = time(NULL); \ tstr = g_strdup(ctime(&t)); \ tstr[strlen(tstr)-1] = 0; \ gettimeofday(&tv,NULL); \ fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \ fprintf(stderr, ": "); \ fprintf(stderr, arg); \ fprintf(stderr, "\n"); \ fflush(stderr); \ if ((Debug==2) || (Debug==3)){ \ fprintf(CustomDebugFile," %s [%d]",tstr, (int) tv.tv_usec); \ fprintf(CustomDebugFile, ": "); \ fprintf(CustomDebugFile, arg); \ fprintf(CustomDebugFile, "\n"); \ fflush(CustomDebugFile); \ } \ g_free(tstr); \ } \ } while(0) #define FATAL(msg) do { \ fprintf(stderr, "FATAL ERROR in output module [%s:%d]:\n "msg, \ __FILE__, __LINE__); \ if (Debug > 1) \ fprintf(CustomDebugFile, "FATAL ERROR in output module [%s:%d]:\n "msg, \ __FILE__, __LINE__); \ exit(EXIT_FAILURE); \ } while (0) int module_load(void); int module_init(char **status_info); SPDVoice **module_list_voices(void); int module_speak(char *data, size_t bytes, SPDMessageType msgtype); int module_stop(void); SPDVoice **module_get_voices(void); int module_tts_output(AudioTrack track, AudioFormat format); int module_play_file(const char *filename); int module_marks_init(SPDMarks *marks); int module_marks_add(SPDMarks *marks, unsigned sample, const char *name); int module_tts_output_marks(AudioTrack track, AudioFormat format, SPDMarks *marks); int module_marks_stop(SPDMarks *marks); int module_marks_clear(SPDMarks *marks); size_t module_pause(void); char *module_is_speaking(void); int module_close(void); SPDVoice **module_list_registered_voices(void); #define UPDATE_PARAMETER(value, setter) do { \ if (msg_settings_old.value != msg_settings.value) \ { \ msg_settings_old.value = msg_settings.value; \ setter (msg_settings.value); \ } \ } while (0) #define UPDATE_STRING_PARAMETER(value, setter) do { \ if (msg_settings_old.value == NULL || msg_settings.value == NULL \ || strcmp (msg_settings_old.value, msg_settings.value)) \ { \ if (msg_settings_old.value != NULL) \ { \ g_free (msg_settings_old.value); \ msg_settings_old.value = NULL; \ } \ if (msg_settings.value != NULL) \ { \ msg_settings_old.value = g_strdup (msg_settings.value); \ setter (msg_settings.value); \ } \ } \ } while (0) #define CHILD_SAMPLE_BUF_SIZE 16384 typedef struct { int pc[2]; int cp[2]; } TModuleDoublePipe; int module_get_message_part(const char *message, char *part, unsigned int *pos, size_t maxlen, const char *dividers); void set_speaking_thread_parameters(); void module_parent_dp_init(TModuleDoublePipe dpipe); void module_child_dp_init(TModuleDoublePipe dpipe); void module_parent_dp_close(TModuleDoublePipe dpipe); void module_child_dp_close(TModuleDoublePipe dpipe); void module_child_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes); int module_parent_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes); int module_parent_dp_read(TModuleDoublePipe dpipe, char *msg, size_t maxlen); int module_child_dp_read(TModuleDoublePipe dpipe, char *msg, size_t maxlen); void module_signal_end(void); void module_strip_punctuation_default(char *buf); void module_strip_punctuation_some(char *buf, char *punct_some); char *module_strip_ssml(char *buf); void module_sigblockall(void); void module_sigblockusr(sigset_t * signal_set); void module_sigunblockusr(sigset_t * signal_set); char *do_message(SPDMessageType msgtype); char *do_speak(void); char *do_sound_icon(void); char *do_char(void); char *do_key(void); void do_stop(void); void do_pause(void); char *do_list_voices(void); char *do_set(void); char *do_audio(void); char *do_loglevel(void); char *do_debug(char *cmd_buf); void do_quit(void); size_t module_parent_wfork(TModuleDoublePipe dpipe, const char *message, SPDMessageType msgtype, const size_t maxlen, const char *dividers, int *pause_requested); int module_parent_wait_continue(TModuleDoublePipe dpipe); void set_speaking_thread_parameters(); int module_terminate_thread(pthread_t thread); char *module_recode_to_iso(char *data, int bytes, char *language, char *fallback); void module_signal_end(void); configoption_t *module_add_config_option(configoption_t * options, int *num_options, const char *name, int type, dotconf_callback_t callback, info_t * info, unsigned long context); configoption_t *add_config_option(configoption_t * options, int *num_config_options, const char *name, int type, dotconf_callback_t callback, info_t * info, unsigned long context); /* --- MODULE DOTCONF OPTIONS DEFINITION AND REGISTRATION --- */ #define MOD_OPTION_1_STR(name) \ static char *name = NULL; \ DOTCONF_CB(name ## _cb) \ { \ if (cmd->data.str != NULL) { \ g_free(name); \ name = g_strdup(cmd->data.str); \ } \ return NULL; \ } #define MOD_OPTION_1_INT(name) \ static int name; \ DOTCONF_CB(name ## _cb) \ { \ name = cmd->data.value; \ return NULL; \ } /* TODO: Switch this to real float, not /100 integer, as soon as DotConf supports floats */ #define MOD_OPTION_1_FLOAT(name) \ static float name; \ DOTCONF_CB(name ## _cb) \ { \ name = ((float) cmd->data.value) / ((float) 100); \ return NULL; \ } #define MOD_OPTION_2(name, arg1, arg2) \ typedef struct{ \ char* arg1; \ char* arg2; \ }T ## name; \ T ## name name; \ \ DOTCONF_CB(name ## _cb) \ { \ if (cmd->data.list[0] != NULL) \ name.arg1 = g_strdup(cmd->data.list[0]); \ if (cmd->data.list[1] != NULL) \ name.arg2 = g_strdup(cmd->data.list[1]); \ return NULL; \ } #define MOD_OPTION_2_HT(name, arg1, arg2) \ typedef struct{ \ char* arg1; \ char* arg2; \ }T ## name; \ GHashTable *name; \ \ DOTCONF_CB(name ## _cb) \ { \ T ## name *new_item; \ char* new_key; \ new_item = (T ## name *) g_malloc(sizeof(T ## name)); \ if (cmd->data.list[0] == NULL) return NULL; \ new_item->arg1 = g_strdup(cmd->data.list[0]); \ new_key = g_strdup(cmd->data.list[0]); \ if (cmd->data.list[1] != NULL) \ new_item->arg2 = g_strdup(cmd->data.list[1]); \ else \ new_item->arg2 = NULL; \ g_hash_table_insert(name, new_key, new_item); \ return NULL; \ } #define MOD_OPTION_3_HT(name, arg1, arg2, arg3) \ typedef struct{ \ char* arg1; \ char* arg2; \ char *arg3; \ }T ## name; \ GHashTable *name; \ \ DOTCONF_CB(name ## _cb) \ { \ T ## name *new_item; \ char* new_key; \ new_item = (T ## name *) g_malloc(sizeof(T ## name)); \ if (cmd->data.list[0] == NULL) return NULL; \ new_item->arg1 = g_strdup(cmd->data.list[0]); \ new_key = g_strdup(cmd->data.list[0]); \ if (cmd->data.list[1] != NULL) \ new_item->arg2 = g_strdup(cmd->data.list[1]); \ else \ new_item->arg2 = NULL; \ if (cmd->data.list[2] != NULL) \ new_item->arg3 = g_strdup(cmd->data.list[2]); \ else \ new_item->arg3 = NULL; \ g_hash_table_insert(name, new_key, new_item); \ return NULL; \ } #define MOD_OPTION_1_STR_REG(name, default) do { \ if (default != NULL) name = g_strdup(default); \ else name = NULL; \ module_dc_options = module_add_config_option(module_dc_options, \ &module_num_dc_options, #name, \ ARG_STR, name ## _cb, NULL, 0); \ } while (0) #define MOD_OPTION_1_INT_REG(name, default) do { \ name = default; \ module_dc_options = module_add_config_option(module_dc_options, \ &module_num_dc_options, #name, \ ARG_INT, name ## _cb, NULL, 0); \ } while (0) /* TODO: Switch this to real float, not /100 integer, as soon as DotConf supports floats */ #define MOD_OPTION_1_FLOAT_REG(name, default) do { \ name = default; \ module_dc_options = module_add_config_option(module_dc_options, \ &module_num_dc_options, #name, \ ARG_INT, name ## _cb, NULL, 0); \ } while (0) #define MOD_OPTION_MORE_REG(name) do { \ module_dc_options = module_add_config_option(module_dc_options, \ &module_num_dc_options, #name, \ ARG_LIST, name ## _cb, NULL, 0); \ } while (0) #define MOD_OPTION_HT_REG(name) do { \ name = g_hash_table_new(g_str_hash, g_str_equal); \ module_dc_options = module_add_config_option(module_dc_options, \ &module_num_dc_options, #name, \ ARG_LIST, name ## _cb, NULL, 0); \ } while (0) /* --- DEBUGGING SUPPORT ---*/ #define DECLARE_DEBUG() \ DOTCONF_CB(Debug ## _cb) \ { \ Debug = cmd->data.value; \ return NULL; \ } #define REGISTER_DEBUG() \ MOD_OPTION_1_INT_REG(Debug, 0); \ /* --- INDEX MARKING --- */ #define INDEX_MARK_BODY_LEN 6 #define INDEX_MARK_BODY "__spd_" char *module_index_mark; /* This macro must be placed at the initialization of the module so that the later functions are possible to use */ #define INIT_INDEX_MARKING() module_index_mark = NULL; void module_report_index_mark(char *mark); void module_report_event_begin(void); void module_report_event_end(void); void module_report_event_stop(void); void module_report_event_pause(void); extern pthread_mutex_t module_stdout_mutex; int module_utils_init(void); int module_audio_init(char **status_info); /* Prototypes from module_utils_addvoice.c */ void module_register_available_voices(void); void module_register_settings_voices(void); char *module_getvoice(char *language, SPDVoiceType voice); gboolean module_existsvoice(char *voicename); #endif /* #ifndef __MODULE_UTILS_H */ speech-dispatcher-0.9.1/src/modules/module_utils.c0000644000175000017500000006365613406252531017166 00000000000000/* * module_utils.c - Module utilities * Functions to help writing output modules for Speech Dispatcher * Copyright (C) 2003,2006, 2007 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: module_utils.c,v 1.55 2008-07-10 15:37:18 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "module_utils.h" static char *module_audio_pars[10]; extern char *module_index_mark; pthread_mutex_t module_stdout_mutex = PTHREAD_MUTEX_INITIALIZER; char *do_message(SPDMessageType msgtype) { int ret; char *cur_line; GString *msg; size_t n; int nlines = 0; msg = g_string_new(""); printf("202 OK RECEIVING MESSAGE\n"); fflush(stdout); while (1) { cur_line = NULL; n = 0; ret = spd_getline(&cur_line, &n, stdin); nlines++; if (ret == -1) return g_strdup("401 ERROR INTERNAL"); if (!strcmp(cur_line, "..\n")) { g_free(cur_line); cur_line = g_strdup(".\n"); } else if (!strcmp(cur_line, ".\n")) { /* Strip the trailing \n */ msg->str[strlen(msg->str) - 1] = 0; g_free(cur_line); break; } g_string_append(msg, cur_line); g_free(cur_line); } if ((msgtype != SPD_MSGTYPE_TEXT) && (nlines > 2)) { return g_strdup("305 DATA MORE THAN ONE LINE"); } if ((msgtype == SPD_MSGTYPE_CHAR) && (!strcmp(msg->str, "space"))) { g_string_free(msg, 1); msg = g_string_new(" "); } /* no sure we need this check here at all */ if (msg->str == NULL || msg->str[0] == 0) { DBG("requested data NULL or empty\n"); g_string_free(msg, TRUE); return g_strdup("301 ERROR CANT SPEAK"); } /* check voice and synthesis_voice settings for consistency */ if (msg_settings.voice.name == NULL && msg_settings_old.voice.name != NULL && msg_settings.voice_type == msg_settings_old.voice_type) { /* force to set voice again, since synthesis_voice changed to NULL */ msg_settings_old.voice_type = -1; } /* Volume is controlled by the synthesizer. Always play at normal on audio device. */ if (spd_audio_set_volume(module_audio_id, 85) < 0) { DBG("Can't set volume. audio not initialized?"); } ret = module_speak(msg->str, strlen(msg->str), msgtype); g_string_free(msg, 1); if (ret <= 0) return g_strdup("301 ERROR CANT SPEAK"); return g_strdup("200 OK SPEAKING"); } char *do_speak(void) { return do_message(SPD_MSGTYPE_TEXT); } char *do_sound_icon(void) { return do_message(SPD_MSGTYPE_SOUND_ICON); } char *do_char(void) { return do_message(SPD_MSGTYPE_CHAR); } char *do_key(void) { return do_message(SPD_MSGTYPE_KEY); } void do_stop(void) { module_stop(); return; } void do_pause(void) { int ret; ret = module_pause(); if (ret) { DBG("WARNING: Can't pause"); return; } return; } #define SET_PARAM_NUM(name, cond) \ if(!strcmp(cur_item, #name)){ \ number = strtol(cur_value, &tptr, 10); \ if(!(cond)){ err = 2; continue; } \ if (tptr == cur_value){ err = 2; continue; } \ msg_settings.name = number; \ } #define SET_PARAM_STR(name) \ if(!strcmp(cur_item, #name)){ \ g_free(msg_settings.name); \ if(!strcmp(cur_value, "NULL")) msg_settings.name = NULL; \ else msg_settings.name = g_strdup(cur_value); \ } #define SET_PARAM_STR_C(name, fconv) \ if(!strcmp(cur_item, #name)){ \ ret = fconv(cur_value); \ if (ret != -1) msg_settings.name = ret; \ else err = 2; \ } char *do_set(void) { char *cur_item = NULL; char *cur_value = NULL; char *line = NULL; int ret; size_t n; int number; char *tptr; int err = 0; /* Error status */ printf("203 OK RECEIVING SETTINGS\n"); fflush(stdout); while (1) { line = NULL; n = 0; ret = spd_getline(&line, &n, stdin); if (ret == -1) { err = 1; break; } if (!strcmp(line, ".\n")) { g_free(line); break; } if (!err) { cur_item = strtok(line, "="); if (cur_item == NULL) { err = 1; continue; } cur_value = strtok(NULL, "\n"); if (cur_value == NULL) { err = 1; continue; } SET_PARAM_NUM(rate, ((number >= -100) && (number <= 100))) else SET_PARAM_NUM(pitch, ((number >= -100) && (number <= 100))) else SET_PARAM_NUM(pitch_range, ((number >= -100) && (number <= 100))) else SET_PARAM_NUM(volume, ((number >= -100) && (number <= 100))) else SET_PARAM_STR_C(punctuation_mode, str2EPunctMode) else SET_PARAM_STR_C(spelling_mode, str2ESpellMode) else SET_PARAM_STR_C(cap_let_recogn, str2ECapLetRecogn) else if (!strcmp(cur_item, "voice")) { ret = str2EVoice(cur_value); if (ret != -1) msg_settings.voice_type = ret; else err = 2; } else if (!strcmp(cur_item, "synthesis_voice")) { g_free(msg_settings.voice.name); if (!strcmp(cur_value, "NULL")) msg_settings.voice.name = NULL; else msg_settings.voice.name = g_strdup(cur_value); } else if (!strcmp(cur_item, "language")) { g_free(msg_settings.voice.language); if (!strcmp(cur_value, "NULL")) msg_settings.voice.language = NULL; else msg_settings.voice.language = g_strdup(cur_value); } else err = 2; /* Unknown parameter */ } g_free(line); } if (err == 0) return g_strdup("203 OK SETTINGS RECEIVED"); if (err == 1) return g_strdup("302 ERROR BAD SYNTAX"); if (err == 2) return g_strdup("303 ERROR INVALID PARAMETER OR VALUE"); return g_strdup("401 ERROR INTERNAL"); /* Can't be reached */ } #define SET_AUDIO_STR(name,idx) \ if(!strcmp(cur_item, #name)){ \ g_free(module_audio_pars[idx]); \ if(!strcmp(cur_value, "NULL")) module_audio_pars[idx] = NULL; \ else module_audio_pars[idx] = g_strdup(cur_value); \ } char *do_audio(void) { char *cur_item = NULL; char *cur_value = NULL; char *line = NULL; int ret; size_t n; int err = 0; /* Error status */ char *status = NULL; char *msg; printf("207 OK RECEIVING AUDIO SETTINGS\n"); fflush(stdout); while (1) { line = NULL; n = 0; ret = spd_getline(&line, &n, stdin); if (ret == -1) { err = 1; break; } if (!strcmp(line, ".\n")) { g_free(line); break; } if (!err) { cur_item = strtok(line, "="); if (cur_item == NULL) { err = 1; continue; } cur_value = strtok(NULL, "\n"); if (cur_value == NULL) { err = 1; continue; } SET_AUDIO_STR(audio_output_method, 0) else SET_AUDIO_STR(audio_oss_device, 1) else SET_AUDIO_STR(audio_alsa_device, 2) else SET_AUDIO_STR(audio_nas_server, 3) else SET_AUDIO_STR(audio_pulse_server, 4) else SET_AUDIO_STR(audio_pulse_min_length, 5) else /* 6 reserved for speech-dispatcher module name */ err = 2; /* Unknown parameter */ } g_free(line); } if (err == 1) return g_strdup("302 ERROR BAD SYNTAX"); if (err == 2) return g_strdup("303 ERROR INVALID PARAMETER OR VALUE"); err = module_audio_init(&status); if (err == 0) msg = g_strdup_printf("203 OK AUDIO INITIALIZED"); else msg = g_strdup_printf("300-%s\n300 UNKNOWN ERROR", status); g_free(status); return msg; } #define SET_LOGLEVEL_NUM(name, cond) \ if(!strcmp(cur_item, #name)){ \ number = strtol(cur_value, &tptr, 10); \ if(!(cond)){ err = 2; continue; } \ if (tptr == cur_value){ err = 2; continue; } \ log_level = number; \ spd_audio_set_loglevel(module_audio_id, number); \ } char *do_loglevel(void) { char *cur_item = NULL; char *cur_value = NULL; char *line = NULL; int ret; size_t n; int number; char *tptr; int err = 0; /* Error status */ char *msg; printf("207 OK RECEIVING LOGLEVEL SETTINGS\n"); fflush(stdout); while (1) { line = NULL; n = 0; ret = spd_getline(&line, &n, stdin); if (ret == -1) { err = 1; break; } if (!strcmp(line, ".\n")) { g_free(line); break; } if (!err) { cur_item = strtok(line, "="); if (cur_item == NULL) { err = 1; continue; } cur_value = strtok(NULL, "\n"); if (cur_value == NULL) { err = 1; continue; } SET_LOGLEVEL_NUM(log_level, 1) else err = 2; /* Unknown parameter */ } g_free(line); } if (err == 1) return g_strdup("302 ERROR BAD SYNTAX"); if (err == 2) return g_strdup("303 ERROR INVALID PARAMETER OR VALUE"); msg = g_strdup_printf("203 OK LOG LEVEL SET"); return msg; } char *do_debug(char *cmd_buf) { /* TODO: Develop the full on/off logic etc. */ char **cmd; char *filename; cmd = g_strsplit(cmd_buf, " ", -1); if (!cmd[1]) { g_strfreev(cmd); return g_strdup("302 ERROR BAD SYNTAX"); } if (!strcmp(cmd[1], "ON")) { if (!cmd[2]) { g_strfreev(cmd); return g_strdup("302 ERROR BAD SYNTAX"); } filename = cmd[2]; DBG("Additional logging into specific path %s requested", filename); FILE *new_CustomDebugFile = fopen(filename, "w+"); if (new_CustomDebugFile == NULL) { DBG("ERROR: Can't open custom debug file for logging: %d (%s)", errno, strerror(errno)); return g_strdup("303 CANT OPEN CUSTOM DEBUG FILE"); } if (CustomDebugFile != NULL) fclose(CustomDebugFile); CustomDebugFile = new_CustomDebugFile; if (Debug == 1) Debug = 3; else Debug = 2; DBG("Additional logging initialized"); } else if (!strcmp(cmd[1], "OFF")) { if (Debug == 3) Debug = 1; else Debug = 0; if (CustomDebugFile != NULL) fclose(CustomDebugFile); CustomDebugFile = NULL; DBG("Additional logging into specific path terminated"); } else { return g_strdup("302 ERROR BAD SYNTAX"); } g_strfreev(cmd); return g_strdup("200 OK DEBUGGING ON"); } char *do_list_voices(void) { SPDVoice **voices; int i; char *lang, *variant; GString *voice_list; voices = module_list_voices(); if (voices == NULL) { return g_strdup("304 CANT LIST VOICES"); } voice_list = g_string_new(""); for (i = 0; voices[i] != NULL; i++) { if (voices[i]->name == NULL) { /* Shouldn't happen! */ DBG("Unnamed voice found; ignoring it."); continue; } if (voices[i]->language == NULL) lang = "none"; else lang = voices[i]->language; if (voices[i]->variant == NULL) variant = "none"; else variant = voices[i]->variant; g_string_append_printf(voice_list, "200-%s\t%s\t%s\n", voices[i]->name, lang, variant); } /* check whether we found at least one voice */ if (voice_list->len == 0) { g_string_free(voice_list, TRUE); return g_strdup("304 CANT LIST VOICES"); } g_string_append(voice_list, "200 OK VOICE LIST SENT"); DBG("Voice prepared to send to speechd"); return g_string_free(voice_list, FALSE); } #undef SET_PARAM_NUM #undef SET_PARAM_STR /* This has to return int (although it doesn't return at all) so that we could * call it from PROCESS_CMD() macro like the other commands that return * something */ void do_quit(void) { printf("210 OK QUIT\n"); fflush(stdout); module_close(); spd_audio_close(module_audio_id); module_audio_id = NULL; return; } int module_get_message_part(const char *message, char *part, unsigned int *pos, size_t maxlen, const char *dividers) { int i, n; int num_dividers; int len; assert(part != NULL); assert(message != NULL); len = strlen(message); if (message[*pos] == 0) return -1; if (dividers != NULL) { num_dividers = strlen(dividers); } else { num_dividers = 0; } for (i = 0; i <= maxlen - 1; i++) { part[i] = message[*pos]; if (part[i] == 0) { return i; } // DBG("pos: %d", *pos); if ((len - 1 - i) > 2) { if ((message[*pos + 1] == ' ') || (message[*pos + 1] == '\n') || (message[*pos + 1] == '\r')) { for (n = 0; n <= num_dividers - 1; n++) { if ((part[i] == dividers[n])) { part[i + 1] = 0; (*pos)++; return i + 1; } } if ((message[*pos] == '\n') && (message[*pos + 1] == '\n')) { part[i + 1] = 0; (*pos)++; return i + 1; } if ((len - 1 - i) > 4) { if (((message[*pos] == '\r') && (message[*pos + 1] == '\n')) && ((message[*pos + 2] == '\r') && (message[*pos + 3] == '\n'))) { part[i + 1] = 0; (*pos)++; return i + 1; } } } } (*pos)++; } part[i] = 0; return i; } void module_strip_punctuation_some(char *message, char *punct_chars) { int len; char *p = message; int i; assert(message != NULL); if (punct_chars == NULL) return; len = strlen(message); for (i = 0; i <= len - 1; i++) { if (strchr(punct_chars, *p)) { DBG("Substitution %d: char -%c- for whitespace\n", i, *p); *p = ' '; } p++; } } char *module_strip_ssml(char *message) { int len; char *out; int i, n; int omit = 0; assert(message != NULL); len = strlen(message); out = (char *)g_malloc(sizeof(char) * (len + 1)); for (i = 0, n = 0; i <= len; i++) { if (message[i] == '<') { omit = 1; continue; } if (message[i] == '>') { omit = 0; continue; } if (!strncmp(&(message[i]), "<", 4)) { i += 3; out[n++] = '<'; } else if (!strncmp(&(message[i]), ">", 4)) { i += 3; out[n++] = '>'; } else if (!strncmp(&(message[i]), "&", 5)) { i += 4; out[n++] = '&'; } else if (!strncmp(&(message[i]), """, 6)) { i += 5; out[n++] = '"'; } else if (!strncmp(&(message[i]), "'", 6)) { i += 5; out[n++] = '\''; } else if (!omit || i == len) out[n++] = message[i]; } DBG("In stripping ssml: |%s|", out); return out; } void module_strip_punctuation_default(char *buf) { assert(buf != NULL); module_strip_punctuation_some(buf, "~#$%^&*+=|<>[]_"); } size_t module_parent_wfork(TModuleDoublePipe dpipe, const char *message, SPDMessageType msgtype, const size_t maxlen, const char *dividers, int *pause_requested) { unsigned int pos = 0; char msg[16]; char *buf; int bytes; size_t read_bytes = 0; DBG("Entering parent process, closing pipes"); buf = (char *)g_malloc((maxlen + 1) * sizeof(char)); module_parent_dp_init(dpipe); pos = 0; while (1) { DBG(" Looping...\n"); bytes = module_get_message_part(message, buf, &pos, maxlen, dividers); DBG("Returned %d bytes from get_part\n", bytes); if (*pause_requested) { DBG("Pause requested in parent"); module_parent_dp_close(dpipe); *pause_requested = 0; return 0; } if (bytes > 0) { DBG("Sending buf to child:|%s| %d\n", buf, bytes); module_parent_dp_write(dpipe, buf, bytes); DBG("Waiting for response from child...\n"); while (1) { read_bytes = module_parent_dp_read(dpipe, msg, 8); if (read_bytes == 0) { DBG("parent: Read bytes 0, child stopped\n"); break; } if (msg[0] == 'C') { DBG("Ok, received report to continue...\n"); break; } } } if ((bytes == -1) || (read_bytes == 0)) { DBG("End of data in parent, closing pipes"); module_parent_dp_close(dpipe); break; } } return 0; } int module_parent_wait_continue(TModuleDoublePipe dpipe) { char msg[16]; int bytes; DBG("parent: Waiting for response from child...\n"); while (1) { bytes = module_parent_dp_read(dpipe, msg, 8); if (bytes == 0) { DBG("parent: Read bytes 0, child stopped\n"); return 1; } if (msg[0] == 'C') { DBG("parent: Ok, received report to continue...\n"); return 0; } } } void module_parent_dp_init(TModuleDoublePipe dpipe) { close(dpipe.pc[0]); close(dpipe.cp[1]); } void module_parent_dp_close(TModuleDoublePipe dpipe) { close(dpipe.pc[1]); close(dpipe.cp[0]); } void module_child_dp_init(TModuleDoublePipe dpipe) { close(dpipe.pc[1]); close(dpipe.cp[0]); } void module_child_dp_close(TModuleDoublePipe dpipe) { close(dpipe.pc[0]); close(dpipe.cp[1]); } void module_child_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes) { int ret; assert(msg != NULL); ret = write(dpipe.cp[1], msg, bytes); assert(ret); } int module_parent_dp_write(TModuleDoublePipe dpipe, const char *msg, size_t bytes) { ssize_t ret; assert(msg != NULL); DBG("going to write %lu bytes", (long unsigned)bytes); ret = write(dpipe.pc[1], msg, bytes); DBG("written %ld bytes", (long)ret); return ret; } int module_child_dp_read(TModuleDoublePipe dpipe, char *msg, size_t maxlen) { int bytes; while ((bytes = read(dpipe.pc[0], msg, maxlen)) < 0) { if (errno != EINTR) { FATAL("Unable to read data"); } } return bytes; } int module_parent_dp_read(TModuleDoublePipe dpipe, char *msg, size_t maxlen) { int bytes; while ((bytes = read(dpipe.cp[0], msg, maxlen)) < 0) { if (errno != EINTR) { FATAL("Unable to read data"); } } return bytes; } void module_sigblockall(void) { int ret; sigset_t all_signals; DBG("Blocking all signals"); sigfillset(&all_signals); ret = sigprocmask(SIG_BLOCK, &all_signals, NULL); if (ret != 0) DBG("Can't block signals, expect problems with terminating!\n"); } void module_sigunblockusr(sigset_t * some_signals) { int ret; DBG("UnBlocking user signal"); sigdelset(some_signals, SIGUSR1); ret = sigprocmask(SIG_SETMASK, some_signals, NULL); if (ret != 0) DBG("Can't block signal set, expect problems with terminating!\n"); } void module_sigblockusr(sigset_t * some_signals) { int ret; DBG("Blocking user signal"); sigaddset(some_signals, SIGUSR1); ret = sigprocmask(SIG_SETMASK, some_signals, NULL); if (ret != 0) DBG("Can't block signal set, expect problems when terminating!\n"); } void set_speaking_thread_parameters() { int ret; sigset_t all_signals; ret = sigfillset(&all_signals); if (ret == 0) { ret = pthread_sigmask(SIG_BLOCK, &all_signals, NULL); if (ret != 0) DBG("Can't set signal set, expect problems when terminating!\n"); } else { DBG("Can't fill signal set, expect problems when terminating!\n"); } pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); } int module_terminate_thread(pthread_t thread) { int ret; ret = pthread_cancel(thread); if (ret != 0) { DBG("Cancellation of speak thread failed"); return 1; } ret = pthread_join(thread, NULL); if (ret != 0) { DBG("join failed!\n"); return 1; } return 0; } char *module_recode_to_iso(char *data, int bytes, char *language, char *fallback) { char *recoded; if (language == NULL) recoded = g_strdup(data); else if (!strcmp(language, "cs")) recoded = (char *)g_convert_with_fallback(data, bytes, "ISO8859-2", "UTF-8", fallback, NULL, NULL, NULL); else recoded = (char *)g_convert_with_fallback(data, bytes, "ISO8859-1", "UTF-8", fallback, NULL, NULL, NULL); if (recoded == NULL) DBG("festival: Conversion to ISO coding failed\n"); return recoded; } void module_send_asynchronous(char *text) { pthread_mutex_lock(&module_stdout_mutex); DBG("Printing reply: %s", text); fputs(text, stdout); fflush(stdout); DBG("Printed"); pthread_mutex_unlock(&module_stdout_mutex); } void module_report_index_mark(char *mark) { char *reply; DBG("Event: Index mark %s", mark); if (mark != NULL) reply = g_strdup_printf("700-%s\n700 INDEX MARK\n", mark); else return; module_send_asynchronous(reply); g_free(reply); } void module_report_event_begin(void) { module_send_asynchronous("701 BEGIN\n"); } void module_report_event_end(void) { module_send_asynchronous("702 END\n"); } void module_report_event_stop(void) { module_send_asynchronous("703 STOP\n"); } void module_report_event_pause(void) { module_send_asynchronous("704 PAUSE\n"); } /* --- CONFIGURATION --- */ configoption_t *module_add_config_option(configoption_t * options, int *num_options, const char *name, int type, dotconf_callback_t callback, info_t * info, unsigned long context) { configoption_t *opts; int num_config_options = *num_options; assert(name != NULL); num_config_options++; opts = (configoption_t *) g_realloc(options, (num_config_options + 1) * sizeof(configoption_t)); opts[num_config_options - 1].name = (char *)g_strdup(name); opts[num_config_options - 1].type = type; opts[num_config_options - 1].callback = callback; opts[num_config_options - 1].info = info; opts[num_config_options - 1].context = context; *num_options = num_config_options; return opts; } int module_audio_init(char **status_info) { char *error = 0; gchar **outputs; int i = 0; DBG("Opening audio output system"); if (NULL == module_audio_pars[0]) { *status_info = g_strdup ("Sound output method specified in configuration not supported. " "Please choose 'oss', 'alsa', 'nas', 'libao' or 'pulse'."); return -1; } g_free(module_audio_pars[6]); module_audio_pars[6] = strdup(module_name); outputs = g_strsplit(module_audio_pars[0], ",", 0); while (NULL != outputs[i]) { module_audio_id = spd_audio_open(outputs[i], (void **)&module_audio_pars[1], &error); if (module_audio_id) { DBG("Using %s audio output method", outputs[i]); g_strfreev(outputs); *status_info = g_strdup("audio initialized successfully."); return 0; } i++; } *status_info = g_strdup_printf("Opening sound device failed. Reason: %s. ", error); g_free(error); /* g_malloc'ed, in spd_audio_open. */ g_strfreev(outputs); return -1; } int module_tts_output(AudioTrack track, AudioFormat format) { if (spd_audio_play(module_audio_id, track, format) < 0) { DBG("Can't play track for unknown reason."); return -1; } return 0; } /* Plays the specified audio file. */ int module_play_file(const char *filename) { int result = 0; int subformat; sf_count_t items; sf_count_t readcount; SNDFILE *sf; SF_INFO sfinfo; DBG("Playing |%s|", filename); memset(&sfinfo, 0, sizeof(sfinfo)); sf = sf_open(filename, SFM_READ, &sfinfo); if (NULL == sf) { DBG("%s", sf_strerror(NULL)); return -1; } if (sfinfo.channels < 1 || sfinfo.channels > 2) { DBG("ERROR: channels = %d.\n", sfinfo.channels); result = FALSE; goto cleanup1; } if (sfinfo.frames > 0x7FFFFFFF || sfinfo.frames == 0) { DBG("ERROR: Unknown number of frames."); result = FALSE; goto cleanup1; } subformat = sfinfo.format & SF_FORMAT_SUBMASK; items = sfinfo.channels * sfinfo.frames; DBG("Frames = %jd, channels = %ld", sfinfo.frames, (long)sfinfo.channels); DBG("Samplerate = %i, items = %Ld", sfinfo.samplerate, (long long)items); DBG("Major format = 0x%08X, subformat = 0x%08X, endian = 0x%08X", sfinfo.format & SF_FORMAT_TYPEMASK, subformat, sfinfo.format & SF_FORMAT_ENDMASK); if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) { /* Set scaling for float to integer conversion. */ sf_command(sf, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE); } AudioTrack track; track.num_samples = sfinfo.frames; track.num_channels = sfinfo.channels; track.sample_rate = sfinfo.samplerate; track.bits = 16; track.samples = g_malloc(items * sizeof(short)); readcount = sf_read_short(sf, (short *)track.samples, items); DBG("Read %Ld items from audio file.", (long long)readcount); if (readcount > 0) { track.num_samples = readcount / sfinfo.channels; DBG("Sending %i samples to audio.", track.num_samples); int ret = module_tts_output(track, SPD_AUDIO_LE); if (ret < 0) { DBG("ERROR: Can't play track for unknown reason."); result = -1; goto cleanup2; } DBG("Sent to audio."); } cleanup2: g_free(track.samples); cleanup1: sf_close(sf); return result; } int module_marks_init(SPDMarks *marks) { marks->num = 0; marks->allocated = 0; marks->samples = NULL; marks->names = NULL; marks->stop = 0; return 0; } int module_marks_add(SPDMarks *marks, unsigned sample, const char *name) { marks->num++; if (marks->num >= marks->allocated) { /* Amortized reallocation */ marks->allocated = marks->num * 2; marks->samples = g_realloc(marks->samples, marks->allocated * sizeof(marks->samples[0])); marks->names = g_realloc(marks->names, marks->allocated * sizeof(marks->names[0])); } marks->samples[marks->num - 1] = sample; marks->names[marks->num - 1] = g_strdup(name); return 0; } int module_marks_clear(SPDMarks *marks) { unsigned i; for (i = 0; i < marks->num; i++) g_free(marks->names[i]); marks->num = 0; marks->allocated = 0; g_free(marks->samples); marks->samples = NULL; g_free(marks->names); marks->names = NULL; marks->stop = 0; return 0; } int module_tts_output_marks(AudioTrack track, AudioFormat format, SPDMarks *marks) { AudioTrack cur = track; int current_sample = 0; /* Loop control */ int start = 0; int end = marks->num; int delta = 0; /* loop below figures out the delta */ int i; for (i = 1; i < marks->num; i++) { if (marks->samples[i - 1] > marks->samples[i]) { /* Decreasing mark order */ if (delta > 0) { DBG("WARNING: Mixed samples order"); } else { start = marks->num - 1; end = -1; delta = -1; } } else if (marks->samples[i - 1] < marks->samples[i]) { /* Increasing mark order */ if (delta < 0) { DBG("WARNING: Mixed samples order"); } else { delta = 1; } } } if (delta == 0) { /* All marks are at the same sample */ delta = 1; } /* Alternate speaking and reporting mark */ for (i = start; i != end; i += delta) { unsigned end_sample = marks->samples[i]; cur.samples = &track.samples[current_sample]; cur.num_samples = end_sample - current_sample; current_sample = end_sample; if (cur.num_samples && module_tts_output(cur, format)) return -1; if (marks->stop) return 1; module_report_index_mark(marks->names[i]); } /* Finish with remaining bits if any */ if (track.num_samples > current_sample) { cur.samples = &track.samples[current_sample]; cur.num_samples = track.num_samples - current_sample; if (module_tts_output(cur, format)) return -1; } return 0; } int module_marks_stop(SPDMarks *marks) { marks->stop = 1; return 0; } speech-dispatcher-0.9.1/src/modules/module_main.c0000644000175000017500000001124513406252524016737 00000000000000/* * module_main.c - One way of doing main() in output modules. * * Copyright (C) 2001, 2002, 2003, 2006 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: module_main.c,v 1.17 2008-10-15 17:05:37 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "module_utils.h" #define PROCESS_CMD(command, function) \ if (!strcmp(cmd_buf, #command"\n")){ \ char *msg; \ pthread_mutex_lock(&module_stdout_mutex); \ if (printf("%s\n", msg = (char*) function()) < 0){ \ DBG("Broken pipe, exiting...\n"); \ ret = 2; \ break; \ } \ fflush(stdout); \ pthread_mutex_unlock(&module_stdout_mutex);\ g_free(msg); \ } #define PROCESS_CMD_W_ARGS(command, function) \ if (!strncmp(cmd_buf, #command, strlen(#command))){ \ char *msg; \ pthread_mutex_lock(&module_stdout_mutex); \ if (printf("%s\n", msg = (char*) function(cmd_buf)) < 0){ \ DBG("Broken pipe, exiting...\n"); \ ret = 2; \ break; \ } \ fflush(stdout); \ pthread_mutex_unlock(&module_stdout_mutex);\ g_free(msg); \ } #define PROCESS_CMD_NRP(command, function) \ if (!strcmp(cmd_buf, #command"\n")){ \ function(); \ } int main(int argc, char *argv[]) { char *cmd_buf; int ret; size_t n; char *configfilename = NULL; char *status_info = NULL; /* Initialize ltdl's list of preloaded audio backends. */ LTDL_SET_PRELOADED_SYMBOLS(); module_num_dc_options = 0; module_audio_id = 0; if (argc >= 2) { configfilename = g_strdup(argv[1]); } ret = module_load(); if (ret == -1) { module_close(); exit(1); } if (configfilename != NULL) { /* Add the LAST option */ module_dc_options = module_add_config_option(module_dc_options, &module_num_dc_options, "", 0, NULL, NULL, 0); configfile = dotconf_create(configfilename, module_dc_options, 0, CASE_INSENSITIVE); if (configfile) { if (dotconf_command_loop(configfile) == 0) { DBG("Error reading config file\n"); module_close(); exit(1); } dotconf_cleanup(configfile); DBG("Configuration (pre) has been read from \"%s\"\n", configfilename); g_free(configfilename); } else { DBG("Can't read specified config file!\n"); } } else { DBG("No config file specified, using defaults...\n"); } cmd_buf = NULL; n = 0; ret = spd_getline(&cmd_buf, &n, stdin); if (ret == -1) { DBG("Broken pipe when reading INIT, exiting... \n"); module_close(); exit(2); } if (strcmp(cmd_buf, "INIT\n")) { DBG("ERROR: Wrong communication from module client: didn't call INIT\n"); module_close(); exit(3); } ret = module_init(&status_info); if (status_info == NULL) { status_info = g_strdup("unknown, was not set by module"); } if (ret != 0) { printf("399-%s\n", status_info); printf("%s\n", "399 ERR CANT INIT MODULE"); g_free(status_info); module_close(); exit(1); } printf("299-%s\n", status_info); ret = printf("%s\n", "299 OK LOADED SUCCESSFULLY"); if (ret < 0) { DBG("Broken pipe, exiting...\n"); module_close(); exit(2); } fflush(stdout); g_free(status_info); g_free(cmd_buf); while (1) { cmd_buf = NULL; n = 0; ret = spd_getline(&cmd_buf, &n, stdin); if (ret == -1) { DBG("Broken pipe, exiting... \n"); ret = 2; break; } DBG("CMD: <%s>", cmd_buf); PROCESS_CMD(SPEAK, do_speak) else PROCESS_CMD(SOUND_ICON, do_sound_icon) else PROCESS_CMD(CHAR, do_char) else PROCESS_CMD(KEY, do_key) else PROCESS_CMD_NRP(STOP, do_stop) else PROCESS_CMD_NRP(PAUSE, do_pause) else PROCESS_CMD(LIST VOICES, do_list_voices) else PROCESS_CMD(SET, do_set) else PROCESS_CMD(AUDIO, do_audio) else PROCESS_CMD(LOGLEVEL, do_loglevel) else PROCESS_CMD_W_ARGS(DEBUG, do_debug) else if (!strcmp(cmd_buf, "QUIT\n")) { do_quit(); exit(0); } else { printf("300 ERR UNKNOWN COMMAND\n"); fflush(stdout); } g_free(cmd_buf); } module_close(); exit(ret); } #undef PROCESS_CMD speech-dispatcher-0.9.1/src/modules/spd_audio.h0000644000175000017500000000244713406252572016431 00000000000000 /* * spd_audio.h -- The SPD Audio Library Header * * Copyright (C) 2004 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: spd_audio.h,v 1.21 2008-10-15 17:28:17 hanke Exp $ */ #ifndef __SPD_AUDIO_H #define __SPD_AUDIO_H #include #define SPD_AUDIO_LIB_PREFIX "spd_" AudioID *spd_audio_open(char *name, void **pars, char **error); int spd_audio_play(AudioID * id, AudioTrack track, AudioFormat format); int spd_audio_stop(AudioID * id); int spd_audio_close(AudioID * id); int spd_audio_set_volume(AudioID * id, int volume); void spd_audio_set_loglevel(AudioID * id, int level); char const *spd_audio_get_playcmd(AudioID * id); #endif /* ifndef #__SPD_AUDIO_H */ speech-dispatcher-0.9.1/src/modules/spd_audio.c0000644000175000017500000002121613406252565016421 00000000000000 /* * spd_audio.c -- Spd Audio Output Library * * Copyright (C) 2004, 2006 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: spd_audio.c,v 1.21 2008-06-09 10:29:12 hanke Exp $ */ /* * spd_audio is a simple realtime audio output library with the capability of * playing 8 or 16 bit data, immediate stop and synchronization. This library * currently provides OSS, NAS, ALSA and PulseAudio backend. The available backends are * specified at compile-time using the directives WITH_OSS, WITH_NAS, WITH_ALSA, * WITH_PULSE, WITH_LIBAO but the user program is allowed to switch between them at run-time. */ #ifdef HAVE_CONFIG_H #include #endif #include "spd_audio.h" #include #include #include #include #include #include #include #include #include #include #include static int spd_audio_log_level; static lt_dlhandle lt_h; /* Dynamically load a library with RTLD_GLOBAL set. This is needed when a dynamically-loaded library has its own plugins that call into the parent library. Most of the credit for this function goes to Gary Vaughan. */ static lt_dlhandle my_dlopenextglobal(const char *filename) { lt_dlhandle handle = NULL; lt_dladvise advise; if (lt_dladvise_init(&advise)) return handle; if (!lt_dladvise_ext(&advise) && !lt_dladvise_global(&advise)) handle = lt_dlopenadvise(filename, advise); lt_dladvise_destroy(&advise); return handle; } /* Open the audio device. Arguments: type -- The requested device. Currently AudioOSS or AudioNAS. pars -- and array of pointers to parameters to pass to the device backend, terminated by a NULL pointer. See the source/documentation of each specific backend. error -- a pointer to the string where error description is stored in case of failure (returned AudioID == NULL). Otherwise will contain NULL. Return value: Newly allocated AudioID structure that can be passed to all other spd_audio functions, or NULL in case of failure. */ AudioID *spd_audio_open(char *name, void **pars, char **error) { AudioID *id; spd_audio_plugin_t const *p; spd_audio_plugin_t *(*fn) (void); gchar *libname; int ret; /* now check whether dynamic plugin is available */ ret = lt_dlinit(); if (ret != 0) { *error = (char *)g_strdup_printf("lt_dlinit() failed"); return (AudioID *) NULL; } ret = lt_dlsetsearchpath(PLUGIN_DIR); if (ret != 0) { *error = (char *)g_strdup_printf("lt_dlsetsearchpath() failed"); return (AudioID *) NULL; } libname = g_strdup_printf(SPD_AUDIO_LIB_PREFIX "%s", name); lt_h = my_dlopenextglobal(libname); g_free(libname); if (NULL == lt_h) { *error = (char *)g_strdup_printf("Cannot open plugin %s. error: %s", name, lt_dlerror()); return (AudioID *) NULL; } fn = lt_dlsym(lt_h, SPD_AUDIO_PLUGIN_ENTRY_STR); if (NULL == fn) { *error = (char *)g_strdup_printf("Cannot find symbol %s", SPD_AUDIO_PLUGIN_ENTRY_STR); return (AudioID *) NULL; } p = fn(); if (p == NULL || p->name == NULL) { *error = (char *)g_strdup_printf("plugin %s not found", name); return (AudioID *) NULL; } id = p->open(pars); if (id == NULL) { *error = (char *)g_strdup_printf("Couldn't open %s plugin", name); return (AudioID *) NULL; } id->function = p; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) id->format = SPD_AUDIO_BE; #else id->format = SPD_AUDIO_LE; #endif *error = NULL; return id; } /* Play a track on the audio device (blocking). Arguments: id -- the AudioID* of the device returned by spd_audio_open track -- a track to play (see spd_audio.h) Return value: 0 if everything is ok, a non-zero value in case of failure. See the particular backend documentation or source for the meaning of these non-zero values. Comment: spd_audio_play() is a blocking function. It returns exactly when the given track stopped playing. However, it's possible to safely interrupt it using spd_audio_stop() described below. (spd_audio_stop() needs to be called from another thread, obviously.) */ int spd_audio_play(AudioID * id, AudioTrack track, AudioFormat format) { int ret; if (id && id->function->play) { /* Only perform byte swapping if the driver in use has given us audio in an endian format other than what the running CPU supports. */ if (format != id->format) { unsigned char *out_ptr, *out_end, c; out_ptr = (unsigned char *)track.samples; out_end = out_ptr + track.num_samples * 2 * track.num_channels; while (out_ptr < out_end) { c = out_ptr[0]; out_ptr[0] = out_ptr[1]; out_ptr[1] = c; out_ptr += 2; } } ret = id->function->play(id, track); } else { fprintf(stderr, "Play not supported on this device\n"); return -1; } return ret; } /* Stop playing the current track on device id Arguments: id -- the AudioID* of the device returned by spd_audio_open Return value: 0 if everything is ok, a non-zero value in case of failure. See the particular backend documentation or source for the meaning of these non-zero values. Comment: spd_audio_stop() safely interrupts spd_audio_play() when called from another thread. It shouldn't cause any clicks or unwanted effects in the sound output. It's safe to call spd_audio_stop() even if the device isn't playing any track. In that case, it does nothing. However, there is a danger when using spd_audio_stop(). Since you must obviously do it from another thread than where spd_audio_play is running, you must make yourself sure that the device is still open and the id you pass it is valid and will be valid until spd_audio_stop returns. In other words, you should use some mutex or other synchronization device to be sure spd_audio_close isn't called before or during spd_audio_stop execution. */ int spd_audio_stop(AudioID * id) { int ret; if (id && id->function->stop) { ret = id->function->stop(id); } else { fprintf(stderr, "Stop not supported on this device\n"); return -1; } return ret; } /* Close the audio device id Arguments: id -- the AudioID* of the device returned by spd_audio_open Return value: 0 if everything is ok, a non-zero value in case of failure. Comments: Please make sure no other spd_audio function with this device id is running in another threads. See spd_audio_stop() for detailed description of possible problems. */ int spd_audio_close(AudioID * id) { int ret = 0; if (id && id->function->close) { ret = (id->function->close(id)); } if (NULL != lt_h) { lt_dlclose(lt_h); lt_h = NULL; lt_dlexit(); } return ret; } /* Set volume for playing tracks on the device id Arguments: id -- the AudioID* of the device returned by spd_audio_open volume -- a value in the range <-100:100> where -100 means the least volume (probably silence), 0 the default volume and +100 the highest volume possible to make on that device for a single flow (i.e. not using mixer). Return value: 0 if everything is ok, a non-zero value in case of failure. See the particular backend documentation or source for the meaning of these non-zero values. Comments: In case of /dev/dsp, it's not possible to set volume for the particular flow. For that reason, the value 0 means the volume the track was recorded on and each smaller value means less volume (since this works by deviding the samples in the track by a constant). */ int spd_audio_set_volume(AudioID * id, int volume) { if ((volume > 100) || (volume < -100)) { fprintf(stderr, "Requested volume out of range"); return -1; } if (id == NULL) { fprintf(stderr, "audio id is NULL in spd_audio_set_volume\n"); return -1; } id->volume = volume; return 0; } void spd_audio_set_loglevel(AudioID * id, int level) { if (level) { spd_audio_log_level = level; if (id != 0 && id->function != 0) id->function->set_loglevel(level); } } char const *spd_audio_get_playcmd(AudioID * id) { if (id != 0 && id->function != 0) { return id->function->get_playcmd(); } return NULL; } speech-dispatcher-0.9.1/src/modules/baratinoo_compat.h0000644000175000017500000001446013406252413017773 00000000000000/* * baratinoo.h - Shim for Baratinoo (VoxyGen) * to be able to build the Baratinoo module without the Baratinoo SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include typedef enum { BARATINOO_ALL_PARSING, /* Proprietary parsing and XML parsing both activated */ BARATINOO_NO_PARSING, /* No parsing at all */ BARATINOO_PROPRIETARY_PARSING, /* Proprietary parsing only */ BARATINOO_XML_PARSING /* XML parsing only */ } BARATINOO_PARSING; typedef enum { /* Enum changed in 8.4. */ /* BARATINOO_UTF8 is defined dynamically below, the 2 values below are * just here to be excessively rigorous and make sure possible values are * included in the enumeration */ BARATINOO_UTF8__V8_1 = 11, BARATINOO_UTF8__V8_4 = 13, } BARATINOO_TEXT_ENCODING; typedef enum { BARATINOO_MARKER_EVENT, BARATINOO_WAITMARKER_EVENT, } BARATINOO_EVENT_TYPE; typedef enum { BARATINOO_UNINITIALIZED, BARATINOO_INITIALIZED, BARATINOO_READY, BARATINOO_RUNNING, BARATINOO_EVENT, BARATINOO_INPUT_ERROR, BARATINOO_ENGINE_ERROR } BARATINOOC_STATE; typedef enum { BARATINOO_INIT_OK, BARATINOO_INIT_ERROR } BARATINOO_INIT_RETURN; typedef enum { BARATINOO_TRACE_ERROR, BARATINOO_TRACE_INIT, BARATINOO_TRACE_WARNING, BARATINOO_TRACE_INFO, BARATINOO_TRACE_DEBUG } BaratinooTraceLevel; typedef void (*BaratinooTraceCB)(BaratinooTraceLevel level, int engineNumber, const char *source, const void *privatedata, const char *format, va_list args); typedef void* BCengine; typedef void* BCinputTextBuffer; typedef void* BCoutputSignalBuffer; typedef struct { int major; int minor; /* we don't care about possible extras */ } BaratinooVersionStruct; typedef struct { BARATINOO_EVENT_TYPE type; float timeStamp; /* millisecond unit */ unsigned long byteStamp; /* byte unit */ unsigned long sampleStamp; /* sample unit */ union { struct { const char *name; } marker; struct { const char *name; float duration; /* millisecond unit */ unsigned int samples; /* sample unit */ } waitMarker; struct { /* UTF-8 encoding */ const char *tts; const char *input; } word; struct { /* UTF-8 encoding */ const char *tts; const char *input; } punctuation; struct { /* UTF-8 encoding */ const char *input; } separator; struct { const char *symbol; float duration; /* millisecond unit */ unsigned int samples; /* sample unit */ } phoneme; /* viseme field is 8.4 and later, but doesn't affect union size */ struct { const char *name; const char *language; } newVoice; struct { int type; int size; const char *datas; } raw; } data; } BaratinooEvent; typedef struct { const char *name; const char *language; const char *iso639; const char *iso3166; const char *variant; const char *accent; const char *gender; const char *version; const char *modules; int age; int expire_days; } BaratinooVoiceInfo__V8_1; typedef struct { const char *name; const char *language; const char *iso639; const char *iso3166; const char *variant; const char *accent; const char *gender; const char *version; const char *speech_modes; const char *modules; int age; int expire_days; } BaratinooVoiceInfo__V8_4; /* we use the biggest as default impl as we have to allocate it on the stack */ typedef BaratinooVoiceInfo__V8_4 BaratinooVoiceInfo; /* lib and version */ extern BARATINOO_INIT_RETURN BCinitlib(BaratinooTraceCB traceCB); extern void BCterminatelib(void); extern const char *BCgetBaratinooVersion(void); extern const BaratinooVersionStruct *BCgetBaratinooVersionStruct(void); /* engine */ extern BCengine BCnew(const void *privatedata); extern void BCinit(BCengine engine, const char *config); extern void BCdelete(BCengine engine); extern BARATINOOC_STATE BCgetState(BCengine engine); extern BARATINOOC_STATE BCprocessLoop(BCengine engine, int count); extern BARATINOOC_STATE BCpurge(BCengine engine); extern void BCsetWantedEvent(BCengine engine, BARATINOO_EVENT_TYPE type); extern BaratinooEvent BCgetEvent(BCengine engine); extern int BCgetNumberOfVoices(BCengine engine); extern BaratinooVoiceInfo BCgetVoiceInfo(BCengine engine,int voiceNumber); /* I/O */ typedef enum { BARATINOO_PCM = 0, } BARATINOO_SIGNAL_CODING; extern BCinputTextBuffer BCinputTextBufferNew(BARATINOO_PARSING parsing, BARATINOO_TEXT_ENCODING encoding, int voiceIndex, char *voiceModules); extern void BCinputTextBufferDelete(BCinputTextBuffer inputTextBuffer); extern int BCinputTextBufferInit(BCinputTextBuffer inputTextBuffer, const char *text); extern BARATINOOC_STATE BCinputTextBufferSetInEngine(BCinputTextBuffer inputTextBuffer, BCengine engine); extern BCoutputSignalBuffer BCoutputSignalBufferNew(BARATINOO_SIGNAL_CODING coding, int frequency); extern void BCoutputSignalBufferDelete(BCoutputSignalBuffer outputSignalBuffer); extern void BCoutputTextBufferSetInEngine(BCoutputSignalBuffer outputSignalBuffer, BCengine engine); extern int BCoutputSignalBufferIsError(BCoutputSignalBuffer outputSignalBuffer); extern char * BCoutputSignalBufferGetSignalBuffer(BCoutputSignalBuffer outputSignalBuffer); extern int BCoutputSignalBufferGetSignalLength(BCoutputSignalBuffer outputSignalBuffer); extern void BCoutputSignalBufferResetSignal(BCoutputSignalBuffer outputSignalBuffer); speech-dispatcher-0.9.1/src/modules/baratinoo.c0000644000175000017500000012043613455123146016430 00000000000000/* * baratinoo.c - Speech Dispatcher backend for Baratinoo (VoxyGen) * * Copyright (C) 2016 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * Input and output choices. * * - The input is sent to the engine through a BCinputTextBuffer. There is * a single one of those at any given time, and it is filled in * module_speak() and consumed in the synthesis thread. * * This doesn't use an input callback generating a continuous flow (and * blocking waiting for more data) even though it would be a fairly nice * design and would allow not to set speech attributes like volume, pitch and * rate as often. This is because the Baratinoo engine has 2 limitations on * the input callback: * * * It consumes everything (or at least a lot) up until the callbacks * reports the input end by returning 0. Alternatively one could use the * \flush command followed by a newline, so this is not really limiting. * * * More problematic, as the buffer callback is expected to feed a single * input, calling BCpurge() (for handling stop events) unregisters it, * requiring to re-add it afterward. This renders the continuous flow a * lot less useful, as speech attributes like volume, pitch and rate would * have to be set again. * * - The output uses the signal buffer instead of callback. * The output callback sends sound to the output module phonem by * phonem, which cause noise parasits with ALSA due to a reset of * parameters for each sound call. */ #ifdef HAVE_CONFIG_H #include #endif #include #ifdef BARATINOO_ABI_IS_STABLE_ENOUGH_FOR_ME /* See below why this is problematic. It can however be useful to get the * compiler help to check compatibility */ # define BARATINOO_C_API # include "baratinoo.h" # include "baratinooio.h" #define VOICE_INFO_MEMBER(member_type, struct_p, member) \ (((BaratinooVoiceInfo *)(struct_p))->member) #else /*------------------------------ Baratinoo API ------------------------------*/ /* * This file does NOT include baratinoo.h and baratinooio.h on purpose. * The reason is that Baratinoo does not provide ABI stability, and various * things change in minor versions. This is a problem for this module that * would like to support several versions at once. * * To work around this, we re-define all the API we need from the Baratinoo * headers, and patch compatibility possibly dynamically. * * This has to be done with *EXTREME CARE* not to slip off face-first into the * wall. What we keep is the lowest common denominator between the supported * versions, and for the incompatible bits we use dynamic mapping and offsets. * * Currently supported versions: * - 8.1 * - 8.4 * * To add a new version, you need to: * - First, check the diff between the oldest supported version and the new * version. Diffing against the newest supported version can be handy but * is not necessarily enough. * - Once the incompatibilities are identified and they affect us, amend the * code as necessary, keeping in mind to support older versions. You'll * have to add a new `BV_` constant for the new version, and make sure * everything that uses these constants handles the new value. * - What to look for: * - Members of structures that changed offsed (reordered, changed type, etc.) * - Enumeration values that changed value (order changed, previous member * getting a different default value, etc.) * - Union that changed size. * - Function arguments that changed type or order. * - Update get_baratinoo_supported_version() to return the appropriate * constant in the appropriate situation. If the new version did not break * compatibility with an already supported version, you might just return * the constant for that other version. * * GOTCHAS * - do NOT access BaratinooVoiceInfo members directly, always use * VOICE_INFO_MEMBER(type, struct_p, member) * - Make sure the structures allocated on the stack are large enough for all * versions. */ #include "baratinoo_compat.h" /* Dynamic compatibility part */ #include typedef enum { BV_UNSUPPORTED = -1, BV_8_1, BV_8_4, N_SUPPORTED_BARATINOO_VERSIONS } SupportedBaratinooVersion; /* BARATINOO_UTF8 */ static const BARATINOO_TEXT_ENCODING bv_BARATINOO_UTF8[N_SUPPORTED_BARATINOO_VERSIONS] = { [BV_8_1] = BARATINOO_UTF8__V8_1, [BV_8_4] = BARATINOO_UTF8__V8_4, }; #define BARATINOO_UTF8 (bv_BARATINOO_UTF8[baratinoo_engine.supported_version]) /* BaratinooVoiceInfo */ enum { VI_name, VI_language, VI_iso639, VI_iso3166, VI_gender, VI_age, N_VI_MEMBERS }; static const size_t bv_VoiceInfo_offsets[N_SUPPORTED_BARATINOO_VERSIONS][N_VI_MEMBERS] = { #define BVIF_MEMBER_DECL(struct, member) [VI_##member] = G_STRUCT_OFFSET(struct, member) [BV_8_1] = { BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_1, name), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_1, language), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_1, iso639), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_1, iso3166), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_1, gender), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_1, age), }, [BV_8_4] = { BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_4, name), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_4, language), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_4, iso639), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_4, iso3166), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_4, gender), BVIF_MEMBER_DECL(BaratinooVoiceInfo__V8_4, age), }, #undef BVIF_MEMBER_DECL }; #define VOICE_INFO_MEMBER(member_type, struct_p, member) \ G_STRUCT_MEMBER(member_type, struct_p, bv_VoiceInfo_offsets[baratinoo_engine.supported_version][VI_##member]) #endif /* ! BARATINOO_ABI_IS_STABLE_ENOUGH_FOR_ME */ /*------------------------ Speech-Dispatcher module ------------------------*/ #include "spd_audio.h" #include #include "module_utils.h" #define MODULE_NAME "baratinoo" #define DBG_MODNAME "Baratinoo: " #define MODULE_VERSION "0.1" #define DEBUG_MODULE 1 DECLARE_DEBUG(); typedef struct { /* Thread primitives */ pthread_t thread; sem_t semaphore; #ifndef BARATINOO_ABI_IS_STABLE_ENOUGH_FOR_ME SupportedBaratinooVersion supported_version; #endif BCengine engine; /* The buffer consumed by the TTS engine. It is NULL when the TTS * thread is ready to accept new input. Otherwise, the thread is in * the process of synthesizing speech. */ BCinputTextBuffer buffer; /* The output signal */ BCoutputSignalBuffer output_signal; SPDVoice **voice_list; /* settings */ int voice; /* request flags */ gboolean pause_requested; gboolean stop_requested; gboolean close_requested; SPDMarks marks; } Engine; /* engine and state */ static Engine baratinoo_engine = { .engine = NULL, .buffer = NULL, .output_signal = NULL, .voice_list = NULL, .voice = 0, .pause_requested = FALSE, .stop_requested = FALSE, .close_requested = FALSE }; /* Internal functions prototypes */ static void *_baratinoo_speak(void *); static SPDVoice **baratinoo_list_voices(BCengine *engine); /* Parameters */ static void baratinoo_set_voice_type(SPDVoiceType voice); static void baratinoo_set_language(char *lang); static void baratinoo_set_synthesis_voice(char *synthesis_voice); /* Engine callbacks */ static void baratinoo_trace_cb(BaratinooTraceLevel level, int engine_num, const char *source, const void *data, const char *format, va_list args); static int baratinoo_output_signal(void *privateData, const void *address, int length); /* SSML conversion functions */ static void append_ssml_as_proprietary(const Engine *engine, GString *buf, const char *data, gsize size); /* Module configuration options */ MOD_OPTION_1_STR(BaratinooConfigPath); MOD_OPTION_1_INT(BaratinooSampleRate); MOD_OPTION_1_INT(BaratinooMinRate); MOD_OPTION_1_INT(BaratinooNormalRate); MOD_OPTION_1_INT(BaratinooMaxRate); MOD_OPTION_1_STR(BaratinooPunctuationList); MOD_OPTION_1_STR(BaratinooIntonationList); MOD_OPTION_1_STR(BaratinooNoIntonationList); /* Public functions */ int module_load(void) { const char *conf_env; char *default_config = NULL; INIT_SETTINGS_TABLES(); REGISTER_DEBUG(); /* BaratinooConfigPath default value comes from the environment or * user XDG configuration location */ conf_env = getenv("BARATINOO_CONFIG_PATH"); if (conf_env && conf_env[0] != '\0') { default_config = g_strdup(conf_env); } else { default_config = g_build_filename(g_get_user_config_dir(), "baratinoo.cfg", NULL); } MOD_OPTION_1_STR_REG(BaratinooConfigPath, default_config); g_free(default_config); /* Sample rate. 16000Hz is the voices default, not requiring resampling */ MOD_OPTION_1_INT_REG(BaratinooSampleRate, 16000); /* Speech rate */ MOD_OPTION_1_INT_REG(BaratinooMinRate, -100); MOD_OPTION_1_INT_REG(BaratinooNormalRate, 0); MOD_OPTION_1_INT_REG(BaratinooMaxRate, 100); /* Punctuation */ MOD_OPTION_1_STR_REG(BaratinooPunctuationList, "@/+-_"); MOD_OPTION_1_STR_REG(BaratinooIntonationList, "?!;:,."); MOD_OPTION_1_STR_REG(BaratinooNoIntonationList, ""); return 0; } #ifndef BARATINOO_ABI_IS_STABLE_ENOUGH_FOR_ME static SupportedBaratinooVersion get_baratinoo_supported_version(void) { const BaratinooVersionStruct *version = BCgetBaratinooVersionStruct(); switch (version->major) { case 8: switch (version->minor) { case 1: return BV_8_1; case 4: return BV_8_4; } break; } return BV_UNSUPPORTED; } #endif int module_init(char **status_info) { Engine *engine = &baratinoo_engine; int ret; BARATINOOC_STATE state; DBG(DBG_MODNAME "Module init"); INIT_INDEX_MARKING(); DBG(DBG_MODNAME "BaratinooPunctuationList = %s", BaratinooPunctuationList); DBG(DBG_MODNAME "BaratinooIntonationList = %s", BaratinooIntonationList); DBG(DBG_MODNAME "BaratinooNoIntonationList = %s", BaratinooNoIntonationList); *status_info = NULL; engine->pause_requested = FALSE; engine->stop_requested = FALSE; engine->close_requested = FALSE; /* Init Baratinoo */ if (BCinitlib(baratinoo_trace_cb) != BARATINOO_INIT_OK) { DBG(DBG_MODNAME "Failed to initialize library"); *status_info = g_strdup("Failed to initialize Baratinoo. " "Make sure your installation is " "properly set up."); return -1; } DBG(DBG_MODNAME "Using Baratinoo %s", BCgetBaratinooVersion()); #ifndef BARATINOO_ABI_IS_STABLE_ENOUGH_FOR_ME engine->supported_version = get_baratinoo_supported_version(); if (engine->supported_version == BV_UNSUPPORTED) { DBG(DBG_MODNAME "Unsupported library version"); *status_info = g_strdup("Unsupported Baratinoo engine version."); return -1; } DBG(DBG_MODNAME "Using Baratinoo compatibility level %d", engine->supported_version); #endif engine->engine = BCnew(NULL); if (!engine->engine) { DBG(DBG_MODNAME "Failed to allocate engine"); *status_info = g_strdup("Failed to create Baratinoo engine."); return -1; } BCinit(engine->engine, BaratinooConfigPath); state = BCgetState(engine->engine); if (state != BARATINOO_INITIALIZED) { DBG(DBG_MODNAME "Failed to initialize engine"); *status_info = g_strdup("Failed to initialize Baratinoo engine. " "Make sure your setup is OK."); return -1; } /* Find voices */ engine->voice_list = baratinoo_list_voices(engine->engine); if (!engine->voice_list) { DBG(DBG_MODNAME "No voice available"); *status_info = g_strdup("No voice found. Make sure your setup " "includes at least one voice."); return -1; } /* Setup output (audio) signal handling */ DBG(DBG_MODNAME "Using PCM output at %dHz", BaratinooSampleRate); engine->output_signal = BCoutputSignalBufferNew(BARATINOO_PCM, BaratinooSampleRate); if (!engine->output_signal) { DBG(DBG_MODNAME "Cannot allocate BCoutputSignalBufferNew"); return -1; } if (BCgetState(engine->engine) != BARATINOO_INITIALIZED) { DBG(DBG_MODNAME "Failed to initialize output signal handler"); *status_info = g_strdup("Failed to initialize Baratinoo output " "signal handler. Is the configured " "sample rate correct?"); return -1; } BCoutputTextBufferSetInEngine(engine->output_signal, engine->engine); BCsetWantedEvent(engine->engine, BARATINOO_MARKER_EVENT); /* Setup TTS thread */ sem_init(&engine->semaphore, 0, 0); DBG(DBG_MODNAME "creating new thread for baratinoo_speak"); ret = pthread_create(&engine->thread, NULL, _baratinoo_speak, engine); if (ret != 0) { DBG(DBG_MODNAME "thread creation failed"); *status_info = g_strdup("The module couldn't initialize threads. " "This could be either an internal problem or an " "architecture problem. If you are sure your architecture " "supports threads, please report a bug."); return -1; } module_marks_init(&engine->marks); DBG(DBG_MODNAME "Initialization successfully."); *status_info = g_strdup("Baratinoo initialized successfully."); return 0; } SPDVoice **module_list_voices(void) { Engine *engine = &baratinoo_engine; return engine->voice_list; } int module_speak(gchar *data, size_t bytes, SPDMessageType msgtype) { Engine *engine = &baratinoo_engine; GString *buffer = NULL; int rate; DBG(DBG_MODNAME "Speech requested"); assert(msg_settings.rate >= -100 && msg_settings.rate <= +100); assert(msg_settings.pitch >= -100 && msg_settings.pitch <= +100); assert(msg_settings.pitch_range >= -100 && msg_settings.pitch_range <= +100); assert(msg_settings.volume >= -100 && msg_settings.volume <= +100); if (engine->buffer != NULL) { DBG(DBG_MODNAME "WARNING: module_speak() called during speech"); return 0; } engine->pause_requested = FALSE; engine->stop_requested = FALSE; /* select voice following parameters. we don't use tags for this as * we need to do some computation on our end anyway and need pass an * ID when creating the buffer too */ /* NOTE: these functions access the engine, which wouldn't be safe if * we didn't know that the thread is sleeping. But we do know it * is, as @c Engine::buffer is NULL */ UPDATE_STRING_PARAMETER(voice.language, baratinoo_set_language); UPDATE_PARAMETER(voice_type, baratinoo_set_voice_type); UPDATE_STRING_PARAMETER(voice.name, baratinoo_set_synthesis_voice); engine->buffer = BCinputTextBufferNew(BARATINOO_PROPRIETARY_PARSING, BARATINOO_UTF8, engine->voice, 0); if (!engine->buffer) { DBG(DBG_MODNAME "Failed to allocate input buffer"); goto err; } buffer = g_string_new(NULL); /* Apply speech parameters */ if (msg_settings.rate < 0) rate = BaratinooNormalRate + (BaratinooNormalRate - BaratinooMinRate) * msg_settings.rate / 100; else rate = BaratinooNormalRate + (BaratinooMaxRate - BaratinooNormalRate) * msg_settings.rate / 100; if (rate != 0) { g_string_append_printf(buffer, "\\rate{%+d%%}", rate); } if (msg_settings.pitch != 0 || msg_settings.pitch_range != 0) { g_string_append_printf(buffer, "\\pitch{%+d%% %+d%%}", msg_settings.pitch, msg_settings.pitch_range); } if (msg_settings.volume != 0) { g_string_append_printf(buffer, "\\volume{%+d%%}", msg_settings.volume); } switch (msgtype) { case SPD_MSGTYPE_SPELL: /* FIXME: use \spell one day? */ case SPD_MSGTYPE_CHAR: g_string_append(buffer, "\\sayas<{characters}"); g_string_append_len(buffer, data, bytes); g_string_append(buffer, "\\sayas>{}"); break; default: /* FIXME: */ case SPD_MSGTYPE_TEXT: append_ssml_as_proprietary(engine, buffer, data, bytes); break; } DBG(DBG_MODNAME "SSML input: %s", data); DBG(DBG_MODNAME "Sending buffer: %s", buffer->str); if (!BCinputTextBufferInit(engine->buffer, buffer->str)) { DBG(DBG_MODNAME "Failed to initialize input buffer"); goto err; } g_string_free(buffer, TRUE); sem_post(&engine->semaphore); DBG(DBG_MODNAME "leaving module_speak() normally"); return bytes; err: if (buffer) g_string_free(buffer, TRUE); if (engine->buffer) { BCinputTextBufferDelete(engine->buffer); engine->buffer = NULL; } return 0; } int module_stop(void) { Engine *engine = &baratinoo_engine; DBG(DBG_MODNAME "Stop requested"); engine->stop_requested = TRUE; module_marks_stop(&engine->marks); if (module_audio_id) { DBG(DBG_MODNAME "Stopping audio currently playing."); if (spd_audio_stop(module_audio_id) != 0) DBG(DBG_MODNAME "spd_audio_stop() returned non-zero value."); } return 0; } size_t module_pause(void) { Engine *engine = &baratinoo_engine; DBG(DBG_MODNAME "Pause requested"); engine->pause_requested = TRUE; module_marks_stop(&engine->marks); return 0; } int module_close(void) { Engine *engine = &baratinoo_engine; DBG(DBG_MODNAME "close()"); DBG(DBG_MODNAME "Terminating threads"); /* Politely ask the thread to terminate */ engine->stop_requested = TRUE; engine->close_requested = TRUE; module_marks_stop(&engine->marks); sem_post(&engine->semaphore); /* ...and give it a chance to actually quit. */ g_usleep(25000); /* Make sure the thread has really exited */ pthread_cancel(engine->thread); DBG(DBG_MODNAME "Joining threads."); if (pthread_join(engine->thread, NULL) != 0) DBG(DBG_MODNAME "Failed to join threads."); sem_destroy(&engine->semaphore); /* destroy voice list */ if (engine->voice_list != NULL) { int i; for (i = 0; engine->voice_list[i] != NULL; i++) { g_free(engine->voice_list[i]->name); g_free(engine->voice_list[i]->language); g_free(engine->voice_list[i]->variant); g_free(engine->voice_list[i]); } g_free(engine->voice_list); engine->voice_list = NULL; } /* destroy output signal */ BCoutputSignalBufferDelete(engine->output_signal); engine->output_signal = NULL; /* destroy engine */ if (engine->engine) { BCdelete(engine->engine); engine->engine = NULL; } /* uninitialize */ BCterminatelib(); module_marks_clear(&engine->marks); DBG(DBG_MODNAME "Module closed."); return 0; } /* Internal functions */ /** * @brief Lists voices in SPD format * @param engine An engine. * @returns A NULL-terminated list of @c SPDVoice, or NULL if no voice found. */ static SPDVoice **baratinoo_list_voices(BCengine *engine) { SPDVoice **voices; int n_voices; int i; n_voices = BCgetNumberOfVoices(engine); if (n_voices < 1) return NULL; voices = g_malloc_n(n_voices + 1, sizeof *voices); DBG(DBG_MODNAME "Got %d available voices:", n_voices); for (i = 0; i < n_voices; i++) { SPDVoice *voice; const char *language; const char *dash; BaratinooVoiceInfo voice_info_DO_NO_ACCESS_DIRECTLY = BCgetVoiceInfo(engine, i); void *voice_info = &voice_info_DO_NO_ACCESS_DIRECTLY; DBG(DBG_MODNAME "\tVoice #%d: name=%s, language=%s, gender=%s", i, VOICE_INFO_MEMBER(char *, voice_info, name), VOICE_INFO_MEMBER(char *, voice_info, language), VOICE_INFO_MEMBER(char *, voice_info, gender)); voice = g_malloc0(sizeof *voice); voice->name = g_strdup(VOICE_INFO_MEMBER(char *, voice_info, name)); language = VOICE_INFO_MEMBER(char *, voice_info, language); dash = strchr(language, '-'); if (dash) { voice->language = g_strndup(language, dash - language); voice->variant = g_ascii_strdown(dash + 1, -1); } else { voice->language = g_strdup(language); } voices[i] = voice; } voices[i] = NULL; return voices; } /** * @brief Internal TTS thread. * @param data An Engine structure. * @returns NULL. * * The TTS thread. It waits on @c Engine::semaphore to consume input data * from @c Engine::buffer. * * @see Engine::pause_requested * @see Engine::stop_requested * @see Engine::close_requested */ static void *_baratinoo_speak(void *data) { Engine *engine = data; BARATINOOC_STATE state = BARATINOO_READY; set_speaking_thread_parameters(); while (!engine->close_requested) { sem_wait(&engine->semaphore); DBG(DBG_MODNAME "Semaphore on"); engine->stop_requested = FALSE; if (!engine->buffer) continue; state = BCinputTextBufferSetInEngine(engine->buffer, engine->engine); if (state != BARATINOO_READY) { DBG(DBG_MODNAME "Failed to set input buffer"); continue; } module_report_event_begin(); while (1) { if (engine->stop_requested || engine->close_requested) { DBG(DBG_MODNAME "Stop in child, terminating"); BCinputTextBufferDelete(engine->buffer); engine->buffer = NULL; module_report_event_stop(); break; } do { state = BCprocessLoop(engine->engine, -1); if (state == BARATINOO_EVENT) { BaratinooEvent event = BCgetEvent(engine->engine); if (event.type == BARATINOO_MARKER_EVENT) { DBG(DBG_MODNAME "Reached mark '%s' at sample %lu", event.data.marker.name, event.sampleStamp); /* TODO: re-enable marks once audio glitches of module_tts_output are fixed */ /* module_marks_add(&engine->marks, event.sampleStamp, event.data.marker.name); */ /* if reached a spd mark and pausing requested, stop */ if (engine->pause_requested && g_str_has_prefix(event.data.marker.name, INDEX_MARK_BODY)) { DBG(DBG_MODNAME "Pausing in thread"); state = BCpurge(engine->engine); engine->pause_requested = FALSE; module_report_event_pause(); } } } else if (state == BARATINOO_INPUT_ERROR || state == BARATINOO_ENGINE_ERROR) { /* CANCEL would be better I guess, but * that's good enough */ module_report_event_stop(); } } while (state == BARATINOO_RUNNING || state == BARATINOO_EVENT); BCinputTextBufferDelete(engine->buffer); engine->buffer = NULL; DBG(DBG_MODNAME "Trying to synthesize text"); if (BCoutputSignalBufferIsError(engine->output_signal) || engine->close_requested) { DBG(DBG_MODNAME "Error with the output signal"); BCoutputSignalBufferResetSignal(engine->output_signal); module_report_event_stop(); } else { baratinoo_output_signal(engine, BCoutputSignalBufferGetSignalBuffer(engine->output_signal), BCoutputSignalBufferGetSignalLength(engine->output_signal)); BCoutputSignalBufferResetSignal(engine->output_signal); if (engine->stop_requested || engine->close_requested) { DBG(DBG_MODNAME "Stop in child, terminating"); module_report_event_stop(); } else { module_report_event_end(); } } break; } engine->stop_requested = FALSE; } DBG(DBG_MODNAME "leaving thread with state=%d", state); pthread_exit(NULL); } /* Voice selection */ /** * @brief Matches a Baratinoo voice info against a SPD language * @param info A voice info to match. * @param lang A SPD language to match against. * @returns The quality of the match: the higher the better. * * Gives a score to a voice based on its compatibility with @p lang. */ static int lang_match_level(const void *vinfo, const char *lang) { int level = 0; const char *language = VOICE_INFO_MEMBER(char *, vinfo, language); const char *iso639 = VOICE_INFO_MEMBER(char *, vinfo, iso639); const char *iso3166 = VOICE_INFO_MEMBER(char *, vinfo, iso3166); if (g_ascii_strcasecmp(lang, language) == 0) level += 10; else { gchar **a = g_strsplit_set(language, "-", 2); gchar **b = g_strsplit_set(lang, "-", 2); /* language */ if (g_ascii_strcasecmp(a[0], b[0]) == 0) level += 8; else if (g_ascii_strcasecmp(iso639, b[0]) == 0) level += 8; else if (g_ascii_strncasecmp(a[0], b[0], 2) == 0) level += 5; /* partial match */ /* region */ if (a[1] && b[1] && g_ascii_strcasecmp(a[1], b[1]) == 0) level += 2; else if (b[1] && g_ascii_strcasecmp(iso3166, b[1]) == 0) level += 2; else if (a[1] && b[1] && g_ascii_strncasecmp(a[1], b[1], 2) == 0) level += 1; /* partial match */ g_strfreev(a); g_strfreev(b); } DBG(DBG_MODNAME "lang_match_level({language=%s, iso639=%s, iso3166=%s}, lang=%s) = %d", language, iso639, iso3166, lang, level); return level; } /** * @brief Sort two Baratinoo voices by SPD criteria. * @param a A voice info. * @param b Another voice info. * @param lang A SPD language. * @param voice_code A SPD voice code. * @returns < 0 if @p a is best, > 0 if @p b is best, and 0 if they are equally * matching. Larger divergence from 0 means better match. */ static int sort_voice(const void *voice_a, const void *voice_b, const char *lang, SPDVoiceType voice_code) { int cmp = 0; const char *a_gender = VOICE_INFO_MEMBER(char *, voice_a, gender); const char *b_gender = VOICE_INFO_MEMBER(char *, voice_b, gender); int a_age = VOICE_INFO_MEMBER(int, voice_a, age); int b_age = VOICE_INFO_MEMBER(int, voice_b, age); cmp -= lang_match_level(voice_a, lang); cmp += lang_match_level(voice_b, lang); if (strcmp(a_gender, b_gender) != 0) { const char *gender; switch (voice_code) { default: case SPD_MALE1: case SPD_MALE2: case SPD_MALE3: case SPD_CHILD_MALE: gender = "male"; break; case SPD_FEMALE1: case SPD_FEMALE2: case SPD_FEMALE3: case SPD_CHILD_FEMALE: gender = "female"; break; } if (strcmp(gender, a_gender) == 0) cmp--; if (strcmp(gender, b_gender) == 0) cmp++; } switch (voice_code) { case SPD_CHILD_MALE: case SPD_CHILD_FEMALE: if (a_age && a_age <= 15) cmp--; if (b_age && b_age <= 15) cmp++; break; default: /* we expect mostly adult voices, so only compare if age is set */ if (a_age && b_age) { if (a_age > 15) cmp--; if (b_age > 15) cmp++; } break; } DBG(DBG_MODNAME "Comparing %s <> %s gives %d", VOICE_INFO_MEMBER(char*, voice_a, name), VOICE_INFO_MEMBER(char*, voice_b, name), cmp); return cmp; } /* Given a language code and SD voice code, gets the Baratinoo voice. */ static int baratinoo_find_voice(const Engine *engine, const char *lang, SPDVoiceType voice_code) { int i; int best_match = -1; int nth_match = 0; int offset = 0; /* nth voice we'd like */ BaratinooVoiceInfo best_info; DBG(DBG_MODNAME "baratinoo_find_voice(lang=%s, voice_code=%d)", lang, voice_code); switch (voice_code) { case SPD_MALE3: case SPD_FEMALE3: offset++; /* FALLTHRU */ case SPD_MALE2: case SPD_FEMALE2: offset++; /* FALLTHRU */ default: break; } for (i = 0; i < BCgetNumberOfVoices(engine->engine); i++) { if (i == 0) { best_match = i; best_info = BCgetVoiceInfo(engine->engine, i); nth_match++; } else { BaratinooVoiceInfo info = BCgetVoiceInfo(engine->engine, i); int cmp = sort_voice(&best_info, &info, lang, voice_code); if (cmp >= 0) { if (cmp > 0) nth_match = 0; if (nth_match <= offset) { best_match = i; best_info = info; } nth_match++; } } } return best_match; } /* Given a language code and SD voice code, sets the voice. */ static void baratinoo_set_language_and_voice(Engine *engine, const char *lang, SPDVoiceType voice_code) { int voice = baratinoo_find_voice(engine, lang, voice_code); if (voice < 0) { DBG(DBG_MODNAME "No voice match found, not changing voice."); } else { DBG(DBG_MODNAME "Best voice match is %d.", voice); engine->voice = voice; } } /* UPDATE_PARAMETER callback to set the voice type */ static void baratinoo_set_voice_type(SPDVoiceType voice) { Engine *engine = &baratinoo_engine; assert(msg_settings.voice.language); baratinoo_set_language_and_voice(engine, msg_settings.voice.language, voice); } /* UPDATE_PARAMETER callback to set the voice language */ static void baratinoo_set_language(char *lang) { Engine *engine = &baratinoo_engine; baratinoo_set_language_and_voice(engine, lang, msg_settings.voice_type); } /* UPDATE_PARAMETER callback to set the voice by name */ static void baratinoo_set_synthesis_voice(char *synthesis_voice) { Engine *engine = &baratinoo_engine; int i; if (synthesis_voice == NULL) return; for (i = 0; i < BCgetNumberOfVoices(engine->engine); i++) { BaratinooVoiceInfo info = BCgetVoiceInfo(engine->engine, i); if (g_ascii_strcasecmp(synthesis_voice, VOICE_INFO_MEMBER(char*, &info, name)) == 0) { engine->voice = i; return; } } DBG(DBG_MODNAME "Failed to set synthesis voice to '%s': not found.", synthesis_voice); } /* Engine callbacks */ /** * @brief Logs a message from Baratinoo * @param level Message importance. * @param engine_num ID of the engine that emitted the message, or 0 if it is a * library message. * @param source Message category. * @param data Private data, unused. * @param format printf-like @p format. * @param args arguments for @p format. */ static void baratinoo_trace_cb(BaratinooTraceLevel level, int engine_num, const char *source, const void *data, const char *format, va_list args) { const char *prefix = ""; if (!Debug) { switch (level) { case BARATINOO_TRACE_INIT: case BARATINOO_TRACE_INFO: case BARATINOO_TRACE_DEBUG: return; default: break; } } switch (level) { case BARATINOO_TRACE_ERROR: prefix = "ERROR"; break; case BARATINOO_TRACE_INIT: prefix = "INIT"; break; case BARATINOO_TRACE_WARNING: prefix = "WARNING"; break; case BARATINOO_TRACE_INFO: prefix = "INFO"; break; case BARATINOO_TRACE_DEBUG: prefix = "DEBUG"; break; } if (engine_num == 0) fprintf(stderr, "Baratinoo library: "); else fprintf(stderr, "Baratinoo engine #%d: ", engine_num); fprintf(stderr, "%s: %s ", prefix, source); vfprintf(stderr, format, args); fprintf(stderr, "\n"); } /** * @brief Output (sound) callback * @param private_data An Engine structure. * @param address Audio samples. * @param length Length of @p address, in bytes. * @returns Whether to break out of the process loop. * * Called by the engine during speech synthesis. * * @see BCprocessLoop() */ static int baratinoo_output_signal(void *private_data, const void *address, int length) { Engine *engine = private_data; AudioTrack track; #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) AudioFormat format = SPD_AUDIO_BE; #else AudioFormat format = SPD_AUDIO_LE; #endif /* If stop is requested during synthesis, abort here to stop speech as * early as possible, even if the engine didn't finish its cycle yet. */ if (engine->stop_requested) { DBG(DBG_MODNAME "Not playing message because it got stopped"); return engine->stop_requested; } /* We receive 16 bits PCM data */ track.num_samples = length / 2; /* 16 bits per sample = 2 bytes */ track.num_channels = 1; track.sample_rate = BaratinooSampleRate; track.bits = 16; track.samples = (short *) address; DBG(DBG_MODNAME "Playing part of the message"); if (module_tts_output_marks(track, format, &engine->marks) < 0) DBG(DBG_MODNAME "ERROR: failed to play the track"); module_marks_clear(&engine->marks); return engine->stop_requested; } /* SSML conversion functions */ typedef struct { const Engine *engine; GString *buffer; /* Voice ID stack for the current element */ int voice_stack[32]; unsigned int voice_stack_len; } SsmlPraserState; /* Adds a language change command for @p lang if appropriate */ static void ssml2baratinoo_push_lang(SsmlPraserState *state, const char *lang) { int voice; if (state->voice_stack_len > 0) voice = state->voice_stack[state->voice_stack_len - 1]; else voice = state->engine->voice; if (lang) { DBG(DBG_MODNAME "Processing xml:lang=\"%s\"", lang); int new_voice = baratinoo_find_voice(&baratinoo_engine, lang, msg_settings.voice_type); if (new_voice >= 0 && new_voice != voice) { g_string_append_printf(state->buffer, "\\vox{%d}", new_voice); voice = new_voice; } } if (state->voice_stack_len >= G_N_ELEMENTS(state->voice_stack)) { DBG(DBG_MODNAME "WARNING: voice stack exhausted, expect incorrect voices."); } else { state->voice_stack[state->voice_stack_len++] = voice; } } /* Pops a language pushed with @c ssml2baratinoo_push_lang() */ static void ssml2baratinoo_pop_lang(SsmlPraserState *state) { if (state->voice_stack_len > 0) { int cur_voice = state->voice_stack[--state->voice_stack_len]; if (state->voice_stack_len > 0) { int new_voice = state->voice_stack[state->voice_stack_len - 1]; if (new_voice != cur_voice) g_string_append_printf(state->buffer, "\\vox{%d}", new_voice); } } } /* locates a string in a NULL-terminated array of strings * Returns -1 if not found, the index otherwise. */ static int attribute_index(const char **names, const char *name) { int i; for (i = 0; names && names[i] != NULL; i++) { if (strcmp(names[i], name) == 0) return i; } return -1; } /* Markup element start callback */ static void ssml2baratinoo_start_element(GMarkupParseContext *ctx, const gchar *element, const gchar **attribute_names, const gchar **attribute_values, gpointer data, GError **error) { SsmlPraserState *state = data; int lang_id; /* handle voice changes */ lang_id = attribute_index(attribute_names, "xml:lang"); ssml2baratinoo_push_lang(state, lang_id < 0 ? NULL : attribute_values[lang_id]); /* handle elements */ if (strcmp(element, "mark") == 0) { int i = attribute_index(attribute_names, "name"); g_string_append_printf(state->buffer, "\\mark{%s}", i < 0 ? "" : attribute_values[i]); } else if (strcmp(element, "emphasis") == 0) { int i = attribute_index(attribute_names, "level"); g_string_append_printf(state->buffer, "\\emph<{%s}", i < 0 ? "" : attribute_values[i]); } else if (strcmp(element, "say-as") == 0) { int i_as = attribute_index(attribute_names, "interpret-as"); int i_fmt = attribute_index(attribute_names, "format"); int i_detail = attribute_index(attribute_names, "detail"); if (i_as < 0) { DBG(DBG_MODNAME "Missing required 'interpret-as' attribute of '' tag"); i_fmt = i_detail = -1; } else if (i_fmt < 0 && i_detail >= 0) { DBG(DBG_MODNAME "Ignoring 'detail' attribute of '' tag because it is " "not supported without a 'format' attribute"); i_detail = -1; } g_string_append_printf(state->buffer, "\\sayas<{%s %s %s}", i_as < 0 ? "" : attribute_values[i_as], i_fmt < 0 ? "" : attribute_values[i_fmt], i_detail < 0 ? "" : attribute_values[i_detail]); } else { /* ignore other elements */ /* TODO: handle more elements */ } } /* Markup element end callback */ static void ssml2baratinoo_end_element(GMarkupParseContext *ctx, const gchar *element, gpointer data, GError **error) { SsmlPraserState *state = data; if (strcmp(element, "emphasis") == 0) { g_string_append(state->buffer, "\\emph>{}"); } else if (strcmp(element, "say-as") == 0) { g_string_append(state->buffer, "\\sayas>{}"); } ssml2baratinoo_pop_lang(state); } /* Markup text node callback. * * This not only converts to the proprietary format (by escaping things that * would be interpreted by it), but also pre-processes the text for some * features that are missing from Baratinoo. * * - Punctuation speaking * * As the engine doesn't support speaking of the punctuation itself, we alter * the input to explicitly tell the engine to do it. It is kind of tricky, * because we want to keep the punctuation meaning of the characters, e.g. how * they affect speech as means of intonation and pauses. * * The approach here is that for every punctuation character included in the * selected mode (none/some/all), we wrap it in "\sayas<{characters}" markup * so that it is spoken by the engine. But in order to keep the punctuation * meaning of the character, in case it has some, we duplicate it outside the * markup with a heuristic on whether it will or not affect speech intonation * and pauses, and whether or not the engine would speak the character itself * already (as we definitely don't want to get duplicated speech for a * character). * This heuristic is as follows: * - If the character is listed in BaratinooIntonationList and the next * character is not punctuation or alphanumeric, duplicate the character. * - Always append a space after a duplicated character, hoping the engine * won't consider speaking it. * * This won't always give the same results as the engine would by itself, but * it isn't really possible as the engine behavior is language-dependent in a * non-obvious fashion. For example, a French voice will speak "1.2.3" as * "Un. Deux. Trois", while an English one will speak it as "One dot two dot * three": the dot here didn't have the same interpretation, and wasn't spoken * the same (once altering the voice, the other spoken plain and simple). * * However, the heuristic here should be highly unlikely to lead to duplicate * character speaking, and catch most of the intonation and pause cases. * * - Why is this done that way? * * Another, possibly more robust, approach could be using 2 passes in the * engine itself, and relying on events to get information on how the engine * interprets the input in the first (silent) pass, and alter it as needed for * a second (spoken) pass. This wouldn't guarantee the altered input would be * interpreted the same, but it would seem like a safe enough bet. * * However, the engine is too slow for this to be viable in a real-time * processing environment for anything but tiny input. Even about 25 lines of * IRC conversation can easily take several seconds to process in the first * pass (even without doing any actual pre-processing on our end), delaying * the actual speech by an unacceptable amount of time. * * Ideally, the engine will some day support speaking punctuation itself, and * this part of the pre-processing could be dropped. */ static void ssml2baratinoo_text(GMarkupParseContext *ctx, const gchar *text, gsize len, gpointer data, GError **error) { SsmlPraserState *state = data; const gchar *p; for (p = text; p < (text + len); p = g_utf8_next_char(p)) { if (*p == '\\') { /* escape the \ by appending a comment so it won't be * interpreted as a command */ g_string_append(state->buffer, "\\\\{}"); } else { gboolean say_as_char, do_not_say; gunichar ch = g_utf8_get_char(p); /* if punctuation mode is not NONE and the character * should be spoken, manually wrap it with \sayas */ say_as_char = ((msg_settings.punctuation_mode == SPD_PUNCT_SOME && g_utf8_strchr(BaratinooPunctuationList, -1, ch)) || (msg_settings.punctuation_mode == SPD_PUNCT_ALL && g_unichar_ispunct(ch))); do_not_say = ((msg_settings.punctuation_mode == SPD_PUNCT_NONE && g_utf8_strchr(BaratinooNoIntonationList, -1, ch))); if (say_as_char) g_string_append(state->buffer, "\\sayas<{characters}"); if (!do_not_say) g_string_append_unichar(state->buffer, ch); if (say_as_char) { g_string_append(state->buffer, "\\sayas>{}"); /* if the character should influence intonation, * add it back, but *only* if it wouldn't be spoken */ if (g_utf8_strchr(BaratinooIntonationList, -1, ch)) { const gchar *next = g_utf8_next_char(p); gunichar ch_next; if (next < text + len) ch_next = g_utf8_get_char(next); else ch_next = '\n'; if (!g_unichar_isalnum(ch_next) && !g_unichar_ispunct(ch_next)) { g_string_append_unichar(state->buffer, ch); /* Append an extra space to try and * make sure it's considered as * punctuation and isn't spoken. */ g_string_append_c(state->buffer, ' '); } } } } } } /** * @brief Converts SSML data to Baratinoo's proprietary format. * @param buf A buffer to write to. * @param data SSML data to convert. * @param size Length of @p data * * @warning Only a subset of the input SSML is currently translated, the rest * being discarded. */ static void append_ssml_as_proprietary(const Engine *engine, GString *buf, const char *data, gsize size) { /* FIXME: we could possibly use SSML mode, but the Baratinoo parser is * very strict and *requires* "xmlns", "version" and "lang" attributes * on the tag, which speech-dispatcher doesn't provide. * * Moreover, we need to add tags for volume/rate/pitch so we'd have to * amend the data anyway. */ static const GMarkupParser parser = { .start_element = ssml2baratinoo_start_element, .end_element = ssml2baratinoo_end_element, .text = ssml2baratinoo_text, }; SsmlPraserState state = { .engine = engine, .buffer = buf, .voice_stack_len = 0, }; GMarkupParseContext *ctx; GError *err = NULL; ctx = g_markup_parse_context_new(&parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &state, NULL); if (!g_markup_parse_context_parse(ctx, data, size, &err) || !g_markup_parse_context_end_parse(ctx, &err)) { DBG(DBG_MODNAME "Failed to convert SSML: %s", err->message); g_error_free(err); } g_markup_parse_context_free(ctx); } speech-dispatcher-0.9.1/src/modules/README0000644000175000017500000000136013406252376015164 00000000000000dummy-message.wav is Copyright (C) 2008 Brailcom, o.p.s and is licensed under the following terms: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (file COPYING in the root directory). You should have received a copy of the GNU General Public License along with this program. If not, see . speech-dispatcher-0.9.1/src/modules/Makefile.in0000644000175000017500000017305213465233610016354 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # # Copyright (C) 2002 - 2018 Brailcom, o.p.s. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ modulebin_PROGRAMS = sd_dummy$(EXEEXT) sd_generic$(EXEEXT) \ sd_festival$(EXEEXT) sd_cicero$(EXEEXT) $(am__EXEEXT_1) \ $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \ $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ $(am__EXEEXT_8) @flite_support_TRUE@am__append_1 = sd_flite @ibmtts_support_TRUE@am__append_2 = sd_ibmtts @ibmtts_shim_TRUE@@ibmtts_support_TRUE@am__append_3 = -L. @ibmtts_shim_TRUE@@ibmtts_support_TRUE@am__append_4 = $(EXTRA_sd_ibmtts_DEPENDENCIES) @espeak_support_TRUE@am__append_5 = sd_espeak @espeak_ng_support_TRUE@am__append_6 = sd_espeak-ng @ivona_support_TRUE@am__append_7 = sd_ivona @pico_support_TRUE@am__append_8 = sd_pico @baratinoo_support_TRUE@am__append_9 = sd_baratinoo @baratinoo_shim_TRUE@@baratinoo_support_TRUE@am__append_10 = -L. @baratinoo_shim_TRUE@@baratinoo_support_TRUE@am__append_11 = $(EXTRA_sd_baratinoo_DEPENDENCIES) @kali_support_TRUE@am__append_12 = sd_kali @kali_shim_TRUE@@kali_support_TRUE@am__append_13 = -L. @kali_shim_TRUE@@kali_support_TRUE@am__append_14 = -I$(srcdir)/kali_shim @kali_shim_TRUE@@kali_support_TRUE@am__append_15 = $(EXTRA_sd_kali_DEPENDENCIES) subdir = src/modules ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_snddata_DATA) \ $(am__noinst_HEADERS_DIST) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @flite_support_TRUE@am__EXEEXT_1 = sd_flite$(EXEEXT) @ibmtts_support_TRUE@am__EXEEXT_2 = sd_ibmtts$(EXEEXT) @espeak_support_TRUE@am__EXEEXT_3 = sd_espeak$(EXEEXT) @espeak_ng_support_TRUE@am__EXEEXT_4 = sd_espeak-ng$(EXEEXT) @ivona_support_TRUE@am__EXEEXT_5 = sd_ivona$(EXEEXT) @pico_support_TRUE@am__EXEEXT_6 = sd_pico$(EXEEXT) @baratinoo_support_TRUE@am__EXEEXT_7 = sd_baratinoo$(EXEEXT) @kali_support_TRUE@am__EXEEXT_8 = sd_kali$(EXEEXT) am__installdirs = "$(DESTDIR)$(modulebindir)" \ "$(DESTDIR)$(snddatadir)" PROGRAMS = $(modulebin_PROGRAMS) am__sd_baratinoo_SOURCES_DIST = baratinoo.c baratinoo_compat.h \ spd_audio.c spd_audio.h module_main.c module_utils.c \ module_utils.h am__objects_1 = spd_audio.$(OBJEXT) am__objects_2 = module_main.$(OBJEXT) module_utils.$(OBJEXT) @baratinoo_support_TRUE@am_sd_baratinoo_OBJECTS = baratinoo.$(OBJEXT) \ @baratinoo_support_TRUE@ $(am__objects_1) $(am__objects_2) sd_baratinoo_OBJECTS = $(am_sd_baratinoo_OBJECTS) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) @baratinoo_support_TRUE@sd_baratinoo_DEPENDENCIES = $(top_builddir)/src/common/libcommon.la \ @baratinoo_support_TRUE@ $(am__DEPENDENCIES_1) \ @baratinoo_support_TRUE@ $(am__DEPENDENCIES_2) \ @baratinoo_support_TRUE@ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_sd_cicero_OBJECTS = cicero.$(OBJEXT) $(am__objects_1) \ $(am__objects_2) sd_cicero_OBJECTS = $(am_sd_cicero_OBJECTS) sd_cicero_DEPENDENCIES = $(top_builddir)/src/common/libcommon.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am_sd_dummy_OBJECTS = dummy.$(OBJEXT) $(am__objects_1) \ $(am__objects_2) module_utils_addvoice.$(OBJEXT) sd_dummy_OBJECTS = $(am_sd_dummy_OBJECTS) sd_dummy_DEPENDENCIES = $(top_builddir)/src/common/libcommon.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am__sd_espeak_SOURCES_DIST = espeak.c spd_audio.c spd_audio.h \ module_main.c module_utils.c module_utils.h @espeak_support_TRUE@am_sd_espeak_OBJECTS = espeak.$(OBJEXT) \ @espeak_support_TRUE@ $(am__objects_1) $(am__objects_2) sd_espeak_OBJECTS = $(am_sd_espeak_OBJECTS) @espeak_support_TRUE@sd_espeak_DEPENDENCIES = \ @espeak_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @espeak_support_TRUE@ $(am__DEPENDENCIES_1) \ @espeak_support_TRUE@ $(am__DEPENDENCIES_1) \ @espeak_support_TRUE@ $(am__DEPENDENCIES_2) am__sd_espeak_ng_SOURCES_DIST = espeak-ng.c spd_audio.c spd_audio.h \ module_main.c module_utils.c module_utils.h am__objects_3 = sd_espeak_ng-spd_audio.$(OBJEXT) am__objects_4 = sd_espeak_ng-module_main.$(OBJEXT) \ sd_espeak_ng-module_utils.$(OBJEXT) @espeak_ng_support_TRUE@am_sd_espeak_ng_OBJECTS = \ @espeak_ng_support_TRUE@ sd_espeak_ng-espeak-ng.$(OBJEXT) \ @espeak_ng_support_TRUE@ $(am__objects_3) $(am__objects_4) sd_espeak_ng_OBJECTS = $(am_sd_espeak_ng_OBJECTS) @espeak_ng_support_TRUE@sd_espeak_ng_DEPENDENCIES = $(top_builddir)/src/common/libcommon.la \ @espeak_ng_support_TRUE@ $(am__DEPENDENCIES_1) \ @espeak_ng_support_TRUE@ $(am__DEPENDENCIES_1) \ @espeak_ng_support_TRUE@ $(am__DEPENDENCIES_1) \ @espeak_ng_support_TRUE@ $(am__DEPENDENCIES_2) sd_espeak_ng_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(sd_espeak_ng_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_sd_festival_OBJECTS = festival.$(OBJEXT) festival_client.$(OBJEXT) \ $(am__objects_1) $(am__objects_2) sd_festival_OBJECTS = $(am_sd_festival_OBJECTS) sd_festival_DEPENDENCIES = $(top_builddir)/src/common/libcommon.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_1) am__sd_flite_SOURCES_DIST = flite.c spd_audio.c spd_audio.h \ module_main.c module_utils.c module_utils.h @flite_support_TRUE@am_sd_flite_OBJECTS = flite.$(OBJEXT) \ @flite_support_TRUE@ $(am__objects_1) $(am__objects_2) sd_flite_OBJECTS = $(am_sd_flite_OBJECTS) @flite_support_TRUE@sd_flite_DEPENDENCIES = \ @flite_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @flite_support_TRUE@ $(am__DEPENDENCIES_1) \ @flite_support_TRUE@ $(am__DEPENDENCIES_1) \ @flite_support_TRUE@ $(am__DEPENDENCIES_1) \ @flite_support_TRUE@ $(am__DEPENDENCIES_2) am_sd_generic_OBJECTS = generic.$(OBJEXT) $(am__objects_1) \ $(am__objects_2) module_utils_addvoice.$(OBJEXT) sd_generic_OBJECTS = $(am_sd_generic_OBJECTS) sd_generic_DEPENDENCIES = $(top_builddir)/src/common/libcommon.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am__sd_ibmtts_SOURCES_DIST = ibmtts.c spd_audio.c spd_audio.h \ module_main.c module_utils.c module_utils.h \ module_utils_addvoice.c @ibmtts_support_TRUE@am_sd_ibmtts_OBJECTS = ibmtts.$(OBJEXT) \ @ibmtts_support_TRUE@ $(am__objects_1) $(am__objects_2) \ @ibmtts_support_TRUE@ module_utils_addvoice.$(OBJEXT) sd_ibmtts_OBJECTS = $(am_sd_ibmtts_OBJECTS) @ibmtts_support_TRUE@sd_ibmtts_DEPENDENCIES = \ @ibmtts_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @ibmtts_support_TRUE@ $(am__DEPENDENCIES_1) \ @ibmtts_support_TRUE@ $(am__DEPENDENCIES_2) \ @ibmtts_support_TRUE@ $(am__DEPENDENCIES_1) am__sd_ivona_SOURCES_DIST = ivona.c ivona_client.c ivona_client.h \ spd_audio.c spd_audio.h module_main.c module_utils.c \ module_utils.h @ivona_support_TRUE@am_sd_ivona_OBJECTS = ivona.$(OBJEXT) \ @ivona_support_TRUE@ ivona_client.$(OBJEXT) $(am__objects_1) \ @ivona_support_TRUE@ $(am__objects_2) sd_ivona_OBJECTS = $(am_sd_ivona_OBJECTS) @ivona_support_TRUE@sd_ivona_DEPENDENCIES = \ @ivona_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @ivona_support_TRUE@ $(am__DEPENDENCIES_1) \ @ivona_support_TRUE@ $(am__DEPENDENCIES_2) am__sd_kali_SOURCES_DIST = kali.cpp spd_audio.c spd_audio.h \ module_main.c module_utils.c module_utils.h am__objects_5 = sd_kali-spd_audio.$(OBJEXT) am__objects_6 = sd_kali-module_main.$(OBJEXT) \ sd_kali-module_utils.$(OBJEXT) @kali_support_TRUE@am_sd_kali_OBJECTS = sd_kali-kali.$(OBJEXT) \ @kali_support_TRUE@ $(am__objects_5) $(am__objects_6) sd_kali_OBJECTS = $(am_sd_kali_OBJECTS) @kali_support_TRUE@sd_kali_DEPENDENCIES = \ @kali_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @kali_support_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ @kali_support_TRUE@ $(am__DEPENDENCIES_1) am__sd_pico_SOURCES_DIST = pico.c spd_audio.c spd_audio.h \ module_main.c module_utils.c module_utils.h @pico_support_TRUE@am_sd_pico_OBJECTS = pico.$(OBJEXT) \ @pico_support_TRUE@ $(am__objects_1) $(am__objects_2) sd_pico_OBJECTS = $(am_sd_pico_OBJECTS) @pico_support_TRUE@sd_pico_DEPENDENCIES = \ @pico_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @pico_support_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/baratinoo.Po ./$(DEPDIR)/cicero.Po \ ./$(DEPDIR)/dummy.Po ./$(DEPDIR)/espeak.Po \ ./$(DEPDIR)/festival.Po ./$(DEPDIR)/festival_client.Po \ ./$(DEPDIR)/flite.Po ./$(DEPDIR)/generic.Po \ ./$(DEPDIR)/ibmtts.Po ./$(DEPDIR)/ivona.Po \ ./$(DEPDIR)/ivona_client.Po ./$(DEPDIR)/module_main.Po \ ./$(DEPDIR)/module_utils.Po \ ./$(DEPDIR)/module_utils_addvoice.Po ./$(DEPDIR)/pico.Po \ ./$(DEPDIR)/sd_espeak_ng-espeak-ng.Po \ ./$(DEPDIR)/sd_espeak_ng-module_main.Po \ ./$(DEPDIR)/sd_espeak_ng-module_utils.Po \ ./$(DEPDIR)/sd_espeak_ng-spd_audio.Po \ ./$(DEPDIR)/sd_kali-kali.Po ./$(DEPDIR)/sd_kali-module_main.Po \ ./$(DEPDIR)/sd_kali-module_utils.Po \ ./$(DEPDIR)/sd_kali-spd_audio.Po ./$(DEPDIR)/spd_audio.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(sd_baratinoo_SOURCES) $(sd_cicero_SOURCES) \ $(sd_dummy_SOURCES) $(sd_espeak_SOURCES) \ $(sd_espeak_ng_SOURCES) $(sd_festival_SOURCES) \ $(sd_flite_SOURCES) $(sd_generic_SOURCES) $(sd_ibmtts_SOURCES) \ $(sd_ivona_SOURCES) $(sd_kali_SOURCES) $(sd_pico_SOURCES) DIST_SOURCES = $(am__sd_baratinoo_SOURCES_DIST) $(sd_cicero_SOURCES) \ $(sd_dummy_SOURCES) $(am__sd_espeak_SOURCES_DIST) \ $(am__sd_espeak_ng_SOURCES_DIST) $(sd_festival_SOURCES) \ $(am__sd_flite_SOURCES_DIST) $(sd_generic_SOURCES) \ $(am__sd_ibmtts_SOURCES_DIST) $(am__sd_ivona_SOURCES_DIST) \ $(am__sd_kali_SOURCES_DIST) $(am__sd_pico_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_snddata_DATA) am__noinst_HEADERS_DIST = kali_shim/kali/Kali/kali.h HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOTCONF_CFLAGS = @DOTCONF_CFLAGS@ DOTCONF_LIBS = @DOTCONF_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ERROR_CFLAGS = @ERROR_CFLAGS@ ESPEAK_NG_CFLAGS = @ESPEAK_NG_CFLAGS@ ESPEAK_NG_LIBS = @ESPEAK_NG_LIBS@ EXEEXT = @EXEEXT@ EXTRA_ESPEAK_LIBS = @EXTRA_ESPEAK_LIBS@ EXTRA_SOCKET_LIBS = @EXTRA_SOCKET_LIBS@ FGREP = @FGREP@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GMODULE_CFLAGS = @GMODULE_CFLAGS@ GMODULE_LIBS = @GMODULE_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBAO_CFLAGS = @LIBAO_CFLAGS@ LIBAO_LIBS = @LIBAO_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_SPD_AGE = @LIB_SPD_AGE@ LIB_SPD_CURRENT = @LIB_SPD_CURRENT@ LIB_SPD_REVISION = @LIB_SPD_REVISION@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAJOR_VERSION = @MAJOR_VERSION@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MICRO_VERSION = @MICRO_VERSION@ MINOR_VERSION = @MINOR_VERSION@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NAS_LIBS = @NAS_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PULSE_CFLAGS = @PULSE_CFLAGS@ PULSE_LIBS = @PULSE_LIBS@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RDYNAMIC = @RDYNAMIC@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ audio_dlopen_modules = @audio_dlopen_modules@ audiodir = @audiodir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ clientconfdir = @clientconfdir@ clientconforigdir = @clientconforigdir@ datadir = @datadir@ datarootdir = @datarootdir@ default_audio_method = @default_audio_method@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ flite_basic = @flite_basic@ flite_kal = @flite_kal@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ ibmtts_include = @ibmtts_include@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedatadir = @localedatadir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ modulebindir = @modulebindir@ moduleconfdir = @moduleconfdir@ moduleconforigdir = @moduleconforigdir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ snddatadir = @snddatadir@ spdconfdir = @spdconfdir@ spdconforigdir = @spdconforigdir@ spddesktopconforigdir = @spddesktopconforigdir@ spdincludedir = @spdincludedir@ spdlibdir = @spdlibdir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = baratinoo_shim.c README.baratinoo kali_Kali_shim.cpp \ kali_KGlobal_shim.cpp kali_KTrans_shim.cpp \ kali_KParle_shim.cpp kali_KAnalyse_shim.cpp ibmtts_shim.c \ eci.h mluvitko.c CLEANFILES = $(am__append_4) $(am__append_11) $(am__append_15) inc_local = -I$(top_srcdir)/include audio_SOURCES = spd_audio.c spd_audio.h common_SOURCES = module_main.c module_utils.c module_utils.h common_LDADD = $(SNDFILE_LIBS) $(DOTCONF_LIBS) $(GLIB_LIBS) $(GTHREAD_LIBS) AM_CFLAGS = $(ERROR_CFLAGS) AM_CPPFLAGS = $(inc_local) -DDATADIR=\"$(snddatadir)\" -D_GNU_SOURCE \ -DPLUGIN_DIR="\"$(audiodir)\"" \ $(DOTCONF_CFLAGS) $(GLIB_CFLAGS) $(GTHREAD_CFLAGS) \ $(ibmtts_include) $(SNDFILE_CFLAGS) sd_dummy_SOURCES = dummy.c $(audio_SOURCES) $(common_SOURCES) \ module_utils_addvoice.c sd_dummy_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) dist_snddata_DATA = dummy-message.wav sd_festival_SOURCES = festival.c festival_client.c festival_client.h \ $(audio_SOURCES) $(common_SOURCES) sd_festival_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) $(EXTRA_SOCKET_LIBS) sd_generic_SOURCES = generic.c $(audio_SOURCES) $(common_SOURCES) \ module_utils_addvoice.c sd_generic_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) sd_cicero_SOURCES = cicero.c $(audio_SOURCES) $(common_SOURCES) sd_cicero_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) @flite_support_TRUE@sd_flite_SOURCES = flite.c $(audio_SOURCES) $(common_SOURCES) @flite_support_TRUE@sd_flite_LDADD = $(top_builddir)/src/common/libcommon.la \ @flite_support_TRUE@ $(audio_dlopen_modules) \ @flite_support_TRUE@ $(flite_kal) $(flite_basic) \ @flite_support_TRUE@ $(common_LDADD) @ibmtts_support_TRUE@sd_ibmtts_SOURCES = ibmtts.c $(audio_SOURCES) $(common_SOURCES) \ @ibmtts_support_TRUE@ module_utils_addvoice.c @ibmtts_support_TRUE@sd_ibmtts_LDADD = \ @ibmtts_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @ibmtts_support_TRUE@ $(audio_dlopen_modules) -libmeci \ @ibmtts_support_TRUE@ $(common_LDADD) $(am__append_3) @ibmtts_shim_TRUE@@ibmtts_support_TRUE@EXTRA_sd_ibmtts_DEPENDENCIES = libibmeci.so @espeak_support_TRUE@sd_espeak_SOURCES = espeak.c $(audio_SOURCES) $(common_SOURCES) @espeak_support_TRUE@sd_espeak_LDADD = $(top_builddir)/src/common/libcommon.la \ @espeak_support_TRUE@ $(audio_dlopen_modules) \ @espeak_support_TRUE@ -lespeak $(EXTRA_ESPEAK_LIBS) \ @espeak_support_TRUE@ $(common_LDADD) @espeak_ng_support_TRUE@sd_espeak_ng_SOURCES = espeak-ng.c $(audio_SOURCES) $(common_SOURCES) @espeak_ng_support_TRUE@sd_espeak_ng_CFLAGS = -DESPEAK_NG_INCLUDE $(ESPEAK_NG_CFLAGS) @espeak_ng_support_TRUE@sd_espeak_ng_LDADD = $(top_builddir)/src/common/libcommon.la \ @espeak_ng_support_TRUE@ $(audio_dlopen_modules) \ @espeak_ng_support_TRUE@ $(ESPEAK_NG_LIBS) $(EXTRA_ESPEAK_LIBS) \ @espeak_ng_support_TRUE@ $(common_LDADD) @ivona_support_TRUE@sd_ivona_SOURCES = ivona.c ivona_client.c ivona_client.h $(audio_SOURCES) \ @ivona_support_TRUE@ $(common_SOURCES) @ivona_support_TRUE@sd_ivona_LDADD = $(top_builddir)/src/common/libcommon.la \ @ivona_support_TRUE@ $(audio_dlopen_modules) \ @ivona_support_TRUE@ -ldumbtts \ @ivona_support_TRUE@ $(common_LDADD) @pico_support_TRUE@sd_pico_SOURCES = pico.c $(audio_SOURCES) $(common_SOURCES) @pico_support_TRUE@sd_pico_LDADD = $(top_builddir)/src/common/libcommon.la \ @pico_support_TRUE@ $(audio_dlopen_modules) -lttspico \ @pico_support_TRUE@ $(common_LDADD) @baratinoo_support_TRUE@sd_baratinoo_SOURCES = baratinoo.c baratinoo_compat.h $(audio_SOURCES) $(common_SOURCES) @baratinoo_support_TRUE@sd_baratinoo_LDADD = $(top_builddir)/src/common/libcommon.la \ @baratinoo_support_TRUE@ $(audio_dlopen_modules) -lbaratinoo \ @baratinoo_support_TRUE@ -lpthread -ldl $(common_LDADD) \ @baratinoo_support_TRUE@ $(am__append_10) @baratinoo_shim_TRUE@@baratinoo_support_TRUE@EXTRA_sd_baratinoo_DEPENDENCIES = libbaratinoo.so @kali_support_TRUE@KALI_DIR = /usr/lib/kali @kali_support_TRUE@sd_kali_SOURCES = kali.cpp $(audio_SOURCES) $(common_SOURCES) @kali_support_TRUE@sd_kali_LDADD = \ @kali_support_TRUE@ $(top_builddir)/src/common/libcommon.la \ @kali_support_TRUE@ $(audio_dlopen_modules) -lKali -lKGlobal \ @kali_support_TRUE@ -lKTrans -lKParle -lKAnalyse \ @kali_support_TRUE@ $(common_LDADD) $(am__append_13) @kali_support_TRUE@sd_kali_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_14) @kali_shim_TRUE@@kali_support_TRUE@noinst_HEADERS = kali_shim/kali/Kali/kali.h @kali_shim_TRUE@@kali_support_TRUE@EXTRA_sd_kali_DEPENDENCIES = libKali.so libKGlobal.so libKTrans.so libKParle.so libKAnalyse.so all: all-am .SUFFIXES: .SUFFIXES: .c .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/modules/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/modules/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-modulebinPROGRAMS: $(modulebin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(modulebin_PROGRAMS)'; test -n "$(modulebindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(modulebindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(modulebindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(modulebindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(modulebindir)$$dir" || exit $$?; \ } \ ; done uninstall-modulebinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(modulebin_PROGRAMS)'; test -n "$(modulebindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(modulebindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(modulebindir)" && rm -f $$files clean-modulebinPROGRAMS: @list='$(modulebin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list sd_baratinoo$(EXEEXT): $(sd_baratinoo_OBJECTS) $(sd_baratinoo_DEPENDENCIES) $(EXTRA_sd_baratinoo_DEPENDENCIES) @rm -f sd_baratinoo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_baratinoo_OBJECTS) $(sd_baratinoo_LDADD) $(LIBS) sd_cicero$(EXEEXT): $(sd_cicero_OBJECTS) $(sd_cicero_DEPENDENCIES) $(EXTRA_sd_cicero_DEPENDENCIES) @rm -f sd_cicero$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_cicero_OBJECTS) $(sd_cicero_LDADD) $(LIBS) sd_dummy$(EXEEXT): $(sd_dummy_OBJECTS) $(sd_dummy_DEPENDENCIES) $(EXTRA_sd_dummy_DEPENDENCIES) @rm -f sd_dummy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_dummy_OBJECTS) $(sd_dummy_LDADD) $(LIBS) sd_espeak$(EXEEXT): $(sd_espeak_OBJECTS) $(sd_espeak_DEPENDENCIES) $(EXTRA_sd_espeak_DEPENDENCIES) @rm -f sd_espeak$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_espeak_OBJECTS) $(sd_espeak_LDADD) $(LIBS) sd_espeak-ng$(EXEEXT): $(sd_espeak_ng_OBJECTS) $(sd_espeak_ng_DEPENDENCIES) $(EXTRA_sd_espeak_ng_DEPENDENCIES) @rm -f sd_espeak-ng$(EXEEXT) $(AM_V_CCLD)$(sd_espeak_ng_LINK) $(sd_espeak_ng_OBJECTS) $(sd_espeak_ng_LDADD) $(LIBS) sd_festival$(EXEEXT): $(sd_festival_OBJECTS) $(sd_festival_DEPENDENCIES) $(EXTRA_sd_festival_DEPENDENCIES) @rm -f sd_festival$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_festival_OBJECTS) $(sd_festival_LDADD) $(LIBS) sd_flite$(EXEEXT): $(sd_flite_OBJECTS) $(sd_flite_DEPENDENCIES) $(EXTRA_sd_flite_DEPENDENCIES) @rm -f sd_flite$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_flite_OBJECTS) $(sd_flite_LDADD) $(LIBS) sd_generic$(EXEEXT): $(sd_generic_OBJECTS) $(sd_generic_DEPENDENCIES) $(EXTRA_sd_generic_DEPENDENCIES) @rm -f sd_generic$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_generic_OBJECTS) $(sd_generic_LDADD) $(LIBS) sd_ibmtts$(EXEEXT): $(sd_ibmtts_OBJECTS) $(sd_ibmtts_DEPENDENCIES) $(EXTRA_sd_ibmtts_DEPENDENCIES) @rm -f sd_ibmtts$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_ibmtts_OBJECTS) $(sd_ibmtts_LDADD) $(LIBS) sd_ivona$(EXEEXT): $(sd_ivona_OBJECTS) $(sd_ivona_DEPENDENCIES) $(EXTRA_sd_ivona_DEPENDENCIES) @rm -f sd_ivona$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_ivona_OBJECTS) $(sd_ivona_LDADD) $(LIBS) sd_kali$(EXEEXT): $(sd_kali_OBJECTS) $(sd_kali_DEPENDENCIES) $(EXTRA_sd_kali_DEPENDENCIES) @rm -f sd_kali$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(sd_kali_OBJECTS) $(sd_kali_LDADD) $(LIBS) sd_pico$(EXEEXT): $(sd_pico_OBJECTS) $(sd_pico_DEPENDENCIES) $(EXTRA_sd_pico_DEPENDENCIES) @rm -f sd_pico$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sd_pico_OBJECTS) $(sd_pico_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/baratinoo.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cicero.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/espeak.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/festival.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/festival_client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flite.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ibmtts.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ivona.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ivona_client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module_utils.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module_utils_addvoice.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pico.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_espeak_ng-espeak-ng.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_espeak_ng-module_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_espeak_ng-module_utils.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_espeak_ng-spd_audio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_kali-kali.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_kali-module_main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_kali-module_utils.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sd_kali-spd_audio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spd_audio.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< sd_espeak_ng-espeak-ng.o: espeak-ng.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-espeak-ng.o -MD -MP -MF $(DEPDIR)/sd_espeak_ng-espeak-ng.Tpo -c -o sd_espeak_ng-espeak-ng.o `test -f 'espeak-ng.c' || echo '$(srcdir)/'`espeak-ng.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-espeak-ng.Tpo $(DEPDIR)/sd_espeak_ng-espeak-ng.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='espeak-ng.c' object='sd_espeak_ng-espeak-ng.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-espeak-ng.o `test -f 'espeak-ng.c' || echo '$(srcdir)/'`espeak-ng.c sd_espeak_ng-espeak-ng.obj: espeak-ng.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-espeak-ng.obj -MD -MP -MF $(DEPDIR)/sd_espeak_ng-espeak-ng.Tpo -c -o sd_espeak_ng-espeak-ng.obj `if test -f 'espeak-ng.c'; then $(CYGPATH_W) 'espeak-ng.c'; else $(CYGPATH_W) '$(srcdir)/espeak-ng.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-espeak-ng.Tpo $(DEPDIR)/sd_espeak_ng-espeak-ng.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='espeak-ng.c' object='sd_espeak_ng-espeak-ng.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-espeak-ng.obj `if test -f 'espeak-ng.c'; then $(CYGPATH_W) 'espeak-ng.c'; else $(CYGPATH_W) '$(srcdir)/espeak-ng.c'; fi` sd_espeak_ng-spd_audio.o: spd_audio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-spd_audio.o -MD -MP -MF $(DEPDIR)/sd_espeak_ng-spd_audio.Tpo -c -o sd_espeak_ng-spd_audio.o `test -f 'spd_audio.c' || echo '$(srcdir)/'`spd_audio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-spd_audio.Tpo $(DEPDIR)/sd_espeak_ng-spd_audio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spd_audio.c' object='sd_espeak_ng-spd_audio.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-spd_audio.o `test -f 'spd_audio.c' || echo '$(srcdir)/'`spd_audio.c sd_espeak_ng-spd_audio.obj: spd_audio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-spd_audio.obj -MD -MP -MF $(DEPDIR)/sd_espeak_ng-spd_audio.Tpo -c -o sd_espeak_ng-spd_audio.obj `if test -f 'spd_audio.c'; then $(CYGPATH_W) 'spd_audio.c'; else $(CYGPATH_W) '$(srcdir)/spd_audio.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-spd_audio.Tpo $(DEPDIR)/sd_espeak_ng-spd_audio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spd_audio.c' object='sd_espeak_ng-spd_audio.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-spd_audio.obj `if test -f 'spd_audio.c'; then $(CYGPATH_W) 'spd_audio.c'; else $(CYGPATH_W) '$(srcdir)/spd_audio.c'; fi` sd_espeak_ng-module_main.o: module_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-module_main.o -MD -MP -MF $(DEPDIR)/sd_espeak_ng-module_main.Tpo -c -o sd_espeak_ng-module_main.o `test -f 'module_main.c' || echo '$(srcdir)/'`module_main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-module_main.Tpo $(DEPDIR)/sd_espeak_ng-module_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_main.c' object='sd_espeak_ng-module_main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-module_main.o `test -f 'module_main.c' || echo '$(srcdir)/'`module_main.c sd_espeak_ng-module_main.obj: module_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-module_main.obj -MD -MP -MF $(DEPDIR)/sd_espeak_ng-module_main.Tpo -c -o sd_espeak_ng-module_main.obj `if test -f 'module_main.c'; then $(CYGPATH_W) 'module_main.c'; else $(CYGPATH_W) '$(srcdir)/module_main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-module_main.Tpo $(DEPDIR)/sd_espeak_ng-module_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_main.c' object='sd_espeak_ng-module_main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-module_main.obj `if test -f 'module_main.c'; then $(CYGPATH_W) 'module_main.c'; else $(CYGPATH_W) '$(srcdir)/module_main.c'; fi` sd_espeak_ng-module_utils.o: module_utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-module_utils.o -MD -MP -MF $(DEPDIR)/sd_espeak_ng-module_utils.Tpo -c -o sd_espeak_ng-module_utils.o `test -f 'module_utils.c' || echo '$(srcdir)/'`module_utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-module_utils.Tpo $(DEPDIR)/sd_espeak_ng-module_utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_utils.c' object='sd_espeak_ng-module_utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-module_utils.o `test -f 'module_utils.c' || echo '$(srcdir)/'`module_utils.c sd_espeak_ng-module_utils.obj: module_utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -MT sd_espeak_ng-module_utils.obj -MD -MP -MF $(DEPDIR)/sd_espeak_ng-module_utils.Tpo -c -o sd_espeak_ng-module_utils.obj `if test -f 'module_utils.c'; then $(CYGPATH_W) 'module_utils.c'; else $(CYGPATH_W) '$(srcdir)/module_utils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_espeak_ng-module_utils.Tpo $(DEPDIR)/sd_espeak_ng-module_utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_utils.c' object='sd_espeak_ng-module_utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sd_espeak_ng_CFLAGS) $(CFLAGS) -c -o sd_espeak_ng-module_utils.obj `if test -f 'module_utils.c'; then $(CYGPATH_W) 'module_utils.c'; else $(CYGPATH_W) '$(srcdir)/module_utils.c'; fi` sd_kali-spd_audio.o: spd_audio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sd_kali-spd_audio.o -MD -MP -MF $(DEPDIR)/sd_kali-spd_audio.Tpo -c -o sd_kali-spd_audio.o `test -f 'spd_audio.c' || echo '$(srcdir)/'`spd_audio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-spd_audio.Tpo $(DEPDIR)/sd_kali-spd_audio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spd_audio.c' object='sd_kali-spd_audio.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sd_kali-spd_audio.o `test -f 'spd_audio.c' || echo '$(srcdir)/'`spd_audio.c sd_kali-spd_audio.obj: spd_audio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sd_kali-spd_audio.obj -MD -MP -MF $(DEPDIR)/sd_kali-spd_audio.Tpo -c -o sd_kali-spd_audio.obj `if test -f 'spd_audio.c'; then $(CYGPATH_W) 'spd_audio.c'; else $(CYGPATH_W) '$(srcdir)/spd_audio.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-spd_audio.Tpo $(DEPDIR)/sd_kali-spd_audio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spd_audio.c' object='sd_kali-spd_audio.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sd_kali-spd_audio.obj `if test -f 'spd_audio.c'; then $(CYGPATH_W) 'spd_audio.c'; else $(CYGPATH_W) '$(srcdir)/spd_audio.c'; fi` sd_kali-module_main.o: module_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sd_kali-module_main.o -MD -MP -MF $(DEPDIR)/sd_kali-module_main.Tpo -c -o sd_kali-module_main.o `test -f 'module_main.c' || echo '$(srcdir)/'`module_main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-module_main.Tpo $(DEPDIR)/sd_kali-module_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_main.c' object='sd_kali-module_main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sd_kali-module_main.o `test -f 'module_main.c' || echo '$(srcdir)/'`module_main.c sd_kali-module_main.obj: module_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sd_kali-module_main.obj -MD -MP -MF $(DEPDIR)/sd_kali-module_main.Tpo -c -o sd_kali-module_main.obj `if test -f 'module_main.c'; then $(CYGPATH_W) 'module_main.c'; else $(CYGPATH_W) '$(srcdir)/module_main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-module_main.Tpo $(DEPDIR)/sd_kali-module_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_main.c' object='sd_kali-module_main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sd_kali-module_main.obj `if test -f 'module_main.c'; then $(CYGPATH_W) 'module_main.c'; else $(CYGPATH_W) '$(srcdir)/module_main.c'; fi` sd_kali-module_utils.o: module_utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sd_kali-module_utils.o -MD -MP -MF $(DEPDIR)/sd_kali-module_utils.Tpo -c -o sd_kali-module_utils.o `test -f 'module_utils.c' || echo '$(srcdir)/'`module_utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-module_utils.Tpo $(DEPDIR)/sd_kali-module_utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_utils.c' object='sd_kali-module_utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sd_kali-module_utils.o `test -f 'module_utils.c' || echo '$(srcdir)/'`module_utils.c sd_kali-module_utils.obj: module_utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sd_kali-module_utils.obj -MD -MP -MF $(DEPDIR)/sd_kali-module_utils.Tpo -c -o sd_kali-module_utils.obj `if test -f 'module_utils.c'; then $(CYGPATH_W) 'module_utils.c'; else $(CYGPATH_W) '$(srcdir)/module_utils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-module_utils.Tpo $(DEPDIR)/sd_kali-module_utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='module_utils.c' object='sd_kali-module_utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sd_kali-module_utils.obj `if test -f 'module_utils.c'; then $(CYGPATH_W) 'module_utils.c'; else $(CYGPATH_W) '$(srcdir)/module_utils.c'; fi` .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< sd_kali-kali.o: kali.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sd_kali-kali.o -MD -MP -MF $(DEPDIR)/sd_kali-kali.Tpo -c -o sd_kali-kali.o `test -f 'kali.cpp' || echo '$(srcdir)/'`kali.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-kali.Tpo $(DEPDIR)/sd_kali-kali.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='kali.cpp' object='sd_kali-kali.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sd_kali-kali.o `test -f 'kali.cpp' || echo '$(srcdir)/'`kali.cpp sd_kali-kali.obj: kali.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sd_kali-kali.obj -MD -MP -MF $(DEPDIR)/sd_kali-kali.Tpo -c -o sd_kali-kali.obj `if test -f 'kali.cpp'; then $(CYGPATH_W) 'kali.cpp'; else $(CYGPATH_W) '$(srcdir)/kali.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sd_kali-kali.Tpo $(DEPDIR)/sd_kali-kali.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='kali.cpp' object='sd_kali-kali.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sd_kali_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sd_kali-kali.obj `if test -f 'kali.cpp'; then $(CYGPATH_W) 'kali.cpp'; else $(CYGPATH_W) '$(srcdir)/kali.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_snddataDATA: $(dist_snddata_DATA) @$(NORMAL_INSTALL) @list='$(dist_snddata_DATA)'; test -n "$(snddatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(snddatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(snddatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(snddatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(snddatadir)" || exit $$?; \ done uninstall-dist_snddataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_snddata_DATA)'; test -n "$(snddatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(snddatadir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(modulebindir)" "$(DESTDIR)$(snddatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-modulebinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/baratinoo.Po -rm -f ./$(DEPDIR)/cicero.Po -rm -f ./$(DEPDIR)/dummy.Po -rm -f ./$(DEPDIR)/espeak.Po -rm -f ./$(DEPDIR)/festival.Po -rm -f ./$(DEPDIR)/festival_client.Po -rm -f ./$(DEPDIR)/flite.Po -rm -f ./$(DEPDIR)/generic.Po -rm -f ./$(DEPDIR)/ibmtts.Po -rm -f ./$(DEPDIR)/ivona.Po -rm -f ./$(DEPDIR)/ivona_client.Po -rm -f ./$(DEPDIR)/module_main.Po -rm -f ./$(DEPDIR)/module_utils.Po -rm -f ./$(DEPDIR)/module_utils_addvoice.Po -rm -f ./$(DEPDIR)/pico.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-espeak-ng.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-module_main.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-module_utils.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-spd_audio.Po -rm -f ./$(DEPDIR)/sd_kali-kali.Po -rm -f ./$(DEPDIR)/sd_kali-module_main.Po -rm -f ./$(DEPDIR)/sd_kali-module_utils.Po -rm -f ./$(DEPDIR)/sd_kali-spd_audio.Po -rm -f ./$(DEPDIR)/spd_audio.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_snddataDATA install-modulebinPROGRAMS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/baratinoo.Po -rm -f ./$(DEPDIR)/cicero.Po -rm -f ./$(DEPDIR)/dummy.Po -rm -f ./$(DEPDIR)/espeak.Po -rm -f ./$(DEPDIR)/festival.Po -rm -f ./$(DEPDIR)/festival_client.Po -rm -f ./$(DEPDIR)/flite.Po -rm -f ./$(DEPDIR)/generic.Po -rm -f ./$(DEPDIR)/ibmtts.Po -rm -f ./$(DEPDIR)/ivona.Po -rm -f ./$(DEPDIR)/ivona_client.Po -rm -f ./$(DEPDIR)/module_main.Po -rm -f ./$(DEPDIR)/module_utils.Po -rm -f ./$(DEPDIR)/module_utils_addvoice.Po -rm -f ./$(DEPDIR)/pico.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-espeak-ng.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-module_main.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-module_utils.Po -rm -f ./$(DEPDIR)/sd_espeak_ng-spd_audio.Po -rm -f ./$(DEPDIR)/sd_kali-kali.Po -rm -f ./$(DEPDIR)/sd_kali-module_main.Po -rm -f ./$(DEPDIR)/sd_kali-module_utils.Po -rm -f ./$(DEPDIR)/sd_kali-spd_audio.Po -rm -f ./$(DEPDIR)/spd_audio.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_snddataDATA uninstall-modulebinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libtool clean-modulebinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_snddataDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-modulebinPROGRAMS install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-dist_snddataDATA \ uninstall-modulebinPROGRAMS .PRECIOUS: Makefile @ibmtts_shim_TRUE@@ibmtts_support_TRUE@libibmeci.so: $(srcdir)/ibmtts_shim.c @ibmtts_shim_TRUE@@ibmtts_support_TRUE@ $(CC) -fPIC -shared $< -o $@ @baratinoo_shim_TRUE@@baratinoo_support_TRUE@libbaratinoo.so: $(srcdir)/baratinoo_shim.c @baratinoo_shim_TRUE@@baratinoo_support_TRUE@ $(CC) -fPIC -shared $< -o $@ @kali_shim_TRUE@@kali_support_TRUE@lib%.so: $(srcdir)/kali_%_shim.cpp @kali_shim_TRUE@@kali_support_TRUE@ $(CXX) -fPIC -shared $< -o $@ -I$(srcdir)/kali_shim -include $(top_srcdir)/git.mk # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: speech-dispatcher-0.9.1/src/modules/dummy-message.wav0000644000175000017500000050007511447133620017600 00000000000000RIFF5€WAVEfmt @@data€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‰Ž’•—–••••–”“’‘ŒŒ‹Š‰ˆ‡‡††……„„„ƒƒ‚‚‚‚‚€€€€€€€€€€€‰‘’•˜–”””””‘ŒŠŠˆ†„€€€~€€‚‚‚€€€€€€€€€€€€€€€…˜˘žžŸ ¤Ľ›‘Ž‹‡€yy|}{yy{€‚€ƒ…†ƒ‚ƒƒ‚€~€€~~€€€€€€€€€”ލ˘ŠĽ§Ş›ˆ„†€yunp|~z}…‹‡„ˆ‰…‚~{}€}z{}„„ƒ‚€‚~€~‚œ°ĽŁŠŚŞŠ–†…†~xsow‚‚~ƒ‰ŽŒ……ˆ†zxy~}yzƒ…„‚‚†‡ƒ~€|{}€€€ťŠŠĽĽĽ‹v€ˆznpt€Œƒyˆ•‰‚…Š~qv€zx‚‹„{~……{yƒ~y}‚„‚ƒ†’¸­›ŠŚ›–‚mpzoepy‚ŽŒ‡‘š‘†ƒ~|}tmt|}~„ŠŽ‰ƒ„…}ywz~|z~ƒ……„‚…„‰Šľ Ł¨˘Ą–€}Š„xz|ƒˆ~„Š„€|‚‡~x}‚ƒ‚~}„‡}ƒ||‚ƒ€~~„~~‚ƒŸĽ¨ŤŠŞŠŒ‹†‚~}„ˆ†„‡‰Šˆƒƒ„‚}€~~~ƒ‚ƒ…„…„ƒ„„ƒ‚ƒ‚ƒ„‚€€€€€€~~~}~~~~~~~€~ƒƒ„…„„…„„ƒƒƒ„„‚€~|}}{zzzz|}~~€€€‚€‚€‚‚€€€€€€€€€€€€€‚€‚‚‚€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€‚€€‚€~€€€€€~€‚‚‚€‚€€~€€~€~~~~~~€€€€€€€€€€€€x{|z}{|ƒ‚‚ƒ‚ƒ‚~~~~}}~‚ƒ‚€~~~€€€‚‚‚€€~„¤ł§Ś¤˘¤˜‚qnrojhm|‹•š—Œ€yywqlkr{ƒ…А’ˆƒ{uqsw{}~‚‡‹Œ‰††ƒ’­¨Ÿœžœ‹zquwrnow†Œ‹Ž“”Ž„|z{xrorz€ƒƒ…ŠŽˆƒ€~zutw{}~ƒ‡‰ˆ…„ƒ…žŻŁŸ  —…tryqfmv€Šˆ‰“𓉄‚~yplsyyz€ˆŽŠˆ‰ˆ€zwwxwvy„……‡‰‰†€€}‹ł°•¨˛Ľž‹ux~p_hw~†‰ˆ–Ą˜Œ‰†yohnvvv~‡Ž‘Ž‹Œ„{vuutsu|ƒ…‡‰ŒŠ†€}|›Ż•™ŹŁŸ˜y}heq|„‚‰—œ“Ž‹€utyytsy‡‡„ˆŒ†€€~zvw|~}}€„‡†„„†…‚•Šžœ¤  ‹tmopx{}А‹‰‹‰~xzzxvuw‚€†‰‰‡ƒ‚„‚}zyy{{yy}€ƒ„“¤›•žžœ‚ƒ…}tposzyu{ƒˆŠ‰‡ŠŽŒ…€€|wvz||{|„†„ƒ„††„€€|{|~}‚š –›ž˘œŒ†‰…~yrqxzvv{„‡„ƒˆŠˆ†‚‚ƒ{{|~~|{~‚€ƒ„ƒ€~~€~‚‘•‘”””˜•‹†‡…~xv{|zz|~‚…ƒ‚…††…‚‚‚€~}}~~}~€€€‚‚‚€€€€Œ‘Ž““‰‰ˆ‡†~€€~}‚€€ƒ€€€€€€€€€€€€€€€€€€€‚’Ž“•Ž‹ŽŒŠŒ‰†Š‹ˆŠ‹‰‰Š†„…‚€‚€}}|yz{z{|zz{{||z|}{|~~‚‚ƒ……„ƒ€€€~~}}}||}{|||}|}~€€‚ƒ‚‚ƒƒ…„ƒƒ„……„…ƒ„†„„„„†……††‡‡†‡†††…††…†„„„„„„ƒƒ‚€€~~~~~€€‚‚ƒ„„„„ƒ„……†…„…………„„……ƒ„„„„…„…††††††‡†††…„„„ƒƒƒ‚‚‚‚‚‚‚‚ƒ‚ƒƒ‚‚‚€€€€~~~~~~~~~~~~~€€‚‚‚‚ƒƒƒƒƒ‚ƒƒ‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€}~€€€€€€€€€€€€€€€€€€€€€€€€€…‡‡‡‡ˆˆˆˆ‡‡‡††………„„„ƒƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€‰Œˆ„ƒƒ„ƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‡Œ‰…ƒƒ„ƒ}}~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€…“šœ˜–•’ŽŠ„~~~~~ƒ…†……„„ƒ‚€~~~~€‚‚‚€€€€€€˜ľšź¸Ÿ’ŠxiaWUcmu„Ž” ¤ž™‘ƒztjdfflw†”•—•‡€wrolmrv|ƒˆŒ‘ŽŠ„€{y}ƒ‰‘—œĄĽ¤˘ž–ˆ€ytqoqtx}ƒ‡Œ‘Œˆ„{wuttvx{‚…ˆ‰ŠŠˆ†ƒ€~{zxxyz€‰’œ¤Ş­°Ż­ŠŁ›“‹ƒ|vrommoruy~‚†‰‹ŽŒ‹ˆ†ƒ€}{zyxxyz{}€‚ƒ„………„„ƒ„‡ŠŽ’•˜ššš™—”‘ˆ„~{yxxxy{}‚„…†‡‡†…„ƒ‚€~}}||}}~~€‚‚ƒƒƒ„…‡ˆŠŒŽ‘’’’‘‘ŽŒŠˆ†„‚€~}||{{{{||}~€€‚‚‚ƒƒƒƒ‚‚‚€€€€ƒ…ˆŠ’’“’‘‹‰‡„‚€~}{zyxwwwwxxyz{|}~€€‚‚ƒƒƒ„„„ƒƒƒƒ‚‚ƒ„„…†‡ˆ‰ŠŠ‹‹‹ŠŠ‰‰ˆ‡†…„ƒ‚€~~}}}}~~~€€€€€€€€€€€€€€€€€€€€€€€€‚€~‚‚€ƒ„„‡‡…„„‚~{z|{xxz{}~~€‚ƒƒƒƒƒƒ‚†””‘“”•–†„„€{wtvzzy{ƒ‡‡„„…„‚|{|}||}‚ƒƒ‚ƒƒƒ‚€~~~~~}~‹Ş´­ŽŠĽŚ›ƒsqomokm}ŠŽ‘‘”•‹}vsuyzy~†Œ‡‚{xuv|‚„……††‡‚„ĽšłŽ‹ŒŠyifjwŠ‹•–”Šyprtvxx|‡Œ‡‚€ztsv|‚………‡ˆ†ƒ|yz{™ÁĆż°’ƒvibeq‡œ œ—‰‚xlgkt€ŠŽŽŽŠƒ{spsx}‚…ˆ‹‹ˆƒ}yxwz{…ŻĚĘÁچ|wlbahy“¤Łž•Š„|pffmy‡‘‘Œ‡voosz€…ˆ‹ŒŠ‡€zwvyz‹¸ÍÉżž~upjgin~˜ĽĽŸ€zuolmr}‹“”‘Šƒ~zursv}…ЋЇƒ€}zwyx‹šÎÉžœ|urkgin~™ĽĽžŽ€zvplmr}Œ“”‰‚{ussw~†Š‹‰‡ƒ€~yxwŹËÉÁ¤‚wunihkx’٤Ÿ’‚|yrmmpzˆ’“‘‹„€|wsqsx„††‡†…ƒ|z|šťšąŚˆŠ„ulmp~ސ‹Œ‹Š‹‡|uvx|€€‚†‡‡…€|}~~~~~‚„ƒ‚‚ľž˛Ş•„††znnqy‹“‹‹‰‰ˆ€vux{€ƒ…‡†…‚}|~~~~~„ƒ‚‚ž˝ş°Ł‹ƒ‡ƒumos€‘’Œ‹Šˆ‰†{tvy|‚ƒ€‚†‡†„€||~~~~~‚„‚‚€‰ŽżľŹš……‡~qlmnw†‰„†ˆ†‡Š†}{}||€€}~‚ƒƒ€€€~~€€™ˇ˝şľ¤•’’Š}yvs{…‡„†‡†‡Š‡€}~€€}~ƒ‚€€€€€~€‡Ś˝ť¸Żž“’‘…yxuu‡†„†ˆ†ˆŠ„~}~}‚ƒ‚€‚€€€€˜ł´ľĂĹť˝ÂˇŤŤŠ›”—‘†‡Š‚~ƒ„}„}‚„€„ƒ„‚ƒ‚~€‚‡ž§ŁŞł­ŠŻ­ĄŸ˜‡ƒ‡…€„€}‚ƒƒ‚~ƒ€‚‚€‚€‚‚Ł§Ľ­ąŹŹŻŠ ž›’Œ‡€}|~}|}‚‚ƒ‚‚‚€€€€€€€€‹ŸŚ¤Ź˛ŹŤ°Ş Ÿœ’ˆ}{~}{}€‚ƒ‚‚‚‚€€€€€„—¤Ł§ąŻŤ°ŻŁŸŸ–‰€~{wz{yz~~}€‚‚„„‚ƒ„‚‚‚€€€‚’ĄĄŁ­Ž¨­Ż¤žž–ŒŠ‡{{xtvwvx{|}‚‚‚„„ƒƒ„‚€~¤Ş­ŔĚĆÉĎÇźš˛Ł™”Œ||xsvzwy€„ˆ†…ˆˆ……†„~}~~ŒŁŠŠźÍĹĹĎÉş¸ľĽ˜•Ž€z{voqusry}|~„†„‡Šˆ†ˆˆ„ƒƒ‚~}}~}}‹ ¤˘´Ă˝šÂÁ´­­Ł•‚zzxrqvvtx}~~ƒ†„…ˆˆ††‡„‚‚‚€~}~‡¨ŁŤžÂş¸žş­¨Ś’Ž‹ƒ}}|wwzzy{„ƒƒ„…„ƒ„ƒ‚‚€~ˆž¨¤Ź˝Âş¸žš­¨Śœ’ŽŠƒ}}|wwzzy{„ƒƒ„…„ƒ„ƒ‚€€™ś›˛¸Ą“”ˆwtlktohs…ƒ†’–‘Š‰ƒ{wwwsquz|}…ˆ‰‰‰ˆˆ„Ž‹‹ą­˜Ž–ˆzxpsypkw‚ƒƒ‘Œ‹ŠŠˆ‚|z{zutx||}€„†‡‡‡‰‰ƒ…ƒ† ™…¤Š– š’›Ž~‚„ypttsusv‚~†‹‹‹ŠŠŒ‰ƒƒzyyyyxy}~~ƒ„„†„•Ť””łŚ¤”–˜‚y|okpprur|‡‚ƒŽŽ‹‹Œ†€€zwwvxxwz€ƒ††‡†ˆŁ§‹Ą´œŸŸ‘™‘{{wlnsqsuu†€†ŽŒ‹ŒŠƒ€xwxwwwx|~€„††…ˆ†•Š“’ł¤˜Ł•”—ƒz}omsrquu{…‚‚Ž‹ŒŒ‹‹†€{wxxwxxz~ƒ……†…ˆ…Ś—•°˘›¤•–˜…ƒ~tqutsxw|…‚ƒŒ‹Œ‹Šˆ…zwyxwyz|€„†…††‡„‰¤š‡§Ş’Ÿ™Ž–‰z€tmsuqvxy„…‹‹‹ŒŠˆ†~{vxywxz{~€€ƒ††††‡…†Ÿ † Ž”œœŽ•{}wnrxtv||…‰…‰‰Š‰…‚~{zzuuyyy|€‚„…†ˆˆ†…„ƒ€€œŸ›°–˜‘”|yyinxrsz|„І‰’ŠŠ‹‡‚zzytsxyx{‚„†‡ˆŠ‡…†ƒ}‚ ˜€Ł­“››’•‹}z€{lq|yzƒŠŠ‰ŽŽ†‚€{wvxyyy~ƒ„„†‰ˆ†„ƒƒ|{z|xˆŽš‡łś››–‹|mkunam|}€†Ž––Ž‘zzxrnpuxy|ƒŠŠŠŒ‹†‚€~zwuwyvą–ŠŽŽ—Š…ˆslly}sw‰‹†‹Œ‚|}€{su|€}|‚ˆ‡ƒƒ…†‚}}~{z~€€„„…ŤľŠ–ľ Šƒ„wols‚~u‚‘ˆ†ŒŽ…|z~wsy}†‰…‚‚…„~{}€}z|€‚€€‚„…˜ť™…Ź­~{„|sss†‰“|‚|vv}ƒ~ˆ‰„€ƒ|z}€€~~‚…ƒ€€‚ƒ~}~ƒŹż‡ŤŠŠor|rnu‹“‡€‹—Ž{w‚{ru€‡ƒ~‚‹‹‚|ƒ€yx}‚~„†ƒ‚‚}}|žŻ•ąŸ}kyxom}’‚ƒ’–†wy|z{ˆ‰ƒ€ƒ†‚|z|€€ƒ…‚€€€€}~ƒŹĚĽ‡–™‹sglrˆ„’š’ƒ}~|xuty‚‡†„†‰†|z{|||~‚……ƒ‚‚}|}~€€ƒ‚ŁË­†‘™Žwglr}ˆƒ‚™”…}~}yvtx‡‡„†ˆ‡|z{|}|~……ƒ‚‚€~|}~€€ÁÚąŽ‰†ƒxmhmŠ˘˜ˆˆŒŒ„wpnz‰‡€‚ˆ‹ˆ€zwz}}‚†‡ƒ}~€}|‚„‚€€„ąÚź”Œˆ…|pji€ž›Šˆ‹Œ‡{rnv†ˆ†ŠŠƒ|wy€‚}}…‡„€}}€~|~ƒƒ€Ś×ڌ‰…~rkhzšžˆ‹Œˆ}snsƒ‰‚€…ŠŠ„}xx‚~|€„ˆŠ‰‚{z}€€„„‚~}’Äăßʨ‡ss~{xŒ™Ł¤—€trty‚‚…Œ‹„}wvz€‚ƒ„„…„|z|~€‚‚‚‚~~~”Ĺăŕ˨†rr}zy‚šŁ¤—€trty‚‚…Œ‹„}wuz‚‚ƒ„„…„€|z|~€‚‚‚~~~”Ĺăŕ˨†rr}zy‚šŁ¤—€trty‚‚…Œ‹„}wuz‚‚ƒ‚‚„„‚|||~‚‚€~‘źÚáŘş•xmqqv„Žš˘ ”‡zppuzƒ‡Š‹Œ‰‚}yxy|€‚ƒ……„ƒ}|}~€‚‚‚‚€‘ťŮßך•ynrrv…Ž™Ą “‡{qpuzƒ‡ŠŠ‹‰‚}yxy|€‚ƒ„…„ƒ}|}~€‚‚‚‚€€€˜ÄÜŕÓ˛unrrx†œ˘ž‘„vlmpuz„†‰ŒŠ‡ƒ~zxy{}‚„„„ƒ€~}}}€‚…ŁĂĐÔĆŠŒwqmnux|†—™—…}xuvx{~…‡ˆˆ†ƒ}|{|~€‚ƒƒ‚€~~~€€€‰ŤÇŇÔÂŁ‡uplovx~ˆ’˜™—Žƒ|wuvx|~†‡ˆˆ…‚}|{|~€‚ƒƒƒƒ‚€€€Ž­ŔÉɸŸŠ~xtvwvy…Œ‘’މ…€}||||}~€‚„„„ƒ‚€€€€€€€€€€‚™śÄËÄŽ–…|vtxvv{ˆŽ’‘Œˆƒ~}||{|}ƒ„„„ƒ€€€€€€€~{yxvuvwwyz{|}~}|~}{zxuuwz€‚ƒƒ€}|{{}~~€€ƒ†‰‰‡†ƒ€€„ƒƒ††ˆ‰‰ˆ‰Š‰‡†‚}|ywz}~‚ƒ‚„†‡ˆˆ„{wuvvxxvwwux{|‚„„ƒ€zurqswyxwvuvxzzzzyxz{|}}}|}}}~~~~~~~€€€€€‚‚‚‚‚€‚‚‚‚‚‚‚ƒ‚‚ƒƒ„„„ƒ„„„„„ƒƒ„„„…………†…††††††……„ƒ‚~~}}||{{{|||||||}}}}}}}}}~~~~~~~~~}}}}}~~}}}}~~~~€€‚‚‚€€~}}}~~~~}}}~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€}€‚€~€‚~‚€~ƒ~€~€€€‚€‚€‚€‚€€‚~€€‚€€‚€€€€€€€€€€‚€‚‚‚ƒ„‚ƒƒƒƒ‚‚‚‚€€€€€~€~~~~~~~~€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒƒƒƒ„„„ƒ‚‚ƒ„ƒ‚‚ƒƒ‚‚‚‚‚ƒƒ‚‚„…„„ƒ…†…ƒƒƒ‚ƒ„‚‚ƒƒ‚ƒƒ„†††…ƒƒ…„ƒƒƒ‚‚€‚ƒ}~€€€~€€‚€ƒƒ‚‚€€€}€€‚ƒ‚‚‚ƒ‚ƒ‚€€€€~~}}€}}~||€~~€€}|}ƒ~|~€€}}‚„…„‚‚‚~}}}€ƒ„ƒ€}z{}‚~ƒƒ„ƒ~‚ƒƒ‚‚……„‚~~}}~}}}€~~{zz{~{z|€‚}{|~€‚‚€‚‚‚€€€€€€€€€€€€€€€€€€€‡łĂĚĘŔˇ°ŠĄ˜Ž„~€ƒ…†…†‡ˆ‰ˆ†ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€§şÇÍÇźąĽ—‡ueZW]gs‰“¤ŚŁœ„yqjfefks}‡”——”Šƒ{tommpty~„‰ŽŠ…{‚ŚŔÂ˨˘Ÿ’…vdWWcox…Œš˘Ł ˜‹~vpliiimv€‰””“‘ˆztonprw{€…ŠŠ‡ƒ{ЧˇÁČÁťť˛˘‘lca__elv…‘™žĄŸœ˜„{rkihilsy‰Ž’””‘މ‚}xsqqqtw|€…ˆ‹ŒŠĽźÄĘÇşłŻĄna`bbhqy…’›žĄ˘œ—’†|vplmopu|‚ˆŽ‘‘Šˆ†„ƒ€€€‡“––˜—•”’‹‰‡†„ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‹‘”•——–•“‘ŒŠˆ‡…„ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€…‡ˆ‰‰ˆˆˆ†…„‚€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ†‡‰‹‹‹Œ‹ŠŠ‰‡†…„ƒƒƒ‚‚€€~~~~~~~€€€€€€€~~~~~€€€‚‚ƒƒƒƒƒƒƒ‚‚€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒ€€~€‚‚€‚‚‚‚ƒ€‚€~€~~€€~€€€€€€~}~}~€~€~€~€€~~~~~}~€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€‚€€€€€€€‚€€€€€€€€~~~~~~~}~~~~~~~~~~€€~~~~~€€~~€€€€€€€€€€€€€€€€€~~~~~~~~~~~~~~}~~~}~~}}~~~~~~€€€€€‚‚€€€€€€€€€€€€€€~~}~†— Ş´źÂČÉÉČĹżš˛Ť¤ž˜“Œ‹‹ŒŽ‘‘’’‘‹Šˆ†„ƒ‚‚‚‚ƒƒƒƒƒƒƒƒ‚‚„•Ś°şÁÇËĚĚĘĆŔ¸Ż§ž–Žˆƒ}{{|}~€‚ƒ…†††††…„ƒ‚€€€€€€€ˆš§­łšźťšś­¤–އ‚}ywxxxz|~‚ƒ„…††……„ƒ‚€~€€€€€€€€€€€‰œĄ ˛ź´şÂ¸ąľŹ ž˜‡„ywwusvwvx|{}ƒ„ƒ„…„ƒƒƒ‚€€€€€€€Šž˘˘´šŻˇ˝°­ą§žžšŒ‡‚‚‚~}€|€~‚€‚‚€‚€€€€€€€€€€€€€€€€€‡›¨ŹşÄźŔÇżšźľŠ¨Ł™”“‡…„€~€~{}}}€~€‚‚‚€‚€€€€€€€€€‘˘§Żžť¸ÁżľˇśŞĽ¤œ”’ˆ……‚~}}~~€€‚‚‚€€€€€€€€€€€€€€€ˆžŻ¸ĆÍĆÄĹ˝ś´ŞŸš“‹‡ƒ€~|||{}~~€‚ƒƒ‚ƒƒ‚‚‚€€€€€€€€€€€€€€€€€€§łžËÉÁšŠ—‰|soou{‚Š’“‘ŽŠ„|yxyz}€‚„…†…„ƒ~}}}~€‚‚‚€€…ŸŔŢřýëË x]QTap€‹”•–˜—“Œ‚yqmnrz‡Š‹Š‡„€}{zzz|‚„††„‚€~||}~€€ŽÍéüďËĄnJAG_€˜¨Ž¨Ÿ•‰yqmkmtŠ“—•…|ursv{€„†‡‡†…‚€}{zz|~‚ƒ„…„™ťÂÄż–wo_aux{ˆŽ’œŸ•‰~phnsv‚‡‡Œ‹‰…|wutv|ƒ‡ˆ††…€}|zy|~€ƒ„„…„˜şÁĂ˝’uobgyyx‚ˆž¤šŠ~nfpuw‚ƒ€ŠŽŠ}utsu~‚€„‡…ˆŠƒ}wv{~„„‚„…żÁŔľŠtsjozspy„“ĄŚš‰~spwwtvw{ˆ’”’Šyyyyzyw|ƒ‡‹‹†‚€~{xy{ƒ…œšššą‘„‚vsoeco€Ž™œ”Š…€tkkow††‡ŠŒŒ…|wvvwwuw{~‚„ƒ‚ƒ„ƒƒ€~}~“ŞŠŹ§˜›ž•Œvsz~{}||…‹‰ˆ…‚ƒ†ƒ€~{{€€~‚ƒ‚€‚~|}~~~}||}~‚Š”˜˜šžŸĄĄž›™—–”Œˆ†…„‚€}||}}}|{|}~‚‚‚€€€€€„Œ’—š˜šŸ˘ŁĄžœš—”’‰‡„‚€~}||||}}~€€‚‚‚‚‚‚‚€€€€€€ƒŠ•›Ÿ˘ŁŁ˘ œ™•‘Š†‚€~|{zzz{{|}~€‚‚ƒƒƒƒ‚‚‚‚€€~~~~}}}}}‚„‡Š‹‘“•––——––•”“‘ŽŒŠ‡…ƒ~|zyxwvvuuuvvwwxyz{|}~€‚ƒƒ„„…ˆ‹’“•—˜™šš™™˜—–”’ŽŒ‰‡…ƒ}|{zyyxxxyyyzz{{||}}~~~€€€€€€‚„†ˆŠ‹ŽŽŒ‹‹‰ˆˆ‡†…„„ƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒ„…††‡ˆˆ‰‰‰ŠŠ‰‰‰‰ˆˆ‡‡††……„„ƒƒ‚‚€€€€€€€‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚€€€€€€€€€€€€€€€€‚‚‚ƒ‚‚‚€€€€ƒƒ€~~~}€}~~€‚‚‚‚€€}}‚‚‚‚€~~€}~€ƒƒƒ‚‚€~~€€€‚€€‚‚‚…„ƒ„„„„„ƒ„…ƒ‚„‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€‚ƒƒƒƒƒ‚ƒ‚‚ƒƒƒ‚ƒƒ‚ƒ‚‚‚‚‚€€€€€€€…†…ŠŒŒ‘“’‘’Ž‹‰‡„‚€~|{yyxwwwxxyz{|~€‚ƒ„…………………„„ƒ‚‚€~€„ƒ„‰‰‹ŽŽŽŒŠ‰‡…ƒ~}{{zzzzz{|}~€‚ƒƒƒ„ƒƒƒƒ‚‚€€~ƒ‰ˆ’“˜™™œ™™—”’Šˆƒ€~{yxuuvuvwxz{|€ƒ„„…………„ƒƒ€~}~}}~}~‹ŒŽ——œŸ›Ÿž˜˜“Œ†‚|yyvvwuxyy|~‚ƒ„…„„„ƒ‚‚€€~~~~~~~~€€€‚‚‚’Œ–žšŸŸ˘—˜•‰‡‚~|wuwsruuvxz}€‚…‡‡ˆ‰ˆˆ‡……„€€~}||{|{{}}}€Ž•‹–Ą›žž›ž˜Ž‡}{{usqputrw|}~†ˆˆˆŠŒŠ‡ˆ‡„~{yz{zy{|}}~‚‚ƒ„……ƒ’›–Ľžžšž™ŽŒ‡{y{ussqvxvx~‚‚ƒˆ‰‰‰ˆ‰‰†ƒ‚‚|||{zzz|}}~‚‚‚„„„„‚„ƒƒ—œ‰˜Šžœ››•ކ‡‡xszvqqswyyz†…ƒ‰ŒŠ‰ˆˆˆ…€€~zz{{zz{}~~ƒ‚‚„„„ƒ‚ƒ…›ˆŹŸš™œ™Ž‡€pkttomt|}~‡‰‘އ„†„~yxzyttx{{z~ƒ„„…‡‰ˆ……†„€~~zˆŠĽŚœœŸ˜ˆ‚…}mouqlmuzz}€ˆŽŠŠ‘ˆ‡ˆ„~zyzwstxzyzƒƒƒ…ˆ‰‡††‡„€z~™˜„šŞ œ›Ÿ“Ž„…xlqusopy~‚ƒŠŠŒŽŒ…‚‚|xvxxwvy}…‡‡††‡‡„‚€|{|{‘¤ŽŻŁŸ˘—Œ„z~zhfornku„†‹”“Ž‡€~zursvvuw|‚†‰Š‰ˆˆˆ†‚~{yyz{yŚ’“°˛§ĄĄŁ˜Ž„x{xgdkomkt‚†ˆŒ••Žˆ€~}yuqruutv|‚ƒ†Š‹Šˆ‰ˆ†‚}zxxyzyŠŽšŤŹşĆÁŹĄ›‘Ž…rgirtjhu€…‡†‰“”Œ„†‰…}ww{{yxv{‚€‚‡‡„‚‚ƒ„~}}€}{}€€€–¸ź­ŽźĆź§•Ž‹nejuujkyƒˆˆ†Š”’‰‚†ˆ„|vx{{zww}‚ƒ€ƒˆ‡„ƒ„~|}€||}€€†ŚŔľŠ˛ÂĆł ™’‰yhfpwqhp†‰††Œ’”„‚ˆˆ€xuz|{yvy€ƒ‚€†‰…‚‚„ƒ}|~||´żŽŞšĆÁŞœ—„peitwlhvƒˆˆ…ˆ“”‹‚…І}vw||yww|‚ƒ€~‚ˆˆ„„„~}}€€}{}€€~€Ź˝ąŤšČÄŽĄž–ކvjiqulfs€…„„‰’“…†Š‡wx}{xww{€‡ˆ„‚‚„„~~}{}~€ˆĽźľŤľĹÇł˘Ÿ˜ˆzlhouofo~„…„ˆŽ‘“‡…‰ˆxw||ywwz€…ˆ…‚‚„…‚~~€~||€~…žş¸Ť˛Âɸ¤Ÿ™Š}nhmuqgl|„…„‡‘“ˆ…ˆ‰ƒzv{}ywwy~€„ˆ†ƒ‚„…ƒ€~~~||~€€~~‚…›šťŻłÄĚ˝ŠŁž”‹€qhjqpfhwƒ‚†‘’’ˆ‰‹†}wz}yuux{~‚‡‡„‚„†…~}|}€~~€‚…›šťŻłÄĚžŠŁŸ”‹€qhjqpfgwƒ‚…Ž’’’ˆ‰‹†}wz}yuux{~‚‡‡„‚„†…~||}€~~€‚…›šťŻłÄĚžŠŁŸ”‹€qhjqpfgvƒ‚†Ž“““‹‹‹‡yy{xttvz{}~€‚†‡†……‡†ƒ€€}|||}~~~‡ĄşľŤ˛ÂĆľŁŸš†{ohinmfiw€‚‚†’’’‹‹Š…yz{xutwz{}€ƒ†‡†……†…‚€~}|||}~~~Š¨ź˛ŤľÄĹąĄŸ˜Ž„xmhjolelyƒ‚‡““‘Œ‹‰…~zzzxvuwz|}~€ƒ…†………†…ƒ€€~}|}}~~~€‚”˛šŽŤśĂžŠ™”tljnpkipz‚ƒƒˆŽ’’ދЉˆƒ}zz{yvvx{}~~€ƒ………„……„‚€€~}|}~~~€‡ ˇłŠŹšŔ´Ł™•‘‰|pjkookks}ƒ„…‰’‘ދЉ‡‚|zzzxvvx{}~ƒ…†…………„‚€~}|}}~~~€ŁŹ§§Źł´Ź —“‘Š}sprspmnt|€€…ŠŽŠˆ‰Šˆƒ}~~|yxz|}}}~ƒƒ‚‚ƒ„„ƒ€€~}}~~~~~€†š§ §ŤŤŤ¤—‘Ž‚vqpopoklt|€‚†‹Š‹ŒŠ…}|||ywwz}€‚…‡‡†………„‚€~}}}|{{|~€€‚”ŞŹ­ŽŠ­°¨œ‹xsy~~„…ƒ‡ŠŠŒŒŠ…ƒ}}~|}~}~€‚ƒ‚‚ƒ€€~€€€€€€€€€€€€€€‹ŁłĂĐĘžł¤—‹ƒ}|wty|~„ˆ‡ˆ‰‡…†…~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ”§ˇĆËĂşŽŁ›˜”Œˆ‚‚‚„††„„„‚ƒ„ƒ‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€Š˜§ľżÁ˝ˇłŻŽŽŽ­ŤŠ§§ŚĽ¤˘ žœ›™˜˜–•”“’‘ŽŒ‹‹Š‰‰ˆˆ‡‡†††……„„„„ƒƒƒ‚‚‚‚‚‚†“˜ Ą¤§ŠŤŽŻŻŽŻŽŽŽ­ŹŞŠ§ŚĽŁ˘ Ÿœš™˜–•”’‘ŽŒ‹‹Š‰ˆˆ‡‡††……„„„ƒƒƒ‚‚‚‚…‹ŽŽŽŽ‘‘‘‘‘‘‘‘ŽŽŽŽŽŽŒŒŒŒŒŒŒŒ‹‹‹‹‹‹‹‹ŠŠŠŠ‰‰‰‰‰Œ’––——••––˜™™™˜˜———˜˜˜———–––––––••••”””””“““““’’’’’‘‘‘‘‘ŽŽŽŽŽŽ–šš››™™šš›œœ›››››››››šššš™™™™˜˜˜˜—————––––••••”””””““““’’’’’‘‘‘‘‘‘‘—œœ›››œžŸžžœœ››››››ššš™™™™˜˜˜˜————––––•••••””””“““““’’’’’‘‘‘‘‘’—›ž ŸœšššŸŸžœ›ššš›››š™˜™™š››››š™˜—–•””““’ŽŒ‹‰ˆˆ‰ˆˆˆ‡‡‡‡ˆ‰‰‰ˆ†…………………„„ƒ‚ƒƒ„……„ƒƒƒƒƒƒƒ„„„„„„……†††††††††‡‡‡‡‡†…„„…††††…„„……††††††………………†………………†‡‡‡‡†††††††††…„ƒƒ„…††…„ƒƒƒ„„………†……„„„„„…………„ƒ‚€~~€‚€€€€‚‚‚€€€€€€€€€€€~}}~€€~}}}}~~~~~~€‚‚‚‚‚€€€€‚‚ƒƒƒ‚‚‚ƒƒƒƒƒ‚‚‚‚‚‚‚ƒ‚‚‚‚‚‚‚‚ƒ„„„„„„ƒƒƒƒ„„…………„„„„„……†‡ˆˆˆˆ‡††…„„……†……ƒ‚‚‚ƒƒƒ‚‚‚‚‚ƒƒƒ„„…†††………„„„ƒƒ‚€€€~}|||{{{zzzyyyyyyyxxxxxyyzzyxyyzzzzzzz{{{{{{{{{|}}€€‚‚‚€~~~}{z{{}}}|zyyyz{{{zzz{}~}}||}}~~}|||}~~~~}}}~€€€€€€€‚‚‚‚‚‚‚‚‚‚ƒƒ‚‚‚ƒƒ„„…………„„ƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚€€€€€€€‚‚ƒ‚‚‚‚‚‚ƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒƒƒ„„„„„„ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚ƒƒ„„„ƒƒ‚€‚‚€€€€€€€€€€€€€‚‚‚‚‚‚€€€€‚‚ƒƒƒƒ‚‚‚‚‚‚€~~~~~€~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€‚ƒƒƒƒ‚€€€€€€€€€€€€€~}}}~~~~}||||}}}}}}|}~~~~€€~~~~~~~€€€~}}}~~~~~~~~~€€‚‚ƒƒƒƒ‚‚‚‚‚€€€€‚‚‚‚‚‚‚‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚‚ƒƒ„„ƒƒ‚‚€€€‚‚€€€‚ƒ„ƒƒƒ‚‚‚‚‚‚€€€€€€€€€€€€‚‚ƒƒƒƒ‚‚€€€€€~~~~~~~~~}}}}}}||||}~~~~}||||}~~~~~~€€€‚‚‚‚ƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚€€€€€~~~~~~~~~}}}}}}~}}||{{|}}}}|}}}~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€‚‚‚‚‚€€~~~~~~}}}}}}}}||||||}|||||}}}}}}}}}||}}~~}}|}}~~~~}}~~~€€€€€€€€€€~~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚ƒ‚‚‚€€€€€€€~~~~~~€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€†­ś“´ŠžŽ|zvdZo|vyƒšš’‘”‡wtuspkmw€ƒ‚‡”Š‡†„}uruwuuy€…‡†ˆŒ‹‰‚†ŹłŒ“ŞĄ™‰{|}k`uƒ{{Š–•Œ‡“ƒvxyxsnr|~‡Ž‰†‡ˆ„|xz{xux}€ƒˆˆ‡„†Šˇ“˜ą§›€€€xecwzrx‚Œ”‘Œ–‘‚|~{vpntz{zˆŒŠ‰Š‹Šƒ}||zuux{}}ƒˆ†‹¨ą¤Ş˛ŻŞŸˆŠ€ljonopr|ˆŠ†•“Œ‡‡†}uvyvtux}€†Šˆ††††ƒ~|}~zyzšŞœ˘łľŻŚš““‰qlrojjlu‚„‰••ŽŽ…‚„‚{yyyzzx{€~‚ƒ‚„„ƒ†‡„†‡„ƒƒ‚€€€€~~}|||{|}|}~~~~~}~~€~~ƒ…„†‡†‡‡†…………†„‚‚~|{|zwwxwxy{|}€€‚‚ƒ„‚ƒƒƒ‚ƒ‚‚‚€€€€€€€‚‚‚‚‚‚‚€€€€€€€€‚‚ƒƒ‚‚‚‚‚‚€€€~€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚ƒ€~~~}}}}}~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‡Ž“‘‹ˆ„€~€‚‚ƒ‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‡ŠŒ‰†„ƒ„……„‚€‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~€€€€€€€€€€‚‚‚‚‚€€~~€‚€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~‚}ƒ‚ƒƒƒ€}€‚€~~€~€‚~‚}‚ƒ}ƒƒƒ~€ƒƒ‚~‚ƒƒ€~ƒ‚€€‚‚‚€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€~€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€‚€€€€‚€€€€€€€€€€€€€€€€€€€€€€€~€‚‚‚„„ƒƒ‚‚€~~}}}~~~~~€€€~€€€€€€~€€€‚‚ƒ…„ƒ„…„ƒ€€}}}|||{||||}}~}}~}}|}~~~~€~{z}zĄŸ¤­°łŹ —“‹{rnlnllt}„†‹””ŒŠ‡{wvutsuz~€‚…ˆŠ‰‡‡„ŒĄ¤ ¨Ť­Şž•‘urprqpu}„†ˆŒ’Šˆ‡‚}xwwwvvz€ƒ†‡†…††—­ ™°´Ś ˜•”‡vs|xlnx~~€‹‘Š…Š‰€~€|uw~yy€…„€†ˆ„~ŠŤŹ–Ł¸ąĽ™“˜’|mx}iapustu€Œˆ‚Œ–‡‰Œˆ‚|{€|su|{wy~‚€ŻŸ“ľśŁ¨Ąšœ|{€vemvnpvw‚‡†‘ˆ‹Šˆ‡ƒ|wz|zzz}~ƒ“ž˜Ÿ­­ŞŚŁ¤œ‰Šwuuvtqv~~}‚‡ˆ††ˆ‰…ƒƒ}}~~||€œ˜ĄŻŻŻ­ŞŞ˘–‘‡~}}|{z„‚ƒˆŠ‰‡†ˆ†€‚€}|~~}‚€€‚ƒ›—ٞ­ą˛ŹŻĽ˜˜“‡ƒ‚€€†‰ˆŠ‹‹‰‡„€€€}|}~~‚ƒƒƒ…ƒƒ“œ˜§łąˇˇ˛ľŤŸž—Œˆ…ƒ‚‚ƒ‡Š‰ŒŽŠˆ…‚€}|}~~‚ƒƒ„„…”šŠľ˛ˇˇłą¨žš“‰ƒƒ€~ƒ…‰ŠŒŽŒŠ‡„~|{|~~‚„„„„…”™Šľ˛śˇ´ą¨˘š’ƒ}|‚…†ˆŒŒŒ‹‰‰†‚}||}}}€‚‚‚„…”ŁŸ¨ź˝¸¸şś¨Ÿš’‰€|}z}„‡†ˆŒ‹‹Š…€€€}zz}~|~‚ƒ‚‚„…†—­°­ˇČËźłˇł˘”Š€zyvtw}~|Š‹†‡ŒŒ†„…„€~~~{|~~|~‚‚•ŽłŽ¸ĚĐżľšľ¤•Šyxurv~~|‹Œ‡‡‡„†„€}~}{{~~|~‚‚…ąŻŽ˝ÎËťˇšŽ›“‘…vrtnfhoomrz|{€‡‡…ˆ‹Š†‡ˆ†‚‚€}}~}{‚˜ŽąłÂĎÍČĘÉž˛­§™ˆ„zsstposwwx}‚‚†‰ˆ†ˆˆ†„„„‚€€€~ƒ—ŞŤŹšÄÁžÁżľŤ§ “ˆ„~tnnmiimpquz„ˆŠ‹‹‹‰‰‡„‚}|„™¨¨ŹşÂżžÁ˝łŤ§Ÿ’‰„}tonlijnpqu{~€„‡ˆ‰‹‹Š‰ˆ‡…ƒ‚€}~ŠžŚ¤­şź¸šş´ŞŚĄ—Œ‡ƒ{tsronppruwy|~~€‚€€€‚•˘˘ŞŻŹŹŤ¤™’‹ˆ„}}{{}}~€‚ƒƒƒƒ‚€€€€€€€€€€€…– ¤°śľśľŽŚ˘™‹‡~~}€‚‚„†……†…ƒƒƒ€€€€€€€€‰™˘Şśšşş¸°¨˘™‹†€~}~~‚ƒ„……†………„ƒ‚€€€€€‰›§˛ÁČÉËÇŔšŽ¤›ˆ‚{wvtuwx{~€‚„…‡‡‡††„„ƒ€€€€€€€€‹™Ľ°źÁĆÉÄż¸Ž¤›‘Š…}}|~€‚„‡‡ˆ‰ˆ‡†„ƒ‚€€~~€€„‘žŠľžÂÇÇÁź´ŠĄ—Žˆƒ~}}}ƒ…‡ˆ‰ŠŠ‰ˆ†„‚€~}|||}~€€‚Š’šĄĄŸœ—“‹…€zvttuwy{~€ƒ†‡‰ˆˆ†…ƒ‚€~}||||}}~€‚‚„”› Ÿ™•‘މ„zwuuwxz|„†‡ˆˆ‡†„ƒ€~‚ƒƒƒƒ‚‚‚‚ƒƒ‚ƒƒ„………††‡‡††ƒ‚€€€‚ƒ„ƒ‚€~}}|||zzzxxzy{||}~}€}|zy{{z{yxxwxzyz{yy{y{}|}~}}}}~}~~~~}}~€‚ƒƒ‚‚€€€‚ƒ‚ƒƒ‚‚€€‚‚‚ƒƒ‚ƒƒ‚ƒƒƒ„…„„…„„…„ƒ„ƒƒ„…„…†††‡†††………ƒƒ~}{zyxxwvuttttttsrsrruttvwwxyyzz{{{|||}~}~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€‚‚ƒƒ€€ƒ€„„‚‚ƒ€ƒ‚€€€€€€€€€~€€‚†‹‡Š‘‘““’’ŒŠ†ƒ~{zxvvvuvwxz|}ƒ„†‡‡ˆˆ‡‡†…„‚‚€‡†ƒˆ‹‹ŒŽŽŒ‹‹‰†„ƒ€}{zzxxyyz{|}€‚ƒƒ„„„„ƒƒƒ‚…—š žš—•’ˆ…„€}||{zz|}}~€‚‚‚ƒƒƒ‚ƒƒ‚€€ˆ”™œŸžŸ ™–”‹‡„‚||{{z{|}}€‚‚ƒ„ƒƒƒƒ‚€€~€~‚Œ˜š™œ™›œ•‘‘އ„~ywzywx{|}}ƒ‚‚„……„ƒ„„‚€~~‡Šš˜››™š“‘‘‹†ƒ€|wyzxwy{}}~ƒ‚‚ƒƒƒ‚€~}|}}~}€ąœ—­şŻ—’šujlokedr~†“™•’“ˆ~zzxrlntwvx~…‰ˆŠ‹˜ˇł™ ľ´†ŒŽxtlls||v€Ž‹†|yywtqsxz~ƒ†‰‹‹ˆˆ…“ľś˘˘ŤąŚ“Ёxyrfciuzy€‰––”‘ˆ~xusrppsw}‚„‡‹Ž‹Š‡† šŤž™—‘ކqktvuvy}‡’‹‹‹‰…‚€yuxyyy|€ƒ‡‡……†„‚˜ˇş˛ŻŞŚ šzllmlmpuyƒ“’’’Œˆ„{uuuttwz}†ˆ‰‰‰ˆ…„‚žšśŽŹ¨¤™vljgjry|}…Ž’Žˆ„~yyyww{}„…„……„‚€}…ŚťźżťŤœ•’‡wsohku|€…ŒŽŒ‘‹‡„€{xzywz}~€ƒ……„……‚~†ĽźźżşŤœ”’‡wsohku}€…‹‰‡Œ‹‡†„zyzyz~ƒƒƒ…„‚€}†¤¸ŔĘĂ­œ…{wwojoty„‘‘‘‰†…|{ywwz}‚„„„……ƒ‚‚~}…˘¸ÁĘĂŽœ…|wwpjosyƒ‘‘‘Š†…}|{yy|~‚…„„…ƒ€}‚œłžÍÍšĽ”soqoow{}†‘“ˆ„{xyyy|„…„……‚€€~}}€•°˝ËĐžŞ—…vnponuz|„Œ‘“‘Š„|xyyx{~„††††„€~|}}ŽŤšÇŃÂŹ™ƒqiikkrz{ƒ’•˜–އyttuux}…ˆ‡ˆˆ…€~{{{‡ĽˇÄŃČąˆujikkpxz€‹‘”˜—ˆ‚{ttutw|~€„‡ˆˆˆ…€|zz–ŽżŐŘǡŸ€pe]_fms}ˆ–žœš—‹€{rlnprx‚†ŒŒ‹Œ‰„‚~ywzާšĐÚË˝§‡ti__ekpz…Š“œœš™ƒ}umnpqv}„‹Œ‹ŒŠ…‚zw…žŻÄŘÍ˝ŽŽulb_gnrzƒ‰Ž˜›—˜‘„~wnnqrw}„ˆ‹ŠŠŠ…‚€|x}•ŤźÔŐĂśœ|oe]ckpv€ˆŒ”›™˜–‰€zqmpqt{€ƒ‡‹‹Š‹‡ƒ}yyŠŁ´ËŮË˝Şˆumackns|‡—˜š˜Ž…~tppptz}…‡ˆŠŠˆ†ƒ|zx„ ˛ĆŘÍźŤ‹skaaios{‚‡Ž–™™˜…~uopqsy~…ˆˆŠŠˆ†ƒ{zx€›ŻÁ×ŇŔ°‘vlb_fmqx‚†—™˜™„~voprsy€„ˆˆ‰Š‡„ƒ{zzxƒžąĹÚŇŔ°ulb`ios{ƒ‡Ž˜™˜˜Žƒ~uoqrtz…ˆˆ‰Š‡„ƒ~zzzxƒžąĹÚŇŔ°ukb`ios{„‡˜™›™‡wuutw|…ˆˆ‰Š†„ƒ}|{y{|‰ĽˇËÚĚşĽ…qibemqv|ƒˆ™š˜–Š€zrortx}€‚…‡ˆ‰Š‡ƒ}zzyz}ŞťĐÚȡ ngafnrw~„Š’š™˜”‡yrquvz~€…‡‡‰‰…‚€{z{z}~„žąžĎĹŻŸ„pmklswx{‚…Œ––“‘†}zutxz{~€€‚††‡ˆ„€|{||}€ލľĹĎş¨•ymmjovyy~„‡—”“ށ{xsuzz|‚†…ƒ…‚€|~~~†›Ş¸Ĺž°¤’ƒzvy{z€…†‹Š‰ˆ‚€€}|}~€€ƒ‚ƒ‚€~€€€€€€„”§ľÂŔ´Ś•‡{xxzz~ƒ†ŠŒ‹‰‡ƒ€€~}~~~€€€€€€€€€€€€€€€€€‰“›˘Ľ¤Ł˘ ž›—•“‘ŽŒ‹Š‰ˆ‡‡†……„„ƒƒƒ‚‚‚‚‚€€€‡‘šĄĽ¤ŁŁĄŸœ˜•“’‘ŽŒŒ‹‹‹‰ŠŠˆ‰ˆ‡ˆ‡‡‡ˆ‡††„„…ƒƒ„‚‚‚‚‚‚‚‚€€€€‚‚€‚€‚‚‚‚ƒ‚ƒƒ‚ƒ‚‚‚‚€€€‚€‚‚€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€~‚~€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€~€‚€€€€€€€‚€€~€€€€€€€€€€~€€€€€€€€€~€~€€€€€€‚€€€€€€€~€€~€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒ‚‚‚‚€€€~€~~}}~~}}}|}~}~~~~~€€€€ƒ„ƒƒ‚‚‚}€€}|}}}}~~€}~~}}|||{z|}|}}~~€‚‚ƒ…†…†‡ˆˆ†„………„‚‚‚€€ƒ‚€„‚‚ƒ€ƒ‚‚ƒƒ‚…€~‚€‚„ƒ€„}€€~€€~€~~‚€€ƒ€‚€„„ƒ…€ƒ€}€€}~~€€€€€€€€€€€€€€ƒˆ“™’‘ŽŒ…~ytxzxy{€ƒ‚ƒ‡‰‡…††ƒ€~{z|}||~€‚„„ƒƒƒƒ€€†ˆ‰–”ŽŠ„€wvzyxz|€‚ƒ‡ˆ……‡…‚€€}{{}|{}€€‚„ƒ‚ƒƒƒ€€—žŽ˘žž›˜Ž‚~€wkpurrv}ƒ„„‹‰ŒŒ‡‚}xuxzxx|€ƒ†‡……†…ƒ€€|Š‘–ŻŤŞŻŤ°Ť›™˜Œ€zxsjhjmlks{|…ŒŽ“’‹‹‰ƒ~}|xttvvuw{}}‚†…‰ž —§°ŠŞŚ¤Ś˜Žˆ}tsrlhjnoos{…ŠŽ‘‹Šˆ„€~}zwvwvvwy{|~‚„„‡™ž’ŁŻ˘§¨ĄŚš•Œ~|yupknpmnsyzy†…‡‰Œ‰‰‹ˆ„ƒƒ}{}|yyz|{{}€‚ƒ‘˜žŤ§Ş˘ŤĄ—Ą–Š†~vwxrquvtvz|~†……ˆˆˆˆ‡ˆ‡„„ƒ€~~|||}||~|ˆ‘†“ •˘›Ł—–‰{vwsosqotuvz{~‚ƒ„ˆ‰‰‹ŠŠŠˆ‡†ƒ‚}|{zzyy{yŠ‚Š–˜šĽŁŸ¨§˘Ś¤ĄŁš—’”Ž‹‹…„„}}~yyyvwwtwwuwxwzyy|||~€‚ƒ†‡‡‹Œ‘‘‘’‘ŽŽŒ‹Š‰ˆ‡‡†…„„ƒƒ‚‚€€€€€€€€€€€€€€€€€€€€ƒ‚ƒ…„…†…††††††††……………„„„ƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚†‹Ž‘ŽŒŒŠ‰ˆ‰‰‰Š‰‡‡†…ƒ‚‚‚€€€€€‚€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚~€€~‚}ƒ~ƒ~€‚~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ„„…†…‚~||zz~€}}}||}€~~}~€|}}‚„ƒ„…ƒ„ƒ~~|{}~€ƒƒ‚ƒ…„ƒƒ‚ƒ€€}}€‚€‚…‡ˆ……‰‹‰†„†‡†‚€ƒ„‚€„…ƒ„†ˆ‰‹Š‡‰ˆ†„€€~|zyz{{}}}€€€‚ƒ„€}ˆž˘™ ŤŹŠœ“”’‚srtqminz~Š’’ŽŒŽ‰€}}{vrrwzxy~„†††ˆ‹‰„‚ƒ‚~zy{|zy{§Ś˘­ąąŹ“’‹ynmlkiho|‡•–’†~zzwroqw{{~…ŠŒŠŠ‹‹†€}|zwtuy{|~‡ˆ‰¤şŤŠ¸ľŤŸŒwa[gkkqy†•™•™Ą‡|vmehoppw‚Š‘••ކ‚zsnnrttx†ŠŠŒŽŽ„”ľĽ‘ڍ ›ˆ}‚ƒpamxuwz€’˜‹•˜‚}z|vjjuzxy€‰Ž‰‹Œ‚|{{xrpt{|{…‰‰†‚‚„~€§śš¨žšŽtlxzjjzƒ’Š‹˜–†{{yxunp†ƒƒˆŽŠ~wtvz~~‚ˆ‰†„ƒƒ~yz|}}|€‚‡Ťž¤Ł°¤šŒtjsrchy‚Œ’’š‹ƒ{ytlny~}€†ŠŽ†„†ƒ}xvw{|z|‚††…„…†ƒ|}}||{~…ĽťŠŚŽŠŁ–~ouwhfox…‹ƒ†’“Š„„uw‚}ƒ‰…~‚ƒ‚}{ƒ}~€ƒƒ}ƒ}‚‚~}€‚ƒ’˘Ľ¨ŹŞŞŚšŠ„…‡……ˆ‰‰†‚‚„‚~€~‚€€€‚‚‚„„„…………ƒƒƒ„„ƒ‚‚ƒ„ƒ€‚€‚‚ƒ‚‚„†………††‡†„„ƒ‚~€~~‚ƒ„„„…„ƒ‚€€~~}|}}}|{||}}}~€€€‚ƒ‚„†„„…ƒ„…‚ƒ„‚„€ƒ€ƒƒ‚‚€€€€€€~~~€€€€€€€€€€€~€~€€~€€€€‚€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€‚‚€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€~~€€€€€€€~~€€~€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~~~~~~~}~~}}}}}}}}}}~}~~}~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~€€€€€€€€€€‚‚ƒ†‡ŠŒ‹‹‹‹Šˆ††‡‡…„ƒ€‚‚ƒ‚‚„†‡‡Š‰‡‡†„„„„††††‡†…†…„‚‚‚„…„‚‚‚‚‚‚‚‚ƒƒ€‚€ƒ‚‚€€ƒƒ‚ƒƒ€€~~~€‚€€~|€€€€€€‚€‚‚‚‚€€€~~}€€€€}}~~~~€€€~}~~€€|‚€~€€~€‚€‚‚‚ƒƒ‚‚‚€}}}~€€ƒ}{{~‚„„~|{€ƒ€€€‚ƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€”łżľŸ‰~~|ƒŽ——z{~~ƒˆŠ†€||~€€€ƒ„ƒ~}~€€€€‚‚€€€€€€€€–ÁžĄ’}tzxol{Ž™“…€{uqrz†‰…ƒ~yvw}‚…†…„„‚{z{~€‚ƒƒƒƒ‚}}}~€‚‚‚‚•żź ‘|t{zpm{˜œ’…|vrt|‡ŽŒ‡ƒ€}yvy…‡†„‚‚~{z|€‚ƒ‚‚‚‚€~}}~€‚~”Âż yr|{rn|‘œœ€{}|wst~А…}yvy€†ˆ…‚€}{{~ƒƒ‚€~}~€}•Âźœzu}{rp€“™—Œ}|wuy‚Šˆƒ€|zy}‚……ƒ‚}|}€‚€~~€€€€~¸˝Ą“‚|zrp€”“‹ƒƒ|vv{‚‡‡…„„‚|{|‚‚‚‚‚~€€€€€€€€€€€€€€€‹ŻťŞšŽ…„xuƒŽˆƒ„„z|€ƒ…„‚ƒ‚~~€€€€€€€€€€€€€€€€€€€€€€€ƒ–ŤŽŠĽŸš”‰ƒ‹–šš™–•††‰Š‹ŒŒ…~‚ƒ„‡ˆ…€ƒ…„‚€€€~~€‚‚‚€€~‰‹ˆŠŠŠ‹Š‰‰‰ˆˆ‡‡‡†………„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€ˆŒŠ‹‹‹Œ‹ŠŠŠ‰‰ˆˆˆ‡†††……„„„ƒƒƒƒƒƒƒ‚‚€€€€€€€~~~~~~~€€€€‚‚‚ƒƒƒ‚‚‚ƒ„‚‚ƒƒƒƒ‚‚ƒ„„„„„……„„„„„ƒ‚‚‚‚‚€€€€€€€€€€€€€€€€€€‚‚‚€‚‚‚‚‚‚€€€€€€€€€‚‚‚€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€‚€€‚€~€‚€€€€€€€‚€€€€‚€‚€‚‚€~€‚€€‚€‚€‚€€€€~~~~~~}}~~~~}}€|€€|€€~~€€~€~€~€~€€~€}‚}ƒ}‚~€‚ƒ~~€€€~~ƒ}ƒ{€‚}€‚}ƒ€|€€€}‚~€€~ƒ|ƒ~~‚}ƒ}‚ƒ~~„~}„~ƒ‚|‚ƒ{ƒ}€€€€€~€~‚€€€€‚~€ƒ|€ƒ€‚€€€‚~€~€€|‚}~€~‚€€‚€€}€€‚€€€~€‚€}ƒ€€€ƒ~€€~~ƒ~}ƒ‚ƒ~…‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‡‘“—œœ™“‘‡„‚~}~}}€€€‚ƒ‚ƒ„‚‚ƒ€€€€€€€€€€€€€€€€€€€€€ŠŁĽžĄžĄ˜…z|xuslkw‚ƒ†‰”އ…„‚€zttyzz{|€†ˆ†…†††„€|}~}{zz}€€€ƒ„„ƒš¨Ą˘˘ŸĽ¤•‡…ƒ}|vms{{{x|……||{}~~~€ƒƒ‚~€€€€~€‚€€€€€€€˛ĐăčÖśš†vle[TZj˜ŤąŹ¤™…{nc]]etƒ–™˜•“„zqjhlrz‡‹Žˆztrqsvy~‚ŹĎäîäǧ|k_TJL\u¨ľľ°Šž‘ƒq_SPVew†‘š Ł˘’‚sg``eks}†˜œ›–ƒyrmkkmsz„ŸÇăóóŰš›„o^QFBPh…˘śźš˛§™ŠwbRKKTcs‚š˘§§˘—Š{neaadjq{…–šš—ˆ€ysnllot‡§žËŃĹŻŸui\ST]l› Ł˘Ÿš‘…wlcadjqz‚‰–˜˜“Œƒ{uqnnpsx~…ŠŽ‰…€{wtss~™Ž´¸śĽ˜”Š|qg][dp{†–˜œ™‡|qkjikpv}„’””’Œ†€zuqpprw|‚‡‹Ž‹ˆ…‚}{zy–¸ÓßÚÍÄ˝ł§™ƒyojjnsvy~ƒˆ‹ŒŒŠ‡„‚€~|{{{|}~€‚‚‚‚‚€€€€€€…ššŇÜÖƽ´¨›‘‰sjimrstx„‡ˆŠŽ‰†…„‚||||{{|~€€‚ƒ‚‚‚‚‚€€€€€€€†žÄßäŘÉĂŔ´Ąvi]Y_ioqv”––˜˜•†‚€{uqqtvvx|„…†ˆ‰‰‡„ƒ‚€~|{||||}‚‰˘ĆŕĺŮÉžł Žti`ajqrt}š››œš“Š„€yojlqsrszƒˆŠ‹‘މ††„~wuwxwux|€‚…‰‰‡ˇĺńŮšŽťÁŤŠsf[SSapkg^AG`€˜˘››Ąœ˜“~k_RTev‹Ÿ¤˘œŽ‚|tqroosv}ˆ•˜“ЁwopoyŸĂÚôíĆŁtG>@Jj‚ŽžŚĽ¤{j_\ao‹”˜–‘‹ƒ{tpnqw~…‹Ž‰…€|ywxx}~ž×ĐÍł}b^W^t€„™Ÿ—„vmefr|ƒ‹ŽŒŒˆ}xtsv{€…‰‰ˆ†ƒ€~|zz{~~ŽźŇÎŇşŒwl_alsx€Ž—š Žƒ{plpsw}„ˆ‹ŽŒˆ…zxxxz|ƒ…††…ƒ~~{ˆłÉÇˡ‘~wrrstpmy‡œ ™Ž†ƒ€~vrsw}…‰‰…‚‚‚„†„€|yy{ƒ‚€~€¸ÍĚ̸™†€ƒ‚{xlajy‡”˜–Ž†ŠŽŠ€wrv{~€|{|†ˆˆ…€€‚‚|{~~‹ŹžÂÄšŠœ•˜’‡€shioy€‚…ƒ†‹Ž‹†€{}~€~{yy}€‚ƒ‚€€ƒ……„‚€€€‡—¤¨Ş¨¤ Ÿ˘ ™‡~zy{zwusrv{€ƒƒƒ‚ƒ…ˆŠˆ†ƒ€€}{{|~€€~‚ˆ™ĽŞ­ŤŚĄ ˘Ÿ˜‡~yvuspnlknqux{}„‡‰ŠŠŠ‰ˆˆ‡…„‚€~}}||{{{{|}€‰– ŠŻąąą˛˛°Ť¤œ”‡‚|wsomlmnprux{~„‡ˆŠŠŠ‹Š‰ˆ†„ƒ€~}|{{{{{Š– Š­ŻŻŽ­ŠĽ ™’Œ†|xtrpppprtvx{}ƒ…†‡‡‡‡††…„ƒ‚€~~}}}}€‡—žĽŞ­°ąąŻ­Š¤ž˜“‡‚~zwutsstuvxz|~€‚„…‡ˆ‰‰ŠŠŠŠŠ‰‰ˆ‡†…„ƒƒ„†‰Œ’•—™›œœœœ›™˜–”‘‹ˆ†„‚€~||{zzzzzzz{{||}}~~~€€€‚„†ˆŠ‹ŒŽŽŽŽŽŽŒŒ‹‹ŠŠ‰ˆˆ‡‡††……„„„ƒƒƒƒ‚‚‚‚‚‚€‚‚ƒƒ‚‚‚‚ƒ‚}|~‚‚€~~€‚‚‚ƒƒ‚€~€€~}~€€}~~}~€€€€€€~€}}€€€‚€‚€€‚‚€‚‚€€€‚€€€~€€€€€€€€€€~‚‚‚€€€€€€€€€€€~€€€€€€€€€~€‚€€€€€€€€€€€€€€€€€€€€€~‚~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€‚€€€€€€€€€€€‚€€~€€€€€€‚€€‚€€€€€€€€€~€€€€~€€€€~€€€€€€€€€€€€€€€€€€‚‚€~€€€€~€~€€~€€€~€€€€€‚‚‚€€‚‚€€‚€‚€‚‚‚‚‚€€€€€€~€€‚€€€€‚€€€‚‚ƒ‚€€€‚„ƒ‚€~€‚‚€‚‚€€~~€€‚€€‚ƒ‚€~}~~~‚‚‚€}~€€~~€‚‚‚~~~€‚ƒƒ‚‚‚‚~}{|€‚‚€€€€€€„ž˝ÍÔĘŤŽ{ooy…Ž”˜–‘Œ„|yxz~ƒ‡ˆˆ†ƒ€~}}~‚ƒƒ‚€€€€€€€„žžÍÔĘŤŽ{onv|…‹‘—š–‹uoqx…ˆˆ‡†…„‚~{xy|€„†…„‚€~~~€ƒƒ~Š´ÍĚČĽt`[av‰ŽŒ‹”•Š{qilx„ŒŽ‹…|yz}…ˆ†ƒ€}|}~€€€‚‚‚~~~œĆÎÍźŠg[VgŒ“•“’Ž†{rlmvŠŠ„|{zz{}ƒ†‡†ƒ€}{|}‚ƒƒ‚€~~~~€šÎČşiabq‚Œ“–š˜Žƒtkmu€‹ŽŽ‹†|yww|†‰ˆ…~|{|}‚ƒ„„‚€~}}~‚‚‚~‹šÎĂłˆfciw‚‰Ž‘š›ƒsjnx‚‰‹‹‰‡„~yvv{†ˆ‡„~|||~ƒ„„‚€~~~~‚ƒ‚€~”Ä˸˘zgnwzx‚‹–¤›‡ynov}€€‡Œƒzvw|}~€‚‡‰†‚}{|}~„…„~}~€ƒ‚‚€ŞĎťŸ‡or}~pl‚“ Ł|‚}qls~‘ˆ„†ˆ„{try‚ƒ‚‚…ˆ‡‚|y{~~~~…†„€~~}}ƒ„€—Ĺžœ‚}}vkd|–—•Žˆ‹ˆ|niu~€„‹†}{|zww{‚†‡………ƒ€|z{}~€ƒ……ƒ~}}}€€‰´Ć¤‘‘ƒmhgq‡‰‹–›Ž€xtuvvw}ˆŠˆˆˆƒ|xxz{{~‚†‡…„ƒ‚|{|}~ƒ„ƒ‚€€~}~~ŔŹ’—ž—xgmt{zy†“™‘†‡‡€vpt{~€†Œ‹†‚€|yx{€ƒ…††ƒ€€~||}€€€ƒƒƒ€‚Œ˛Ž”™ žŽwrv~ylvˆ‘„ˆ„wxwsz…‡‚„‹ˆz~‚€yx~„ƒ~~ƒ‡„~}ƒ{|€ƒ€}€‚…€…­ˇš•ž•‚sq~€ml|ˆ‰‚€ˆ‘€z‚‡wu}„‚zzƒ‰…~}„‡‚{z„z|‚…|~ƒ…€|~ƒƒ|}ƒƒŸ´ĄžĽĽ ‘ƒ{‚smw€…€††„‡ƒ|w{€{z€†…€~ƒ†ƒ~|€ƒ~|‚ƒ€}ƒƒ€~‚‚~~‚–Ź˘›¤Š§œ”‰…‹‚tsy~|{|~‡‹„…Ї‚€~€ƒz{€‚~~„ƒ„~~€€€‚€€‘ŁĄŸĄŚŹŠ¤™‘Œ„{rrqrqmpv{€€ƒ‡ŠŽ‹Š‰Š‡ƒ€}}|zywxz{~~‚ƒ††…†…†…ƒ‚€~}|{z}‰œŻŔÄš§xkfglrw}†˜ŸŸ˜~rjghkotz‰‘––“Œ„|vrqqruy~„ŠŽŽŠ†|ywuuwy}…‰”˘­śśŹžŽtlfb`afnx‚‹’–˜˜•‘‹…~xspooruz~ƒ‡ŠŒŒŒŠ‡„€}zxwwxz|~€ƒ„†††…„ƒ€‡Ž–œ›˜”‹†€{wtstvy}€„ˆŠŽŽ‹‰†ƒ€}{yxwwxy{}‚„…††††…„‚€}}||||}~~‚…ŠŽ’•———•’‹‡‚~{xvuuuwy{~€ƒ…‡ˆ‰‰ˆ‡†„‚€}|{zz{{|}€‚ƒƒ„„„„…„„„„„„„ƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ‚‚€‚€ƒ€‚€‚€€€€€€€€€~€~‚€‚„~€~‚€}‚€}€€€€~€€€€€~‚~‚‚€ƒ‚ƒ€‚~~‚|€~~€€€~€}‚€~~~€€€~~}€‚€ƒ}‚‚~€}‚‚~‚€‚‚‚‚€„‚€‚}‚~~„€~‚€ƒ~€ƒ}}€~}~€€€€€~~~~~~€}‚~€€ƒ‚‚ƒ‚ƒ‹”—™˜——š™”‘‘ˆ…‚‚{xxxwutuwwwxz|}~ƒ„„„†‡‡†…††…ƒƒ‚‚~}||}}}|}~~†ŒŠŒ’—˜˜™™œœ—”””‹ˆ…„|yz{zxy|€ƒ……„ƒ„…ƒ€€€~}~~~~€€€€‚‚€Ż§”¤śś§š–Ž}u}~tjly|wv{„Їƒ…Œ‰‚ƒ††€{{~|xy~~|~ƒ…ƒ€„†ƒ€€‚ƒ€}}€}}€‚€•° ”޸´¤œŁŸ–€ysilzzqry‚†ƒ„Œ‰‚…‹‰‚|~‚|xy~€|y|‚„€~€„†‚€„„}~€}}€—˛Ľ˜Ťˇľ¨››—“Žyoz}ulky}}{‚Ž†ƒ†Ž‹‚‚„|wy~}x|ƒ‚~ƒ†„€~‚„‚~|‚~|~‚~~„ ´ ™­š´Ąšž—“‹yv}~vkq~}{{}…‰ˆ…‚ˆ†€‚„€|||{{~‚~‚ƒ€‚‚~€~€€€~€€†˘Ź™ ąłŽ Ÿ˜’„y€upow{vx{ˆ„‚‡ŠŒ‡‚…†„|}€~|z|€~}~‚‚€‚ƒƒ€€‚~€€~~€€€~‰¨Š—ĄŻłŽŸ›š™—‚v~zpkv{{yu‰‡„†ŽŠ„‚ˆ…}{|zy|€‚}{ƒ…€~„„}€ƒ‚€|~|€‹ŚĽ•ŁŻąŞ›˜”y€xomwzywwˆ‡……Œ‰†ˆŠ…|}|xwy|{zz~‚‚„††„ƒ„…ƒ€€|}|ƒ–˜— §¤››šš”‡€~zpnqstqry~‚ˆŒ‹‰‹‹‰…€~zyyyzxxyz|z|‚ƒƒ„„†…„ˆ†„„‚‚‚‚}€}€€„ƒ„…‚…‡‡†††…‰‡ƒ…„‚ƒƒ€„…„„†……††……„~|zwvurponlllmnnomnqnppppprqrrrtqtsststsuttututvwuvwvvwwwyxyyx|yz{x€~~yzzzzxywyxvyuxxwxvywxywywyzwywzxx{y{xz{y}y{||||~|~~~~€~€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€‚€€€€€€€€~€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€‚€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€~‚€€€€€€€€€€€€€€€€€€€€€€€‚€‚~€‚€€‚~€~‚€€€‚~€~ƒ~‚}‚‚~€€€‚€€€€€€€€€€€€€€€€€€~‚€€€€~‚‚‚€€€€€€€~~€€€€€€€€€€€€€€€€€€€€€€‚€‚~€€€€€€€€€€€€~€‚~€~€€€€€€€€€€‚€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€‚€€€€‚€€‚€€‚€€€€€€€€€€€€€€€€€€€€~~€‚ƒƒƒƒ‚ƒƒ‚€€}~€€€‚‚‚ƒƒ„ƒ‚‚‚€€€~}}}~}{}}|}}~€€‚€€~~€~€~~‚€‚ƒƒ‚€‚€‚‰ˆ ˇ°Ž´ˇś¨™‹…sjkmqoq{†ŒŒŽ“–”‡†ƒ}vstuuux~‚„…‡Š‹ˆ†„ƒ}{z{zzz|€‚„˜Ť¨Ş˛´´Ť›’ކvmklnmox‚ˆŠ’•”Šˆ…xttusrv{~~…ˆˆ††‡†‚}zz|}}}~‚‚•ŻĽŸľšŹĽœ–”ˆupxuiku|Œ“‡ŒŠ‚~€|tu|~yy„„†‰„€„‚}{~€~{|€‚~‹ŤŞœ­š°Šž”–Œumuoaakmpsv‚Œˆˆ’–ŒŒˆ‚|{}wruywwz~‚‚„ˆˆ……‡…‚€€€~}z…˘™ˆŞ´ž¤¤Ÿ”ƒ‚†|joypmuu}ƒ~‚Žˆ‰ŽŒ‡…ƒ‚{w{|ww{}}~ƒ†ƒ„ˆ†…„ƒ„~’‘ƒ™ ’š˜•šƒ‹†wxystrpz{v…ƒ†‰‰‹†‰‰‚€€}|ywyzwy}}‚…†„†‡…„ƒ‚‚~Š˜‡Ą–•š’—”„…Š}uzutvpv~xyƒƒƒ††‰Š„…‰„€€~{||{~€‚ƒ€ƒ‚‚€ƒ‘“’Ł¤ŚŁĽĽœ•”†~|zutyywz‚‚…ˆ‡…‡‡…ƒ‚‚~}~~||~~~~€‚‚‚Š—Ÿ¤˘˘¤Ÿš—“ˆƒ}xvwvvwy|}„……†‡‡†……„‚€~}}}}}}~€€€‚€ƒ’œŸŁĽ˘Ľ¤™–‘‹…€~{vvvvvwz}~ƒ……‡‡‡ˆ††…ƒ‚~~|||{||}~~€‚ƒ‰•›™ŸžœŸš–•Š‡‚}|wuvstvux{|‚ƒ…‡‡‰ˆ‡ˆ†…„‚€~}|{{|{|}}~€ƒ‚…ššœŸžžœ™—”Œ‹…ƒƒ~‚‚ƒ„ƒ„„ƒƒ‚‚‚€€€€€€€€€€€€€€€‡ŒŠ–ššŁ¤Ľ¨Ľ¤Łžš˜“Œ‡„„€€€‚ƒƒ„…„……ƒ„ƒ‚€€€€€€€€€€‡ŒŠ•››Ľ¨ŠŽ­ŹŹ¨¤˘—•ŒŒ‡†‡…†‡†ˆ‰‰Š‹ŠŠŠˆˆ‡……„‚‚€€€€€€‚‚‚‚‚‚€‡ŒŠ•œ›Ľ¨ŠŽ­Ź­¨¤Łœ˜–Ž‰‹ŠŠŽ“”•˜——˜–•”ŠŠ‡††…………†ˆˆ‰ŠŠ‹‹‹‹Š‰ˆˆŒŽ–šŸĽ¨Ž˛˛ľś´˛ŻŹ¨ŁŸ˜•”’’‘’”•–˜š›œœœœš˜—”’Ž‹‰‰‰ˆ‰‰ŠŠ‹ŒŽŽŽŽŽŽ‘‘”˜šžĄ¤§ŠŞŹ­ŹŹŤŠ§¤˘Ÿœ™—•“’ŽŽŽŽŒŒ‹Š‰ˆˆ‡††…………………„…„…ˆ‹Œ‘•™œ ¤§¨ŞŤŤŞŠ§ĽŁ š—•’‹‰†„ƒ‚€€~~}|}}|}}|~~~€‚ƒƒƒ„„ƒ„„ƒƒ‚‚‚€€€€~~}|||{{zzyyyxyxxxxyyyzzz|||}~~€‚‚‚‚‚€€€~~~~~~~~}~~}~~~~~~€€€‚€‚ƒ‚ƒ‚€‚€‚€€€€€‚‚‚‚‚€‚‚‚‚‚€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€~€€€‚‚‚‚‚€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€~~~~~~~~~~~~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚ƒƒ„„„„„„„„„„ƒƒ‚€€~~~}}}}}}}}}}}~~~€€‚‚ƒ„„„……††††‡‡‡‡††††………„„„ƒƒƒ„„„„„„„„„„„„ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚€€~~}}}|||||||||||}}~~€‚ƒ„……††‡‡‡‡‡††……„„„ƒƒƒƒƒƒƒƒƒ‚‚‚‚€€~|{ywvtqonnnqtw{€ƒ…ˆ‰‡…‚}zxwxyy{{{{zxwvvx{„‰Ž‘“’‰†„ƒ„…†‡‡†„}xtqnmnoqtwz|€ƒ…ˆŒ’“”–˜š››š˜“Žˆztoljijkmpsvy|~€€€€~}||{{{|}}~€€€€€€€€€€€€€€€€ˆ•ڏÇÓŰáâŕŮĎĂľ¨›‡€|zz}€„‰Œ‘’‘Š‡„~}|{{|}€‚ƒ„„ƒƒ‚€€~‹šŤŔŃÜăĺáÚĐ´Ľ—Ё{xx{ƒˆŒ’’‘Œˆ…~|{z{|}‚ƒ„„ƒƒ‚~~~~~€‚Ž˘ľĚáęíéÜĚşĽ’ƒvnlot}‡—œžœ™“Œ…~xusrtvy|‚„‡‰Š‹‹‰‡„~{yxxyz|~‚…“ŠžÚń÷őčȧ‡gRIFKU`js|ƒ‹–ŸŚŹ­¨Ÿ’ƒuia^`djry…‰Œ’““‘Œ†€yspoquz„†ŠłÇâńęÝÁ–sWB?HVhz†Œ’–˜ŁŁĄ›~obZ[`jx„Œ’”’Ž‹ˆ‡ƒzupoorx…Š‹ˆ…ƒ—ŤŔŰĺŢŃ´Žr[LNXdr~„‡‹Ž‘˜žŸŸ—‰|oebfoz†Ž’”’Š†}zvtssv{‡ŒŽ‹†}yxv€š­ÁŮÓÁ°ŠhYLK[ky‹•˜œŸ›˜–Œwjaadky†˜›—’Œƒ|wsrvy†‰‹Œ‰„€|yyy{ƒ……„–śÍćđŐ˛ŠYEHRr’ ŹŹž”‹zwpoqs{…“•ˆ€xssuy‚„††……ƒ€}|{|}ƒ„„‚‚€}ˆ§˝Ňâϲ—veimu„€ƒ“Šˆˆ†„……€€~|€~|‚}~~ƒ‚~‚„‚~€ƒƒ‚€€~€€€~~~€€~~}€~~}~€~€€‚‚‚‚€€€€€€€€€€€€‚€€€€€€€€‚‚‚‚€€€€€€€€€€€€€€€€€‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~~~€}|}~~~€~}~€~€€€€€€€€€€~€€~€~€~~€~€‚€~€€€~~‚~‚€€ƒ~~ƒ‚~€€ƒ‚~€„~‚€~€ƒ~ƒ€€€€€€~€~€€€€€€€€~€€€~€‚€‚‚‚‚€€€€~~}€}|~€€‚€€ƒšŞ§¨Ż˛­˘•Œˆ‚upswyz~„ŠŒŠŠ‹‹†~}{yz}€‚„„„ƒ‚‚~~~~~€€€‚€€€€~ˆĄŤ§Ş˛łŤŸ“‹ˆsptxyz†ŒŒŠ‹ŒŠ…€~~|zxz~€‚…‡‡†„ƒ‚€}{{|||}‚ƒƒ„„„ƒ€}|}}˜ľĽœ­ŽĽ—„wyve]it{€„Ž›ž–Œ‚womopnr|…ŠŒŽ‘’އ~zvrquz}„‰ŒŒ‰‡…ƒ~zwwyx{|‰ˇĂĽŽ˝ŽŁqltiU\r}‡ŽŽ›Ş Ž‰‡~tjbittsŒ“•‘ŽŽƒwrrqqps|…ˆ‰Œ‹…|zvrsv{~€„ˆŞÉ­ĄľŠœ‘rclm_Zl}†’’”ŁĽ•‰ƒ~wnfcmutxƒŒ’“ŒŽ‹ywuutru}‚ƒ…ˆ‹‹‰„zxxy{}{†¨ąŁŞŻŹŤ›„}xgdgmy|x„”—”‘†xuxvrpqy‚€…‹Œˆ„„…ywyzzyy~ƒ„ƒ„†‡‡…~|œ”’™˜ž‘†‡ˆztpt{xtx„ˆ‡„ˆŒ‡ƒ‚‚~ywz||{z}‚„ƒ‚ƒ…†…€‚€}||~~}~€‚‚€ŒĄ“› –‡‡‹…}ysu}{vx}††ƒ‰‰†„„‚}{|~~||€‚€€ƒ„€€~€€~€˜’’””˜–Œ…††~xuz}{y{~‚…ƒ„‡†…‚€‚€}}}~~}}€€€€€€€€€€€€€ˆ’‘•‰ˆˆ‡‡ƒ~~€~}~‚€ƒ‚€‚€€€€€€€€€~|~~~€‚‚‚€‚€€‚‚‚ƒ„„„„ƒƒƒƒƒƒ€€€€ƒ„ƒ„††††„„„„ƒ‚‚‚‚ƒ‚€€€€€€€€€€€€€€€€€€€‚ƒ‚ƒ‚ƒ……††‡‡‡‡‡‡†††………†…„ƒƒƒ‚‚€€‚‚ƒ„„…††……„ƒƒ‚~~}|}}||{{|{{|z{|{{||}~~~€€€€€€€€€‚‚‚ƒƒƒƒƒ„„„„„„„ƒƒƒƒƒ‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€‚‚‚ƒƒƒƒƒƒƒƒƒƒ‚‚‚‚‚‚‚€€€€€€€€€€€€€€…‡‡‡‡ˆˆˆˆ‡‡‡††………„„ƒƒ‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€†ŒŠ…ƒƒ„„‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€Š—›œ—–”‘‡‚€~~~~€‚ƒƒƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚˜­ąˇ°˘Ą –Œ~okptuyy|‡‘’‡‡‡„€{uv{}~€†ŠŒ‹ˆ„~}{zyxxz~ƒ„…„„ƒƒ€~}|}„œŚŹŹ§ ™‘‰yroosx…‰ŽŒŠ‡…„ƒ‚‚‚ƒƒ„„„„„ƒƒ‚‚‚€€€€€€€€€‚„…‡‰ŠŠ‹ŠŠ‰ˆ‡††………„„„„„„ƒƒƒƒƒ‚‚‚‚€€€€€~~~~~~~~~~~~~~~~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ†‡ˆ‡…ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ…‡ˆ‡…ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒ„„ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~€€€€~€‚ƒ„ƒ‚‚‚~~~~|}~~~~€€€~€~}}€€€€~€€€‚ƒ‚€‚~€€‚‚~ƒƒ€€‚ƒ€€€‚‚~~~€}~~€~€€€€‚‚}}~€€}|}€€}~€‚‚€€€€€€€€€€}‚……„‚~|~€€~~„…„€|{~‚€€€ƒƒ€~~‚‚€€‚ƒ‚~‚‚€~‚‚ƒ‚€€€€€€€~}}}~€~||}~€|{|~€€}}~€€€€~{ywvvvvvtsrsuwvuuvvwxy{}~~€‚ƒƒƒƒ‚€€}{zzzyvvvwvtstuvvwxyzzxwxzyvtuvvwyzz{|~€€ƒƒ‚‚…‡‡†ˆ‰‰ˆ†………„„……‚}yy|~~ƒ„ƒ‚€~~~€‚€€€€€ƒ’źđ˙˙ňÇŠ¤ ’tWHLZixˆ—˘ŚĽ¤Ľ¤ ™‘‹‡ƒ€|{{{||}ƒ„„„……„ƒ‚‚€†œšĐŮÓȽˇŹ…|tokloruy}‚‡ŠŒŒŒŒŠˆ…ƒ~|{{{|}~€‚‚ƒƒƒ‚‚€€ƒ–¸ŘçáŃĹÁť­˜ƒume_]ajsy‡—™˜–“Œ…zwutssvz}‚„‡ˆˆ‡†…„‚€~}|…ŸÄßćŰĚĹÁ¸§‘~skc^]cmuz‰’˜™—•’Šƒ}yvsqrtx{~…ˆ‹‹Š‰ˆ‡…~|{}’żĺîÜŔ´ťşŠsd^VRYeqwzƒ”ٍ¤œ—•…zsomhgksz~…Œ‘’‹‰„zxwvy•ĆéíŘž¸Ŕ꧉pd\TQZbis€šš˜˜“Œƒ}xtnnrvy}†‰‰‰‰‡„~}{zz{|~‹ˇäíÝĘť˛ĄŒvcX[hw~‚•—™™–‘†}zxtrsvz|€…ˆˆˆˆ‡…‚|yxz|~€ƒƒ’żŰÔÎź–€zvqgcfiwžŸ™‰…zqmmov‡‰‹‹Š‰‡…zxvvy}€ƒ…††……ŒˇÓÎĘş—‚}{wvzwxˆ•˜ Ÿ…~urtuuy€…‰‹‡‚{xxww{~€„ˆˆ‡†ƒ}{zy‹ˇËĚҡ‹|n^bjjp~˜˘ŠĄ‘‡xiknmvˆ’‘ˆ}vtqsz}€†ˆ‡‰‰…~ywx‚ŚĹĎŐÁ–{i[bosw†Žœ§Ł—‰uffkp|ƒƒ‡Œ‘‹zsnqx|‚‡‡‡ˆ‡…„|yxv‚ĽŔĎŰÉĄ‡mY^hkuƒŒ›˘˘ ’}pidju{‰‹Œ‘‹‡€uqqrwƒ†‰‰‡‡…~{xv~™ˇÍăáČŻ‘reb`fpu|‰•›˘Ł™Ž„vlmmow}€†ŒŒŽŠƒ€{uvww{€ƒ‡†…†„€…ľÇÜÚŔޏpffdjuy~Š”˜ž –‹ƒvmopotwtv{}ŠŒ‹…ƒƒ~}yzzx{~‚“ŠśÄĚĂˇŹœ‰‚ysnfchmt€ˆ‹‘ŽŠˆ„|ywttxyz}‚……‡ˆ†„ƒ~~|”¤ąĂĆź´¨—‹ƒ|vnfbbcfkoqtwx|€‚„††……„„ƒƒ‚€€~~~€€‚™˘­ł˛°­¨ĽŁ ›–Š„}}}|{{{|~€‚‚‚‚‚‚‚‚‚€€€€€€€€€€€€€„š¤Ż˛°ŽŤ¨ŠŞ¨ĽŸ˜‘ŒŠ‰‰‰†ƒ~‚ƒ‚€‚ƒ‚€€€€€ƒŠ“Š°´śľłłł˛°ŹŚŸ™”‘Ž‹ˆ†ƒ€‚‚‚‚€€‚‚‚€€‚€€€€…А˜ŸŁ§ŠŞŞŹŹŹŤŠĽĄ˜”‘Š†‚|yxvvuuuuuvwyz|}~€‚ƒƒ„„„„„„„„ˆŽ”›ĄĽ§ŠŠŞŤŹŤŞ§ŁŸ›–“Œˆ…‚~|zyxwvvvvwxyz{|}~€‚ƒƒ„„„„„„„ƒ…‰“˜œŸ˘¤Ś¨ŠŞŠ¨Ľ˘Ÿœ™•’ŽŠ†ƒ€}{ywvutttuuvwxy{|~€‚ƒ„„……………†ŠŽŽŽŽŽŽŒŒ‹‹Š‰‰ˆˆ‡‡††………„„„ƒƒƒƒ‚‚‚‚‚€€€€€€€€€„ˆŠŠŠŠ‹‹‹‹ŠŠŠ‰‰ˆˆ‡‡‡††………„„„ƒƒƒƒ‚‚‚‚‚‚€€€€€€€€€€ƒˆŠ‰‹‹Š‰ŠŠ‰‰‰ˆ‡‡‡†………„„„ƒƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€†Š‰Š‹Š‰ŠŠŠ‰‰ˆ‡‡‡†………„„„„ƒƒƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€‹ŁŤˇłŻąŚœ—Œ„zxwx{|„„†‰‡‡‡…„‚€~~~}~‚ƒƒƒƒ‚‚€€~~~~~‰ĄŹ¸ĹśŽŹš—”ƒxl`^aipz‚‹‘’›˜‘…~|vqmifhmpuz|‚‡‹‘ŽŒŠ‡…€|yvtuuw†”žŤ­Š­ŹŞŞĄ“‡}tpmfbaafpw}ƒˆ”™›š—‘ŽŠ…€zsomlnpqtx|‡ŠŒŽŽŽŽŠ‡‚„•™ž—”˜———…}z{ysrtw~ƒ„„……ˆŠˆ…~|}}|{zz}€‚ƒƒ‚ƒ„„ƒ‚~~~~~}~€€‡šĽŞŽĽœ›—‘‹~qmnpuxwz‡Ž’‹‰‡†…€zwuvz||}~€…ˆˆ‡…‚‚‚}{z|~‚„‚‡žŻ´¸Ş—“Œƒ~qddmwƒ‹ŠŒ’”–“ˆ|wssvutw}ƒ‹ŽŒ‰‡„ƒ|xvvy}‚„†ˆˆ…‚}}}||{…˘´šźŤ–•Ž}uj\`nw‹Œ–˜’Žƒustrtwv{…ŠŽŠ„„‚~|yuv{~„ƒ„†‡†„€}{|}~€ƒ„ˆ ˝ÎÓĘą˜„wmhgkt„•ŁŤŤĽšŽƒxpjhioyƒŒ“••‘Œ…~xsqqsx}ƒˆ‹Œ‹‰†‚~zxwwxz|}‚„…‰–§°ˇš°Łš‘‡€{rkhikr{‡Œ‘’Œˆƒ|yvttuwx{‚„‡ˆˆˆ‡…ƒ}|{zz{|~€‚ƒ„„„„ƒ‡–ĽŽśšą¨Łœ•‘‹uoifjorv{~‚‡Œ‘’ŒŠ†‚€}zxvuuwy{}€‚ƒ…†‡‡‡†„‚~}|||||}~‡šŠ˛ź˝´Ź§Ÿ—’‰}slechlpu{~ƒ‰Ž‘””‘Ž‹‡ƒ€}ywuttvxy|~€‚„…†‡‡†…„‚€~}|||}}~ˆ™Ś°šš˛­Š˘œ˜ƒzsmkmnosvx}ƒ‡ŠŽŒ‹‰‡…‚}{yxyyz{}~‚ƒ„„„„ƒ‚€€~~}~~~~‚ŸŞ´š´ŤĽ”‹‚ysmikosx}€ƒ‡ŠŒŽ‹ˆ„}{zyxxz{}‚ƒ„„„„„ƒƒ‚€~}}}}~~€Šš§ąš¸ąŹŚž™”‹xqjikmptx{„ˆŒ‹‡…ƒ€}{yxxyz{}€‚ƒ„……„ƒ‚€€~~~}}~~€€ˆ™§°šš°¨˘™“ˆ}umfehmrx~ƒ‡Œ‘‘ŽŠ‡…‚€~}|{{|||}~€‚‚‚‚‚€€€€€€‚Š‘–˘Ł¤ŚĽŁĄ ™—”Œ‰†…„‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚…†ˆŠŒŽŒ‹‹Š‰ˆˆ‡‡‡†………„„„„ƒƒƒ‚‚‚‚‚‚€€€€€€€€€€€€€€€„†ˆŠŒŽŽŒ‹‹‰‡†…ƒ‚€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚ƒ„…††‡‡‡‡‡†……„ƒƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‹Š”˜˜œžĄš›™“‘‰‡‚}}zvutttstwxx{}~€ƒ…††‡‡‡‡††…„ƒ‚€~~}}|}||†‹‡——œœ˘ œ›–’‹‡ƒ}{zustrsttwyz}€‚„†‡ˆ‰‰‰‰ˆ‡†„ƒ€~}|{{zz{{||‚‹Žœ›žŁŸ¤¤››•ŽŠ†~ytvsorssvwz}€„‡‡ˆ‰‰‰‰‡††ƒ~||{{{z{|}}‘’‹›Ą›Ą ˘›”•“Šƒƒ~yxsswrrwyz}€ƒ…‡‡‰‹‰ˆ‰‡…ƒ|{{{zy{{|}~€‚„ƒŽœ”§ ž˘Ÿœ‘ˆ|y{uqqotuqv}~~‡‰‰‰Š‹‡‡ˆ„~~|zy{|z{~€ƒƒ„ƒ…›ŸŒœ­ žœœ”Œ„†…upxuoprwzz{ˆ†„Š‹‰ˆˆˆ„€€~yy{zyy{}~~‚„ƒƒ…„…‚‹Ą–Œ¤§œ››™‘‰ƒˆruysqqty{{}„Ї†Œ‹ˆ†‡…€}{}zvwzzzz}‚‚ƒ†‡†„…‡ƒŁ’§Śš˜˜š’‰ƒ}zkowsoqy~€„‹Š‰ŽŠ„„…{xxzwtvz|{|„„„…‡ˆ†ƒƒ„‚”ڐŞŞ—™œ‘ˆy}{kjsvspy‚ƒ…‡Š‘‹ŠŒ‹…~~~zwtvyxxy~‚‚‚…ˆ‰‡†††„€–ޤ• ´ş¤‘™ –„wy~xqmoy~zy}ˆŽ‡„ˆ†€‚„‚~yz}}{y{€€€„…‚ƒ„€•ŽŚ•œ˛źŚ– š†vx}ztkjt}~wuƒŒƒ‚Œ“Œ„…ˆ„}zz~zvx~‚~z}ƒ†ƒ€…†„ƒ›°Ľ–œľ˝Ľ’—˘‰z{~|vmkqz}vr}ŠŒ‚Š“…ƒ‰Œ†|~€~zwx|~{y{ƒ€~…‡ƒ„—¨Ą—œŽ´Ą”™Ÿ™‡~zrnoqtvsu|ƒ…ƒŠŒ‡‡‹‹†€}ywyzzxx{~~……„ƒˆ–›–‘—˘˘–‘–„}}|tpquwusw}‚€ƒ‰ŒŠ‡‡Š‹‡‚‚‚~zyz|{xy{~~}~ƒ„ƒ‚Š—›’‹š›•’—˜“‘“••“‘‘ŽŽŒ‹Œ‹‰‡ˆ‰ˆ‡‡ˆ†…„„„ƒ„„„ƒ‚‚ƒ‚€‚ƒƒ€€ƒ„„€‚„ƒ‚€‚……ƒ€‚‚~‚~|}€‚€~€€€~~~~~~€€€€‚€‚‚€€€€‚‚‚‚€€€~€€€ƒ„ƒ‚‚ƒƒ‚€€~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚~~€~€‚~€€€€€~‚~‚€€‚|ƒ‚€}‚€€~‚€~~ƒƒ€‚ƒ…ƒ||‚ƒ€€ƒ‚}„~}„‚„„ƒ€‚€}€€€€}‚€~€€~‚‚€‚‚‚€€€~}~€€€€€~~€}~€€~€ƒ‚~€ƒ‚€~‚‚ƒ~€~‚€€€€€€€€€€‚~~ƒ}‚‚‚‚‚~‚€}€~~€‚€~~€ƒ~}‚€€‚ƒ‚~‚€~~€}€€€}ƒ~„‚‚~€ƒ€ƒ€‚€€‚‚ƒ€€€~‚‚€€€‚~~€€‚‚}~‚‚ƒƒ„„‚……‚‚„…„‚ƒ„…„€‚…ƒ†…„„„†‰‰††ˆ‰‡…ƒ„ƒ€‚€€ƒ…†ˆ‰‡„…„~|~€~~~||€~z{|}~}€~}}€€€‚…„„‡ˆ‡†…„……‚€€€‚€€€€€€€€€€€şÁ™Œ˜˜…qnvƒ‹ƒ~‹–z€‚zx‡‡€~ƒ†‚}{~‚~}„ƒ~€‚€~~€‚‚€€~ťÁ™‹˜š…pnuˆœ”†‰Œ†xot‡…ƒ„‡Š‡}wy}€„‡…€||~€~‚„„~€~~ŽŔËŁŽs}|ii–ž™€„zpovƒŽ†„†…xtx†…‚ƒ„…{y{€‚€ƒ„}|~€†˛Ń´—‡u{oiz•ĄšŽ|„~pox†‘Ž…ƒ…~wtxƒ‰†„„€zx|ƒ„€ƒ„€|{~‚€~†˛Ď˛—ˆz€ni|—Ą—‹~‡}oozŠ‘‹…†}ut|‡‰‚~†…~xy€…ƒ~…ƒ~z|‚ƒ~€¤ĚŔŁ“„…‡uiv‘Ÿ™‚Š‚roxˆŠ€‡Švs{†ˆ|€‡ˆ€xx€…ƒ}|†…z|‚„€}}™ĂĆ­ž‘~lqˆš™…†Šyot‚Œ‰€~†Œ‡{ty‚†€z|…‰…|y~„„~z}„†‚||…‚~zŒľĆˇ¨™›Žwnz”ކ†‘”ˆyt{…‡z€Š„{y€†ƒ{y‡‡{|ƒ†{z„„|~ƒ„|ƒ śľŹŞŤŹ§˜‡„ŒŠ„„А‘‰ƒˆ‰ƒ~}†…€}€……~~„‚~}€ƒƒ€~~ƒ~~€‚€~† ľł­ŹŹŤĽ—ˆ…Œ‰…†‹‰‚€|ustpnqrqtxxy~~ƒ‚ƒ‚‚‚€€€€€‚’ĽŠ­źżˇšť°§§Ÿ’ƒ~€|xz|y{~~‚ƒƒ…ƒƒ„ƒ‚‚€€€€€€€€€€€€ŁŞŹšŔ¸ˇť˛§Ś ’Œƒ|}{vx{xy}~}ƒ‚ƒ…„ƒ„„‚‚ƒ€€€€€€€€€€€‹ŸŞŹľžşš˝śŤŠ¤˜‘އ~}xxzyx|~}€ƒ‚‚……„……ƒƒƒ‚€~~~~€€€€ˆ›ŞŹ˛ť¸´ş¸­ŠĽ˜„|zvppqoquvx|€„††ˆ‰ˆˆˆ‡…„ƒ€~}}}||}}}~€…—ŞŽł˝źˇ˝žł­Ťž’‘Š~zyqmpomruuy~€‚†‰‰ŠŒ‹ŠŠˆ†…ƒ‚€~~~~~~€€„•§ŻťÄžşšŻĽ˘™Ž‰ƒzwvrsvvx|~€ƒ……‡‡†‡†„ƒ‚€~~~~~~~~€€€‰”šŸ¤ŠŽ°­Ş¨ŚŁž™–•”‘ŽŽŽ‹Š‹Š‰ˆ‡‡†…„„„„ƒ‚‚‚‚‚‚€€€…ŠŠŒŽŽŽŽŽŒŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆˆ‡‡‡‡††††……………„„„„„„„ƒ‡ŒŽ‘’‘‘’‘‘ŽŒŒ‹‹‹Š‰‰‡‡‡††…„„„ƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€‚€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€‚€€‚€~‚€€€‚ƒ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€‚€€€€‚€‚€‚‚€€€€€€€€~€~~~~€~~€~€~€€€€€~~€€€€€€€€€€€€€€€€€~€~€~~€€€€€~€€~~€€€‚€‚€€€€‚€‚€€€€€€‚€€€€€~~€‚ƒ‚€~}~ƒ~~€‚ƒ‚€€€‚ƒ„}{|~‚€‚‚€€~~~€ƒƒ€€€€€€€€€€€‚ƒ‚€€€€~ƒ„…„‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‡ĽÂĎÔŤŠxnq|‡–˜•Š‚{yx{€„‡ˆˆ…‚~|}~€‚ƒ‚‚€€‡­ÎÎËŻ{aZ]p†ŽŒŽ“–Œ}rjju‚‹‡‚€|yx{…ˆˆ„~|~~€˘ÉĎÎťˆe[YiŒŽŒ’–ukhq‰Š„~}}{zz}…‡‡…~{|}~€€žČĎνŠfYSe~Œ•—•“Ž†{rlmv‹‘‹…|zzz{}€ƒ†‡†ƒ€}|||~¸ËČż˜tg`ivˆ”™—“‡yqnqy€†Š‹Šˆ„€|yxy}„…†…ƒ}}|~ƒŚČȧ~meit{„ˆ—˜”‹}tprx~„‡ˆ‰ˆ†‚~zyz|€‚„„„ƒ€~~}}€“žĘÁątmnuw}ƒ‰•˜•ytuy|€ƒ…ˆ‰‡„}{|}~‚ƒ„ƒ€~~~šÂ²Ÿ„zxzxox…Ž—“Œ†ƒƒ}yww~‚……„…„ƒ}||~€‚ƒ‚€~€~…­ČśŁ”†ƒxkbk‚‰‡ŠŽ”†}w{|yx|ƒ‡†„ƒ„ƒ€|{}€‚ƒƒ€‘˝˝Ÿ˜›˜ˆwpn|ˆŽš“‡‡‡„~xx|€€}‚ˆ‡ƒ‚‚€}|~€€‚ƒƒ¤ź˘”˘Ś’zy|z|wy†Œƒ‡‡{}}|{€…„‚†…€}~€€„€‹ŻŽ—˘Ž˘„‡‚~xt‚ˆˆˆƒ„„z~|}„„€„~~€‚}€›śĄ–ŤŽš……ˆ€{syˆƒ{Ž‹€‚‡…|}‚|{ƒ…~~‚ƒ‚}€‚€}€‹ŞŠ›­śŚ—•”‡‚~yƒ„|€Š‹ƒ„Іƒ~|€„~‚ƒ€€€~‚€~€˜ŻĄŸ´˛ ”˜’…ƒ~†ƒ€…Š‚‡Š…€‚€€~‚‚€ƒƒ€€‚€€€€€Š¤¨˘ŻşłĽ˘Ą•Žˆƒ††ƒƒ‰‡‡‹‰†ƒƒ‚€~€‚€€ƒ‚€€€€€€•ŞŁĽśš­˘Ł‘‹„{x{zsv|€…ƒ…„€€ƒ|~~}€~~‚€‚€~…›ŞŤŻźÄźśˇŻŁž›ˆ‹Šƒ‚ˆˆ„†‹ˆ…ˆ‰„‚…„€ƒ~ƒ€~‚‚€ƒŚ°°šÄÁşť¸ŞŸœ“…~wprurry}|†‡…ˆ‹ˆ†ˆ‡ƒƒ}}}{}}}€€‹¤˛ą¸ĹÄź˝źŽĄŸ—ˆ€€yoqtrtxyz‚„ˆŠŠ‹‹Š‰ˆ†„‚€~|{{z{{{}€”§´Ůřřý˙úřüäĎĐľ•”…mrsbgrjn€~Žˆ’•‹Ž’‡…‰|}w}}w|€ƒ•Ť¸ÇŐÖÖÚÔĘġ§•‰……‚„‹•ž¤ŚŞŹŠŚŁ›”‰‚€}{|€„‰‹Ž‘’’’”™Ÿ§ŻľťŔÄĆĆÄŔť´Ž¨˘œ˜•””•–˜›Ÿ  Ÿ›˜•‘Š†ƒ€}zxvtsrqqsw{€†‹”˜œŸĄŁ¤ĽĽĽ¤ŁĄŸš—•’Šˆ†ƒ‚€~}|{{zzzzzz{{{|}}ƒ‡Œ‘–šĄŁŚ¨¨ŠŠ¨§ĽŁĄžœ™–“‹ˆ†ƒ€~}|{zzzzzzzz{{|}}~‚…‡‹Ž‘”—™œžŸ ĄĄĄĄ Ÿœš—•’Šˆ…ƒ€~|zywvutsssssttuvwx{~…‰”—š ˘ŁĽĽŚŚŚĽĽ¤˘ĄŸ›™–”‘Šˆ†„‚€~}{{{|~€ƒƒ„„‚ƒ…„~}‚€}~‚„ƒ‚‚ƒ‚|||yvxzyxz|}€€„‡„ƒƒ„„‚€€‚~~~€€ƒ„‚…ˆ†ˆ†„……ƒƒ‚‚‚ƒ€‚€€ƒƒ‚‚€‚ƒ~‚€“Ś ŸŞŽŽŚ™““‹ypppmjjs~€€†”“Ž…}|{xspsxyy{‚†‡†ˆŠ‹ˆ„–¨žš¤§§ ’Šyqttsonw‚€…Ž‘‹‰Œ‹ƒ|||zusv{|z|‚†‡…†ˆ‰†–˛Ś›ŹąŤ˘‘†‡ƒm`jqmns~“ސ›’‰…‚~ujkrsps}…ŠŠ‹”‡ƒƒyss’Š™™˛šł¨™“”ˆlaklccjxˆ‹‰’˘˘–Ž‹ƒvjkpmhmy‚‡ˆŒ”™“‹ˆ‡‚xrm}¤ŸŠŚš˛Ž‘•‘x^epgbfp…ŠŒ§Œ‰†|jdmpjis€‰ŒŒ–˜„€{tlnr}¤Ž’ŚÁľ¨šŒ‡s_Ugphn|‹˜š—˜œŽ}yxqhbfouw{†‘“‘‘’‘Š€zyvqnnvx‚Ť´œ°Â˛Š›‹ƒ{nYZihfsŠ–™—Ÿ§‘މ‚|rjmrnlt|…‡‰’‰‰ˆƒ~zwzwz—ŁšŁ°ąŻ¨œ”•Štormkkks€‚€‰““‘“–”’ŒŒ‰‡ˆˆ‡††…„ƒ}zzxvuuttuuvvwyxz|{|~~~€‚‚…†„…†…‚€€€~{{{zxz{|}}}€ƒ‚‚„„ƒ„„……„†††‡†††………„…ƒƒƒ€€€€€€€€‚‚€€€€‚‚‚‚€‚€€€€€€€€€€€‚€€€~~}~}}~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚€€€€~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€}|~}{z{}}|~€€~€€€€€€€€€€€€€~~€€‚‚€‚ƒ€€€€}€‚~~€~~€‚~€€€~€‚~€‚‚‚€€~€‚~€~€‚~‚ƒƒ„ƒ€ƒ…ƒ€‚„‚€„€‚‚‚ƒƒ‚‚„ƒ‚~€~€€€€€€€€‚€~€€€‚„€ƒ‚€€€€‚—ŤŞ¨Żł°¤—‰ƒwprwyz}ƒŠ‹Š‹‹‡‚~}{yy|€„…„ƒ‚‚‚€~~~~~~€€€Ž§Ź¨Źł˛¨›‰†{qpuyy{ˆŒŠ‹Œ‰ƒ~}|zy{ƒ…‡‡…ƒƒ‚|{{||}~€ƒƒ„‚ł˛›¤ŹŁ˜†usxm`gv~ƒ†Œ—ž˜Ž‹Šƒxolorrs{…‹Ž‡|zvrqsy}‚‡‹Œˆ‰ƒ’şŚƒ Ś“Ž{pzsdu‰‡…ˆ‰”˜ˆ|€…}spt|€{{…Ž‹…„†‡ƒzvz~{xz€……‚ƒ†ˆ„~}ŽľĄ„ŁŤ˜‘€v|€r`p…‚„‰”™Œ€„Ёsqty|xv€‹Š„…‰Š†z|{vw}€†ˆ†€ƒ€”ą˜Š§Ł”ށy|pew„~€†‰‘”Ё†‰~uuuwywv|…†ƒ„ˆ‰ˆ„€€~zx{}~}~€ƒ…ƒ‚„„˛™’Ľ¤œƒ~|tfp}}}~„‘އ†Œˆzy{{xvxƒ‚„‡ˆ†‚‚‚~}}||||||}~}ƒ˜¤ž˘­­ŠŤŤ˘›ž™Ž‹Œ…{{~z~~}‚ƒ„‚€‚„€€ƒ‚€‚€~~€€€†¤¤ŽŹ¨ŤŞŸ›ž—ŒŒŒ„‚z{€}z}~ƒ‚‚…‚€ƒƒ€€ƒ€~€€€‰Ą¨ĄŤ´Ş§°Ť››œ†‰…{z~yuz}yy€€}…ƒ…†‚‚…ƒ€‚‚~€~€~€€€€”Ľ˘¤ł°§Ž°˘œ —ŠŒŒ}‚x{€{z|€…„…€…‚‚ƒ~‚€}€‚~~‚€~€‚ˆ›Ľ˘Š˛ŹŞąŹĄž“Љ†}z|ytw{xx~}€„ƒ‚†‡ƒ„†„ƒƒ}€}}~|}}}~~ˆš§ąşźšˇ˛ŤĽ ˜’Žˆ„‚~~~}‚‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€‚šŁŤŻą˛ą­¨Ł™•’ŽŒ‹‹ŠŠ‰ˆ‡†……„ƒƒƒ‚‚‚‚€€€€€€€€€€€€€€€…‡‰‹ŒŽŽŽŽŽŒŒ‹‹ŠŠŠ‰‰ˆˆˆ‡‡‡†††…………„„„„„ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚„ˆ‰‹ŽŽŽŒŒŒŠŠŠ‰‰ˆˆˆ‡‡‡†‡†††…†………„…ƒƒ„ƒ‚ƒ‚‚ƒ‚‚ƒ‚ƒƒ‚‚ƒ‚‚€‚€€€€€€€€€€€€€€€€€€‚€€€€€‚ƒƒ‚ƒ‚€~€€€~~}~}€~~‚€€€~€€~}}‚‚€€~€€}€€~€€€ƒƒ€‚‚€€}€‚ƒ€~€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~€€€€~€€€€€€€€€‚€€€€€€€€€€~€€~~€€€€€€€€€€€~€€€€€‚€€€€€€€€€€€€€€€€€€‚€‚ƒ‚ƒ‚ƒ‚ƒƒƒƒƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒ‚ƒƒ‚‚‚‚€}}}||{zzyzyyyyyyzzyzyzzyzz{{{||}|||{||||||||{}||}}}}}}~~€€€€€~~}}}}}~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‰”ŸŹ´śˇ˛Ť¤›’Š‚zuqoqtx}‚†‹Ž‘‘Ž‹‡ƒ|xvuuvxz}€ƒ…‡‰‰‰ˆ‡…ƒ€~|{yzy~’˘Ş´˛ŠŹŤ¤˘–‚xoijifgjpz…‹’‘“—“‹‚}|ywvsrux|€ƒ„†ˆŠŠŠˆ…ƒ€~~{yyxƒ˜¤ŹłŹ¨Ť§˘œŒ}unkljhjovˆŒŠ‡†‚|xtsux{~„†ˆˆ‡…‚}|{{{{}€ƒ„„„…žś¸ź´™’|vgdksŠŽ‘”’‘yuqrvwy}…ŠŒ‹‰†‚~{yxxz}€‚„………„ƒ‚~{†¤ľˇ˝Ź——‹{yqm|‹“™˜ˆ†€xvss}†‰Œ…„ƒ}zywyƒ…‡†ƒ‚~||z|€‚ƒ„ƒ‚€~˜ĆŇÎÓw{nktlrŸ§¨˜‚wvrptrw‰“”•Š}{yvwxw}†‹Œ‹„~}|z{|}‚†‡…‚}|~}ƒ°ŰÖŨxjtqry‚’Ľ­Ÿ†vnlv|z‚Œ‘•‚vruy}‚…Š‹†€zvy}€‚„……ƒ|{|~‚•ČÝĘśkowsx~‰›Š§’{rlq||}‡Ž’’‰}xy{{}€…Љ„}|}}}‚……ƒ€~~~~€‚‚„ŞÍˇ™†tx|vr{‘™€z}|wu{…‡€}{y|††ƒ€€}|}€‚ƒ‚€€~€‚€‚Ž˝ÉŠ’~u||spšŸ–Š|{|us}‰„~€}yx|ƒˆ‡‚€€|{}„ƒ€€~}~‚‚–ĆĘĽ|v|zqp†žŸ•‡{{zss€ŒŒƒ~€|wx~…‰†€~{{~‚„ƒ€~}~€‚„ŤË°“„y||unsŒš˜…€yrt~‡‹‰„ƒƒ‚~yx|„„‚‚ƒƒ€}|}‚‚~~€žĆŁŽx|yrm{”š–Œ‚€}uqx‚ˆˆ…ƒƒ„€{y{‚‚ƒƒ~}~€€€‚€€€ĄĹ´™Œ€€wnuŠ““…„…yuy€…†„ƒ„…}{|€‚ƒ~~€€€€€€€€€‰łĆˇŠ™Œ‹Š~v‚‹Ž‘‹„…ˆƒ~~~…„ƒ‚€~€€€€€€€€€€€€€€€€€€€€€’˛ś¨‰‰†{z…‰ŒŒ†ƒ……€~‚„‚€‚€~€€€€€€€€€€€€€€€€€€€€€„™ŞŤ¨¤Ÿš”‹‰“œŸŸš—‘ˆ„ˆŒ‘‘‘‘Œ†‚‚„†‡ˆŠ‹‰…€€‚ƒ…‡†„€€€€€‚„„ƒ‚€‹ĄŤŠ§ŁŸš‘Š—žžœš–ކ†Š‹‹ŽŠ‡‡‡††ˆˆˆˆ†………„„…………„„„ƒƒƒƒƒƒƒƒ‚ƒ…’—–™š—•“’•””—–””’ŒŒ‹‹‹‹ŠŠŠ‰‰‰ˆ‡ˆ‡‡‡††††………„……„„„„ƒ„™—”›™•œš–——”’”’‰Œ‹†‡ˆ…„‡…‚…„‚‚€€~~€€~€~€~€‚€€ƒƒ€ƒ…‚…„‚€„ƒ€„„ƒ€€‚‚‚€€~€€€~€€€~‚€}‚€€€€ƒ€„ƒ€€€‚€€~€}€}€~€‚‚|€‚~‚€€‚€‚€~‚~‚€€€€}ƒ}€‚‚€~„€~€€€€~ƒ€|ƒ€|ƒ~‚‚€€€€€€‚€~‚}€ƒ~„~~‚~€€‚}„|‚€€€ƒ~€…{„|‚‚€€‚€‚‚€€‚‚‚{‚ƒzƒ„zƒƒ}‚‚‚€}‚}‚|€ƒ}‚~‚}„|€…x‚…y‚„~„€{„‚zƒ}‚€}‚‚}„~„~}…{€ƒ‚~ƒ~ƒ‚z†z†‚ƒ~€„|‚ƒ{‚‚~‚‚|€‚‚~~ƒ€€€€~€„{ƒ{‚€~ƒ€ƒ~ƒ~ƒ}~€~}‚ƒ{€…~~‚€~ƒ~~‚~€€~~„}}„~}€~‚€€€€ƒ{€…{„€€~‚‚}ƒ€|ƒ‚}ƒ}€‚€~€~ƒ|‚~€|„€{€†|‚„†ƒ€ƒ‚„€~ƒ‚€~ƒ|‚‚~€€€‚ƒ}…~}ƒ~€‚~€‚€€€€~‚‚~~‚~€„~‚„~€‚~€„|ƒ€ƒ~‚€€€€‚€€€€€€€‚€~‚€‚€€€€‚€~€€€€€€€~€€~€€~€~ƒ€‚~€€€€€€€€€‚‚‚‚€€€€€€€~€~~~~€€€€€€€€€€€€€€€€€€€€€€€‚‚€‚‚€‚‚‚‚‚‚ƒ„„„„„…„„ƒƒ„ƒƒ‚‚‚‚€€€€€€€€€€€€‚‚‚‚‚‚‚ƒƒ‚ƒƒƒƒ‚‚‚ƒ‚‚ƒ‚‚ƒƒƒ„„„„…………………„„„‚‚‚€€€€€‚‚€€€€~~€~}}€~€€€€€€€€€€€€€€€€€€€€€‡‹Œ‘“”•••””“’‘ŽŒ‹Š‰ˆ‡††…„„ƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€€€ƒ‹‘‘‘‘‘ŽŽŒŒ‹‹ŠŠ‰‰‰ˆˆ‡‡‡†††…………„„ƒƒ‚‚‚‚€€€€€€€€€ˆ™˘Ś¨˘›™››˜•ˆ††††…ƒ€€‚‚ƒ‚€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ž¤§ŚŸšš›™—“Œ‡†††‡†„ƒƒƒ„…„ƒ‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€Ž­ť˝ž­–ŽŠ„€yrw|€‡Š‡‡…ƒ„„€~~|}€€‚€‚‚€€€€€€€€€€€€€€€‡ŻÉČĚśŠwpgjsqlv„ŽžŠ ‘‡yprurswy‹’’‘‹{zxwyyy|…‰‹ˆ„~|||{{}~€ƒ†…„ƒ€›ÁĆÇÁ˜yskjuxqu„žŤĽshluww{~ƒ˜–†xpqux}~~‡‹‡~xuvz~€‚…ˆ‰†€~w†śÉĹĆĄrjigu~tp}Œ™ŤŹ•€rfgu{y{}Œ™™’…ujmt{€‚€‡ŒŽ…yqpt|‚„ƒ‚ƒ…‰‰„~vuu„ľŇËȧreeboyrq€”¤˛Ż“xh^bs{{~‡”Ÿmchs|‚„ƒ…‹‹rlnu†‡†…†ˆ‰†wsryźÔÇÄŁma_[jvw}ŸŞŻŚ‹ob[`q|€†Œ’™œ”„sgbiv€‡Š‹ŒŠvnlqzƒ‰‹Šˆ‡…‚}wtty‡ŹÓÓϡ€b[Ubtz‚ž¨ŤĽrd[^o|„Œ‘”—–rifmy‚ŠŽŒˆ‚{tpqw†‹‹‰‡ƒ|ywwz~ƒ‡Š¨ÉĚČą€c[Xg{ƒŠ•œ Ł™„qe^fv‹’’‘‹‚yqknu~‡ŽŒ‰„{wuuy~„ˆŠ‰†‚~|zy{|‚„‡…ŠŠżŔž xeZ]p€‰•–˜˜thelw„Ž’‘މƒ~ytrsx€‡Œ‹†|yxxz|€„†ˆ‡…}{z{|~‚„„ˆŠÍÔÖżŠngcv‹Ž••–—~ollv‰Ž‡€{zyx}„‰‰ˆƒ|{}|€‚ƒƒƒ~}}~€‚€€€~ˆŻĎÖŮš„ndby‹Œ•–˜˜Žznjjy‰ŽŒƒ€ƒ‚}xvz‚‡‰‰‚}|}~€~~„…ƒ}}}€‚€‚€ŽśÎÔШzibk‚‹Š‹Ž”š’~rjk{Š‡~ƒ„ƒyuy‡Šˆ||}€‚€~}~€ƒ„‚€~}~€€€‚—ťÉŃÜ~peo~ƒ‡Œ˜šxmq{…ˆ„„††„ƒ~xy{}‚…ƒ‚‚€€€~~}~€‚‚‚€€€€€€ƒ ŔÍŮÍŤ–…uvxty„‡™”Œ|}yy~~………‡„€|~}€€‚ƒ€€~€€€€€€€€†›ŤˇźŽœzzyx~‚†‹†€~}{}~~ƒƒ„…‚€~~€‚‚ƒ„……†††…„ƒ‚‚€€~‚„……††††„ƒ‚€€€~}{{{{{|zyyy{}€€€€€~}{{|~€€~~}}~~~}~€‚ƒ…„ƒƒ€‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€‚€€~€€‚€€€€€€€‚€€€€€€€€‚‚‚€€€~}~~~~~~~}~€€€~~€€€€€€€€€€‚€€€€€€€~~€~€€€€€€€€€€€~~~~~~€€‚‚‚‚ƒƒ‚ƒ‚‚‚‚‚‚‚€€€€€€€€€€€~€€‚€ƒ‚ƒ‚ƒ‚‚‚ƒ‚€€€€‰“ŸŤ´śˇ˛Ť¤›’Šƒ|wtrsux{‚…‡‰‰‰ˆ‡…ƒ€~}}||}}~€‚‚‚‚‚€€€€€€€€„“Ą­ˇˇąŹ¤—wmffhkqv{ƒ‰”—–•’Ž‹†€zurppqsux|…ˆ‹ŒŒŒ‹‰†ƒ|zxwwwxz|~ƒ……Ł­łˇ­ŚŚŸ™“ƒunihlllou|†Ž‘’“’‘‘‡{wutssstx}„‡ˆ‰ŠŠŠˆ…‚}{zyy{|‚ƒ„„…ƒ…ľśşł™’}vgekt~ŠŽ‘“‘‘Œzvrsvwy}…ŠŒŠˆ†‚€~{yyxz}€‚„…………ƒ€~|||}~‚ŒŤşťżŹ–”Š}zmadlvƒ••“‘‰}zyy„„†‰ˆˆ‡|zz{ƒ…„„ƒ}}|}€€‚‚‚‚~~~~€›ËŐĎÒtxlitmsĄ¨¨˜uuqotsxŠ”••Š|zyuwxw}‡ŒŒ‹„}||y{{{€…‡‡†~~}|}~€‚…„‚€„ŽŘŃż¤xmxvuz‘˘Ş„vpnx}z‹“ށvsv{~‚„ŠŠ…€zwz~€‚ƒ„…ƒ|{|~‚‚‚~}“ÇÝËş“mpupu}ˆšŠ¨“}slpz{~‹’’Œyvyzz~ƒˆŠ‡}||||~„…„~~~~€‚‚‚€€~€ƒŤÎ¸š‡ux{tpz‘žš{~{vuz…‡}zy|††„€}|}€‚ƒ‚€€~~~€€€žÎ­’€uzzsn€šĄ˜‹}z~{tr}Аކ€}xw|ƒˆ‡ƒ€€|z}„„€€~}~€‚‚€€~~€ŸĚÄ ‹yv{xpr‹ ž“…|}~yrs~‰ŽŒ…‚~xw{……ƒ‚ƒƒ€}{|‚‚‚~~€€€€‚€€~€‡´ÉŞ’ƒy|zsmv™—„~wqv€ˆ‹ˆ„ƒƒ‚}xy|„ƒ‚‚ƒ‚€}|}€€€‚‚~€€€€€€€~—Áť‚€yor†’“†„…ƒ{ux~„†„ƒ„…‚~{|~€‚ƒ‚€~~€€€€€€€€€€€€€€€€ƒŞĆŽ–‰€skxŠŒ‡€‚…zz}€…„€€‚‚€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€‹­¸ŤŸ’‰‰‡}yƒ‰Œ‡ƒ„†~~~„ƒ€‚€~€€€€€€€€€€€€€€€€€€€€€€€€€€‹˘ŹŠ§˘˜‰Œ—žŸžœ™•……ŠŽ‘‘‘Šƒƒ…†ˆ‰‹Š‡ƒ€€‚„†‡…ƒ€€€€ƒ„„‚€€€€‚‚„•¨Ź¨¤Ÿš–‘‘˜œœ›˜•’’“’“””’’ŽŽŒŒŒ‹ŠŠ‰‰‰‰ˆˆˆ‡‡‡††††……………„„„„„„ƒ„ƒ†“˜—š›˜–”‘“–••——””’‘‘‘ŒŒ‹‹‹ŠŠŠ‰‰‰ˆˆ‡†‡……†ƒƒƒ‚‚ƒƒƒƒ‚ƒ‚ƒ€‚€‚‚€ƒ‚‚‚‚€€€‚‚‚ƒ„‚ƒ„‚ƒ‚ƒ‚€‚~ƒ€€‚‚€ƒ„€„†ƒƒ„ƒ‚ƒ„€‚„ƒ~‚€‚€‚€~€€‚ƒ€€€€€~‚‚~€€‚‚~ƒ€€„}‚‚~ƒƒ~‚€ƒ€€‚€€€€~ƒ}€„}€ƒ€‚€€‚‚‚~‚~€€~€€~‚}€ƒ{‚~‚€}‚€€€‚€‚~ƒ€€€ƒ~‚}„~„}€‚~€€‚€}‚~ƒ}‚~‚‚~~‚|ƒ|„€‚~‚€€ƒ}‚|ƒƒ|€‚~…~|‡~z†z„‚{„|„{ƒ‚|‚‚}‚~€„{€…y€…}ƒ€}‚€~ƒ|€…y‚…zƒ~ƒ|‚}‚ƒ~ƒ€€‚}‚{‚‚}~‚€€€~‚€ƒ}€ƒ|‚‚|‚€€€|ƒƒx„„x„‚{ƒ€€ƒ}ƒ€|ƒ€‚~€~„€€ƒ~„}|…}ƒ}ƒ}„ƒ€~€~€„}…~}…}„€}„{‚‚|ƒ‚|€ƒ~~„}„~ƒ}‚}€ƒ~„}„~€€€€€‚€~€€€€€€€€}€‚~€€€~€€€€€€‚~€ƒ~€ƒ‚‚ƒƒ„„€~~}|~}~~€€€}~~ƒƒ‚ƒ‚~}|€~€€€€€‚‚€‚€€ƒ€ƒ~„€~ƒ~‚‚~‚€‚€‚ƒ‚~~ƒ€€~‚€€~€€‚~~‚~‚~ƒ€€€‚~€}‚ƒ~€ƒ€ƒ€‚‚‚€~€}€€~‚€€ƒ€‚ƒ€‚€}€~€€€€€€€‚~€‚€‚ƒ€~€~~€€€ƒ€‚ƒ€ƒ‚~€€€~}}||}}|}~~€€‚„’œŁŹŹ¨Š§˘ž—Œƒ}uqpmkmosx~‚†ŠŒŽŒ‰…ƒ|zxvvvwy{}ƒ…†‡‡‡†…„‚€~}|}|ŸŞ´´­Š¤ž—Œ}phdeilou|…–™™—“‹…~wqmmnqtx|‚‡‹Ž‘ŽŠ‡‚}zwtsrrsux{‚‘Ś­śž˛ąľŞ§˘Ž‚zmjicacdhs{€ˆ–™˜™–Ž‹‡~{vssqrvwy}~…†ˆ‰‰‡‡†„ƒ~~|{{~ĄŽźŔź˝ťśľ­‘ƒwrojhfcfms|„‡Œ“”“Œ†‚{ywutttwz|‚ƒ…‡‡ˆˆ‡…„‚€}}{„˜Ł˛Á˝şšŻ­Ź —‹{qmiikjkosz„‰‘‘‘’Ž‹†€}zxyyz|~‚„…††…„ƒ€~}}}}~€“­šËĐ˝ˇŤ—”Œ{ulbelq{„‡‹‘”Š‡zzwvxxx|~€„††‡†„„ƒ€~||||}€‚‚ƒ†Ÿą˝ÎĆśąžŽrqjgu€Š›Ąœ”…€{qqqms{~ˆ‘‘’‘ˆ~wtvtu{~ˆŠŠŒˆƒ|xxxw|}…¨ÉŢöëĤzUONPbouˆš¤´ťŽŸŒo_ZU]lt€”š˘ž–qjdcls{†•”Œ…{uqloux‚ˆąŃáó纒c60:Ks’ŸŻ°Ľ¤Ÿ’Œ~g\SO_t‡ŸŤŠ¤—„ypijmmsy~‰’–™–Œ‚xnklpx€…‰Œ‹­ÉŮëŢł_87BW~˜˘ŹŠœ˜ŽŠ~j`XUdwŠŸŠĽŸ‘vpknqqv{ˆ”–“Š€wnlos{‚…‰‹Œ­ŃĚġˆa][^s†‰–š˜˜”…tnihr…ŠŠ‰†€zxutx~‚†‰‰†„‚~|{{z|ƒ„…„‚‚~‘žÍĹĹŚvfd^h|ƒ„Œ–—˜š‘tnilx€„‹Ž‹Š‰…{xuuz~‚†ˆ‡…„~}|{{}ƒ„„ƒƒ€…­ÍÇơ†he_bu‚ƒˆ’–—š—ˆzrjir{ˆŒŒŠŠ‡ƒ{wuw{ƒ‡‡‡…ƒ€}|{|}ƒ„„ƒ‚€›ÄĘČěrf^]n~ƒ‡Ž“•˜šwnhmw~…‹ŒŠŠˆ…}yuvy|†‡‡†„~||||~€‚„ƒ„‚ˆŻËČɡ‡jc[bu…Š‘”–š—‰|sjhqzˆŒŒŠ‰‡ƒ{wuwz~ƒ‡ˆ‡†„‚€~|{{|}€‚‚„‚šČÁÇŻ„vnchrw{‚Ž•–›˜Š{qosvz„‡‰‹‹‡ƒ€{xyy{~‚„……„‚}}}|~€‚–ÁČĂǧ€vkairw{ƒ•—œ–ˆ€yposvz€…ˆŠŒ‹†ƒzxyy{~ƒ„……„‚}}||~‚‚ŸĆĆĹĝ|thbksx}†’–˜“†woortw{€„‡Œ‰‡ƒ~{zzz{}~€‚………„‚€~~}~~~›ÄËĚʨ†zroprrmpŒ• Ÿ’ˆzxxywtw{‡ŒŒŠ†‚}~}{{{{~‚„……„‚€€~~}€ŁČĘÍĆ ‚xqoqsrlsƒ—Ąœ†yxyyvtx{€ˆŒ‰†~~~}{{{|‚„……ƒ€€€~~|‰łËÍĐ˝œ‡€ƒ‚|ym`gv…“š—ƒƒ†‡Š‡|rorzˆˆ‚€…‰ˆ„}yy{ƒƒ€~|~„†„~}—ÁÎĐË­€„‚}xg`l|Œ™›“†ƒ†‰‹ƒwpou~…І€}~‚‡Š‡{xy|‚„ƒ}|~‚…†‚€|‚ŞĘÎŃÁŸ‡}…{o^^ix‡ŽŠƒ‰‘†}uuz}|zy|‚†ˆ†‚~‚ƒƒ€}||~€‚€~°ÁĆơ¤–’–‡€qfhp{‚…†‚€†ŠŽ‹…~z|~€~{zz‚„…ƒ€€€‚ƒƒ‚}}~~…¤˝ĂĆ˝Ťœ“•”‰‚wigmv}~~|y~‡’Œ‡ƒ…ˆ‰ˆƒ}yxz~€}zz|€ƒ„ƒ„…„‚~~€Œž§ŞŞĽĄžĄŁž–‚{yz|zvsqsx~‚„ƒ‚‚„‡ŠŠˆ„€€‚~|{{}€€~~€ƒƒ‚€€Š›ĽŠŤ¨ŁŸ™“Œƒ|xtsqonlmorvy|~€‚…ˆ‰ŠŠ‰‰ˆ‡†„ƒ~}||{{{{||}~€€ƒ‹—ĄŞŻąą°°°ŽŞŁ›“Œ†|xspmmmoqsvx{‚…‡ˆ‰ŠŠŠŠ‰ˆ†„ƒ€~}||{{{{||}}~€…•¤ŞŽ°˛łąŻŤŚ ›•‰„{xutssstvwy{~ƒ„…†††††…„ƒƒ‚€~~~~~~~~€„Œ”œŁŠŹŻą˛ąŻ­ŞŚ˘ž™”‹‡ƒ|ywusrqqqqqrsuvwyz|}~€‚ƒ„„„„…„„„„ƒƒƒ‚‚„‡Š‘”—™›œžžžœ™˜–“’ŽŒŠ‰ˆ††…„ƒ‚‚€€€€€€€€€€€€€€€€€€€‚„†ˆŠŠ‹‹‹‹‹‹‹‹ŠŠŠ‰‰ˆˆˆ‡‡†††………„„„„ƒƒƒƒƒ‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚€~€€€€€€€€‚€‚‚€€€€‚‚€‚‚~€‚‚€€€~~€€€€€€€‚‚‚€€€€€€€€€€€€€€€€€€€€€‚‚€‚€€~~€~€€€€€€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~~~~~~~~~€€€€€~~€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€~€€€€€€‚€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€~~~€€€‚€€€~€€€€€€€€€€‚‚‚‚€€€€€€€€€€‚‚€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€‚€‚‚€‚€€‚‚€‚€€‚€€€€€‚‚„ƒ„…ƒ„ƒ‚‚€€~~}}}|}|}|}}{~}}~|~~~€€€€€~~€€€€€€‚ƒƒ„ƒ„Ž˜˘Żľśś°¨Ą™ˆzwtstvy}€ƒ†ˆ‰‰‰ˆ†…ƒ~}}|}}~€‚‚‚‚€€€€žŞś¸˛Ž§Ÿ™ƒyofegiouyˆŽ”—–•‘Œˆƒ|wrnmnoruy}‚†ŠŽŒ‹ˆ…‚~{xvvvvxy~¤­ˇ¸ŻŽ­ĽŸ”umgghfgkr{†Ž‘”••–•‰‚{wurqpprw{€„‡ˆŠŒŒ‹‰†‚€}{zxwwyz~ŁŤľˇŞ˘›ƒ{nghls}…А”””‘‰‚|vsssuy}†Š‹‹‰†ƒ}zyxy{}‚„……†„ƒ~|}{‚Ÿľ¸ż´œ˜‘ƒ~scbhq}‰Ž“•””Ž‚{uqruuw|€…‹‹Š‡ƒ~{yxy~‚…†…ƒ‚€}|{}„ƒŽşŐĎĘĽwurhsso…œŚŠŸˆvtsptuuƒ’”•€yyvvyx{„‹ŒŒ‡||zz|{~„†‡‡ƒ~~}|}}~•ĆŘŃțuwngrmp‹ ŠŞœ„vttrw}‚™“Ёwtwz{~„ˆ‹‹…}zyz}€‚…†…‚~{{}€‚‚„ƒœÍ×IJˆktwty€‹œ¨¤zrms}|~ˆŽ’‘†zsuy|€‚ƒˆŠ‡‚|xx|‚ƒ„„„}{|}€ƒ‚‚‚§Ëśš‡vz~vqzœ™|~}zw|†ŒŽˆ€~|z}…†„€€}|~€‚ƒ‚€€€~~€€€€~˝ĘŞ“u|zrr‚˜–Š}|~zuv~‰Ž‹„€€|yy}ƒ‡†‚€~|{~ƒƒ~}~€€€€~žĚÄ ‹zw|xoqŠ ž“…{}xqu‚‹‚~€€{wx†‰†€~{{~ƒ„ƒ€}}‚€€€~…łÉŞ’ƒy}{tlvŽ™—„€xquˆ‹ˆ„ƒƒ‚}yx|„ƒ‚‚ƒƒ€}|}‚‚~~€€€‚•Ăż‹|y}yqn€–™”Ё€|urzƒŠŠ†ƒƒƒ€{x{‚ƒ‚‚ƒƒ~}}€€€‚‚€€€€€€€€ƒŞĆ­–‰uny”’‹„„…€xuz††ƒƒ„„}{|€ƒƒ~€€€€€€€€€€€€~źŔŚ›…Їyv†ŒŽ†…‡€|~‚†‚ƒ€~‚€€€€€€€€€€€€€€€€€€€€€€€€€˜śłŚš‰Š„y|†Š‹…ƒ†…~~ƒ„‚€‚‚~€€€€€€~€€€€€€€€€€€€€€€€„™ŞŤ¨¤Ÿš“‹‰“œŸŸš—‘ˆ„ˆŒ‘‘‘‘Œ†‚‚„†‡‰Š‹‰…€€‚ƒ…‡†„‚€€€‚ƒ„ƒ‚€‹ŁŽŹ¨Ł˜ˆ‹˜žžĄĄžš•’”“”——•”‘ŽŽŽŽŽŒ‹‹Š‰ŠŠ‰‰‰ˆˆˆ‡‡‡††††…………„…„†‘™˜šœ™—•’“––•˜˜••“‘‘‘‘ŽŒ‹ŒŒ‹ŠŠ‰‰‰ˆˆˆ‡‡‡‡††††…„†„„†ƒ…†ƒ†…„†„…„„†„…†ƒƒƒƒ‚‚ƒ‚‚‚‚‚‚‚‚ƒƒ€„„€‚ƒ‚ƒƒ„‚ƒƒ‚„ƒƒ‚€ƒ€ƒ~‚‚‚ƒ‚‚€‚€€€~‚~~‚~~€‚€€ƒ}‚}‚€€€‚€‚}€‚~€~ƒ~~~~€€€~€€~‚}‚€€€‚~€‚~€€€~€ƒ}„}€ƒ}€‚€}‚}‚€€€}ƒ€~‚€€€~„~ƒ{ƒ‚|ƒ‚€ƒ~‚‚€~‚‚{ƒƒy„‚|ƒ‚~ƒ}…|~„|…~~„|ƒ|ƒ|ƒ€~„~}„|…€{†€|„€~‚~„|ƒ|„|ƒ|ƒ}~ƒ}‚~€~‚€}„~}†|~ƒ}‚zƒ‚|€‚€~ƒ}†|}ˆ{}‡~}„}‚ƒ}€ƒ~ƒ~}„|‚€}€‚~€‚}€‚}€ƒ|‚€€€€‚~‚~€‚}‚}€~‚~‚‚}ƒ~„}€ƒ}ƒ~…}€~ƒ~„~ƒ}€ƒ~€€€‚€~€‚~€€€€€€€‚€~€~‚€‚€‚ƒ~€~€‚€€~€€€€€‚€€‚€€€‚~‚€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒƒƒ‚€‚€‚€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€~€}€€}€}€~€}€}€~}€~|}}~}}}}}~€~€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€~€€€€€€€€€€€€€€~€€€€‚€€ƒ€‚€€€€~€~€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚ƒ„……„ƒƒ‚€~}}|}}}}~~~}}~~~‚‚ƒƒ‚€€€€€}~~}}}~}}}}~|~€‚ƒ…ƒ„‡‡„ƒ…‡ˆ†‚…ˆ‡…„„†ˆ‡…†‰Š‰‰‡ˆŠˆ†„…†…ƒ‚‚‚€€€€€€€€}€‚~}€€€€‚„ƒ~…€€ƒƒ€€‚ƒ€‚€€ƒ‚ƒ„‚ƒ„‚‚‚‚‚}€ƒ~‚„„‚‚‚‚€~€}€}~}~€„‚„„ƒ‚~€~}€€‚‚€€€€€‘ˆš”‘Žˆ€~€{tvzxxz~‚‚‚†‰ˆ…†‡„~|z{}|{~€‚ƒ„ƒƒƒƒ‚€Š’ˆ‹–’ŽŒŒ‰~~ww{zz{~‚ƒ„ˆ‡„…†„}{|}}|}€ƒƒƒ‚‚„€‰Ą™¨ŞŸŸ›˜”ˆ}~~qkstrty€…„†Ž‹‰ŒŠ…€~~{wvyzxz~‚…ˆˆ‡ˆŠˆ‡—ž’œŠ˘ŁĄž˘™Ž‹‚zwxtnorutu|ƒˆŒŒŠ‹‹‡……ƒ||{ywxzyy{†š™–ŞŽŠ­ŠŠ¨š“’ˆ}vsoifgjkkqx{~„‰Ž’’ŽŠ…‚}ywvvtuuxzz‹˜Ž›ŽĽŠŻ§­Ś—›–†|vrkiljhlruv{„†ˆŒŒ‹Œˆ†…ƒzz~ywzz{|‹–Œ›ŹŁŞŽ¨°§›˘šŒŠ„zrqrnlosrrx|~€‡‰†‰‹‰ˆ‡‡‡ƒ‚€}}|}z~އ…š•• —Ÿ˘“›œ‘‡ˆ|~yvvvuuvwyz{€ƒ„…†…†‡………„‚€|ƒŠ‡“‹”–“Ž“ŠŠ‰„‚€||zvyxuxxx{{}€€„„„††††………ƒ‚‚€}|}‚‚„„†ˆ‡ˆŠ‰Š‹Š‹‹‰ŠŠˆˆ‡††…ƒ„‚€~~}}~}}}}}~}~~~‚ƒƒ‡ˆ‰‹‹Ž‘ŽŒ‹Š‰ˆˆ‡††…„„ƒƒ‚‚‚€€€€€€€€€€€‚‚‚„„„†…††††††††……………„„„ƒƒƒ‚‚‚‚‚€€€€€€€€€€€€€€ƒ‚ƒ„„………………„„„ƒƒƒ‚€€€€~€€€€‚‚‚‚€€€€~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ‡‹‘ŽŒ‹Š‰ˆ‰‰ŠŠ‰‰ˆˆ‡‡†………„……„„ƒƒƒ‚‚€€€€€€€€€‚€€€~€~€€€€€€€€€€€€€€€€€€€€€€€€‚€€‚‚€€€€€~‚€~ƒ‚€€€‚~€‚~€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒƒ„„€€€€‚}}{~}~}|~€‚ƒ‚€‚€|~}€‚‚„ƒ‚„‚~}zzyz{zz|~~}‚~|}~}~}}€~|}€~|‚ƒ…ˆŠ‰‡‰Š‡„€€|x{{xz{{€~†‡†ˆŠˆ‡‡„‚}}~~€‚ƒƒƒƒ„ƒ‚€~~~~~~€‚”ŚžŞ­ŤĽ˜’“Šxqrpnkkt~‡“‘ŽŽ„}}|xsqtxyy|‚†‡†ˆŠŠ‡ƒ‚‚|x˜Ÿ”žŤ­ŹĄ—˜—‡uruqlkp|„„…˜–‘‹„ysuupnry‚ˆŒ‰‰ˆƒ}xwxusuz”˛¨Ľ˝ĂšŹœ‹eWad^al|”“›¨§š‘Œ†}oddiifmz…‹Ž’™œ–Œˆ…~tmjmpnryşşŚżĚžą™†‚z`IQa_bn}–¤Ÿ ŹŻ Žƒ|uiYVbijo}Ž˜›™œĄ›Š}xurmjq~†ˆ‰’ Âş™Ą¤’‡vdiyvjwŒ“—•Œ–‰vruutrq|ŠŒ‡Š‹ƒ{{}xrtz~‚‚ƒˆŒˆ„‚€|zvˆłą™¨ŻĽž‰rs{n_jx€‹‹Š– ˜Š†ƒ|rjqz{z~…‹‹…‡‰„}xwy|zx}ƒ……„„††„}а˛ĄĽŁĄŽvryjls}‹ŠƒŠ—–‹„€ƒzpt}~||„‰„~‚ƒ{z€ƒ|}„ƒ~}‚ƒ~}ŠĄ§Ł§ŤŽŤŽˆ|~…‰„‡Œ‹†……{~‚ƒ€}„…~€‚ƒ€}~‚‚€~‚‚€‚‚‚‚€€€€€€€€€€‚ƒ„ƒƒ††…ƒƒƒ„…ƒ‚ƒ‚ƒ„‚‚‚ƒƒ„††…††„ƒ‚€€~~||}|||||||~~}€€‚ƒ‚„…†‡‡‡‡‡‡…„„‚€~{|}{||z{|{{|{{|||}||}}}~}}~~~~~€€€€€€€‚‚€€‚ƒƒ‚‚€€~~€~~~€~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚~€€€€€€€€€€€€€€€€€‚€€€€€~€~€€€~€€€€€€~€~€‚€‚€€€€‚€€€€€~€~€€€€€€€€€€€€€€€€€‚€€‚€‚€ƒ€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€ƒƒ‚‚‚…‡‡‰‰Š‹‹‰ˆˆˆ‰‰‹‹‹‹‰ŠŠŠŠŠˆ‡‰ŠŠ‰‡…†ˆ†…‡…„††…ˆŠ‹’’”“Œ‰‡‡„ƒƒ‚ƒ‚‚ƒ‚€‚€€‚‚ƒ‚~€~€‚ƒ€~€€‚€€‚€‚~€€ƒ‚~~€€‚}ƒ‚€‚ƒ~€€€ƒƒ€~||ƒ‚ƒ‚~~€€‚ƒƒ‚}}€‚‚‚‚€~|||ƒƒ~||„„‚€~~~}|~€‚‚€€™śž˛›†~~€}}„˜–‹z{~~€„‰Š†||~€€ƒ„ƒ€~}€€€€‚‚€€€€€€€­ż¸¤€~|‹–˜ƒ{z~~~‚‡Šˆ‚}|~€~~„…„€~~~~‚ƒ‚€€€€~€€‚€ˆ˛ĆŤ—„swzslt‡–˜Š€}xsqw‚‹Ž‹†„‚{vvz€…†…„„ƒ€}zz|€‚ƒƒƒƒ‚€~|}~ Ç¸›Štr{wop‚•›}{|zurvŒ‘‹„€~|xw{‚‡ˆ…‚}z{~‚„„‚~|}€ƒ€˝ĆĽ‘{nx{snyœž”‚z|{wst|‰†}ywz€†‡…‚€}{{~ƒƒ‚~}~€€‚„ŤÉŻ”…sw}wpuŠ˜™”†|}~yuv}†ŒŒ†€~{y{€„†„ƒ‚€~|}~‚‚€~~€ Â˛šŒ}|}vpuˆ“”‡‚‚yux~„ˆ†„„ƒ~{{}€‚‚‚‚‚€~~€€€€€€€€€ŒŻťŠš…„xuƒŽˆƒ„„z|€ƒ…„‚ƒ‚~~€€€€€€€€€€€€€€€€€€€’¨ŻŞŚĄ›–Œ„‰”šš™—•’‰€€…ˆŠ‹‹‡€~‚‚„‡ˆ†‚€‚…„‚€€~~€‚‚‚Ł­Ş§Ł˜Ž†‡†‚‚€€~}}}}}}}}}}}~~~~~~~€€€€€€€€€€€€€€€‡ŒŠ‹‹‹ŒŒŠŠŠŠ‰‰ˆˆ‡†††……„„„ƒƒƒƒ‚‚‚‚‚€€€€‚ƒ‚‚€€€€€€€€€€€~~~~~~~€€‚ƒ‚‚ƒ‚‚‚‚€€€€€€€€€€‚‚‚€€€€€€€€€€€€€€€€€€€€€€‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€‚‚~‚€~ƒ‚‚€€€€€€€~€€ƒ‚€‚€‚€€‚‚€€€€€€€€€€‚€~‚~‚€‚‚ƒ‚~€‚‚€}ƒ€|‚€‚€~‚}‚~‚€€€}ƒ|€„~„€„}ƒ}}€‚|ƒ~}ƒ}‚~‚€€€€€€‚€€€‚}}ƒ~„‚~€~„}€„}‚~‚~‚‚‚|ƒ{„‚}ƒ~…~~„~~€~€~~€}€‚~€€€~€~€€€~€€|‚~€‚~„~€€€~‚‚~~€€€€€ƒ€~ƒ~€‚‚~€ƒ~~€€€‚€~ƒ‚€‚‚}‚‚}€‚€ƒ€ƒ€~‚~€~€‚‚€€€€€€…Ž”—›œš•‘މ…‚}}}}~€€‚ƒƒƒ„ƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€ƒ“•›œš“‹‡{xtrtwz}„ˆ‹ŒŠŠˆ…ƒ€|zyyyz{}€‚ƒ„…………ƒ€~}|||~~€€‚‚…ŤĄĄĄ œŒ{yytsnjsƒƒ†‰”’‰…„‚€|urvyxxy{…„ƒ„…††ƒ€€€~}{|~~€‚–§˘Ł§˘ĽŚ™Š†„}zvmpyyz}€‚ŠˆˆŠ‡‡†€|~~{{{z}€€€€ƒ‚€€}~~~€‚‡™¨ąśŻĽŸ˜Œuiehmt}ƒ‰’˜™˜“Šƒ}vromotz€†ŠŒŒ‰…{xuuvwz~‚…‡‰ˆˆ†ƒ~§ąąŤ¨Ľœ‘…vnllotx~ˆ”—•Œ‡|wqprty~‚…ŠŒŒŒ‰…~zxwuvy{~‚„†ˆˆˆ†„‹–›ŸŸ™•“ˆ‚ytssuy|~…‰‹ŽŽ‹‰†~|wvwwy}~…†‡‰‡…„~}{zzz{}€‚„„……ƒˆ“› Łž™–‰…}wussw{~„ˆ‰ŒŽ‹Šˆ‚}yxxxy|~€„…†‡‡…„‚~}{{|{}€ƒƒƒ„ƒ‚„‰’”’‰…‚~zyxxz|~‚„…ˆˆ‡†…‚€~|{{{|}~€‚ƒ„…„ƒƒ€~}}}~€€€€~~}}}}}}}}}}}~~~~~}~}}~~}~~~~~~~}}~~~~~~~€€€€€€€€~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€‚€€€€‚‚€€€€€€€€€€~~€~€€€€~€€‚€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€‚€€€€€€€€€€~‚€~‚€€ƒ€‚‚‚ƒ‚‚‚‚‚‚ƒ‚€‚‚ƒ‚„ƒ‚„‚ƒ‚€‚€€~~~}~€€€ƒ‚ƒ„ƒ„ƒ‚ƒ‚~~}}}|}|||{|{{{{|{{||}|}||}}~~€€€€€€€€€€€€€€€€€€€€€€€€€€‡’œŠłśˇłŹĽ”‹„}xursuw{~…‡ˆ‰‰ˆ‡†„‚€~}|{{|}~€‚ƒƒ„„„ƒ‚€~~}}~~…•ŁŻ¸ľ°ŻŞŚĄ”…xmhggffioxƒŒ‘”•–˜—”ކ~yusqonpsx~‚…ˆŠŒ‹ˆ„~|zxwvyŠŚąłŞŤŹŚ˘˜†zrlkkhgjpyƒŠŽ’“••‹„~zwusqqrvzƒ…†††…ƒ€}{zzz{}~€‚„™śźžťĄ“‘‚{uf`gp{ˆ’–”’ƒzupptvw|…ŠŒŠ‡ƒ€~{xxwy|‚„……†…„‚€}||{‹ŤśşžŠ˜˜Œ|ladlu‚‹Œ”•’Œtqty€„…‡‹‹‰„}wwy|€‚ƒ…††„}{{|~€ƒ„ƒƒ‰ľŇĚʧzyvjtrm‚š¤¨Ÿ‰xvuqtus‚‘“•€z{wwywzƒŠ‹‹‡|}{z|{}ƒ††‡ƒ~}}˘ÔŘǰjssqxĄŹ¤‹xpkt|zА”‘…xrty|€‚„‰‹‡{wx|‚ƒ„…„€|{|~€‚‚ƒ‚œÎŘÄą‡ktwsy€‹ŠŁŒzrms}|~ˆ’‘†ysuy|€‚ƒˆ‹‡|z|~„…„~}~~€‚‚ƒ€•ÄÄŁŽzu}yrt‡šœ”†{}~yuwŠŠ‚~|zz„†…‚€€€~|}‚ƒ‚€€~~€źÉŠ“u|zrr‚˜œ–Š|{~zuu~‰ŽŒ„€}yx}ƒ‡†‚€€€|{}„ƒ€€~}~€‚€ƒŠÎş™‡yx|vov‘ ›‚z}~wqx…Ž‰€~€zwz‡ˆ„€€€}{|ƒ„‚€€}}€‚ŸÇˇ—‰{{}wpp†˜˜’‡€€{ss|…Љ…ƒƒƒzx{ƒ„ƒ‚ƒƒ~||~€‚‚€~~€€€‚€—Äżœ‹|y}xqn–™”Ё€€|trz„ŠŠ†„„ƒzy{€ƒƒ‚‚ƒƒ~}~€€€‚‚€€€€€‚ťŔĄ‘ƒ~€{qp‚’“ˆƒ„ƒ|uw}ƒ†…ƒƒ…ƒ|{~€‚ƒ‚€~~€€€€€€€€€€„ŞĆşŤœ‹‹vŠ‘Œ„„‡„~~~€……ƒ‚~€€€€€€€€€€€€€€€€€€€€€€€€˜śłŚš‰Š„y|†ŠŒ…ƒ†…~~ƒ„‚€‚‚~€€€€€€€€€€€€€€€€€€€€ĽŹŠŚĄœ—ŽˆŽ™žŸž›™”‹…†‹Ž‘‘‘Žˆƒƒ…‡ˆ‰‹Š†‚€€‚‚„†‡…‚€€€ƒ„„‚€Š ŤŞŠ¤ž™‘‰Œ–ŸŸš–Œ‘’’‘Œ‹ŠŠŠŠ‹‹‹Š‰ˆˆ‡‡‡‡‡‡†††………„„„„„„„ƒƒƒƒ‹—˜—›š–•“‘”–”–˜–””‘‘ŽŒŒ‹‹‹‹ŠŠŠ‰‰ˆˆˆˆ‡‡‡†††…………………„„…„„ƒ‚„„‚„‚ƒƒ‚‚‚ƒ‚‚€ƒƒƒ‚ƒ„ƒ…‡„„…ƒ‚ƒ€‚€~~|}~~~}||~}{}z}~}~€€€‚€€€}~~}€~€}ƒ~ƒ~ƒ~„€‚€‚‚‚~‚‚~ƒ‚€‚€ƒ‚„‚€€~€€~‚€~€€€‚~~‚~€€‚‚~€„|‚}„€‚~€€‚~€‚€€~‚‚}‚~ƒ~€€€€‚|‚ƒ{ƒ}‚€€€€€~€€€~€‚~€€ƒ|‚{„€}„€~ƒ~ƒ}ƒ‚€|ƒ‚z‚ƒ|€„~€ƒ}‚~‚~~‚‚€€ƒ}~„~}ƒ€}‚€}ƒ€‚~€}‚‚~~ƒy…‚x†|„~€„|†z€„|‚~ƒ{„€{…~}ƒ€}ƒ|€‚~‚~ƒ‚€€€‚~„|€„|‚~‚€‚}€~~~€€€~ƒ~‚~ƒ~„~‚€‚~‚~€€‚€€€€€€€€‚‚~€€€€~ƒ}ƒ}‚€€€‚~‚€~‚€ƒ~€€€€€~‚~‚‚~ƒ€€€€€€€€~€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€~€}~}~€~€~€~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€€€€€~€€€€€€€€€€€€€€€‚‚‚€‚€‚€€€€€~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€ƒƒ‚‚‚ƒƒ‚‚€€€€€€€‚‚‚ƒ‚‚‚€€€€~}~}}}}~}|~~}‚‚ƒ„„……„„…„ƒƒ‚‚ƒ€‚€€‚ƒ‚ƒ…„…†„ƒ…„ƒ‚‚‚‚~~~~{}€|z~€~~‚}‚}|~€}€‚~~€}~‚ƒ‚€€€ƒ€€|~}€~€‚€~‚„‚ƒ‚ƒ‚…~‚}~}~~~~€‚‚‚€€€€€€€€€€€€€€‡’‹‹˜–‘‘ŽŠƒ~€~vuyyxy}ƒ‚„ˆ‰††‡…‚€}z{||{}€ƒ„„ƒƒƒ‚€€€~}~~~~€€‚‡Ÿž‘ڰ˘ š–Š}|~riptqsx€†…‡Ž’ŠŒ‹†€~}{vuxyxy}‚‚„‡ˆ†…†…‚}{{|||}€ƒ„…œŁ“ŚˇŠŹ­¨Źž”Žvttmfinpnq|€…ŒŽ“މˆˆƒ}z{yusvxvvz~‚†‡†‡ˆˆ†„…„~~{…•ސ¤Ł˘¨¤¨§š™™Ž†‚}yrmoolmrvwz„†ˆ‹ŽŽŠ‡…ƒ}{zywwwxyz|~€‚„……†††…„„ƒˆ—‘¨˘ŸŞĽ¨§™ž‰ˆ‚}utwroquwux€€€„‡Šˆ‡‹‹‡‡‡†ƒ€~||}|z|}}}}€€‚‚‚‚ƒƒ‚ƒ‰•‰Ą•™ —Ą›•ŠŽˆ„ƒ{{|vuvwvvxz{|~‚‚ƒ…†‡‡‡‡‡……„ƒ€~}||{|||}}~€‚‚‚ƒ‚ˆˆŽ˜”—’—“ޒއ‡…€{wxtpspmomnpmorprutwyx{}|€‚ƒƒ……„†……†………„„„ƒ‚ƒ‚€€€ƒ‚ƒ‡†ˆŠŠŒŒŽŽŽŽŒŒ‹ŠŠ‰ˆˆ‡††……„„ƒƒ‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ‚ƒ…„…†…††††††††……………„„„ƒƒƒ‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚€€‚‚€ƒ~€‚€‚‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ƒ‰”šœžĄŁ¤¤˘Ÿœ™•’‹‡„‚€~}|{{{||}~~€‚‚‚‚‚‚‚€€€€€€€€€€€€€€€€€€€€€€€€ƒ‡‰’“““’’‘ŽŽŒ‹ŠŠ‰ˆˆ‡‡††……„„ƒƒƒƒ‚‚‚‚‚ƒ‚‚€‚~€‚€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€}‚ƒ…‚‚ƒ‚…†…‚€‚€{~‚~}€‚€~€~‚‚}~ƒ}€€‚„…‚€„‚|ƒ€‚‚€ƒ‚~}}}}}|~€€‚‚‚€€~~„š˘ž˘˘˘¤ž…|vrlkrwy}‚‡‘‹ˆƒ~zxwvuvx|‚ƒ†ˆ‰ˆ‡…ƒ}{zz{{|}‚ƒ„„„„ƒ~~ ŸŸ”’“‰}urqu||}„‰ˆƒ‚€}zwvy}€‚ƒ„…‡†„}}}||}~€‚ƒƒ‚‚‚‚~~~~€‚‚‚€‚łť­Ź‘•~kfio}ƒ~ƒ”˜•Œutuvxxy†ŒŽˆ}|zyxxy}‚‡‰ˆ†ƒ€~|zyz}€ƒ„„„ƒƒ‚€~|||~šÂËĆť™zvofcck„šŁĽž’‰…ukffn|ˆ”‘Š…}yvsru{‚‰Š…€|zyxxz}€…ˆˆ‡…~|{{{}~€ƒƒľĎÓÓˇˆj[U]ny~ˆ–žŚŹŸŠxf\`jv„Ž†ƒ|zyvvz|‚‡‰‰ˆƒ|yy|}‚‚ƒƒ‚‚€~~}~€‚‚‚”´Íçň׾‹ZEDLj‡˜§ŠŸ™‘†{sonnu‡”‘†~xvuw{~„„…†…ƒ}|{|~‚‚‚‚€€€€‹ŠżÔâÎą–o^ads…‰‹ŽŒŒ‘‘‹‚yxvw}€ƒ‚€‚‚€€~€€€€€€€€€€€€€€€€€€€€€€€€€€€€Ž˘ŻÂż¸ČźŹą¨ ™”–ŽŠŠ‡Œ‰ˆˆ‡ˆ†††ƒ……€}ƒ~‚‚ƒ……‚ƒ…€€}€~}€~}€€~~~~}€}‚~‚€‚€ƒ‚ƒ‚‚‚‚‚‚‚€‚ƒ‚‚ƒ‚‚‚‚‚‚‚‚‚€€€€€€~~~€€€€€~~€~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€€€€€€€~~~~~~~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€‚‚€‚‚~~€€€€‚€€€€‚‚€‚€€‚€€€€€€‚€‚‚€€€~~~}}}||{|{{{{{z{{z{{z{{{{{||||||||||||||||||}||}}|}~}~~~€€€€€€€€|zxvvtssqrqprsswz|€‚ƒƒ~}zxvsqqsvy|~€„†‡‹ŒŒ‹ˆˆˆ‡‡‰‰ˆˆ†‚‚€}~€‚…„ƒƒ€~~}€}{zwxz{~~}~}}~}}€€~€ƒ…ˆ‰‰Š‰ˆ‰‡…„€~}|{zyy{{}‚ƒŁŠ°śŤŞŽĽĄœ‰|ukggb_adkv†’–œŸžœ—‰ƒ|wqkgghkosx~„Š“••”’‹†|wsponopsw{‡ŸŤľÁťˇź´­Ş—…{mdc]XZ\`lw‰‘•œĄĄĄž–‰{unigegkotz…‹’””“‘ŽŠ…€{wtrqqqsuzŁŤšź´š¸°Ż¤‘†znkg`]^_epx~‡Œ˜š›œ˜‘މ‚~yspnlnqrvz}‚‡‰‹ŽŒŠˆ…‚~|zxwvvw~“ŁŽťşśť¸łł§–Œusohgfdksw…†‹‘“•Š…‚}yxutvwx{|}ƒ„†‡†††„„ƒ€}||||…˜¨śÂżźž¸ľłĽ—‹|sqlhgeelrzƒˆ‹‘’•”‘މƒ|ywusttvy|~ƒ…‡ˆˆˆ‡†„‚€~||{{{|‰ŤźÄŔžšą°Š‘‚tlgefhgjpu~‡Œ‘”“““‘‹†€|xvuttuuw{}ƒ„……„ƒƒ€~}|||}~€€“­šËĐ˝śŞ–”Œ{ulbelr|„‡‹‘”Š‡zzwvxxx|~€„††‡†„„ƒ€~||||}€‚ƒ‚‚‚€¨´ÄĎž´Ź˜“xpeflr~‹”–’Œ‰zwrnrty‚‡‹ŽŠˆƒ}{xuvxy~ƒ…ˆŠˆ†„€}|yyz{}Ž˛ÍâôßššnQPOUiszŽœŚľś¨š„i^YWcpx…‘”œ š”‹{oidfov~‰•’Š‚ytpmqv{‚ˆ‰ŽŤÇÔçÜąŽc<:FW}—ŸŞ¨››—ŠlbZVdwˆ§¤ž‘€wqlorqv{~‡’•“‰xomps{‚…‰Š‰‰‡“´ĘÚć̤‚U. # ## Process this file with automake to produce Makefile.in EXTRA_DIST = baratinoo_shim.c README.baratinoo EXTRA_DIST += kali_Kali_shim.cpp kali_KGlobal_shim.cpp kali_KTrans_shim.cpp kali_KParle_shim.cpp kali_KAnalyse_shim.cpp EXTRA_DIST += ibmtts_shim.c eci.h EXTRA_DIST += mluvitko.c CLEANFILES = inc_local = -I$(top_srcdir)/include audio_SOURCES = spd_audio.c spd_audio.h common_SOURCES = module_main.c module_utils.c module_utils.h common_LDADD = $(SNDFILE_LIBS) $(DOTCONF_LIBS) $(GLIB_LIBS) $(GTHREAD_LIBS) AM_CFLAGS = $(ERROR_CFLAGS) AM_CPPFLAGS = $(inc_local) -DDATADIR=\"$(snddatadir)\" -D_GNU_SOURCE \ -DPLUGIN_DIR="\"$(audiodir)\"" \ $(DOTCONF_CFLAGS) $(GLIB_CFLAGS) $(GTHREAD_CFLAGS) \ $(ibmtts_include) $(SNDFILE_CFLAGS) modulebin_PROGRAMS = sd_dummy sd_generic sd_festival sd_cicero sd_dummy_SOURCES = dummy.c $(audio_SOURCES) $(common_SOURCES) \ module_utils_addvoice.c sd_dummy_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) dist_snddata_DATA = dummy-message.wav sd_festival_SOURCES = festival.c festival_client.c festival_client.h \ $(audio_SOURCES) $(common_SOURCES) sd_festival_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) $(EXTRA_SOCKET_LIBS) sd_generic_SOURCES = generic.c $(audio_SOURCES) $(common_SOURCES) \ module_utils_addvoice.c sd_generic_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) sd_cicero_SOURCES = cicero.c $(audio_SOURCES) $(common_SOURCES) sd_cicero_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(common_LDADD) if flite_support modulebin_PROGRAMS += sd_flite sd_flite_SOURCES = flite.c $(audio_SOURCES) $(common_SOURCES) sd_flite_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(flite_kal) $(flite_basic) \ $(common_LDADD) endif if ibmtts_support modulebin_PROGRAMS += sd_ibmtts sd_ibmtts_SOURCES = ibmtts.c $(audio_SOURCES) $(common_SOURCES) \ module_utils_addvoice.c sd_ibmtts_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ -libmeci \ $(common_LDADD) if ibmtts_shim sd_ibmtts_LDADD += -L. EXTRA_sd_ibmtts_DEPENDENCIES = libibmeci.so libibmeci.so: $(srcdir)/ibmtts_shim.c $(CC) -fPIC -shared $< -o $@ CLEANFILES += $(EXTRA_sd_ibmtts_DEPENDENCIES) endif endif if espeak_support modulebin_PROGRAMS += sd_espeak sd_espeak_SOURCES = espeak.c $(audio_SOURCES) $(common_SOURCES) sd_espeak_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ -lespeak $(EXTRA_ESPEAK_LIBS) \ $(common_LDADD) endif if espeak_ng_support modulebin_PROGRAMS += sd_espeak-ng sd_espeak_ng_SOURCES = espeak-ng.c $(audio_SOURCES) $(common_SOURCES) sd_espeak_ng_CFLAGS = -DESPEAK_NG_INCLUDE $(ESPEAK_NG_CFLAGS) sd_espeak_ng_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ $(ESPEAK_NG_LIBS) $(EXTRA_ESPEAK_LIBS) \ $(common_LDADD) endif if ivona_support modulebin_PROGRAMS += sd_ivona sd_ivona_SOURCES = ivona.c ivona_client.c ivona_client.h $(audio_SOURCES) \ $(common_SOURCES) sd_ivona_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ -ldumbtts \ $(common_LDADD) endif if pico_support modulebin_PROGRAMS += sd_pico sd_pico_SOURCES = pico.c $(audio_SOURCES) $(common_SOURCES) sd_pico_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) -lttspico \ $(common_LDADD) endif if baratinoo_support modulebin_PROGRAMS += sd_baratinoo sd_baratinoo_SOURCES = baratinoo.c baratinoo_compat.h $(audio_SOURCES) $(common_SOURCES) sd_baratinoo_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) -lbaratinoo -lpthread -ldl \ $(common_LDADD) if baratinoo_shim sd_baratinoo_LDADD += -L. EXTRA_sd_baratinoo_DEPENDENCIES = libbaratinoo.so libbaratinoo.so: $(srcdir)/baratinoo_shim.c $(CC) -fPIC -shared $< -o $@ CLEANFILES += $(EXTRA_sd_baratinoo_DEPENDENCIES) endif endif if kali_support modulebin_PROGRAMS += sd_kali KALI_DIR = /usr/lib/kali sd_kali_SOURCES = kali.cpp $(audio_SOURCES) $(common_SOURCES) sd_kali_LDADD = $(top_builddir)/src/common/libcommon.la \ $(audio_dlopen_modules) \ -lKali -lKGlobal -lKTrans -lKParle -lKAnalyse \ $(common_LDADD) sd_kali_CPPFLAGS = $(AM_CPPFLAGS) if kali_shim sd_kali_LDADD += -L. sd_kali_CPPFLAGS += -I$(srcdir)/kali_shim noinst_HEADERS = kali_shim/kali/Kali/kali.h EXTRA_sd_kali_DEPENDENCIES = libKali.so libKGlobal.so libKTrans.so libKParle.so libKAnalyse.so lib%.so: $(srcdir)/kali_%_shim.cpp $(CXX) -fPIC -shared $< -o $@ -I$(srcdir)/kali_shim CLEANFILES += $(EXTRA_sd_kali_DEPENDENCIES) endif endif -include $(top_srcdir)/git.mk speech-dispatcher-0.9.1/src/modules/kali_shim/0000755000175000017500000000000013465234513016322 500000000000000speech-dispatcher-0.9.1/src/modules/kali_shim/kali/0000755000175000017500000000000013465234513017242 500000000000000speech-dispatcher-0.9.1/src/modules/kali_shim/kali/Kali/0000755000175000017500000000000013465234513020122 500000000000000speech-dispatcher-0.9.1/src/modules/kali_shim/kali/Kali/kali.h0000644000175000017500000000436313406252513021134 00000000000000/* * kali/Kali/kali.h - Shim for Kali * to be able to build the Kali module without the Kali SDK. * * Copyright (C) 2018 Hypra * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ typedef struct { int bits; int num_channels; int sample_rate; int num_samples; const signed short *samples; } AudioTrackKali; extern "C" { extern bool initGlobal(void); extern bool initParle(void); extern bool initTrans(void); extern bool initAnalyse(void); extern bool initKali(void); extern const AudioTrackKali *GetBufMultiKaliStd(short nK); extern void SetSortieBufMultiKaliStd(short nK, bool sortieBuf); extern void SetSortieSonMultiKaliStd(short nK, bool sortieSon); extern short GetDebitDefautKaliStd(void); extern short GetDebitMinKaliStd(void); extern short GetDebitMaxKaliStd(void); extern void SetDebitKali(short debit); extern short GetVolumeDefautKaliStd(void); extern short GetVolumeMinKaliStd(void); extern short GetVolumeMaxKaliStd(void); extern void SetVolumeKali(short volume); extern short GetHauteurDefautKaliStd(void); extern short GetHauteurMinKaliStd(void); extern short GetHauteurMaxKaliStd(void); extern void SetHauteurKali(short hauteur); extern void SetModeLectureKali(short modeLecture); extern short GetNLangueVoixKaliStd(short nVoix); extern char *GetNomLangueKali(short nLangue, char *nomLangue); extern void SetLangueKali(short nLangue); extern short GetNbVoixKali(void); extern char *GetNomVoixKali(short nVoix, char *nomVoix); extern void SetVoixKali(short nVoix); extern short MessageKali(unsigned char* texte); extern short QueryIndexKali(void); extern bool quitteGlobal(void); extern bool quitteParle(void); extern bool quitteTrans(void); extern bool quitteAnalyse(void); } speech-dispatcher-0.9.1/src/audio/0000755000175000017500000000000013465234513014013 500000000000000speech-dispatcher-0.9.1/src/audio/pulse.c0000644000175000017500000002230213406252257015226 00000000000000 /* * pulse.c -- The simple pulseaudio backend for the spd_audio library. * * Copyright 2007-2009 Gilles Casse * Copyright 2008-2010 Brailcom, o.p.s * Copyright 2008-2015 Luke Yelavich * Copyright 2009 Rui Batista * Copyright 2009 Marco Skambraks * Copyright 2010 Andrei Kholodnyi * Copyright 2010 Christopher Brannon * Copyright 2010-2011 William Hubbs * Copyright 2015 Jeremy Whiting * Copyright 2018 Samuel Thibault * * Copied from Luke Yelavich's libao.c driver, and merged with code from * Marco's ao_pulse.c driver, by Bill Cox, Dec 21, 2009. * * Minor changes be Rui Batista to configure settings through speech-dispatcher configuration files * Date: Dec 22, 2009 * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #define SPD_AUDIO_PLUGIN_ENTRY spd_pulse_LTX_spd_audio_plugin_get #include typedef struct { AudioID id; pa_simple *pa_simple; char *pa_server; char *pa_name; int pa_min_audio_length; volatile int pa_stop_playback; int pa_current_rate; // Sample rate for currently PA connection int pa_current_bps; // Bits per sample rate for currently PA connection int pa_current_channels; // Number of channels for currently PA connection } spd_pulse_id_t; /* send a packet of XXX bytes to the sound device */ #define PULSE_SEND_BYTES 256 /* This is the smallest audio sound we are expected to play immediately without buffering. */ /* Changed to define on config file. Default is the same. */ /* Default to 20 ms of latency (1764 = 44100 * 0.020 * 2) */ #define DEFAULT_PA_MIN_AUDIO_LENGTH 1764 static int pulse_log_level; static char const *pulse_play_cmd = "paplay -n speech-dispatcher-generic"; #define MSG(level, arg...) \ if(level <= pulse_log_level){ \ time_t t; \ struct timeval tv; \ char *tstr; \ t = time(NULL); \ tstr = g_strdup(ctime(&t)); \ tstr[strlen(tstr)-1] = 0; \ gettimeofday(&tv,NULL); \ fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \ fprintf(stderr," Pulse: "); \ fprintf(stderr,arg); \ fprintf(stderr,"\n"); \ fflush(stderr); \ g_free(tstr); \ } #define ERR(arg...) \ { \ time_t t; \ struct timeval tv; \ char *tstr; \ t = time(NULL); \ tstr = g_strdup(ctime(&t)); \ tstr[strlen(tstr)-1] = 0; \ gettimeofday(&tv,NULL); \ fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \ fprintf(stderr," Pulse ERROR: "); \ fprintf(stderr,arg); \ fprintf(stderr,"\n"); \ fflush(stderr); \ g_free(tstr); \ } static int _pulse_open(spd_pulse_id_t * id, int sample_rate, int num_channels, int bytes_per_sample) { pa_buffer_attr buffAttr; pa_sample_spec ss; int error; char *client_name; ss.rate = sample_rate; ss.channels = num_channels; if (bytes_per_sample == 2) { switch (id->id.format) { case SPD_AUDIO_LE: ss.format = PA_SAMPLE_S16LE; break; case SPD_AUDIO_BE: ss.format = PA_SAMPLE_S16BE; break; } } else { ss.format = PA_SAMPLE_U8; } /* Set prebuf to one sample so that keys are spoken as soon as typed rather than delayed until the next key pressed */ buffAttr.maxlength = (uint32_t) - 1; //buffAttr.tlength = (uint32_t)-1; - this is the default, which causes key echo to not work properly. buffAttr.tlength = id->pa_min_audio_length; buffAttr.prebuf = (uint32_t) - 1; buffAttr.minreq = (uint32_t) - 1; buffAttr.fragsize = (uint32_t) - 1; if (!id->pa_name || asprintf(&client_name, "speech-dispatcher-%s", id->pa_name) < 0) client_name = strdup("speech-dispatcher"); /* Open new connection */ if (! (id->pa_simple = pa_simple_new(id->pa_server, client_name, PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &buffAttr, &error))) { fprintf(stderr, __FILE__ ": pa_simple_new() failed: %s\n", pa_strerror(error)); free(client_name); return 1; } free(client_name); return 0; } /* Close the connection to the server. Does not free the AudioID struct. */ /* Usable in pulse_play, which closes connections on failure or */ /* changes in audio parameters. */ static void pulse_connection_close(spd_pulse_id_t * pulse_id) { if (pulse_id->pa_simple != NULL) { pa_simple_free(pulse_id->pa_simple); pulse_id->pa_simple = NULL; } } static AudioID *pulse_open(void **pars) { spd_pulse_id_t *pulse_id; int ret; pulse_id = (spd_pulse_id_t *) g_malloc(sizeof(spd_pulse_id_t)); /* Select an Endianness for the initial connection. */ #if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) pulse_id->id.format = SPD_AUDIO_BE; #else pulse_id->id.format = SPD_AUDIO_LE; #endif pulse_id->pa_simple = NULL; pulse_id->pa_server = (char *)pars[3]; pulse_id->pa_name = (char *)pars[5]; pulse_id->pa_min_audio_length = DEFAULT_PA_MIN_AUDIO_LENGTH; pulse_id->pa_current_rate = -1; pulse_id->pa_current_bps = -1; pulse_id->pa_current_channels = -1; if (!strcmp(pulse_id->pa_server, "default")) { pulse_id->pa_server = NULL; } if (pars[4] != NULL && atoi(pars[4]) != 0) pulse_id->pa_min_audio_length = atoi(pars[4]); pulse_id->pa_stop_playback = 0; ret = _pulse_open(pulse_id, 44100, 1, 2); if (ret) { g_free(pulse_id); pulse_id = NULL; } return (AudioID *) pulse_id; } static int pulse_play(AudioID * id, AudioTrack track) { int bytes_per_sample; int num_bytes; int outcnt = 0; signed short *output_samples; int i; int error; spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id; if (id == NULL) { return -1; } if (track.samples == NULL || track.num_samples <= 0) { return 0; } MSG(4, "Starting playback\n"); /* Choose the correct format */ if (track.bits == 16) { bytes_per_sample = 2; } else if (track.bits == 8) { bytes_per_sample = 1; } else { ERR("ERROR: Unsupported sound data format, track.bits = %d\n", track.bits); return -1; } output_samples = track.samples; num_bytes = track.num_samples * bytes_per_sample; /* Check if the current connection has suitable parameters for this track */ if (pulse_id->pa_current_rate != track.sample_rate || pulse_id->pa_current_bps != track.bits || pulse_id->pa_current_channels != track.num_channels) { MSG(4, "Reopening connection due to change in track parameters sample_rate:%d bps:%d channels:%d\n", track.sample_rate, track.bits, track.num_channels); /* Close old connection if any */ pulse_connection_close(pulse_id); /* Open a new connection */ _pulse_open(pulse_id, track.sample_rate, track.num_channels, bytes_per_sample); /* Keep track of current connection parameters */ pulse_id->pa_current_rate = track.sample_rate; pulse_id->pa_current_bps = track.bits; pulse_id->pa_current_channels = track.num_channels; } MSG(4, "bytes to play: %d, (%f secs)\n", num_bytes, (((float)(num_bytes) / 2) / (float)track.sample_rate)); pulse_id->pa_stop_playback = 0; outcnt = 0; i = 0; while ((outcnt < num_bytes) && !pulse_id->pa_stop_playback) { if ((num_bytes - outcnt) > PULSE_SEND_BYTES) { i = PULSE_SEND_BYTES; } else { i = (num_bytes - outcnt); } if (pa_simple_write (pulse_id->pa_simple, ((char *)output_samples) + outcnt, i, &error) < 0) { pa_simple_drain(pulse_id->pa_simple, NULL); pulse_connection_close(pulse_id); MSG(4, "ERROR: Audio: pulse_play(): %s - closing device - re-open it in next run\n", pa_strerror(error)); break; } else { MSG(4, "Pulse: wrote %u bytes\n", i); } outcnt += i; } return 0; } /* stop the pulse_play() loop */ static int pulse_stop(AudioID * id) { spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id; pulse_id->pa_stop_playback = 1; return 0; } static int pulse_close(AudioID * id) { spd_pulse_id_t *pulse_id = (spd_pulse_id_t *) id; pulse_connection_close(pulse_id); g_free(pulse_id); id = NULL; return 0; } static int pulse_set_volume(AudioID * id, int volume) { return 0; } static void pulse_set_loglevel(int level) { if (level) { pulse_log_level = level; } } static char const *pulse_get_playcmd(void) { return pulse_play_cmd; } /* Provide the pulse backend. */ static spd_audio_plugin_t pulse_functions = { "pulse", pulse_open, pulse_play, pulse_stop, pulse_close, pulse_set_volume, pulse_set_loglevel, pulse_get_playcmd }; spd_audio_plugin_t *pulse_plugin_get(void) { return &pulse_functions; } spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void) __attribute__ ((weak, alias("pulse_plugin_get"))); #undef MSG #undef ERR speech-dispatcher-0.9.1/src/audio/oss.c0000644000175000017500000003170413406252253014704 00000000000000 /* * oss.c -- The Open Sound System backend for the spd_audio library. * * Copyright (C) 2004,2006 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: oss.c,v 1.13 2006-07-11 16:12:26 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include /* for open, close */ #include #include #include #include #define SPD_AUDIO_PLUGIN_ENTRY spd_oss_LTX_spd_audio_plugin_get #include typedef struct { AudioID id; int fd; char *device_name; pthread_mutex_t fd_mutex; pthread_cond_t pt_cond; pthread_mutex_t pt_mutex; } spd_oss_id_t; static int _oss_open(spd_oss_id_t * id); static int _oss_close(spd_oss_id_t * id); static int _oss_sync(spd_oss_id_t * id); /* Put a message into the logfile (stderr) */ #define MSG(level, arg...) \ if(level <= oss_log_level){ \ time_t t; \ struct timeval tv; \ char *tstr; \ t = time(NULL); \ tstr = g_strdup(ctime(&t)); \ tstr[strlen(tstr)-1] = 0; \ gettimeofday(&tv,NULL); \ fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \ fprintf(stderr," OSS: "); \ fprintf(stderr,arg); \ fprintf(stderr,"\n"); \ fflush(stderr); \ g_free(tstr); \ } #define ERR(arg...) \ { \ time_t t; \ struct timeval tv; \ char *tstr; \ t = time(NULL); \ tstr = g_strdup(ctime(&t)); \ tstr[strlen(tstr)-1] = 0; \ gettimeofday(&tv,NULL); \ fprintf(stderr," %s [%d]",tstr, (int) tv.tv_usec); \ fprintf(stderr," OSS ERROR: "); \ fprintf(stderr,arg); \ fprintf(stderr,"\n"); \ fflush(stderr); \ g_free(tstr); \ } static int oss_log_level; static char const *oss_play_cmd = "play"; static int _oss_open(spd_oss_id_t * id) { MSG(1, "_oss_open()") pthread_mutex_lock(&id->fd_mutex); id->fd = open(id->device_name, O_WRONLY, 0); if (id->fd < 0) { perror(id->device_name); pthread_mutex_unlock(&id->fd_mutex); id = NULL; return -1; } pthread_mutex_unlock(&id->fd_mutex); return 0; } static int _oss_close(spd_oss_id_t * id) { MSG(1, "_oss_close()") if (id == NULL) return 0; if (id->fd < 0) return 0; pthread_mutex_lock(&id->fd_mutex); close(id->fd); id->fd = -1; pthread_mutex_unlock(&id->fd_mutex); return 0; } /* Open OSS device Arguments: **pars: (char*) pars[0] -- the name of the device (e.g. "/dev/dsp") (void*) pars[1] = NULL */ static AudioID *oss_open(void **pars) { spd_oss_id_t *oss_id; int ret; if (pars[0] == NULL) return NULL; oss_id = (spd_oss_id_t *) g_malloc(sizeof(spd_oss_id_t)); oss_id->device_name = g_strdup((char *)pars[0]); pthread_mutex_init(&oss_id->fd_mutex, NULL); pthread_cond_init(&oss_id->pt_cond, NULL); pthread_mutex_init(&oss_id->pt_mutex, NULL); /* Test if it's possible to access the device */ ret = _oss_open(oss_id); if (ret) { g_free(oss_id->device_name); g_free(oss_id); return NULL; } ret = _oss_close(oss_id); if (ret) { g_free(oss_id->device_name); g_free(oss_id); return NULL; } return (AudioID *) oss_id; } /* Internal function. */ static int _oss_sync(spd_oss_id_t * id) { int ret; ret = ioctl(id->fd, SNDCTL_DSP_POST, 0); if (ret == -1) { perror("reset"); return -1; } return 0; } static int oss_play(AudioID * id, AudioTrack track) { int ret, ret2; struct timeval now; struct timespec timeout; float lenght; int r = 0; int format, oformat, channels, speed; int bytes_per_sample; int num_bytes; signed short *output_samples; float delay = 0; float DELAY = 0.1; /* in seconds */ audio_buf_info info; int bytes; float real_volume; int i; int re; spd_oss_id_t *oss_id = (spd_oss_id_t *) id; AudioTrack track_volume; if (oss_id == NULL) return -1; /* Open the sound device. This is necessary for OSS so that the application doesn't prevent others from accessing /dev/dsp when it doesn't play anything. */ ret = _oss_open(oss_id); if (ret) return -2; /* Create a copy of track with the adjusted volume */ track_volume = track; track_volume.samples = (short *)g_malloc(sizeof(short) * track.num_samples); real_volume = ((float)id->volume + 100) / (float)200; for (i = 0; i <= track.num_samples - 1; i++) track_volume.samples[i] = track.samples[i] * real_volume; /* Choose the correct format */ if (track.bits == 16) { format = AFMT_S16_NE; bytes_per_sample = 2; } else if (track.bits == 8) { bytes_per_sample = 1; format = AFMT_S8; } else { ERR("Audio: Unrecognized sound data format.\n"); _oss_close(oss_id); return -10; } oformat = format; ret = ioctl(oss_id->fd, SNDCTL_DSP_SETFMT, &format); if (ret == -1) { perror("OSS ERROR: format"); _oss_close(oss_id); return -1; } if (format != oformat) { ERR("Device doesn't support 16-bit sound format.\n"); _oss_close(oss_id); return -2; } /* Choose the correct number of channels */ channels = track.num_channels; ret = ioctl(oss_id->fd, SNDCTL_DSP_CHANNELS, &channels); if (ret == -1) { perror("OSS ERROR: channels"); _oss_close(oss_id); return -3; } if (channels != track.num_channels) { MSG(1, "Device doesn't support stereo sound.\n"); _oss_close(oss_id); return -4; } /* Choose the correct sample rate */ speed = track.sample_rate; ret = ioctl(oss_id->fd, SNDCTL_DSP_SPEED, &speed); if (ret == -1) { ERR("OSS ERROR: Can't set sample rate %d nor any similar.", track.sample_rate); _oss_close(oss_id); return -5; } if (speed != track.sample_rate) { ERR("Device doesn't support bitrate %d, using %d instead.\n", track.sample_rate, speed); } /* Is it not an empty track? */ if (track.samples == NULL) { _oss_close(oss_id); return 0; } /* Loop until all samples are played on the device. In the meantime, wait in pthread_cond_timedwait for more data or for interruption. */ MSG(4, "Starting playback"); output_samples = track_volume.samples; num_bytes = track.num_samples * bytes_per_sample; MSG(4, "bytes to play: %d, (%f secs)", num_bytes, (((float)(num_bytes) / 2) / (float)track.sample_rate)); while (num_bytes > 0) { /* OSS doesn't support non-blocking write, so lets check how much data can we write so that write() returns immediatelly */ re = ioctl(oss_id->fd, SNDCTL_DSP_GETOSPACE, &info); if (re == -1) { perror("OSS ERROR: GETOSPACE"); _oss_close(oss_id); return -5; } /* If there is not enough space for a single fragment, try later. (This shouldn't happen, it has very bad effect on synchronization!) */ if (info.fragments == 0) { MSG(4, "WARNING: There is not enough space for a single fragment, looping"); usleep(100); continue; } MSG(4, "There is space for %d more fragments, fragment size is %d bytes", info.fragments, info.fragsize); bytes = info.fragments * info.fragsize; ret = write(oss_id->fd, output_samples, num_bytes > bytes ? bytes : num_bytes); /* Handle write() errors */ if (ret <= 0) { perror("audio"); _oss_close(oss_id); return -6; } num_bytes -= ret; output_samples += ret / 2; MSG(4, "%d bytes written to OSS, %d remaining", ret, num_bytes); /* If there is some more data that is less than a full fragment, we need to write it immediatelly so that it doesn't cause buffer underruns later. */ if ((num_bytes > 0) && (num_bytes < info.fragsize) && (bytes + num_bytes < info.bytes)) { MSG(4, "Writing the rest of the data (%d bytes) to OSS, not a full fragment", num_bytes); ret2 = write(oss_id->fd, output_samples, num_bytes); num_bytes -= ret2; output_samples += ret2 / 2; ret += ret2; } /* Handle write() errors */ if (ret <= 0) { perror("audio"); _oss_close(oss_id); return -6; } /* Some timing magic... We need to wait for the time computed from the number of samples written. But this wait needs to be interruptible by oss_stop(). Furthermore, there need to be no buffer underrruns, so we actually wait a bit (DELAY) less in the first pass through the while() loop. Then our timer will be DELAY nsecs backwards. */ MSG(4, "Now we will try to wait"); pthread_mutex_lock(&oss_id->pt_mutex); lenght = (((float)(ret) / 2) / (float)track.sample_rate); if (!delay) { delay = lenght > DELAY ? DELAY : lenght; lenght -= delay; } MSG(4, "Wait for %f secs (begin: %f, delay: %f)", lenght, lenght + delay, delay) gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec + (int)lenght; timeout.tv_nsec = now.tv_usec * 1000 + (lenght - (int)lenght) * 1000000000; //MSG("5, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, timeout.tv_nsec, // now.tv_sec, now.tv_usec*1000, timeout.tv_sec - now.tv_sec, timeout.tv_nsec-now.tv_usec*1000); timeout.tv_sec += timeout.tv_nsec / 1000000000; timeout.tv_nsec = timeout.tv_nsec % 1000000000; // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, timeout.tv_nsec, // now.tv_sec, now.tv_usec*1000, timeout.tv_sec - now.tv_sec, timeout.tv_nsec-now.tv_usec*1000); r = pthread_cond_timedwait(&oss_id->pt_cond, &oss_id->pt_mutex, &timeout); pthread_mutex_unlock(&oss_id->pt_mutex); MSG(4, "End of wait"); /* The pthread_cond_timedwait was interrupted by change in the condition variable? if so, terminate. */ if (r != ETIMEDOUT) { MSG(4, "Playback stopped, %d", r); break; } } /* ...one more excersise in timing magic. Wait for the resting delay secs. */ /* Ugly hack: correct for the time we spend outside timing segments */ delay -= 0.05; MSG(4, "Wait for the resting delay = %f secs", delay) if ((delay > 0) && (r == ETIMEDOUT)) { pthread_mutex_lock(&oss_id->pt_mutex); gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = now.tv_usec * 1000 + delay * 1000000000; // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, timeout.tv_nsec, // now.tv_sec, now.tv_usec*1000, timeout.tv_sec - now.tv_sec, timeout.tv_nsec-now.tv_usec*1000); timeout.tv_sec += timeout.tv_nsec / 1000000000; timeout.tv_nsec = timeout.tv_nsec % 1000000000; // MSG("6, waiting till %d:%d (%d:%d | %d:%d)", timeout.tv_sec, timeout.tv_nsec, // now.tv_sec, now.tv_usec*1000, timeout.tv_sec - now.tv_sec, timeout.tv_nsec-now.tv_usec*1000); r = pthread_cond_timedwait(&oss_id->pt_cond, &oss_id->pt_mutex, &timeout); pthread_mutex_unlock(&oss_id->pt_mutex); } MSG(4, "End of wait"); if (track_volume.samples != NULL) g_free(track_volume.samples); /* Flush all the buffers */ _oss_sync(oss_id); /* Close the device so that we don't block other apps trying to access the device. */ _oss_close(oss_id); MSG(4, "Device closed"); return 0; } /* Stop the playback on the device and interrupt oss_play */ static int oss_stop(AudioID * id) { int ret = 0; spd_oss_id_t *oss_id = (spd_oss_id_t *) id; if (oss_id == NULL) return 0; MSG(4, "stop() called"); /* Stop the playback on /dev/dsp */ pthread_mutex_lock(&oss_id->fd_mutex); if (oss_id->fd >= 0) ret = ioctl(oss_id->fd, SNDCTL_DSP_RESET, 0); pthread_mutex_unlock(&oss_id->fd_mutex); if (ret == -1) { perror("reset"); return -1; } /* Interrupt oss_play by setting the condition variable */ pthread_mutex_lock(&oss_id->pt_mutex); pthread_cond_signal(&oss_id->pt_cond); pthread_mutex_unlock(&oss_id->pt_mutex); return 0; } /* Close the device */ static int oss_close(AudioID * id) { spd_oss_id_t *oss_id = (spd_oss_id_t *) id; /* Does nothing because the device is being automatically openned and closed in oss_play before and after playing each sample. */ g_free(oss_id->device_name); g_free(oss_id); id = NULL; return 0; } /* Set volume Comments: /dev/dsp can't set volume. We just multiply the track samples by a constant in oss_play (see oss_play() for more information). */ static int oss_set_volume(AudioID * id, int volume) { return 0; } static void oss_set_loglevel(int level) { if (level) { oss_log_level = level; } } static char const *oss_get_playcmd(void) { return oss_play_cmd; } /* Provide the OSS backend. */ static spd_audio_plugin_t oss_functions = { "oss", oss_open, oss_play, oss_stop, oss_close, oss_set_volume, oss_set_loglevel, oss_get_playcmd }; spd_audio_plugin_t *oss_plugin_get(void) { return &oss_functions; } spd_audio_plugin_t *SPD_AUDIO_PLUGIN_ENTRY(void) __attribute__ ((weak, alias("oss_plugin_get"))); #undef MSG #undef ERR speech-dispatcher-0.9.1/src/audio/nas.c0000644000175000017500000001425713406252247014670 00000000000000/* * nas.c -- The Network Audio System backend for the spd_audio library. * * Copyright (C) 2004,2006 Brailcom, o.p.s. * * This is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1, or (at your option) any later * version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * $Id: nas.c,v 1.8 2006-07-11 16:12:26 hanke Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include