QAudioRecorder detect user not speaking and stop - qt

I want to use QAudioRecorder to record audio from the user and then use the audio output file for speech to text. I could successfully run and record audio from this example, http://doc.qt.io/qt-5/qtmultimedia-multimedia-audiorecorder-example.html.
But my problem is, I need to detect if user has stopped speaking while QAudioRecorder is actively recording audio. So QAudioRecorder should only stop when user is not speaking.
I could stop QAudioRecorder for fixed seconds using QTimer as below:
void AudioRecorder::toggleRecord()
{
if (audioRecorder->state() == QMediaRecorder::StoppedState) {
audioRecorder->setAudioInput(boxValue(ui->audioDeviceBox).toString());
QAudioEncoderSettings settings;
settings.setCodec(boxValue(ui->audioCodecBox).toString());
settings.setSampleRate(boxValue(ui->sampleRateBox).toInt());
settings.setBitRate(boxValue(ui->bitrateBox).toInt());
settings.setChannelCount(boxValue(ui->channelsBox).toInt());
settings.setQuality(QMultimedia::EncodingQuality(ui->qualitySlider->value()));
settings.setEncodingMode(ui->constantQualityRadioButton->isChecked() ?
QMultimedia::ConstantQualityEncoding :
QMultimedia::ConstantBitRateEncoding);
QString container = boxValue(ui->containerBox).toString();
audioRecorder->setEncodingSettings(settings, QVideoEncoderSettings(), container);
audioRecorder->record();
this->recordTimeout();
}
else {
this->stopRecording();
}
}
void AudioRecorder::recordTimeout()
{
QTimer* mTimer = new QTimer(this);
mTimer->setSingleShot(true);
connect(mTimer, SIGNAL(timeout()), SLOT(stopRecording()));
mTimer->start(6000);
}
void AudioRecorder::stopRecording()
{
audioRecorder->stop();
}
But instead of this it should stop recording when user is not speaking. The QAudioProbe class has this signal audioBufferProbed(QAudioBuffer) which may be helpful to check level of audio but I don't know how to use it and what level can be used to detect if user is not speaking.

