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