diff options
Diffstat (limited to 'src/krunch.cxx')
-rw-r--r-- | src/krunch.cxx | 308 |
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; +} |