Virtual Reader draft
authorMarkus Bröker <mbroeker@largo.dyndns.tv>
Sat, 13 Dec 2008 15:56:39 +0100
changeset 0 06dd3b8d90ad
child 1 fd135abaac89
Virtual Reader committer: Markus Bröker <mbroeker@largo.homelinux.org>
Makefile
README
audio/.keep
bin/festival_write_wav
bin/mbrola_write_wav
include/MBrola.h
include/audioplayer.h
include/festival_interface.h
include/interface.h
include/keyboard.h
include/mbrola_interface.h
include/proser_interface.h
include/sentence.h
include/thread.h
player/Makefile
player/audioplayer.c
player/main.c
run
src/Makefile
src/audioplayer.c
src/festival_interface.c
src/keyboard.c
src/main.c
src/mbrola_interface.c
src/proser_interface.c
src/sentence.c
src/thread.c
test.txt
new file mode 100644
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+TARGETS=player src
+
+all:
+	@for i in $(TARGETS); \
+	do \
+		make --no-print-directory -C $$i all; \
+	done
+
+.PHONY: clean distclean
+
+clean:
+	@for i in $(TARGETS); \
+	do \
+		make --no-print-directory -C $$i clean; \
+	done
+	@rm -f *~ include/*~
+
+distclean:
+	@for i in $(TARGETS); \
+	do \
+		make --no-print-directory -C $$i distclean; \
+	done
+
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,24 @@
+Projekt VirtualReader
+
+Authors    : Klaus_Dieter, bordi, mbroeker
+Maintainer : mbroeker
+
+LINKS:
+http://www.atip.de/index.php?option=com_content&task=view&id=46&Itemid=74
+MBrola Project: http://tcts.fpms.ac.be/synthesis/mbrola.html
+	- http://www.ikp.uni-bonn.de/dt/forsch/phonetik/hadifix/txt2pho.zip
+Festival Synth: http://www.cstr.ed.ac.uk/projects/festival
+	- install festival and copy text2wave to /usr/local/bin
+
+Requirements:
+	1. MBROLA, FESTIVAL or Proser TTS-System
+	2. txt2phpo, preproc and pipeflt for mbrola,
+	   text2wave for festival
+	3. SDL-1.2.x
+
+Directory Structure for /opt/mbrola
+drwxr-xr-x 2 root root  144 2007-12-20 09:24 bin
+drwxr-xr-x 2 root root  840 2007-08-23 17:56 data
+drwxr-xr-x 3 root root  152 2002-11-07 11:48 de5
+drwxr-xr-x 2 root root   80 2007-08-23 17:54 doc
+-rw-r--r-- 1 root root 5836 2007-08-23 17:57 Rules.lst
new file mode 100644
new file mode 100755
--- /dev/null
+++ b/bin/festival_write_wav
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+file=$1
+
+eval "cat $file |\
+text2wave - -o $2"
+
+
+
new file mode 100755
--- /dev/null
+++ b/bin/mbrola_write_wav
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+ROOT=/opt/mbrola                # Where are the needed files?
+VOICE=$ROOT/de5/de5             # Path to the mbrola-voice
+SEX=f                           # m/f Which sex has your voice?
+
+file=$1
+
+eval "cat $file |\
+$ROOT/bin/pipefilt |\
+$ROOT/bin/preproc $ROOT/Rules.lst $ROOT/data/hadifix.abk |\
+$ROOT/bin/txt2pho -$SEX -p $ROOT/data/ |\
+$ROOT/bin/mbrola $VOICE - $2"
new file mode 100644
--- /dev/null
+++ b/include/MBrola.h
@@ -0,0 +1,9 @@
+/**
+ *  $Id: MBrola.h 48 2008-01-09 23:59:19Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/MBrola.h $
+ */
+
+#ifndef MBROLA_H
+#define MBROLA_H
+
+#endif
new file mode 100644
--- /dev/null
+++ b/include/audioplayer.h
@@ -0,0 +1,54 @@
+/**
+ *  $Id: audioplayer.h 48 2008-01-09 23:59:19Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/audioplayer.h $
+ */
+
+#ifndef __AUDIOPLAYER_H__
+#define __AUDIOPLAYER_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <SDL/SDL.h>
+
+/* audioplayer(filename, milliseconds, position) */
+int audioplayer (char *, Uint32);
+
+/* initializes the sdl-soundsystem and prepares local structures */
+int audio_init ();
+
+/* closes the sdl-soundsystem and frees local structures */
+void audio_shutdown ();
+
+/* audioplayer_getwavelength(filename) */
+Uint32 audioplayer_getwavelength (char *);
+
+/* returns the bitrate of the wave-file */
+int audioplayer_getbitrate ();
+
+/* stopps playback immediately */
+void audioplayer_stop ();
+
+/* returns the current time in ms */
+Uint32 audioplayer_gettime ();
+
+/* sets the current position in ms */
+void audioplayer_settime (long);
+
+/* returns the length of the RIFF in ms */
+Uint32 audioplayer_getsoundlen ();
+
+/* returns the current position */
+Uint32 audioplayer_getposition ();
+
+/* wait replaces sdl_delay */
+void audioplayer_delay (Uint32);
+
+/* switches verbosity on/off */
+void audioplayer_setverbose (int);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/include/festival_interface.h
@@ -0,0 +1,31 @@
+/**
+ *  $Id: festival_interface.h 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/festival_interface.h $
+ */
+
+#ifndef __FESTIVAL_INTERFACE_H__
+#define __FESTIVAL_INTERFACE_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+
+typedef struct {
+    char *TextFile;
+    char *AudioFile;
+    char *Voice;
+    char *Path;
+} tts_options;
+
+typedef struct {
+} ttshandles;
+
+tts_options interface_get_cl_opts (int, char **);
+
+int interface_write_to_wav (char *, char *, ttshandles, tts_options);
+ttshandles interface_init (tts_options);
+long *interface_get_timing (ttshandles, char *);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/include/interface.h
@@ -0,0 +1,21 @@
+/**
+ *  $Id: interface.h 48 2008-01-09 23:59:19Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/interface.h $
+ */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#ifdef PROSER
+#include <proser_interface.h>
+#endif
+
+#ifdef MBROLA
+#include <mbrola_interface.h>
+#endif
+
+#ifdef FESTIVAL
+#include <festival_interface.h>
+#endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/include/keyboard.h
@@ -0,0 +1,18 @@
+/**
+ *  $Id: keyboard.h 48 2008-01-09 23:59:19Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/keyboard.h $
+ */
+
+#ifndef __KEYBOARD_H__
+#define __KEYBOARD_H__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <termios.h>
+#ifdef DEBUG
+#include <ctype.h>
+#endif
+
+char getSingleKey (void);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/include/mbrola_interface.h
@@ -0,0 +1,31 @@
+/**
+ *  $Id: mbrola_interface.h 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/mbrola_interface.h $
+ */
+
+#ifndef __MBROLA_INTERFACE_H__
+#define __MBROLA_INTERFACE_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <MBrola.h>
+
+typedef struct {
+    char *TextFile;
+    char *AudioFile;
+    char *Voice;
+    char *Path;
+} tts_options;
+
+typedef struct {
+} ttshandles;
+
+tts_options interface_get_cl_opts (int, char **);
+
+int interface_write_to_wav (char *, char *, ttshandles, tts_options);
+ttshandles interface_init (tts_options);
+long *interface_get_timing (ttshandles, char *);
+#endif
new file mode 100644
--- /dev/null
+++ b/include/proser_interface.h
@@ -0,0 +1,37 @@
+/**
+ *  $Id: proser_interface.h 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/proser_interface.h $
+ */
+
+#ifndef __PROSER_INTERFACE_H__
+#define __PROSER_INTERFACE_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <Proser.h>
+
+typedef struct {
+    char *TextFile;
+    char *AudioFile;
+    char *Voice;
+    char *Path;
+    float PreEmphasis;
+    float Speed;
+    AudioType Stype;
+    OUTTYPE FileType;
+    // nicht ganz so schön, aber funktioniert
+    PROOPT ProserOpt;
+} tts_options;
+
+typedef struct {
+    NLPBLOCK GermanNlp;
+} ttshandles;
+
+tts_options interface_get_cl_opts (int, char **);
+
+int interface_write_to_wav (char *, char *, ttshandles, tts_options);
+ttshandles interface_init (tts_options);
+long *interface_get_timing (ttshandles, char *);
+#endif
new file mode 100644
--- /dev/null
+++ b/include/sentence.h
@@ -0,0 +1,28 @@
+/**
+ *  $Id: sentence.h 48 2008-01-09 23:59:19Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/sentence.h $
+ */
+
+#ifndef __SENTENCE_H__
+#define __SENTENCE_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* prepares the text */
+int *parse (char *);
+
+/* reads a textfile */
+char *readbuffer (char *);
+
+/* extracts a substring from a buffer */
+char *getSentence (char *, int, int);
+
+/* counts the words of a string */
+int words (char *);
+
+char **getstrings (char *, int *);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/include/thread.h
@@ -0,0 +1,37 @@
+/**
+ *  $Id: thread.h 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/include/thread.h $
+ */
+
+#ifndef __THREAD_H__
+#define __THREAD_H__
+
+#include <pthread.h>
+#include <sentence.h>
+#include <interface.h>
+#include <audioplayer.h>
+
+#ifndef TIMEOUT
+#define TIMEOUT 186
+#endif
+
+typedef struct {
+    int satz;
+    int items;
+    char *fname;
+    tts_options ttsopt;
+    ttshandles ttsh;
+    char **sentences;
+    long **timings;
+} ThreadData;
+
+/* reads the wavefiles from disk */
+void readtext (ThreadData *);
+
+/* stores the data on the harddisk */
+void writewav (ThreadData *);
+
+/* (re)starts a thread */
+int p_thread_restart (pthread_t, void *, ThreadData *);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/player/Makefile
@@ -0,0 +1,34 @@
+    CC	= gcc
+CFLAGS =  -Wall -O2 -DLINUX -DWINAPI="" $(shell sdl-config --cflags)
+INCLUDE= -I../include
+LDFLAGS = -Wl,-rpath,lib $(shell sdl-config --libs)
+ DEBUG	= -g -ggdb
+TARGET  = ../bin/audioplayer
+OBJECTS = \
+	main.o \
+	audioplayer.o
+
+.c.o:
+	@$(CC) -c $(CFLAGS) $(INCLUDE) $(DEBUG) -o $@ $<
+	@echo "CC $<"
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+	@$(CC) $(OBJECTS) $(LDFLAGS) -o $@
+	@echo "LD OBJECTS -o $@"
+
+.PHONY: clean distclean
+
+clean:
+	@rm -f *.o *~
+	@echo "CLEANING $$PWD"
+
+distclean:
+	@make clean
+	@rm -f $(TARGET)
+	@echo "WIPING $$PWD OUT"
+
+install: $(TARGET)
+	install -m 755 $(TARGET) ~/bin/
+
new file mode 100644
--- /dev/null
+++ b/player/audioplayer.c
@@ -0,0 +1,228 @@
+/**
+ *  $Id: audioplayer.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/player/audioplayer.c $
+ */
+
+#include <audioplayer.h>
+
+typedef struct {
+    SDL_AudioSpec spec;         // internal structure
+    Uint8 *sound_buffer;        // malloced pointer from sdl
+    Uint32 sound_pos;           // position
+    Uint32 sound_len;           // length in bytes
+    Uint32 length;              // Length in Milliseconds
+
+    int opened;                 // bool opened
+    int loaded;                 // bool loaded
+    int verbose;                // verbose messages
+    int timeout;                // timeout
+    int timer;                  // bool timer
+} AudioDevice;
+
+AudioDevice AD;
+
+int audio_init ()
+{
+    // initialize SDL for audio output
+    if (SDL_Init (SDL_INIT_AUDIO) < 0) {
+        fprintf (stderr, "audio_init: Cannot initialize SDL-Subsystem\n");
+        return -1;
+    }
+
+    AD.sound_buffer = 0;
+    AD.sound_pos = 0;
+    AD.sound_len = 0;
+
+    AD.opened = 0;
+    AD.loaded = 0;
+    AD.verbose = 0;
+
+    AD.timeout = 0;
+    AD.timer = 0;
+
+    return 0;
+}
+
+void audio_shutdown ()
+{
+    // quit sdl
+    SDL_AudioQuit ();
+    SDL_Quit ();
+}
+
+static void Callback (void *userdata, Uint8 * stream, int len)
+{
+    Uint8 *waveptr = NULL;
+
+    /*
+     *     loaded = 0 Segmentation fault
+     *        len = 0 nothing to play
+     */
+    if (!(AD.loaded && len))
+        return;
+
+    waveptr = AD.sound_buffer + AD.sound_pos;
+    SDL_MixAudio (stream, waveptr, len, SDL_MIX_MAXVOLUME);
+    AD.sound_pos += len;        // bereits gespielt
+
+    if (audioplayer_gettime () > (AD.length - AD.timeout)) {
+        AD.sound_pos = AD.length;
+        AD.sound_len = 0;
+        AD.timer = 0;
+    }
+}
+
+Uint32 audioplayer_getsoundlen ()
+{
+    return AD.sound_len;
+}
+
+void audioplayer_media_info (char *fname)
+{
+    AD.length = audioplayer_getwavelength (fname);
+
+    printf ("Playing %s: %d Hz, %d Bit Audio, %d Channel(s), %3.2d ms\n",
+            fname, AD.spec.freq, audioplayer_getbitrate (), AD.spec.channels, AD.length);
+}
+
+int audioplayer_getbitrate ()
+{
+    int bitrate = 0;
+
+    switch (AD.spec.format) {
+    case AUDIO_U8:
+    case AUDIO_S8:
+        bitrate = 8;
+        break;
+    case AUDIO_S16LSB:
+    case AUDIO_S16MSB:
+    case AUDIO_U16LSB:
+    case AUDIO_U16MSB:
+        bitrate = 16;
+        break;
+    }
+
+    return bitrate;
+}
+
+Uint32 audioplayer_getwavelength (char *fname)
+{
+    struct stat info;
+    Uint32 value = 0;
+
+    if (fname == NULL)
+        return AD.length;
+
+    if (stat (fname, &info) == 0)
+        /*
+         * the value is really big, so be carefull
+         * changes in the order result in different values
+         * the storage type isn`t well choosen...
+         */
+        value = ((info.st_size) / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0);
+
+    return (value);
+}
+
+Uint32 audioplayer_getposition ()
+{
+    return AD.sound_pos;
+}
+
+Uint32 audioplayer_gettime ()
+{
+    Uint32 ret;
+
+    ret = AD.sound_pos / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0;
+
+    return ret;
+}
+
+void audioplayer_settime (long tm)
+{
+    AD.sound_pos = tm / 1000.0 * (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0));
+
+    /*
+     * Eine Adresse ...
+     */
+    while ((AD.sound_pos % 2) != 0)
+        AD.sound_pos++;
+
+    if (AD.verbose)
+        printf ("\e[31m[ATTENTION]\e[37m [#%d/#%d] = %d ms\n", AD.sound_pos, AD.sound_len, audioplayer_gettime ());
+}
+
+void audioplayer_stop ()
+{
+    /*
+     * stops the callback function
+     */
+    SDL_PauseAudio (1);
+    AD.spec.callback = NULL;
+
+    if (AD.loaded == 1)
+        SDL_FreeWAV (AD.sound_buffer);
+
+    AD.loaded = 0;
+    AD.timer = 0;
+}
+
+void audioplayer_delay (Uint32 milliseconds)
+{
+    struct timespec tm;
+
+    tm.tv_sec = 0;
+    tm.tv_nsec = milliseconds * 1000;
+
+    while (AD.timer)
+        nanosleep (&tm, NULL);
+}
+
+void audioplayer_setverbose (int verbose)
+{
+    AD.verbose = verbose;
+}
+
+int audioplayer (char *fname, Uint32 timeout)
+{
+    if (SDL_LoadWAV (fname, &AD.spec, &AD.sound_buffer, &AD.sound_len) == NULL) {
+        printf ("SDL: %s\n", SDL_GetError ());
+        return -1;
+    }
+
+    AD.loaded = 1;
+
+    if (!AD.opened) {
+        AD.spec.callback = Callback;
+        if (SDL_OpenAudio (&AD.spec, NULL) < 0) {
+            fprintf (stderr, "Cannot open audio device: %s\n", SDL_GetError ());
+            return -1;
+        }
+        AD.opened = 1;
+    }
+
+    /*
+     * calls implicitly getwavelength
+     */
+    audioplayer_media_info (fname);
+
+    AD.sound_pos = 0;
+
+    /*
+     * starts playback via Callback function
+     */
+    SDL_PauseAudio (0);
+
+    /*
+     * initializes the timeout mechanism
+     */
+    AD.timer = 1;
+    AD.timeout = timeout;
+
+    /*
+     * controlled delay
+     */
+    audioplayer_delay (timeout);
+
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/player/main.c
@@ -0,0 +1,50 @@
+/**
+ *  $Id: main.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/player/main.c $
+ */
+
+#include <audioplayer.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#define TIMEOUT 186
+
+void help (char *prgname)
+{
+    printf ("Usage: %s [-h] sndfile1,[sndfile2,...]\n", prgname);
+    printf ("\t sndfile\t: a valid wave file\n");
+    printf ("\t-h help \t: shows this screen\n");
+}
+
+int main (int argc, char **argv)
+{
+    int i;
+
+    while ((i = getopt (argc, argv, "h")) > 0) {
+        switch (i) {
+        case 'h':
+            help (argv[0]);
+            exit (0);
+            break;
+        default:
+            printf ("Unknown Option %c\n", i);
+            help (argv[0]);
+            exit (0);
+        }
+    }
+
+    if (argc == optind) {
+        help (argv[0]);
+        exit (0);
+    }
+
+    audio_init ();
+
+    for (i = optind; i < argc; i++) {
+        audioplayer (argv[i], TIMEOUT);
+        audioplayer_stop ();
+    }
+
+    audio_shutdown ();
+    return 0;
+}
new file mode 100755
--- /dev/null
+++ b/run
@@ -0,0 +1,68 @@
+#!/bin/bash
+# $Header: /work/c/VirtualReader/run-20070320,v 1.3 2007/03/20 20:00:00 bordi $
+
+VALGRIND="$(which valgrind)"
+STRACE="$(which strace)"
+GDB="$(which gdb)"
+DDD="$(which ddd)"
+SPLINT="$(which splint)"
+BUILD="make -C src"
+PROG="bin/vreader"
+FILE="test.txt"
+OPTIONS="-i ${FILE} -v voice/De_Carla_22kHz -p data -format WAV -o test.wav"
+
+$BUILD
+if [ $? == 0 ]
+    then
+    echo 
+    echo "   VirtualReader - Version 0.1"
+    echo
+    echo "       Navigation Keys:"
+    echo " ##############################"
+    echo " # i: next word               #"
+    echo " # j: previous sentence       #"
+    echo " # k: previous word           #"
+    echo " # l: next sentence           #"
+    echo " # p: print position          #"
+    echo " # q: quit                    #"
+    echo " # r: reset to first position #"
+    echo " # s: print current sentence  #"
+    echo " # v: switch verbosity on/off #"
+    echo " ##############################"
+    echo "    Press ENTER to Start"
+    read
+    case $1 in 
+	valgrind)
+	    $VALGRIND $PROG $OPTIONS
+	    ;;
+	strace)
+	    $STRACE $PROG $OPTIONS
+	    ;;
+	gdb)
+	    echo "break 67">gdb.exec
+	    echo "r $OPTIONS" >> gdb.exec	   
+	    DEBUG=1 $GDB -x gdb.exec $PROG
+	    rm -f gdb.exec 
+	    ;;
+	ddd)
+	    echo "break 67">gdb.exec
+	    echo "r $OPTIONS" >> gdb.exec	   
+	    $DDD -x gdb.exec $PROG
+	    rm -f gdb.exec 
+	    ;;
+	splint)
+	    $SPLINT -Iinclude -DMBROLA -warnposix src/main.c
+	    ;;
+	help)
+	    echo "Usage: run [commands]"
+	    echo "valid commands are: strace, gdb, \
+ddd, valgrind and help"	    
+	    exit 0		
+	    ;;
+	*)
+	    $PROG $OPTIONS
+	    ;;
+    esac    
+fi
+
+rm -f audio/*.wav;
new file mode 100644
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,62 @@
+###### USER CONFIG ###############
+TARGET  = ../bin/vreader         #
+MBROLA  = /opt/mbrola/bin/mbrola #
+FESTIVAL= /usr/bin/festival      #
+INSTDIR = ~/bin                  #
+##### USER CONFIG ENDS ###########
+
+   CC	= gcc
+MCFLAGS =  -Wall -O2 -DMBROLA $(shell sdl-config --cflags)
+FCFLAGS =  -Wall -O2 -DFESTIVAL $(shell sdl-config --cflags)
+PCFLAGS =  -Wall -O2 -DPROSER -DLINUX -DWINAPI="" $(shell sdl-config --cflags)
+INCLUDE = -I../include
+LDFLAGS = -Wl,-rpath,lib -L../lib $(shell sdl-config --libs)
+ DEBUG	= -g -ggdb
+OBJECTS = \
+	main.o \
+	sentence.o \
+	keyboard.o \
+	thread.o \
+	audioplayer.o \
+	proser_interface.o \
+	mbrola_interface.o \
+	festival_interface.o
+
+.c.o:
+	@if [ -f ../lib/libProserGerman.a ]; \
+	then \
+		$(CC) -c $(PCFLAGS) $(INCLUDE) $(DEBUG) -o $@ $<; \
+	elif [ -x $(MBROLA) ]; \
+	then \
+		$(CC) -c $(MCFLAGS) $(INCLUDE) $(DEBUG) -o $@ $<; \
+	elif [ -x $(FESTIVAL) ]; \
+	then \
+		$(CC) -c $(FCFLAGS) $(INCLUDE) $(DEBUG) -o $@ $<; \
+	else \
+		echo "Cannot find any TTS-System on your Machine"; \
+	fi;
+	@echo "CC $<"
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+	@if [ -f ../lib/libProserGerman.a ]; \
+	then \
+		$(CC) $(OBJECTS) $(LDFLAGS) -lProserGerman -o $@; \
+	else \
+		$(CC) $(OBJECTS) $(LDFLAGS) -o $@; fi
+	@echo "LD OBJECTS -o $@"
+
+.PHONY: clean distclean
+
+clean:
+	@rm -f *.o *~
+	@echo "CLEANING $$PWD"
+
+distclean:
+	@make clean
+	@rm -f $(TARGET)
+	@echo "WIPING $$PWD OUT"
+
+install: $(TARGET)
+	install -m 755 $(TARGET) $(INSTDIR)
new file mode 100644
--- /dev/null
+++ b/src/audioplayer.c
@@ -0,0 +1,232 @@
+/**
+ *  $Id: audioplayer.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/audioplayer.c $
+ */
+
+#include <audioplayer.h>
+
+typedef struct {
+    SDL_AudioSpec spec;         // internal structure
+    Uint8 *sound_buffer;        // malloced pointer from sdl
+    Uint32 sound_pos;           // position
+    Uint32 sound_len;           // length in bytes
+    Uint32 length;              // Length in Milliseconds
+
+    int opened;                 // bool opened
+    int loaded;                 // bool loaded
+    int verbose;                // verbose messages
+    int timeout;                // timeout
+    int timer;                  // bool timer
+} AudioDevice;
+
+AudioDevice AD;
+
+int audio_init ()
+{
+    /*
+     * initialize SDL for audio output
+     */
+    if (SDL_Init (SDL_INIT_AUDIO) < 0) {
+        fprintf (stderr, "audio_init: Cannot initialize SDL-Subsystem\n");
+        return -1;
+    }
+
+    AD.sound_buffer = 0;
+    AD.sound_pos = 0;
+    AD.sound_len = 0;
+
+    AD.opened = 0;
+    AD.loaded = 0;
+    AD.verbose = 0;
+
+    AD.timeout = 0;
+    AD.timer = 0;
+
+    return 0;
+}
+
+void audio_shutdown ()
+{
+    /*
+     * quit sdl
+     */
+    SDL_AudioQuit ();
+    SDL_Quit ();
+}
+
+static void Callback (void *userdata, Uint8 * stream, int len)
+{
+    Uint8 *waveptr = NULL;
+
+    /*
+     *     loaded = 0 Segmentation fault
+     *        len = 0 nothing to play
+     */
+    if (!(AD.loaded && len))
+        return;
+
+    waveptr = AD.sound_buffer + AD.sound_pos;
+    SDL_MixAudio (stream, waveptr, len, SDL_MIX_MAXVOLUME);
+    AD.sound_pos += len;        /* bereits gespielt */
+
+    if (audioplayer_gettime () > (AD.length - AD.timeout)) {
+        AD.sound_pos = AD.length;
+        AD.sound_len = 0;
+        AD.timer = 0;
+    }
+}
+
+Uint32 audioplayer_getsoundlen ()
+{
+    return AD.sound_len;
+}
+
+void audioplayer_media_info (char *fname)
+{
+    AD.length = audioplayer_getwavelength (fname);
+
+    printf ("Playing %s: %d Hz, %d Bit Audio, %d Channel(s), %3.2d ms\n",
+            fname, AD.spec.freq, audioplayer_getbitrate (), AD.spec.channels, AD.length);
+}
+
+int audioplayer_getbitrate ()
+{
+    int bitrate = 0;
+
+    switch (AD.spec.format) {
+    case AUDIO_U8:
+    case AUDIO_S8:
+        bitrate = 8;
+        break;
+    case AUDIO_S16LSB:
+    case AUDIO_S16MSB:
+    case AUDIO_U16LSB:
+    case AUDIO_U16MSB:
+        bitrate = 16;
+        break;
+    }
+
+    return bitrate;
+}
+
+Uint32 audioplayer_getwavelength (char *fname)
+{
+    struct stat info;
+    Uint32 value = 0;
+
+    if (fname == NULL)
+        return AD.length;
+
+    if (stat (fname, &info) == 0)
+        /*
+         * the value is really big, so be carefull
+         * changes in the order result in different values
+         * the storage type isn`t well choosen...
+         */
+        value = ((info.st_size) / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0);
+
+    return (value);
+}
+
+Uint32 audioplayer_getposition ()
+{
+    return AD.sound_pos;
+}
+
+Uint32 audioplayer_gettime ()
+{
+    Uint32 ret;
+
+    ret = AD.sound_pos / (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0)) * 1000.0;
+
+    return ret;
+}
+
+void audioplayer_settime (long tm)
+{
+    AD.sound_pos = tm / 1000.0 * (AD.spec.freq * AD.spec.channels * (audioplayer_getbitrate () / 8.0));
+
+    /*
+     * Eine Adresse ...
+     */
+    while ((AD.sound_pos % 2) != 0)
+        AD.sound_pos++;
+
+    if (AD.verbose)
+        printf ("\e[31m[ATTENTION]\e[37m [#%d/#%d] = %d ms\n", AD.sound_pos, AD.sound_len, audioplayer_gettime ());
+}
+
+void audioplayer_stop ()
+{
+    /*
+     * stops the callback function
+     */
+    SDL_PauseAudio (1);
+    AD.spec.callback = NULL;
+
+    if (AD.loaded == 1)
+        SDL_FreeWAV (AD.sound_buffer);
+
+    AD.loaded = 0;
+    AD.timer = 0;
+}
+
+void audioplayer_delay (Uint32 milliseconds)
+{
+    struct timespec tm;
+
+    tm.tv_sec = 0;
+    tm.tv_nsec = milliseconds * 1000;
+
+    while (AD.timer)
+        nanosleep (&tm, NULL);
+}
+
+void audioplayer_setverbose (int verbose)
+{
+    AD.verbose = verbose;
+}
+
+int audioplayer (char *fname, Uint32 timeout)
+{
+    if (SDL_LoadWAV (fname, &AD.spec, &AD.sound_buffer, &AD.sound_len) == NULL) {
+        printf ("SDL: %s\n", SDL_GetError ());
+        return -1;
+    }
+
+    AD.loaded = 1;
+
+    if (!AD.opened) {
+        AD.spec.callback = Callback;
+        if (SDL_OpenAudio (&AD.spec, NULL) < 0) {
+            fprintf (stderr, "Cannot open audio device: %s\n", SDL_GetError ());
+            return -1;
+        }
+        AD.opened = 1;
+    }
+
+    /*
+     * calls implicitly getwavelength
+     */
+    audioplayer_media_info (fname);
+
+    AD.sound_pos = 0;
+
+    /*
+     * starts playback via Callback function
+     */
+    SDL_PauseAudio (0);
+
+    /*
+     * initializes the timeout mechanism
+     */
+    AD.timer = 1;
+    AD.timeout = timeout;
+
+    /*
+     * controlled delay
+     */
+    audioplayer_delay (timeout);
+
+    return 0;
+}
new file mode 100644
--- /dev/null
+++ b/src/festival_interface.c
@@ -0,0 +1,75 @@
+/**
+ *  $Id: festival_interface.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/festival_interface.c $
+ */
+
+#ifdef FESTIVAL
+#include <festival_interface.h>
+
+ttshandles interface_init (tts_options t_options)
+{
+    ttshandles handle;
+
+    return handle;
+}
+
+long *interface_get_timing (ttshandles tts, char *text)
+{
+    int i;
+    long *t = NULL;
+
+    for (i = 0; i < strlen (text); i++) {
+        t = realloc (t, (i + 2) * sizeof (long));
+        t[i] = i * 20 + 10;
+    }
+
+    t[i] = 0;
+    return t;
+};
+
+int interface_write_to_wav (char *fname, char *text, ttshandles t_handles, tts_options t_options)
+{
+    char *s = NULL;
+
+    if ((s = malloc (strlen (text) + 80)) == NULL)
+        return -1;
+
+    sprintf (s, "printf \"%s\" | bin/festival_write_wav - %s", text, fname);
+#ifdef DEBUG
+    printf ("Writing %s\n", fname);
+#endif
+    system (s);
+
+    if (s != NULL)
+        free (s);
+    return 0;
+}
+
+tts_options interface_get_cl_opts (int num, char **arguments)
+{
+    tts_options options = { 0, 0, 0, 0 };
+    int c;
+
+    while ((c = getopt (num, arguments, "p:v:i:")) > 0) {
+        switch (c) {
+        case 'p':
+            options.Path = optarg;
+            break;
+        case 'v':
+            options.Voice = optarg;
+            break;
+        case 'i':
+            options.TextFile = optarg;
+            break;
+        }
+    }
+
+    if (options.TextFile == NULL) {
+        fprintf (stderr, "It's substantial to give a text file by -i <text file>!\n");
+        exit (0);
+    }
+
+    return options;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/keyboard.c
@@ -0,0 +1,36 @@
+/**
+ *  $Id: keyboard.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/keyboard.c $
+ */
+
+#include <keyboard.h>
+
+char getSingleKey ()
+{
+    // read and return single key with 1 second timeout
+
+    struct termios new_settings;
+    struct termios stored_settings;
+    int timeout = 1;            // 1 sec timeout
+    char c;
+
+    tcgetattr (0, &stored_settings);
+    new_settings = stored_settings;
+
+    new_settings.c_lflag &= ~(ICANON | ECHO);
+
+    new_settings.c_cc[VTIME] = timeout * 10;
+    new_settings.c_cc[VMIN] = 0;
+    tcsetattr (0, TCSANOW, &new_settings);
+
+    fflush (stdout);
+    c = getchar ();
+
+    tcsetattr (0, TCSANOW, &stored_settings);
+
+#ifdef DEBUG
+    if (isalpha (c))
+        printf ("received keypress: %c\n", c);
+#endif
+    return c;
+}
new file mode 100644
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,223 @@
+/**
+ *  $Id: main.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/main.c $
+ */
+
+#include <sentence.h>
+#include <keyboard.h>
+#include <thread.h>
+#include <audioplayer.h>
+#include <interface.h>
+
+#define STARTWRITER   0
+#define      WRITER   1
+#define      READER   2
+
+#define        STEP   2         // jump back n-steps
+
+void find_next (ThreadData * data)
+{
+    long tm = (long)audioplayer_gettime ();
+    long position;
+    int i, max;
+
+    max = words (data->sentences[data->satz]);
+
+    for (i = 0; i < max; i++) {
+        if (data->timings[data->satz][i] > tm)
+            break;
+    }
+
+    position = data->timings[data->satz][i];
+    audioplayer_settime (position);
+}
+
+void find_prev (ThreadData * data)
+{
+    long tm = (long)audioplayer_gettime ();
+    long position;
+    int i, max;
+
+    max = words (data->sentences[data->satz]);
+
+    for (i = STEP; i < max; i++) {
+        if (data->timings[data->satz][i] > tm)
+            break;
+    }
+
+    position = data->timings[data->satz][i - STEP];
+    audioplayer_settime (position);
+}
+
+int main (int argc, char **argv)
+{
+    char **sentences = NULL;    // to store an array of strings
+    char *Text = NULL;          // to store the content of a textfile
+    long **timings = NULL;      // to store the timings
+    int i, count;               // sentence counter
+    int verbose = 0;
+
+    pthread_t p_thread, w_thread;
+
+    ThreadData *data[3];        // independent thread data
+
+    tts_options ttsopt = interface_get_cl_opts (argc, argv);
+    ttshandles ttsh = interface_init (ttsopt);
+
+    if ((Text = readbuffer (ttsopt.TextFile)) != NULL) {
+        sentences = getstrings (Text, &count);
+        free (Text);
+    } else {
+        printf ("ERROR: Textfile %s is corrupt.\n", ttsopt.TextFile);
+        free (ttsopt.TextFile);
+        free (ttsopt.AudioFile);
+        free (ttsopt.Voice);
+        free (ttsopt.Path);
+
+        return EXIT_SUCCESS;
+    }
+
+    // Timinganalyse des Textes
+    if ((timings = calloc ((size_t) count, sizeof (long *) + 1)) == NULL) {
+        free (ttsopt.TextFile);
+        free (ttsopt.AudioFile);
+        free (ttsopt.Voice);
+        free (ttsopt.Path);
+
+        return EXIT_SUCCESS;
+    }
+
+    for (i = 0; i < count; i++) {
+        timings[i] = interface_get_timing (ttsh, sentences[i]);
+    }
+
+    /*
+     * Initialize Sound
+     */
+    if (audio_init ())
+        fprintf (stderr, "AUDIO ERROR\n");
+
+    for (i = 0; i < 3; i++) {
+        data[i] = malloc (sizeof (ThreadData) + 1);
+        if (data[i] == NULL)
+            exit (0);
+        data[i]->ttsopt = ttsopt;
+        data[i]->ttsh = ttsh;
+        data[i]->fname = ttsopt.TextFile;
+        data[i]->sentences = sentences;
+        data[i]->timings = timings;
+    }
+
+    /*
+     * write sentences from 0-1 :)
+     */
+    data[STARTWRITER]->satz = 0;
+    data[STARTWRITER]->items = 1;
+
+    pthread_create (&w_thread, NULL, (void *)writewav, data[STARTWRITER]);
+    pthread_join (w_thread, NULL);
+
+    /*
+     * write sentences from 1-count :)
+     */
+    data[WRITER]->satz = 1;
+    data[WRITER]->items = count;
+    pthread_create (&w_thread, NULL, (void *)writewav, data[WRITER]);
+
+    data[READER]->satz = 0;
+    data[READER]->items = count;
+    pthread_create (&p_thread, NULL, (void *)readtext, data[READER]);
+
+    while (data[READER]->satz < data[READER]->items) {
+        switch (getSingleKey ()) {
+        case 'i':
+            // next word
+            if (data[READER]->satz < data[READER]->items)
+                find_next (data[READER]);
+            else
+                printf ("ERROR: Cannot seek anymore\n");
+            break;
+
+        case 'j':
+            // previous sentence
+            if (data[READER]->satz > 0) {
+                data[READER]->satz--;
+                p_thread_restart (p_thread, readtext, data[READER]);
+            }
+            break;
+
+        case 'k':
+            // previous word
+            find_prev (data[READER]);
+            break;
+
+        case 'l':
+            // next sentence
+            if (data[READER]->satz < data[READER]->items) {
+                data[READER]->satz++;
+                p_thread_restart (p_thread, readtext, data[READER]);
+            }
+            break;
+
+        case 'p':
+            // print useful informations
+            printf ("Current Position:  [%5d/%5d]ms = #%d\n",
+                    audioplayer_gettime (), audioplayer_getwavelength (NULL), audioplayer_getposition ());
+            break;
+
+        case 'q':
+            // quit
+            pthread_cancel (w_thread);
+            pthread_cancel (p_thread);
+            data[READER]->satz = data[READER]->items;
+            break;
+
+        case 'r':
+            // reset player
+            pthread_cancel (p_thread);
+            if (!pthread_join (p_thread, NULL))
+                printf ("RESET\n");
+            break;
+        case 's':
+            printf ("S[%d]: %s\n", data[READER]->satz, sentences[data[READER]->satz]);
+            break;
+        case 'v':
+            verbose ^= 1;
+            audioplayer_setverbose (verbose);
+            break;
+
+        default:
+            /*
+             * unknown command
+             */
+            break;
+        }
+    }
+
+    if (!pthread_join (p_thread, NULL))
+        printf ("The last thread exited\n");
+
+    // cleanup memory
+    for (i = 0; i < count; i++) {
+        if (sentences[i] != NULL)
+            free (sentences[i]);
+        if (timings[i] != NULL)
+            free (timings[i]);
+    }
+
+    if (sentences != NULL)
+        free (sentences);
+
+    if (timings != NULL)
+        free (timings);
+
+    for (i = 0; i < 3; i++)
+        if (data[i] != NULL)
+            free (data[i]);
+
+    /*
+     * Cleanup sound
+     */
+    audio_shutdown ();
+    pthread_exit (NULL);
+}
new file mode 100644
--- /dev/null
+++ b/src/mbrola_interface.c
@@ -0,0 +1,79 @@
+/**
+ *  $Id: mbrola_interface.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/mbrola_interface.c $
+ */
+
+#ifdef MBROLA
+#include <mbrola_interface.h>
+
+ttshandles interface_init (tts_options t_options)
+{
+    ttshandles handle;
+
+    return handle;
+}
+
+long *interface_get_timing (ttshandles tts, char *text)
+{
+    long *t = NULL;
+    int i = 0;
+
+    for (i = 0; i < strlen (text); i++) {
+        t = realloc (t, (i + 2) * sizeof (long));
+        t[i] = i * 20 + 10;
+    }
+#ifdef DEBUG
+    printf ("\nTiming analysis ends\n");
+#endif
+
+    t[i] = 0;
+
+    return t;
+};
+
+int interface_write_to_wav (char *fname, char *text, ttshandles t_handles, tts_options t_options)
+{
+    char *s = NULL;
+
+    if ((s = malloc (strlen (text) + 80)) == NULL)
+        return -1;
+
+    sprintf (s, "printf \"%s\" | bin/mbrola_write_wav - %s", text, fname);
+#ifdef DEBUG
+    printf ("Writing %s\n", fname);
+#endif
+    system (s);
+
+    if (s != NULL)
+        free (s);
+    return 0;
+}
+
+tts_options interface_get_cl_opts (int num, char **arguments)
+{
+    tts_options options = { 0, 0, 0, 0 };
+    int c;
+
+    while ((c = getopt (num, arguments, "p:v:i:")) > 0) {
+        switch (c) {
+        case 'p':
+            options.Path = optarg;
+            break;
+        case 'v':
+            options.Voice = optarg;
+            break;
+        case 'i':
+            options.TextFile = optarg;
+            break;
+        }
+    }
+
+    if (options.TextFile == NULL) {
+        fprintf (stderr, "It's substantial to give a text file by -i <text file>!\n");
+        exit (0);
+    }
+
+    return options;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/src/proser_interface.c
@@ -0,0 +1,167 @@
+/**
+ *  $Id: proser_interface.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/proser_interface.c $
+ */
+
+#ifdef PROSER
+#include <proser_interface.h>
+
+ttshandles interface_init (tts_options propt)
+{
+
+    ttshandles pr_handle;
+
+    // initialize Proser options and set default values for a given voice
+    if (init_ProserOpt (&propt.ProserOpt, propt.Voice)) {
+        fprintf (stderr, "Fatal error occurred in set_ProserOpt: %s\n", GetLastNlpErrorDescription (NULL));
+        exit (-1);
+    }
+    // the path to the TTS input data like dictionaries and prosodic stuff has to be set
+
+    propt.ProserOpt.Path = strdup (propt.Path);
+
+    // here some more manipulations of the standard settings can be done
+
+    propt.ProserOpt.PreEmphasis = propt.PreEmphasis;
+    propt.ProserOpt.Speed = propt.Speed;
+
+    // initialize channel //
+    if (!(pr_handle.GermanNlp = OpenNlp (&propt.ProserOpt))) {
+        fprintf (stderr, "Fatal error occurred in OpenNlp: %s (%d)\n",
+                 GetLastNlpErrorDescription (pr_handle.GermanNlp), (int)GetLastNlpError (pr_handle.GermanNlp));
+        exit (-1);
+    }
+    // delete structure for Proser Options //
+    if (delete_ProserOpt (&propt.ProserOpt)) {
+        fprintf (stderr, "Fatal error occurred in delete_ProserOpt: %s\n", GetLastNlpErrorDescription (NULL));
+        exit (-1);
+    }
+    return pr_handle;
+}
+
+int interface_write_to_wav (char *Filename, char *Text, ttshandles prosh, tts_options propt)
+{
+    // write Text to a file
+    if (ProserSynthText (prosh.GermanNlp, Text, Filename, propt.FileType, propt.Stype)) {
+        fprintf (stderr, "Fatal error occurred in ProserSynthText: %s\n", GetLastNlpErrorDescription (prosh.GermanNlp));
+        return (-1);
+    }
+    return (0);
+}
+
+long *interface_get_timing (ttshandles prosh, char *Text)
+{
+    // analyze given text, return array with long values containing
+    // time in ms when each word of the given text will start in the
+    // output
+    long *timings = NULL;
+    LPPHONEME PhoneticSentenceDescription;
+    long NumberOfPhoneticUnits;
+    int i = 0, WordNum = 0;
+
+    PhoneticSentenceDescription = TextToPho (prosh.GermanNlp, Text, &NumberOfPhoneticUnits);
+#ifdef DEBUG
+    printf ("\n[S] %s\n", Text);
+#endif
+    while (i < (NumberOfPhoneticUnits - 1)) {
+        if (PhoneticSentenceDescription[i + 1].Event != 0) {
+            timings = realloc (timings, (WordNum + 2) * sizeof (long));
+            timings[WordNum] = PhoneticSentenceDescription[i + 1].Offset;
+#ifdef DEBUG
+            printf ("Wort:\t %i \t Time: %ld ms\n", WordNum, PhoneticSentenceDescription[i + 1].Offset);
+#endif
+            WordNum++;
+        }
+        i++;
+    }
+    timings[WordNum] = 0;
+    return timings;
+}
+
+tts_options interface_get_cl_opts (int argc, char **argv)
+{
+    int i, j;
+    tts_options propt;
+
+    propt.TextFile = propt.AudioFile = propt.Voice = propt.Path = NULL;
+
+    j = 0;
+    propt.PreEmphasis = 0.0f;
+    propt.Speed = 1.0f;
+    propt.Stype = LIN16;
+    propt.FileType = WAV;
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp (argv[i], "-i")) {
+            propt.TextFile = argv[++i];
+            continue;
+        } else if (!strcmp (argv[i], "-o")) {
+            propt.AudioFile = argv[++i];
+            continue;
+        } else if (!strcmp (argv[i], "-v")) {
+            propt.Voice = argv[++i];
+            continue;
+        } else if (!strcmp (argv[i], "-p")) {
+            propt.Path = argv[++i];
+            continue;
+        } else if (!strcmp (argv[i], "-pre")) {
+            propt.PreEmphasis = atof (argv[++i]);
+            continue;
+        } else if (!strcmp (argv[i], "-speed")) {
+            propt.Speed = atof (argv[++i]);
+            continue;
+        } else if (!strcmp (argv[i], "-format")) {
+            i++;
+            for (j = 0; j < (int)strlen (argv[i]); j++)
+                argv[i][j] = toupper (argv[i][j]);
+            if (!strcmp (argv[i], "RAW")) {
+                propt.FileType = RAW;
+                continue;
+            } else if (!strcmp (argv[i], "WAV")) {
+                propt.FileType = WAV;
+                continue;
+            } else if (!strcmp (argv[i], "AU")) {
+                propt.FileType = AU;
+                continue;
+            } else {
+                fprintf (stderr, "Unknown output type %s\n", argv[i]);
+                fprintf (stderr, "Supported output types: RAW - AU - WAV\n");
+                exit (-1);
+            }
+        }
+        if (strcmp (argv[i], "-audio") == 0) {
+            i++;
+            for (j = 0; j < strlen (argv[i]); j++)
+                argv[i][j] = toupper (argv[i][j]);
+            if (!strcmp (argv[i], "LIN16")) {
+                propt.Stype = LIN16;
+                continue;
+            } else if (!strcmp (argv[i], "LIN8")) {
+                propt.Stype = LIN8;
+                continue;
+            } else if (!strcmp (argv[i], "ULAW")) {
+                propt.Stype = ULAW;
+                continue;
+            } else if (!strcmp (argv[i], "ALAW")) {
+                propt.Stype = ALAW;
+                continue;
+            }
+        } else {
+            fprintf (stderr, "Unknown option: %s\n", argv[i]);
+            exit (-1);
+        }
+    }
+
+    if (!propt.TextFile) {
+        fprintf (stderr, "It's substantial to give a text file by -i <text file>!\n");
+        exit (-1);
+    } else if (!propt.Voice) {
+        fprintf (stderr, "It's substantial to give a voice database by -v <voice>!\n");
+        exit (-1);
+    } else if (!propt.Path) {
+        fprintf (stderr, "It's substantial to give a path for the prosodic stuff by -p <path>!\n");
+        exit (-1);
+    }
+    return (propt);
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/src/sentence.c
@@ -0,0 +1,164 @@
+/**
+ *  $Id: sentence.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/sentence.c $
+ */
+
+#include <sentence.h>
+
+int words (char *ptr)
+{
+    char *buffer = NULL;
+    char *token;
+    int count = 0;
+
+    if (ptr != NULL)
+        buffer = strdup (ptr);
+
+    if (buffer == NULL)
+        return -1;
+
+    token = strtok (buffer, " ");
+    while (token != NULL) {
+        token = strtok (NULL, " ");
+        count++;
+    }
+
+    if (buffer != NULL)
+        free (buffer);
+
+    return count;
+}
+
+int *parse (char *buf)
+{
+    int count = 0;
+    int i;
+    int *s_ptr = NULL;
+
+    s_ptr = malloc (2 * sizeof (int));
+    s_ptr[count++] = 0;
+
+    for (i = 0; i < strlen (buf); i++)
+        switch (buf[i]) {
+        case '\n':
+        case '\t':
+        case '"':
+        case '\'':
+            buf[i] = ' ';
+            break;
+        case '.':
+        case '!':
+        case '?':
+            s_ptr = realloc (s_ptr, (count + 2) * sizeof (int));
+            if (s_ptr == NULL) {
+                printf ("Not enough memory\n");
+                return NULL;
+            }
+            s_ptr[count++] = ++i;
+            break;
+        default:
+            break;
+        }
+
+    s_ptr[count] = 0;
+
+    return s_ptr;
+}
+
+char *readbuffer (char *fname)
+{
+    FILE *f;
+    char *text = NULL;
+    char buffer[201];
+
+    if ((f = fopen (fname, "r")) == NULL) {
+        fprintf (stderr, "ERROR: Cannot open %s for reading!\n", fname);
+        return NULL;
+    }
+
+    text = malloc (2);
+    *text = 0;
+
+    while (fgets (buffer, 200, f) != 0) {
+        if ((text = realloc (text, strlen (text) + strlen (buffer) + 1)) == NULL) {
+            printf ("Not enough memory\n");
+            return NULL;
+        };
+        strcat (text, buffer);
+        *buffer = 0;
+    }
+
+    fclose (f);
+    return text;
+}
+
+char *getSentence (char *text, int start, int end)
+{
+    int i;
+    char *value = NULL;
+
+    if ((i = end - start) < 0)
+        return NULL;
+
+    value = malloc (i + 1);
+    if (value == NULL)
+        return NULL;
+
+    i = 1;
+    while (i) {
+        switch (text[start]) {
+        case '.':
+        case ',':
+        case '!':
+        case '?':
+        case '(':
+        case ')':
+        case '\n':
+        case ' ':
+            start++;
+            break;
+        default:
+            i = 0;
+            break;
+        }
+    }
+
+    for (i = start; i < end; i++) {
+        value[i - start] = text[i];
+    }
+
+    value[i - start] = 0;
+
+    return value;
+}
+
+char **getstrings (char *Text, int *value)
+{
+    char *ptr;
+    int i = 0;
+    int count = 0;
+    char **sentences = NULL;
+    int *s_ptr;
+
+    if ((s_ptr = parse (Text)) == NULL)
+        return NULL;
+
+    while (s_ptr[i + 1] > 0) {
+        if ((ptr = getSentence (Text, s_ptr[i], s_ptr[i + 1])) == NULL)
+            return NULL;
+        if (strlen (ptr) > 0) {
+            if ((sentences = realloc (sentences, (count + 1) * sizeof (char *) + 1)) == NULL)
+                return NULL;
+            sentences[count++] = strdup (ptr);
+        }
+        if (ptr != NULL)
+            free (ptr);
+        i++;
+    }
+
+    if (s_ptr)
+        free (s_ptr);
+
+    *value = count;
+    return sentences;
+}
new file mode 100644
--- /dev/null
+++ b/src/thread.c
@@ -0,0 +1,60 @@
+/**
+ *  $Id: thread.c 53 2008-01-10 00:19:41Z mbroeker $
+ * $URL: http://localhost/svn/c/VirtualReader/trunk/src/thread.c $
+ */
+
+#include <thread.h>
+
+int p_thread_restart (pthread_t p_thread, void *func, ThreadData * data)
+{
+    // stops a thread, waits for it to exit and then restarts it using
+    // the current data structure
+    int ret;
+
+    pthread_cancel (p_thread);
+    if (pthread_join (p_thread, NULL))
+        printf ("RESTART: Cannot find a suitable thread :)\n");
+
+    ret = pthread_create (&p_thread, NULL, (void *)func, data);
+
+    /*
+     * TODO: Error Handling
+     */
+    return ret;
+}
+
+void readtext (ThreadData * data)
+{
+    // read the current sentence using the audio player
+    // TODO - test for existence (completeness?) of file before read
+    char fname[80];
+
+    pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+    pthread_cleanup_push (audioplayer_stop, NULL);
+
+    for (; data->satz < data->items; data->satz++) {
+        sprintf (fname, "audio/%s-%i.wav", data->fname, data->satz);
+        if ((audioplayer (fname, TIMEOUT)) != -1)
+            audioplayer_stop ();
+        else
+            pthread_exit (NULL);
+    }
+
+    pthread_exit (NULL);
+    pthread_cleanup_pop (1);
+}
+
+void writewav (ThreadData * data)
+{
+    // write wav file for each sentence between data->satz adn
+    // data->items
+    char fname[80];
+    int i;
+
+    for (i = data->satz; i < data->items; i++) {
+        sprintf (fname, "audio/%s-%i.wav", data->fname, i);
+        interface_write_to_wav (fname, data->sentences[i], data->ttsh, data->ttsopt);
+    }
+
+    pthread_exit (NULL);
+}
new file mode 100644
--- /dev/null
+++ b/test.txt
@@ -0,0 +1,111 @@
+Einst herrschte ein großer starker Pirat über die sieben Weltmeere. 
+Überall war "er verhasst und bekannt. Er riss Alles an sich, was nicht 
+Niet- und Nagelfest war und erschreckte Alle durch seine angsteinflößede 
+Art und durch sein Aussehen. Seine Besatzung hatte sich nach und nach 
+aus dem Staube" gemacht, wei der Pirat Alles für sich haben wollte und 
+ungerecht zu ihnen war. Er machte ihnen das Leben an Bord stets zur 
+Hölle. Das Schiff des Piratens wurde immer prunkvoller und schöner. Die 
+Segel waren aus goldener Seide, die Masten aus Elfenbein, das Holz aus 
+Teak, die Schrauben und Muttern, die alles fest hielten aus feinem 
+Silber. Das Glas in den Fenstern war aus schillerndem Perlmutt und 
+glitzerte mit dem Meer um die Wette. Zufrieden spazierte der Pirat über 
+sein Schiff, welches ein einzig großer Schatz war. Er liebte seinen 
+Reichtum und wollte immer mehr davon. BEkam er das, was er wollte, war 
+er ein paar Tage glücklich, doch dann wurde der Drang nach etwas noch 
+Größerem und noch Schönerem immer größer. Irgendetwas fehlte da, was ihn 
+unendlich glücklich machen würde. Doch kein Rubin der Welt, keine 
+goldene Krone, kein silberner Taler schaffte es ihn länger als 3 Tage 
+glücklich zu machen. Somit musste er, um seine Zufriedenheit zu erhalten 
+sehr oft auf Raubzug gehen.
+Eines Tages kam er an eine kleine Insel. Schon von weitem sah er die 
+kleine Truppe von Eingeborenen, die um ein Lagerfeuer saßen, trommelten, 
+aßen und lachten.
+Sie hatten nichts bei sich, außer ihre Baströckchen, ihre Instrumente 
+und ihr spärliches Mahl –
+und doch machten sie einen glücklicheren Eindruck, als er sich je 
+vorstellen konnte.
+Er hatte selten Menschen gesehen, die so glücklich und zufrieden waren 
+wie diese.
+Er fragte sich, welche Schätze sie wohl zu Hause versteckt hielten. Denn 
+ohne einen großen Reichtum ließe sich in seinem Piratenkopf die große 
+Glückseeligkeit nicht erklären.
+Als er den Anker warf und an Land ging, stürmte der Stamm der 
+Eingeborenen hastig von Dannen, bis auf ein kleiner Junge. Der Pirat 
+fragte den Jungen, warum sie anderen weggelaufen sind und was es denn 
+bei ihm im Dorf schönes zu holen gäbe.
+Der kleine Junge antwortete munter und fürchtete sich kein bisschen vor 
+dem Pirat, auch wenn dieser furcht erregend aussah. In seinen Augen 
+nämlich sah der Junge Unsicherheit, Traurigkeit und Einsamkeit. Außerdem 
+bemerkte der Junge das Holzbein des Piraten. Damit hätte er ihm nie so 
+flink folgen können. Der Junge erzählte dem Pirat von seinem Dorf, den 
+Blätter und Strohhütten und von seiner Familien und seinen Freunden.
+„Freunde?“ fragte der Pirat. Er konnte sich nichts darunter vorstellen 
+unter diesem Begriff.
+Der kleine Junge versuchte ihm zu erklären, was Freundschaft ist und der 
+Pirat staunte nicht schlecht. Nun wollte er unbedingt einen Freund 
+haben, denn der Junge meinte, ein Freund sei der größte Schatz der Welt. 
+Das machte den Piraten neugierig.
+Doch so einfach war das nicht. Ein Freund ist unbezahlbar und das 
+verstand der Pirat nicht.
+Man konnte einen Freund nicht einfach kaufen oder stibitzen.
+Andere Dinge zählten. Dinge, von denen der Pirat noch nie in seinem 
+Leben gehört hatte.
+Der kleine Junge wollte dem Pirat zeigen, was Freundschaft ist und sie 
+trafen sich jeden Tag, redeten, lachten und machten Feuer. Der Junge 
+zeigte dem Pirat wie man Fische fängt und der Pirat zeigte dem Jungen, 
+in welchen Muscheln man dir größten Perlen findet.
+Nach und nach verloren auch die anderen vom Stamm die Furcht vor dem 
+Piraten und abends wurde am Lagerfeuer getanzt, gesungen und gelacht. 
+Der Pirat fühlte sich wohler als je zuvor und hatte durch den kleinen 
+Jungen erfahren, was es bedeutet, Freunde zu finden.
+Er wurde von Tag zu Tag glücklicher und zufriedener und ihm stand wenig 
+Sinn nach seinen Räuberzügen.
+Eines Tages jedoch wurde der kleine Junge sehr krank. Keine Heilpflanze 
+konnte ihm helfen, kein Schamane konnte Wunder bewirken, keiner der im 
+Tanz und Klang herbeigerufenen Geister halfen ihm. Ein wichtiges 
+Medikament von einem anderen Kontinent wurde benötigt.
+Somit machte sich der Pirat sofort auf die Reise, dieses Medikament zu 
+besorgen. Die Zeit war knapp. Es blieben dem Jungen nur noch wenige 
+Wochen, vielleicht sogar nur Tage.
+Der Stamm war dem Piraten sehr dankbar und sie beteten und hofften auf 
+eine baldige Rückkehr mit dem Medikament. Der Pirat fuhr drei Tage und 
+drei Nächte durch Wind und Wetter und kam endlich an seinem Zielort an. 
+Er machte sich große Sorgen um seinen Freund. Das Medikament war sehr 
+teuer. Der Pirat wollte es mit Kanonenschuss und Messerwurf erwerben, 
+doch irgendetwas hielt ihn zurück. Er konnte seine Boshaftigkeit nicht 
+mehr zeigen, denn wenn er in die Gesichter von den Menschen schaute, 
+ihre Blicke sah, dann musste er an seinen Freund denken und an seinen 
+Stamm, der ihn so freundlich aufgenommen hatte.
+Also beschloss er das Medikament zu kaufen. Er gab sehr viel von seinem 
+Reichtum ab und verkaufte ebenso einen Teil davon, um ein paar Geschenke 
+und Nahrungsmittel für den Stamm mitzubringen. Nun war sein Schiff gar 
+nicht mehr so pompös, wie zuvor, aber es störte ihn seltsamerweise nicht 
+weiter. Für ihn zählte nur das Leben seines Freundes, dem kleinen 
+Jungen. Auf dem Weg zu ihm kam er an einer kleinen einsamen Insel 
+vorbei, auf der eine Familie gestrandet war. Sie flehten um Hilfe, dass 
+er sie mitnehme. Da der Pirat jedoch schnellst möglich in eine andere 
+Richtung musste, um zur Insel seines Freundes zu gelangen, blieb ihm 
+nichts anderes übrig als ihnen das große Schiff zu überlassen. Er selbst 
+fuhr mit dem kleinen Beiboot zur Insel, die nicht mehr so weit entfernt 
+war.
+Ein wenig seltsam war es schon, alles abgegeben zu haben, doch mit dem 
+Seufzer kam auch eine seltsame Erleichterung. Wie eine tonnenschwere 
+Last, die abgeworfen wurde.
+Als der Pirat an der Insel ankam, wurde er schon erwartet. Der Junge war 
+noch schlechter zurecht als zuvor und der Guru hatte schon das letzte 
+Gebet ausgesprochen und ihn einbalsamiert. Das Medikament jedoch half 
+ihm in allerletzter Sekunde und er wurde von Tag zu Tag gesünder. Nach 
+einer Woche konnte er wieder aufstehen und mit den anderen Kindern 
+spielen. Während sein Vater einen Arm um den Pirat legte und „Mnumbai, y 
+zmuni“ – Danke, mein Freund, sagte, schaute der Pirat glücklich zu. Der 
+Junge hatte sein Leben zurückbekommen, Dank ihm. Und er hatte wahre 
+Freunde gefunden. Das hatte er dem Jungen zu verdanken. Der Pirat hatte 
+ebenfalls bewiesen, dass ihm ein Freund mehr wert ist, als alle Schätze 
+der Welt. Er wurde damit belohnt, dass er nicht weiter einsam war.
+Der Stamm nahm den Pirat für immer bei sich auf und er war glücklich und 
+zufrieden bis an sein Lebensende. Sein kleiner Freund wuchs heran und 
+wurde irgendwann ein weiser Häuptling. Er erzählte seinen Kindern und 
+Kindeskindern am Lagerfeuer von seinem treuen Piratenfreund. Immer, wenn 
+er ein Piratenschiff am Horizont vorbeifahren sah, dachte er an seinen 
+Freund zurück, dem er sein Leben zu verdanken hatte.
+