khotkeys: remove barely implemented voice trigger feature

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2021-03-13 19:34:42 +02:00
parent ebe50d1a6d
commit 1fa840757f
16 changed files with 0 additions and 1618 deletions

View file

@ -103,8 +103,6 @@ void KHotKeysModule::reread_configuration()
kDebug() << _settings.areGesturesDisabled();
KHotKeys::gesture_handler->enable( !_settings.areGesturesDisabled() );
KHotKeys::gesture_handler->set_exclude( _settings.gesturesExclude() );
// FIXME: SOUND
// KHotKeys::voice_handler->set_shortcut( _settings.voice_shortcut );
actions_root = _settings.actions();
KHotKeys::khotkeys_set_active( true );
}

View file

@ -43,7 +43,6 @@ set(khotkeysprivate_SRCS
triggers/trigger.cpp
triggers/trigger_list.cpp
triggers/triggers.cpp
# triggers/voice_trigger.cpp
triggers/window_trigger.cpp
# WINDOWS_HELPER
@ -62,11 +61,6 @@ set(khotkeysprivate_SRCS
settings_writer.cpp
shortcuts_handler.cpp
windows_handler.cpp
# search for FIXME: SOUND
# sound.cpp
# soundrecorder.cpp
# voices.cpp
# voicesignature.cpp
)
add_library(khotkeysprivate SHARED ${khotkeysprivate_SRCS})

View file

@ -19,12 +19,8 @@
#include "windows_handler.h"
#include "triggers/triggers.h"
#include "triggers/gestures.h"
#include "voices.h"
#include "shortcuts_handler.h"
// FIXME: SOUND
// #include "soundrecorder.h"
namespace KHotKeys
{
@ -49,8 +45,6 @@ void init_global_data( bool active_P, QObject* owner_P )
{
gesture_handler = new Gesture( active_P, owner_P );
}
// FIXME: SOUND
// static_cast< void >( new Voice( active_P, owner_P ));
khotkeys_set_active( false );
}

View file

@ -169,9 +169,6 @@ void Settings::reinitialize()
daemon_disabled = false;
// Currently unused
voice_shortcut = KShortcut();
already_imported = QStringList();
}
@ -211,12 +208,6 @@ void Settings::setGestureTimeOut(int timeout)
}
void Settings::setVoiceShortcut( const KShortcut &shortcut )
{
voice_shortcut = shortcut;
}
ActionDataGroup *Settings::takeActions()
{
ActionDataGroup *res = m_actions;
@ -225,12 +216,6 @@ ActionDataGroup *Settings::takeActions()
}
KShortcut Settings::voiceShortcut() const
{
return voice_shortcut;
}
bool Settings::import(KConfig& config, ImportType ask, ActionState state)
{
return importFrom(m_actions, config, ask, state);
@ -459,10 +444,6 @@ bool Settings::reread_settings(bool include_disabled)
delete gestures_exclude;
gestures_exclude = new Windowdef_list( gesturesExcludeConfig );
// ### Voice
KConfigGroup voiceConfig( &config, "Voice" );
voice_shortcut=KShortcut( voiceConfig.readEntry("Shortcut" , "") );
bool rc = read_settings(m_actions, config, include_disabled, Retain);
// Ensure the system groups exist
validate();

View file

@ -166,15 +166,6 @@ public:
void setGesturesExclude( Windowdef_list *gestures );
Windowdef_list *gesturesExclude();
const Windowdef_list *gesturesExclude() const;
//@}
/**
* @name Voice Commands
*/
//@{
void setVoiceShortcut( const KShortcut &shortcut );
KShortcut voiceShortcut() const;
//@}
/**
* Check if the given config file is a valid khotkeys file
@ -242,11 +233,6 @@ private:
*/
bool daemon_disabled;
/**
* The shortcut that triggers a voice command
*/
KShortcut voice_shortcut;
/**
* List of id's for all imported files.
*/

View file

@ -267,8 +267,6 @@ void SettingsWriter::writeTo(KConfigBase &config)
}
else
config.deleteGroup( "GesturesExclude" );
KConfigGroup voiceConfig( &config, "Voice" );
voiceConfig.writeEntry("Shortcut" , _settings->voice_shortcut.toString() );
}

View file

