1 /* 2 * Song.h - class song - the root of the model-tree 3 * 4 * Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net> 5 * 6 * This file is part of LMMS - https://lmms.io 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public 19 * License along with this program (see COPYING); if not, write to the 20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301 USA. 22 * 23 */ 24 25 #ifndef SONG_H 26 #define SONG_H 27 28 #include <utility> 29 30 #include <QtCore/QSharedMemory> 31 #include <QtCore/QVector> 32 33 #include "TrackContainer.h" 34 #include "Controller.h" 35 #include "MeterModel.h" 36 #include "Mixer.h" 37 #include "VstSyncController.h" 38 39 40 class AutomationTrack; 41 class Pattern; 42 class TimeLineWidget; 43 44 45 const bpm_t MinTempo = 10; 46 const bpm_t DefaultTempo = 140; 47 const bpm_t MaxTempo = 999; 48 const tick_t MaxSongLength = 9999 * DefaultTicksPerTact; 49 50 51 class EXPORT Song : public TrackContainer 52 { 53 Q_OBJECT 54 mapPropertyFromModel( int,getTempo,setTempo,m_tempoModel ); 55 mapPropertyFromModel( int,masterPitch,setMasterPitch,m_masterPitchModel ); 56 mapPropertyFromModel( int,masterVolume,setMasterVolume, m_masterVolumeModel ); 57 public: 58 enum PlayModes 59 { 60 Mode_None, 61 Mode_PlaySong, 62 Mode_PlayBB, 63 Mode_PlayPattern, 64 Mode_PlayAutomationPattern, 65 Mode_Count 66 } ; 67 68 void clearErrors(); 69 void collectError( const QString error ); 70 bool hasErrors(); 71 QString errorSummary(); 72 73 class PlayPos : public MidiTime 74 { 75 public: 76 PlayPos( const int abs = 0 ) : MidiTime(abs)77 MidiTime( abs ), 78 m_timeLine( NULL ), 79 m_currentFrame( 0.0f ) 80 { 81 } setCurrentFrame(const float f)82 inline void setCurrentFrame( const float f ) 83 { 84 m_currentFrame = f; 85 } currentFrame()86 inline float currentFrame() const 87 { 88 return m_currentFrame; 89 } setJumped(const bool jumped)90 inline void setJumped( const bool jumped ) 91 { 92 m_jumped = jumped; 93 } jumped()94 inline bool jumped() const 95 { 96 return m_jumped; 97 } 98 TimeLineWidget * m_timeLine; 99 100 private: 101 float m_currentFrame; 102 bool m_jumped; 103 104 } ; 105 106 107 108 void processNextBuffer(); 109 getLoadingTrackCount()110 inline int getLoadingTrackCount() const 111 { 112 return m_nLoadingTrack; 113 } getMilliseconds()114 inline int getMilliseconds() const 115 { 116 return m_elapsedMilliSeconds; 117 } setMilliSeconds(float ellapsedMilliSeconds)118 inline void setMilliSeconds( float ellapsedMilliSeconds ) 119 { 120 m_elapsedMilliSeconds = ellapsedMilliSeconds; 121 } getTacts()122 inline int getTacts() const 123 { 124 return currentTact(); 125 } 126 ticksPerTact()127 inline int ticksPerTact() const 128 { 129 return MidiTime::ticksPerTact(m_timeSigModel); 130 } 131 132 // Returns the beat position inside the bar, 0-based getBeat()133 inline int getBeat() const 134 { 135 return getPlayPos().getBeatWithinBar(m_timeSigModel); 136 } 137 // the remainder after bar and beat are removed getBeatTicks()138 inline int getBeatTicks() const 139 { 140 return getPlayPos().getTickWithinBeat(m_timeSigModel); 141 } getTicks()142 inline int getTicks() const 143 { 144 return currentTick(); 145 } getFrames()146 inline f_cnt_t getFrames() const 147 { 148 return currentFrame(); 149 } isPaused()150 inline bool isPaused() const 151 { 152 return m_paused; 153 } 154 isPlaying()155 inline bool isPlaying() const 156 { 157 return m_playing == true && m_exporting == false; 158 } 159 isStopped()160 inline bool isStopped() const 161 { 162 return m_playing == false && m_paused == false; 163 } 164 isExporting()165 inline bool isExporting() const 166 { 167 return m_exporting; 168 } 169 setExportLoop(bool exportLoop)170 inline void setExportLoop( bool exportLoop ) 171 { 172 m_exportLoop = exportLoop; 173 } 174 isRecording()175 inline bool isRecording() const 176 { 177 return m_recording; 178 } 179 180 bool isExportDone() const; 181 std::pair<MidiTime, MidiTime> getExportEndpoints() const; 182 setRenderBetweenMarkers(bool renderBetweenMarkers)183 inline void setRenderBetweenMarkers( bool renderBetweenMarkers ) 184 { 185 m_renderBetweenMarkers = renderBetweenMarkers; 186 } 187 playMode()188 inline PlayModes playMode() const 189 { 190 return m_playMode; 191 } 192 getPlayPos(PlayModes pm)193 inline PlayPos & getPlayPos( PlayModes pm ) 194 { 195 return m_playPos[pm]; 196 } getPlayPos(PlayModes pm)197 inline const PlayPos & getPlayPos( PlayModes pm ) const 198 { 199 return m_playPos[pm]; 200 } getPlayPos()201 inline const PlayPos & getPlayPos() const 202 { 203 return getPlayPos(m_playMode); 204 } 205 206 void updateLength(); length()207 tact_t length() const 208 { 209 return m_length; 210 } 211 212 213 bpm_t getTempo(); 214 virtual AutomationPattern * tempoAutomationPattern(); 215 globalAutomationTrack()216 AutomationTrack * globalAutomationTrack() 217 { 218 return m_globalAutomationTrack; 219 } 220 221 //TODO: Add Q_DECL_OVERRIDE when Qt4 is dropped 222 AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const; 223 224 // file management 225 void createNewProject(); 226 void createNewProjectFromTemplate( const QString & templ ); 227 void loadProject( const QString & filename ); 228 bool guiSaveProject(); 229 bool guiSaveProjectAs( const QString & filename ); 230 bool saveProjectFile( const QString & filename ); 231 projectFileName()232 const QString & projectFileName() const 233 { 234 return m_fileName; 235 } 236 isLoadingProject()237 bool isLoadingProject() const 238 { 239 return m_loadingProject; 240 } 241 loadingCancelled()242 void loadingCancelled() 243 { 244 m_isCancelled = true; 245 Engine::mixer()->clearNewPlayHandles(); 246 } 247 isCancelled()248 bool isCancelled() 249 { 250 return m_isCancelled; 251 } 252 isModified()253 bool isModified() const 254 { 255 return m_modified; 256 } 257 nodeName()258 virtual QString nodeName() const 259 { 260 return "song"; 261 } 262 fixedTCOs()263 virtual bool fixedTCOs() const 264 { 265 return false; 266 } 267 268 void addController( Controller * c ); 269 void removeController( Controller * c ); 270 271 controllers()272 const ControllerVector & controllers() const 273 { 274 return m_controllers; 275 } 276 277 getTimeSigModel()278 MeterModel & getTimeSigModel() 279 { 280 return m_timeSigModel; 281 } 282 283 284 public slots: 285 void playSong(); 286 void record(); 287 void playAndRecord(); 288 void playBB(); 289 void playPattern( const Pattern * patternToPlay, bool loop = true ); 290 void togglePause(); 291 void stop(); 292 293 void importProject(); 294 void exportProject( bool multiExport = false ); 295 void exportProjectTracks(); 296 void exportProjectMidi(); 297 298 void startExport(); 299 void stopExport(); 300 301 302 void setModified(); 303 304 void clearProject(); 305 306 void addBBTrack(); 307 308 309 private slots: 310 void insertBar(); 311 void removeBar(); 312 void addSampleTrack(); 313 void addAutomationTrack(); 314 315 void setTempo(); 316 void setTimeSignature(); 317 318 void masterVolumeChanged(); 319 320 void savePos(); 321 322 void updateFramesPerTick(); 323 324 325 326 private: 327 Song(); 328 Song( const Song & ); 329 virtual ~Song(); 330 331 currentTact()332 inline tact_t currentTact() const 333 { 334 return m_playPos[m_playMode].getTact(); 335 } 336 currentTick()337 inline tick_t currentTick() const 338 { 339 return m_playPos[m_playMode].getTicks(); 340 } 341 currentFrame()342 inline f_cnt_t currentFrame() const 343 { 344 return m_playPos[m_playMode].getTicks() * Engine::framesPerTick() + 345 m_playPos[m_playMode].currentFrame(); 346 } 347 348 void setPlayPos( tick_t ticks, PlayModes playMode ); 349 350 void saveControllerStates( QDomDocument & doc, QDomElement & element ); 351 void restoreControllerStates( const QDomElement & element ); 352 353 void removeAllControllers(); 354 355 void processAutomations(const TrackList& tracks, MidiTime timeStart, fpp_t frames); 356 357 AutomationTrack * m_globalAutomationTrack; 358 359 IntModel m_tempoModel; 360 MeterModel m_timeSigModel; 361 int m_oldTicksPerTact; 362 IntModel m_masterVolumeModel; 363 IntModel m_masterPitchModel; 364 365 ControllerVector m_controllers; 366 367 int m_nLoadingTrack; 368 369 QString m_fileName; 370 QString m_oldFileName; 371 bool m_modified; 372 bool m_loadOnLaunch; 373 374 volatile bool m_recording; 375 volatile bool m_exporting; 376 volatile bool m_exportLoop; 377 volatile bool m_renderBetweenMarkers; 378 volatile bool m_playing; 379 volatile bool m_paused; 380 381 bool m_loadingProject; 382 bool m_isCancelled; 383 384 QStringList m_errors; 385 386 PlayModes m_playMode; 387 PlayPos m_playPos[Mode_Count]; 388 tact_t m_length; 389 390 const Pattern* m_patternToPlay; 391 bool m_loopPattern; 392 393 double m_elapsedMilliSeconds; 394 tick_t m_elapsedTicks; 395 tact_t m_elapsedTacts; 396 397 VstSyncController m_vstSyncController; 398 399 400 friend class LmmsCore; 401 friend class SongEditor; 402 friend class mainWindow; 403 friend class ControllerRackView; 404 405 signals: 406 void projectLoaded(); 407 void playbackStateChanged(); 408 void playbackPositionChanged(); 409 void lengthChanged( int tacts ); 410 void tempoChanged( bpm_t newBPM ); 411 void timeSignatureChanged( int oldTicksPerTact, int ticksPerTact ); 412 void controllerAdded( Controller * ); 413 void controllerRemoved( Controller * ); 414 void updateSampleTracks(); 415 416 } ; 417 418 419 #endif 420