Skip to content
GAudioOutput.cc 6.97 KiB
Newer Older
pixhawk's avatar
pixhawk committed
/*=====================================================================

pixhawk's avatar
pixhawk committed
QGroundControl Open Source Ground Control Station
pixhawk's avatar
pixhawk committed

pixhawk's avatar
pixhawk committed
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
pixhawk's avatar
pixhawk committed

pixhawk's avatar
pixhawk committed
This file is part of the QGROUNDCONTROL project
pixhawk's avatar
pixhawk committed

pixhawk's avatar
pixhawk committed
    QGROUNDCONTROL is free software: you can redistribute it and/or modify
pixhawk's avatar
pixhawk committed
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

pixhawk's avatar
pixhawk committed
    QGROUNDCONTROL is distributed in the hope that it will be useful,
pixhawk's avatar
pixhawk committed
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
pixhawk's avatar
pixhawk committed
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
pixhawk's avatar
pixhawk committed

======================================================================*/

/**
 * @file
 *   @brief Implementation of audio output
 *
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QApplication>
pixhawk's avatar
pixhawk committed
#include <QTemporaryFile>
pixhawk's avatar
pixhawk committed
#include "GAudioOutput.h"
#include "MG.h"

pixhawk's avatar
pixhawk committed
#include <QDebug>

#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
#endif
// Speech synthesis is only supported with MSVC compiler
#if _MSC_VER2
// Documentation: http://msdn.microsoft.com/en-us/library/ee125082%28v=VS.85%29.aspx
pixhawk's avatar
pixhawk committed
#include <sapi.h>
pixhawk's avatar
pixhawk committed
using System;
using System.Speech.Synthesis;
#endif
pixhawk's avatar
pixhawk committed

#ifdef Q_OS_LINUX
extern "C" {
#include <flite/flite.h>
    cst_voice* register_cmu_us_kal(const char* voxdir);
};
#endif
pixhawk's avatar
pixhawk committed

/**
 * This class follows the singleton design pattern
 * @see http://en.wikipedia.org/wiki/Singleton_pattern
 * A call to this function thus returns the only instance of this object
 * the call can occur at any place in the code, no reference to the
 * GAudioOutput object has to be passed.
 */
GAudioOutput* GAudioOutput::instance()
{
    static GAudioOutput* _instance = 0;
    if(_instance == 0) {
        _instance = new GAudioOutput();
        // Set the application as parent to ensure that this object
        // will be destroyed when the main application exits
        _instance->setParent(qApp);
    }
    return _instance;
}

GAudioOutput::GAudioOutput(QObject* parent) : QObject(parent),
voiceIndex(0),
emergency(false)
{
pixhawk's avatar
pixhawk committed
    flite_init();
    // Initialize audio output
pixhawk's avatar
pixhawk committed
    m_media = new Phonon::MediaObject(this);
    Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
    createPath(m_media, audioOutput);

    // Prepare regular emergency signal, will be fired off on calling startEmergency()
pixhawk's avatar
pixhawk committed
    emergencyTimer = new QTimer();
    connect(emergencyTimer, SIGNAL(timeout()), this, SLOT(beep()));

    switch (voiceIndex)
    {
    case 0:
        selectFemaleVoice();
        break;
    default:
pixhawk's avatar
pixhawk committed
        break;
    }
}

bool GAudioOutput::say(QString text, int severity)
{
    // TODO Add severity filter
    Q_UNUSED(severity);
pixhawk's avatar
pixhawk committed
    bool res = false;
    if (!emergency)
    {
pixhawk's avatar
pixhawk committed

        // Speech synthesis is only supported with MSVC compiler
#ifdef _MSC_VER2
pixhawk's avatar
pixhawk committed
        SpeechSynthesizer synth = new SpeechSynthesizer();
        synth.SelectVoice("Microsoft Anna");
        synth.SpeakText(text.toStdString().c_str());
        res = true;
pixhawk's avatar
pixhawk committed
#endif

pixhawk's avatar
pixhawk committed
        QTemporaryFile file;
        file.setFileTemplate("XXXXXX.wav");
        if (file.open())
        {
            cst_voice* v = register_cmu_us_kal(NULL);
lm's avatar
lm committed
            cst_wave* wav = flite_text_to_wave(text.toStdString().c_str(), v);
pixhawk's avatar
pixhawk committed
            // file.fileName() returns the unique file name
            cst_wave_save(wav, file.fileName().toStdString().c_str(), "riff");
            m_media->setCurrentSource(Phonon::MediaSource(file.fileName().toStdString().c_str()));
            m_media->play();
            res = true;
        }
#endif

#ifdef Q_OS_MAC
        // Slashes necessary to have the right start to the sentence
        // copying data prevents SpeakString from reading additional chars
        text = "\\" + text;
        QStdWString str = text.toStdWString();
        unsigned char str2[1024] = {};
        memcpy(str2, text.toAscii().data(), str.length());
        SpeakString(str2);
pixhawk's avatar
pixhawk committed
    }
    return res;
}