@ -1,343 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Olivier Goffart *
* ogoffart@kde.org *
* *
* 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. *
***************************************************************************/
#include "sound.h"
#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <kdebug.h>
Sound::Sound()
{
}
Sound::~Sound()
{
}
#define READ_FROM_STREAM(FORMAT,NAME) FORMAT NAME; stream >> NAME;
#define MAGIC(CH) { \
stream >> magic; \
if( magic != ( (CH)[0] | (CH)[1]<<8 | (CH)[2]<< 16 | (CH)[3] << 24 ) ) \
{ \
kWarning() << "bad format " << magic << " != " << CH "\n";\
return;\
} }
#define ABS(X) ( (X>0) ? X : -X )
void Sound::load(const QString& filename)
{
kDebug() << filename;
data=QVector<Q_INT32>();
QFile file(filename);
if(!file.open(IO_ReadOnly))
{
kWarning() <<"unable to open file" ;
return;
}
QDataStream stream(&file);
stream.setByteOrder( QDataStream::LittleEndian );
Q_INT32 magic;
MAGIC("RIFF");
READ_FROM_STREAM(quint32,ChunkSize);
MAGIC("WAVE");
MAGIC("fmt ");
READ_FROM_STREAM(quint32,ChunkSize2);
READ_FROM_STREAM(Q_INT16,AudioFormat);
READ_FROM_STREAM(Q_UINT16,NumberOfChannels);
READ_FROM_STREAM(quint32,SampleRate);
_fs=SampleRate;
READ_FROM_STREAM(quint32,ByteRate);
READ_FROM_STREAM(Q_UINT16,BlockAlign);
READ_FROM_STREAM(Q_UINT16,BitsPerSample);
MAGIC("data");
READ_FROM_STREAM(QByteArray,SoundData);
NumberOfChannels=1; //Wav i play are broken
file.close();
uint BytePS=BitsPerSample/8;
uint NumberOfSamples = (SoundData.size())/(NumberOfChannels*BytePS);
data.resize(NumberOfSamples);
// kDebug() << NumberOfSamples << " samples";
max=0;
for(unsigned long int f=0;f<NumberOfSamples;f++)
{
Q_INT32 nb=0;
for(uint k=0;k<BytePS;k++)
{
nb |= (SoundData[(unsigned int)(f*BytePS+k)]&0x000000FF) << (k*8);
}
if(nb & (1 << (BytePS*8 -1)) )
nb = nb-(1<<BytePS*8);
data[f]=nb;
if(ABS(nb)>max)
{
max=ABS(nb);
}
}
/* static int q=0;
QString name="test" + QString::number(q++) + ".wav";
save(name);*/
}
#define SMAGIC(CH) { stream << ( Q_INT32) ( (CH)[0] | (CH)[1]<<8 | (CH)[2]<< 16 | (CH)[3] << 24 ) ; }
void Sound::save(const QString& filename) const
{
kDebug() << filename << " - " << data.size() << endl;
QFile file(filename);
if(!file.open(IO_WriteOnly))
{
kWarning() <<"unable to open file" ;
return;
}
QDataStream stream(&file);
stream.setByteOrder( QDataStream::LittleEndian );
QByteArray SoundData(data.size()*2, '\0');
for(long int f=0;f<data.size();f++)
{
Q_UINT16 val= (signed short int) ( (data.at(f) * ((double)(1<<13)/(signed)max) ) );
SoundData[ (uint)(2*f) ]= val & 0x00FF;
SoundData[(uint)(2*f+1)]= (val & 0xFF00) >> 8;
// kDebug() << data.at(f) << " / " << max << " = " << val << " | " << SoundData[ 2*f ] << " "<< SoundData[ 2*f+1 ] << endl;
}
Q_UINT16 NumberOfChannels=2;
quint32 SampleRate=_fs;
SMAGIC("RIFF");
//READ_FROM_STREAM(quint32,ChunkSize);
stream << (quint32)(36+ SoundData.size());
SMAGIC("WAVE");
SMAGIC("fmt ");
//READ_FROM_STREAM(quint32,ChunkSize2);
stream << (quint32)(16);
//READ_FROM_STREAM(Q_INT16,AudioFormat);
stream << (Q_INT16)(1);
//READ_FROM_STREAM(Q_UINT16,NumberOfChannels);
stream << (Q_UINT16)(NumberOfChannels);
//READ_FROM_STREAM(quint32,SampleRate);
stream << (quint32)(SampleRate);
//READ_FROM_STREAM(quint32,ByteRate);
stream << (quint32)(NumberOfChannels*SampleRate*16/8);
//READ_FROM_STREAM(Q_UINT16,BlockAlign);
stream << (Q_UINT16)(16/8 *NumberOfChannels);
//READ_FROM_STREAM(Q_UINT16,BitsPerSample);
stream << (Q_UINT16)(16);
SMAGIC("data");
//READ_FROM_STREAM(QByteArray,SoundData);
stream << SoundData;
file.close();
}
#if 0
void Sound::load(const QString& filename)
{
cout << "saout \n";
data=QMemArray<long unsigned int>();
static const int BUFFER_LEN = 4096;
//code from libtunepimp
//(wav_trm.cpp)
FILE *source;
unsigned char buffer[100], *copyBuffer;
unsigned int bytes;
unsigned long ulRIFF;
unsigned long ulLength;
unsigned long ulWAVE;
unsigned long ulType;
unsigned long ulCount;
unsigned long ulLimit;
bool haveWaveHeader = false;
unsigned long waveSize = 0;
WAVEFORMAT waveFormat;
int toRead;
mb_int64_t fileLen = 0;
source = fopen(filename.ascii(), "rb");
if (source == NULL)
{
// errorString = string("File not found");
// fclose(source);
cout << "File not found \n";
return;
}
fseek(source, 0, SEEK_END);
fileLen = ftell(source);
fseek(source, 0, SEEK_SET);
if (fread(buffer, 1, 12, source) != 12)
{
// errorString = string("File is too short");
cout << "File is to short \n";
fclose(source);
return ;
}
ulRIFF = (unsigned long)(((unsigned long *)buffer)[0]);
ulLength = (unsigned long)(((unsigned long *)buffer)[1]);
ulWAVE = (unsigned long)(((unsigned long *)buffer)[2]);
if(ulRIFF != MAKEFOURCC('R', 'I', 'F', 'F') ||
ulWAVE != MAKEFOURCC('W', 'A', 'V', 'E'))
{
// errorString = strdup("File is not in WAVE format");
cout << "File is not WAVE \n";
fclose(source);
return ;
}
// Run through the bytes looking for the tags
ulCount = 0;
ulLimit = ulLength - 4;
while (ulCount < ulLimit && waveSize == 0)
{
if (fread(buffer, 1, 8, source) != 8)
{
// errorString = strdup("File is too short");
cout << "File is to short \n";
fclose(source);
return;
}
ulType = (unsigned long)(((unsigned long *)buffer)[0]);
ulLength = (unsigned long)(((unsigned long *)buffer)[1]);
switch (ulType)
{
// format
case MAKEFOURCC('f', 'm', 't', ' '):
if (ulLength < sizeof(WAVEFORMAT))
{
// errorString = strdup("File is too short");
cout << "File is to short \n";
fclose(source);
return ;
}
if (fread(&waveFormat, 1, ulLength, source) != ulLength)
{
// errorString = strdup("File is too short");
cout << "File is to short \n";
fclose(source);
return ;
}
if (waveFormat.wFormatTag != WAVE_FORMAT_PCM)
{
// errorString = strdup("Unsupported WAV format");
cout << "Unsupported WAVE \n";
fclose(source);
return ;
}
haveWaveHeader = true;
ulCount += ulLength;
break;
// data
case MAKEFOURCC('d', 'a', 't', 'a'):
waveSize = ulLength;
break;
default:
fseek(source, ulLength, SEEK_CUR);
break;
}
}
if (!haveWaveHeader)
{
// errorString = strdup("Could not find WAV header");
cout << "Header nbot found \n";
fclose(source);
return ;
}
fileLen -= (mb_int64_t)ftell(source);
fileLen /= waveFormat.nChannels;
fileLen /= (waveFormat.nBlockAlign / waveFormat.nChannels);
fileLen /= waveFormat.nSamplesPerSec;
//on ne lit qu'un channel
//waveSize=fileLen;
data.resize(waveSize);
unsigned long pos=0;
cout << "Weeee "<< waveSize <<"\n";
copyBuffer = (unsigned char*)malloc(BUFFER_LEN);
if (copyBuffer == NULL)
{
// errorString = strdup("Cannot allocate buffer space.");
return ;
}
for(;;)
{
toRead = min(waveSize, (unsigned long)BUFFER_LEN);
if (toRead <= 0)
break;
bytes = fread(copyBuffer, 1, toRead, source);
if (bytes <= 0)
break;
for(uint f=0;f<bytes;f+=4)
{
data[pos]=(((unsigned long*)copyBuffer)[f/4]);
pos++;
}
waveSize -= toRead;
}
free(copyBuffer);
fclose(source);
return ;
}
#endif

