p-groarke / wsay

Windows "say"
BSD 3-Clause "New" or "Revised" License
141 stars 11 forks source link

wsay output (-l -d) cannot be piped #30

Closed IvanScheers closed 5 months ago

IvanScheers commented 5 months ago

As I said in replying to "Radio effects" I ran into a strange issue.

Today while implementing to use wsay.exe in my project to create TTS wav files, which then are post-processed before going out to the speakers.

Wsay -l gives a list of available voices (it reports more of them than my current library). I tried a function I use now and then for grabbing output from a command. That runs a CLI app and pulls in the output using a pipe. However, for wsay this doesn't work as expected.

While it's perfectly possible to do "wsay -l > voices.tmp" on the command line and have a file with all the voices, when running it with from within my app using a pipe to get the output I only get 1 character in my pipe ("1").

For the time being I can go with the former method and pull voices.tmp in to get a list of available voices. I do find it quite strange that piping the output of wsay -l doesn't work. Isn't that voice list just output to stdout ?

This is test code I use for catching output from a CLI app:

#include <stdio.h>
#include <stdlib.h>

#ifdef WIN32
FILE *popen ( const char* command, const char* flags) {return _popen(command,flags);}
int pclose ( FILE* fd) { return _pclose(fd);}
#endif

int main()
{
    char psBuffer[128];
    FILE *iopipe;

//    if( (iopipe = popen( "wsay -l", "r" )) == NULL )  // only "1" received
    if( (iopipe = popen( "dir /od", "r" )) == NULL ) // receives complete directory listing
    {
        printf("Could not run command or open a pipe");
        exit( 1 );
    }

    while( !feof( iopipe ) )
    {
        if( fgets( psBuffer, 128, iopipe ) != NULL )
            printf( psBuffer );
    }

    auto result = pclose(iopipe);
    printf( "\nProcess returned ");
    if(result == 0)
        printf("success");
    else
        printf("fail");
    return 0;
}
p-groarke commented 5 months ago

Hey @IvanScheers, I'm not sure what to tell you. wsay simply outputs to std::wcout as seen here : https://github.com/p-groarke/wsay/blob/93f245a070742c54e96db107dfdbff17d39e8d8c/src/main.cpp#L41

It's probably a wide char issue on your end. wsay is fully unicode aware and works internally as utf16 multi-byte.

Look intoSetConsoleCP, SetConsoleOutputCP to set your codepage to utf8 or utf16. You can also take a look at _setmode. Maybe you need to use native windows functions to capture (PeekNamedPipe and ugly things like that).

I'd make a test with a small application that outputs to std::wcout to repro and debug. Just std::wcout the voice list. I doubt it has anything to do with wsay tbh.

Good luck!

p-groarke commented 5 months ago

I'm going to close the issue since I think switching to wide-chars (or utf8 translation) will fix your problem. But if it doesn't or you can't repro with another simpler app, please reopen.