summaryrefslogtreecommitdiff
path: root/src/krunch.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/krunch.cxx')
-rw-r--r--src/krunch.cxx308
1 files changed, 308 insertions, 0 deletions
diff --git a/src/krunch.cxx b/src/krunch.cxx
new file mode 100644
index 0000000..a7adf8f
--- /dev/null
+++ b/src/krunch.cxx
@@ -0,0 +1,308 @@
+#include "krunch.h"
+#include "thrower.h"
+#include <valarray>
+#include <iostream>
+#include <iomanip>
+#include "refout.h" /* for class ref_to_krunch */
+#include "gui.h"
+//??? #include "iir_bp.h"
+#include "bad_thing.h"
+//?? #include "biquad.h"
+
+// forward reference:
+void dumpit_cout(const double rp, const double ip);
+
+// typical usage:
+//?? biquad butterworth({1., 2., 1.},
+//?? {1., -1.99911142347079540116, 0.99911181807963833634});
+
+//////////////////////////////////////////////////////////////////////
+// main entry point for krunch job
+//
+void* krunch(void* _arg){
+ using namespace std;
+ krunch_arg* arg((krunch_arg*) _arg);
+
+ int num_indic = arg->topwin->ndc8r.size();
+
+ thrower* toss = new thrower[num_indic];
+
+ thrower* flushy = new thrower;
+
+ for (int ii = 0; ii < num_indic; ii++) {
+ QMetaObject::Connection rslt = QObject::connect(
+ &toss[ii], SIGNAL(_newReading(double,double, double,double)),
+ arg->topwin->ndc8r[ii],
+ SLOT(setIndication(double,double, double,double)));
+
+ if (!rslt) {
+ cout << "Krunch: Failed to connect, column " << ii
+ << " rslt: " << rslt << endl;
+ exit(3);
+ }
+ }
+
+ {
+ QMetaObject::Connection rslt = QObject::connect( flushy, SIGNAL(_flush()),
+ arg->topwin, SLOT(flush()) );
+
+ if (!rslt) {
+ cout << "Krunch: Failed to connect flush: "
+ << rslt << endl;
+ exit(3);
+ }
+ }
+
+ alsa_pcm* pcm = arg->pcm;
+ int nframe = arg->setup->nframe;
+
+ int left_idx = 0;
+ int right_idx = 1;
+
+/// Kludge test: left_idx = 10; right_idx = 11;
+// Be careful to index outside array boundaries:
+ int topchan = pcm->nchan - 1;
+ if (left_idx > topchan) left_idx = topchan;
+ if (right_idx > topchan) right_idx = topchan;
+
+#if 0
+ if (snd_pcm_state(arg->otherpcm->phndl) != SND_PCM_STATE_RUNNING) {
+ cout << "Krunch waits: "
+ << arg->otherpcm->alsa_state_name()
+ << endl;
+ }
+#endif
+ while (snd_pcm_state(arg->otherpcm->phndl) != SND_PCM_STATE_RUNNING) {
+ usleep(1000);
+ }
+
+ double left_real(0);
+ double left_ineg(0); // the *negative* of the imaginary part
+ double right_real(0);
+ double right_ineg(0); // the *negative* of the imaginary part
+
+//#define PHASE_CHANGE
+#ifdef PHASE_CHANGE
+ double old_phase(0);
+#endif
+ double old_cpkp(0), old_fpkp(0);
+ double theta(0);
+ double dtheta(0);
+ int kperno(0);
+
+//////////////////
+// main krunch loop
+//
+// this is a SINGLE loop over TWO variables;
+// the cap_buffer is filled in units of nframe
+// and emptied (processed) in units of fpkp.
+// Parallel code appears in refout.cxx
+ int cap_end(nframe * pcm->nchan);
+ valarray<datum> cap_buffer(cap_end);
+ int cap_idx(cap_end);
+ int ref_end(123456);
+ int ref_idx(ref_end);
+ double decalage(0);
+
+ for (;;) { // loop over all samples
+
+// loop control for capture (read) process:
+ if (cap_idx >= nframe) {
+ int didread = arg->setup->read_stuff(pcm, &cap_buffer[0]);
+ if (didread != nframe) {
+ fprintf(stderr, "Krunch: ignoring peculiar buffer size %d not %d\n",
+ didread, nframe);
+ continue;
+ }
+ cap_idx = 0;
+ }
+
+// Loop control for reference process.
+// Note that frequency and phase-offset only changes at
+// the boundary between krunch periods.
+ if (ref_idx == ref_end) {
+ if (kperno == 0) {
+ decalage = arg->otherpcm->ss_time() - pcm->ss_time();
+ }
+
+#if 0
+ cout << "declalage: " << decalage
+ << " samples: " << decalage * pcm->rate
+ << " skipme: " << skipme
+ << endl;
+#endif
+ ref_to_krunch kper;
+ int didread = read(arg->pipefd, &kper, sizeof(kper));
+ if (didread != sizeof(kper)) {
+ fprintf(stderr, "Krunch: could not read from pipe: ");
+ perror(0);
+ exeunt(1);
+ }
+ if (kperno != kper.period) {
+ fprintf(stderr, "Krunch: phase error: expecting %d got %d\n",
+ kperno, kper.period);
+ exeunt(1);
+ }
+ double freq = double(pcm->rate) * double(kper.cpkp)
+ / double(kper.fpkp);
+// the phase offset:
+ theta = (decalage + timeShift) * freq * 2. * M_PI;
+ theta += phaseShift * M_PI / 180.;
+#ifdef PHASE_CHANGE
+ if (theta != old_phase){
+ cout << "Krunch: new phase: " << theta
+ << " decalage: " << decalage
+ << " timeShift: " << timeShift
+ << " phaseShift: " << timeShift
+ << " freq: " << freq
+ << endl;
+ old_phase = theta;
+ }
+#endif
+ left_real = left_ineg = 0.;
+ right_real = right_ineg = 0.;
+ ref_idx = 0;
+ ref_end = kper.fpkp;
+ dtheta = 2. * M_PI * kper.cpkp / kper.fpkp;
+ // cpkp == cycles per krunch period
+ // fpkp == frames per krunch period
+ if (old_cpkp != kper.cpkp || old_fpkp != kper.fpkp){
+#if 0
+ cout.precision(6);
+ cout << fixed;
+ cout << "Krunch switching to: " << freq
+ << setprecision(1)
+ << " cpkp: " << kper.cpkp
+ << " fpkp: " << kper.fpkp
+ << " dtheta: " << setprecision(20) << dtheta
+ << endl;
+#endif
+ old_cpkp = kper.cpkp;
+ old_fpkp = kper.fpkp;
+ }
+ kperno++;
+ }
+ double left = cap_buffer[cap_idx * pcm->nchan + left_idx ];
+ double right = cap_buffer[cap_idx * pcm->nchan + right_idx];
+
+ left_real += left * cos(theta);
+ left_ineg += left * sin(theta);
+
+ right_real += right * cos(theta);
+ right_ineg += right * sin(theta);
+
+ theta += dtheta;
+ cap_idx++;
+ ref_idx++;
+
+// Do a little post-processing.
+// This does not replace or even affect the
+// loop-control above.
+ if (ref_idx >= ref_end) {
+
+// put in the minus sign here, to convert ineg to the
+// actual imaginary part with the proper sign.
+ do {
+ double unit = pow(10., ViCal_dB / 20.);
+ unit /= full_swing;
+// account for the number of points of points in this krunch period:
+ unit /= double(ref_end);
+// account for the fact that integral(sin^2) is only 0.5, not 1:
+ unit *= 2.;
+ if (num_indic <= 0) break;
+ toss[0].newReading(0,0, left_real * unit, -left_ineg * unit);
+ if (num_indic <= 1) break;
+ toss[1].newReading(0,0, right_real * unit, -right_ineg * unit);
+ if (num_indic <= 2) break;
+ toss[2].newReading(right_real * unit, -right_ineg * unit,
+ left_real * unit, -left_ineg * unit);
+ } while (0);
+ flushy->flush();
+ }
+ }
+ // should never reach here
+ return 0;
+}
+
+////////////////////
+void dumpit_cout(const double rp, const double ip){
+ using namespace std;
+ cout.precision(4);
+ int wid(12);
+ double mag(sqrt(rp*rp + ip*ip));
+ double phase(0);
+ if (mag) phase = atan2(ip, rp);
+ cout
+ << " : " << fixed << setw(wid) << rp
+ << " " << fixed << setw(wid) << ip
+ << " " << fixed << setw(wid) << mag
+ << " " << fixed << setw(wid) << phase * 180 / M_PI
+ << endl;
+}
+
+// Just like snd_pcm_readi(),
+// except the buff is always of the type of datum (int32_t),
+// no matter what type the raw hardware uses.
+// Return value:
+// nonnegative: # of frames read
+// negative: error code
+int readi(const alsa_pcm* pcm, datum* buff, const int nframe){
+ using namespace std;
+ if (pcm->format == SND_PCM_FORMAT_S32_LE) {
+ return snd_pcm_readi(pcm->phndl, buff, nframe);
+ } else if (pcm->format == SND_PCM_FORMAT_S16_LE) {
+ valarray<int16_t> tmp(nframe * pcm->nchan);
+ int rslt = snd_pcm_readi(pcm->phndl, &tmp[0], nframe);
+ if (rslt <= 0) return rslt;
+ int16_t* from (&tmp[0]);
+ datum* to (buff);
+ int fudge(1<<16);
+ for (unsigned int ii = 0; ii < rslt * pcm->nchan; ii++){
+ *to++ = *from++ * fudge;
+ }
+ return rslt;
+ } else {
+ cerr << "Don't know how to convert pcm data from format "
+ << snd_pcm_format_name(pcm->format) << endl;
+ exeunt(1);
+ }
+ return 0; // defeat stupid compiler warning
+}
+
+////////////////////////////////////////
+// Read some data and maybe write checkfile
+int snark::read_stuff(alsa_pcm* pcm, datum* cap_buffer){
+
+ int sts;
+ int frames_read;
+
+ for (;;){ // keep trying to read
+ frames_read = readi(pcm, &cap_buffer[0], nframe);
+ if (frames_read == nframe) break; // good!
+ if (frames_read > 0 ||
+ frames_read == -EPIPE) { // recover from overruns
+ if (xrun_verbosity) fprintf(stderr,
+ "Read_stuff overrun: requested %i got %i: %s" NL,
+ nframe, frames_read, snd_strerror(frames_read));
+ snd_pcm_prepare(pcm->phndl);
+ } else { // unrecoverable error
+ fprintf(stderr, "Read_stuff requested %i got %i: %s" NL,
+ nframe, frames_read, snd_strerror(frames_read));
+ exeunt(1);
+ }
+ }
+
+ int gotbytes = snd_pcm_frames_to_bytes(pcm->phndl, frames_read);
+
+ if (wcheck_fd >= 0) {
+ sts = write(wcheck_fd, &cap_buffer[0], gotbytes);
+ if (sts != gotbytes) {
+ fprintf(stderr, "Write error on raw output file (%i): %m" NL, wcheck_fd);
+ exeunt(1);
+ }
+ close(wcheck_fd);
+ wcheck_fd = -1;
+ }
+
+ return frames_read;
+}