Migrating from C to C++ (5)

IC-7410try

The colored boxes are the areas for waveform (mono) and waterfall of IC7410, and waveform (I and Q) and waterfall of Soft66LC4.

NewSound *mynewsound[2];
vector<NewSound*> newusblist;

int main(int argc, char *argv[])
{
	mynewsound[0] = new SoundIC7410{argv[1]};	/* IC-7410 */
	mynewsound[1] = new SoundSoft66{argv[2]};	/* Soft66LC4 */
	for(int i=0;i<2;i++) {
		newusblist.push_back(mynewsound[i]);
	}

	argc = 1;			/* just for the next line */
	Glib::RefPtr < Gtk::Application > app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

	Gtk::Window mywindow;
	Gtk::VBox   mybox;
	MyDrawingArea *aaa;

	mywindow.set_title("IC-7410 Rig Control Program (C++ version)");
	for(auto x : newusblist) {
		aaa = new MyDrawingArea(x);
		mybox.pack_start(*aaa, FALSE, FALSE, 0);
	}
	mywindow.add(mybox);
	mywindow.show_all();
	return app->run(mywindow);
}
class NewSound : public Gtk::Box {
public:
	virtual int waveform_nsamples () const = 0;
	virtual int waveform_nchannels() const = 0;
	virtual int waterfall_nfft    () const = 0;
	virtual int waterfall_ntime   () const = 0;
	virtual ~NewSound();
};

struct AlsaParams { // Advanced Linux Sound Architecture
	// ...
};

class SoundIC7410 : public NewSound, protected AlsaParams {
public:
	SoundIC7410();
	SoundIC7410(char *s);
	virtual ~SoundIC7410();
	int waveform_nsamples () const override {return  800;};
	int waveform_nchannels() const override {return    1;};
	int waterfall_nfft    () const override {return  512;};
	int waterfall_ntime   () const override {return  256;};
	// ...
public:
	char* sound_device = nullptr;
	// ...
};

class SoundSoft66 : public NewSound, protected AlsaParams {
public:
	SoundSoft66();
	SoundSoft66(char *s);
	virtual ~SoundSoft66();
	int waveform_nsamples () const override {return  600;};
	int waveform_nchannels() const override {return    2;};
	int waterfall_nfft    () const override {return  400;};
	int waterfall_ntime   () const override {return  300;};
	// ...
private:
	char* sound_device = nullptr;
	// ...
};
class MyDrawingArea : public Gtk::DrawingArea {
public:
	MyDrawingArea();
	MyDrawingArea(NewSound*);
	virtual ~MyDrawingArea();
	bool on_draw(const Cairo::RefPtr < Cairo::Context > &cr) override;
private:
	int count     {0};
	int nchannels {0};
	int nsamples  {0};
	int nfft      {0};
	int ntime     {0};
};
MyDrawingArea::MyDrawingArea(NewSound *x) : count {0} {
	nsamples  = x->waveform_nsamples ();
	nchannels = x->waveform_nchannels();
	nfft      = x->waterfall_nfft    ();
	ntime     = x->waterfall_ntime   ();

	set_size_request(max(nsamples, nfft), 100*nchannels + ntime + 30);
}

MyDrawingArea::~MyDrawingArea() {
	// TODO Auto-generated destructor stub
}

bool MyDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> &cr) {
	cr->save();
		for(int iy=0;iy<nchannels;iy++) {
			cr->set_source_rgba(0.1*nchannels, 0.5*iy, 0.5, 1.0);
			cr->rectangle( 10, 10+100*iy,  nsamples - 20,  80);
			cr->fill();
			cr->stroke();
		}
	cr->restore();

	cr->save();
			cr->set_source_rgba(0.4, 0.1*(n%10), 0.5, 1.0);
			cr->rectangle(10, 10+100*nchannels, nfft, ntime);
			cr->fill();
			cr->stroke();
	cr->restore();

	return true;
}

I am not sure if I am going to the right direction or not.

ATOM

atom
https://atom.io/

A hackable text editor for the 21st Century

I have been using vi for many many years, but maybe I should try a new one.

Migrating from C to C++ (4)

So it is going to be something like this:

int main(int argc, char *argv[])
{
    NewSound *mynewsound[2];
    vector<NewSound*> newusblist;

    mynewsound[0] = new SoundIC7410{argv[1]};	/* IC-7410 */
    mynewsound[1] = new SoundSoft66{argv[2]};	/* Soft66LC4 */
    for(int i=0;i<2;i++) {
        newusblist.push_back(mynewsound[i]);    /* better ways to do this? */
    }
    // ...
}
class NewSound : public Gtk::Box {
public:
    virtual void draw_waveform (Gtk::Box&) = 0; // a pure virtual function
    virtual void draw_waterfall(Gtk::Box&) = 0; // a pure virtual function
    virtual ~NewSound();
};

struct AlsaParams { // Advanced Linux Sound Architecture
    // ...
};

class SoundIC7410 : public NewSound, protected AlsaParams {
public:
    SoundIC7410();
    SoundIC7410(char *s);
    virtual ~SoundIC7410();
    void draw_waveform (Gtk::Box&) override;
    void draw_waterfall(Gtk::Box&) override;
    // ...
private:
    char* sound_device = nullptr;
    // ...
};

class SoundSoft66 : public NewSound, protected AlsaParams {
    // ...
};
void f(vector<NewSound*> newusblist&) {
    // Gtk::Box mybox;
    for(auto x : newusblist) {
        x->draw_waveform (mybox);
        x->draw_waterfall(mybox);
    }
}

