/* AmigaNarrator Copyright (c) 2023 Arthur Choung. All rights reserved. Email: arthur -at- hotdoglinux.com This file is part of AmigaNarrator. AmigaNarrator 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 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 #include #include "m68k.h" void m68k_write_memory_32_no_log(unsigned int addr, unsigned int val); static int _pitch_parameter = 110; //pitch static int _rate_parameter = 150; //speaking rate (wpm) static int _volume_parameter = 64; //volume static int _sampfreq_parameter = 22200; //sampling frequency (Hz) static int _sex_parameter = 0; //sex 0=male 1=female static int _mode_parameter = 0; //mode 0=naturalf0 1=roboticf0 2=manualf0 #define INPUT_BUFSIZE 0x1000 static char *_inputptr = 0; static char _inputbuf[INPUT_BUFSIZE]; static char const *_library_path = "Devs/narrator.device"; #define LIBRARY_BUFSIZE 100000 #define LIBRARY_MAX_HUNKS 8 static unsigned char _library_buf[LIBRARY_BUFSIZE]; static int _library_size = 0; static int _library_pos = 0; static int _library_number_of_hunks = 0; static unsigned int _library_hunk_base[LIBRARY_MAX_HUNKS]; #define MAX_RAM (16*1024*1024) static unsigned char _ram[MAX_RAM]; static unsigned int _inputbase = 0x28000; static unsigned int _execbase = 0x20000; static unsigned int _allocmem = 0x100000; static unsigned int _narrator_rb = 0x22000; static unsigned int _msgport = 0x22800; static unsigned int _audiomsgport = 0x22c00; static unsigned int _librarybase = 0x23000; static unsigned int _audiochanbase = 0x24000; static unsigned int _taskbase = 0x25000; static int _allocsignal = 31; static unsigned int _mainbase = 0x26000; static unsigned int _stackpointer = 0x1f000; static unsigned int _libraryname = 0x27000; static unsigned int _addtask = 0; static unsigned int _makelibrary = 0; void load_library() { fprintf(stderr, "opening '%s'\n", _library_path); FILE *fp = fopen(_library_path, "rb"); if (!fp) { fprintf(stderr, "unable to open '%s'\n", _library_path); exit(1); } int result = fread(_library_buf, 1, LIBRARY_BUFSIZE, fp); fprintf(stderr, "fread %d (0x%x)\n", result, result); _library_size = result; _library_pos = 0; fclose(fp); } unsigned int library_read_32() { if (_library_pos >= _library_size-3) { fprintf(stderr, "library_read_32 past end of file %x\n", _library_pos); exit(1); } uint8_t *p = (uint8_t *) &_library_buf[_library_pos]; _library_pos += 4; unsigned int val; val = *p++; val <<= 8; val |= *p++; val <<= 8; val |= *p++; val <<= 8; val |= *p; return val; } void process_hunks() { unsigned int number_of_hunks = 0; unsigned int memory_pos = 0; unsigned int hunk_index = 0; unsigned int hunk_end = 0; unsigned int reloc32_pos = 0; unsigned int reloc32_hunk_index = 0; for(;;) { unsigned int hunk_id = library_read_32(); if (hunk_id == 0x3f3) { fprintf(stderr, "found HUNK_HEADER 0x3f3\n"); unsigned int zero = library_read_32(); if (zero != 0) { fprintf(stderr, "expecting 0\n"); exit(1); } number_of_hunks = library_read_32(); fprintf(stderr, "number_of_hunks %d\n", number_of_hunks); unsigned int first_hunk = library_read_32(); fprintf(stderr, "first_hunk %d\n", first_hunk); unsigned int last_hunk = library_read_32(); fprintf(stderr, "last_hunk %d\n", last_hunk); for (unsigned int i=first_hunk; i<=last_hunk; i++) { unsigned int hunk_size = library_read_32(); fprintf(stderr, "hunk %d size 0x%x\n", i, hunk_size); } } else if (hunk_id == 0x3e9) { fprintf(stderr, "found HUNK_CODE 0x3e9\n"); unsigned int number_of_longwords = library_read_32(); fprintf(stderr, "number_of_longwords 0x%x\n", number_of_longwords); if (hunk_index >= number_of_hunks) { fprintf(stderr, "unexpected hunk\n"); exit(1); } _library_hunk_base[hunk_index] = memory_pos; hunk_index++; for (unsigned int i=0; i= number_of_hunks) { fprintf(stderr, "unexpected hunk\n"); exit(1); } _library_hunk_base[hunk_index] = memory_pos; hunk_index++; for (unsigned int i=0; i= number_of_hunks) { fprintf(stderr, "unexpected hunk\n"); exit(1); } _library_hunk_base[hunk_index] = memory_pos; hunk_index++; memory_pos += 4*number_of_longwords; } else { fprintf(stderr, "unhandled hunk type %x\n", hunk_id); exit(1); } } if (reloc32_pos) { _library_pos = reloc32_pos; for(;;) { unsigned int number_of_offsets = library_read_32(); fprintf(stderr, "number_of_offsets %d\n", number_of_offsets); if (!number_of_offsets) { break; } unsigned int hunk_number = library_read_32(); fprintf(stderr, "hunk_number %d\n", hunk_number); if (hunk_number >= hunk_index) { fprintf(stderr, "hunk_number too high\n"); exit(1); } for (int i=0; i= MAX_RAM) { fprintf(stderr, "m68k_read_memory_8 %x OUT OF BOUNDS\n", addr); return 0; } unsigned int val = _ram[addr]; // fprintf(stderr, "m68k_read_memory_8 %x %x\n", addr, val); return val; } unsigned int m68k_read_memory_16(unsigned int addr) { if (addr >= MAX_RAM-1) { fprintf(stderr, "m68k_read_memory_16 %x OUT OF BOUNDS\n", addr); return 0; } uint8_t *p = (uint8_t *) &_ram[addr]; unsigned int val; val = *p++; val <<= 8; val |= *p; // fprintf(stderr, "m68k_read_memory_16 %x %x\n", addr, val); return val; } unsigned int m68k_read_memory_32(unsigned int addr) { if (addr >= MAX_RAM-3) { fprintf(stderr, "m68k_read_memory_32 %x OUT OF BOUNDS\n", addr); return 0; } uint8_t *p = (uint8_t *) &_ram[addr]; unsigned int val; val = *p++; val <<= 8; val |= *p++; val <<= 8; val |= *p++; val <<= 8; val |= *p; // fprintf(stderr, "m68k_read_memory_32 %x %x\n", addr, val); return val; } unsigned int m68k_read_immediate_16(unsigned int address) { return m68k_read_memory_16(address); } unsigned int m68k_read_immediate_32(unsigned int address) { return m68k_read_memory_32(address); } unsigned int m68k_read_pcrelative_8(unsigned int address) { return m68k_read_memory_8(address); } unsigned int m68k_read_pcrelative_16(unsigned int address) { return m68k_read_memory_16(address); } unsigned int m68k_read_pcrelative_32(unsigned int address) { return m68k_read_memory_32(address); } void m68k_write_memory_8(unsigned int addr, unsigned int val) { if (addr >= MAX_RAM) { fprintf(stderr, "m68k_read_memory_8 %x OUT OF BOUNDS\n", addr); return; } fprintf(stderr, "m68k_write_memory_8 addr %x val %x\n", addr, val); _ram[addr] = val; } void m68k_write_memory_16(unsigned int addr, unsigned int val) { if (addr >= MAX_RAM-1) { fprintf(stderr, "m68k_read_memory_16 %x OUT OF BOUNDS\n", addr); return; } fprintf(stderr, "m68k_write_memory_16 addr %x val %x\n", addr, val); uint8_t *p = (uint8_t *) &_ram[addr]; p[1] = val&0xff; val >>= 8; p[0] = val&0xff; } void m68k_write_memory_32(unsigned int addr, unsigned int val) { if (addr >= MAX_RAM-3) { fprintf(stderr, "m68k_read_memory_32 %x OUT OF BOUNDS\n", addr); return; } fprintf(stderr, "m68k_write_memory_32 addr %x val %x\n", addr, val); uint8_t *p = (uint8_t *) &_ram[addr]; p[3] = val&0xff; val >>= 8; p[2] = val&0xff; val >>= 8; p[1] = val&0xff; val >>= 8; p[0] = val&0xff; } void m68k_write_memory_32_no_log(unsigned int addr, unsigned int val) { if (addr >= MAX_RAM-3) { fprintf(stderr, "m68k_read_memory_32 %x OUT OF BOUNDS\n", addr); return; } uint8_t *p = (uint8_t *) &_ram[addr]; p[3] = val&0xff; val >>= 8; p[2] = val&0xff; val >>= 8; p[1] = val&0xff; val >>= 8; p[0] = val&0xff; } unsigned int m68k_read_disassembler_8(unsigned int addr) { if (addr >= MAX_RAM) { fprintf(stderr, "m68k_read_disassembler_8 %x OUT OF BOUNDS\n", addr); return 0; } unsigned int val = _ram[addr]; // fprintf(stderr, "m68k_read_disassembler_8 %x %x\n", addr, val); return val; } unsigned int m68k_read_disassembler_16(unsigned int addr) { if (addr >= MAX_RAM-1) { fprintf(stderr, "m68k_read_disassembler_16 %x OUT OF BOUNDS\n", addr); return 0; } uint8_t *p = (uint8_t *) &_ram[addr]; unsigned int val; val = *p++; val <<= 8; val |= *p; // fprintf(stderr, "m68k_read_disassembler_16 %x %x\n", addr, val); return val; } unsigned int m68k_read_disassembler_32(unsigned int addr) { if (addr >= MAX_RAM-3) { fprintf(stderr, "m68k_read_disassembler_32 %x OUT OF BOUNDS\n", addr); return 0; } uint8_t *p = (uint8_t *) &_ram[addr]; unsigned int val; val = *p++; val <<= 8; val |= *p++; val <<= 8; val |= *p++; val <<= 8; val |= *p; // fprintf(stderr, "m68k_read_disassembler_32 %x %x\n", addr, val); return val; } void make_hex(char *buf, unsigned int pc, unsigned int len) { char *p = buf; for (unsigned int i=0; i 0) { *p++ = ' '; } sprintf(p, "%04x", m68k_read_memory_16(pc)); pc += 2; p += 4; } } void instr_hook_callback(unsigned int pc) { char buf[256]; char buf2[256]; unsigned int sp = m68k_get_reg(0, M68K_REG_SP); unsigned int instr_size = m68k_disassemble(buf, pc, M68K_CPU_TYPE_68000); make_hex(buf2, pc, instr_size); { unsigned int a0 = m68k_get_reg(0, M68K_REG_A0); unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); unsigned int a2 = m68k_get_reg(0, M68K_REG_A2); unsigned int a3 = m68k_get_reg(0, M68K_REG_A3); unsigned int a4 = m68k_get_reg(0, M68K_REG_A4); unsigned int a5 = m68k_get_reg(0, M68K_REG_A5); unsigned int a6 = m68k_get_reg(0, M68K_REG_A6); fprintf(stderr, "Execute %03x: %-20s: %s (SP=%x A0=%x A1=%x A2=%x A3=%x A4=%x A5=%x A6=%x)\n", pc, buf2, buf, sp, a0, a1, a2, a3, a4, a5, a6); } unsigned int instr = m68k_read_memory_16(pc); if (instr == 0x4eae) { //jsr if (instr_size == 4) { unsigned int a6 = m68k_get_reg(0, M68K_REG_A6); unsigned int arg = m68k_read_memory_16(pc+2); fprintf(stderr, "***** JSR %x A6=%x 4=%x\n", arg, a6, m68k_read_memory_32(4)); m68k_write_memory_16(0x10000+arg, 0x4e75); // rts m68k_set_reg(M68K_REG_A6, _execbase); if (arg == 0xff3a) { // AllocMem -$c6 unsigned int d0 = m68k_get_reg(0, M68K_REG_D0); // byteSize unsigned int d1 = m68k_get_reg(0, M68K_REG_D1); // attributes fprintf(stderr, "***** AllocMem byteSize %x attributes %x _allocmem %x\n", d0, d1, _allocmem); m68k_set_reg(M68K_REG_D0, _allocmem); if (d0 % 4 != 0) { d0 /= 4; d0++; d0 *= 4; } _allocmem += d0; } else if (arg == 0xfeb6) { // AllocSignal -$14a unsigned int d0 = m68k_get_reg(0, M68K_REG_D0); // signalNum fprintf(stderr, "***** AllocSignal signalNum %x _allocsignal %x\n", d0, _allocsignal); m68k_set_reg(M68K_REG_D0, _allocsignal); // should check to see signal is available _allocsignal--; } else if (arg == 0xfeda) { // FindTask -$126 unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); fprintf(stderr, "***** FindTask %x '%s'\n", a1, (a1) ? ((char *)(_ram+a1)) : "(a1 is 0)"); m68k_set_reg(M68K_REG_D0, _taskbase); } else if (arg == 0xfee6) { // AddTask -$11a unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); // task unsigned int a2 = m68k_get_reg(0, M68K_REG_A2); // initialPC unsigned int a3 = m68k_get_reg(0, M68K_REG_A3); // finalPC fprintf(stderr, "***** AddTask task %x initialPC %x finalPC %x\n", a1, a2, a3); m68k_set_reg(M68K_REG_D0, _taskbase); m68k_write_memory_32(_addtask, a2); //set the jsr addr in _mainbase } else if (arg == 0xffac) { // MakeLibrary -$54 unsigned int a0 = m68k_get_reg(0, M68K_REG_A0); // vectors unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); // structure unsigned int a2 = m68k_get_reg(0, M68K_REG_A2); // init unsigned int d0 = m68k_get_reg(0, M68K_REG_D0); // dSize unsigned int d1 = m68k_get_reg(0, M68K_REG_D1); // segList fprintf(stderr, "***** MakeLibrary vectors %x structure %x init %x dSize %x segList %x\n", a0, a1, a2, d0, d1); m68k_set_reg(M68K_REG_D0, _librarybase); unsigned int vectorbase = a0; for (int i=0; i<8; i++) { unsigned int vector = m68k_read_memory_32(vectorbase+i*4); if (vector == 0xffffffff) { fprintf(stderr, "end of vectors\n"); break; } fprintf(stderr, "vector[%d] = %x\n", i, vector); if (i == 0) { fprintf(stderr, "openfunc %x\n", vector); m68k_write_memory_32(_makelibrary, vector); //set the jsr addr in _mainbase } } } else if (arg == 0xfe50) { // AddDevice -$1b0 unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); // device fprintf(stderr, "***** AddDevice %x\n", a1); } else if (arg == 0xfe44) { // OpenDevice -$1bc unsigned int a0 = m68k_get_reg(0, M68K_REG_A0); unsigned int d0 = m68k_get_reg(0, M68K_REG_D0); unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); unsigned int d1 = m68k_get_reg(0, M68K_REG_D1); fprintf(stderr, "***** OpenDevice devName %x '%s' unit %x ioRequest %x flags %x\n", a0, _ram+a0, d0, a1, d1); m68k_set_reg(M68K_REG_D0, 0); m68k_write_memory_32(a1+14, _audiomsgport); } else if (arg == 0xfe92) { // PutMsg -$16e unsigned int a0 = m68k_get_reg(0, M68K_REG_A0); unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); fprintf(stderr, "***** PutMsg port %x message %x\n", a0, a1); } else if (arg == 0xfe38) { // DoIO -$1c8 unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); fprintf(stderr, "***** DoIO ioRequest %x\n", a1); unsigned int io_Unit = m68k_read_memory_32(a1+24); fprintf(stderr, "***** DoIO io_Unit %x\n", io_Unit); unsigned int io_Command = m68k_read_memory_16(a1+28); fprintf(stderr, "***** DoIO io_Command %x\n", io_Command); fprintf(stderr, "***** DoIO io_Flags %x\n", m68k_read_memory_8(a1+30)); fprintf(stderr, "***** DoIO io_Error %x\n", m68k_read_memory_8(a1+31)); unsigned int ioa_Data = m68k_read_memory_32(a1+34); fprintf(stderr, "***** DoIO ioa_Data %x\n", ioa_Data); unsigned int ioa_Length = m68k_read_memory_32(a1+38); fprintf(stderr, "***** DoIO ioa_Length %x\n", ioa_Length); unsigned int ioa_Period = m68k_read_memory_16(a1+42); fprintf(stderr, "***** DoIO ioa_Period %x\n", ioa_Period); unsigned int ioa_Volume = m68k_read_memory_16(a1+44); fprintf(stderr, "***** DoIO ioa_Volume %x\n", ioa_Volume); unsigned int ioa_Cycles = m68k_read_memory_16(a1+46); fprintf(stderr, "***** DoIO ioa_Cycles %x\n", ioa_Cycles); if (io_Command == 6) { //CMD_STOP fprintf(stderr, "***** DoIO CMD_STOP\n"); } else if (io_Command == 7) { //CMD_START fprintf(stderr, "***** DoIO CMD_START\n"); } else if (io_Command == 9) { //ADCMD_FREE fprintf(stderr, "***** DoIO ADCMD_FREE mn_ReplyPort %x\n", m68k_read_memory_32(a1+14)); fprintf(stderr, "***** DoIO ADCMD_FREE io_Device %x\n", m68k_read_memory_32(a1+20)); m68k_write_memory_8(a1+31, 0); } m68k_set_reg(M68K_REG_D0, 0); } else if (arg == 0xfebc) { // Signal -$144 unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); unsigned int d0 = m68k_get_reg(0, M68K_REG_D0); fprintf(stderr, "***** Signal task %x signalSet %x\n", a1, d0); } else if (arg == 0xfe86) { // ReplyMsg -$17a unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); fprintf(stderr, "***** ReplyMsg message %x\n", a1); fprintf(stderr, "***** io_Error %x\n", m68k_read_memory_8(_narrator_rb+31)); exit(1); } else if (arg == 0xfe8c) { // GetMsg -$174 unsigned int a0 = m68k_get_reg(0, M68K_REG_A0); fprintf(stderr, "***** GetMsg port %x\n", a0); int len = strlen(_inputptr); if (len >= INPUT_BUFSIZE) { len = INPUT_BUFSIZE; } strncpy((char *)_ram+_inputbase, _inputptr, INPUT_BUFSIZE); m68k_write_memory_16(_narrator_rb+28, 3); // CMD_WRITE 3 //io_Command m68k_write_memory_32(_narrator_rb+44, 0); //io_Offset m68k_write_memory_32(_narrator_rb+40, _inputbase); //io_Data m68k_write_memory_32(_narrator_rb+36, len); //io_length m68k_write_memory_16(_narrator_rb+48, _rate_parameter); //rate m68k_write_memory_16(_narrator_rb+50, _pitch_parameter); //pitch m68k_write_memory_16(_narrator_rb+52, _mode_parameter); //mode 0 natural 1 robotic 2 manual m68k_write_memory_16(_narrator_rb+54, _sex_parameter); //sex 0 male 1 female m68k_write_memory_16(_narrator_rb+62, _volume_parameter); //volume 0-64 m68k_write_memory_16(_narrator_rb+64, _sampfreq_parameter); //sampfreq m68k_write_memory_8(_audiochanbase, 3);//not necessary to have all these values m68k_write_memory_8(_audiochanbase, 5); m68k_write_memory_8(_audiochanbase, 10); m68k_write_memory_8(_audiochanbase, 12); m68k_write_memory_32(_narrator_rb+56, _audiochanbase);//ch_masks m68k_write_memory_16(_narrator_rb+60, 4);//nm_masks m68k_write_memory_16(_narrator_rb+31, 0); //io_Error m68k_set_reg(M68K_REG_D0, _narrator_rb); } else if (arg == 0xfec2) { // Wait -$13e unsigned int d0 = m68k_get_reg(0, M68K_REG_D0); fprintf(stderr, "***** Wait signalSet %x\n", d0); unsigned int a2 = m68k_get_reg(0, M68K_REG_A2); fprintf(stderr, "***** Wait A2 %x\n", a2); fprintf(stderr, "***** Wait A2+0x22 %x\n", a2+0x22); fprintf(stderr, "***** Wait (A2+0x22) %x\n", m68k_read_memory_32(a2+0x22)); m68k_set_reg(M68K_REG_A2, _librarybase); } else if (arg == 0xffe2) { // device BeginIO -$1e unsigned int a1 = m68k_get_reg(0, M68K_REG_A1); fprintf(stderr, "***** device BeginIO %x\n", a1); unsigned int io_Unit = m68k_read_memory_32(a1+24); fprintf(stderr, "***** BeginIO io_Unit %x\n", io_Unit); unsigned int io_Command = m68k_read_memory_16(a1+28); fprintf(stderr, "***** BeginIO io_Command %x\n", io_Command); fprintf(stderr, "***** BeginIO io_Flags %x\n", m68k_read_memory_8(a1+30)); fprintf(stderr, "***** BeginIO io_Error %x\n", m68k_read_memory_8(a1+31)); unsigned int ioa_Data = m68k_read_memory_32(a1+34); fprintf(stderr, "***** BeginIO ioa_Data %x\n", ioa_Data); unsigned int ioa_Length = m68k_read_memory_32(a1+38); fprintf(stderr, "***** BeginIO ioa_Length %x\n", ioa_Length); unsigned int ioa_Period = m68k_read_memory_16(a1+42); fprintf(stderr, "***** BeginIO ioa_Period %x\n", ioa_Period); unsigned int ioa_Volume = m68k_read_memory_16(a1+44); fprintf(stderr, "***** BeginIO ioa_Volume %x\n", ioa_Volume); unsigned int ioa_Cycles = m68k_read_memory_16(a1+46); fprintf(stderr, "***** BeginIO ioa_Cycles %x\n", ioa_Cycles); for (unsigned int i=0; i 0) { if (_inputbuf[len-1] == '\n') { _inputbuf[len-1] = 0; } } _inputptr = _inputbuf; } else if (!strcmp(argv[i], "-d")) { if (i+1 < argc) { _library_path = argv[i+1]; i++; } else { fprintf(stderr, "error, expecting path for -d\n"); exit(1); } } else if (!strcmp(argv[i], "-f")) { if (i+1 < argc) { long val = strtol(argv[i+1], 0, 10); if ((val < 5000) || (val > 28000)) { fprintf(stderr, "error, sampling_frequency out of range (5000-28000)\n"); exit(1); } _sampfreq_parameter = val; i++; } else { fprintf(stderr, "error, expecting sampling_frequency for -f\n"); exit(1); } } else if (!strcmp(argv[i], "-m")) { if (i+1 < argc) { long val = strtol(argv[i+1], 0, 10); if ((val < 0) || (val > 1)) { fprintf(stderr, "error, invalid mode (0-1)\n"); exit(1); } _mode_parameter = val; i++; } else { fprintf(stderr, "error, expecting mode for -m\n"); exit(1); } } else if (!strcmp(argv[i], "-p")) { if (i+1 < argc) { long val = strtol(argv[i+1], 0, 10); if ((val < 65) || (val > 320)) { fprintf(stderr, "error, pitch out of range (65-320)\n"); exit(1); } _pitch_parameter = val; i++; } else { fprintf(stderr, "error, expecting pitch for -p\n"); exit(1); } } else if (!strcmp(argv[i], "-r")) { if (i+1 < argc) { long val = strtol(argv[i+1], 0, 10); if ((val < 40) || (val > 400)) { fprintf(stderr, "error, rate out of range (40-400)\n"); exit(1); } _rate_parameter = val; i++; } else { fprintf(stderr, "error, expecting rate for -r\n"); exit(1); } } else if (!strcmp(argv[i], "-s")) { if (i+1 < argc) { long val = strtol(argv[i+1], 0, 10); if ((val < 0) || (val > 1)) { fprintf(stderr, "error, invalid sex (0-1)\n"); exit(1); } _sex_parameter = val; i++; } else { fprintf(stderr, "error, expecting sex for -s\n"); exit(1); } } else { _inputptr = argv[i]; } } if (!_inputptr) { fprintf(stderr, "Usage: %s [options] <-|phonetic_text>\n", argv[0]); fprintf(stderr, "\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, "-d narrator_device_file\n"); fprintf(stderr, "-f sampling_frequency (5000-28000)\n"); fprintf(stderr, "-m mode (0=natural 1=robotic)\n"); fprintf(stderr, "-p pitch (65-320)\n"); fprintf(stderr, "-r rate (40-400)\n"); fprintf(stderr, "-s sex (0=male 1=female)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Examples:\n"); fprintf(stderr, "\n"); fprintf(stderr, "%s \"/HEH4LOW WER4LD.\"\n", argv[0]); fprintf(stderr, "%s -p 110 -r 150 -f 22200 -s 1 -m 1 \"/HEH4LOW WER4LD.\"\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~1.0 \"/HEH4LOW WER4LD.\"\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~1.1 \"/HEH4LOW WER4LD.\"\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~1.2 \"/HEH4LOW WER4LD.\"\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~2.04 \"/HEH4LOW WER4LD.\"\n", argv[0]); fprintf(stderr, "\n"); fprintf(stderr, "# read from stdin\n"); fprintf(stderr, "%s -\n", argv[0]); fprintf(stderr, "%s -p 110 -r 150 -f 22200 -s 1 -m 1 -\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~1.0 -\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~1.1 -\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~1.2 -\n", argv[0]); fprintf(stderr, "%s -d Devs/narrator.device~2.04 -\n", argv[0]); fprintf(stderr, "\n"); fprintf(stderr, "PCM samples will be written to stdout.\n"); fprintf(stderr, "The format is S8 (signed 8-bit) at 22200 Hz\n"); fprintf(stderr, "\n"); fprintf(stderr, "If using Linux, play using ALSA: aplay -f S8 -r 22200\n"); fprintf(stderr, "\n"); fprintf(stderr, "Redirect stderr to /dev/null to speed up process\n"); exit(1); } for (int i=0; i