View file

@ -1,58 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Olivier Goffart *
* ogoffart@kde.org *
* *
* 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. *
***************************************************************************/
#ifndef SOUND_H
#define SOUND_H
#include <QVector>
#include <QtCore/qstring.h>
#include <kdemacros.h>
/**
@author Olivier Goffart
*/
class KDE_EXPORT Sound{
public:
Sound();
~Sound();
void load(const QString &filename);
void save(const QString &filename) const;
unsigned int size() const
{
return data.size();
}
inline float at(int pos) const
{
return (float)(data.at(pos))/max;
}
inline uint fs() const
{
return _fs;
}
QVector<Q_INT32> data;
quint32 max;
uint _fs;
};
#endif

View file

@ -1,81 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Olivier Goffart *
* ogoffart@kde.org *
* *
* 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. *
***************************************************************************/
#include "soundrecorder.h"
#include <kdebug.h>
#include <klocale.h>
#include <QtCore/QTimer>
#include <QtCore/QLibrary>
#include "khotkeysglobal.h"
namespace KHotKeys
{
SoundRecorder::create_ptr SoundRecorder::create_fun = NULL;
bool SoundRecorder::init( QLibrary* lib )
{
#ifdef HAVE_ARTS
if( create_fun == NULL && lib != NULL )
create_fun = (create_ptr) lib->symbol( "khotkeys_soundrecorder_create" );
#endif
// kDebug() << "soundrecorder:" << create_fun << ":" << lib;
return create_fun != NULL;
}
SoundRecorder* SoundRecorder::create( QObject* parent )
{
#ifdef HAVE_ARTS
if( create_fun != NULL )
return create_fun( parent, name );
#endif
return new SoundRecorder( parent );
}
SoundRecorder::SoundRecorder(QObject *parent) : QObject(parent) {}
SoundRecorder::~SoundRecorder()
{
}
void SoundRecorder::start()
{
}
void SoundRecorder::stop()
{
}
void SoundRecorder::abort()
{
}
Sound SoundRecorder::sound()
{
Sound s;
return s;
}
}
#include "moc_soundrecorder.cpp"

