jdkmidi class library documentation

Copyright © 2004 J.D. Koftinoff Software, Ltd.

Released under the GNU General Public License (GPL)




Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

src/jdkmidi_track.cpp

Go to the documentation of this file.
00001 /*
00002  *  libjdkmidi-2004 C++ Class Library for MIDI
00003  *
00004  *  Copyright (C) 2004  J.D. Koftinoff Software, Ltd.
00005  *  www.jdkoftinoff.com
00006  *  jeffk@jdkoftinoff.com
00007  *
00008  *  *** RELEASED UNDER THE GNU GENERAL PUBLIC LICENSE (GPL) April 27, 2004 ***
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 */
00024 /*
00025 **  Copyright 1986 to 1998 By J.D. Koftinoff Software, Ltd.
00026 **
00027 **  All rights reserved.
00028 **
00029 **  No one may duplicate this source code in any form for any reason
00030 **  without the written permission given by J.D. Koftinoff Software, Ltd.
00031 **
00032 */
00033 
00034 
00035 #include "jdkmidi/world.h"
00036 
00037 #include "jdkmidi/track.h"
00038 
00039 
00040 #ifndef DEBUG_MDTRACK
00041 # define DEBUG_MDTRACK  0
00042 #endif
00043 
00044 #if DEBUG_MDTRACK
00045 # undef DBG
00046 # define DBG(a) a
00047 #endif
00048 
00049 namespace jdkmidi
00050 {
00051   
00052   const MIDITimedBigMessage * MIDITrackChunk::GetEventAddress( int event_num ) const
00053   {
00054     return &buf[event_num];
00055   }
00056   
00057   MIDITimedBigMessage * MIDITrackChunk::GetEventAddress( int event_num )
00058   {
00059     return &buf[event_num];
00060   }
00061   
00062   
00063   
00064   
00065   
00066   MIDITrack::MIDITrack( int size) 
00067   {
00068     buf_size=0;
00069     num_events=0;
00070     
00071     for( int i=0; i<MIDIChunksPerTrack; ++i )
00072       chunk[i]=0;
00073     
00074     if( size )
00075     {
00076       Expand( size );
00077     }
00078     
00079   } 
00080   
00081   MIDITrack::MIDITrack( const MIDITrack &t )  
00082   {
00083     buf_size=0;
00084     num_events=0;
00085     
00086     
00087     for( int i=0; i<t.GetNumEvents(); ++i )
00088     {
00089       const MIDITimedBigMessage *src;
00090       src = t.GetEventAddress( i );
00091       PutEvent(*src);
00092     }
00093   } 
00094   
00095   MIDITrack::~MIDITrack() 
00096   {
00097     for( int i=0; i<buf_size/MIDITrackChunkSize; ++i )
00098       delete chunk[i];
00099   } 
00100   
00101   void  MIDITrack::Clear()  
00102   {
00103     num_events = 0;
00104   } 
00105   
00106   
00107   void  MIDITrack::ClearAndMerge(
00108     const MIDITrack *src1,
00109     const MIDITrack *src2
00110     )
00111   {
00112     Clear();
00113     
00114     const MIDITimedBigMessage *ev1;
00115     int cur_trk1ev=0;
00116     int num_trk1ev = src1->GetNumEvents();
00117     
00118     const MIDITimedBigMessage *ev2;
00119     int cur_trk2ev=0;
00120     int num_trk2ev = src2->GetNumEvents();
00121     
00122     MIDIClockTime last_data_end_time=0;
00123     
00124     while(
00125       cur_trk1ev<num_trk1ev
00126       || cur_trk2ev<num_trk2ev
00127       )
00128     {
00129       // skip any NOPs on track 1
00130       
00131       ev1=src1->GetEventAddress( cur_trk1ev );
00132       ev2=src2->GetEventAddress( cur_trk2ev );
00133       
00134       bool has_ev1 = (cur_trk1ev<num_trk1ev) && ev1;
00135       bool has_ev2 = (cur_trk2ev<num_trk2ev) && ev2;
00136       
00137       if( has_ev1 && ev1->IsNoOp() )
00138       {
00139         cur_trk1ev++;
00140         continue;
00141       }
00142       
00143       // skip any NOPs on track 2
00144       
00145       if( has_ev2 && ev2->IsNoOp() )
00146       {
00147         cur_trk2ev++;
00148         continue;
00149       }
00150       
00151       // skip all data end
00152       
00153       if( has_ev1 && ev1->IsDataEnd() )
00154       {
00155         if( ev1->GetTime() > last_data_end_time )
00156         {
00157           last_data_end_time = ev1->GetTime();
00158         }
00159         cur_trk1ev++;
00160         continue;
00161       }
00162       
00163       if( has_ev2 && ev2->IsDataEnd() )
00164       {
00165         if( ev2->GetTime() > last_data_end_time )
00166         {
00167           last_data_end_time = ev2->GetTime();
00168         }
00169         cur_trk2ev++;
00170         continue;
00171       }
00172       
00173       if( (has_ev1 && !has_ev2) )
00174       {
00175         // nothing left on trk 2
00176         
00177         if( !ev1->IsNoOp())
00178         {
00179           if( ev1->GetTime() > last_data_end_time )
00180           {
00181             last_data_end_time = ev1->GetTime();
00182           }
00183           
00184           PutEvent( *ev1 );
00185           ++cur_trk1ev;
00186         }
00187       } else if( (!has_ev1 && has_ev2) )
00188       {
00189         // nothing left on trk 1
00190         if( !ev2->IsNoOp() )
00191         {
00192           PutEvent( *ev2 );
00193           ++cur_trk2ev;
00194         }
00195       } else if( has_ev1 && has_ev2 )
00196       {
00197         int trk=1;
00198         
00199         if( (ev1->GetTime() <= ev2->GetTime()) )
00200         {
00201           trk=1;
00202         }
00203         else
00204         {
00205           trk=2;
00206         }
00207         
00208         if( trk==1 )
00209         {
00210           if( ev1->GetTime() > last_data_end_time )
00211           {
00212             last_data_end_time = ev1->GetTime();
00213           }
00214           
00215           PutEvent( *ev1 );
00216           
00217           ++cur_trk1ev;
00218         }
00219         else
00220         {
00221           if( ev2->GetTime() > last_data_end_time )
00222           {
00223             last_data_end_time = ev2->GetTime();
00224           }
00225           
00226           PutEvent( *ev2 );
00227           ++cur_trk2ev;
00228         }
00229       }
00230     }
00231     
00232     // put single final data end event
00233     
00234     MIDITimedBigMessage dataend;
00235     
00236     dataend.SetTime( last_data_end_time );
00237     dataend.SetDataEnd();
00238     
00239     PutEvent( dataend );
00240   }
00241   
00242 #if 0
00243   bool  MIDITrack::Insert( int start_event, int num )
00244   {
00245     // TODO: Insert
00246     return true;
00247   }
00248   
00249   bool  MIDITrack::Delete( int start_event, int num  )
00250   {
00251     // TODO: Delete
00252     return true;
00253   }
00254   
00255   void  MIDITrack::QSort( int left, int right )
00256   {
00257     int i,j;
00258     MIDITimedBigMessage *x, y;
00259     
00260     i=left; j=right;
00261     
00262     // search for a non NOP message for our median
00263     
00264     int pos=(left+right)/2;
00265     
00266     for( ;pos<=right;++pos )
00267     {
00268       x=GetEventAddress(pos);
00269       if( x && !x->IsNoOp() ) 
00270         break;
00271     }
00272     if( GetEventAddress( pos )->IsNoOp() )
00273     {
00274       for( pos=(left+right)/2; pos>=left; --pos )
00275       {
00276         x = GetEventAddress(pos);
00277         if( x && !x->IsNoOp() )
00278           break;
00279       }
00280     }
00281     
00282     if( x && x->IsNoOp() )
00283       return;
00284     
00285     do
00286     {
00287       while( MIDITimedMessage::CompareEvents( *GetEventAddress(i), *x ) == 2 &&
00288              i<right ) ++i;
00289       
00290       while( MIDITimedMessage::CompareEvents( *x, *GetEventAddress(j) ) == 2 &&
00291              j>left ) --j;
00292       
00293       if( i<=j )
00294       {
00295         y=*GetEventAddress( i );
00296         *GetEventAddress( i ) = *GetEventAddress( j );
00297         *GetEventAddress( j ) = y;
00298         ++i;
00299         --j;
00300       }
00301       
00302     } while( i<=j );
00303     
00304     if( left<j )
00305     {
00306       QSort(left,j);
00307     }
00308     if( i<right )
00309     {
00310       QSort(i,right);
00311     }
00312     
00313   }
00314   
00315   
00316   void  MIDITrack::Sort()
00317   {
00318 //
00319 // A simple single buffer sorting algorithm.
00320 //
00321 // first, see if we need sorting by checking each element
00322 // with the next. they should all be in order.
00323 //
00324 // if not, do qsort algorithm
00325     
00326     unsigned int i;
00327     unsigned int first_out_of_order_item=0;
00328     
00329     for( i=0; i<num_events-1; ++i )
00330     {
00331       first_out_of_order_item=i+1;
00332       if( MIDITimedMessage::CompareEvents(
00333             *GetEventAddress(i),
00334             *GetEventAddress(first_out_of_order_item)
00335             )==1 )
00336         break;
00337     }
00338     
00339     if( first_out_of_order_item>=num_events-1 )
00340     {
00341 //    return;   // no need for sort
00342     }
00343     
00344     QSort(0,num_events-1);
00345   }
00346   
00347 #endif
00348   
00349   void  MIDITrack::Shrink() 
00350   {
00351     int num_chunks_used = (int)((num_events / MIDITrackChunkSize) +1);
00352     int num_chunks_alloced = (int)(buf_size/MIDITrackChunkSize);
00353     
00354     if( num_chunks_used < num_chunks_alloced )
00355     {
00356       for( int i=num_chunks_used; i<num_chunks_alloced; ++i )
00357       {
00358         delete(chunk[i]);
00359         chunk[i]=0;
00360       }
00361       buf_size=num_chunks_used * MIDITrackChunkSize;
00362     }
00363   } 
00364   
00365   bool  MIDITrack::Expand( int increase_amount )  
00366   {
00367     int num_chunks_to_expand = (int)((increase_amount/MIDITrackChunkSize)+1);
00368     int num_chunks_alloced = (int)(buf_size/MIDITrackChunkSize);
00369     int new_last_chunk_num= (int)(num_chunks_to_expand + num_chunks_alloced);
00370     
00371     if( new_last_chunk_num >= MIDIChunksPerTrack )
00372     {
00373       return false;
00374     }
00375     
00376     for( int i=num_chunks_alloced; i<new_last_chunk_num; ++i )
00377     {
00378       chunk[i]=new MIDITrackChunk;
00379       
00380       if( !chunk[i] )
00381       {
00382         buf_size=(i-1)*MIDITrackChunkSize;
00383         return false;
00384       }
00385     }
00386     
00387     buf_size=new_last_chunk_num * MIDITrackChunkSize;
00388     
00389     return true;    
00390   } 
00391   
00392   MIDITimedBigMessage * MIDITrack::GetEventAddress( int event_num ) 
00393   {
00394     return chunk[ event_num/(MIDITrackChunkSize) ]->GetEventAddress( 
00395       (event_num%MIDITrackChunkSize) );   
00396   } 
00397   
00398   const MIDITimedBigMessage * MIDITrack::GetEventAddress( int event_num ) const 
00399   {
00400     return chunk[ event_num/(MIDITrackChunkSize) ]->GetEventAddress( 
00401       (event_num%MIDITrackChunkSize) );       
00402   } 
00403   
00404   bool  MIDITrack::PutEvent( const MIDITimedBigMessage &msg ) 
00405   {
00406     if( num_events >= buf_size )
00407     {
00408       if( !Expand() )
00409         return false;
00410     }
00411     
00412     GetEventAddress( num_events++ )->Copy( msg );
00413     
00414     return true;
00415   } 
00416   
00417   bool  MIDITrack::PutEvent( const MIDITimedMessage &msg, MIDISystemExclusive *sysex )  
00418   {
00419     if( num_events >= buf_size )
00420     {
00421       if( !Expand() )
00422         return false;
00423     }
00424     
00425     MIDITimedBigMessage *e = GetEventAddress( num_events );
00426     
00427     e->Copy( msg );
00428     e->CopySysEx( sysex );
00429     
00430     ++num_events;
00431     
00432     return true;
00433   } 
00434   
00435   bool  MIDITrack::GetEvent( int event_num, MIDITimedBigMessage *msg ) const  
00436   {
00437     if( event_num >= num_events )
00438     {
00439       return false;
00440     }
00441     else
00442     {
00443       msg->Copy( *GetEventAddress( event_num ) );
00444       return true;
00445     }
00446   } 
00447   
00448   bool  MIDITrack::SetEvent( int event_num, const MIDITimedBigMessage &msg )  
00449   {
00450     if( event_num>=num_events )
00451     {
00452       return false;
00453     }
00454     else
00455     {
00456       GetEventAddress( event_num )->Copy( msg );
00457       return true;
00458     }
00459   } 
00460   
00461   bool  MIDITrack::MakeEventNoOp( int event_num ) 
00462   {
00463     if( event_num>=num_events )
00464     {
00465       return false;
00466     }
00467     else
00468     {
00469       MIDITimedBigMessage *ev = GetEventAddress( event_num );
00470       
00471       if( ev )
00472       {
00473         ev->ClearSysEx();
00474         ev->SetNoOp();
00475       }
00476       return true;
00477     }
00478   } 
00479   
00480   bool  MIDITrack::FindEventNumber( MIDIClockTime time, int *event_num ) const 
00481   {
00482     ENTER("MIDITrack::FindEventNumber( int , int * )");
00483     
00484     // TO DO: try make this a binary search
00485     
00486     for( int i=0; i<num_events; ++i )
00487     {
00488       const MIDITimedBigMessage *msg = GetEventAddress( i );
00489       
00490       if( msg->GetTime()>=time )
00491       {
00492         *event_num=i;
00493         return true;
00494       }
00495     }
00496     
00497     *event_num=num_events;
00498     return false;
00499   } 
00500   
00501   const MIDITimedBigMessage *MIDITrack::GetEvent( int event_num ) const 
00502   {
00503     if( event_num >= num_events )
00504     {
00505       return 0;
00506     }
00507     else
00508     {
00509       return GetEventAddress( event_num );
00510     }
00511     
00512   } 
00513   
00514   MIDITimedBigMessage *MIDITrack::GetEvent( int event_num ) 
00515   {
00516     if( event_num >= num_events )
00517     {
00518       return 0;
00519     }
00520     else
00521     {
00522       return GetEventAddress( event_num );
00523     }
00524     
00525   } 
00526   
00527   int MIDITrack::GetBufferSize()  const   
00528   { 
00529     return buf_size;    
00530   }
00531   
00532   int MIDITrack::GetNumEvents() const     
00533   { 
00534     return num_events;
00535   }
00536   
00537 }