c++ - 在 C++ 中将 espeak_SetSynthCallback 设置为成员函数

标签 c++ qt espeak

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

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

libespeak 支持回调功能,每次合成语音时都会调用该功能。 回调函数采用三个参数,我想用它们来可视化语音。下面的代码在正确调用回调函数的意义上起作用,但没有用,因为我无法访问其他成员函数或变量。

项目语音.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);
};

项目语音.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) 设置回调函数),代码将不再编译,因为参数无法转换。


更新:下面的建议有效。但是,我现在遇到了另一个问题。 这是类现在的样子:

项目语音.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();
}

项目语音.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);
}

关于c++ - 在 C++ 中将 espeak_SetSynthCallback 设置为成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26157309/

相关文章:

c++ - C++ 中 libpq++ postgresql 的静态链接

下面这段代码的 C++ 等效项 (sprintf)

c++ - 在小部件和向导页面之间共享数据

python-3.x - pyttsx 和 gTTS 模块错误

c++ - Espeak 功能

linux - 如何让电脑唱歌

c++ - boost asio优先级和链

c++ - QPainter - 沿圆圈绘制对象

qt - 如何防止 QML 按钮在短时间内多次点击?

c++ - KeyPressEvent 不起作用