// // Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu> // Creation Date: Mon Oct 26 17:00:30 PST 1998 // Last Modified: Thurs 30 Oct 1998 // Last Modified: 22 Nov 1998 (changed Nidaq class to be multi channel input) // Filename: ...sig/doc/examples/improv/synthImprov/position1/position1.cpp // Syntax: C++; synthImprov 2.0; (Windows 95 only) // // Description: plays notes according to 1D input data coming from NIDAQ card. // #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 channel = 0; // the NIDAQ channel to listen to Voice voice; // for MIDI output (auto handles note off messages) double min = 10.0; // miniumum value from NIDAQ, adapts double max = -10.0; // maximum value from NIDAQ, adapts int keyno; // MIDI keynumber to play int velocity; // MIDI attack velocity int minDur = 20; // 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("POSITION: by Craig Stuart Sapp <craig@ccrma.stanford.edu> 26 Oct 1998"); pcl("version 22 November 1998"); printintermediateline(); psl(" NIDAQ device initially on channel 0. Initial data range is"); psl(" 2.4 to 2.5, but range adapts. So go through whole range of sensor"); psl(" to set the software range."); psl(" Commands:"); psl(" \"0\"-\"9\" = select NIDAQ analog input channel"); 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 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 << "\rmin = " << min << "\tmax = " << max << "\tcurrent = " << sensor[channel][0] << "\t\t" << 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[channel][0] > max) max = sensor[channel][0]; if (sensor[channel][0] < min) min = sensor[channel][0]; // keyno is the note to be played. It is in the range from 0 to 127 keyno = 127 - (int)((sensor[channel][0] - min) / (max - min) * 127); // 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 (keyno < 2 || keyno > 125) { // turn off notes out of sensor range voice.off(); } else { velocity = 120; 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)) { cout << "\nresetting data aquisition ... " << flush; channel = key - '0'; cout << "done." << endl; cout << "Channel " << key - '0' << " selected" << endl; return; } switch (key) { case 'd': // toggle display of sensor data on screen display = !display; break; } } /*------------------ end improvization algorithms -----------------------*/ // md5sum: 3a695dbb5cacad35e71d160268d345ec position1.cpp [20050403]