PDA

View Full Version : How to Route a Horizontal Slider Value to My Code?



keenanw
14th August 2013, 20:47
Hello, apologies for being a newb, and I hope my question makes sense. I am just starting to learn c++ and qt, and I'm working on a simple midi controlled oscillator with gui using the Synthesis Toolkit (mostly by copying and pasting code). I've run into a snag and I was hoping someone could help me.

I have a (working) horizontal slider and the rest of the code is working too in another Qthread. So everything works, the slider displays, the oscillator makes sound and accepts midi messages. The problem is that I want to work the value of the slider into the code, and I don't know how to do that. The applicable parts of the code are gain.h and gain.cpp, which contain the slider code, and also sine.cpp, which I want to somehow make use of gain.h/gain.cpp. Here is the code, which again I copied and pasted from the internet to get a working slider:





#ifndef LCDRANGE_H
#define LCDRANGE_H

#include <QWidget>

class QSlider;

class Gain : public QWidget
{
Q_OBJECT

public:
Gain(QWidget *parent = 0);

int value() const;

public slots:
void setValue(int value);

signals:
void valueChanged(int newValue);

private:
QSlider *slider;
};

#endif



And here is gain.cpp:




#include <QSlider>
#include <QVBoxLayout>
#include "gain.h"

Gain::Gain(QWidget *parent)
: QWidget(parent)
{

slider = new QSlider(Qt::Horizontal);
slider->setRange(1, 100);
slider->setValue(50);

connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));


QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(slider);
setLayout(layout);
}

int Gain::value() const
{
return slider->value();
}

void Gain::setValue(int value)
{
slider->setValue(value);

}



Now how to route it to my other code? I specifically want to take the value of the horizontal slider, convert it to a value between 0 and 1, and multiply the value of my output so that it functions as a volume control for the oscillator. Every attempt I have made so far to add any reference to the horizontal slider in my oscillator code results in the code not compiling, the gui not displaying, the oscillator making no sound, or an error about "must create application before qpaint" something-or-other.

Thanks in advance for your time and help.

anda_skoa
14th August 2013, 21:03
hard to tell without knowing how you instantiate Gain and how you tried to connect it.

Btw, if you want to convert the value to be in the floating point range of 0 to 1 I would do that right there in Gain where you have access to the slider's range.
I.e. Gain::value(), setValue() and valueChanged() would all deal with the 0..1 range, which they then map to the actual range of the slider.

This allows you to change the "precision" at any time just by changing the slider's range.

Cheers,
_

keenanw
14th August 2013, 21:22
Thanks for the reply.

Well, for instance, in sine.cpp I tried this:




int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void *dataPointer )
{
Gain *volume = new volume;

SineWave *sine = (SineWave *) dataPointer;
register StkFloat *samples = (StkFloat *) outputBuffer;
for ( unsigned int i=0; i<nBufferFrames; i++ )
*samples++ = (sine->tick() * vel) * volume->valueChanged() / 100;

return 0;
}


This results in a number of errors including "no matching function for call to 'Gain::valueChanged()'" and "cannot convert 'int*' to 'gain*' in initialization". So I'm asking a very general question. What is a good way to instantiate Gain in the first place in any c++ code? Any ideas or links to examples? I can't seem to find anything useful about this on the internet, probably because I don't know enough to google the right questions.

ChrisW67
14th August 2013, 23:21
The "no matching function" error arises because valueChanged() is a signal and its generated code is declared in the protected section of the class. If you want the value from the slider object directly then you want the value() function, not the signal indicating it has changed.

I assume that the "cannot convert 'int*' to 'gain*' in initialization" relates to this line:


Gain *volume = new volume;

The LHS of this is type "Gain*". Since there's no class called "volume" the compiler has assumed an int so the RHS is type "int*". It's not entirely clear what you are trying to achieve here with this circular reference. If, as I suspect, you intended to create a new Gain object:


Gain *volume = new Gain;

then, had you succeeded, you would have always had value() == 50 from a slider that the user neither saw nor interacted with.

In a normal Qt program you would have a UI built containing widgets like your slider, ideally quite separate from the code that actually does substantial stuff in response. You can use Designer or hand code that UI. You would connect() the valueChanged() signal of your slider to a slot that reacts immediately to the changed value, for example pushing a new volume figure into your generator code. Assuming the tick() routine is part of the code you have pushed to another thread you could put the receiving slot in that QObject and store the current volume figure as a member variable in the generator thread.

Unless you want to do something like anda_skoa suggests to get a floating point or logarithmic slider then it strikes me that your Gain class could simply be a QSlider subclass, something like:


class Gain: public QSlider
{
Q_OBJECT
public:
explicit Gain(QWidget *p = 0): QSlider(Qt::Horizontal, p) {
setRange(1, 100);
setValue(50);
}
};

Do you want to allow a zero volume?

keenanw
15th August 2013, 02:51
Yeah, I really meant




Gain *volume = new Gain;



I'll look into implementing the gui with Qt Designer, since I'm still having no luck. Thanks.