Accounting, yet another language?

922px-Pacioli

https://en.wikipedia.org/wiki/Accounting

It is said that accounting is the language of business. I believe that understanding of a specific part of our universe (or world, or society), at least to some extent, requires mastering a particular language used in that field.

You can not fully enjoy works of Shakespeare if you do not understand (early modern?) English, and you can not fully enjoy your ham life if you do not QSO on CW.

Mutex (3)

Selection_084

Sound::asound_read() writes audio samples into audio_signal[] by incrementing the write pointer signal_end, while MyDrawingAreaS::on_draw() also modifies the write pointer when it shifts down the bulk of data in audio_signal[].

Mutex (2)

Moved the place to start a thread for data capture.

void thread_for_read(Sound* s) {
	while(1) {
		usleep(200000); /* 0.2sec */
		mtx.lock();
		s->loop_count = s->asound_read();
		mtx.unlock();
	}
}

int Sound::asound_init() {
	// lots of stuff for sound device initialize
	std::thread t1{bind(thread_for_read, this)};
	t1.detach();
	return 0;
}
% cat log.txt
SoundIC7410::SoundIC7410()  sound_device = hw:2,0, channels = 1, rate = 32000
Sound::asound_init(): starting a thread.
SoundSoft66::SoundSoft66()  sound_device = hw:1,0, channels = 2, rate = 48000
thread_for_read(): id = 139684893808384 <- this line is for IC7410.
Sound::asound_init(): starting a thread.
thread_for_read(): id = 139684877022976 <- this line is for Soft66.

The output lines are interleaved as usual.

% ps aux -L | egrep '(Sprig|USER)'
USER       PID   LWP %CPU NLWP %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user1     5581  5581 52.3    5  0.6 474400 52532 pts/1    Sl+  10:36   1:48 ./Sprigmm025 hw:2,0 hw:1,0 /dev/ttyUSB1
user1     5581  5585  0.0    5  0.6 474400 52532 pts/1    Sl+  10:36   0:00 ./Sprigmm025 hw:2,0 hw:1,0 /dev/ttyUSB1
user1     5581  5586  0.0    5  0.6 474400 52532 pts/1    Sl+  10:36   0:00 ./Sprigmm025 hw:2,0 hw:1,0 /dev/ttyUSB1
user1     5581  5587  0.0    5  0.6 474400 52532 pts/1    Sl+  10:36   0:00 ./Sprigmm025 hw:2,0 hw:1,0 /dev/ttyUSB1
user1     5581  5588  0.0    5  0.6 474400 52532 pts/1    Sl+  10:36   0:00 ./Sprigmm025 hw:2,0 hw:1,0 /dev/ttyUSB1

Mutex

A mutex is an object used for controlling access in a multi-threaded system.

#include <mutex>
std::mutex mtx; /* global */

void thread_test(Sound* s) {
	while(1) {
		usleep(200000); /* 0.2sec */
		mtx.lock();
		s->loop_count = s->asound_read(); /* write pointer goes forward */
		mtx.unlock();
	}
}

bool MyDrawingAreaS::on_draw(const Cairo::RefPtr<Cairo::Context> &cr) {
	if(s->loop_count) {
		while(s->signal_end - s->signal_start >= nfft*channels) {
			mtx.lock();
			s->asound_fftcopy(); /* write pointer sometimes goes back */
			mtx.unlock();
//
}
% ag locked log.txt | tail
58033:AAA locked in thread_test();
58037:BBB locked in on_draw();
58038:BBB locked in on_draw();
58039:BBB locked in on_draw();
58040:BBB locked in on_draw();
58041:BBB locked in on_draw();
58042:BBB locked in on_draw();
58043:BBB locked in on_draw();
58044:AAA locked in thread_test();
58046:BBB locked in on_draw();
58047:BBB locked in on_draw();

% ag AAA | wc; ag BBB | wc                          
   4284   17136  183477
  40219  160876 1561654

The lines AAA and BBB should appear 5 (=1/0.2) times per second, and 46.9 (=48000/1024) times per second, respectively. Note that 40219/4284 (= 9.39) is close to 46.9/5 (=9.37).

Threads in C++11 (3)

void thread_test(Sound* s) {
	while(1) {
		usleep(200000); /* 0.2sec */
		s->loop_count = s->asound_read();
	}
}

So the function asound_read() is called 5 times per second. Since the function returns the number of blocks read, each containing 4k samples, the average value of loop_count should be 2.34 (= 0.2*(48000/4k)).

% ag --no-numbers loop_count log.txt | sort | uniq -c
      3 loop_count = 0
   2282 loop_count = 2
    992 loop_count = 3

After a short run of the program, the average value obtained is 2.30 (= (3*0+2282*2+992*3)/(3+2282+992)), and no -EPIPE error (overrun for capture) was observed during the run.

Threads in C++11 (2)

Selection_082

Now sound capture is from another thread.

void thread_test(Sound* s) {
	while(1) {
		usleep(100000);
		s->loop_count = s->asound_read();
	}
}

MyDrawingAreaS::MyDrawingAreaS(Sound* ss) : s {ss} {
	thread t1{bind(thread_test, s)};
	t1.detach();
}

This is quite a dirty hack, but it seems to work. Note that the waveforms looks funny because of the inappropriate setting of the input level.

_set_near

I knew that before, but have forgotten.

SoundIC7410::SoundIC7410()  sound_device = hw:2,0, channels = 1, rate = 32000, buffer_size = 131072, period_size = 4096

snd_pcm_hw_params_set_buffer_size_near: buffer_size_org = 131072 , buffer_size = 131072
snd_pcm_hw_params_set_period_size_near: period_size_org = 4096 , period_size = 4096

This is OK, but:

SoundSoft66::SoundSoft66()  sound_device = hw:1,0, channels = 2, rate = 48000, buffer_size = 32768, period_size = 6144

snd_pcm_hw_params_set_buffer_size_near: buffer_size_org = 32768 , buffer_size = 16384
snd_pcm_hw_params_set_period_size_near: period_size_org = 6144 , period_size = 8192

So this is the cause of capture overrun (-EPIPE errors) with Soft66LC4 occurring with some set of parameters. They are not exactly set, but with other part of the program, they are assumed to be the original intended values.

IC-7410 Rig Control Program (C++ version), build=0815a_081a

Many CW signals on the band last night. A contest was going on?

The Silver Searcher

user1@PC1: ~-Downloads-alsa-utils-1.0.29_078

The Silver Serarcher is a code searching tool, something like grep or ack.

Looks nice? I hope this tool will help solve my problem that the sound system (ALSA) does not or only sometimes recover from -EPIPE errors (overrun for capture).