View file

@ -1,62 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Olivier Goffart *
* ogoffart@kde.org *
* *
* 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. *
***************************************************************************/
#ifndef RECORDER_H
#define RECORDER_H
#include <QtCore/QObject>
#include "sound.h"
#include <kdemacros.h>
#include <QLibrary>
namespace KHotKeys
{
/**
@author Olivier Goffart
*/
class KDE_EXPORT SoundRecorder : public QObject
{
Q_OBJECT
public:
static SoundRecorder* create( QObject* parent = 0 );
virtual ~SoundRecorder();
virtual void start();
virtual void stop();
virtual void abort();
virtual Sound sound();
static bool init( QLibrary* );
signals:
void recorded(const Sound&);
protected:
SoundRecorder(QObject *parent = 0);
typedef SoundRecorder* (*create_ptr)( QObject*, const char* );
private:
static create_ptr create_fun;
};
}
#endif

View file

@ -28,7 +28,6 @@
#include <kdemacros.h>
#include "khotkeysglobal.h"
#include "voicesignature.h"
#include "input.h"
#include "windows_handler.h"
@ -351,50 +350,6 @@ class KDE_EXPORT GestureTrigger
StrokePoints _pointdata;
};
// FIXME: SOUND
#if 0
class KDE_EXPORT Voice_trigger
: public QObject, public Trigger
{
Q_OBJECT
typedef Trigger base;
public:
Voice_trigger( ActionData* data_P, const QString& Voice_P, const VoiceSignature & signature1_P, const VoiceSignature & signature2_P );
Voice_trigger( KConfigGroup& cfg_P, ActionData* data_P );
virtual ~Voice_trigger();
virtual void cfg_write( KConfigGroup& cfg_P ) const;
virtual Trigger* copy( ActionData* data_P ) const;
virtual const QString description() const;
const QString& voicecode() const;
virtual void activate( bool activate_P );
VoiceSignature voicesignature( int ech ) const;
virtual TriggerType type() const { return SoundTrigger; }
public slots:
void handle_Voice( );
private:
QString _voicecode;
VoiceSignature _voicesignature[2];
};
#endif
// FIXME: SOUND
#if 0
// Voice_trigger
inline
const QString& Voice_trigger::voicecode() const
{
return _voicecode;
}
inline
VoiceSignature Voice_trigger::voicesignature(int ech) const
{
return _voicesignature[ech-1];
}
#endif
} // namespace KHotKeys

View file

