Menu

Pocketsphinx C++ program crashes except when I manually run it from terminal window in Raspbian

Help
Justin
2018-01-26
2018-01-29
  • Justin

    Justin - 2018-01-26

    I have a very strange issue. My code below works just fine when I run it via the command line but it crashes (around ps_init(config) I believe) when I double-click the executable with my mouse pointer or try to run the code inside of a Qt application. I'm running this on a Raspberry Pi 3. Can anyone tell me what is wrong?

    COMPILE CMD:
    g++ -o Jeeves Jeeves.cpp 'pkg-config --cflags --libs pocketsphinx sphinxbase'

    CODE:

    // Libraries for speech decoding
    #include <iostream>
    #include <unordered_map>
    #include <ctime>
    #include <string>
    #include <pocketsphinx.h>
    #include <sphinxbase/ad.h>
    #include <sphinxbase/err.h>
    
    // Libraries for running system commands
    #include <stdlib.h>
    
    // We use these libraries to create background timers
    #include <chrono>
    #include <future>
    #include <thread>
    #include <mutex>
    
    using namespace std;
    
    #define AUDIO_BUFFER_SIZE 4096
    #define INPUT_WAIT_TIME_SEC 5
    #define KEY_PHRASE "HEY JEEVES"
    
    #define COMMAND_BEGIN_CUE   (system("aplay -D plughw:0,0 /home/pi/Speech_Recognition/Sound_Effects/Beep_Init.wav"))
    #define COMMAND_END_CUE     (system("aplay -D plughw:0,0 /home/pi/Speech_Recognition/Sound_Effects/Beep_ACK.wav"))
    #define COMMAND_TIMEOUT_CUE (system("aplay -D plughw:0,0 /home/pi/Speech_Recognition/Sound_Effects/Beep_NACK.wav"))
    
    string recognize_from_microphone();
    inline void background_timer();
    bool readTimeOut();
    inline void speak(const string &speech);
    
    bool timeout = false;
    mutex timeout_flag_mutex;
    
    typedef void (*Action)(void); // function pointer type
    typedef string Command;
    
    typedef unordered_map<Command, Action> CommandActionMap;
    
    ps_decoder_t *ps;                  // create pocketsphinx decoder structure
    cmd_ln_t *config;                  // create configuration structure
    ad_rec_t *ad;                      // create audio recording structure - for use with ALSA functions
    
    int16 adbuf[AUDIO_BUFFER_SIZE];    // buffer array to hold audio data
    uint8 utt_started, in_speech;      // flags for tracking active speech - has speech started? - is speech currently happening?
    int32 k;                           // holds the number of frames in the audio buffer
    char const *hyp;                   // pointer to "hypothesis" (best guess at the decoded result)
    
    const string empty_string = string();
    
    // Command actions begin
    
    static void introduction()
    {
      string speech = "Hello. I am Jeeves, your personal assistant.";
      speak(speech);
      return;
    }
    
    // End of Command actions
    
    int main(int argc, char *argv[]) {
    
      // Initialize command/action dictionary
      CommandActionMap commandActions = {
    
        {"INTRODUCE YOURSELF", &introduction}
    
      }; COMMAND_BEGIN_CUE;
    
      // Initialize speech to text engine
      config = cmd_ln_init(NULL, ps_args(), TRUE,                                 // Load the configuration structure - ps_args() passes the default values
                   "-hmm", "/usr/local/share/pocketsphinx/model/en-us/en-us",     // path to the standard english language model
                   "-lm", "/home/pi/Speech_Recognition/Custom_Models/7221.lm",    // custom language model (file must be present)
                   "-dict", "/home/pi/Speech_Recognition/Custom_Models/7221.dic", // custom dictionary (file must be present)
                   "-remove_noise", "yes",                                        // filter background noise
                   "-logfn", "/dev/null",                                         // suppress log info from being sent to screen
                   NULL);
    
      ps = ps_init(config);                                                        // initialize the pocketsphinx decoder
      ad = ad_open_dev("sysdefault", (int) cmd_ln_float32_r(config, "-samprate")); // open default microphone (plughw:0,0) at default samplerate
    
      while(1)
        {
          timeout_flag_mutex.lock();
          timeout = false;
          timeout_flag_mutex.unlock();
          string decoded_speech = recognize_from_microphone();         // call the function to capture and decode speech           
          cout << "Decoded Speech: "<< decoded_speech << "\n" <<endl;  // send decoded speech to screen
          if (decoded_speech.compare(KEY_PHRASE) == 0)
        {
          auto future = async(background_timer);                       // start a background timer to cancel command listening if no speech detected
          cout << "Key phrase " << KEY_PHRASE << " detected; waiting for additional input..." << endl;
          COMMAND_BEGIN_CUE;                                           // cue command ready sound effect
          string decoded_command = recognize_from_microphone();        // call the function to capture and decode commands
          if (decoded_command.compare(empty_string) != 0)
            {
              COMMAND_END_CUE;
              cout << "Decoded Command: "<< decoded_command << "\n" <<endl; // send decoded command to screen
    
              // Parse the command and find associated action if it exists
              auto iter = commandActions.find(decoded_command);
              if (iter == commandActions.end())
            {
              // not found
              speak("I'm sorry, I did not recognize that command.");
            }
              else
            {
              (*iter->second)();
            }
            }
        }
        }
    
      COMMAND_END_CUE;
      ad_close(ad);                                                    // close the microphone
    }
    
    string recognize_from_microphone(){
    
      ad_start_rec(ad);                                // start recording
      ps_start_utt(ps);                                // mark the start of the utterance
      utt_started = FALSE;                             // clear the utt_started flag
    
      while(!readTimeOut() || utt_started) {
        k = ad_read(ad, adbuf, AUDIO_BUFFER_SIZE);   // capture the number of frames in the audio buffer
        ps_process_raw(ps, adbuf, k, FALSE, FALSE);  // send the audio buffer to the pocketsphinx decoder
    
        in_speech = ps_get_in_speech(ps);            // test to see if speech is being detected
    
        if (in_speech && !utt_started) {             // if speech has started and utt_started flag is false                            
          utt_started = TRUE;                      // then set the flag
        }
    
        if (!in_speech && utt_started) {             // if speech has ended and the utt_started flag is true 
          ps_end_utt(ps);                          // then mark the end of the utterance
          ad_stop_rec(ad);                         // stop recording
          hyp = ps_get_hyp(ps, NULL );             // query pocketsphinx for "hypothesis" of decoded statement
          return hyp;                              // the function returns the hypothesis
          break;                                   // exit the while loop and return to main
        }
      }
    
      COMMAND_TIMEOUT_CUE;                         // cue command timeout sound effect
    
      cout << "Command timeout..." << endl;
      return empty_string;
    }
    
    void background_timer()
    {
      // Sleep for a period of time and then set the timeout flag
      this_thread::sleep_for(chrono::seconds(INPUT_WAIT_TIME_SEC));
      timeout_flag_mutex.lock();
      timeout = true;
      timeout_flag_mutex.unlock();
      return;
    }
    
    bool readTimeOut()
    {
      timeout_flag_mutex.lock();
      bool result = timeout;
      timeout_flag_mutex.unlock();
      return timeout;
    }
    
    void speak(const string &speech)
    {
      // Convert speech to .wav file and then call OS media player
      string command = "pico2wave -w res.wav \"";
      command += speech;
      command += "\" && aplay -D plughw:0,0 res.wav";
      system(command.c_str());
      return;
    }
    
     
    • Nickolay V. Shmyrev

      You'd better provide a backtrace of the crash. You can collect it with gdb.

       
      • Justin

        Justin - 2018-01-26

        Running it through gdb (via script so I could reproduce the behavior) it doesn't seem to technically crash. But it exits with code 01 when it calls ps_init().

         
  • Justin

    Justin - 2018-01-26

    I think it has something to do with the environment variables. I know running from terminal versus double-clicking the executable changes the perspective. But, if I am correct, I don't know which environment variables ps_init() depends on.

     

    Last edit: Justin 2018-01-26
  • Justin

    Justin - 2018-01-26

    I just tried running the program with my gdb script with the logs unsupressed and the last entry in the logs is this:

    "FATAL: "cmn.c", line 126: Unknown CMN type 'batch'"

    Can anyone tell me what's happening here?

     
  • Justin

    Justin - 2018-01-26

    I just tried running the program with my gdb script with the logs unsupressed and the last entry in the logs is this:

    "FATAL: "cmn.c", line 126: Unknown CMN type 'batch'"

    Can anyone tell me what's happening here?

     
    • Nickolay V. Shmyrev

      You have two pocketsphinx installations - old in /usr and new probably in /usr/local. You configured LD_LIBRARY_PATH to load new installation but just in terminal, not globally. Probably you added it to bash_profile but didn't relogin. So desktop software still uses old library.

      You need to configure linker properly.

       
      • Justin

        Justin - 2018-01-26

        Ah that would seem to be in the right direction, thank you! I had the program dump out the environment variables every time it runs.

        When I type ./Jeeves in the terminal, the environment variable list shows LD_LIBRARY_PATH=/usr/local/lib as it should. But when I double click the Jeeves executable or try to run it via external qt app, the environment variable list no longer contains LD_LIBRARY_PATH so it probably is defaulting to the old stuff.

        I tried adding this to /etc/bash.bashrc:

        LD_LIBRARY_PATH="/usr/local/lib"
        export LD_LIBRARY_PATH
        PATH=$PATH:/usr/local/lib/
        export PATH

        Hoping it would set it globally but it seems it didn't work. How do I remedy this?

         
        • Nickolay V. Shmyrev

          Edit /etc/ld.so.conf and run ldconfig

           

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.