Pencil2D  ff90c0872e88be3bf81c548cd60f01983012ec49
Pencil2D is an animation software for both bitmap and vector graphics. It is free, multi-platform, and open source.
 All Classes Functions
playbackmanager.cpp
1 /*
2 
3 Pencil - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2017 Matthew Chiawen Chang
6 
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 */
17 
18 #include "playbackmanager.h"
19 
20 #include <QTimer>
21 #include "object.h"
22 #include "editor.h"
23 #include "layersound.h"
24 #include "layermanager.h"
25 #include "soundmanager.h"
26 #include "soundclip.h"
27 #include "soundplayer.h"
28 
29 PlaybackManager::PlaybackManager( QObject* parent ) : BaseManager( parent )
30 {
31 }
32 
33 bool PlaybackManager::init()
34 {
35  mTimer = new QTimer( this );
36  connect( mTimer, &QTimer::timeout, this, &PlaybackManager::timerTick );
37  return true;
38 }
39 
40 Status PlaybackManager::load( Object* o )
41 {
42  const ObjectData* e = o->data();
43 
44  mIsLooping = e->isLooping();
45  mIsRangedPlayback = e->isRangedPlayback();
46  mMarkInFrame = e->getMarkInFrameNumber();
47  mMarkOutFrame = e->getMarkOutFrameNumber();
48  mFps = e->getFrameRate();
49 
50  return Status::OK;
51 }
52 
53 Status PlaybackManager::save( Object* o )
54 {
55  ObjectData* data = o->data();
56  data->setLooping( mIsLooping );
57  data->setRangedPlayback( mIsRangedPlayback );
58  data->setMarkInFrameNumber( mMarkInFrame );
59  data->setMarkOutFrameNumber( mMarkOutFrame );
60  data->setFrameRate( mFps );
61  return Status::OK;
62 }
63 
64 bool PlaybackManager::isPlaying()
65 {
66  return mTimer->isActive();
67 }
68 
69 void PlaybackManager::play()
70 {
71  int projectLength = editor()->layers()->projectLength();
72 
73  mStartFrame = ( mIsRangedPlayback ) ? mMarkInFrame : 1;
74  mEndFrame = ( mIsRangedPlayback ) ? mMarkOutFrame : projectLength;
75 
76  if ( editor()->currentFrame() >= mEndFrame )
77  {
78  editor()->scrubTo( mStartFrame );
79  }
80 
81  mTimer->setInterval( 1000.0f / mFps );
82  mTimer->start();
83 
84  // Check for any sounds we should start playing part-way through.
85  mCheckForSoundsHalfway = true;
86 
87  emit playStateChanged(true);
88 }
89 
90 void PlaybackManager::stop()
91 {
92  mTimer->stop();
93  stopSounds();
94  emit playStateChanged(false);
95 }
96 
97 void PlaybackManager::setFps( int fps )
98 {
99  if ( mFps != fps )
100  {
101  mFps = fps;
102  emit fpsChanged( mFps );
103 
104  // Update key-frame lengths of sound layers,
105  // since the length depends on fps.
106  for ( int i = 0; i < object()->getLayerCount(); ++i )
107  {
108  Layer* layer = object()->getLayer( i );
109  if ( layer->type() == Layer::SOUND )
110  {
111  auto soundLayer = dynamic_cast<LayerSound *>(layer);
112  soundLayer->updateFrameLengths(mFps);
113  }
114  }
115  }
116 }
117 
118 void PlaybackManager::playSounds( int frame )
119 {
120  // If sound is turned off, don't play anything.
121  if(!mIsPlaySound)
122  {
123  return;
124  }
125 
126  std::vector< LayerSound* > kSoundLayers;
127  for ( int i = 0; i < object()->getLayerCount(); ++i )
128  {
129  Layer* layer = object()->getLayer( i );
130  if ( layer->type() == Layer::SOUND )
131  {
132  kSoundLayers.push_back( static_cast< LayerSound* >( layer ) );
133  }
134  }
135 
136  for ( LayerSound* layer : kSoundLayers )
137  {
138  if (mCheckForSoundsHalfway)
139  {
140  // Check for sounds which we should start playing from part-way through.
141  if ( layer->keyExistsWhichCovers( frame ) )
142  {
143  KeyFrame* key = layer->getKeyFrameWhichCovers( frame );
144  SoundClip* clip = static_cast< SoundClip* >( key );
145 
146  clip->playFromPosition(frame, mFps);
147  }
148 
149  // Set flag to false, since this check should only be done when
150  // starting play-back, or when looping.
151  mCheckForSoundsHalfway = false;
152  }
153  else if ( layer->keyExists( frame ) )
154  {
155  KeyFrame* key = layer->getKeyFrameAt( frame );
156  SoundClip* clip = static_cast< SoundClip* >( key );
157 
158  clip->play();
159 
160  // save the position of our active sound frame
161  mActiveSoundFrame = frame;
162  }
163 
164  if ( frame >= mEndFrame )
165  {
166  KeyFrame* key = layer->getKeyFrameWhichCovers( mActiveSoundFrame );
167  SoundClip* clip = static_cast< SoundClip* >( key );
168  clip->stop();
169  }
170  }
171 }
172 
173 void PlaybackManager::stopSounds()
174 {
175  std::vector< LayerSound* > kSoundLayers;
176  for ( int i = 0; i < object()->getLayerCount(); ++i )
177  {
178  Layer* layer = object()->getLayer( i );
179  if ( layer->type() == Layer::SOUND )
180  {
181  kSoundLayers.push_back( static_cast< LayerSound* >( layer ) );
182  }
183  }
184 
185  for ( LayerSound* layer : kSoundLayers )
186  {
187  layer->foreachKeyFrame( []( KeyFrame* key )
188  {
189  SoundClip* clip = static_cast< SoundClip* >( key );
190  clip->stop();
191  } );
192  }
193 }
194 
195 void PlaybackManager::timerTick()
196 {
197  playSounds( editor()->currentFrame() );
198 
199  if ( editor()->currentFrame() >= mEndFrame )
200  {
201  if ( mIsLooping )
202  {
203  editor()->scrubTo( mStartFrame );
204  mCheckForSoundsHalfway = true;
205  }
206  else
207  {
208  stop();
209  }
210  }
211  else
212  {
213  editor()->scrubForward();
214  }
215 }
216 
217 void PlaybackManager::setLooping( bool isLoop )
218 {
219  if ( mIsLooping != isLoop )
220  {
221  mIsLooping = isLoop;
222  emit loopStateChanged( mIsLooping );
223  }
224 }
225 
226 void PlaybackManager::enableRangedPlayback( bool b )
227 {
228  if ( mIsRangedPlayback != b )
229  {
230  mIsRangedPlayback = b;
231  emit rangedPlaybackStateChanged( mIsRangedPlayback );
232  }
233 }
234 
235 void PlaybackManager::enableSound(bool b)
236 {
237  mIsPlaySound = b;
238 
239  if(!mIsPlaySound)
240  {
241  stopSounds();
242 
243  // If, during playback, the sound is turned on again,
244  // check for sounds partway through.
245  mCheckForSoundsHalfway = true;
246  }
247 }
248 
249 
Definition: layer.h:32
Definition: object.h:71