Do not copy and paste (2)

class Sound : public AlsaParams {
public:
//	virtual int asound_fftcopy() = 0;
	int asound_fftcopy(); /* not a virtual function */
};

int Sound::asound_fftcopy() {
	/* copy into FFT input buffer */
	if(signal_end - signal_start >= nfft*channels) { /* this should always be true */
		auto p = signal_start;
		switch (channels) {
		case 1:
			for (int i = 0; i < nfft; i++) {
				in[i][0] = *p++ * audio_window[i];
				in[i][1] = 0.0; /* no imaginary part */
			}
			break;
		case 2:
			for (int i = 0; i < nfft; i++) {
				in[i][1] = *p++ * audio_window[i]; /* reverse I and Q */
				in[i][0] = *p++ * audio_window[i]; /* reverse I and Q */
			}
			break;
		default:
			exit(1);
		}
		return 0;
	} else { /* should never happen */
		cout << "Sound::asound_fftcopy((): error " << endl;
		return 1;
	}
}

This is slightly better, but using switch statements is not very recommended.

Do not copy and paste

Sometimes you are tempted to copy and paste some of your code.

class Sound : public AlsaParams {
public:
	virtual int asound_fftcopy () = 0;
//
};

int SoundIC7410::asound_fftcopy() {
	/* copy into FFT input buffer */
	if(signal_end - signal_start >= nfft*channels) { /* this should always be true */
		auto p = signal_start;
		for (int i = 0; i < nfft; i++) {
			in[i][0] = *p++ * audio_window[i];
			in[i][1] = 0.0; /* no imaginary part */
		}
		return 0;
	} else { /* should never happen */
		cout << "SoundIC7410::asound_fftcopy((): error " << endl;
		return 1;
	}
}

int SoundSoft66::asound_fftcopy() {
	/* copy into FFT input buffer */
	if(signal_end - signal_start >= nfft*channels) { /* this should always be true */
		auto p = signal_start;
		for (int i = 0; i < nfft; i++) {
			in[i][1] = *p++ * audio_window[i]; /* invert I and Q signals */
			in[i][0] = *p++ * audio_window[i]; /* invert I and Q signals */
		}
		return 0;
	} else { /* should never happen */
		cout << "SoundSoft66::asound_fftcopy((): error " << endl;
		return 1;
	}
}

But, it is almost always a bad idea to do so. So in this particular case, what should I do?

Note that I am using complex one-dimensional DFTs for both cases so that there is more room for refactoring.

cw_decode

Is this decodable?

It works, but (2)

Gnuplot_067

This is to show how the pointers move in the buffer.

	buffer_size =  32   * 1024;
	period_size =   5.5 * 1024; /* intentionally odd number */
	nfft        =   2   * 1024;

	double *audio_signal {nullptr};
	double *signal_start {nullptr};  /* valid data in [start,end) */
	double *signal_end   {nullptr};

	audio_signal = new double [large_enough];
	signal_start = audio_signal;
	signal_end   = audio_signal;

	for (int i = 0; i < period_size; i++) {
		*signal_end++ = samples[i]; /* get new set of samples */
	}

	while(s->signal_end - s->signal_start >= nfft) {
		auto p = signal_start;
		for (int i = 0; i < nfft; i++) {
			in_real[i] = *p++ * audio_window[i]; /* copy into FFT buffer */
		}
		fftw_execute(s->plan);
		/* update waterfall, etc. */
		signal_start += nfft/2; /* shift the FFT window for half the FFT size */
	}

	/* move a bulk of samples not used for FFT to the top of the buffer */

	auto p = s->audio_signal;
	auto q = s->signal_start;
	while(q < s->signal_end) {
		*p++ = *q++;
	}
	s->signal_start = s->audio_signal;
	s->signal_end   = p;

It seems that the buffer operation is stable.

Gnuplot_068

W1AW Code Practice Files

Selection_062

I am still enjoying W1AW code practice files with my iPod. Here is how I download, say, all the 40 wpm files.

% wget -r -l1 --no-parent -nH -nd -w 10 --random-wait -A.mp3 http://www.arrl.org/40-wpm-code-archive

Timeout intervals revisited

Gnuplot_058

Measured timeout intervals using std::chrono.

bool MyDrawingAreaS::on_timeout() {
	current = chrono::system_clock::now();
	auto diff1 = current - start;
	auto diff2 = current - current_b4;
	current_b4 = current;
	cout << "MyDrawingAreaS::on_timeout(): elapsed time = " << chrono::duration_cast<std::chrono::milliseconds>(diff1).count() 
             << " msec (delta = " << chrono::duration_cast<std::chrono::milliseconds>(diff2).count() << " msec),  count = "
             << count << ", nch = " << nch << endl;
% grep timer_value log.txt 
SoundIC7410::SoundIC7410(): timer_value = 125

% grep "MyDrawingAreaS::on_timeout(): elapsed time" log.txt | head -1 
MyDrawingAreaS::on_timeout(): elapsed time = 147 msec (delta = 147 msec),  count = 2, nch = 1

% grep "MyDrawingAreaS::on_timeout(): elapsed time" log.txt | awk '{print $9}' > on_timeout.txt

% gnuplot
> plot "on_timeout.txt"

% R
> x<-read.csv("on_timeout.txt")
> hist(x[,1], col="orange", breaks=200)

R Graphics: Device 2 (ACTIVE)_059

I do not know if the result is reasonable or not. With a very simple program like this:

#include <iostream>
#include <chrono>

void f(int n)
{
// lots of stuff
}

int main()
{
	std::chrono::time_point<std::chrono::system_clock> start, end, endb4;
	start = std::chrono::system_clock::now();
	endb4 = start;
	int n=35;
	for(int i=0;i<1000;i++) {
		f(n);
		end = std::chrono::system_clock::now();
		std::chrono::duration<double> elapsed_seconds = end-endb4;
		endb4 = end;
		if(i>0) std::cout <<  elapsed_seconds.count() << endl;
	}
}

we have the following results.

Gnuplot_060

R Graphics: Device 2 (ACTIVE)_061

Please also see my previous articles: Timeout Intervals, and Timeout Intervals (2).

It works, but

Selection_057

Accessing an array with a pointer is not a very good idea.

	audio_signal = new double [buffer_size];
	signal_start = audio_signal;
	signal_end   = audio_signal; /* valid signal in [start, end) */
//
	for (int i = 0; i < (int) (period_size * channels); i++) {
		*signal_end++ = samples[i]; /* get new signal */
	}
//
	if(signal_end - signal_start >= nfft) { /* if there is enough for FFT */
		for (int i = 0; i < nfft; i++) {
			in_real[i] = *signal_start++ * audio_window[i];
		}
	}
//
	auto p = signal_start;
	auto q = audio_signal;
	while(p < signal_end) {
		*q++ = *p++;
	}

	signal_start = audio_signal;
	signal_end   = q;

The code is far from nice and simple.

Windows Something

capture_001_02082015_112420

I have an old PC with P55A-GD65 motherboard, and tried to see if my homepage is viewable.

Note that I only check my pages with Google Chrome, so whatever happens with Windows Something and its new browser, it is not my fault.