void SoundIC7410::draw_waveform(Gtk::Box& box) const{
    // Gtk::DrawingArea ttt;
    // ttt.set_size_request(200,200);
    box.pack_start(ttt, FALSE, FALSE, 0);
}

Migrating from C to C++ (3)

howtoprogram

https://www.youtube.com/watch?v=tj8BoOYvo00

How to Code Like Bjarne Stroustrup? I don’t know, but, one thing to do is read Bjarne Stroustrup’s C++ Style and Technique FAQ carefully.

One example from the qeustion, Why do my compiles take so long? is:

class Shape {
public:		// interface to users of Shapes
	virtual void draw() const = 0;
	virtual void rotate(int degrees) = 0;
	virtual Point center() const = 0;
	// ...
	// no data
};

struct Common {
	Color col;
	// ...
};

class Circle : public Shape, protected Common {
public:	
	void draw() const;
	void rotate(int) { } // nothing to do to rotate a circle!
	Point center() const { return cent; }
	// ...
protected:
	Point cent;
	int radius;
};

class Triangle : public Shape, protected Common {
public:	
	void draw() const;
	void rotate(int);
	Point center() const;
	// ...
protected:
	Point a, b, c;
};	

This code is given as an answer to the related question:

But what if there really is some information that is common to all derived classes (or simply to several derived classes)?

He says: Simply make that information a class and derive the implementation classes from that also.

So in my case, it could be something like this:

class Sound { // an abstract class
public:
	virtual void draw_waveform () const = 0; // a pure virtual function
	virtual void draw_waterfall() const = 0; // a pure virtual function
	// ...
};

struct AlsaParams { // Advanced Linux Sound Architecture
	snd_pcm_uframes_t   buffer_size = 0;
	snd_pcm_uframes_t   period_size = 0;
	snd_pcm_sframes_t   avail = 0;
	snd_pcm_sframes_t   frames_actually_read = 0;
	snd_pcm_t           *handle = nullptr;
	snd_pcm_hw_params_t *hwparams = nullptr;
	snd_pcm_sw_params_t *swparams = nullptr;
	snd_async_handler_t *ahandler = nullptr;
	// ...
};

class SoundIC7410 : public Sound, protected AlsaParams {
public:	
	void draw_waveform () const;
	void draw_waterfall() const;
	// ...
private:
	int nchannels = 1;
	// ...
};

class SoundSoft66 : public Sound, protected AlsaParams {
public:	
	void draw_waveform () const;
	void draw_waterfall() const;
	// ...
private:
	int nchannels = 2;
	// ...
};

void f(const vector<Sound*>& s) {
	for(auto x : s) {
		x->draw_waveform ();
		x->draw_waterfall();
	}

Selection_025

Migrating from C to C++ (2)

fiveprogramminglang

https://www.youtube.com/watch?v=NvWTnIoQZj4

The C++ Programming Language (4th Edition) is a very good book, but understanding the concepts behind is not trivial and still is very difficult for me.

There is a short paper, Why C++ is not just an Object-Oriented Programming Language, in which he says that:

A language or technique is object-oriented if and only if it directly supports:

[1] Abstraction – providing some form of classes and objects.

[2] Inheritance – providing the ability to build new abstractions out of existing ones.

[3] Run-time polymorphism – providing some form of run-time binding.

class Usbsound_mono: public Usbsound {
public:
	Usbsound_mono();
	Usbsound_mono(char *s);
	virtual ~Usbsound_mono();
};
class Usbsound_iq: public Usbsound {
public:
	Usbsound_iq();
	Usbsound_iq(char *s);
	virtual ~Usbsound_iq();
};

Usbsound *mydevice[2]; /* I have two usb sound devices */
mydevice[0] = new Usbsound_mono{argv[1]}; /* this is IC-7410 */
mydevice[1] = new Usbsound_iq  {argv[2]}; /* this is Soft66LC4 */

This is just a starting point, I need to add many more features, such as pure virtual functions, abstract base classes, etc.

Passing arguments to a base-class constructor

IC7410faq

This is another FAQ, which I did not know.

% sprigmm hw:2,0 hw:1,0

Here the device names hw:2,0 and hw:1,0 are for IC-7410 and Soft66LC4, respectively.

	Usbsound *mydevice[2]; /* I have two usb sound devices */
	mydevice[0] = new Usbsound_mono{argv[1]}; /* this is IC-7410 */
	mydevice[1] = new Usbsound_iq  {argv[2]}; /* this is Soft66LC4 */

The two usb sound devices behave similarly and and they are both derived from a base-class Usbsound.

class Usbsound_mono: public Usbsound {
public:
	Usbsound_mono();
	Usbsound_mono(char *s);
	virtual ~Usbsound_mono();
};
class Usbsound_iq: public Usbsound {
public:
	Usbsound_iq();
	Usbsound_iq(char *s);
	virtual ~Usbsound_iq();
};

The device name for each sound device, eg. hw:2,0, must be passed to the base-class constructor, Usbsound::Usbsound, for initialization.

Usbsound_mono::Usbsound_mono(char* s) : Usbsound(s) {
	rate        = 32000;
	buffer_size = 32 * 1024;
	period_size =  8 * 1024;
}
Usbsound_iq::Usbsound_iq(char* s) : Usbsound(s)  {
	rate        = 48000;
	buffer_size = 96 * 1024;
	period_size =  2 * 1024;
}

The bit rate and other related parameters are specific for each device.