|
CLAM-Development
1.3
|
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 #include <CLAM/MIDIDataTypes.hxx> 00029 00030 namespace MIDI 00031 { 00032 00033 class TempoImpl 00034 /* hidden implementation of class Tempo */ 00035 { 00036 friend class Tempo; 00037 private: 00038 Song* mSong; 00039 Track* mTrack; 00040 Track::EventIterator mIterator; 00041 int mUsPerQ; // microseconds per quarternote 00042 bool mHasTempo; 00043 00044 /* while iterating through the tempo events, we need to keep track of 00045 ** the time, by applying all the tempo changes and calculation the 00046 ** time increment. these two vars are used in the process 00047 */ 00048 int mLastTicks; 00049 int mLastTime; 00050 00051 TempoImpl(Song* song = 0,Track* track = 0) 00052 { 00053 Init(song,track); 00054 } 00055 00056 void Init(Song* song = 0,Track* track = 0) 00057 { 00058 mHasTempo=false; 00059 mSong = song; 00060 mTrack = track; 00061 if (mSong && mTrack==0) 00062 { 00063 for (int i=0;i<mSong->Tracks();i++) 00064 { 00065 Track* t = mSong->GetTrack(i); 00066 if (t->HasTempoEvents()) 00067 { 00068 mTrack = t; 00069 break; 00070 } 00071 } 00072 } 00073 if (mTrack) 00074 { 00075 mHasTempo=true; 00076 mIterator = mTrack->Begin(); 00077 } 00078 mUsPerQ = 500000; 00079 mLastTime = 0; 00080 mLastTicks = 0; 00081 } 00082 00083 Milliseconds TicksToTime(Ticks t) 00084 { 00085 if(!mHasTempo) 00086 { 00087 // return time based on tempo = 120 bpm because the track has not tempo events 00088 return (Milliseconds)((double)t*480.0/(double)mSong->GetTicksPerQ()); 00089 } 00090 00091 int i = 0; 00092 00093 /* move the iterator to the next tempo event */ 00094 while (mIterator!=mTrack->End()) 00095 { 00096 const Event &ev = **mIterator; 00097 if ( ev[0]==0xFF && ev[1]==0x51) 00098 { 00099 break; 00100 } 00101 mIterator++; 00102 } 00103 00104 /* if we are at the end of the tempo track, or we are at a tempo 00105 ** event _after_ Ticks t, then we start from the beginning 00106 */ 00107 if (mIterator==mTrack->End() || ((*mIterator)->GetTicks()>t)) 00108 { 00109 mIterator = mTrack->Begin(); 00110 mUsPerQ = 500000; 00111 mLastTime = 0; 00112 mLastTicks = 0; 00113 } 00114 00115 std::list<Event*>::const_iterator prevIterator = mIterator; 00116 00117 00118 /* look for the first tempo event after Ticks t, and adjust 00119 ** mLastTime and mLastTicks while doing this 00120 */ 00121 while (mIterator!=mTrack->End()) 00122 { 00123 const Event &ev = **mIterator; 00124 if ( ev[0]==0xFF && ev[1]==0x51 ) 00125 { 00126 if (ev.GetTicks()>t) 00127 { 00128 break; 00129 } 00130 00131 MetaEvent* ev = (MetaEvent*) *mIterator; 00132 00133 // the following is to say: 00134 // (ticks/ticksPerQ)*msPerQ 00135 // but we change the order to stay with integers 00136 mLastTime += 00137 ( (TInt64(ev->GetTicks() - mLastTicks) * TInt64(mUsPerQ)) / 00138 (TInt64(mSong->GetTicksPerQ())*TInt64(1000)) ); 00139 00140 mUsPerQ = 00141 (ev->mData[0]<<16) | 00142 (ev->mData[1]<<8) | 00143 (ev->mData[0]); 00144 00145 mLastTicks = ev->GetTicks(); 00146 00147 prevIterator = mIterator; 00148 } 00149 mIterator++; 00150 i++; 00151 } 00152 00153 /* move one back, to the event before or at Ticks t */ 00154 mIterator = prevIterator; 00155 00156 // the following is to say: 00157 // (ticks/ticksPerQ)*msPerQ 00158 // but we change the order to stay with integers 00159 return mLastTime + Milliseconds( 00160 (TInt64(t - mLastTicks) * TInt64(mUsPerQ)) / 00161 (TInt64(mSong->GetTicksPerQ())*TInt64(1000))); 00162 } 00163 }; 00164 00165 Tempo::Tempo(Song* song,Track* track) 00166 { 00167 mImpl = new TempoImpl(song,track); 00168 } 00169 00170 Tempo::~Tempo() 00171 { 00172 delete mImpl; 00173 } 00174 00175 void Tempo::Init(Song* song,Track* track) 00176 { 00177 mImpl->Init(song,track); 00178 } 00179 00180 Milliseconds Tempo::TicksToTime(Ticks t) 00181 { 00182 return mImpl->TicksToTime(t); 00183 } 00184 00185 }; 00186
1.7.6.1