Amiga.org

Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: jjans on September 26, 2004, 07:49:54 PM

Title: Artificial Speech "narrator.device" and SASC/C++
Post by: jjans on September 26, 2004, 07:49:54 PM
I am following an old C manual example (Inside the Amiga with C by Thomas Berry published by SAMS) that is dated back to the Lattice days), and Workbench 1.3 in regards to creating a program that makes the Amiga speak using the narrator.device and Translate().

My system is A500, running 3.1 Roms, and I am getting no errors during compile with SASC/C++ 6.xx. I get no crashes when I run the program, and the device seems to open correctly, and the Translate() is returning a converted string to Phonetics OK.

The system is not making any sound however. I was wondering if 2.04 to 3.xx roms handle the speech routines differently than the old 1.3 Roms that I should be aware of?

Is there a modern source example available I could look at to compare with my old  example?

/***************************************************/
#include "stdafx.h"
#include "main_protos.h"

struct Library *TranslatorBase=NULL;
extern struct Library *OpenLibrary();
struct MsgPort *WPort, *RPort;
extern struct IORequest *CreateExtIO();
extern struct Library *OpenLibrary();
struct narrator_rb *wmes;
struct mouth_rb *rmes;

BYTE audChanMasks[]={3,5,10,12};

int main(void)
{
   UBYTE in_string[80], out_string[300];
   
   printf("Enter a string ");
   gets(in_string);
   
   if(get_phoneme(in_string, strlen(in_string),out_string, 300) == ERR)
   {
      puts("get_phoneme error!");
      exit(FALSE);
   }  
   printf("The phoneme translation of %s is %s\n", in_string, out_string);
   
   if(talk_to_me(out_string) == ERR)
      exit(FALSE);
   
   return 0;
}

/***************************************************************/

int get_phoneme(in,inLen,out,outLen)
UBYTE *in,*out;
SHORT inLen,outLen;
{
   int error=0;
   
   TranslatorBase = (struct Library*)OpenLibrary("translator.library",1);
   if(TranslatorBase==NULL)
   {
      puts("Cannot Open Translator.library!");
       return ERR;
   }
   // Translate this string to phonetics
   if(error=Translate(in,inLen,out,outLen) != 0)
   {
      printf("Cannot Translate %d\n",error);
      return ERR;
   }
   
   CloseLibrary(TranslatorBase);
   
   return SUCCESS;
}

/***************************************************************/

talk_to_me(speech)
UBYTE *speech;
{
   if((WPort=(struct MsgPort*)CreatePort(0,0)) == NULL)
      return (ERR);
     
   if((RPort=(struct MsgPort*)CreatePort(0,0)) == NULL)
      return (ERR);
     
   if((wmes=(struct narrator_rb*)CreateExtIO(WPort,sizeof(struct
   narrator_rb))) == NULL)
      return (ERR);      
   
   if((rmes=(struct mouth_rb*)CreateExtIO(RPort,sizeof(struct mouth_rb)))
   == NULL)
      return (ERR);
   
   wmes->message.io_Command = CMD_WRITE;
   wmes->message.io_Data = (APTR)speech;
   wmes->message.io_Length = strlen(speech);
   wmes->ch_masks = audChanMasks;
   wmes->nm_masks = sizeof(audChanMasks);
   
   if(OpenDevice("narrator.device", 0, wmes, 0) != 0)
      return (ERR);
     
   wmes->mouths = 0;
   wmes->volume = 64;
   wmes->rate = 20;
   wmes->sex = MALE;
   wmes->pitch = DEFPITCH;
   
   rmes->voice.message.io_Device = wmes->message.io_Device;
   rmes->voice.io_Unit = wmes->message.io_Unit;
   rmes->width = 0;
   rmes->height = 0;
   rmes->voice.message.io_Command = CMD_READ;
   rmes->voice.io_Error = 0;
   
   SendIO(wmes);
     
   while(rmes->voice.message.io_Error != ND_NoWrite)
   DoIO(rmes);
         
   return(SUCCESS);      
}
Title: Re: Artificial Speech "narrator.device" and SASC/C++
Post by: PiR on October 06, 2004, 02:55:35 PM
Hi

I thought someone else will reply on this, but it seems like you're doomed with me.

Here is my reply for you: both improved (you asked for it), prepared for SAS/C 6.5x and with the answer for your question inside. Try it and find it out!

Cheers

Code: [Select]

/***************************************************/
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/translator.h>
#include <clib/alib_protos.h>
#include <dos/dos.h>
#include <devices/narrator.h>
#include <stdio.h>
#include <string.h>


const static BYTE audChanMasks[]={3,5,10,12};

/***************************************************************/

int get_phoneme( UBYTE *in, SHORT inLen, UBYTE *out, SHORT outLen)
{
  struct Library *TranslatorBase;
  int retVal, error;

  TranslatorBase = (struct Library*)OpenLibrary(&quot;translator.library&quot;,1);
  if( !TranslatorBase ) {
    puts(&quot;Cannot Open Translator.library!&quot;);
    return RETURN_FAIL;
  }
  retVal = RETURN_OK;
  // Translate this string to phonetics
  if(error=Translate(in,inLen,out,outLen) != 0 ) {
    printf(&quot;Cannot Translate %d\n&quot;,error);
    retVal = RETURN_FAIL;
  }

  CloseLibrary(TranslatorBase);

  return retVal;
}

/***************************************************************/

