// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: 22 Nov 1998 // Last Modified: 22 Nov 1998 // Last Modified: Sat Mar 27 18:14:41 PST 1999 // Filename: ...sig/doc/examples/improv/synthImprov/2dpos/2dpos.cpp // Syntax: C++; synthImprov 2.0; NIDAQ (Windows 95 only) // // Description: plays notes according to 2D input data coming from NIDAQ card. // the keys (pitches) of the output are based on one channel of // input and their velocities are based on another channel of input // #include "synthImprov.h" /* basic MIDI I/O interface with MIDI synthesizer */ #include "Nidaq.h" /* interface with NIDAQ Card(Windows 95 only) */ /*----------------- beginning of improvization algorithms ---------------*/ // global variables: Nidaq sensor; // NIDAQ card interface for sensor int keychan = 0; // the NIDAQ channel to listen to for keys int velchan = 0; // the NIDAQ channel to listen to for velocities int keyselect = 0; // boolean to listen to keyboard for key chann int velselect = 0; // boolean to listen to keyboard for vel chann int keydir = 1; // for changing sensor direction of key numbers int veldir = 1; // for changing sensor direction of velocities Voice voice; // for MIDI output (auto handles note off messages) int inst = GM_VIBRAPHONE; // initial instrument to play notes on int sustain = 0; // for sustain pedal double keymin = 10.0; // miniumum value from NIDAQ for keys, adapts double keymax = -10.0; // maximum value from NIDAQ for keys, adapts double velmin = 10.0; // miniumum value from NIDAQ for vel, adapts double velmax = -10.0; // maximum value from NIDAQ for vel, adapts int keyno; // MIDI keynumber to play int velocity; // MIDI attack velocity int minDur = 40; // minimum duration of output notes SigTimer displayTimer; // for displaying positions on the screen int display = 0; // boolean for display sensor data on screen // non-interface function declarations: void makeNote(void); /*--------------------- maintenance algorithms --------------------------*/ ////////////////////////////// // // description -- this function is called by the improv interface // whenever a capital "D" is pressed on the computer keyboard. // Put a description of the program and how to use it here. // void description(void) { cout << '\n'; printboxtop(); pcl("2dpos: by Craig Stuart Sapp <craig@ccrma.stanford.edu> 22 Nov 1998"); printintermediateline(); psl(" NIDAQ device initially on channel 0. Initial sensor range will "); psl(" adapt as sensor moves. So go through whole range of sensor"); psl(" to fix the software range."); psl(" Commands:"); psl(" \"0\"-\"9\" = select NIDAQ analog input channel"); psl(" type \"k\" before number to select key channel"); psl(" type \"v\" before number to select velocity channel"); psl(" \"-\", \"=\" = change instruments, \" \" = sustain pedal"); psl(" \"z\" = reset key sensor range, \"x\" = reset vel sensor range"); psl(" \"a\" = switch key sensor range, \"s\" = switch vel sensor range"); psl(" \"d\" = toggle sensor display."); printboxbottom(); } ////////////////////////////// // // initialization -- this function is called by the improv // intervace once at the start of the program. Put items // here which need to be initialized at the beginning of // the program. // void initialization(void) { sensor.initialize(options.argv()); // start CVIRTE stuff for NIDAQ card sensor.setPollPeriod(1); // check for new data every 1 millisecond sensor.setFrameSize(1); // data transfer size from NIDAQ card sensor.setModeLatest(); // just look at most recent data in buffer sensor.setSrate(500); // set NIDAQ sampling rate to X Hz sensor.activateAllChannels(); // turn on all channels for sampling cout << "starting data aquisition ... " << flush; sensor.start(); // start aquiring data from NIDAQ card cout << "ready." << endl; voice.setPort(synth.getOutputPort()); // specify output port of voice voice.setChannel(0); // specify output chan of voice voice.pc(inst); displayTimer.setPeriod(200); // display position every X milliseconds } ////////////////////////////// // // finishup -- this function is called by the improv interface // whenever the function is exited. Put items here which // need to be taken care of when the program is finished. // void finishup(void) { } /*-------------------- main loop algorithms -----------------------------*/ ////////////////////////////// // // mainloopalgorithms -- this function is called by the improv interface // continuously while the program is running. The variable t_time // which stores the current time is set just before this function is // called and remains constant while in this functions. // void mainloopalgorithms(void) { sensor.checkPoll(); // see if it is time to check for new data frame makeNote(); // check if it is time to play a MIDI note if (display && displayTimer.expired()) { displayTimer.reset(); cout << "\r\t\t\t\t\t\t\t\t\t"; cout << "\rkey0= " << (int)(100 * keymin)/100.0 << " keyx= " << (int)(100 * keymax)/100.0 << " keyc= " << (int)(100 * sensor[keychan][0])/100.0 << " \tvel0= " << (int)(100 * velmin)/100.0 << " velx= " << (int)(100 * velmax)/100.0 << " velc= " << (int)(100 * sensor[velchan][0])/100.0 << " " << flush; } } ////////////////////////////// // // makeNote -- plays a new note whenever sensor detects // a new note value, but limit the minimum time between // notes. void makeNote(void) { // if the duration of the previous note is long enough and // the sensor is not at its min or max value, then play a note // if the interval distance has been traversed since the last // note which was played. if (t_time - voice.getOnTime() > minDur) { // adjust the range of the sensor values if necessary: if (sensor[keychan][0] > keymax) keymax = sensor[keychan][0]; if (sensor[keychan][0] < keymin) keymin = sensor[keychan][0]; if (sensor[velchan][0] > velmax) velmax = sensor[velchan][0]; if (sensor[velchan][0] < velmin) velmin = sensor[velchan][0]; // keyno is the note to be played. It is in the range from 0 to 127 keyno = (int)((sensor[keychan][0] - keymin) / (keymax - keymin) * 127); if (keydir == -1) { keyno = 127 - keyno; } velocity = (int)((sensor[velchan][0] - velmin) / (velmax - velmin) * 127); if (veldir == -1) { velocity = 127 - velocity; } // limit the range of keyno to valid range, in case max/min not correct if (keyno < 0) keyno = 0; if (keyno > 127) keyno = 127; if (velocity < 0) velocity = 0; if (velocity > 127) velocity = 127; if (keyno < 2 || keyno > 125) { // turn off notes out of sensor range voice.off(); } else { voice.play(keyno, velocity); } } } /*-------------------- triggered algorithms -----------------------------*/ /////////////////////////////// // // keyboardchar -- this function is called by the improv interface // whenever a key is pressed on the computer keyboard. // Put commands here which will be executed when a key is // pressed on the computer keyboard. // void keyboardchar(int key) { // select a NIDAQ channel if the key is a number from 0 to 9: if (isdigit(key)) { if (keyselect) { keychan = key - '0'; keyselect = 0; cout << "\nKey Channel " << key - '0' << " selected" << endl; } if (velselect) { velchan = key - '0'; velselect = 0; cout << "\nVelocity Channel " << key - '0' << " selected" << endl; } return; } switch (key) { case 'd': // toggle display of sensor data on screen display = !display; break; case 'k': // toggle key number channel select option keyselect = !keyselect; break; case 'v': // toggle velocity channel select option velselect = !velselect; break; case 'z': // reset the key sensor range keymax = -10.0; keymin = 10.0; break; case 'x': // reset the velocity sensor range velmax = -10.0; velmin = 10.0; break; case 'a': // reverse the key axis of the sensor data keydir = -keydir; break; case 's': // reverse the veolcity sensor direction veldir = -veldir; break; case '-': // decrement instrument inst--; if (inst < 0) inst = 127; voice.pc(inst); cout << "\ninst = " << inst << endl; break; case '=': // increment instrument inst++; if (inst > 127) inst = 0; voice.pc(inst); cout << "\ninst = " << inst << endl; break; case ' ': // sustain pedal on/off sustain = !sustain; voice.sustain(sustain); cout << "\nsustain = " << sustain << endl; break; } } /*------------------ end improvization algorithms -----------------------*/ // md5sum: 7039d0f8b8c44c88411361e93b892257 2dpos.cpp [20050403]