I've been trying to do more or less the same thing for a while now. There is an example - https://doc.qt.io/qt-5/qtdatavisualization-audiolevels-example.html that shows you how implement an audio level meter which should be helpful. The example uses QAudioInput. Specifically, it uses QAudioInput::start(QIODevice * device) and passes a custom QIODevice to implement the audio level meter. The problem with this approach using QAudioInput is once you've got the data, it's not easy to encode it and write it out to file where as with QAudioRecorder it's simple.
Anyway ... your right QAudioProbe is your best bet if you want to record the easy way with QAudioRecorder. I adapted the Qt audio level meter example to work with QAudioProbe instead of QAudioInput/QIODevice. See - https://gist.github.com/sam-at-github/bf66e84105cc3e23e7113cca5e3b1772.
One minor issue the level meter needs QAudioFormat but QAudioRecorder only provides you with a QEncoderSettings (Should probably fix code to use the latter. I don't know why both QEncoderSettings and QAudioFormat need to exist ...). You just gotta get a QAudioDeviceInfo for the device your using then use QAudioDeviceInfo::preferredFormat().
Relaed Post: Qt: API to write raw QAudioInput data to file just like QAudioRecorder

Related

How should a Qt-based preferences panel broadcast that a pref has changed?

I am trying to design a preferences panel for my multidocument app. When a given pref changes – font size, say – all of the document windows should immediately update to reflect the new pref value. I don't want to construct the preferences panel up front, for all the document windows to connect to, because it contains a QFontComboBox that takes more than a second to set itself up (ouch); that's not a price I want to pay at startup. So then, my question is: what is an elegant design for the prefs panel to let all the document windows know about the change? In Cocoa, which I'm more used to, I'd use NSNotification to broadcast a notification from the prefs panel that all the document windows could observe; that provides the loose coupling required (since objects can add themselves as observers before the broadcaster exists).
Two approaches occur to me so far:
Loop through topLevelWidgets, do a dynamic cast to my document window class, and for all the document windows I thereby find, just call a hard-coded method on them directly.
Make a second class, PreferencesNotifier, that is separate from the UI object that takes so long to load, and construct a singleton object of this class at startup that all of the document windows can connect themselves to. When the preferences panel eventually gets created, it can send signals to slots in PreferencesNotifier, which will then call its own signals to notify the connected document windows.
Neither seems quite as elegant as NSNotification, and I'm wondering if I'm missing something. Thanks for any tips.
First thing, do not try to copy patterns, like Cocoa's NSNotification/NotificationCenter, to other frameworks (or languages, or...). There are various ways to send messages and generally each framework has picked one. Trying to use the one method that was picked by the framework you are using will lead to the most elegant solutions.
If you really want to, you could implement your own set of classes that will do exactly what NSNotification does. It will feel more elegant to you, but only because you are used to using Cocoa. It will feel odd to every other Qt developer. Also, this solution will require you to write a lot of code as you will not be able to leverage all the features of Qt.
The first solution you are suggesting is a bit ugly and looks more like a hack than anything.
What I do, when I have to handle preferences in a program, is something similar to your solution 2. I create a class that is responsible for handling all settings: read/write setting file, change setting, set default values, etc. Generally this class is a singleton. This class has very limited access to other parts of the program, and generally no access at all to the UI. Each components that needs to access the preferences will use this class. If you do it properly (e.g. use Q_PROPERTY), this class can even be accessed by QML, if you ever need to use Qt Quick.
class Settings: public QObject {
Q_OBJECT
Q_PROERTY(bool showX READ showX WRITE setShowX NOTIFY showXChanged)
public:
bool showX() const { return m_showX; }
void setShowX(bool show) {
if (show == m_showX)
return;
m_showX = show;
emit showXChanged(m_showX);
}
signals:
void showXChanged(bool);
public slots:
void save() const; // Save to disk
void load(); // Load from disk
private:
QSettings m_settings; // Handle load/save from/to disk
bool m_showX;
};
class Window {
Window() {
...
m_widgetX->setVisible(settings->showX());
connect(settings, &Settings::showXChanged,
this, [this](bool show) { m_widgetX->setVisible(show); }
);
...
}
};
class PrefWindow {
PrefWindow () {
...
ui->checkBoxShowX->setChecked(settings->showX());
...
}
private slots:
void on_saveButton_clicked() {
settings->setShowX(ui->checkBoxShowX->checked()):
settings->save();
}
};

Incremental Loading in QScintilla Object

I am using a an object of QScintilla and I am reading the file in QScintilla Object incrementally.
Header myEditor.h
class myScintilla: public QScintilla {
public readFile();
};
#include "myEditor.h"
void myEditor::readFile() {
if (FILE* fp = fopen(ofilename.toLatin1(), "r")) {
QTextStream ts(fp, QIODevice::ReadOnly);
int bufferSize =(1024* 1024)/2;
do {
QString s = ts.read(bufferSize);
append(s);
} while(!ts.atEnd());
}
Even after this change there will be still performance issue while reading large files. It took around
1) 25 seconds to read a file of size 1.5 GB. (Machine cores 4 , 16 GB RAM)
2 10 seconds of file of size 512MB (on same machine)
Is there any way we can load the file in QScintilla object incrementally based on movement of scrollbar?
I found your question interesting so did a little bit of Googling on your behalf. It seems to me that while Scintilla exposes this functionality via the Loader interface, in fact the QScintilla class does not. To make this work, it seems that what you would have to do is use the QScintillaBase class to send the SCI_CREATELOADER message to the Scintilla control.
Edit: Also, you do not want to use append in a loop. That will cause all sorts of terrible things to happen. It will likely force rendering, some sort of indexing, etc. Before using my suggestion above, I would suggest that you instead build up a gigantic QString in memory and then set that at the end. Better to pre-allocate. That might be a little faster.
FINAL ANSWER
Edit #2: OK, it was bothering me that such an industrial strength editor component like Scintilla did not support this natively but it seems that the right way to do this is by using a combination of features:
You start with a document allocated using SCI_ALLOCATE where the number of bytes is the size of your file
You listen for the SCN_UPDATEUI event
Then, based on where the user is scrolling to, you load that data
It should be straightforward to map the above to QScintillaBase as a test.

Application GUI state saving in Qt

What is an optimal and an appropriate way to save the state of a Qt GUI so I get the same state I had back when I closed the application ?
By state I mean : current indexes (for combo box ...), color palette, widgets positions... right before closing the application
You can use the QSettings class.
Simple use of QSettings class (code inspired from Qt's documentation):
In the main-window of your application code member functions that saves and restore the settings:
void MainWindow::writeSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize(400, 400)).toSize());
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
Call those 2 functions from the MainWindow constructor and from the closeEvent override, like this:
MainWindow::MainWindow()
{
// code from constructor
//...
readSettings();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
//optional check if the user really want to quit
// and/or if the user want to save settings
writeSettings();
event->accept();
}
The direct answer requires specific elaborated design for your code and not really a short Qt question or even the question specific to Qt. That is about C++ which is not the VM-based language that assists with serializing the state of program code to data. Having all objects serializable we can then attempt to apply certain C++/Qt classes/techniques.
This task is much easier to accomplish with languages like Java, though. And with C++/Qt you have to routinely make serialize-able / serialize / restore everything that is running in your code and still no guarantee that works as long as the context is not fully captured. This task is not easy for sure and makes sense only in specific application.
The most you can get directly from Qt is to save/restore QMainWindow and other independent widgets geometry (position/size):
saveGeometry
restoreGeometry
... and that solution is still somewhat incomplete or you may/not use QSettings for the storage.
I use QSettings for this. With routines similar to Zlatomir's.
For each window I have in the project I use a different section in QSettings and have readSettings() and writeSettings() in the source for each window.
Anything on the form that I want to persist I have to explicitly save and recall. In the case of a QComboBox it would be something like:
QSettings settings("Organisation", "MySoftware");
settings.beginGroup("WindowNumberTwo");
settings.setValue("ComboIndex", combobox->currentIndex());
// save more values here
// ...
settings.endGroup();
I don't know of a built in way to persist your window states - it has to be don't value by value.

