using threads to eliminate a never ending loop
Hi guys,
I have a program in Qt Creator which outputs a sine wave with the click of a pushButton. However, due to a never ending while loop in my pushButton function, the application freezes when I click the pushButton. So I am using threads for my function and ending the while loop by eliminating the thread with the click of another pushButton(pushButton2).
I build my code with no errors. however, when I run it, the pushButton does not generate a sine wave and I get the following message:
@QMetaObject::connectSlotsByName: No matching signal for on_write_loop(snd_pcm_t*,signed short*,snd_pcm_channel_area_t*)@
Any help would be greatly appreciated.
My code snippets are below:
wave.cpp:
Code:
void wave::on_write_loop(snd_pcm_t *handles, signed short *samples , snd_pcm_channel_area_t *areas)
{
double freq = ui->frequency->text().toDouble();
double ampl = ui->amplitude->text().toDouble();
double phase = 0;
signed short *ptr;
int err, cptr;
while (1) {
generate_sine(0, period_size, &phase, freq, ampl);
ptr = samples;
cptr = period_size;
while (cptr > 0) {
err = snd_pcm_writei(hspdif, ptr, cptr);
if (err == -EAGAIN)
continue;
if (err < 0) {
if (xrun_recovery(hspdif, err) < 0) {
printf("Write error: %s ", snd_strerror(err));
exit(EXIT_FAILURE);
}
break; /* skip one period */
}
ptr += err * channels;
cptr -= err;
}
}
}
ui(new Ui::wave)
{
ui->setupUi(this);
//setup();
mThread = new MyThread(this);
connect(mThread, SIGNAL(write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)), this, SLOT(on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)));
}
wave::~wave()
{
delete ui;
}
void wave::on_pushButton_clicked()
{
//Generate
mThread->start();
}
void wave::on_pushButton_2_clicked()
{
//Terminate
mThread->Stop = true;
}
wave.h:
Code:
#ifndef WAVE_H
#define WAVE_H
#include "ui_wave.h"
#include <alsa/asoundlib.h>
#include <QMainWindow>
#include <QObject>
#include "mythread.h"
namespace Ui {
class wave;
}
{
Q_OBJECT
public:
explicit wave
(QWidget *parent
= 0);
~wave();
MyThread *mThread;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void setup();
private:
Ui::wave *ui;
public slots:
void on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*);
;
#endif // WAVE_H
MyThread.cpp:
Code:
void MyThread::run()
{
mutex.lock();
if (this->Stop)
mutex.unlock();
const char *device = "plughw:0,0";
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);
int err = snd_output_stdio_attach(&output, stdout, 0);
printf( "snd_output_stdio_attach err=%d\n", err);
err = snd_pcm_open(&hspdif, device, SND_PCM_STREAM_PLAYBACK, 0);
printf( "snd_pcm_open err=%d\n", err);
err = set_hwparams(hspdif, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
printf( "set_hwparams err=%d\n", err);
err = set_swparams(hspdif, swparams);
printf( "set_swparams err=%d\n", err);
samples = new signed short [period_size * channels * snd_pcm_format_physical_width(format)];
printf( "samples array_size=%d\n", int( period_size * channels * snd_pcm_format_physical_width(format)) );
areas = new snd_pcm_channel_area_t [channels];
printf( "areas channels=%d\n", channels);
for (unsigned int chn = 0; chn < channels; chn++) {
areas[chn].addr = samples;
areas[chn].first = chn * snd_pcm_format_physical_width(format);
areas[chn].step = channels * snd_pcm_format_physical_width(format);
}
emit write_loop(hspdif, samples, areas);
}
MyThread.h:
Code:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <alsa/asoundlib.h>
#include <QThread>
{
Q_OBJECT
public:
explicit MyThread
(QObject *parent
= 0);
void run();
bool Stop;
signals:
void write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*);
public slots:
};
#endif // MYTHREAD_H
Re: using threads to eliminate a never ending loop
Your source is a bit complicated...
You use QThread in a stange way.
Try this :
- Put the QThread::run() content in your wave constructor.
- Remove your class MyThread and any reference to QThread
- In your UI class add :
Code:
signals:
void startWave(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*);
private:
.
Add the following code your constructor :
Code:
thread.start();
Wave *wave = new Wave();
wave->moveToThread(thread);
connect(this, SIGNAL(startWave(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)), wave, SLOT(on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)));
And emit your signal when you want to start playing.
That should work without subclassing QThread.
Code not tested i have to leave fast.
Good luck
Re: using threads to eliminate a never ending loop
Quote:
Originally Posted by
nix
Your source is a bit complicated...
You use QThread in a stange way.
Try this :
- Put the QThread::run() content in your wave constructor.
- Remove your class MyThread and any reference to QThread
- In your UI class add :
Code:
signals:
void startWave(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*);
private:
.
Add the following code your constructor :
Code:
thread.start();
Wave *wave = new Wave();
wave->moveToThread(thread);
connect(this, SIGNAL(startWave(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)), wave, SLOT(on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)));
And emit your signal when you want to start playing.
That should work without subclassing QThread.
Code not tested i have to leave fast.
Good luck
Hey thanks alot. I did as you said and I'm running into the error:
error: request for member ‘start’ in ‘((wave*)this)->wave::thread’, which is of non-class type ‘QThread*’
Re: using threads to eliminate a never ending loop
I made a mistake in the code I give you try of course.
Re: using threads to eliminate a never ending loop
Quote:
Originally Posted by
nix
I made a mistake in the code I give you try
of course.
I am now getting this error:
Code:
QMetaObject::connectSlotsByName: No matching
signal for on_write_loop
(snd_pcm_t
*,
signed short*,snd_pcm_channel_area_t
*) Wave: pcm_params.c:2286: snd_pcm_hw_refine: Assertion `pcm && params' failed.
The program has unexpectedly finished.
also, I think you mean:
Code:
thread->start();
wave *Wave = new wave();
Wave->moveToThread(thread);
connect(this, SIGNAL(startWave(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)), Wave, SLOT(on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)));
Added after 5 minutes:
Quote:
Originally Posted by
duma
I am now getting this error:
Code:
QMetaObject::connectSlotsByName: No matching
signal for on_write_loop
(snd_pcm_t
*,
signed short*,snd_pcm_channel_area_t
*) Wave: pcm_params.c:2286: snd_pcm_hw_refine: Assertion `pcm && params' failed.
The program has unexpectedly finished.
also, I think you mean:
Code:
thread->start();
wave *Wave = new wave();
Wave->moveToThread(thread);
connect(this, SIGNAL(startWave(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)), Wave, SLOT(on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)));
Got rid of the first error:QMetaObject::connectSlotsByName: No matching signal for on_write_loop(snd_pcm_t*,signed short*,snd_pcm_channel_area_t*)
I changed on_write_loop to onWriteLoop. Because a function with format on_Foo_Bar look for a children named Foo and connect that slot to Foo’s Bar signal.
Now working on the second error. Any help would be appreciated. Thanks
Re: using threads to eliminate a never ending loop
My mistake.
The initialization of your pcm is on GUI thread and the use in the new thread that's bad, it should be the same. So you have to put the init in the Wave object and do it after the moveToThread.
So create a new slot used as on_write_loop or put the init in on_write_loop.
Re: using threads to eliminate a never ending loop
Quote:
Originally Posted by
nix
My mistake.
The initialization of your pcm is on GUI thread and the use in the new thread that's bad, it should be the same. So you have to put the init in the Wave object and do it after the moveToThread.
So create a new slot used as on_write_loop or put the init in on_write_loop.
I am getting the following errors:
../Wave/wave.cpp:310:9: error: expected unqualified-id before ‘->’ token
../Wave/wave.cpp:311:5: error: ‘Wave’ was not declared in this scope
../Wave/wave.cpp:311:16: error: expected primary-expression before ‘=’ token
../Wave/wave.cpp:311:22: error: expected type-specifier before ‘Wave’
../Wave/wave.cpp:311:22: error: expected ‘;’ before ‘Wave’
Also, I don't believe we can create a “wave†object inside of a “wave†and, and then move that second object into a thread. Excuse me if I am wrong.
Re: using threads to eliminate a never ending loop
Get rid of the thread completely, read the [wiki]Keeping the GUI Responsive[/wiki] article and employ the "step by step" pattern to your problem. Also consider making your code more "C++-ish" and less "C-ish".
Re: using threads to eliminate a never ending loop
Quote:
Originally Posted by
wysota
Get rid of the thread completely, read the [wiki]Keeping the GUI Responsive[/wiki] article and employ the "step by step" pattern to your problem. Also consider making your code more "C++-ish" and less "C-ish".
Thanks for the reply. this seems like exactly what i need. Although, if I apply the step by step method, a time limit will be placed on my event loop. But i want my loop to remain infinite so that it doesn't stop running and only stops when I click the STOP pushButton.
Re: using threads to eliminate a never ending loop
Read the article again, I think you didn't understand every part of it. If something is unclear, ask. In short, there is no time limit on your whole operation, only on a single iteration of it.
Re: using threads to eliminate a never ending loop
Quote:
Originally Posted by
wysota
Read the article again, I think you didn't understand every part of it. If something is unclear, ask. In short, there is no time limit on your whole operation, only on a single iteration of it.
Got it working. thanks alot :)