//midi_monster.cpp #include #include #include #include #include #include #include #include #include #include "my_definitions.h" #include "midi_monster.h" using namespace std; MidiMonster::MidiMonster(){ locked_key = "locked_key"; calculateSilence = false; //reset_g_t = false; // num_notes_on = 0; init_all_maps(); } MidiMonster::~MidiMonster(){} //init function just puts the locking key into every map void MidiMonster::init_all_maps(){ pitchMap[locked_key] = vector >(1); pitchMap[locked_key][0] = MAP_LOCK_FALSE; durMap[locked_key] = vector >(1); durMap[locked_key][0] = MAP_LOCK_FALSE; // nnoMap[locked_key] = vector >(1); // nnoMap[locked_key][0] = MAP_LOCK_FALSE; // velMap[locked_key] = vector >(1); // velMap[locked_key][0] = MAP_LOCK_FALSE; // ivalMap[locked_key] = vector >(1); // ivalMap[locked_key][0] = MAP_LOCK_FALSE; // t_ivalMap[locked_key] = vector >(1); // t_ivalMap[locked_key][0] = MAP_LOCK_FALSE; } void MidiMonster::store_midi(std::vector< unsigned char > *message, float g_t){ // heirinch taub - common lisp common music //static int last_onset_t = 0; //cout<<"store_midi"<at(ON_OFF_BYTE) == NOTE_ON){ //store the start time of that pitch in MAP incoming_pitches[(int)message->at(PITCH_BYTE)] = g_t; // push(num_notes_on++, nno2map, NNO_CHAIN_SIZE); // process(nno2map, nnoMap, NNO_CHAIN_SIZE); //store the t_ival, i.e the onset overlap /* int onset_overlap = (int)g_t - last_onset_t; push(onset_overlap, t_ival2map, T_IVAL_CHAIN_SIZE); process(t_ival2map, t_ivalMap, T_IVAL_CHAIN_SIZE); last_onset_t = (int)g_t; */ //check to see if it should save a silence duration // if(calculateSilence){ // float old_g_t = incoming_pitches[REST_PITCH]; // int elapsed_t = quantize((int)g_t - (int)old_g_t); // push(elapsed_t, dur2map, DUR_CHAIN_SIZE); // process(dur2map, durMap, DUR_CHAIN_SIZE); // calculateSilence = false; // } //save the volume // push((int)message->at(VEL_BYTE), vel2map, VEL_CHAIN_SIZE); // process(vel2map, velMap, VEL_CHAIN_SIZE); } //stuff for finished notes else if ((int)message->at(ON_OFF_BYTE) == NOTE_OFF){ //store the pitch of the completed note push((int)message->at(PITCH_BYTE), pitch2map, PITCH_CHAIN_SIZE); process(pitch2map, pitchMap, PITCH_CHAIN_SIZE); //save the duration of the complete note float old_g_t = incoming_pitches[(int)message->at(PITCH_BYTE)]; int elapsed_t = quantize((int)g_t - (int)old_g_t); push(elapsed_t, dur2map, DUR_CHAIN_SIZE); process(dur2map, durMap, DUR_CHAIN_SIZE); //deal with calculating the silence here !!!!!!!!!!! // incoming_pitches.erase(incoming_pitches.find((int)message->at(PITCH_BYTE))); // //if there are no incoming pitches // if( incoming_pitches.size() == 0 ){ // cout<<"you should hear silence now...."<= 2){ // int p_cur = pitch2map[pitch2map.size()-1]; // if(p_cur == 0) return; // int p_prev; // for(int i = pitch2map.size() - 2; i >= 0; i--){ // p_prev = pitch2map[i]; // if ( p_prev != 0) break; // } // int ival = p_prev - p_cur; // push(ival, ival2map, IVAL_CHAIN_SIZE); // process(ival2map, ivalMap, IVAL_CHAIN_SIZE); // } } } //for use to keep the right number of things in the pitch2map, dur2map, ival2map, vel2map void MidiMonster::push(int data, vector& v, int max_size){ //if there is nothing, or not a full load in the vector, short circuit out // cout<& v, monsterMap& m, int max_size){ if(v.size() != max_size) return; // cout<= quantBound/2) return numSamples + quantBound - extra; else return numSamples - extra; } void MidiMonster::put_into_map(string key, int val, monsterMap& cur_map){ //cout<<"Put into map: "< >(); cur_map[key].push_back(pair(val, 1)); //cout << cur_map[key][0].first << " brand new key,val"< >& cur_vec = cur_map[key]; //cout<<"cur_vec.size()"<(val, 1)); unlock(cur_map); return; } } //makes a key from the first size - 1 entries in pitch2map, vel2map, dur2map, ival2mp string MidiMonster::makeKey(vector& v, int max_size){ //convert all but last val in the vec into a string. The last item in the vec is the map value! string key; for(int i = 0; i < max_size - 1; i++){ stringstream ss; ss << v[i]; key += ss.str() + '_'; } return key; } string MidiMonster::int2str(int i){ string str; stringstream ss; ss << i; str += ss.str(); return str; } bool MidiMonster::map_is_unlocked(monsterMap& m){ return m[locked_key][0] == MAP_LOCK_FALSE; } void MidiMonster::lock(monsterMap& m){ m[locked_key][0] = MAP_LOCK_TRUE; } void MidiMonster::unlock(monsterMap& m){ m[locked_key][0] = MAP_LOCK_FALSE; //cout<<"map has been unlocked"<noteOn(0, pitch2play[pitch2play.size() - 1], 126);//vel2play[vel2play.size() - 1]); //when the elapsed time has passed, turn things off, update, and turn them back on if((int)g_t - startingsamp >= 100 + dur2play[dur2play.size() - 1]){ // the extra 100 helps the ring buffer!! synth->noteOff( 0, pitch2play[pitch2play.size() - 1] ); //update the pitch string pitchKey = makeKey(pitch2play, PITCH_CHAIN_SIZE); int nextPitch = lookup_key(pitchKey, pitchMap); push(nextPitch, pitch2play, PITCH_CHAIN_SIZE); //update the dur string durKey = makeKey(dur2play, DUR_CHAIN_SIZE); int nextDur = lookup_key(durKey, durMap); push(nextDur, dur2play, DUR_CHAIN_SIZE); //update the nno // string nnoKey = makeKey(nno2play, NNO_CHAIN_SIZE); // int nextNno = lookup_key(nnoKey, nnoMap); // push(nextNno, nno2play, NNO_CHAIN_SIZE); //update the ival // string ivalKey = makeKey(ival2play, IVAL_CHAIN_SIZE); // int nextIval = lookup_key(ivalKey, ivalMap); // push(nextIval, ival2play, IVAL_CHAIN_SIZE); //update the t_ival // string t_ivalKey = makeKey(t_ival2play, T_IVAL_CHAIN_SIZE); // int nextTival = lookup_key(t_ivalKey, t_ivalMap); // push(nextTival, t_ival2play, T_IVAL_CHAIN_SIZE); // if(reset_g_t){ // //clear all the maps // if(map_is_unlocked(pitchMap)){ // lock(pitchMap); // if(map_is_unlocked(durMap)){ // lock(durMap); // pitchMap.clear(); // durMap.clear(); // } // } // unlock(pitchMap); // unlock(durMap); // return; // } synth->noteOn( 0, nextPitch, 126); startingsamp = (int)g_t; } } int MidiMonster::lookup_key(string key, monsterMap& m){ int nextItem ; if(map_is_unlocked(m)){ lock(m); // if key is not in the map if(m.find(key) == m.end()){ // ((m.find(key))->second).size() == 0 !!!!!!! if the vector attached is size 0, that is bad //cout<<"key not found in maps"< >& v = m.find(key)->second; nextItem = get_val_from_vector(it, &m); unlock(m); return nextItem; } } int MidiMonster::get_val_from_vector(monsterMap::iterator mmit, monsterMap* m){ //find total number of items in that vector vector >& v = mmit->second; int sum = sum_histories(v); if(sum == 0)cout<<"why is the sum 0???????????"<= index) { // 1/50th of the time, decrement that notes history! if(rand() % 50 == 1){ //v[i] should be a pair, the second of which is the history v[i].second -= 1; if(v[i].second == 0){ //cout<<"Just in case"<(ret_val, 8)); } if(v.size() == 0 && m == &pitchMap){ if(m->size() == 2){ v.push_back(pair(ret_val, 8)); } else{ m->erase(mmit); } } return ret_val; } } return v[i].first; } //assume that the ifs were not hit, and sum is smaller than index } } int MidiMonster::get_some_other_probable_item(monsterMap& m){ int max = 0; monsterMap::iterator biggest = m.begin(); //find the longest vector in the map for( monsterMap::iterator i = m.begin(); i != m.end(); ++i ){ //if the vector length is bigger than the max so far AND the first pair isn't the locked indicator if ( (i->second).size() >= max && (i->first) != locked_key) {//(i->second)[0].first != 1 ){ max = (i->second).size(); biggest = i; } } // use the reference to the biggest vector in the map to find a value in that vector if(biggest->first == locked_key) cout<<"there is a problem in get_some_other_probable_item locked Key"< >& cur_vec = i->second; pair node = find_node_position(i->first); int sumHist = sum_histories(cur_vec); //add transprent ring! glColor4f(1, 1, 1, 0.015); //draw node glPushMatrix(); glTranslatef(node.first, mess_with(node.second, g_t), 0); glutSolidSphere(70 + sumHist, 10, 10); glutSolidSphere(50 + sumHist, 10, 10); glutSolidSphere(35 + sumHist,10,10); glutSolidSphere(20 + sumHist, 10, 10); glPopMatrix(); //deal with colors! if(i->first == key_being_played_now){ // change the color when that key is being actually played! glColor4f(0, 0.9, 0.5, 0.1); } else{ glColor4f(0.8, 0, 0, 0.25); } //draw node glPushMatrix(); glTranslatef(node.first, mess_with(node.second, g_t), 0); glutSolidSphere(10 + sumHist,10,10); glutSolidSphere(2 + sumHist, 10, 10); glPopMatrix(); //draw the connection from node to hash of its entries for(int entry = 0; entry < cur_vec.size(); entry++){ pair destination = find_node_position(int2str(cur_vec[entry].first)); glPushMatrix(); glBegin(GL_LINE_STRIP); glVertex3f(0,0,0); glVertex3f(node.first, mess_with(node.second, g_t), 0); //glVertex3f(destination.first, mess_with(destination.second, g_t), 0); glLineWidth(100); glVertex3f(0, 0, 0); glLineWidth(1); glEnd(); glPopMatrix(); } } unlock(pitchMap); } } void MidiMonster::draw2(float g_t){ if(map_is_unlocked(durMap)){ lock(durMap); // short circuit out if the map is not ready if(durMap.size() == 1){ unlock(durMap); return; } //save the current key being looked up string key_being_played_now; //int pitch_being_played_now; if(dur2play.size() == DUR_CHAIN_SIZE){ key_being_played_now = makeKey(dur2play, DUR_CHAIN_SIZE); //pitch_being_played_now = pitch2play[pitch2play.size() - 1]; } //for each key in the pitch map, draw the keys as nodes randomly on screen for(monsterMap::iterator i = durMap.begin(); i != durMap.end(); ++i){ //navigate to the vector associated with the key. vector >& cur_vec = i->second; pair node = find_node_position(i->first); int sumHist = sum_histories(cur_vec); //add transprent ring! glColor4f(1, 1, 1, 0.015); //draw node glPushMatrix(); glTranslatef(node.first, mess_with(node.second, g_t), 0); glutSolidSphere(70 + sumHist, 10, 10); glutSolidSphere(50 + sumHist, 10, 10); glutSolidSphere(35 + sumHist,10,10); glutSolidSphere(20 + sumHist, 10, 10); glPopMatrix(); //deal with colors! if(i->first == key_being_played_now){ // change the color when that key is being actually played! glColor4f(0.5, 0.5, 0, 0.2); } else{ glColor4f(0, 0, 0.9, 0.35); } //draw node glPushMatrix(); glTranslatef(node.first, mess_with(node.second, g_t), 0); glutSolidSphere(10 + sumHist,10,10); glutSolidSphere(2 + sumHist, 10, 10); glPopMatrix(); //draw the connection from node to hash of its entries for(int entry = 0; entry < cur_vec.size(); entry++){ pair destination = find_node_position(int2str(cur_vec[entry].first)); glPushMatrix(); glBegin(GL_LINE_STRIP); glVertex3f(X_DIMENSION,0,0); glVertex3f(node.first, mess_with(node.second, g_t), 0); //glVertex3f(destination.first, mess_with(destination.second, g_t), 0); glLineWidth(100); glVertex3f(X_DIMENSION, 0, 0); glLineWidth(1); glEnd(); glPopMatrix(); } } unlock(durMap); } } pair MidiMonster::find_node_position(string key){ long int h = hash(key); float x = abs(h % X_DIMENSION); //fmod(abs(h % 1920) + 0.0003*g_t, 1920); float y = abs(h % Y_DIMENSION); return pair(x, y); } float MidiMonster::mess_with(float y, float g_t){ return fmod(y + 0.0003*g_t, Y_DIMENSION); } int MidiMonster::sum_histories(vector >& v){ int sum = 0; for(int i = 0; i < v.size(); i++ ){ sum += v[i].second; } return sum; } long int MidiMonster::hash(string key){ long int h = 29; for(int i = 0; i < key.length(); i++){ h *= (int)key.at(i); //if(i == 0) h = h * 7919 + 97 * i; //if(i == 1) // h *= h; } // cout<<"key: "<