]> git.sesse.net Git - kdenlive/blob - src/timecode.cpp
Improved timeline ruler
[kdenlive] / src / timecode.cpp
1 /***************************************************************************
2                           timecode  -  description
3                              -------------------
4     begin                : Wed Dec 17 2003
5     copyright            : (C) 2003 by Jason Wood
6     email                : jasonwood@blueyonder.co.uk
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #include "timecode.h"
18
19 #include <kdebug.h>
20 #include <klocale.h>
21
22 Timecode::Timecode(Formats format, int framesPerSecond,
23                    bool dropFrame): m_format(format), m_dropFrame(dropFrame),
24         m_displayedFramesPerSecond(framesPerSecond) {
25 }
26
27 Timecode::~Timecode() {
28 }
29
30 int Timecode::fps() {
31     return m_displayedFramesPerSecond;
32 }
33
34
35 int Timecode::getFrameCount(const QString duration, double fps) const {
36     if (m_dropFrame) {
37         // calculate how many frames need to be dropped every minute.
38         int frames;
39         int toDrop = (int) floor(600.0 * (m_displayedFramesPerSecond - fps)  + 0.5);
40
41         int perMinute = toDrop / 9;
42         int tenthMinute = toDrop % 9;
43
44         // calculate how many frames are in a normal minute, and how many are in a tenth minute.
45         int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - perMinute;
46         int tenthMinuteFrames = (m_displayedFramesPerSecond * 60) - tenthMinute;;
47
48         // Number of actual frames in a 10 minute interval :
49         int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames;
50         frames = 6 * duration.section(":", 0, 0).toInt() * tenMinutes;
51         int minutes = duration.section(":", 1, 1).toInt();
52         frames += ((int) minutes / 10) * tenMinutes;
53         int mins = minutes % 10;
54         if (mins > 0) {
55             frames += tenthMinuteFrames;
56             mins--;
57             if (mins > 0) frames += mins * normalMinuteFrames;
58         }
59         if (minutes % 10 > 0) frames -= perMinute;
60         frames += duration.section(":", 2, 2).toInt() * m_displayedFramesPerSecond + duration.section(":", 3, 3).toInt();
61         return frames;
62     }
63     return (int)((duration.section(":", 0, 0).toInt()*3600.0 + duration.section(":", 1, 1).toInt()*60.0 + duration.section(":", 2, 2).toInt()) * fps + duration.section(":", 3, 3).toInt());
64 }
65
66 QString Timecode::getTimecode(const GenTime & time, double fps) const {
67     switch (m_format) {
68     case HH_MM_SS_FF:
69         return getTimecodeHH_MM_SS_FF(time, fps);
70         break;
71     case HH_MM_SS_HH:
72         return getTimecodeHH_MM_SS_HH(time);
73         break;
74     case Frames:
75         return getTimecodeFrames(time, fps);
76         break;
77     case Seconds:
78         return getTimecodeSeconds(time);
79         break;
80     default:
81         kWarning() <<
82         "Unknown timecode format specified, defaulting to HH_MM_SS_FF"
83         << endl;
84         return getTimecodeHH_MM_SS_FF(time, fps);
85     }
86 }
87
88 QString Timecode::getTimecodeFromFrames(int frames) {
89     return getTimecodeHH_MM_SS_FF(frames);
90 }
91
92 //static
93 QString Timecode::getEasyTimecode(const GenTime & time, const double &fps) {
94     // Returns the timecode in an easily read display, like 3 min. 5 sec.
95     int frames = (int)time.frames(fps);
96     int seconds = frames / (int) floor(fps + 0.5);
97     frames = frames % ((int) fps);
98
99     int minutes = seconds / 60;
100     seconds = seconds % 60;
101     int hours = minutes / 60;
102     minutes = minutes % 60;
103
104     QString text;
105     bool trim = false;
106
107     if (hours != 0) {
108         text.append(QString::number(hours).rightJustified(2, '0', FALSE));
109         text.append(" " + i18n("hour") + " ");
110         trim = true;
111     }
112     if (minutes != 0 || trim) {
113         if (!trim) {
114             text.append(QString::number(minutes));
115         } else
116             text.append(QString::number(minutes).rightJustified(2, '0', FALSE));
117         text.append(" " + i18n("min.") + " ");
118         trim = true;
119     }
120     if (seconds != 0 || trim) {
121         if (!trim) {
122             text.append(QString::number(seconds));
123         } else
124             text.append(QString::number(seconds).rightJustified(2, '0', FALSE));
125         text.append(" " + i18n("sec."));
126         trim = true;
127     }
128     if (!trim) {
129         text.append(QString::number(frames));
130         text.append(" " + i18n("frames"));
131     }
132
133     return text;
134 }
135
136
137 QString Timecode::getTimecodeHH_MM_SS_FF(const GenTime & time, double fps) const {
138     if (m_dropFrame)
139         return getTimecodeDropFrame(time, fps);
140
141     return getTimecodeHH_MM_SS_FF((int)time.frames(fps));
142 }
143
144 QString Timecode::getTimecodeHH_MM_SS_FF(int frames) const {
145     int seconds = frames / m_displayedFramesPerSecond;
146     frames = frames % m_displayedFramesPerSecond;
147
148     int minutes = seconds / 60;
149     seconds = seconds % 60;
150     int hours = minutes / 60;
151     minutes = minutes % 60;
152
153     QString text;
154
155     text.append(QString::number(hours).rightJustified(2, '0', FALSE));
156     text.append(":");
157     text.append(QString::number(minutes).rightJustified(2, '0', FALSE));
158     text.append(":");
159     text.append(QString::number(seconds).rightJustified(2, '0', FALSE));
160     text.append(":");
161     text.append(QString::number(frames).rightJustified(2, '0', FALSE));
162
163     return text;
164 }
165
166 QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const {
167     int hundredths = (int)(time.seconds() * 100);
168     int seconds = hundredths / 100;
169     hundredths = hundredths % 100;
170     int minutes = seconds / 60;
171     seconds = seconds % 60;
172     int hours = minutes / 60;
173     minutes = minutes % 60;
174
175     QString text;
176
177     text.append(QString::number(hours).rightJustified(2, '0', FALSE));
178     text.append(":");
179     text.append(QString::number(minutes).rightJustified(2, '0', FALSE));
180     text.append(":");
181     text.append(QString::number(seconds).rightJustified(2, '0', FALSE));
182     text.append(":");
183     text.append(QString::number(hundredths).rightJustified(2, '0', FALSE));
184
185     return text;
186 }
187
188 QString Timecode::getTimecodeFrames(const GenTime & time, double fps) const {
189     return QString::number(time.frames(fps));
190 }
191
192 QString Timecode::getTimecodeSeconds(const GenTime & time) const {
193     return QString::number(time.seconds());
194 }
195
196 QString Timecode::getTimecodeDropFrame(const GenTime & time, double fps) const {
197     // Calculate the timecode using dropframes to remove the difference in fps. Note that this algorithm should work
198     // for NTSC times, but is untested for any others - it is in no way an "official" algorithm, unless it's by fluke.
199     int frames = (int)time.frames(fps);
200
201     // calculate how many frames need to be dropped every minute.
202     int toDrop = (int) floor(600.0 * (m_displayedFramesPerSecond - fps)  + 0.5);
203
204     int perMinute = toDrop / 9;
205     int tenthMinute = toDrop % 9;
206
207     // calculate how many frames are in a normal minute, and how many are in a tenth minute.
208     int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - perMinute;
209     int tenthMinuteFrames = (m_displayedFramesPerSecond * 60) - tenthMinute;;
210
211     // Number of actual frames in a 10 minute interval :
212     int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames;
213
214     int tenMinuteIntervals = frames / tenMinutes;
215     frames = frames % tenMinutes;
216
217     int hours = tenMinuteIntervals / 6;
218     tenMinuteIntervals = tenMinuteIntervals % 6;
219
220     // At the point, we have figured out HH:M?:??:??
221
222     int numMinutes;
223
224     if (frames < tenthMinuteFrames) {
225         // tenth minute logic applies.
226         numMinutes = 0;
227     } else {
228         // normal minute logic applies.
229         numMinutes = 1 + (frames - tenthMinuteFrames) / normalMinuteFrames;
230         frames = (frames - tenthMinuteFrames) % normalMinuteFrames;
231         frames +=  tenthMinute + perMinute;
232     }
233     // We now have HH:MM:??:??
234
235     int seconds = frames / m_displayedFramesPerSecond;
236     frames = frames % m_displayedFramesPerSecond;
237
238     // We now have HH:MM:SS:FF
239
240     // THANK FUCK FOR THAT.
241
242     QString text;
243     text.append(QString::number(hours).rightJustified(2, '0', FALSE));
244     text.append(":");
245     text.append(QString::number(tenMinuteIntervals));
246     text.append(QString::number(numMinutes));
247     text.append(":");
248     text.append(QString::number(seconds).rightJustified(2, '0', FALSE));
249     text.append(":");
250     text.append(QString::number(frames).rightJustified(2, '0', FALSE));
251
252     return text;
253 }