将espeak_SetSynthCallback设置为C中的成员函数

我的应用程序大量使用文本到语音(通过libespeak).它是用C / Qt5编写的,带有基于QML的前端.

我没有正式的C培训(虽然我有Java背景),因此我不完全确定如何正确实现一些更深奥的功能.

libespeak支持回调功能,每次语音合成时都会调用该功能.
回调函数有三个参数,我想用它来可视化语音.下面的代码的工作原理是回调函数被正确调用,但没有用,因为我无法访问其他成员函数或变量.

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);
}

我想使回调函数成为ItemVoice类的成员.但是,如果我尝试(并使用espeak_SetSynthCallback(ItemVoice :: callback)设置回调函数,则由于无法转换的参数,代码将不再编译.

更新:以下建议有效.但是,我现在遇到了另一个问题.
这就是现在班级的样子:

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();
}

这工作正常.合成开始时调用startSpeaking(),停止时调用stopSpeaking().问题是我需要发送一个Qt信号来更新GUI(updateGUI),并且在发送后大约一秒钟,我的应用程序崩溃时出现分段错误,即使信号没有连接到任何地方.否则它完美无缺.

任何的想法?

谢谢阅读!

最佳答案 没有直接的方法来做你想要的.在你的情况下,你很幸运,因为espeak_EVENT中有void * user_data字段.您可以在调用espeak_Synth()时将其设置为this:

void ItemVoice::synthSpeech() {
    espeak_Synth(...., this);
}

所以在回调中(它仍然是一个全局函数,或ItemVoice中的静态函数)你可以大致这样做:

int staticCallback(short *wav, int numsamples, espeak_EVENT *events) {
    if (numsamples > 0)
        return (static_cast<ItemVoice*>(events[0].user_data))->nonStaticCallback(wav, numsamples, events);
}
点赞