Changeset 77 for trunk/libjdkmidi/trunk

Show
Ignore:
Timestamp:
07/01/06 14:07:50 (2 years ago)
Author:
jeffk@…
Message:

code for editing tracks from 1992 added to jdkmidi_edittrack.cpp, to yet to be transformed and put into use. for reference only so far.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/libjdkmidi/trunk/src/jdkmidi_edittrack.cpp

    r8 r77  
    193193   
    194194} 
     195 
     196#if 0 
     197 
     198/* 
     199 * Note: this code that follows is historic from 1992, before namespaces and bool existed in C++ 
     200 * The plan is to move the concepts and algorithms from this old code into the new form. 
     201 * In this old form, the EMIDITrack class inherited from MIDITrack. In the new form it ought not to,  
     202 * as it breaks the 'is-a' rule. 
     203 */ 
     204 
     205#include "world.h" 
     206#pragma hdrstopd 
     207 
     208 
     209 
     210#include <ETrack.hh> 
     211#include <MMatrix.hh> 
     212 
     213static int cmpmsgtime( const void *a, const void *b ) 
     214{ 
     215   register const TimedMIDIMessage *m1=(TimedMIDIMessage * )a; 
     216   register const TimedMIDIMessage *m2=(TimedMIDIMessage * )b; 
     217 
     218 
     219   // 
     220   // Check if message is a NOP. if it is, then propegate them to 
     221   // the end of track. 
     222   // 
     223 
     224 
     225   Boolean n1 = m1->IsNOP(); 
     226   Boolean  n2 = m2->IsNOP(); 
     227 
     228   if( n1 && n2 ) 
     229      return 0; 
     230       
     231   if( n1 ) 
     232      return 1; 
     233   if( n2 ) 
     234      return -1; 
     235 
     236 
     237   // 
     238   // Compare the event times 
     239   // 
     240 
     241   ulong t1,t2; 
     242 
     243   t1=m1->GetTime(); 
     244   t2=m2->GetTime(); 
     245 
     246   if( t1<t2 ) 
     247      return -1; 
     248   if( t1>t2 ) 
     249      return 1; 
     250 
     251   // the times are the same. put note ons first. 
     252 
     253   if( m1->GetStatus()==M_NOTE_ON && m1->byte2!=0 ) 
     254      return -1; 
     255       
     256   if( m2->GetStatus()==M_NOTE_ON && m2->byte2!=0 ) 
     257      return 1; 
     258          
     259   return 0; 
     260} 
     261 
     262void EMIDITrack::Sort() 
     263{ 
     264   // 
     265   // sort all the midi messages in the buffer by time. 
     266   // do not sort the last event. 
     267   // 
     268 
     269   qsort( buffer, last_event, sizeof( *buffer ), cmpmsgtime  ); 
     270 
     271   // 
     272   // TO DO: Clear away all NOP's at the end of the track. 
     273   // 
     274 
     275   // 
     276   // ok, now find the maximum time value used in the track. 
     277   // this would be the maximum of buffer[last_event-1] and 
     278   // buffer[last_event].  Set the last event ( the data end event) 
     279   // to the maximum time. 
     280   // 
     281 
     282   ulong t1=buffer[last_event-1].GetTime(); 
     283   ulong t2=buffer[last_event].GetTime(); 
     284 
     285   if( t1>t2 ) 
     286      buffer[last_event].SetTime( t1 ); 
     287} 
     288 
     289 
     290void EMIDITrack::CopyEvent( MIDITrack *t, unsigned int ev ) 
     291{ 
     292 
     293   // 
     294   // Get the event from the other track. 
     295   // 
     296 
     297   TimedMIDIMessage m; 
     298 
     299   t->GetEvent( ev, m ); 
     300 
     301   // 
     302   // is it a mark? 
     303   // 
     304 
     305   if( m.IsMark() ) 
     306   { 
     307      // 
     308      // Is it Sys-Ex? 
     309      // 
     310      //if( m.IsSysEx() ) 
     311      //{ 
     312         // 
     313         // yes, make a new sys-ex buffer and copy the 
     314         // sysex into it. 
     315         // 
     316 
     317         //SysEx *e = new SysEx; 
     318 
     319         // 
     320         // TO DO: Copy the SysEx 
     321         // 
     322 
     323      //} 
     324 
     325      // 
     326      // Is it a Text event? 
     327      // 
     328 
     329      //if( m.IsText() ) 
     330      //{ 
     331         // 
     332         // yes,make a new MIDIText event and copy the 
     333         // original into it. 
     334         // 
     335 
     336         //MIDIText *t = new MIDIText; 
     337 
     338         // 
     339         // TO DO: Copy the MIDIText 
     340         // 
     341      //} 
     342 
     343      // 
     344      // Is it a DataEnd event? 
     345      // 
     346 
     347      if( m.IsDataEnd() ) 
     348      { 
     349         // 
     350         // Yes, ignore it. 
     351         // 
     352 
     353         return; 
     354      } 
     355 
     356      // 
     357      // All other marks are just copied over 
     358      // 
     359 
     360   } 
     361 
     362   Put( m ); 
     363} 
     364 
     365 
     366void EMIDITrack::Compress() 
     367{ 
     368   unsigned int from_ev; 
     369   unsigned int to_ev; 
     370   unsigned int nop_count=0; 
     371 
     372   // 
     373   // find the first NOP 
     374   // 
     375 
     376   for( to_ev=0; to_ev<last_event; to_ev++ ) 
     377   { 
     378      if( buffer[to_ev].IsNOP() ) 
     379         break; 
     380   } 
     381 
     382   // 
     383   // if there is no NOP, then there is no way to compress 
     384   // 
     385 
     386   if( to_ev==last_event ) 
     387      return; 
     388 
     389 
     390   // 
     391   // go through the buffer and compress, including the last DATA END event 
     392   // 
     393 
     394   for( from_ev=to_ev+1; from_ev<=last_event; from_ev++ ) 
     395   { 
     396      // 
     397      // find the next non NOP event. 
     398      // 
     399 
     400      if( !buffer[from_ev].IsNOP() ) 
     401      { 
     402 
     403         // 
     404         // keep track of how many NOP's have been replaced 
     405         // 
     406 
     407         nop_count++; 
     408 
     409         // 
     410         // copy the found event to the NOP event 
     411         // 
     412 
     413         buffer[to_ev]=buffer[from_ev]; 
     414 
     415         // 
     416         // put a NOP in the original event 
     417         // 
     418 
     419         buffer[from_ev].SetNOP(); 
     420 
     421         // 
     422         // find the next NOP event. 
     423         // 
     424 
     425         for( to_ev++; to_ev<last_event; to_ev++ ) 
     426         { 
     427            if( buffer[to_ev].IsNOP() ) 
     428               break; 
     429         } 
     430 
     431         // 
     432         // if there is no more NOP's left, 
     433         // then we are done. 
     434         // 
     435 
     436         if( to_ev>=last_event ) 
     437            break; 
     438 
     439      } 
     440   } 
     441 
     442   // 
     443   // Ok, everything is compacted; we gotta now change the 
     444   // last_event to the new value 
     445   // 
     446 
     447   last_event-=nop_count; 
     448 
     449} 
     450 
     451 
     452void EMIDITrack::Truncate( ulong start_time ) 
     453{ 
     454   // find the first event at start_time or greater 
     455   // or the data end event 
     456 
     457   unsigned int ev; 
     458   for( ev=0; ev<last_event; ev++ ) 
     459   { 
     460      if( buffer[ev].IsDataEnd() ) 
     461         break; 
     462 
     463      if( buffer[ev].GetTime() >= start_time ) 
     464         break; 
     465   } 
     466 
     467   // 
     468   // now ev contains the event number that we truncate at 
     469   // 
     470 
     471 
     472   // 
     473   // Search through the deleted events for Sys-Ex or MIDIText events 
     474   // and free the memory for those as well. 
     475   // 
     476 
     477   last_event=ev; 
     478   buffer[ev].SetDataEnd(); 
     479   buffer[ev].SetTime(start_time); 
     480 
     481   FixNotes(); 
     482} 
     483 
     484 
     485void EMIDITrack::FixNotes() 
     486{ 
     487   MIDIMatrix *matrix=new MIDIMatrix; 
     488   TimedMIDIMessage m; 
     489 
     490   // 
     491   // Go through the MIDIEvents, keeping track of all note on events. 
     492   // 
     493 
     494 
     495   for( unsigned int ev=0; ev<=last_event; ev++ ) 
     496   { 
     497      if( buffer[ev].IsDataEnd() ) 
     498      { 
     499         m.SetTime( buffer[ev].GetTime() ); 
     500         break; 
     501      } 
     502      matrix->Process( buffer[ev] ); 
     503   } 
     504 
     505 
     506   // 
     507   // now put a note off message for each note that was left on 
     508   // at the end of the track. Do this for each channel. 
     509   // 
     510 
     511   for( uchar channel=0; channel<16; channel++ ) 
     512   { 
     513      if( matrix->GetChannelCount(channel)>0 ) 
     514      { 
     515         for( uchar note=0; note<128; note++ ) 
     516         { 
     517            uchar num=matrix->GetNoteCount( channel,note); 
     518            for( uchar c=0; c<num; c++ ) 
     519            { 
     520               m.NoteOff( channel, note, 64 ); 
     521               Put( m ); 
     522            } 
     523         } 
     524      } 
     525   } 
     526 
     527   delete matrix; 
     528} 
     529 
     530 
     531 
     532 
     533 
     534void  EMIDITrack::Merge( MIDITrack *trk1, MIDITrack *trk2 ) 
     535{ 
     536   Clear(); 
     537 
     538   unsigned int trk1_ev=0; 
     539   unsigned int trk2_ev=0; 
     540   unsigned int trk1_max=trk1->GetNumEvents(); 
     541   unsigned int trk2_max=trk2->GetNumEvents(); 
     542 
     543   // 
     544   // loop until all events of both tracks are transferred 
     545   // 
     546 
     547   while( (trk1_ev < trk1_max) || (trk2_ev < trk2_max ) ) 
     548   { 
     549 
     550      // 
     551      // is track 1 completed and track 2 not complete? 
     552      // 
     553 
     554      if( (trk1_ev >= trk1_max) && (trk2_ev < trk2_max) ) 
     555      { 
     556         // 
     557         // yes, just copy over the events from track 2 
     558         // 
     559 
     560         CopyEvent( trk2, trk2_ev++ ); 
     561 
     562                  // 
     563         // continue the loop. no reason to 
     564         // check the other if's. 
     565         // 
     566         continue; 
     567      } 
     568 
     569      // 
     570      // is track 2 completed and track 1 not complete? 
     571      // 
     572 
     573      if( (trk2_ev >= trk2_max) && (trk1_ev < trk1_max ) ) 
     574      { 
     575         // 
     576         // yes, just copy over the events from track 1 
     577         // 
     578 
     579         CopyEvent( trk1, trk1_ev++ ); 
     580 
     581 
     582         // 
     583         // continue the loop. 
     584         // 
     585         continue; 
     586 
     587      } 
     588 
     589      // 
     590      // ok since we got here, both tracks are not completed yet. 
     591      // we gotta compare times to see which event we copy over 
     592      // first. 
     593      // 
     594      TimedMIDIMessage m1,m2; 
     595 
     596      trk1->GetEvent( trk1_ev, m1 ); 
     597      trk2->GetEvent( trk2_ev, m2 ); 
     598 
     599      if( m1.GetTime() < m2.GetTime() ) 
     600      { 
     601         // 
     602         // track 1 event came first. copy it over. 
     603         // 
     604         CopyEvent( trk1, trk1_ev++ ); 
     605      } 
     606      else 
     607      { 
     608         // 
     609         // track 2 event came first. copy it over. 
     610         // 
     611 
     612         CopyEvent( trk2, trk2_ev++ ); 
     613      } 
     614   } 
     615 
     616} 
     617 
     618 
     619void  EMIDITrack::Merge( MIDITrack *trk ) 
     620{ 
     621   for( unsigned int ev=0; ev<trk->GetNumEvents(); ev++ ) 
     622   { 
     623      CopyEvent( trk, ev ); 
     624   } 
     625   Sort(); 
     626   FixNotes(); 
     627} 
     628 
     629 
     630void  EMIDITrack::Erase( ulong start, ulong end, Boolean jagged ) 
     631{ 
     632 
     633   // 
     634   // This Erase method should work fine, erasing all events 
     635   // between two times, and will keep track of all note on/off 
     636   // events so that there will be no hung notes. 
     637   // 
     638   // the edit may be jagged or sharp.  if it is jagged, 
     639   // any notes left on before start time and shut off during the 
     640   // erase time will not have their gate times changed. 
     641   // if jagged==FALSE, then the note off's will be moved to 
     642   // 'start' time. 
     643   // 
     644   // also, any note off messages that are AFTER 'end' time 
     645   // that were turned on during the erase time will be erased 
     646   // as well. 
     647   // 
     648   // One thing, though; if a note was turned on before 'start' 
     649   // time and shut off after 'end' time, it will not be affected 
     650   // by this erase method no matter what jagged is set to. 
     651   // 
     652   // Dealing with this situation would require that all 
     653   // events be sorted afterwards. 
     654   // 
     655 
     656 
     657 
     658   // 
     659   // Make sure we got valid values for end. 
     660   // 
     661 
     662   if( end<=start) 
     663      return; 
     664 
     665 
     666   Boolean changed=FALSE;     // set to TRUE if anything is erased. 
     667 
     668 
     669   // 
     670   // start up the MIDIMatrix objects. 
     671   // we need a MIDIMatrix to keep track of the 
     672   // note ON's going into the area we are deleting 
     673   // as well as a MIDIMatrix to keep track of the 
     674   // note ON's that we have deleted that have 
     675   // note OFF's after 'end' time. 
     676   // 
     677 
     678   MIDIMatrix *before_matrix = new MIDIMatrix; 
     679   MIDIMatrix *during_matrix = new MIDIMatrix; 
     680 
     681 
     682   // 
     683   // go through all the events and 'NOP' just the ones 
     684   // in that time period. 
     685   // 
     686 
     687   for( unsigned int ev=0; ev<last_event; ev++ ) 
     688   { 
     689      ulong time = buffer[ev].GetTime(); 
     690 
     691      // 
     692      // if the event is before our erase region, 
     693      // then give it to the before_matrix object 
     694      // 
     695 
     696      if( time<start ) 
     697      { 
     698         before_matrix->Process( buffer[ev] ); 
     699         continue; 
     700      } 
     701 
     702 
     703      if( time>=start && time<end ) 
     704      { 
     705         // 
     706         // see if this event should be ignored or 
     707         // erased. 
     708         // 
     709         TimedMIDIMessage m=buffer[ev]; 
     710 
     711         if( ! FilterEvent( m ) ) 
     712            continue; 
     713 
     714 
     715 
     716         // 
     717         // give this event to our during_matrix object 
     718         // to keep track of note on's 
     719         // 
     720 
     721         during_matrix->Process( buffer[ev] ); 
     722 
     723 
     724         if( buffer[ev].IsMark() ) 
     725         { 
     726            // 
     727            // Is this event a Sys-Ex event? 
     728            // 
     729 
     730            if( m.IsSysEx() ) 
     731            { 
     732               // 
     733               // yep. we delete it as well as the 
     734               // sys-ex message itself. 
     735               // 
     736               unsigned int s=m.GetSysEx(); 
     737 
     738               exclusives.Delete(s); 
     739            } 
     740 
     741            // 
     742            // is this event a MIDIText event? 
     743            // 
     744 
     745            if( m.IsText() ) 
     746            { 
     747               // 
     748               // yep. delete it and the MIDIText 
     749               // event itself. 
     750               // 
     751               unsigned int t=m.GetText(); 
     752               text.Delete(t); 
     753            } 
     754 
     755            // 
     756            // all other sequencer marks just get deleted. 
     757            // 
     758 
     759            changed=TRUE; 
     760            buffer[ev].SetNOP(); 
     761 
     762         } 
     763         else 
     764         { 
     765            // 
     766            // ok, we gotta make sure that if this is a 
     767            // note off event, we do not 'NOP' it if the 
     768            // corresponding note on event was before 
     769            // the start time. 
     770            // 
     771 
     772            if( (buffer[ev].GetStatus()==M_NOTE_ON && 
     773               buffer[ev].GetVelocity()==0 ) 
     774               || buffer[ev].GetStatus()==M_NOTE_OFF ) 
     775            { 
     776 
     777               // 
     778               // ok, it was a note off event. 
     779               // see if it needs to be deleted. 
     780               // 
     781 
     782               uchar channel = buffer[ev].GetChannel(); 
     783               uchar note = buffer[ev].GetNote(); 
     784 
     785               if( before_matrix->GetNoteCount(channel,note)!=0 ) 
     786               { 
     787                  // 
     788                  // do not delete the note off. 
     789                  // we need it. first process it 
     790                  // so we know that note is now off. 
     791                  // 
     792 
     793                  before_matrix->Process( buffer[ev] ); 
     794 
     795                  // 
     796                  // if a non-jagged edit was requested, 
     797                  // then we shall move this note off to 
     798                  // the 'start' time. 
     799                  // 
     800 
     801                  if( !jagged ) 
     802                  { 
     803                     buffer[ev].SetTime( start ); 
     804                  } 
     805 
     806               } 
     807               else 
     808               { 
     809                  changed=TRUE; 
     810                  buffer[ev].SetNOP(); 
     811               } 
     812            } 
     813            else 
     814            { 
     815               // 
     816               // ok, it wasn't a note off message. 
     817               // give it to the during_matrix object. 
     818               // 
     819 
     820               during_matrix->Process( buffer[ev] ); 
     821 
     822               // 
     823               // and now delete it. 
     824               // 
     825 
     826               buffer[ev].SetNOP(); 
     827               changed=TRUE; 
     828            } 
     829         } 
     830      } 
     831 
     832      // 
     833      // if the time of the event>end, and the event is 
     834      // a note off event which was turned on in the 
     835      // during_matrix object, then 'NOP' it. The note on 
     836      // was deleted. 
     837      // 
     838 
     839      if( time>=end ) 
     840      { 
     841         // 
     842         // make sure the message is not a mark. 
     843         // 
     844 
     845         if( !buffer[ev].IsMark() ) 
     846         { 
     847            // 
     848            // is it a note off message? 
     849            // 
     850 
     851            if( buffer[ev].GetStatus()==M_NOTE_OFF 
     852               || (buffer[ev].GetStatus()==M_NOTE_ON && 
     853                buffer[ev].GetVelocity()==0 ) ) 
     854            { 
     855               // 
     856               // ok, it is a note off message, 
     857               // was the corresponding note on 
     858               // deleted? 
     859               // 
     860 
     861               uchar channel=buffer[ev].GetChannel(); 
     862               uchar note=buffer[ev].GetNote(); 
     863 
     864               if( during_matrix->GetNoteCount( channel, note ) ) 
     865               { 
     866                  // 
     867                  // yes, it was, so we gotta NOP this event. 
     868                  // give it to during_matrix so it knows 
     869                  // that the note is off now. 
     870 
     871                  during_matrix->Process( buffer[ev] ); 
     872                  buffer[ev].SetNOP(); 
     873                  changed=TRUE; 
     874               } 
     875            } 
     876         } 
     877      } 
     878 
     879   } 
     880 
     881   // 
     882   // If there were any events NOP'd 
     883   // then we gotta compress them out of the way. 
     884   // 
     885 
     886   if( changed ) 
     887      Compress(); 
     888 
     889 
     890   // 
     891   // kill our helpful MIDIMatrix's 
     892   // 
     893 
     894   delete before_matrix; 
     895   delete during_matrix; 
     896 
     897} 
     898 
     899void    EMIDITrack::Delete( ulong start, ulong end, Boolean jagged ) 
     900{ 
     901   // 
     902   // Delete is just like Erase, except afterwards 
     903   // we move all the event times after 'end' from end to start. 
     904   // 
     905 
     906   // 
     907   // Make sure we got valid values for end. 
     908   // 
     909 
     910   if( end<=start) 
     911      return; 
     912 
     913   // 
     914   // Erase the events 
     915   // 
     916 
     917   Erase( start, end, jagged ); 
     918 
     919 
     920   // 
     921   // calculate the amount that we have to subtract from 
     922   // each event time after 'end' time. 
     923   // 
     924 
     925   ulong diff= end-start; 
     926 
     927 
     928   // 
     929   // go through all events (including the last event, data end) 
     930   // 
     931 
     932   for( unsigned int ev=0; ev<=last_event; ev++ ) 
     933   { 
     934      // 
     935      // get the event's time. 
     936      // 
     937 
     938      ulong time=buffer[ev].GetTime(); 
     939 
     940      // 
     941      // is it after the end time? 
     942      // 
     943 
     944      if( time>=end ) 
     945      { 
     946         // 
     947         // yes, change the event time to what it is 
     948         // supposed to be. 
     949         // 
     950 
     951         buffer[ev].SetTime( time-diff ); 
     952      } 
     953   } 
     954} 
     955 
     956void  EMIDITrack::Insert( ulong start, ulong end ) 
     957{ 
     958   // 
     959   // make sure end is after start. 
     960   // 
     961 
     962   if( end<start ) 
     963      return; 
     964 
     965   // 
     966   // calculate the amount of time we gotta add to the event times 
     967   // 
     968 
     969   ulong diff=end-start; 
     970 
     971   // 
     972   // go through all the events, including the last DATA END event. 
     973   // 
     974 
     975   for( unsigned int ev=0; ev<=last_event; ev++ ) 
     976   { 
     977 
     978      // 
     979      // Get the event's time. 
     980      // 
     981 
     982      ulong time=buffer[ev].GetTime(); 
     983 
     984      // 
     985      // is it after 'start' time? 
     986      // 
     987 
     988      if( time>=start ) 
     989      { 
     990         // 
     991         // move the event forward in time by 'diff' clicks. 
     992         // 
     993 
     994         buffer[ev].SetTime( time+diff ); 
     995      } 
     996   } 
     997} 
     998 
     999#endif