diff --git a/aegisub/src/ass_time.cpp b/aegisub/src/ass_time.cpp index c178e6112..17905c426 100644 --- a/aegisub/src/ass_time.cpp +++ b/aegisub/src/ass_time.cpp @@ -38,6 +38,7 @@ // Includes #include "config.h" +#include #include #include #include "ass_time.h" @@ -244,15 +245,6 @@ wxString AssTime::GetSRTFormated () { } -/////////////////// -// SMPTE formatted -wxString AssTime::GetSMPTE(double fps) -{ - int f = int(GetTimeMiliseconds() * fps / 1000.0); - return wxString::Format(_T("%02i:%02i:%02i:%02i"),GetTimeHours(),GetTimeMinutes(),GetTimeSeconds(),f); -} - - ////////////////////// // AssTime comparison bool operator < (AssTime &t1, AssTime &t2) { @@ -292,3 +284,69 @@ int AssTime::GetTimeMinutes() { return (time % 3600000)/60000; } int AssTime::GetTimeSeconds() { return (time % 60000)/1000; } int AssTime::GetTimeMiliseconds() { return (time % 1000); } int AssTime::GetTimeCentiseconds() { return (time % 1000)/10; } + + + + +FractionalTime::FractionalTime (wxString separator, double numerator, double denominator) { + num = numerator; + den = denominator; + sep = separator; + + // fractions < 1 are not welcome here + if ((num <= 0 || den <= 0) || (num < den)) + throw _T("FractionalTime: nonsensical enumerator or denominator"); + if (sep.IsEmpty()) + throw _T("FractionalTime: no separator specified"); +} + +FractionalTime::~FractionalTime () { + sep.Clear(); +} + +int64_t FractionalTime::ToMillisecs (wxString _text) { + wxString text = _text; + wxString re_str = _T(""); + wxString sep_e = _T("\\") + sep; // escape this just in case it may be a reserved regex character + text.Trim(false); + text.Trim(true); + long h=0,m=0,s=0,ms=0,f=0; + + // hour minute second fraction + re_str << _T("(\\d+)") << sep_e << _T("(\\d+)") << sep_e << _T("(\\d+)") << sep_e << _T("(\\d+)"); + + wxRegEx re(re_str, wxRE_ADVANCED); + if (!re.IsValid()) + throw _T("FractionalTime: regex failure"); + if (!re.Matches(text)) + return 0; // FIXME: throw here too? + + re.GetMatch(text, 1).ToLong(&h); + re.GetMatch(text, 2).ToLong(&m); + re.GetMatch(text, 3).ToLong(&s); + re.GetMatch(text, 4).ToLong(&f); + // FIXME: find out how to do this in a sane way + //if ((double)f >= ((double)num/(double)den) // overflow? + // f = (num/den - 1); + ms = long((1000.0 / (num/den)) * (double)f); + + return (int64_t)((h * 3600000) + (m * 60000) + (s * 1000) + ms); +} + +AssTime FractionalTime::ToAssTime (wxString _text) { + AssTime time; + time.SetMS((int)ToMillisecs(_text)); + return time; +} + +wxString FractionalTime::FromAssTime(AssTime time) { + return FromMillisecs((int64_t)time.GetMS()); +} + +wxString FractionalTime::FromMillisecs(int64_t msec) { + int h = msec / 3600000; + int m = (msec % 3600000)/60000; + int s = (msec % 60000)/1000; + int f = int((msec % 1000) * ((num/den) / 1000.0)); + return wxString::Format(_T("%02i") + sep + _T("%02i") + sep + _T("%02i") + sep + _T("%02i"),h,m,s,f); +} diff --git a/aegisub/src/ass_time.h b/aegisub/src/ass_time.h index 9f44d1f8d..7e39d7baf 100644 --- a/aegisub/src/ass_time.h +++ b/aegisub/src/ass_time.h @@ -41,6 +41,7 @@ // Headers #include #include +#include ///////////////////////////// @@ -66,7 +67,6 @@ public: void ParseSRT(const wxString text); // Sets value to text-form time, in SRT format wxString GetASSFormated(bool ms=false); // Returns the ASS representation of time wxString GetSRTFormated(); // Returns the SRT representation of time - wxString GetSMPTE(double fps); // Returns the SMPTE timecodes for the given frame rate }; // Comparison operators @@ -76,3 +76,24 @@ bool operator < (AssTime &t1, AssTime &t2); bool operator > (AssTime &t1, AssTime &t2); bool operator <= (AssTime &t1, AssTime &t2); bool operator >= (AssTime &t1, AssTime &t2); + + +///////////////////////////// +// Class for that annoying SMPTE format timecodes stuff +class FractionalTime { +private: + int64_t time; // milliseconds, like in AssTime + double num, den; // numerator/denominator + wxString sep; // separator; someone might have separators of more than one character :V + +public: + // dumb assumption? I give no fuck + FractionalTime(wxString separator, double numerator=30.0, double denominator=1.0); + ~FractionalTime(); + + AssTime ToAssTime(wxString fractime); + int64_t ToMillisecs(wxString fractime); + + wxString FromAssTime(AssTime time); + wxString FromMillisecs(int64_t msec); +}; diff --git a/aegisub/src/subtitle_format_encore.cpp b/aegisub/src/subtitle_format_encore.cpp index 9386c4a39..6e97db695 100644 --- a/aegisub/src/subtitle_format_encore.cpp +++ b/aegisub/src/subtitle_format_encore.cpp @@ -87,14 +87,15 @@ void EncoreSubtitleFormat::WriteFile(wxString _filename,wxString encoding) { // Write lines using std::list; int i = 0; + + // Encore wants ; instead of : if we're dealing with NTSC + FractionalTime fp(fps > 26.0 ? _T(";") : _T(":"), fps); + for (list::iterator cur=Line->begin();cur!=Line->end();cur++) { AssDialogue *current = AssEntry::GetAsDialogue(*cur); if (current && !current->Comment) { // Time stamps - wxString timeStamps = wxString::Format(_T("%i "),++i) + current->Start.GetSMPTE(fps) + _T(" ") + current->End.GetSMPTE(fps); - - // Convert : to ; if it's NTSC - if (fps > 26.0) timeStamps.Replace(_T(":"),_T(";")); + wxString timeStamps = wxString::Format(_T("%i "),++i) + fp.FromAssTime(current->Start) + _T(" ") + fp.FromAssTime(current->End); // Write file.WriteLineToFile(timeStamps + current->Text); diff --git a/aegisub/src/subtitle_format_transtation.cpp b/aegisub/src/subtitle_format_transtation.cpp index bfd0dafd0..0fa9549a4 100644 --- a/aegisub/src/subtitle_format_transtation.cpp +++ b/aegisub/src/subtitle_format_transtation.cpp @@ -41,6 +41,7 @@ #include "ass_dialogue.h" #include "ass_file.h" #include "ass_style.h" +#include "ass_time.h" #include "subtitle_format_transtation.h" #include "text_file_writer.h" #include @@ -115,7 +116,8 @@ void TranStationSubtitleFormat::WriteFile(wxString _filename,wxString encoding) // and we otherwise run the risk of having two lines overlap in a // frame, when they should run right into each other. end.SetMS(end.GetMS() - (int)(500.0/fps)); - wxString header = wxString::Format(_T("SUB[%i%s%s "),valign,halign,type) + start.GetSMPTE(fps) + _T(">") + end.GetSMPTE(fps) + _T("]"); + FractionalTime ft(_T(":"),fps); + wxString header = wxString::Format(_T("SUB[%i%s%s "),valign,halign,type) + ft.FromAssTime(start) + _T(">") + ft.FromAssTime(end) + _T("]"); file.WriteLineToFile(header); // Process text