How to save recordings to *.wav? - qt

I trying to change my code to save recordings to wav-files. Later i have to import this to MATLAB.
Its works to save like .*pcm or.*wav. But I want play it with (example VLC Player) external player.
QAudioFormat format;
Conf values;
format.setSampleRate(values.getSampRate());
format.setChannelCount(values.getChannel());
format.setSampleSize(values.getSampSize());
format.setCodec(values.getCodec());
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
in config-file i have configuration:
samp_rate=88200
channel=1
samp_size=24
codec=Audio/PCM
byte_order=QAudioFormat::LittleEndian
sample_type=QAudioFormat::SignedInt
Saving file looks:
m_audio->startrecording(fn+".pcm");
I changed pcm to wav - file will be recorded, but I cant open it with VLC (just import to Audacity with manual input of sample Rate, ByteOrder). Its because of RAW-data? how can able to save my recording like wav-file included sample-size, sampl-rate ...?
Audio.cpp
// ************************************************************************************************
// Audio-Class
// ************************************************************************************************
#include "Audio.h"
#include "Conf.h"
#include "Measure.h"
// ************************************************************************************************
Audio::Audio(Conf *conf)
{
m_conf = conf;
AudioRecord();
}
// ************************************************************************************************
//Initialization and signal-slot connection
void Audio::AudioRecord()
{
QAudioFormat format;
Conf values;
format.setSampleRate(values.getSampRate());
format.setChannelCount(values.getChannel());
format.setSampleSize(values.getSampSize());
format.setCodec(values.getCodec());
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!info.isFormatSupported(format))
{
qWarning() << "Default format not supported";
format = info.nearestFormat(format);
}
m_audio = new QAudioInput(format, this);
connect(m_audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
}
// ************************************************************************************************
//Start recording method
void Audio::startrecording(QString rec_file_path)
{
m_file.setFileName(rec_file_path);
m_file.open(QIODevice::WriteOnly);
m_audio->start(&m_file);
}
// ************************************************************************************************
//Stop recording
void Audio::stoprecording()
{
m_audio->stop();
m_file.close();
}
// ************************************************************************************************
//Recording DEBUG output
void Audio::handleStateChanged(QAudio::State newState)
{
switch (newState)
{
case QAudio::StoppedState:
if (m_audio->error() != QAudio::NoError)
{
qDebug() << "Error!!";
} else
{
qDebug() << "Finished recording";
}
break;
case QAudio::ActiveState:
qDebug() << "Started recording";
break;
default:
break;
}
}
// ************************************************************************************************
Audio.h
// ************************************************************************************************
// Audio-HEADER-file
// ************************************************************************************************
#ifndef AUDIO_H
#define AUDIO_H
// ************************************************************************************************
// Includes
#include <QDebug>
#include <QObject>
#include "Conf.h"
#include <QAudioInput>
#include <QDateTime>
#include <QTimer>
// ************************************************************************************************
// Define
#define SAVE_AUDIO_PATH "/home/nikitajarocky/workspace/QT/UART_PC/IO/"
// ************************************************************************************************
// Class variables and methods
class Audio : public QObject
{
Q_OBJECT
public:
explicit Audio(Conf *conf);
void start(QString file_name);
void stop();
void startrecording(QString);
void stoprecording();
signals:
public slots:
void handleStateChanged(QAudio::State);
void AudioRecord();
private:
Conf *m_conf;
Conf *m_samp_rate;
QAudioInput *m_audio;
QFile m_file;
};
// ************************************************************************************************
#endif // AUDIO_H

