All Classes Namespaces Functions Variables Enumerations Properties Pages
soundmanager.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5 Copyright (C) 2012-2020 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 "soundmanager.h"
19 
20 #include <QString>
21 #include <QFileInfo>
22 #include "editor.h"
23 #include "object.h"
24 #include "layersound.h"
25 #include "soundclip.h"
26 #include "soundplayer.h"
27 #include "layermanager.h"
28 
29 SoundManager::SoundManager(Editor* editor) : BaseManager(editor, __FUNCTION__)
30 {
31 }
32 
33 SoundManager::~SoundManager()
34 {
35 }
36 
37 bool SoundManager::init()
38 {
39  return true;
40 }
41 
42 Status SoundManager::load(Object* obj)
43 {
44  int count = obj->getLayerCount();
45  for (int i = 0; i < count; ++i)
46  {
47  Layer* layer = obj->getLayer(i);
48  if (layer->type() != Layer::SOUND)
49  {
50  continue;
51  }
52 
53  LayerSound* soundLayer = static_cast<LayerSound*>(layer);
54 
55  soundLayer->foreachKeyFrame([this](KeyFrame* key)
56  {
57  SoundClip* clip = dynamic_cast<SoundClip*>(key);
58  Q_ASSERT(clip);
59 
60  createMediaPlayer(clip);
61  });
62  }
63  return Status::OK;
64 }
65 
66 Status SoundManager::save(Object*)
67 {
68  return Status::OK;
69 }
70 
71 Status SoundManager::loadSound(Layer* soundLayer, int frameNumber, QString soundFilePath)
72 {
73  Q_ASSERT(soundLayer);
74  if (soundLayer->type() != Layer::SOUND)
75  {
76  return Status::ERROR_INVALID_LAYER_TYPE;
77  }
78 
79  if (frameNumber < 0)
80  {
81  return Status::ERROR_INVALID_FRAME_NUMBER;
82  }
83 
84  if (!QFile::exists(soundFilePath))
85  {
86  return Status::FILE_NOT_FOUND;
87  }
88 
89  KeyFrame* key = soundLayer->getKeyFrameAt(frameNumber);
90  if (key == nullptr)
91  {
92  key = new SoundClip;
93  soundLayer->addKeyFrame(frameNumber, key);
94  }
95 
96  if (!key->fileName().isEmpty())
97  {
98  // file path should be empty.
99  // we can only load a audio clip to an empty key!
100  return Status::FAIL;
101  }
102 
103  QString strCopyFile = soundLayer->object()->copyFileToDataFolder(soundFilePath);
104  Q_ASSERT(!strCopyFile.isEmpty());
105 
106  QString sOriginalName = QFileInfo(soundFilePath).fileName();
107 
108  SoundClip* soundClip = dynamic_cast<SoundClip*>(key);
109  soundClip->init(strCopyFile);
110  soundClip->setSoundClipName(sOriginalName);
111 
112  Status st = createMediaPlayer(soundClip);
113  if (!st.ok())
114  {
115  delete soundClip;
116  return st;
117  }
118 
119  return Status::OK;
120 }
121 
122 Status SoundManager::loadSound(SoundClip* soundClip, QString strSoundFile)
123 {
124  Q_ASSERT(soundClip);
125 
126  if (!QFile::exists(strSoundFile))
127  {
128  return Status::FILE_NOT_FOUND;
129  }
130 
131  if (strSoundFile.isEmpty())
132  {
133  return Status::FAIL;
134  }
135 
136  QString strCopyFile = editor()->object()->copyFileToDataFolder(strSoundFile);
137  Q_ASSERT(!strCopyFile.isEmpty());
138 
139  soundClip->init(strCopyFile);
140  if (soundClip->soundClipName().isEmpty())
141  {
142  soundClip->setSoundClipName(QFileInfo(strSoundFile).fileName());
143  }
144 
145  Status st = createMediaPlayer(soundClip);
146  if (!st.ok())
147  {
148  delete soundClip;
149  return st;
150  }
151 
152  editor()->layers()->notifyAnimationLengthChanged();
153 
154  return Status::OK;
155 }
156 
157 Status SoundManager::processSound(SoundClip* soundClip)
158 {
159  Q_ASSERT(soundClip);
160 
161  if (!QFile::exists(soundClip->fileName()))
162  {
163  return Status::FILE_NOT_FOUND;
164  }
165  soundClip->init(soundClip->fileName());
166 
167  Status st = createMediaPlayer(soundClip);
168  if (!st.ok())
169  {
170  return st;
171  }
172  return Status::OK;
173 }
174 
175 int SoundManager::soundClipCount() const
176 {
177  LayerManager *layerManager = editor()->layers();
178  int totalCount = 0;
179 
180 
181  for (int i = 0; i < layerManager->count(); ++i)
182  {
183  Layer* layer = layerManager->getLayer(i);
184  if (layer->type() != Layer::SOUND)
185  {
186  continue;
187  }
188 
189  totalCount += layer->keyFrameCount();
190  }
191  return totalCount;
192 }
193 
194 void SoundManager::onDurationChanged(SoundPlayer* player, int64_t duration)
195 {
196  SoundClip* clip = player->clip();
197 
198  double fps = static_cast<double>(editor()->fps());
199 
200  double frameLength = duration * fps / 1000.0;
201  clip->setLength(static_cast<int>(frameLength));
202  clip->setDuration(duration);
203 
204  editor()->layers()->notifyAnimationLengthChanged();
205 
206  emit soundClipDurationChanged();
207 }
208 
209 Status SoundManager::createMediaPlayer(SoundClip* clip)
210 {
211  SoundPlayer* newPlayer = new SoundPlayer();
212  newPlayer->init(clip);
213 
214  connect(newPlayer, &SoundPlayer::durationChanged, this, &SoundManager::onDurationChanged);
215 
216  return Status::OK;
217 }
bool exists() const const
QString fileName() const const
bool isEmpty() const const
Definition: layer.h:38
Definition: object.h:41
Definition: editor.h:55
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void notifyAnimationLengthChanged()
This should be emitted whenever the animation length frames, eg.