@ -1,86 +0,0 @@
/*
Copyright (C) 1999-2001 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2008 Michael Jansen <kde@michael-jansen.biz>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "triggers.h"
#include "action_data.h"
#include "voices.h"
#include "windows.h"
#include <KConfigGroup>
#include <KDebug>
namespace KHotKeys {
Voice_trigger::Voice_trigger( ActionData* data_P, const QString &Voicecode_P, const VoiceSignature& signature1_P, const VoiceSignature& signature2_P )
: Trigger( data_P ), _voicecode( Voicecode_P )
{
_voicesignature[0]=signature1_P;
_voicesignature[1]=signature2_P;
}
Voice_trigger::Voice_trigger( KConfigGroup& cfg_P, ActionData* data_P )
: Trigger( cfg_P, data_P )
{
_voicecode = cfg_P.readEntry( "Name" );
_voicesignature[0].read( cfg_P , "Signature1" );
_voicesignature[1].read( cfg_P , "Signature2" );
}
Voice_trigger::~Voice_trigger()
{
voice_handler->unregister_handler( this );
}
void Voice_trigger::cfg_write( KConfigGroup& cfg_P ) const
{
base::cfg_write( cfg_P );
cfg_P.writeEntry( "Name", voicecode());
cfg_P.writeEntry( "Type", "VOICE" ); // overwrites value set in base::cfg_write()
_voicesignature[0].write( cfg_P , "Signature1" );
_voicesignature[1].write( cfg_P , "Signature2" );
}
Trigger* Voice_trigger::copy( ActionData* data_P ) const
{
kDebug() << "Voice_trigger::copy()";
return new Voice_trigger( data_P ? data_P : data, voicecode(), voicesignature(1) , voicesignature(2) );
}
const QString Voice_trigger::description() const
{
return i18n( "Voice trigger: " ) + voicecode();
}
void Voice_trigger::handle_Voice( )
{
windows_handler->set_action_window( 0 ); // use active window
data->execute();
}
void Voice_trigger::activate( bool activate_P )
{
if( activate_P && khotkeys_active())
voice_handler->register_handler( this );
else
voice_handler->unregister_handler( this );
}
} // namespace KHotKeys

View file

@ -1,287 +0,0 @@
/****************************************************************************
KHotKeys
Copyright (C) 2005 Olivier Goffart <ogoffart @ kde.org>
Distributed under the terms of the GNU General Public License version 2.
****************************************************************************/
#include <kaction.h>
#include "voices.h"
#include "voicesignature.h"
#include "triggers.h"
#include "soundrecorder.h"
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kxerrorhandler.h>
#include <QtCore/QTimer>
#include <X11/Xlib.h>
#include <fixx11h.h>
namespace KHotKeys
{
Voice* voice_handler;
Voice::Voice( bool enabled_P, QObject* parent_P )
: QObject( parent_P) ,_enabled( enabled_P ), _recording( false ), _recorder(0)
{
assert( voice_handler == NULL );
voice_handler = this;
_kga=0L;
_timer=0L;
kDebug() ;
}
Voice::~Voice()
{
kDebug() ;
enable( false );
voice_handler = NULL;
}
void Voice::enable( bool enabled_P )
{
#ifndef HAVE_ARTS
enabled_P = false; // never enabled when there's no support
#endif
if( _enabled == enabled_P )
return;
_enabled = enabled_P;
_kga->setEnabled(enabled_P);
}
void Voice::register_handler( Voice_trigger *trigger_P )
{
if( !_references.contains( trigger_P ))
_references.append(trigger_P);
}
void Voice::unregister_handler( Voice_trigger *trigger_P )
{
_references.remove(trigger_P);
}
void Voice::record_start()
{
kDebug() ;
if(!_recorder)
{
_recorder= SoundRecorder::create(this);
connect(_recorder, SIGNAL(recorded(Sound)), this, SLOT(slot_sound_recorded(Sound)));
}
_recorder->start();
_recording=true;
}
void Voice::record_stop()
{
if(!_recording)
return;
kDebug() ;
delete _timer;
_timer=0L;
_recording=false;
if(_recorder)
_recorder->stop();
}
void Voice::slot_sound_recorded(const Sound &sound_P)
{
VoiceSignature signature(sound_P);
Voice_trigger *trig=0L;
Voice_trigger *sec_trig=0L;
double minimum=800000;
double second_minimum=80000;
int got_count=0;
foreach(Voice_trigger *t, _references)
{
for(int ech=1; ech<=2 ; ech++)
{
double diff=VoiceSignature::diff(signature, t->voicesignature(ech));
if(minimum>=diff)
{
second_minimum=minimum;
minimum=diff;
sec_trig=trig;
trig=t;
}
else if(second_minimum>=diff)
{
second_minimum=diff;
sec_trig=t;
}
if( diff < REJECT_FACTOR_DIFF )
got_count++;
kDebug() << ( (diff < REJECT_FACTOR_DIFF) ? "+++" : "---" ) <<t->voicecode() << ech << " : " << diff;
}
}
// double ecart_relatif=(second_minimum-minimum)/minimum;
// kDebug() << ecart_relatif;
if(trig)
kDebug() << "**** " << trig->voicecode() << " : " << minimum;
// if(trig && ecart_relatif > REJECT_FACTOR_ECART_REL)
// if(trig && got_count==1)
bool selected=trig && (got_count==1 || ( minimum < 1.5*REJECT_FACTOR_DIFF && trig==sec_trig ) );
if(selected)
{
trig->handle_Voice();
}
}
/*bool Voice::x11Event( XEvent* pEvent )
{
if( pEvent->type != XKeyPress && pEvent->type != XKeyRelease )
return false;
KKeyNative keyNative( pEvent );
//kDebug() << keyNative.key().toString();
if(_shortcut.contains(keyNative))
{
if(pEvent->type == XKeyPress && !_recording )
{
record_start();
return true;
}
if(pEvent->type == XKeyRelease && _recording )
{
record_stop();
return true;
}
}
return false;
}
*/
void Voice::set_shortcut( const KShortcut &shortcut)
{
_shortcut = shortcut;
if( !_enabled )
return;
if(!_kga)
{
_kga = new KAction(this);
_kga->setObjectName("khotkeys_voice");
connect(_kga,SIGNAL(triggered(bool)) , this , SLOT(slot_key_pressed()));
}
_kga->setGlobalShortcut(shortcut);
}
void Voice::slot_key_pressed()
{
if( _recording )
record_stop();
else
{
record_start();
if(!_timer)
{
_timer=new QTimer(this);
connect(_timer, SIGNAL(timeout()) , this, SLOT(slot_timeout()));
}
_timer->setSingleShot(true);
_timer->start(1000*20);
}
}
void Voice::slot_timeout()
{
if(_recording && _recorder)
{
_recorder->abort();
_recording=false;
}
_timer->deleteLater();
_timer=0L;
}
QString Voice::isNewSoundFarEnough(const VoiceSignature& signature, const QString &currentTrigger)
{
Voice_trigger *trig=0L;
Voice_trigger *sec_trig=0L;
double minimum=800000;
double second_minimum=80000;
int got_count=0;
foreach (Voice_trigger *t , _references)
{
if(t->voicecode()==currentTrigger)
continue;
for(int ech=1; ech<=2 ; ech++)
{
double diff=VoiceSignature::diff(signature, t->voicesignature(ech));
if(minimum>=diff)
{
second_minimum=minimum;
minimum=diff;
sec_trig=trig;
trig=t;
}
else if(second_minimum>=diff)
{
second_minimum=diff;
sec_trig=t;
}
if( diff < REJECT_FACTOR_DIFF )
got_count++;
kDebug() << ( (diff < REJECT_FACTOR_DIFF) ? "+++" : "---" ) <<t->voicecode() << ech << " : " << diff;
}
}
if(trig)
kDebug() << "**** " << trig->voicecode() << " : " << minimum;
bool selected=trig && ((got_count==1 && minimum < REJECT_FACTOR_DIFF*0.7 ) || ( minimum < REJECT_FACTOR_DIFF && trig==sec_trig ) );
return selected ? trig->voicecode() : QString();
}
bool Voice::doesVoiceCodeExists(const QString &vc)
{
foreach (Voice_trigger *t , _references)
{
if(t->voicecode()==vc)
return true;
}
return false;
}
} // namespace KHotKeys
#include "moc_voices.cpp"