A much simpler approach is use QAudioRecorder, it handles the writing of the header and also handles the audio capture.
It saves you from big changes, if your goal is only recording.
See the example:
audio.h:
#ifndef AUDIO_H
#define AUDIO_H
#include <QtCore>
#include <QtMultimedia>
class Audio : public QObject
{
Q_OBJECT
public:
explicit Audio(QObject *parent = nullptr);
~Audio();
public slots:
QStringList audioInputs();
bool record(const QString &path, const QString &audio_input = QString());
void stop();
private:
QAudioRecorder *m_recorder;
};
#endif // AUDIO_H
audio.cpp:
#include "audio.h"
Audio::Audio(QObject *parent) : QObject(parent)
{
m_recorder = new QAudioRecorder(this);
}
Audio::~Audio()
{
stop();
}
QStringList Audio::audioInputs()
{
return m_recorder->audioInputs();
}
bool Audio::record(const QString &path, const QString &audio_input)
{
QAudioEncoderSettings audio_settings;
audio_settings.setCodec("audio/pcm");
audio_settings.setChannelCount(1);
audio_settings.setSampleRate(44100);
m_recorder->setEncodingSettings(audio_settings);
m_recorder->setOutputLocation(path);
m_recorder->setAudioInput(audio_input);
m_recorder->record();
if (m_recorder->state() == QAudioRecorder::RecordingState)
{
qDebug() << "Recording...";
return true;
}
else
{
qDebug() << qPrintable(m_recorder->errorString());
return false;
}
}
void Audio::stop()
{
if (m_recorder->state() == QAudioRecorder::RecordingState)
{
m_recorder->stop();
qDebug() << "Recording stopped";
}
else
{
qDebug() << "Nothing to stop";
}
}
Usage example (recording 5 seconds):
#include <QtCore>
#include "audio.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Audio audio;
audio.record("file.wav");
QTimer::singleShot(5 * 1000, &audio, &Audio::stop);
return a.exec();
}

Related

How to convert unsigned long long value to a string in qt

