MIDITempo.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
00003  * UNIVERSITAT POMPEU FABRA
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  *
00019  * MIDIFileReader C++ classes
00020  * This code is part of the CLAM library, but also usable stand-alone.
00021  * Maarten de Boer <mdeboer@iua.upf.es>
00022  *
00023  */
00024 #include "MIDITrack.hxx"
00025 #include "MIDISong.hxx"
00026 #include "MIDITempo.hxx"
00027 #include "Defines.hxx"
00028 
00029 namespace MIDI
00030 {
00031 
00032         class TempoImpl
00033         /* hidden implementation of class Tempo */
00034         {
00035         friend class Tempo;
00036         private:
00037                 Song* mSong;
00038                 Track* mTrack;
00039                 Track::EventIterator mIterator;
00040                 int mUsPerQ; // microseconds per quarternote
00041                 bool mHasTempo;
00042                 
00043                 /* while iterating through the tempo events, we need to keep track of
00044                 ** the time, by applying all the tempo changes and calculation the 
00045                 ** time increment. these two vars are used in the process
00046                 */
00047                 int mLastTicks; 
00048                 int mLastTime;
00049                 
00050                 TempoImpl(Song* song = 0,Track* track = 0)
00051                 {
00052                         Init(song,track);
00053                 }
00054                 
00055                 void Init(Song* song = 0,Track* track = 0)
00056                 {
00057                         mHasTempo=false;
00058                         mSong = song;
00059                         mTrack = track;
00060                         if (mSong && mTrack==0)
00061                         {
00062                                 for (int i=0;i<mSong->Tracks();i++)
00063                                 {
00064                                         Track* t = mSong->GetTrack(i);
00065                                         if (t->HasTempoEvents())
00066                                         {
00067                                                 mTrack = t;
00068                                                 break;
00069                                         }
00070                                 }
00071                         }
00072                         if (mTrack)
00073                         {
00074                                 mHasTempo=true;
00075                                 mIterator = mTrack->Begin();
00076                         }
00077                         mUsPerQ = 500000;
00078                         mLastTime = 0;
00079                         mLastTicks = 0;
00080                 }
00081 
00082                 Milliseconds TicksToTime(Ticks t)
00083                 {
00084                         if(!mHasTempo)
00085                         {
00086                                 // return time based on tempo = 120 bpm because the track has not tempo events
00087                                 return (Milliseconds)((double)t*480.0/(double)mSong->GetTicksPerQ());
00088                         }
00089 
00090                         int i = 0;
00091 
00092                         /* move the iterator to the next tempo event */
00093                         while (mIterator!=mTrack->End())
00094                         {
00095                                 const Event &ev = **mIterator;
00096                                 if ( ev[0]==0xFF && ev[1]==0x51)
00097                                 {
00098                                         break;
00099                                 }
00100                                 mIterator++;
00101                         }
00102 
00103                         /* if we are at the end of the tempo track, or we are at a tempo 
00104                         ** event _after_ Ticks t, then we start from the beginning
00105                         */
00106                         if (mIterator==mTrack->End() || ((*mIterator)->GetTicks()>t))
00107                         {
00108                                 mIterator = mTrack->Begin();
00109                                 mUsPerQ = 500000;
00110                                 mLastTime = 0;
00111                                 mLastTicks = 0;
00112                         }
00113 
00114                         std::list<Event*>::const_iterator prevIterator = mIterator;
00115 
00116 
00117                         /* look for the first tempo event after Ticks t, and adjust
00118                         ** mLastTime and mLastTicks while doing this
00119                         */
00120                         while (mIterator!=mTrack->End())
00121                         {
00122                                 const Event &ev = **mIterator;
00123                                 if ( ev[0]==0xFF && ev[1]==0x51 )
00124                                 {
00125                                         if (ev.GetTicks()>t)
00126                                         {
00127                                                 break;
00128                                         }
00129 
00130                                         MetaEvent* ev = (MetaEvent*) *mIterator;
00131 
00132                                         // the following is to say: 
00133                                         // (ticks/ticksPerQ)*msPerQ
00134                                         // but we change the order to stay with integers
00135                                         mLastTime += 
00136                                                 ( (TInt64(ev->GetTicks() - mLastTicks) * TInt64(mUsPerQ)) / 
00137                                                         (TInt64(mSong->GetTicksPerQ())*TInt64(1000)) );
00138 
00139                                         mUsPerQ = 
00140                                                 (ev->mData[0]<<16) | 
00141                                                 (ev->mData[1]<<8) |
00142                                                 (ev->mData[0]);
00143 
00144                                         mLastTicks = ev->GetTicks();
00145 
00146                                         prevIterator = mIterator;
00147                                 }
00148                                 mIterator++;
00149                                 i++;
00150                         }
00151 
00152                         /* move one back, to the event before or at Ticks t */
00153                         mIterator = prevIterator;
00154 
00155                         // the following is to say: 
00156                         // (ticks/ticksPerQ)*msPerQ
00157                         // but we change the order to stay with integers
00158                         return mLastTime + Milliseconds(
00159                                         (TInt64(t - mLastTicks) * TInt64(mUsPerQ)) / 
00160                                         (TInt64(mSong->GetTicksPerQ())*TInt64(1000))); 
00161                 }
00162         };
00163 
00164         Tempo::Tempo(Song* song,Track* track)
00165         {
00166                 mImpl = new TempoImpl(song,track);
00167         }
00168 
00169         Tempo::~Tempo()
00170         {
00171                 delete mImpl;
00172         }
00173 
00174         void Tempo::Init(Song* song,Track* track)
00175         {
00176                 mImpl->Init(song,track);
00177         }
00178         
00179         Milliseconds Tempo::TicksToTime(Ticks t)
00180         {
00181                 return mImpl->TicksToTime(t);
00182         }
00183         
00184 };
00185 

Generated on Tue Aug 12 22:33:43 2008 for CLAM by  doxygen 1.5.5