View file

@ -1,83 +0,0 @@
/****************************************************************************
KHotKeys
Copyright (C) 2005 Olivier Goffart <ogoffart @ kde.org>
Distributed under the terms of the GNU General Public License version 2.
****************************************************************************/
#ifndef VOICES_H_
#define VOICES_H_
#include <QtGui/QWidget>
#include <kshortcut.h>
class Sound;
#include <QTimer>
class KAction;
namespace KHotKeys
{
class Voice;
class SoundRecorder;
class Voice_trigger;
class VoiceSignature;
class KDE_EXPORT Voice : public QObject
{
Q_OBJECT
public:
Voice( bool enabled_P, QObject* parent_P );
virtual ~Voice();
void enable( bool enable_P );
void register_handler( Voice_trigger* );
void unregister_handler( Voice_trigger* );
// bool x11Event( XEvent* e );
void set_shortcut( const KShortcut &k);
/**
* return QString() is a new signature is far enough from others signature
* otherwise, return the stringn which match.
*/
QString isNewSoundFarEnough(const VoiceSignature& s, const QString& currentTrigger);
bool doesVoiceCodeExists(const QString &s);
public slots:
void record_start();
void record_stop();
private slots:
void slot_sound_recorded( const Sound & );
void slot_key_pressed();
void slot_timeout();
signals:
void handle_voice( const QString &voice );
private:
bool _enabled;
bool _recording;
QList<Voice_trigger *> _references;
SoundRecorder *_recorder;
KShortcut _shortcut;
KAction *_kga;
QTimer *_timer;
};
KDE_EXPORT extern Voice* voice_handler;
} // namespace KHotKeys
#endif

View file

