My application makes heavy use of text-to-speech (through libespeak). It is written in C++/Qt5 with a QML-based frontend.
I have no formal C++ training (I have a Java background though) and as such I'm not entirely sure how to properly implement some of the more esoteric features.
libespeak supports a callback feature, which is called every time speech is synthesized. The callback function takes three arguments, which I would like to use to visualize the speech. The code below works in the sense that the callback function is called correctly, but not useful since I can't access other member functions or variables.
itemvoice.h
#include "espeak/speak_lib.h"
int callback(short *wav, int numsamples, espeak_EVENT *events);
class ItemVoice : public Item
{
public:
explicit ItemVoice(QQuickItem *parent = 0);
};
itemvoice.cpp
#include "itemvoice.h"
extern int callback(short *wav, int numsamples, espeak_EVENT *events)
{
// do stuff
}
ItemVoice::ItemVoice(QQuickItem *parent):Item(parent)
{
espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,500,NULL,0);
espeak_SetSynthCallback(callback);
}
I would like to make the callback function a member of the ItemVoice class. However if I try (and set the callback function with espeak_SetSynthCallback(ItemVoice::callback), the code won't compile anymore because of arguments which cannot be converted.
UPDATE: The suggestion below works. However, I have now run into another problem. This is what the class looks like now:
itemvoice.h
#include "espeak/speak_lib.h"
int staticCallback(short *wav, int numsamples, espeak_EVENT *events);
class ItemVoice : public Item
{
Q_OBJECT
public:
explicit ItemVoice(QQuickItem *parent = 0);
void startSpeaking();
void stopSpeaking();
signals:
void updateGUI();
}
itemvoice.cpp
#include "itemvoice.h"
ItemVoice::ItemVoice(QQuickItem *parent):Item(parent)
{
espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,500,NULL,0);
espeak_SetSynthCallback(staticCallback);
}
int staticCallback(short *wav, int numsamples, espeak_EVENT *events)
{
espeak_EVENT_TYPE type=events->type;
if(type==2) // start sentence
(static_cast<ItemVoice*>(events[0].user_data))->startSpeaking();
else if(type==6) // stop sentence
(static_cast<ItemVoice*>(events[0].user_data))->stopSpeaking();
}
void ItemVoice::startSpeaking()
{
//do stuff
updateGUI();
}
void ItemVoice::stopSpeaking()
{
// do stuff
updateGUI();
}
This works correctly. startSpeaking() is called when synthesis begins, and stopSpeaking() when it stops. The problem is that I need to send a Qt signal to update the GUI (updateGUI), and about a second after it's sent, my application crashes with a segmentation fault, even if the signal is not connected anywhere. It works perfectly otherwise.
Any idea?
Thanks for reading!