/*
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