using namespace std; #include #include #include #include "refout.h" #include "lockin.h" #include "gui.h" #include #ifdef TUNER # include /* for ioctl, TCGETA */ # include /* 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 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; }