@ -1,423 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Olivier Goffart *
* ogoffart@kde.org *
* *
* 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. *
***************************************************************************/
#include "voicesignature.h"
#include "sound.h"
#include <kconfig.h>
#include <kconfiggroup.h>
#include <math.h>
#ifdef PI
#undef PI
#endif
#define PI (2.0 * asin(1.0))
#include <kdebug.h>
#include <QtCore/qdatetime.h>
#undef Complex
namespace KHotKeys
{
inline static float ABS(float X)
{
return (X>0) ? X : -X ;
}
inline static int MAX(int X , int Y)
{
return (X>Y) ? X : Y ;
}
inline static int MIN(int X , int Y)
{
return (X<Y) ? X : Y ;
}
class Complex
{
public:
Complex () {}
Complex (double re): _re(re), _im(0.0) {}
Complex (double re, double im): _re(re), _im(im) {}
double Re () const { return _re; }
double Im () const { return _im; }
void operator += (const Complex& c)
{
_re += c._re;
_im += c._im;
}
void operator -= (const Complex& c)
{
_re -= c._re;
_im -= c._im;
}
void operator *= (const Complex& c)
{
double reT = c._re * _re - c._im * _im;
_im = c._re * _im + c._im * _re;
_re = reT;
}
Complex operator- ()
{
return Complex (-_re, -_im);
}
Complex operator- (const Complex& c) const
{
return Complex (_re - c._re, _im - c._im);
}
Complex operator+ (const Complex& c) const
{
return Complex (_re + c._re, _im + c._im);
}
Complex operator* (const Complex& c) const
{
return Complex (_re * c._re - _im * c._im , _im * c._re + _re * c._im);
}
double Mod () const { return sqrt (_re * _re + _im * _im); }
static Complex fromExp(double mod, double arg) { return Complex(mod*cos(arg) , mod*sin(arg)); }
private:
double _re;
double _im;
};
static inline double hamming(uint n, uint size)
{
return HAMMING ? 0.54-0.46*cos( 2*PI*n /(size-1) ) : 1;
}
static QVector<double> fft(const Sound& sound, unsigned int start, unsigned int stop)
{
if(start>=stop || sound.size()==0)
return QVector<double>();
//We need a sample with a size of a power of two
uint size=stop-start;
unsigned short log2size=0;
while( (1<<log2size) < size )
log2size++;
int diff=(1<<log2size) - size;
if(diff > size/4 || 1<<log2size > sound.size() )
{
log2size--;
diff=(1<<log2size) - size;
}
size=1<<log2size;
int start2=start-diff/2;
int stop2=start2+ size;
if(start2<0)
{
stop2-=start2;
start2=0;
}
if(stop2>sound.size())
{
start2-= stop2 - sound.size();
stop2=sound.size();
if(start2<0)
{
stop2-=start2;
start2=0;
}
}
//Generate an array to work in
QVector<Complex> samples(size);
//Fill it with samples in the "reversed carry" order
int rev_carry = 0;
for (uint f = 0; f < size - 1; f++)
{
samples[f]=sound.at(start2+rev_carry)* hamming(rev_carry, size);
// KDEBUG(rev_carry);
int mask = size>>1; // N / 2
// add 1 backwards
while (rev_carry >= mask)
{
rev_carry -= mask; // turn off this bit
mask >>= 1;
}
rev_carry += mask;
}
samples[size-1]=sound.at(start2+size-1)*hamming(size-1, size);
//FFT
for(uint level=0; level < log2size; level++)
{
for( int k=0; k< (size>>1) ; k++)
{
uint indice1 = (k << (level+1) ) % (size-1); // (k*2*2^l)%(N-1)
uint indice2 = indice1 + (1<<level); // (k*2*2^l)%(N-1) + 2^l
uint coefW = ( k << (level+1) ) / (size-1); // (k*2*2^l) div (N-1)
double Wexpn=-2 * PI * coefW / (2 << level); // -2 pi n / 2^(l+1)
Complex W=Complex::fromExp(1, Wexpn) ;
//OPERATION BUTTERFLY
Complex a=samples[indice1];
Complex b=samples[indice2];
samples[indice1]=a+W*b;
samples[indice2]=a-W*b;
// kDebug() << "PAPILLON s_" << indice1 << " s_" << indice2 << " W_" << (2<<level) << "^" << coefW;
}
}
QVector<double> result(size);
for(uint f=0;f<size;f++)
{
result[f]=samples[f].Mod() / size;
}
return result;
}
QVector<double> VoiceSignature::fft(const Sound& sound, unsigned int start, unsigned int stop)
{
return KHotKeys::fft(sound, start, stop);
/*QVector<double> result(8000);
for(int f=0; f<8000;f++)
{
Complex c(0);
for(uint x=start; x<stop; x++)
{
Complex s(sound.at(x));
double angle=-2*PI*f*x/8000;
s*= Complex( cos(angle) , sin(angle) );
c+=s;
}
result[f]= c.Mod()/(stop-start) ;
}
return result;*/
}
bool VoiceSignature::window(const Sound& sound, unsigned int *_start, unsigned int *_stop)
{
bool isNoise=false;
unsigned int length=sound.size();
uint unit=WINDOW_UNIT;
if(length < unit )
return false;
//Fenêtrage
unsigned int start=0 , stop=0;
double moy=0;
for(uint x=0;x<unit;x++)
{
moy+=ABS(sound.at(x));
}
if(moy>WINDOW_MINIMUM*unit)
isNoise=true;
for(uint x=unit; x<length; x++)
{
if(moy<WINDOW_MINIMUM*unit)
{
if(stop==0)
start=x-unit/2;
}
else
stop=x-unit/2;
moy+=ABS(sound.at(x));
moy-=ABS(sound.at(x-unit));
}
if(moy>WINDOW_MINIMUM*unit && isNoise)
return false;
stop=MIN(length,stop+WINDOW_MINIMUM_ECART);
start=MAX(0 ,start-WINDOW_MINIMUM_ECART);
if(_start)
*_start=start;
if(_stop)
*_stop=stop;
return start<stop;
}
//finally doesn't give better results
/*#define HZ_TO_MEL(F) (1127*log(1+(F)/700.0))
#define MEL_TO_HZ(M) ( ( exp((M)/1127.0) -1) *700 )*/
#define HZ_TO_MEL(F) (F)
#define MEL_TO_HZ(F) (F)
VoiceSignature::VoiceSignature(const Sound& sound)
{
static uint temp_wind=0, temp_fft=0, temp_moy=0;
QTime t;
t.start();
unsigned int start , stop;
if(!window(sound,&start,&stop))
{
kWarning() << "No voice found in the sound" ;
return;
}
temp_wind+=t.restart();
uint length=stop-start;
for(int wind=0; wind<WINDOW_NUMBER; wind++)
{
unsigned int w_start=MAX(start, start+ (int)((wind - WINDOW_SUPER)*length/WINDOW_NUMBER));
unsigned int w_stop =MIN(stop , start+ (int)((wind+1.0+WINDOW_SUPER)*length/WINDOW_NUMBER));
QVector<double> fourrier=fft(sound, w_start,w_stop);
temp_fft+=t.restart();
//MEL conversion
double mel_start=HZ_TO_MEL(FFT_RANGE_INF);
uint mel_stop=HZ_TO_MEL(FFT_RANGE_SUP);
for(int four=0; four<FOUR_NUMBER; four++)
{
unsigned int wf_start=mel_start + four*(mel_stop-mel_start)/FOUR_NUMBER;
unsigned int wf_stop=mel_start + (four+1)*(mel_stop-mel_start)/FOUR_NUMBER;
unsigned int f_start=MEL_TO_HZ( wf_start )*fourrier.size()/sound.fs();
unsigned int f_stop=MEL_TO_HZ( wf_stop )*fourrier.size()/sound.fs();
unsigned int f_size=f_stop-f_start;
double nb=0;
for(uint f=f_start; f<f_stop; f++)
{
int freq=f*fourrier.size()/sound.fs();
nb+=fourrier[f]*FFT_PONDERATION(freq);
}
nb/=(f_size);
data[wind][four]=nb;
}
temp_moy+=t.restart();
}
// kDebug() << "wind: "<< temp_wind << " - fft: " << temp_fft << " - moy: " << temp_moy;
}
VoiceSignature::~VoiceSignature()
{
}
float VoiceSignature::diff(const VoiceSignature &s1, const VoiceSignature &s2)
{
if(s1.isNull() || s2.isNull())
return 1000000;
#if 0
double result=0;
for(int x=0;x<WINDOW_NUMBER;x++)
for(int y=0;y<FOUR_NUMBER;y++)
{
double d1=s1.data[x][y]-s2.data[x][y];
result+= d1*d1;//*pond[x][y];
}
return result;
#endif
//DTW
// http://tcts.fpms.ac.be/cours/1005-08/speech/projects/2001/delfabro_henry_poitoux/
const int I=WINDOW_NUMBER;
const int J=WINDOW_NUMBER;
double g[I+1][J+1];
for(int f=1;f<=J;f++)
g[0][f]=10000000;
for(int f=1;f<=I;f++)
g[f][0]=10000000;
g[0][0]=0;
for(int i=1;i<=I;i++)
for(int j=1;j<=J;j++)
{
double d=0;
for(int f=0;f<FOUR_NUMBER;f++)
{
double d1=s1.data[i-1][f]-s2.data[j-1][f];
d+= d1*d1;//*pond[x][y];
}
d=sqrt(d);
g[i][j]=qMin(qMin( g[i-1][j]+d, g[i][j-1]+d ) , g[i-1][j-1]+d+d );
}
return g[I][J]/(I+J);
}
int VoiceSignature::size1()
{
return WINDOW_NUMBER;
}
int VoiceSignature::size2()
{
return FOUR_NUMBER;
}
QMap<int, QMap<int, double> > VoiceSignature::pond;
void VoiceSignature::write(KConfigGroup& cfg, const QString &key) const
{
QStringList sl;
for(int x=0;x<WINDOW_NUMBER;x++)
for(int y=0;y<FOUR_NUMBER;y++)
{
sl.append( QString::number(data[x][y]) );
}
cfg.writeEntry(key,sl);
}
void VoiceSignature::read(KConfigGroup& cfg, const QString &key)
{
QStringList sl=cfg.readEntry(key, QStringList());
for(int x=0;x<WINDOW_NUMBER;x++)
for(int y=0;y<FOUR_NUMBER;y++)
{
data[x][y]= sl[x*FOUR_NUMBER+y].toDouble();
}
}
}

