/////////////////////// // Transform framerate void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) { int n=0; // Run through using std::list; AssEntry *curEntry; AssDialogue *curDialogue; for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { curEntry = *cur; curEntry->StartMS = Input->GetTimeAtFrame(Output->GetFrameAtTime(curEntry->StartMS,true),true); curDialogue = AssEntry::GetAsDialogue(curEntry); // Update dialogue entries if (curDialogue) { // Line data LineData data; data.line = curDialogue; data.k = 0; data.kf = 0; data.ko = 0; // Process stuff curDialogue->ParseASSTags(); curDialogue->ProcessParameters(TransformTimeTags,&data); curDialogue->Start.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->Start.GetMS(),true),true)); curDialogue->End.SetMS(Input->GetTimeAtFrame(Output->GetFrameAtTime(curDialogue->End.GetMS(),false),false)); curDialogue->UpdateText(); curDialogue->UpdateData(); curDialogue->ClearBlocks(); n++; } } }
/////////////////// // split current line void FrameMain::OnVideoTrackSplitLine(wxCommandEvent &event) { videoBox->videoDisplay->Stop(); // Get line AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); if (!curline) return; if( !curline->Movement ) return; // Create split lines int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true); int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false); AssFile *subs = AssFile::top; int ResXValue,ResYValue; swscanf( subs->GetScriptInfo(_T("PlayResX")), _T("%d"), &ResXValue ); swscanf( subs->GetScriptInfo(_T("PlayResY")), _T("%d"), &ResYValue ); int SrcXValue = videoBox->videoDisplay->provider->GetSourceWidth(); int SrcYValue = videoBox->videoDisplay->provider->GetSourceHeight(); float sx = float(ResXValue)/float(SrcXValue); float sy = float(ResYValue)/float(SrcYValue); for( int Frame = StartFrame; Frame < EndFrame; Frame ++ ) { int localframe = Frame - StartFrame; while( curline->Movement->Frames.size() <= localframe ) localframe--; FexMovementFrame f = curline->Movement->Frames[localframe]; // f.Pos.x /= videoBox->videoDisplay->GetW AssDialogue *cur = new AssDialogue( curline->GetEntryData() ); cur->Start.SetMS(VFR_Output.GetTimeAtFrame(Frame,true)); cur->End.SetMS(VFR_Output.GetTimeAtFrame(Frame,false)); cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x*sx, f.Pos.y*sy, f.Scale.x*100, f.Scale.y*100 ) + cur->Text; cur->UpdateData(); SubsBox->InsertLine(cur,EditBox->linen + Frame - StartFrame,true,false); } // Remove Movement DeleteMovement( curline->Movement ); curline->Movement = 0; // Remove Tracker delete curline->Tracker; curline->Tracker = 0; // Remove this line SubsBox->DeleteLines(SubsBox->GetRangeArray(EditBox->linen, EditBox->linen)); videoBox->videoDisplay->RefreshVideo(); }
/////////////////// // link line to move file void FrameMain::OnVideoTrackLinkFile(wxCommandEvent &event) { videoBox->videoDisplay->Stop(); // Get line AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); if (!curline) return; wxString link = wxGetTextFromUser(_("Link name:"), _("Link line to movement file"), curline->Movement?curline->Movement->FileName:_T(""), this); if( link.empty() ) curline->Effect = _T(""); else curline->Effect = _T("FexMovement:")+link; curline->UpdateData(); if( !curline->Effect.empty() && curline->Movement ) SaveMovement( curline->Movement, curline->Effect.AfterFirst(':').c_str() ); }
///////////////////////////// // Set style of current line void DialogStyling::SetStyle (wxString curName, bool jump) { // Get line AssDialogue *line = grid->GetDialogue(linen); // Update line line->Style = curName; line->UpdateData(); // Update grid/subs grid->Refresh(false); if (PreviewCheck->IsChecked()) { grid->ass->FlagAsModified(_("Change Style (Assistant)")); grid->CommitChanges(); } else needCommit = true; // Next line if (jump) JumpToLine(linen+1); }
//////////// // Resample void DialogResample::OnResample (wxCommandEvent &event) { // Resolutions AssFile *subs = AssFile::top; int x1,y1; subs->GetResolution(x1,y1); long x2 = 0; long y2 = 0; ResX->GetValue().ToLong(&x2); ResY->GetValue().ToLong(&y2); // Check for validity if (x1 == 0 || x2 == 0 || y1 == 0 || y2 == 0) { EndModal(0); return; } // Calculate resamples rx = double(x2)/double(x1); ry = double(y2)/double(y1); r = ry; if (Anamorphic->IsChecked()) ar = rx/ry; else ar = 1.0; // Iterate through subs AssStyle *curStyle; AssDialogue *curDiag; for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) { // Apply to dialogues curDiag = AssEntry::GetAsDialogue(*cur); if (curDiag) { try { // Override tags curDiag->ParseASSTags(); curDiag->ProcessParameters(ResampleTags,curDiag); // Drawing tags size_t nblocks = curDiag->Blocks.size(); AssDialogueBlockDrawing *curBlock; for (size_t i=0;i<nblocks;i++) { curBlock = AssDialogueBlock::GetAsDrawing(curDiag->Blocks.at(i)); if (curBlock) { curBlock->MultiplyCoords(rx,ry); } } // Margins curDiag->MarginL = int(curDiag->MarginL * rx + 0.5); curDiag->MarginR = int(curDiag->MarginR * rx + 0.5); curDiag->MarginV = int(curDiag->MarginV * ry + 0.5); // Update curDiag->UpdateText(); curDiag->UpdateData(); curDiag->ClearBlocks(); continue; } catch (const wchar_t *err) { wxLogMessage(err); } catch (wxString err) { wxLogMessage(err); } } // Apply to styles curStyle = AssEntry::GetAsStyle(*cur); if (curStyle) { curStyle->fontsize = int(curStyle->fontsize * r + 0.5); //curStyle->outline_w *= r; //curStyle->shadow_w *= r; curStyle->spacing *= rx; curStyle->scalex *= ar; curStyle->MarginL = int(curStyle->MarginL * rx + 0.5); curStyle->MarginR = int(curStyle->MarginR * rx + 0.5); curStyle->MarginV = int(curStyle->MarginV * ry + 0.5); curStyle->UpdateData(); } } // Change script resolution subs->SetScriptInfo(_T("PlayResX"),wxString::Format(_T("%i"),x2)); subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2)); // Flag as modified subs->FlagAsModified(); grid->CommitChanges();; EndModal(0); }
///////////// // Read file void SRTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using namespace std; // Reader TextFileReader file(filename,encoding); // Default LoadDefault(false); // Parse file int linen = 1; int fileLine = 0; int mode = 0; int lines = 0; long templ; AssDialogue *line = NULL; while (file.HasMoreLines()) { // Reads line wxString curLine = file.ReadLineFromFile(); fileLine++; switch (mode) { case 0: // Checks if there is anything to read if (curLine.IsEmpty()) continue; // Check if it's a line number if (!curLine.IsNumber()) { Clear(); throw wxString::Format(_T("Parse error on entry %i at line %i (expecting line number). Possible malformed file."),linen,fileLine); } // Read line number curLine.ToLong(&templ); if (templ != linen) { linen = templ; } line = new AssDialogue(); mode = 1; break; case 1: // Read timestamps if (curLine.substr(13,3) != _T("-->")) { Clear(); throw wxString::Format(_T("Parse error on entry %i at line %i (expecting timestamps). Possible malformed file."),linen,fileLine); } line->Start.ParseSRT(curLine.substr(0,12)); line->End.ParseSRT(curLine.substr(17,12)); mode = 2; break; case 2: // Checks if it's done if (curLine.IsEmpty() || !file.HasMoreLines()) { mode = 0; linen++; line->group = _T("[Events]"); line->Style = _T("Default"); line->Comment = false; line->UpdateData(); line->ParseSRTTags(); line->StartMS = line->Start.GetMS(); Line->push_back(line); lines++; break; } // Append text if (line->Text != _T("")) line->Text += _T("\\N"); line->Text += curLine; break; } } // No lines? if (lines == 0) { AssDialogue *line = new AssDialogue(); line->group = _T("[Events]"); line->Style = _T("Default"); line->StartMS = 0; line->Start.SetMS(0); line->End.SetMS(5000); Line->push_back(line); } }
///////////// // Read file void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using namespace std; // Reader TextFileReader file(filename,encoding,false); // Default LoadDefault(false); // Data wxString actor; wxString separator = Options.AsText(_T("Text actor separator")); wxString comment = Options.AsText(_T("Text comment starter")); bool isComment = false; int lines = 0; // Parse file AssDialogue *line = NULL; while (file.HasMoreLines()) { // Reads line wxString value = file.ReadLineFromFile(); // Check if this isn't a timecodes file if (value.Left(10) == _T("# timecode")) { throw _T("File is a timecode file, cannot load as subtitles."); } // Read comment data isComment = false; if (comment != _T("") && value.Left(comment.Length()) == comment) { isComment = true; value = value.Mid(comment.Length()); } // Read actor data if (!isComment && separator != _T("")) { if (value[0] != _T(' ') && value[0] != _T('\t')) { int pos = value.Find(separator); if (pos != wxNOT_FOUND) { actor = value.Left(pos); actor.Trim(false); actor.Trim(true); value = value.Mid(pos+1); value.Trim(false); } } } // Trim spaces at start value.Trim(false); // Sets line up line = new AssDialogue(); line->group = _T("[Events]"); line->Style = _T("Default"); if (isComment) line->Actor = _T(""); else line->Actor = actor; if (value.IsEmpty()) { line->Actor = _T(""); isComment = true; } line->Comment = isComment; line->Text = value; line->StartMS = 0; line->Start.SetMS(0); line->End.SetMS(0); line->UpdateData(); //line->ParseASSTags(); // Adds line Line->push_back(line); lines++; } // No lines? if (lines == 0) { AssDialogue *line = new AssDialogue(); line->group = _T("[Events]"); line->Style = _T("Default"); line->StartMS = 0; line->Start.SetMS(0); line->End.SetMS(5000); Line->push_back(line); } }
///////////////////////// // Replace all instances void SearchReplaceEngine::ReplaceAll() { // Setup wxString *Text; int nrows = grid->GetRows(); size_t count = 0; int regFlags = wxRE_ADVANCED; if (!matchCase) { if (isReg) regFlags |= wxRE_ICASE; //else LookFor.MakeLower(); } bool replaced; grid->BeginBatch(); // Selection bool hasSelection = false; wxArrayInt sels = grid->GetSelection(); if (sels.Count() > 0) hasSelection = true; bool inSel = false; if (affect == 1) inSel = true; // Scan for (int i=0;i<nrows;i++) { // Check if row is selected if (inSel && hasSelection && sels.Index(i) == wxNOT_FOUND) { continue; } // Prepare replaced = false; Text = GetText(i,field); // Regular expressions if (isReg) { wxRegEx reg(LookFor,regFlags); if (reg.IsValid()) { size_t reps = reg.ReplaceAll(Text,ReplaceWith); if (reps > 0) replaced = true; count += reps; } } // Normal replace else { if (Text->Contains(LookFor)) { count += Text->Replace(LookFor,ReplaceWith); replaced = true; } } // Replaced? if (replaced) { AssDialogue *cur = grid->GetDialogue(i); cur->UpdateData(); //cur->ParseASSTags(); } } // Commit if (count > 0) { grid->ass->FlagAsModified(); grid->CommitChanges(); wxMessageBox(wxString::Format(_("%i matches were replaced."),count)); } // None found else { wxMessageBox(_("No matches found.")); } grid->EndBatch(); LastWasFind = false; }
//////////////////////////////// // Find & Replace next instance void SearchReplaceEngine::ReplaceNext(bool DoReplace) { // Check if it's OK to go on if (!CanContinue) { OpenDialog(DoReplace); return; } wxArrayInt sels = grid->GetSelection(); // if selection has changed reset values if (sels[0] < curLine) { curLine = sels[0]; Modified = false; LastWasFind = true; pos = 0; matchLen = 0; replaceLen = 0; } // Setup int start = curLine; int nrows = grid->GetRows(); bool found = false; wxString *Text; size_t tempPos; int regFlags = wxRE_ADVANCED; if (!matchCase) { if (isReg) regFlags |= wxRE_ICASE; else LookFor.MakeLower(); } // Search for it while (!found) { Text = GetText(curLine,field); if (DoReplace && LastWasFind) tempPos = pos; else tempPos = pos+replaceLen; // RegExp if (isReg) { wxRegEx regex (LookFor,regFlags); if (regex.IsValid()) { if (regex.Matches(Text->Mid(tempPos))) { size_t match_start; regex.GetMatch(&match_start,&matchLen,0); pos = match_start + tempPos; //matchLen++; found = true; } } } // Normal else { wxString src = Text->Mid(tempPos); if (!matchCase) src.MakeLower(); pos = src.Find(LookFor); if (pos != -1) { pos += tempPos; found = true; matchLen = LookFor.Length(); } } // Didn't find, go to next line if (!found) { curLine++; pos = 0; matchLen = 0; replaceLen = 0; if (curLine == nrows) curLine = 0; if (curLine == start) break; } } // Found if (found) { grid->BeginBatch(); // If replacing if (DoReplace) { // Replace with regular expressions if (isReg) { wxString toReplace = Text->Mid(pos,matchLen); wxRegEx regex(LookFor,regFlags); regex.ReplaceFirst(&toReplace,ReplaceWith); *Text = Text->Left(pos) + toReplace + Text->Mid(pos+matchLen); replaceLen = toReplace.Length(); } // Normal replace else { *Text = Text->Left(pos) + ReplaceWith + Text->Mid(pos+matchLen); replaceLen = ReplaceWith.Length(); } // Update AssDialogue *cur = grid->GetDialogue(curLine); //cur->ParseASSTags(); cur->UpdateData(); // Commit grid->ass->FlagAsModified(); } else { replaceLen = matchLen; } // Select grid->SelectRow(curLine,false); grid->MakeCellVisible(curLine,0); if (field == 0) { grid->editBox->SetToLine(curLine); grid->editBox->TextEdit->SetSelectionU(pos,pos+replaceLen); } grid->EndBatch(); // Update video if (updateVideo) { grid->CommitChanges(); grid->SetVideoToSubs(true); } else if (DoReplace) Modified = true; // hAx to prevent double match on style/actor if (field != 0) replaceLen = 99999; } LastWasFind = !DoReplace; }
////////////////////////////// // Actually process subtitles void DialogTimingProcessor::Process() { // Sort rows SortDialogues(); int rows = Sorted.size(); // Options long inVal = 0; long outVal = 0; leadIn->GetValue().ToLong(&inVal); leadOut->GetValue().ToLong(&outVal); bool addIn = hasLeadIn->IsChecked() && inVal; bool addOut = hasLeadOut->IsChecked() && outVal; // Add lead-in/out if (addIn || addOut) { // Variables AssDialogue *cur; AssDialogue *comp; int start,end; int startLead,endLead; int compStart,compEnd; // For each row for (int i=0;i<rows;i++) { // Get line and check if it's OK cur = GetSortedDialogue(i); // Set variables start = cur->Start.GetMS(); end = cur->End.GetMS(); if (addIn) startLead = start - inVal; else startLead = start; if (addOut) endLead = end + outVal; else endLead = end; // Compare to every previous line (yay for O(n^2)!) to see if it's OK to add lead-in if (addIn) { for (int j=0;j<i;j++) { comp = GetSortedDialogue(j); // Check if they don't already collide (ignore it in that case) if (cur->CollidesWith(comp)) continue; // Get comparison times compEnd = comp->End.GetMS(); // Limit lead-in if needed if (compEnd > startLead) startLead = compEnd; } } // Compare to every line to see how far can lead-out be extended if (addOut) { for (int j=i+1;j<rows;j++) { comp = GetSortedDialogue(j); // Check if they don't already collide (ignore it in that case) if (cur->CollidesWith(comp)) continue; // Get comparison times compStart = comp->Start.GetMS(); // Limit lead-in if needed if (compStart < endLead) endLead = compStart; } } // Set times cur->Start.SetMS(startLead); cur->End.SetMS(endLead); cur->UpdateData(); } } // Make adjascent if (adjsEnable->IsChecked()) { // Variables AssDialogue *cur; AssDialogue *prev = NULL; int curStart,prevEnd; long adjsThres = 0; int dist; // Get threshold adjascentThres->GetValue().ToLong(&adjsThres); // Get bias float bias = adjascentBias->GetValue() / 100.0; // For each row for (int i=0;i<rows;i++) { // Get line and check if it's OK cur = GetSortedDialogue(i); // Check if previous is OK if (!prev) { prev = cur; continue; } // Check if they don't collide if (cur->CollidesWith(prev)) continue; // Compare distance curStart = cur->Start.GetMS(); prevEnd = prev->End.GetMS(); dist = curStart-prevEnd; if (dist > 0 && dist < adjsThres) { int setPos = prevEnd+int(dist*bias); cur->Start.SetMS(setPos); cur->UpdateData(); prev->End.SetMS(setPos); prev->UpdateData(); } // Set previous prev = cur; } } // Keyframe snapping if (keysEnable->IsChecked()) { // Get keyframes KeyFrames = grid->video->KeyFrames; KeyFrames.Add(grid->video->length-1); // Variables int startF,endF; int closest; bool changed; AssDialogue *cur; // Get variables long beforeStart = 0; long afterStart = 0; long beforeEnd = 0; long afterEnd = 0; keysStartBefore->GetValue().ToLong(&beforeStart); keysStartAfter->GetValue().ToLong(&afterStart); keysEndBefore->GetValue().ToLong(&beforeEnd); keysEndAfter->GetValue().ToLong(&afterEnd); // For each row for (int i=0;i<rows;i++) { // Get line and check if it's OK cur = GetSortedDialogue(i); // Get start/end frames startF = VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true); endF = VFR_Output.GetFrameAtTime(cur->End.GetMS(),false); changed = false; // Get closest for start closest = GetClosestKeyFrame(startF); if ((closest > startF && closest-startF <= beforeStart) || (closest < startF && startF-closest <= afterStart)) { cur->Start.SetMS(VFR_Output.GetTimeAtFrame(closest,true)); changed = true; } // Get closest for end closest = GetClosestKeyFrame(endF)-1; if ((closest > endF && closest-endF <= beforeEnd) || (closest < endF && endF-closest <= afterEnd)) { cur->End.SetMS(VFR_Output.GetTimeAtFrame(closest,false)); changed = true; } // Apply changes if (changed) { cur->UpdateData(); } } } // Update grid grid->ass->FlagAsModified(); grid->CommitChanges(); }