I have a calulation that returns large value of factorials of a given number (ex: Factorial of 22 = 17196083355034583040). I want to set the result to a label. I did as shown below.
void Dialog::onNumberChanged(unsigned long long Number)
{
ui->resultPrime->setText(QString::number(Number));
}
MyThread.h
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
bool Stop;
int inputNumber;
unsigned long long resultFactorial;
void Resume();
void Pause();
bool pause;
private:
QMutex sync;
QWaitCondition pauseCond;
// bool pause;
signals:
void NumberChanged(unsigned long long);
public slots:
};
MyThread.cpp
#include "mythread.h"
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>
MyThread::MyThread(QObject *parent):QThread(parent)
{
pause = false;
}
void MyThread::run()
{
QMutex mutex;
int n = inputNumber;
unsigned long long factorial = 1;
// qDebug() << "Enter a positive integer: ";
// cin >> n;
mutex.lock();
if (n < 0)
qDebug() << "Error! Factorial of a negative number doesn't exist.";
else {
for(int i = 1; i <=n; ++i) {
sync.lock();
if(pause)
pauseCond.wait(&sync); // in this place, your thread will stop to execute until someone calls resume
qDebug() << "Paused for now" << pause;
sync.unlock();
factorial *= i;
MyThread().msleep(1000);
emit NumberChanged(factorial);
}
qDebug() << "Factorial of " << n << " = " << factorial;
}
resultFactorial = factorial;
mutex.unlock();
// return factorial;
}
void MyThread::Resume()
{
sync.lock();
pause = false;
sync.unlock();
pauseCond.wakeAll();
}
void MyThread::Pause()
{
sync.lock();
pause = true;
sync.unlock();
}
Dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include "mythread.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
~Dialog();
MyThread *mThread;
private:
Ui::Dialog *ui;
public slots:
void onNumberChanged(unsigned long long);
private slots:
void on_startPrime_clicked();
void on_suspendPrime_clicked();
void on_resumePrime_clicked();
void on_stopPrime_clicked();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include "mythread.h"
#include <QDebug>
//bool pauseCondition = false;
int statusOfPrimeThread = 0;
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Dialog)
{
ui->setupUi(this);
mThread = new MyThread(this);
connect(mThread, SIGNAL(NumberChanged(long)), this, SLOT(onNumberChanged(long)));
ui->activeStatePrime->setText(QString("Not Started"));
// connect(this, SIGNAL(on_resumePrime_clicked), mThread, SLOT(Resume()));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::onNumberChanged(unsigned long long Number)
{
qDebug() << QString::number(17196083355034583040ull);
ui->resultPrime->setText(QString::number(Number));
}
void Dialog::on_startPrime_clicked()
{
// Started
mThread->inputNumber = ui->lineEditPrime->text().toInt();
mThread->start();
if(mThread->isRunning()){
ui->activeStatePrime->setText(QString("Started"));
}
qDebug() << QString::number(17196083355034583040ull);
}
void Dialog::on_suspendPrime_clicked()
{
//Stopped
// mThread->terminate();
// pauseCondition = true;
// mThread->pause = pauseCondition;
mThread->Pause();
ui->activeStatePrime->setText(QString("Paused"));
}
void Dialog::on_resumePrime_clicked()
{
mThread->Resume();
ui->activeStatePrime->setText(QString("Resumed"));
}
void Dialog::on_stopPrime_clicked()
{
mThread->terminate();
ui->activeStatePrime->setText(QString("Terminated"));
}
But the label is not changed. How can I set such a large value, and I am correctly using unsigned long long datatype or is there any other datatype that can be used.

Color channels are changing using Qt QImage with data and I don't know why

I have written a function in Qt to extract the data out of an image for the purpose of manipulating it.
I then have another function to reinsert the data back to an image and display it. The problem I am having is that even if I do no manipulation on the pixel data other than extract and reinsert, it is still changing the data. On a yellow image it changes it to turquoise blue when it should remain yellow.
I am including the function code to extract and reinsert as specimen code. I can include more if it is needed such as the display function etc...Does anyone know if I am doing something wrong?
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
filter = "All Picture Files (*.png *.jpg *.jpeg *.bmp *.tif *.tiff)"
";; Bitmap Files (*.bmp) ;; JPEG (*.jpg *.jpeg) ;; PNG (*.png) ;; TIFF (*.tif *.tiff)";
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::importImage()
{
importCancelled = false;
QString filename = QFileDialog::getOpenFileName(nullptr, QObject::tr("Import Image"), "", filter);
if(!filename.isEmpty()){
image.load(filename);
image = image.convertToFormat(QImage::Format_RGBA8888);
}
else {
importCancelled = true;
if(importCancelled){
QString cleanPlateCancelled = "Operation Cancelled";
ui->statusBar->showMessage(cleanPlateCancelled,5000);
return;
}
}
}
void MainWindow::scaleImage()
{
if (image.isNull()){
return;
}
else {
image = image.scaledToHeight(ui->view->height(), Qt::TransformationMode::SmoothTransformation);
}
}
void MainWindow::displayImage()
{
if (image.isNull()){
return;
}
else {
scene = new QGraphicsScene;
showImage = new QGraphicsPixmapItem(QPixmap::fromImage(image));
scene->addItem(showImage);
ui->view->setScene(scene);
}
}
void MainWindow::rgbaExtraction()
{
numberOfBytes = static_cast<uint>(image.sizeInBytes());
auto const imageData = image.bits();
rgba = std::vector<uchar>(numberOfBytes,0);
rgbaReset = std::vector<uchar>(numberOfBytes,0);
for (uint i{0}; i < numberOfBytes; ++i) {
rgbaReset[i] = rgba[i] = imageData[i];
}
}
void MainWindow::rgbaInsertion()
{
auto *imageData = new uchar[numberOfBytes];
for (uint i{0};i < numberOfBytes;++i) {
imageData[i] = rgba[i];
}
image = QImage(imageData, image.width(), image.height(), QImage::Format_RGBA8888);
}
void MainWindow::on_importButton_clicked()
{
importImage();
scaleImage();
displayImage();
rgbaExtraction();
}
void MainWindow::on_quitButton_clicked()
{
QApplication::quit();
}
void MainWindow::sceneUpdater()
{
showImage->setPixmap(QPixmap::fromImage(image));
scene->update();
ui->view->update();
}
void MainWindow::on_redSlider_valueChanged(int value)
{
QString redString = QString::number(value);
ui->redLabel->setText(redString);
redDelta = value;
colorRed();
rgbaInsertion();
sceneUpdater();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QImage>
#include <QFileDialog>
#include <string>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_importButton_clicked();
void on_quitButton_clicked();
void on_redSlider_valueChanged(int value);
private:
QGraphicsPixmapItem *showImage;
QGraphicsScene *scene;
QString filter;
QImage image;
bool importCancelled;
QStatusBar *statusBar;
uint numberOfBytes;
std::vector<uchar> rgba;
std::vector<uchar> rgbaReset;
int redDelta{0};
int greenDelta{0};
int blueDelta{0};
int opacityDelta{0};
void importImage();
void scaleImage();
void displayImage();
void rgbaExtraction();
void rgbaInsertion();
void sceneUpdater();
void colorRed(); // Implemented in color.cpp
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
color.cpp
#include <mainwindow.h>
void MainWindow::colorRed()
{
for (uint i{0}; i < rgba.size()*sizeof (rgba[i]);i+=4) {
if(rgbaReset[i] + static_cast<uchar>(redDelta)>=255){
rgba[i] = 255;
}
else {
rgba[i] = rgbaReset[i];// + static_cast<uchar>(redDelta);
}
}
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The problem is in scaleImage(), because scaledToHeight() returns another image format. You may omit the scale operation, or convert the returned image to Format_RGBA8888:
void MainWindow::scaleImage()
{
if (image.isNull()){
return;
}
else {
image = image.scaledToHeight(ui->view->height(), Qt::TransformationMode::SmoothTransformation)
.convertToFormat(QImage::Format_RGBA8888);
}
}
My recomendation is to add some instrumentation after each image manipulation to check that it has the expected format:
qDebug() << Q_FUNC_INFO << "image format:" << image.format();

QWebEngine download restart after a reboot

I did an application to download softwares. It's works well with QWebengine.
For the second version, I need to implement the restart of the download after the application is turned off.
My goal is to get possible to restart the same download at the same status after a reboot.
Is it possible?
How to save the status of the current download in a file with WebEngineDownloadItem ?
Thank you for your help
This is how I did :
DownloaderWidget.hpp
#ifndef DOWNLOADERWIDGET_HPP
#define DOWNLOADERWIDGET_HPP
# include <QUrl>
# include <QApplication>
# include <QPushButton>
# include <QString>
# include <QWidget>
# include <QLabel>
# include <QVBoxLayout>
# include <QProgressBar>
# include "downloadermanager.hpp"
class DownloaderWidget : public QWidget
{
Q_OBJECT
public:
explicit DownloaderWidget(QWidget *parent = nullptr);
signals:
public slots:
void download(void);
void pause(void);
void resume(void);
private slots:
void progress(int percent);
private:
static QString const
URL;
QLabel *m_url;
QPushButton *m_start;
QPushButton *m_resume;
QPushButton *m_pause;
QProgressBar *m_status;
DownloaderManager *m_download_manager;
};
#endif // DOWNLOADERWIDGET_HPP
DownloaderManager.hpp
#ifndef DOWNLOADERMANAGER_HPP
#define DOWNLOADERMANAGER_HPP
# include <QUrl>
# include <QObject>
# include <QDebug>
# include <QNetworkAccessManager>
# include <QNetworkRequest>
# include <QNetworkReply>
# include <QFile>
# include <QByteArray>
# include <QStandardPaths>
class DownloaderManager : public QObject
{
Q_OBJECT
public:
explicit DownloaderManager(QObject *parent = nullptr);
signals:
void downloadComplete(void);
void progress(int const percentage);
public slots:
void download(QUrl const &url);
void pause();
void resume();
private slots:
void download(QNetworkRequest &request);
void finished();
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void error(QNetworkReply::NetworkError code);
private:
QNetworkAccessManager
*m_manager;
QNetworkRequest m_request;
QNetworkReply *m_reply;
QFile *m_file;
qint64 m_downloadSizeAtPause;
QString m_name;
QString get_file_name(QUrl const &url);
};
#endif // DOWNLOADERMANAGER_HPP
DownloaderWidget.cpp
#include "downloaderwidget.hpp"
QString const DownloaderWidget::URL = "My great URL";
DownloaderWidget::DownloaderWidget(QWidget *parent)
: QWidget(parent),
m_url(new QLabel(URL, this)),
m_start(new QPushButton("Start", this)),
m_resume(new QPushButton("Resume", this)),
m_pause(new QPushButton("Pause", this)),
m_status(new QProgressBar(this)),
m_download_manager(new DownloaderManager(this))
{
QVBoxLayout *main_layout = new QVBoxLayout(this);
m_status->setOrientation(Qt::Horizontal);
main_layout->addWidget(m_url);
main_layout->addWidget(m_status);
main_layout->addWidget(m_start);
main_layout->addWidget(m_pause);
main_layout->addWidget(m_resume);
QObject::connect(m_start, SIGNAL(clicked()), this, SLOT(download()));
QObject::connect(m_pause, SIGNAL(clicked()), this, SLOT(pause()));
QObject::connect(m_resume, SIGNAL(clicked()), this, SLOT(resume()));
QObject::connect(m_download_manager, SIGNAL(downloadComplete()), qApp, SLOT(quit()));
QObject::connect(m_download_manager, SIGNAL(progress(int)), this, SLOT(progress(int)));
this->m_pause->setEnabled(false);
this->m_resume->setEnabled(false);
}
void DownloaderWidget::download(void)
{
this->m_download_manager->download(QUrl(URL));
this->m_start->setEnabled(false);
this->m_pause->setEnabled(true);
}
void DownloaderWidget::pause()
{
this->m_download_manager->pause();
this->m_pause->setEnabled(false);
this->m_resume->setEnabled(true);
}
void DownloaderWidget::resume(void)
{
this->m_download_manager->resume();
this->m_pause->setEnabled(true);
this->m_resume->setEnabled(false);
}
void DownloaderWidget::progress(int percent)
{
this->m_status->setValue(percent);
}
DownloaderManager.cpp
#include "downloadermanager.hpp"
DownloaderManager::DownloaderManager(QObject *parent) :
QObject(parent),
m_manager(new QNetworkAccessManager(this)),
m_request(),
m_reply(nullptr),
m_file(nullptr),
m_downloadSizeAtPause(0),
m_name("")
{
}
QString DownloaderManager::get_file_name(QUrl const &url)
{
QStringList list = url.toString().split("/");
this->m_name = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/" + list[list.length() - 1];
return (this->m_name + ".download");
}
void DownloaderManager::download(QUrl const &url)
{
this->m_name = this->get_file_name(url);
qDebug() << "Download : file = " << this->m_name;
this->m_downloadSizeAtPause = 0;
this->m_request = QNetworkRequest(url);
this->m_file = new QFile(this->m_name);
this->m_file->open(QIODevice::ReadWrite | QIODevice::Append);
if (this->m_file->size() != 0)
this->resume();
else
this->download(this->m_request);
}
void DownloaderManager::pause(void)
{
qDebug() << "pause()";
if(this->m_reply == nullptr)
return;
QObject::disconnect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::disconnect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
QObject::disconnect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
this->m_reply->abort();
this->m_file->write(this->m_reply->readAll());
this->m_reply = nullptr;
}
void DownloaderManager::resume(void)
{
qDebug() << "resume()";
this->m_file->flush();
this->m_downloadSizeAtPause = this->m_file->size();
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(this->m_downloadSizeAtPause) + "-";
this->m_request.setRawHeader("Range",rangeHeaderValue);
this->download(this->m_request);
}
void DownloaderManager::download(QNetworkRequest &request)
{
qDebug() << "download( QNetworkRequest& request )";
this->m_reply = this->m_manager->get(request);
QObject::connect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
QObject::connect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
}
void DownloaderManager::finished(void)
{
qDebug() << "finihsed";
this->m_file->rename(this->m_name + ".download", this->m_name);
this->m_file->close();
this->m_file = nullptr;
this->m_reply = nullptr;
emit downloadComplete();
}
void DownloaderManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
qDebug() << "Download Progress: Received=" << this->m_downloadSizeAtPause + bytesReceived <<": Total=" << this->m_downloadSizeAtPause + bytesTotal;
this->m_file->write(this->m_reply->readAll());
int percentage =
static_cast<int>((this->m_downloadSizeAtPause + bytesReceived) * 100 ) / (this->m_downloadSizeAtPause + bytesTotal);
qDebug() << percentage;
emit progress(percentage);
}
void DownloaderManager::error(QNetworkReply::NetworkError code)
{
qDebug() << "Error:" <<code;
}
main.cpp
#include <QApplication>
#include "downloaderwidget.hpp"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
DownloaderWidget downloader;
downloader.show();
return (app.exec());
}
I hope this piece of code will help some one in the same case than me Thank you

Transfer serially into Arduino Uno, the text file read by Qt Creator

This is from my previous question of read the text line by line.
Based from #KubaOber answer, I can successfully read and display the content line by line in a certain time interval.
Then, I was trying to transmit the content of the text file serially into Arduino Uno using the source code available on the internet.
Here's the header code:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtSerialPort/QSerialPort>
#include <QSerialPortInfo>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
QSerialPort *arduino;
static const quint16 arduino_uno_vendor_id = 10755;
static const quint16 arduino_uno_product_id = 67;
QString arduino_port_name;
bool arduino_is_available;
QByteArray serialData;
QString serialBuffer;
void updateSpeedometer(QString);
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
Ui::Widget *ui;
private slots:
private:
};
#endif // WIDGET_H
and here's the main.cpp :
#include <QtWidgets>
#include <QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
#include "widget.h"
#include <QDebug>
bool arduino_is_available = false;
QString arduino_port_name = "";
QSerialPort *arduino = new QSerialPort;
QString serialBuffer = "";
static const quint16 arduino_uno_vendor_id = 10755;
static const quint16 arduino_uno_product_id = 67;
class PeriodicReader : public QObject {
Q_OBJECT
QTimer m_timer{this};
QFile m_file{this};
void readLine() {
if (m_file.atEnd()) {
m_timer.stop();
return;
}
QByteArray lineBaru(m_file.readLine());
emit newLine(lineBaru);
qDebug()<<lineBaru;
QString lineString(lineBaru);
qDebug()<<lineString << " converted to QString";
lineString.remove("\n");
qDebug()<<lineString;
lineString.remove(" ");
qDebug()<<lineString;
QRegExp rx("d(\\d+)");
QList<int> list;
int pos = 0;
while ((pos = rx.indexIn(lineString, pos)) != -1) {
list << rx.cap(1).toInt();
pos += rx.matchedLength();
}
qDebug()<<list;
int listi = list.at(0);
qDebug()<<"list[0] :"<<listi;// <<---THIS IS WHERE I CAN GET THE VALUE AFTER THE "d"
updateSpeedometer(lineString);
}
void updateSpeedometer(QString command)
{
if(arduino->isWritable())
{
command.remove(" ");
arduino->write(command.toStdString().c_str());
qDebug() << command.toStdString().c_str() << " is uploaded to Arduino";
}else{
qDebug()<<"Couldn't write to Serial !" ;
}
}
public:
explicit PeriodicReader(QObject * parent = {}) : QObject(parent) {
connect(&m_timer, &QTimer::timeout, this, &PeriodicReader::readLine);
}
void load(const QString & fileName) {
m_file.close(); // allow re-opening of the file
m_file.setFileName(fileName);
if (m_file.open(QFile::ReadOnly | QFile::Text)) {
readLine();
m_timer.start(1000); // <<<---------------HERE IS WHERE I WANT THE DELAY TO BE
}
}
Q_SIGNAL void newLine(const QByteArray &);
};
QString lineToString(QByteArray line)
{
while (line.endsWith('\n') || line.endsWith('\r'))
line.chop(1);
return QString::fromUtf8(line);
}
int main(int argc, char ** argv) {
qDebug()<<"Number of available ports :" <<QSerialPortInfo::availablePorts().length();
foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
qDebug()<<"Has Vendor ID:" << serialPortInfo.hasVendorIdentifier();
if(serialPortInfo.hasVendorIdentifier()){
qDebug()<<"Vendor ID:"<< serialPortInfo.vendorIdentifier();
}
qDebug()<<"Has Product ID:" << serialPortInfo.hasProductIdentifier();
if(serialPortInfo.hasProductIdentifier()){
qDebug()<<"Product ID:"<< serialPortInfo.productIdentifier();
}
}
foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
if(serialPortInfo.hasVendorIdentifier() && serialPortInfo.hasProductIdentifier()){
if(serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id){
if(serialPortInfo.productIdentifier() == arduino_uno_product_id){
arduino_port_name = serialPortInfo.portName();
arduino_is_available = true;
}
}
}
}
if(arduino_is_available){
//open and configure the serialport
arduino->setPortName(arduino_port_name);
arduino->open(QSerialPort::ReadWrite);
arduino->setBaudRate(QSerialPort::Baud9600);
arduino->setDataBits(QSerialPort::Data8);
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
arduino->setFlowControl(QSerialPort::NoFlowControl);
//QObject::connect(arduino,SIGNAL(readyRead()),this,SLOT(readSerial()));
}else{
//show error message
qDebug()<<" Port Error, Couldn't find the Arduino' !";
// QMessageBox::warning(this, "Port Error, Couldn't find the Arduino !");
}
QApplication app{argc, argv};
QWidget window;
QVBoxLayout layout{&window};
QPushButton load{"Load"};
QPlainTextEdit edit;
layout.addWidget(&load);
layout.addWidget(&edit);
window.show();
PeriodicReader reader;
QObject::connect(&load, &QPushButton::clicked, [&]{
auto name = QFileDialog::getOpenFileName(&window);
if (!name.isEmpty()) {
edit.clear(); // allow re-opening of the file
reader.load(name);
}
});
QObject::connect(&reader, &PeriodicReader::newLine, &edit,
[&](const QByteArray & line){ edit.appendPlainText(lineToString(line)); });
return app.exec();
}
#include "main.moc"
It is from the coding of "reading text line by line" I've asked months a go which I include the arduino serial connection coding as well and hey, it worked!
It reads the text line by line and when each line is displayed in textEdit, it also transmitted to Arduino Uno.
So my request is, instead of the delay between line by line is preset at 2 seconds, can the delay duration be controlled by the content of the text file?
Let say.. the first line content inside the text file is 's200 d300' , and the 's200' is processed by arduino to generate a frequency, meanwhile 'd300' is the delay interval in milliseconds before it reads the next line and generate another frequency signal.
So,how to make Qt recognise the 'd300' and use it as the delay value?
QString str = "asa24fsesfd300kslfv0";
QTextDocument document(str);
QTextCursor d = document.find("d");
qDebug()<<d.position();
QString s = str.mid(d.position()-1,6); // How many digits can be after << d >>
int count = 0;
for (int i = 1; i < s.size(); ++i) {
QString d = s.at(i);
if(d.isEmpty()){
break;
}else{
bool ok;
int k = d.toInt(&ok);
if(ok){
count++;
}else{
break;
}
}
}
QString result = str.mid(d.position(),count);
bool ok;
int result_int = result.toInt(&ok);
if(ok){
qDebug()<< result_int;
}
result 300