View file

@ -1,101 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Olivier Goffart *
* ogoffart@kde.org *
* *
* 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. *
***************************************************************************/
#ifndef SIGNATURE_H
#define SIGNATURE_H
#include <QVector>
#include <QtCore/QMap>
#include <kdemacros.h>
#include <KConfig>
class Sound;
#define WINDOW_MINIMUM 0.10
#define WINDOW_MINIMUM_ECART 200
#define WINDOW_NUMBER 7
#define WINDOW_SUPER 0.43
#define WINDOW_UNIT sound.fs()/4
#define FOUR_NUMBER 7
#define FOUR_SUPER 0
#define FFT_RANGE_INF 370
#define FFT_RANGE_SUP 2000
// #define FFT_PONDERATION(f) ((double)log(1+(f))/log(10))
#define FFT_PONDERATION(f) 1
// theses settings are better in a 8000Hz fs
/*#define FFT_RANGE_INF 300
#define FFT_RANGE_SUP 1500*/
//#define REJECT_FACTOR_ECART_REL 0.5
#define REJECT_FACTOR_DIFF 0.0018
#define HAMMING false
namespace KHotKeys
{
/**
@author Olivier Goffart
*/
class KDE_EXPORT VoiceSignature{
public:
explicit VoiceSignature(const Sound& s);
VoiceSignature(){}
~VoiceSignature();
QMap<int, QMap<int, double> > data;
static QMap<int, QMap<int, double> > pond;
static float diff(const VoiceSignature &s1, const VoiceSignature &s2);
static int size1();
static int size2();
static QVector<double> fft(const Sound& sound, unsigned int start, unsigned int stop);
static bool window(const Sound& sound, unsigned int *start, unsigned int *stop);
void write(KConfigGroup& cfg, const QString &key) const;
void read(KConfigGroup& cfg, const QString &key);
inline bool isNull() const
{
return data.isEmpty();
}
};
}
#endif