/**
 * @param text This message will be played after the alert beep
 */
bool GAudioOutput::alert(QString text)
{
    if (!emergency)
    {
        // Play alert sound
pixhawk's avatar
pixhawk committed
        // Say alert message
pixhawk's avatar
pixhawk committed
    }
    else
    {
        return false;
    }
}

void GAudioOutput::notifyPositive()
{
    // Use QFile to transform path for all OS
    QFile f(QCoreApplication::applicationDirPath()+QString("/audio/double_notify.wav"));
    m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str()));
    m_media->play();
}

void GAudioOutput::notifyNegative()
{
    // Use QFile to transform path for all OS
    QFile f(QCoreApplication::applicationDirPath()+QString("/audio/flat_notify.wav"));
    m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str()));
    m_media->play();
}

pixhawk's avatar
pixhawk committed
/**
 * The emergency sound will be played continously during the emergency.
 * call stopEmergency() to disable it again. No speech synthesis or other
 * audio output is available during the emergency.
 *
 * @return true if the emergency could be started, false else
 */
bool GAudioOutput::startEmergency()
{
    if (!emergency)
    {
        emergency = true;
pixhawk's avatar
pixhawk committed
        // Beep immediately and then start timer
        beep();
        emergencyTimer->start(1500);
lm's avatar
lm committed
        QTimer::singleShot(5000, this, SLOT(stopEmergency()));
pixhawk's avatar
pixhawk committed
    }
    return true;
}

/**
 * Stops the continous emergency sound. Use startEmergency() to start
 * the emergency sound.
 *
 * @return true if the emergency could be stopped, false else
 */
bool GAudioOutput::stopEmergency()
{
    if (emergency)
    {
        emergency = false;
        emergencyTimer->stop();
    }
    return true;
}

void GAudioOutput::beep()
{
pixhawk's avatar
pixhawk committed
    // Use QFile to transform path for all OS
    QFile f(QCoreApplication::applicationDirPath()+QString("/audio/alert.wav"));
pixhawk's avatar
pixhawk committed
    m_media->setCurrentSource(Phonon::MediaSource(f.fileName().toStdString().c_str()));
pixhawk's avatar
pixhawk committed
    m_media->play();
}

void GAudioOutput::selectFemaleVoice()
{
lm's avatar
lm committed
    //this->voice = register_cmu_us_slt(NULL);
pixhawk's avatar
pixhawk committed
#endif
}

void GAudioOutput::selectMaleVoice()
{
lm's avatar
lm committed
    //this->voice = register_cmu_us_rms(NULL);
pixhawk's avatar
pixhawk committed
#endif
}

pixhawk's avatar
pixhawk committed
void GAudioOutput::selectNeutralVoice()
{
    this->voice = register_cmu_us_awb(NULL);
pixhawk's avatar
pixhawk committed
#endif
pixhawk's avatar
pixhawk committed

QStringList GAudioOutput::listVoices(void)
{
    QStringList l;
lm's avatar
lm committed
#ifdef Q_OS_LINUX2
    cst_voice *voice;
    const cst_val *v;
pixhawk's avatar
pixhawk committed

pixhawk's avatar
pixhawk committed

    printf("Voices available: ");
    for (v=flite_voice_list; v; v=val_cdr(v))
    {
        voice = val_voice(val_car(v));
        QString s;
        s.sprintf("%s",voice->name);
        printf("%s",voice->name);
        l.append(s);
pixhawk's avatar
pixhawk committed
    }
pixhawk's avatar
pixhawk committed
}