QT track when a user has been idle from the computer?

Im trying to figure out how to track when a user has been idle from the computer, meaning not only my application. The reason is that i want my application to be able to set the user as "Away" after a certain amount of time. Think like Skype which takes you away after X minutes.
Any ideas how to accomplish this?
Edit
What i've got so far to track the mouse:
//Init
mouseTimer = new QTimer();
mouseLastPos = QCursor::pos();
mouseIdleSeconds = 0;
//Connect and Start
connect(mouseTimer, SIGNAL(timeout()), this, SLOT(mouseTimerTick()));
mouseTimer->start(1000);
void MainWindow::mouseTimerTick()
{
QPoint point = QCursor::pos();
if(point != mouseLastPos)
mouseIdleSeconds = 0;
else
mouseIdleSeconds++;
mouseLastPos = point;
//Here you could determine whatever to do
//with the total number of idle seconds.
qDebug() << mouseIdleSeconds;
}
Any way to add keyboard to this also?
There are platform-specific ways of getting idle user notifications. You should almost always use those, instead of rolling your own.
Suppose you insist on rolling your own code. On X11, OS X and Windows, applications simply don't receive any events that are targeted at other applications. Qt doesn't offer much help in monitoring such global events. You need hook into the relevant global events, and filter them. This is platform specific.
So, no matter what you do, you have to write some front-end API that exposes the functionality you're after, and write one or more platform-specific backends.
The preferred platform-specific idle time APIs are:
On Windows, GetLastInputInfo, see this answer.
On OS X, NSWorkspaceWillSleepNotification and NSWorkspaceDidWakeNotification, see this answer.
On X11, it is the screensaver API:
/* gcc -o getIdleTime getIdleTime.c -lXss */
#include <X11/extensions/scrnsaver.h>
#include <stdio.h>
int main(void) {
Display *dpy = XOpenDisplay(NULL);
if (!dpy) {
return(1);
}
XScreenSaverInfo *info = XScreenSaverAllocInfo();
XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), info);
printf("%u", info->idle);
return(0);
}
Best bet would be to check for mouse and keyboard events.
If you override the eventFilter function and in that check for:
QEvent::MouseButtonPress
QEvent::MouseButtonRelease
QEvent::Wheel
QEvent::KeyPress
QEvent::KeyRelease
Create a QTimer, which will be reset on any of the events, and if not, just let the timer tick and fire a callback at whatever intervalls you wish.
Edit:
Please see comments and Kuba Ober's answer for more info.

Qt5 QSerialPort write data

How I can write data in serial port, with delay between send's messages?
This is my code:
void MainWindow::on_pushButton_Done_clicked()
{
if(sport->isOpen()){
sport->clear();
QString cmd = Phase+Mode;
//Write Stop
sport->write("stop!", 5);
//Write Mode
sport->write(cmd.toStdString().c_str(), cmd.toStdString().length());
//Write Speed
sport->write(Speed.toStdString().c_str(), Speed.toStdString().length());
//Write Direction
sport->write(Direction.toStdString().c_str(), Direction.toStdString().length());
//Run
sport->write("start!", 6);
}
}
My device receives an error message when I call this function.
Thank you.
2 options:
use waitForBytesWritten to ensure the bytes are written and then a short sleep
however this will block the thread and will block the gui
the other is using a QTimer to trigger another slot a few times and a field that will indicate what needs to be sent
Looks like you are trying to program some step motor controller or something similar.
Usually in such controllers you should wait for controller response to verify that command was processed properly.
It looks like that your design of code is very bad. Move everything related with this controller to separate class, which has set of slots, something like: starRotateLeftWithSpeed(double). Code will be cleaner and it will be easy to use thread if you decide to use methods like waitForBytesWritten proposed in another answer.
Definitely you should read controller manual more carefully.

Resources