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);
+}