diff options
Diffstat (limited to 'src/refout.cxx')
-rw-r--r-- | src/refout.cxx | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/refout.cxx b/src/refout.cxx new file mode 100644 index 0000000..3642380 --- /dev/null +++ b/src/refout.cxx @@ -0,0 +1,247 @@ +using namespace std; +#include <iostream> +#include <iomanip> +#include <unistd.h> +#include "refout.h" +#include "lockin.h" +#include "gui.h" +#include <alsa/asoundlib.h> +#ifdef TUNER +# include <sys/ioctl.h> /* for ioctl, TCGETA */ +# include <termios.h> /* for ECHO */ +#endif + +datum smash(double foo) { + if (foo > INT_MAX) return INT_MAX; + if (foo < -INT_MAX) return -INT_MAX; + return datum(foo); +} + +#ifdef TUNER + +int fn = fileno(stdin); +string kbd("\t1q2we4r5t6yu8i9op-[=]"); +string keymap("C+D+EF+G+A+BC"); +const double halfstep(pow(2.0, 1.0/12.0)); +int octave(4); +int kbkey(9); // A4 = 440 Hz +int abskey(57); + +void dokey(int newkey){ + abskey = newkey; + ofreq = 440*pow(halfstep, abskey-57); + int myoct = abskey / 12; + int mykey = abskey - myoct*12; + string keyname; + char keylet = keymap[mykey]; + if (keylet == '+') { + keyname += keymap[mykey-1]; + keyname += '#'; + } else keyname += keylet; + + fprintf(stderr, "\r\033[K %2s%1d %6.2f\r", keyname.c_str(), myoct, ofreq); + fflush(stderr); +} + +int escmode(0); + +void chkey(){ + char cc; + int nn = read(fn, &cc, 1); + if (nn <= 0) return; + if (cc == 033) { + escmode = 1; + return; + } + if (escmode) { + if (cc == '~') escmode = 0; + if (cc != 'O' && isupper(cc)) escmode = 0; + if (cc == 'B' || cc == 'D') dokey(abskey-1); + else if (cc == 'A' || cc == 'C') dokey(abskey+1); + return; + } + string::size_type where = kbd.find(cc); + if (where != kbd.npos) { + kbkey = where; + } else if (cc == ',') { + octave--; + if (octave < 0) octave = 0; + } else if (cc == '.') { + octave++; + if (octave > 8) octave = 8; + } else { + int foo; + foo = cc; + fprintf(stderr, "%04o\n", foo); + return; + } + dokey(12*octave + kbkey); +} + +void setkey(){ + kbd += char(127); // the "backspace" key + kbd += '\\'; + kbd += char(10); // the "return" key +} + +#else +inline void chkey(){} // does nothing +inline void setkey(){} // does nothing +#endif + +void* refout(void* _arg){ + + ref_arg* arg = (ref_arg*) _arg; + + setkey(); // FIXME (doesn't do anything at the moment) + + double reftime = .2; // # of seconds in output buffer + int refframe = int(arg->pcm->rate * reftime); // # of frames + int bufsize(refframe * arg->pcm->nchan); + + if (verbosity) cerr << "Refout starts, ofreq: " << actOutFreq + << " INT_MAX: " << INT_MAX + << " sizeof(datum): " << sizeof(datum) + << " refframe: " << refframe + << " bufsize: " << bufsize + << endl; + +#ifdef TUNER + { + termio save; + // If ioctl fails, we're probably not connected to a terminal. + int rslt; + rslt = ioctl(fn, TCGETA, &save); + termio t(save); + t.c_lflag &= ~ECHO; + t.c_lflag &= ~ICANON; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + t.c_cc[VERASE] = 0; + + ioctl(fn, TCSETA, &t); + int temp(1); + ioctl(fn, FIONBIO, &temp); + } +#endif + + Keeper keep(arg->pcm, FPP); + + datum* ptr; + datum foo[2]; + int flip; + +///////////////// +// main refout loop +// +// this is a SINGLE loop over TWO variables; +// the cap_buffer is emptied in units of refframe +// and filled in units of fpkp. +// Parallel code appears in krunch.cxx + valarray<datum> refout_buffer(bufsize); + int out_idx(0); + int ref_end(fpkp); + int ref_idx(0); + double theta0(0); + double theta1(0); + double old_cpkp(0), old_fpkp(0); + double dtheta0(0); + double dtheta1(0); + int kperno(0); + + for (;;) { // loop over all samples + +// loop control for output (write) process + if (out_idx >= refframe) { + int todo = out_idx; + out_idx = 0; + datum* obuf_ptr(&refout_buffer[0]); + + while (todo) { // keep trying to get this buffer out + int rslt = snd_pcm_writei(keep, obuf_ptr, todo); + if (rslt == todo) break; // good! + if (rslt > 0) { // short write = harmless + // but should be rare + cout << "Refout: short write; probably harmless." << endl; + todo -= rslt; + obuf_ptr += rslt; + continue; + } + if (rslt == -EPIPE) { // explicit underrrun + if (xrun_verbosity) fprintf(stderr, + "Refout underrun: wrote %d got %d" NL, todo, rslt); + snd_pcm_prepare(arg->pcm->phndl); // recover from underruns + continue; + } + // some error we don't understand + fprintf(stderr, "Refout wrote %d got %d" NL, todo, rslt); + snd_pcm_prepare(arg->pcm->phndl); // try to recover + } + } + +// Loop control for reference process. +// Note that dtheta0 only changes at the boundary +// between krunch periods. + if (ref_idx == ref_end) { + theta0 = 0.; + // theta1 is free-running + ref_idx = 0; + ref_end = fpkp; + dtheta0 = 2. * M_PI * cpkp / fpkp; + // cpkp == cycles per krunch period + // fpkp == frames per krunch period + if (old_cpkp != cpkp || old_fpkp != fpkp){ + if (verbosity > 0) { + cout.precision(6); + cout << fixed; + double freq = arg->pcm->rate / fpkp * cpkp; + cout << "Refout switching to: " << freq + << setprecision(1) + << " cpkp: " << cpkp + << " fpkp: " << fpkp + << " dtheta: " << setprecision(20) << dtheta0 + << " rate: " << arg->pcm->rate + << endl; + } + old_cpkp = cpkp; + old_fpkp = fpkp; + } + } + if (ref_idx == 0) { + ref_to_krunch kper(kperno, int(cpkp), int(fpkp)); + int didwrite = write(arg->pipefd, &kper, sizeof(kper)); + if (didwrite != sizeof(kper)) { + fprintf(stderr, "refout: write to pipe failed:"); + perror(0); + exeunt(1); + } + kperno++; + } + + + dtheta1 = dtheta0 * arg->ival; + + chkey(); // FIXME + + double expo((refOutAmp_dB - VoCal_dB)/20); + if (expo > 100) expo = 100; + double gainFactor(pow(10, expo)); + double amplitude(full_swing * gainFactor); + + foo[0] = smash(amplitude * cos(theta0)); + foo[1] = smash(amplitude * cos(theta1)); + +// Fill all channels in frame (not just the first two): + ptr = &refout_buffer[out_idx * arg->pcm->nchan]; + for (unsigned int jj = 0; jj < arg->pcm->nchan; jj++) { + flip = jj & 1; // copy foo[0] or foo[1] + *ptr++ = foo[flip]; + } + + theta0 += dtheta0; + theta1 += dtheta1; + out_idx++; + ref_idx++; + } + return 0; +} |