Multi-threading with Qt

I am building a simple GUI in Qt to carry out some Image Processing in OpenCV. I want to use multi-threading so that the GUI is responsive even if the processing becomes very intensive. To do this I am referring the chapter below to build my framework:
http://www.informit.com/articles/article.aspx?p=1405551&seqNum=3
To begin with, I have 2 push buttons, one to load the image and the other to process it.
I have 2 Labels, one to display the input image and one to display the processed image.
As of now, I am loading my input image using slot and signal mechanism in the main thread and I am creating a new thread for the image flip.
However, when I build my code, I get an error
Undefined symbols for architecture x86_64:
"FlipTransaction::FlipTransaction(int)", referenced from:
MainWindow::flipHorizontally() in mainwindow.o ld: symbol(s) not found for architecture x86_64
When I comment out the slot flipHorizontally(), my code builds fine and am able to load the image.
Thus my processing is not being carried out.
Below is my code. Any help is appreciated
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileDialog>
#include <QStatusBar>
// OpenCV Headers
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> // for cvtColor
// Multi-Threading Headers
#include <QThread>
#include <QMutex>
#include <QQueue>
#include <QWaitCondition>
namespace Ui {
class MainWindow;
}
class Transaction
{
public:
virtual ~Transaction() {}
virtual QImage apply(const cv::Mat source_image, cv::Mat dest_image) = 0;
virtual QString message() = 0;
};
class TransactionThread : public QThread
{
Q_OBJECT
public:
TransactionThread();
~TransactionThread();
void addTransaction(Transaction *transact);
void setImage(const QImage &image);
QImage image();
signals:
void transactionStarted(const QString &message);
void allTransactionsDone();
protected:
void run();
private:
QImage currentImage;
Transaction *EndTransaction;
QQueue<Transaction *> transactions;
QWaitCondition transactionAdded;
QMutex mutex;
cv::Mat source_image;
cv::Mat dest_image;
};
class FlipTransaction : public Transaction
{
public:
FlipTransaction(int orientation);
QImage apply(const cv::Mat source_image, cv::Mat dest_image);
QString message();
private:
int orientation;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void addTransaction(Transaction *transact);
void drawOut(QImage qimg);
private slots:
void on_pushButton_clicked();
public slots:
void flipHorizontally();
void allTransactionsDone();
private:
Ui::MainWindow *ui;
public:
TransactionThread thread;
cv::Mat source_image; // Input Image Variable
cv::Mat dest_image; // Output Image Variable
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
statusBar()->showMessage(tr("Ready"), 2000);
connect(&thread, SIGNAL(transactionStarted(const QString &)),
statusBar(), SLOT(showMessage(const QString &)));
connect(&thread, SIGNAL(allTransactionsDone()),
this, SLOT(allTransactionsDone()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::drawOut(QImage qimg)
{
// Display on Label
ui->outputLabel->setPixmap(QPixmap::fromImage(qimg));
// Resize the label to fit the image
ui->outputLabel->resize(ui->outputLabel->pixmap()->size());
}
void MainWindow::addTransaction(Transaction *transact)
{
MainWindow::thread.addTransaction(transact);
}
void MainWindow::on_pushButton_clicked()
{
QString filename = QFileDialog::getOpenFileName(this,
tr("Open Image"), ".",tr("Image Files (*.png *.jpg *.jpeg *.bmp *.gif)"));
// Read Image
source_image = cv::imread(filename.toAscii().data());
// Resize Image
cv::resize(source_image, source_image, cv::Size(128,128) , 0, 0);
// Change to RGB format
cv::cvtColor(source_image,source_image,CV_BGR2RGB);
// Convert to QImage
QImage qimg = QImage((const unsigned char*) source_image.data, source_image.cols, source_image.rows, QImage::Format_RGB888); // convert to QImage
// Display on Input Label
ui->inputLabel->setPixmap(QPixmap::fromImage(qimg));
// Resize the label to fit the image
ui->inputLabel->resize(ui->inputLabel->pixmap()->size());
}
void MainWindow::flipHorizontally()
{
MainWindow::thread.addTransaction(new FlipTransaction(int(1)));
}
void MainWindow::allTransactionsDone()
{
statusBar()->showMessage(tr("Ready"), 2000);
}
TransactionThread::TransactionThread()
{
start();
}
TransactionThread::~TransactionThread()
{
{
QMutexLocker locker(&mutex);
while(!transactions.isEmpty())
delete transactions.dequeue();
transactions.enqueue(EndTransaction);
transactionAdded.wakeOne();
}
wait();
}
void TransactionThread::addTransaction(Transaction *transact)
{
QMutexLocker locker(&mutex);
transactions.enqueue(transact);
transactionAdded.wakeOne();
}
void TransactionThread::setImage(const QImage &image)
{
QMutexLocker locker(&mutex);
currentImage = image;
}
QImage TransactionThread::image()
{
QMutexLocker locker(&mutex);
return currentImage;
}
void TransactionThread::run()
{
Transaction *transact = 0;
QImage oldImage;
forever {
{
QMutexLocker locker(&mutex);
if (transactions.isEmpty())
transactionAdded.wait(&mutex);
transact = transactions.dequeue();
if (transact == EndTransaction)
break;
oldImage = currentImage;
}
emit transactionStarted(transact->message());
QImage newImage = transact->apply(source_image, dest_image);
// QImage newImage = transact->apply(oldImage);
delete transact;
{
QMutexLocker locker(&mutex);
currentImage = newImage;
if (transactions.isEmpty())
emit allTransactionsDone();
}
}
}
QImage FlipTransaction::apply(const cv::Mat source_image, cv::Mat dest_image)
{
// Process Image
cv::flip(source_image, dest_image, orientation);
// Change to RGB format
cv::cvtColor(dest_image,dest_image,CV_BGR2RGB);
// Convert to QImage
QImage qimg = QImage((const unsigned char*) dest_image.data, dest_image.cols, dest_image.rows, QImage::Format_RGB888);
return qimg;
}
QString FlipTransaction::message()
{
if (orientation == 1) {
return QObject::tr("Flipping image horizontally...");
} else {
return QObject::tr("Flipping image vertically...");
}
}

Resources