int talk_to_me(UBYTE *speech) {
  struct narrator_rb *wmes;
  struct mouth_rb *rmes;
  struct MsgPort *WPort;
  struct MsgPort *RPort;
  if((WPort=CreatePort(0,0)) == NULL)
    return RETURN_FAIL;
  if((RPort=CreatePort(0,0)) == NULL ) {
    DeletePort( WPort );
    return RETURN_FAIL;
  }

  if((wmes=(struct narrator_rb*)CreateExtIO(WPort,sizeof(struct narrator_rb))) == NULL) {
    DeletePort( RPort );
    DeletePort( WPort );
    return RETURN_FAIL;
  }

  if((rmes=(struct mouth_rb*)CreateExtIO(RPort,sizeof(struct mouth_rb))) == NULL) {
    DeleteExtIO( wmes );
    DeletePort( RPort );
    DeletePort( WPort );
    return RETURN_FAIL;
  }

  wmes->message.io_Command = CMD_WRITE;
  wmes->message.io_Data = (APTR)speech;
  wmes->message.io_Length = strlen(speech);
  wmes->ch_masks = audChanMasks;
  wmes->nm_masks = sizeof(audChanMasks);

  if(OpenDevice(&quot;narrator.device&quot;, 0, wmes, 0) != 0) {
    DeleteExtIO( rmes );
    DeleteExtIO( wmes );
    DeletePort( RPort );
    DeletePort( WPort );
    return RETURN_FAIL;
  }

  wmes->mouths = 0;
  wmes->volume = 64;
  wmes->rate = 20;
  wmes->sex = MALE;
  wmes->pitch = DEFPITCH;

  rmes->voice.message.io_Device = wmes->message.io_Device;
  rmes->voice.io_Unit = wmes->message.io_Unit;
  rmes->width = 0;
  rmes->height = 0;
  rmes->voice.message.io_Command = CMD_READ;
  rmes->voice.io_Error = 0;

  SendIO(wmes);

  {
    unsigned  cnt = 0;
    while(rmes->voice.message.io_Error != ND_NoWrite) {
      DoIO(rmes);
      ++cnt;
    }
    printf( &quot;cnt = %u\n&quot;, cnt );
  }
  WaitPort( WPort );

  CloseDevice( wmes );
  DeleteExtIO( rmes );
  DeleteExtIO( wmes );
  DeletePort( RPort );
  DeletePort( WPort );

  return RETURN_OK;
}

/***************************************************************/

int main(void)
{
  UBYTE in_string[] = &quot;test string&quot;, out_string[300];

  //printf(&quot;Enter a string &quot;);
  //gets(in_string);

  if( get_phoneme(in_string, strlen(in_string),out_string, 300) ) {
    puts(&quot;get_phoneme error!&quot;);
    return RETURN_FAIL;
  }
  printf(&quot;The phoneme translation of %s is %s\n&quot;, in_string, out_string);

  if( talk_to_me(out_string) )
    return RETURN_FAIL;

  return RETURN_OK;
}

Title: Re: Artificial Speech "narrator.device" and SASC/C++
Post by: jjans on October 07, 2004, 12:11:31 AM
Thanks for the example!

Initial compile still gives me no speech, but I have to take some time  to study your code to figure out why.

Your Health! :pint:  :pint:  :pint:  :pint:
Title: Re: Artificial Speech "narrator.device" and SASC/C++
Post by: DonnyEMU on October 07, 2004, 07:26:38 AM
This sounds silly but have you tried using the old AmigaDOS "SAY" command or redirected a text file to SPEAK: to make sure speech is actually make sure it's working??
Title: Re: Artificial Speech "narrator.device" and SASC/C++
Post by: PiR on October 07, 2004, 12:03:01 PM
jjans

Oh, so thats wired, as I've tried this and had good expected results, as opposite to your example that didn't work for me.

The reason for this, as I suspect, is the fact that reading 'mouth parameters', DoIO(), is performed only once with failure (I didn't analyse the reason for it), and the whole program exits, before narrator.device even begin to speak, therefore it corrupts memory.
Notice WaitPort() I added to force waiting for narrator.device to finish.

Other changes:
- Cleanup (!!!!!) - Esspecially important in AmigaOS, as this cannot be perfored automatically by OS.
- Usage of other include files that allow to call functions directly from the libraries, without the overhead of so called subs. For that reason I could also change TranslatorBase into local variable.
- Changed function arguments declaration from the old K&R style to the new ANSI style.
- Some functional cleanup (what's the difference between return 0 from main on success end exit( FALSE ) on failure? In my opinion exit() should be avoided at all.
- Used 'const' for really constant array, giving the compiler the possibility to put it in the same hunk with the code itself, not with the data.

Besides this code looks good to me and should work. Try it after rebooting, mayby narrator.device stays corrupted...

Good luck
Title: Re: Artificial Speech "narrator.device" and SASC/C++
Post by: itix on October 07, 2004, 01:36:59 PM
Maybe you don't have narrator.device?
Title: Re: Artificial Speech "narrator.device" and SASC/C++
Post by: jjans on October 07, 2004, 03:57:43 PM
Well the AmigaDos 'Say' Command is working on all the machines I tested this on. I tried it on my client machine (also OS 3.1), rebooted to OS 1.3 (via SKICK), and even on WINUAE under different OS configs. Really got me stumped now.

I have a feeling I am missing something really simple here. It may be easier to simply call the exec cli command say (which is working) for my purposes, but then this may be more intense on resources will it not?

I have a feeling that time spent with Visual Studio C++ has spoiled me, and I have to re-read some more basics from the old manuals!:-o

Thanks for your input guys. I'll get it yet!!!!
Gotta go to work now