|
|
|
/***************************************************** vim:set ts=4 sw=4 sts=4:
|
|
|
|
Player Object for playing synthesized audio files. Plays them
|
|
|
|
synchronously.
|
|
|
|
-------------------
|
|
|
|
Copyright:
|
|
|
|
(C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
|
|
|
|
-------------------
|
|
|
|
Original author: Gary Cramblitt <garycramblitt@comcast.net>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
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
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
// TQt includes.
|
|
|
|
#include <tqfile.h>
|
|
|
|
|
|
|
|
// KDE includes.
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <ktempfile.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kparts/componentfactory.h>
|
|
|
|
#include <ktrader.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
// KTTS includes.
|
|
|
|
#include "player.h"
|
|
|
|
#include "stretcher.h"
|
|
|
|
#include "pluginconf.h"
|
|
|
|
|
|
|
|
// TestPlayer includes.
|
|
|
|
#include "testplayer.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*/
|
|
|
|
TestPlayer::TestPlayer(TQObject *parent, const char *name,
|
|
|
|
const int playerOption, const float audioStretchFactor, const TQString &sinkName) :
|
|
|
|
TQObject(parent, name)
|
|
|
|
{
|
|
|
|
m_playerOption = playerOption;
|
|
|
|
m_audioStretchFactor = audioStretchFactor;
|
|
|
|
m_stretcher = 0;
|
|
|
|
m_player = 0;
|
|
|
|
m_sinkName = sinkName;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor.
|
|
|
|
*/
|
|
|
|
TestPlayer::~TestPlayer()
|
|
|
|
{
|
|
|
|
delete m_stretcher;
|
|
|
|
delete m_player;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets which audio player to use.
|
|
|
|
* 0 = aRts
|
|
|
|
* 1 = gstreamer
|
|
|
|
* 2 = ALSA
|
|
|
|
* 3 = aKode
|
|
|
|
*/
|
|
|
|
void TestPlayer::setPlayerOption(const int playerOption) { m_playerOption = playerOption; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the audio stretch factor (Speed adjustment).
|
|
|
|
* 1.0 = normal
|
|
|
|
* 0.5 = twice as fast
|
|
|
|
* 2.0 = twice as slow
|
|
|
|
*/
|
|
|
|
void TestPlayer::setAudioStretchFactor(const float audioStretchFactor)
|
|
|
|
{ m_audioStretchFactor = audioStretchFactor; }
|
|
|
|
|
|
|
|
void TestPlayer::setSinkName(const TQString &sinkName) { m_sinkName = sinkName; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Plays the specifified audio file and waits for completion.
|
|
|
|
* The audio file speed is adjusted according to the stretch factor.
|
|
|
|
* @param waveFile Name of the audio file to play.
|
|
|
|
*/
|
|
|
|
void TestPlayer::play(const TQString &waveFile)
|
|
|
|
{
|
|
|
|
// kdDebug() << "TestPlayer::play: running" << endl;
|
|
|
|
// Create a Stretcher object to adjust the audio Speed.
|
|
|
|
TQString playFile = waveFile;
|
|
|
|
TQString tmpFile;
|
|
|
|
if (m_audioStretchFactor != 1.0)
|
|
|
|
{
|
|
|
|
tmpFile = makeSuggestedFilename();
|
|
|
|
// kdDebug() << "TestPlayer::play: stretching file " << playFile << " by " << m_audioStretchFactor
|
|
|
|
// << " to file " << tmpFile << endl;
|
|
|
|
m_stretcher = new Stretcher();
|
|
|
|
if (m_stretcher->stretch(playFile, tmpFile, m_audioStretchFactor))
|
|
|
|
{
|
|
|
|
while (m_stretcher->getState() != Stretcher::ssFinished) tqApp->processEvents();
|
|
|
|
playFile = m_stretcher->getOutFilename();
|
|
|
|
}
|
|
|
|
delete m_stretcher;
|
|
|
|
m_stretcher = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create player object based on player option.
|
|
|
|
// kdDebug() << "TestPlayer::play: creating Player object with playerOption " << m_playerOption << endl;
|
|
|
|
m_player = createPlayerObject(m_playerOption);
|
|
|
|
// If player object could not be created, avoid crash is the best we can do!
|
|
|
|
if (!m_player) return;
|
|
|
|
// kdDebug() << "TestPlayer::play: starting playback." << endl;
|
|
|
|
m_player->startPlay(playFile);
|
|
|
|
|
|
|
|
// TODO: The following hunk of code would ideally be unnecessary. We would just
|
|
|
|
// return at this point and let take care of
|
|
|
|
// cleaning up the play object. However, because we've been called from DCOP,
|
|
|
|
// this seems to be necessary. The call to processEvents is problematic because
|
|
|
|
// it can cause re-entrancy.
|
|
|
|
while (m_player->playing()) tqApp->processEvents();
|
|
|
|
// kdDebug() << "TestPlayer::play: stopping playback." << endl;
|
|
|
|
m_player->stop();
|
|
|
|
delete m_player;
|
|
|
|
m_player = 0;
|
|
|
|
if (!tmpFile.isEmpty()) TQFile::remove(tmpFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates and returns a player object based on user option.
|
|
|
|
*/
|
|
|
|
Player* TestPlayer::createPlayerObject(int playerOption)
|
|
|
|
{
|
|
|
|
Player* player = 0;
|
|
|
|
TQString plugInName;
|
|
|
|
switch(playerOption)
|
|
|
|
{
|
|
|
|
case 1 :
|
|
|
|
{
|
|
|
|
plugInName = "kttsd_gstplugin";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2 :
|
|
|
|
{
|
|
|
|
plugInName = "kttsd_alsaplugin";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3 :
|
|
|
|
{
|
|
|
|
plugInName = "kttsd_akodeplugin";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
plugInName = "kttsd_artsplugin";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
KTrader::OfferList offers = KTrader::self()->query(
|
|
|
|
"KTTSD/AudioPlugin", TQString("DesktopEntryName == '%1'").arg(plugInName));
|
|
|
|
|
|
|
|
if(offers.count() == 1)
|
|
|
|
{
|
|
|
|
// kdDebug() << "TestPlayer::createPlayerObject: Loading " << offers[0]->library() << endl;
|
|
|
|
KLibFactory *factory = KLibLoader::self()->factory(offers[0]->library().latin1());
|
|
|
|
if (factory)
|
|
|
|
player =
|
|
|
|
KParts::ComponentFactory::createInstanceFromLibrary<Player>(
|
|
|
|
offers[0]->library().latin1(), this, offers[0]->library().latin1());
|
|
|
|
else
|
|
|
|
kdDebug() << "TestPlayer::createPlayerObject: Could not create factory." << endl;
|
|
|
|
}
|
|
|
|
if (player == 0)
|
|
|
|
kdDebug() << "TestPlayer::createPlayerObject: Could not load " + plugInName +
|
|
|
|
". Is KDEDIRS set correctly?" << endl;
|
|
|
|
else
|
|
|
|
// Must have GStreamer >= 0.8.7.
|
|
|
|
if (playerOption == 1)
|
|
|
|
{
|
|
|
|
if (!player->requireVersion(0, 8, 7))
|
|
|
|
{
|
|
|
|
delete player;
|
|
|
|
player = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (player) player->setSinkName(m_sinkName);
|
|
|
|
return player;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a temporary filename for plugins to use as a suggested filename
|
|
|
|
* for synthesis to write to.
|
|
|
|
* @return Full pathname of suggested file.
|
|
|
|
*/
|
|
|
|
TQString TestPlayer::makeSuggestedFilename()
|
|
|
|
{
|
|
|
|
KTempFile tempFile (locateLocal("tmp", "kttsmgr-"), ".wav");
|
|
|
|
TQString waveFile = tempFile.file()->name();
|
|
|
|
tempFile.close();
|
|
|
|
TQFile::remove(waveFile);
|
|
|
|
// kdDebug() << "TestPlayer::makeSuggestedFilename: Suggesting filename: " << waveFile << endl;
|
|
|
|
return PlugInConf::realFilePath(waveFile);
|
|
|
|
}
|
|
|
|
|