Changed volume of espeak slightly.
[ipage.git] / ipage.c
blob90514342825a49afe70e46a73b1dc14f336d1dae
1 /***************************************************************************
2 * Copyright (C) 2010,2011 by Rynhardt Kruger *
3 * email: rynkruger@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see: *
17 * <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
20 #include <curses.h>
21 #include <wchar.h>
22 #include <espeak/speak_lib.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
28 #define _GNU_SOURCE
30 char filename[2000];
31 long linenum = 1;
32 char evoice[40];
33 char epunct[50];
34 long lastline = 0;
35 int chars = 0;
36 int offset = 0;
37 const int ratemult = 35;
38 int rate = 5;
39 int sayall = 0;
40 FILE * source;
41 char mainbuf[1024*64];
42 int mainlen = 1024*64;
43 int mainpos = 0;
44 int datapos = 0;
45 char sbuf [100];
46 char markname[1000];
47 int marks[27];
49 // prototypes
50 char prevchar(FILE * source);
51 int prevline(char * data);
52 int gotoline(int n);
53 int nextline(char * data);
55 int nextchunc() {
56 int i = 0;
57 if (feof(source))
58 return 1;
59 while (! feof(source)&& i < 1024*64) {
60 int f = fgetc(source);
61 if (f == EOF)
62 break;
63 mainbuf[i] = f;
64 i++;
66 mainlen = i;
67 mainpos = 0;
68 return 0;
71 int prevchunc() {
72 if (ftell(source) > mainlen) {
73 fseek(source,0-(mainlen+1024*64),SEEK_CUR);
74 nextchunc();
75 mainpos = 1024*64-1;
76 return 0;
78 return 1;
81 void uprate() {
82 if (rate < 9)
83 rate++;
84 espeak_SetParameter(espeakRATE,rate*ratemult,0);
87 void writesets() {
88 char spath[100];
89 spath[0] = '\0';
90 char *val = getenv("HOME");
91 strcat(spath,val);
92 strcat(spath,"/.ipagerc");
93 FILE *f = fopen(spath,"w");
94 fprintf(f,"speech %s %d %s\n", evoice,rate,epunct);
97 void readsets() {
98 char spath[100];
99 spath[0] = '\0';
100 char *val = getenv("HOME");
101 strcat(spath,val);
102 strcat(spath,"/.ipagerc");
103 FILE *f = fopen(spath,"r");
104 if (!f) {
105 return;
107 char sv[40];
108 int sr = 0;
109 char sp[40];
110 char wp[100];
111 int k = fscanf(f,"speech %s %d %s\n", sv,&sr,sp);
112 if (k == EOF) beep();
113 espeak_SetVoiceByName(sv);
114 espeak_SetParameter(espeakRATE,ratemult*(rate =sr),0);
115 mbstowcs(wp,sp,40);
116 espeak_SetPunctuationList(wp);
117 strcpy(evoice,sv);
118 strcpy(epunct,sp);
119 espeak_SetParameter(espeakPUNCTUATION,espeakPUNCT_SOME,0);
120 fclose(f);
123 void downrate() {
124 if (rate > 1)
125 rate--;
126 espeak_SetParameter(espeakRATE,rate*ratemult,0);
129 void choosepunct() {
130 move(getmaxy(stdscr)-1,0);
131 clrtoeol();
132 mvaddstr(getmaxy(stdscr)-1,0,"Enter punctuation list: ");
133 refresh();
134 char p[50];
135 char wp[110];
136 echo();
137 mvgetnstr(getmaxy(stdscr)-1,getcurx(stdscr),p,50);
138 noecho();
139 strcpy(epunct,p);
140 mbstowcs(wp,p,50);
141 espeak_SetPunctuationList(wp);
142 espeak_SetParameter(espeakPUNCTUATION,espeakPUNCT_SOME,0);
145 void choosevoice() {
146 move(getmaxy(stdscr)-1,0);
147 clrtoeol();
148 mvaddstr(getmaxy(stdscr)-1,0,"Enter voice name: ");
149 refresh();
150 char v[20];
151 echo();
152 mvgetnstr(getmaxy(stdscr)-1,getcurx(stdscr),v,20);
153 noecho();
154 strcpy(evoice,v);
155 espeak_SetVoiceByName(v);
158 void readmarks(FILE * mf) {
159 int i;
160 for (i = 0; i < 27; i++)
161 fscanf(mf,"%d\n",&marks[i]);
164 void createmarks() {
165 int i;
166 for (i = 0; i < 27; i++)
167 marks[i] = 0;
170 void savemarks() {
171 FILE * mf = fopen(markname,"w");
172 int i;
173 for (i = 0; i < 26; i++)
174 fprintf(mf,"%d\n",marks[i]);
175 fprintf(mf,"%d\n",linenum);
176 fclose(mf);
179 int gotomark(int n) {
180 if (n < 0 || n > 26)
181 return 1;
182 if (marks[n] > 0) {
183 gotoline(marks[n]);
184 return 0;
186 else
187 return 2;
190 void gotomarkchar() {
191 move(getmaxy(stdscr)-1,0);
192 clrtoeol();
193 mvaddstr(getmaxy(stdscr)-1,0,"mark: ");
194 refresh();
195 char m = getch();
196 if (m < 'a' || m > 'z' || marks[m-97] == 0) {
197 mvaddstr(getmaxy(stdscr)-1,0,"Invalet mark! Press any key. ");
198 refresh();
199 getch();
200 return;
202 gotomark(m-97);
205 void savemark() {
206 move(getmaxy(stdscr)-1,0);
207 clrtoeol();
208 mvaddstr(getmaxy(stdscr)-1,0,"mark: ");
209 refresh();
210 char m = getch();
211 if (m < 'a' || m > 'z') {
212 mvaddstr(getmaxy(stdscr)-1,0,"Invalet mark! Press any key. ");
213 refresh();
214 getch();
215 return;
217 marks[m-97] = linenum;
220 void initmarks() {
221 strcpy(markname,filename);
222 strcat(markname,".ipm");
223 FILE * mf = fopen(markname,"r");
224 if (!mf)
225 createmarks();
226 else {
227 readmarks(mf);
228 gotomark(26);
229 fclose(mf);
233 void gotobegin() {
234 gotopos(0);
235 linenum = 1;
238 void gotoend() {
239 char data [200];
240 int err = 0;
241 while (err == 0)
242 err = nextline(data);
245 void gotolinenum() {
246 move(getmaxy(stdscr)-1,0);
247 clrtoeol();
248 mvaddstr(getmaxy(stdscr)-1,0,"Enter line number: ");
249 refresh();
250 int num;
251 char snum[5];
252 echo();
253 mvgetnstr(getmaxy(stdscr)-1,getcurx(stdscr),snum,5);
254 noecho();
255 num = atoi(snum);
256 int err = gotoline(num);
257 if (err > 1) {
258 mvaddstr(getmaxy(stdscr)-1,0, "Invalet line number! Press any key. ");
259 refresh();
260 getch();
264 int gotoline(int n) {
265 int l = linenum;
266 char data[200];
267 if (n < 1)
268 return 1;
269 if (n < l)
270 for (; n<l; n++)
271 prevline(data);
272 else {
273 int err = 0;
274 for (; n>l&&err==0; n--)
275 err = nextline(data);
276 if (err>0) {
277 gotoline(l);
278 return 2;
281 return 0;
284 void searchp() {
285 int l = linenum;
286 refresh();
287 char data [getmaxx(stdscr)];
288 int err = 0;
289 prevline(data);
290 strcpy(data,"");
291 while (strcasestr(data,sbuf) == NULL&& err == 0)
292 err = prevline(data);
293 if (err >0) {
294 gotoline(l);
295 mvaddstr(getmaxy(stdscr)-1,0,"Text not found! Press any key. ");
296 refresh();
297 getch();
301 void searchf() {
302 move(getmaxy(stdscr)-1,0);
303 clrtoeol();
304 mvaddstr(getmaxy(stdscr)-1,0,"Enter text to find: ");
305 refresh();
306 echo();
307 mvgetnstr(getmaxy(stdscr)-1,getcurx(stdscr),sbuf,100);
308 noecho();
309 int l = linenum;
310 refresh();
311 char data [getmaxx(stdscr)];
312 int err = 0;
313 nextline(data);
314 strcpy(data,"");
315 while (strcasestr(data,sbuf) == NULL&& err == 0)
316 err = nextline(data);
317 prevline(data);
318 if (err >0) {
319 gotoline(l);
320 mvaddstr(getmaxy(stdscr)-1,0,"Text not found! Press any key. ");
321 refresh();
322 getch();
326 void searchn() {
327 int l = linenum;
328 refresh();
329 char data [getmaxx(stdscr)];
330 int err = 0;
331 nextline(data);
332 strcpy(data,"");
333 while (strcasestr(data,sbuf) == NULL&& err == 0)
334 err = nextline(data);
335 prevline(data);
336 if (err >0) {
337 gotoline(l);
338 mvaddstr(getmaxy(stdscr)-1,0,"Text not found! Press any key. ");
339 refresh();
340 getch();
345 void speakcall(short * wav, int size, espeak_EVENT * evt) {
346 int i = 0;
347 while (evt[i].type !=0) {
348 if (evt[i].type == espeakEVENT_END)
349 chars = evt[i].text_position;
350 else if (evt[i].type == espeakEVENT_MSG_TERMINATED && sayall) {
351 speak();
352 break;
354 i++;
358 char cchar() {
359 return mainbuf[mainpos];
362 int nchar() {
363 if (mainpos < mainlen-1)
364 mainpos++;
365 else if (nextchunc() != 0) {
366 return 1;
368 datapos++;
369 return 0;
372 int pchar() {
373 if (datapos == 0)
374 return 1;
375 if (mainpos > 0)
376 mainpos--;
377 else if (prevchunc() != 0)
378 return 1;
379 datapos--;
380 return 0;
383 int gotopos(int pos) {
384 if (pos > datapos)
385 while (pos>datapos)
386 nchar();
387 else
388 while (pos < datapos) {
389 pchar();
391 return 0;
394 int nextline(char * data) {
395 int i = 0;
396 char c = 0;
397 while (c !='\n') {
398 c = cchar();
399 data[i] = c;
400 i++;
401 if (nchar()) {
402 return 1;
405 data[i] = 0;
406 if (strlen(data) == 0)
407 return 1;
408 linenum++;
409 //char tmp[140];
410 //sprintf(tmp,"espeak %s",data);
411 // system(tmp);
412 // system("beep");
413 return 0;
416 void speak() {
417 if (lastline == linenum)
418 return;
419 lastline = linenum;
420 char paragraph[1200];
421 char retval[140];
422 offset = datapos;
423 strcpy(paragraph,"");
424 strcpy(retval,"");
425 while (strlen(paragraph) < 1000 && strcmp(retval,"\n") != 0) {
426 nextline(retval);
427 strcat(paragraph,retval);
429 espeak_Synth(paragraph,1140,0,POS_CHARACTER,0,1,NULL,NULL);
432 void start_sayall() {
433 if (sayall == 0)
434 sayall = 1;
435 else
436 return;
438 pthread_attr_t pa;
439 pthread_attr_init(&pa);
440 pthread_t thread;
441 pthread_create(&thread,&pa,speak,0);
443 speak();
446 void stop_sayall() {
447 sayall = 0;
448 espeak_Cancel();
449 lastline = 0;
450 int i = offset+chars;
451 char data[100];
452 while (datapos > i)
453 prevline(data);
456 char prevchar(FILE * source) {
457 fseek(source,-2, SEEK_CUR);
458 return (char) getc(source);
461 int prevline(char * data) {
462 if (linenum == 1)
463 return 1;
464 int i = 0;
465 int j = 0;
466 if (linenum > 2) {
467 while (i < 2) {
468 pchar();
469 if (cchar()=='\n')
470 i++;
471 if (i < 2) {
472 data[j] = cchar();
473 j++;
476 data[j] = '\0';
477 nchar();
478 for (i = 0, j = strlen(data)-1; i<j; i++,j--) {
479 char tmp = data[i];
480 data[i] = data[j];
481 data[j]=tmp;
484 else {
485 gotopos(0);
486 nextline(data);
487 linenum -=1;
488 gotopos(0);
490 linenum-=1;
491 return 0;
494 int readpage(char * data) {
495 int i = 0;
496 char line[200];
497 int pos = datapos;
498 int num = linenum;
499 while (i < getmaxy(stdscr)-1 && nextline(line)==0) {
500 strcat(data,line);
501 i++;
503 linenum = num;
504 gotopos(pos);
505 return 0;
508 int nextpage() {
509 char data[200];
510 int i = 0;
511 int err = 0;
512 while (i < getmaxy(stdscr)-1&&err==0) {
513 err = nextline(data);
514 i++;
516 return 0;
519 int prevpage() {
520 char data[200];
521 int i = getmaxy(stdscr)-1;
522 while (i > 0) {
523 prevline(data);
524 i--;
526 return 0;
529 void printpage() {
530 char data[140*79] = "";
531 readpage(data);
532 clear();
533 addstr(data);
534 char tmpstr[140];
535 sprintf(tmpstr,"%s line %d filepos %d (%d)", filename,linenum,ftell(source),mainlen);
536 mvaddstr(getmaxy(stdscr)-1,0,tmpstr);
537 move(0,1);
538 refresh();
539 if (sayall) {
540 stop_sayall();
541 start_sayall();
545 void pagefile() {
546 nextchunc();
547 initscr();
548 noecho();
549 cbreak();
550 keypad(stdscr,true);
551 int ch = 0;
552 initmarks();
553 readsets();
554 printpage();
555 char data[200];
556 while (ch != 'q') {
557 ch = getch();
558 switch(ch) {
559 case 'p':
560 choosepunct();
561 break;
562 case 'v':
563 choosevoice();
564 break;
565 case '1':
566 downrate();
567 break;
568 case '2':
569 uprate();
570 break;
571 case ' ':
572 case KEY_NPAGE:
573 nextpage();
574 printpage();
575 break;
576 case KEY_HOME:
577 case 'B':
578 gotobegin();
579 printpage();
580 break;
581 case KEY_END:
582 case 'E':
583 gotoend();
584 printpage();
585 break;
586 case '<':
587 searchp();
588 printpage();
589 break;
590 case '>':
591 searchn();
592 printpage();
593 break;
594 case 'g':
595 gotolinenum();
596 printpage();
597 break;
598 case 'b':
599 case KEY_PPAGE:
600 prevpage();
601 printpage();
602 break;
603 case KEY_DOWN:
604 nextline(data);
605 printpage();
606 break;
607 case KEY_UP:
608 prevline(data);
609 printpage();
610 break;
611 case 'a':
612 start_sayall();
613 break;
614 case '/':
615 searchf();
616 printpage();
617 break;
618 case 'm':
619 gotomarkchar();
620 printpage();
621 break;
622 case 's':
623 savemark();
624 printpage();
625 break;
626 case 'c':
627 stop_sayall();
628 printpage();
629 break;
632 savemarks();
633 writesets();
634 endwin();
637 main(int argc, char * argv[]) {
638 if (argc == 1) {
639 fprintf(stderr, "Usage: ipage <filename>\n");
640 return 1;
642 char cmd[200];
643 strcpy(filename,argv[1]);
644 sprintf(cmd,"fold -s \"%s\" | dos2unix -U > /tmp/ipage.tmp",filename);
645 int err = system(cmd);
646 system("echo >> /tmp/ipage.tmp");
647 source = fopen("/tmp/ipage.tmp", "r");
648 if (!source|| err) {
649 fprintf(stderr,"File doesn't exist!\n");
650 return 2;
652 espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,100,NULL,1);
653 rate = 5;
654 espeak_SetParameter(espeakRATE,rate*ratemult,0);
655 espeak_SetParameter(espeakPITCH,40,0);
656 espeak_SetParameter(espeakVOLUME,100,0);
657 espeak_SetVoiceByName("en-us");
658 espeak_SetSynthCallback(&speakcall);
659 pagefile();
660 espeak_Terminate();
661 fclose(source);
662 system("rm /tmp/ipage.tmp");
663 return 0;