forked from mia/Aegisub
Implemented new karaoke splitter. Still needs some work, especially graphically.
The timing postproc dialog is now properly centered. Originally committed to SVN as r29.
This commit is contained in:
parent
c6fb2bdf42
commit
3ad6a9db43
7 changed files with 247 additions and 91 deletions
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
// Copyright (c) 2005, Rodrigo Braz Monteiro, Niels Martin Hansen
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -171,9 +171,10 @@ wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISE
|
||||||
JoinButton->SetToolTip(_("Join selected syllables"));
|
JoinButton->SetToolTip(_("Join selected syllables"));
|
||||||
JoinButton->Enable(false);
|
JoinButton->Enable(false);
|
||||||
karaokeSizer->Add(JoinButton,0,wxRIGHT,0);
|
karaokeSizer->Add(JoinButton,0,wxRIGHT,0);
|
||||||
SplitButton = new wxButton(this,Audio_Button_Split,_("Split"),wxDefaultPosition,wxSize(-1,-1));
|
SplitButton = new wxToggleButton(this,Audio_Button_Split,_("Split"),wxDefaultPosition,wxSize(-1,-1));
|
||||||
SplitButton->SetToolTip(_("Split selected syllables"));
|
SplitButton->SetToolTip(_("Toggle splitting-mode"));
|
||||||
SplitButton->Enable(false);
|
SplitButton->Enable(false);
|
||||||
|
SplitButton->SetValue(false);
|
||||||
karaokeSizer->Add(SplitButton,0,wxRIGHT,5);
|
karaokeSizer->Add(SplitButton,0,wxRIGHT,5);
|
||||||
karaokeSizer->Add(audioKaraoke,1,wxEXPAND,0);
|
karaokeSizer->Add(audioKaraoke,1,wxEXPAND,0);
|
||||||
|
|
||||||
|
@ -234,12 +235,12 @@ BEGIN_EVENT_TABLE(AudioBox,wxPanel)
|
||||||
EVT_BUTTON(Audio_Button_Commit, AudioBox::OnCommit)
|
EVT_BUTTON(Audio_Button_Commit, AudioBox::OnCommit)
|
||||||
EVT_BUTTON(Audio_Button_Goto, AudioBox::OnGoto)
|
EVT_BUTTON(Audio_Button_Goto, AudioBox::OnGoto)
|
||||||
EVT_BUTTON(Audio_Button_Join,AudioBox::OnJoin)
|
EVT_BUTTON(Audio_Button_Join,AudioBox::OnJoin)
|
||||||
EVT_BUTTON(Audio_Button_Split,AudioBox::OnSplit)
|
|
||||||
EVT_BUTTON(Audio_Button_Leadin,AudioBox::OnLeadIn)
|
EVT_BUTTON(Audio_Button_Leadin,AudioBox::OnLeadIn)
|
||||||
EVT_BUTTON(Audio_Button_Leadout,AudioBox::OnLeadOut)
|
EVT_BUTTON(Audio_Button_Leadout,AudioBox::OnLeadOut)
|
||||||
|
|
||||||
EVT_TOGGLEBUTTON(Audio_Button_Karaoke, AudioBox::OnKaraoke)
|
EVT_TOGGLEBUTTON(Audio_Button_Karaoke, AudioBox::OnKaraoke)
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_AutoGoto,AudioBox::OnAutoGoto)
|
EVT_TOGGLEBUTTON(Audio_Check_AutoGoto,AudioBox::OnAutoGoto)
|
||||||
|
EVT_TOGGLEBUTTON(Audio_Button_Split,AudioBox::OnSplit)
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_SSA,AudioBox::OnSSAMode)
|
EVT_TOGGLEBUTTON(Audio_Check_SSA,AudioBox::OnSSAMode)
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_Spectrum,AudioBox::OnSpectrumMode)
|
EVT_TOGGLEBUTTON(Audio_Check_Spectrum,AudioBox::OnSpectrumMode)
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_AutoCommit,AudioBox::OnAutoCommit)
|
EVT_TOGGLEBUTTON(Audio_Check_AutoCommit,AudioBox::OnAutoCommit)
|
||||||
|
@ -427,6 +428,9 @@ void AudioBox::OnCommit(wxCommandEvent &event) {
|
||||||
void AudioBox::OnKaraoke(wxCommandEvent &event) {
|
void AudioBox::OnKaraoke(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
if (karaokeMode) {
|
if (karaokeMode) {
|
||||||
|
if (audioKaraoke->splitting) {
|
||||||
|
audioKaraoke->EndSplit(false);
|
||||||
|
}
|
||||||
karaokeMode = false;
|
karaokeMode = false;
|
||||||
audioKaraoke->enabled = false;
|
audioKaraoke->enabled = false;
|
||||||
SetKaraokeButtons(false,false);
|
SetKaraokeButtons(false,false);
|
||||||
|
@ -447,8 +451,14 @@ void AudioBox::OnKaraoke(wxCommandEvent &event) {
|
||||||
// Sets karaoke buttons
|
// Sets karaoke buttons
|
||||||
void AudioBox::SetKaraokeButtons(bool join,bool split) {
|
void AudioBox::SetKaraokeButtons(bool join,bool split) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
JoinButton->Enable(join);
|
JoinButton->Enable(join && !audioKaraoke->splitting);
|
||||||
SplitButton->Enable(split);
|
SplitButton->Enable(split);
|
||||||
|
SplitButton->SetValue(audioKaraoke->splitting);
|
||||||
|
if (audioKaraoke->splitting) {
|
||||||
|
SplitButton->SetLabel(_("Cancel Split"));
|
||||||
|
} else {
|
||||||
|
SplitButton->SetLabel(_("Split"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -464,7 +474,11 @@ void AudioBox::OnJoin(wxCommandEvent &event) {
|
||||||
// Split button
|
// Split button
|
||||||
void AudioBox::OnSplit(wxCommandEvent &event) {
|
void AudioBox::OnSplit(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
audioKaraoke->Split();
|
if (!audioKaraoke->splitting) {
|
||||||
|
audioKaraoke->BeginSplit();
|
||||||
|
} else {
|
||||||
|
audioKaraoke->EndSplit(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ private:
|
||||||
wxSizer *DisplaySizer;
|
wxSizer *DisplaySizer;
|
||||||
wxSashWindow *Sash;
|
wxSashWindow *Sash;
|
||||||
|
|
||||||
wxButton *SplitButton;
|
wxToggleButton *SplitButton;
|
||||||
wxButton *JoinButton;
|
wxButton *JoinButton;
|
||||||
ToggleBitmap *AutoScroll;
|
ToggleBitmap *AutoScroll;
|
||||||
ToggleBitmap *SSAMode;
|
ToggleBitmap *SSAMode;
|
||||||
|
|
|
@ -979,7 +979,9 @@ void AudioDisplay::CommitChanges () {
|
||||||
|
|
||||||
// Update karaoke
|
// Update karaoke
|
||||||
int karSyl = 0;
|
int karSyl = 0;
|
||||||
|
bool wasKaraSplitting = false;
|
||||||
if (karaoke->enabled) {
|
if (karaoke->enabled) {
|
||||||
|
wasKaraSplitting = box->audioKaraoke->splitting;
|
||||||
karaoke->Commit();
|
karaoke->Commit();
|
||||||
karSyl = karaoke->curSyllable;
|
karSyl = karaoke->curSyllable;
|
||||||
}
|
}
|
||||||
|
@ -996,8 +998,8 @@ void AudioDisplay::CommitChanges () {
|
||||||
karaoke->curSyllable = karSyl;
|
karaoke->curSyllable = karSyl;
|
||||||
blockUpdate = false;
|
blockUpdate = false;
|
||||||
|
|
||||||
// If in SSA mode, select next line and "move timing forward"
|
// If in SSA mode, select next line and "move timing forward" (unless the user was splitting karaoke)
|
||||||
if (Options.AsBool(_T("Audio SSA Mode")) && Options.AsBool(_T("Audio SSA Next Line on Commit"))) {
|
if (Options.AsBool(_T("Audio SSA Mode")) && Options.AsBool(_T("Audio SSA Next Line on Commit")) && !wasKaraSplitting) {
|
||||||
dontReadTimes = true;
|
dontReadTimes = true;
|
||||||
Next();
|
Next();
|
||||||
dontReadTimes = false;
|
dontReadTimes = false;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
// Copyright (c) 2005, Rodrigo Braz Monteiro, Niels Martin Hansen
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
////////////////////////
|
////////////////////////
|
||||||
|
@ -51,6 +52,7 @@ KaraokeSyllable::KaraokeSyllable() {
|
||||||
position = 0;
|
position = 0;
|
||||||
display_w = 0;
|
display_w = 0;
|
||||||
display_x = 0;
|
display_x = 0;
|
||||||
|
pending_splits.clear();
|
||||||
selected = false;
|
selected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +63,8 @@ AudioKaraoke::AudioKaraoke(wxWindow *parent)
|
||||||
: wxWindow (parent,-1,wxDefaultPosition,wxSize(10,5),wxTAB_TRAVERSAL|wxBORDER_SUNKEN)
|
: wxWindow (parent,-1,wxDefaultPosition,wxSize(10,5),wxTAB_TRAVERSAL|wxBORDER_SUNKEN)
|
||||||
{
|
{
|
||||||
enabled = false;
|
enabled = false;
|
||||||
|
splitting = false;
|
||||||
|
split_cursor_syl = -1;
|
||||||
curSyllable = 0;
|
curSyllable = 0;
|
||||||
diag = NULL;
|
diag = NULL;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +73,11 @@ AudioKaraoke::AudioKaraoke(wxWindow *parent)
|
||||||
//////////////////////
|
//////////////////////
|
||||||
// Load from dialogue
|
// Load from dialogue
|
||||||
bool AudioKaraoke::LoadFromDialogue(AssDialogue *_diag) {
|
bool AudioKaraoke::LoadFromDialogue(AssDialogue *_diag) {
|
||||||
|
// Make sure we're not in splitting-mode
|
||||||
|
if (splitting) {
|
||||||
|
EndSplit(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Set dialogue
|
// Set dialogue
|
||||||
diag = _diag;
|
diag = _diag;
|
||||||
if (!diag) {
|
if (!diag) {
|
||||||
|
@ -117,6 +126,9 @@ wxString AudioKaraoke::GetSyllableTag(AssDialogueBlockOverride *block,int n) {
|
||||||
////////////////////
|
////////////////////
|
||||||
// Writes line back
|
// Writes line back
|
||||||
void AudioKaraoke::Commit() {
|
void AudioKaraoke::Commit() {
|
||||||
|
if (splitting) {
|
||||||
|
EndSplit(true);
|
||||||
|
}
|
||||||
wxString finalText = _T("");
|
wxString finalText = _T("");
|
||||||
KaraokeSyllable *syl;
|
KaraokeSyllable *syl;
|
||||||
size_t n = syllables.size();
|
size_t n = syllables.size();
|
||||||
|
@ -255,7 +267,6 @@ void AudioKaraoke::OnPaint(wxPaintEvent &event) {
|
||||||
// Set syllable font
|
// Set syllable font
|
||||||
wxFont curFont(9,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,_T("Verdana"),wxFONTENCODING_SYSTEM);
|
wxFont curFont(9,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,_T("Verdana"),wxFONTENCODING_SYSTEM);
|
||||||
dc.SetFont(curFont);
|
dc.SetFont(curFont);
|
||||||
dc.SetPen(wxPen(wxColour(0,0,0)));
|
|
||||||
|
|
||||||
// Draw syllables
|
// Draw syllables
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
@ -266,17 +277,22 @@ void AudioKaraoke::OnPaint(wxPaintEvent &event) {
|
||||||
int delta;
|
int delta;
|
||||||
int dlen;
|
int dlen;
|
||||||
for (size_t i=0;i<syln;i++) {
|
for (size_t i=0;i<syln;i++) {
|
||||||
|
KaraokeSyllable &syl = syllables.at(i);
|
||||||
// Calculate text length
|
// Calculate text length
|
||||||
temptext = syllables.at(i).contents;
|
temptext = syl.contents;
|
||||||
|
// If we're splitting, every character must be drawn
|
||||||
|
if (!splitting) {
|
||||||
temptext.Trim(true);
|
temptext.Trim(true);
|
||||||
temptext.Trim(false);
|
temptext.Trim(false);
|
||||||
|
}
|
||||||
GetTextExtent(temptext,&tw,&th,NULL,NULL,&curFont);
|
GetTextExtent(temptext,&tw,&th,NULL,NULL,&curFont);
|
||||||
delta = 0;
|
delta = 0;
|
||||||
if (tw < 10) delta = 10 - tw;
|
if (tw < 10) delta = 10 - tw;
|
||||||
dlen = tw + 8 + delta;
|
dlen = tw + 8 + delta;
|
||||||
|
|
||||||
// Draw border
|
// Draw border
|
||||||
if (syllables.at(i).selected) {
|
dc.SetPen(wxPen(wxColour(0,0,0)));
|
||||||
|
if (syl.selected && !splitting) {
|
||||||
dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)));
|
dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)));
|
||||||
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
|
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
|
||||||
}
|
}
|
||||||
|
@ -287,11 +303,35 @@ void AudioKaraoke::OnPaint(wxPaintEvent &event) {
|
||||||
dc.DrawRectangle(dx,0,dlen,h);
|
dc.DrawRectangle(dx,0,dlen,h);
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
|
if (splitting) {
|
||||||
|
// Make sure the text position is more predictable in case of splitting
|
||||||
|
dc.DrawText(temptext,dx+4,(h-th)/2);
|
||||||
|
} else {
|
||||||
dc.DrawText(temptext,dx+(delta/2)+4,(h-th)/2);
|
dc.DrawText(temptext,dx+(delta/2)+4,(h-th)/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw pending splits
|
||||||
|
if (syl.pending_splits.size() > 0) {
|
||||||
|
wxArrayInt widths;
|
||||||
|
if (dc.GetPartialTextExtents(temptext, widths)) {
|
||||||
|
for (int i = 0; i < syl.pending_splits.size(); i++) {
|
||||||
|
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
|
||||||
|
dc.DrawLine(dx+4+widths[syl.pending_splits[i]], 0, dx+4+widths[syl.pending_splits[i]], h);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wxLogError(_T("WTF? Failed to GetPartialTextExtents"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (splitting && split_cursor_syl == i && split_cursor_x > 0) {
|
||||||
|
dc.SetPen(*wxRED);
|
||||||
|
dc.DrawLine(dx+4+split_cursor_x, 0, dx+4+split_cursor_x, h);
|
||||||
|
dc.SetPen(wxPen(wxColour(0,0,0)));
|
||||||
|
}
|
||||||
|
|
||||||
// Set syllable data
|
// Set syllable data
|
||||||
syllables.at(i).display_x = dx;
|
syl.display_x = dx;
|
||||||
syllables.at(i).display_w = dlen;
|
syl.display_w = dlen;
|
||||||
|
|
||||||
// Increment dx
|
// Increment dx
|
||||||
dx += dlen;
|
dx += dlen;
|
||||||
|
@ -319,6 +359,7 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
|
||||||
int y = event.GetY();
|
int y = event.GetY();
|
||||||
bool shift = event.m_shiftDown;
|
bool shift = event.m_shiftDown;
|
||||||
|
|
||||||
|
if (!splitting) {
|
||||||
// Left button down
|
// Left button down
|
||||||
if (event.LeftDown()) {
|
if (event.LeftDown()) {
|
||||||
int syl = GetSylAtX(x);
|
int syl = GetSylAtX(x);
|
||||||
|
@ -338,6 +379,81 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
int syli = GetSylAtX(x);
|
||||||
|
|
||||||
|
if (syli != -1) {
|
||||||
|
KaraokeSyllable &syl = syllables.at(syli);
|
||||||
|
|
||||||
|
// Get the widths after each character in the text
|
||||||
|
wxClientDC dc(this);
|
||||||
|
wxFont curFont(9,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,_T("Verdana"),wxFONTENCODING_SYSTEM);
|
||||||
|
dc.SetFont(curFont);
|
||||||
|
wxArrayInt widths;
|
||||||
|
dc.GetPartialTextExtents(syl.contents, widths);
|
||||||
|
|
||||||
|
// Find the character closest to the mouse
|
||||||
|
int rx = x - syl.display_x - 4;
|
||||||
|
int split_cursor_char = -1;
|
||||||
|
split_cursor_syl = -1;
|
||||||
|
split_cursor_x = -1;
|
||||||
|
if (syl.contents.Len() >= 2) {
|
||||||
|
int lastx = widths[0];
|
||||||
|
split_cursor_syl = syli;
|
||||||
|
for (int i = 1; i < widths.size()-1; i++) {
|
||||||
|
//wxLogDebug(_T("rx=%d, lastx=%d, widths[i]=%d, i=%d, widths.size()=%d, syli=%d"), rx, lastx, widths[i], i, widths.size(), syli);
|
||||||
|
if (lastx - rx < widths[i] - rx) {
|
||||||
|
if (rx - lastx < widths[i] - rx) {
|
||||||
|
//wxLogDebug(_T("Found at PREV!"));
|
||||||
|
split_cursor_x = lastx;
|
||||||
|
split_cursor_char = i - 1;
|
||||||
|
break;
|
||||||
|
} else if (rx < widths[i]) {
|
||||||
|
//wxLogDebug(_T("Found at CURRENT!"));
|
||||||
|
split_cursor_x = widths[i];
|
||||||
|
split_cursor_char = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastx = widths[i];
|
||||||
|
}
|
||||||
|
// If no split-point was caught by the for-loop, it must be over the last character,
|
||||||
|
// ie. split at next-to-last position
|
||||||
|
if (split_cursor_x < 0) {
|
||||||
|
//wxLogDebug(_T("Emergency picking LAST!"));
|
||||||
|
split_cursor_x = widths[widths.size()-2];
|
||||||
|
split_cursor_char = widths.size() - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do something if there was a click and we're at a valid position
|
||||||
|
if (event.LeftDown() && split_cursor_char >= 0) {
|
||||||
|
//wxLogDebug(_T("A click!"));
|
||||||
|
int num_removed = 0;
|
||||||
|
std::vector<int>::iterator i = syl.pending_splits.begin();
|
||||||
|
while (i != syl.pending_splits.end()) {
|
||||||
|
if (split_cursor_char == *i) {
|
||||||
|
//wxLogDebug(_T("Erasing entry"));
|
||||||
|
num_removed++;
|
||||||
|
syl.pending_splits.erase(i);
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_removed == 0) {
|
||||||
|
syl.pending_splits.push_back(split_cursor_char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
split_cursor_syl = -1;
|
||||||
|
split_cursor_x = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (split_cursor_syl >= 0) {
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -424,84 +540,98 @@ void AudioKaraoke::Join() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////
|
////////////////////////
|
||||||
// Split syllables
|
// Enter splitting-mode
|
||||||
void AudioKaraoke::Split() {
|
void AudioKaraoke::BeginSplit() {
|
||||||
// Variables
|
splitting = true;
|
||||||
bool hasSplit = false;
|
split_cursor_syl = -1;
|
||||||
|
split_cursor_x = -1;
|
||||||
|
box->SetKaraokeButtons(false, true);
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Loop
|
|
||||||
size_t syls = syllables.size();
|
////////////////////////////////////////////
|
||||||
for (size_t i=0;i<syls;i++) {
|
// Leave splitting-mode, committing changes
|
||||||
if (syllables.at(i).selected) {
|
void AudioKaraoke::EndSplit(bool commit) {
|
||||||
int split = SplitSyl(i);
|
splitting = false;
|
||||||
if (split > 0) {
|
bool hasSplit = false;
|
||||||
syls += split;
|
for (int i = 0; i < syllables.size(); i ++) {
|
||||||
i += split;
|
if (syllables[i].pending_splits.size() > 0) {
|
||||||
|
if (commit) {
|
||||||
|
SplitSyl(i);
|
||||||
hasSplit = true;
|
hasSplit = true;
|
||||||
}
|
} else {
|
||||||
if (split == -1) break;
|
syllables[i].pending_splits.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSelection(0);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
if (hasSplit) {
|
if (hasSplit) {
|
||||||
display->NeedCommit = true;
|
display->NeedCommit = true;
|
||||||
display->Update();
|
display->Update();
|
||||||
Refresh(false);
|
|
||||||
}
|
}
|
||||||
|
// Always redraw, since the display is different in splitting mode
|
||||||
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
/////////////////////////////////////////////////
|
||||||
// Split a syllable
|
// Split a syllable using the pending_slits data
|
||||||
int AudioKaraoke::SplitSyl (int n) {
|
int AudioKaraoke::SplitSyl (int n) {
|
||||||
// Get split text
|
syllables.reserve(syllables.size() + syllables[n].pending_splits.size());
|
||||||
KaraokeSyllable *curSyl = &syllables.at(n);
|
|
||||||
wxString result = wxGetTextFromUser(_("Enter pipes (\"|\") to split:"), _("Split syllable"), curSyl->contents);
|
|
||||||
if (result.IsEmpty()) return -1;
|
|
||||||
|
|
||||||
// Prepare parsing
|
// Start by sorting the split points
|
||||||
const int splits = result.Freq(_T('|'));
|
std::sort(syllables[n].pending_splits.begin(),syllables[n].pending_splits.end());
|
||||||
const int totalCharLen = curSyl->contents.Length() + splits + 1;
|
|
||||||
const int charRound = totalCharLen / 2;
|
|
||||||
const int totalTimeLen = curSyl->length;
|
|
||||||
int curpos = curSyl->position;
|
|
||||||
int curlen = 0;
|
|
||||||
wxStringTokenizer tkn(result,_T("|"),wxTOKEN_RET_EMPTY_ALL);
|
|
||||||
bool isFirst = true;
|
|
||||||
|
|
||||||
// Parse
|
wxString originalText = syllables[n].contents;
|
||||||
for (int curn=n;tkn.HasMoreTokens();curn++) {
|
int originalDuration = syllables[n].length;
|
||||||
// Prepare syllable
|
|
||||||
if (!isFirst) {
|
// Fixup the first syllable
|
||||||
|
syllables[n].contents = originalText.Mid(0, syllables[n].pending_splits[0] + 1);
|
||||||
|
syllables[n].length = originalDuration * syllables[n].contents.Length() / originalText.Length();
|
||||||
|
int curpos = syllables[n].position + syllables[n].length;
|
||||||
|
|
||||||
|
// For each split, make a new syllable
|
||||||
|
for (int i = 0; i < syllables[n].pending_splits.size(); i++) {
|
||||||
KaraokeSyllable temp;
|
KaraokeSyllable temp;
|
||||||
syllables.insert(syllables.begin()+curn,temp);
|
if (i < syllables[n].pending_splits.size()-1) {
|
||||||
temp.selected = true;
|
// in the middle
|
||||||
|
temp.contents = originalText.Mid(syllables[n].pending_splits[i]+1, syllables[n].pending_splits[i+1] - syllables[n].pending_splits[i]);
|
||||||
|
} else {
|
||||||
|
// the last one (take the rest)
|
||||||
|
temp.contents = originalText.Mid(syllables[n].pending_splits[i]+1);
|
||||||
}
|
}
|
||||||
curSyl = &syllables.at(curn);
|
temp.length = originalDuration * temp.contents.Length() / originalText.Length();
|
||||||
|
temp.position = curpos;
|
||||||
// Set text
|
curpos += temp.length;
|
||||||
wxString token = tkn.GetNextToken();
|
syllables.insert(syllables.begin()+n+i+1, temp);
|
||||||
curSyl->contents = token;
|
|
||||||
|
|
||||||
// Set position
|
|
||||||
int len = (totalTimeLen * (token.Length() + 1) + charRound) / totalCharLen;
|
|
||||||
curlen += len;
|
|
||||||
if (curlen > totalTimeLen) {
|
|
||||||
len -= totalTimeLen - curlen;
|
|
||||||
curlen = totalTimeLen;
|
|
||||||
}
|
|
||||||
curSyl->length = len;
|
|
||||||
curSyl->position = curpos;
|
|
||||||
curpos += len;
|
|
||||||
|
|
||||||
// Done
|
|
||||||
isFirst = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return splits
|
// The total duration of the new syllables will be equal to or less than the original duration
|
||||||
return splits;
|
// Fix this, so they'll always add up
|
||||||
|
// Use an unfair method, just adding 1 to each syllable one after another, until it's correct
|
||||||
|
int newDuration = 0;
|
||||||
|
for (int j = n; j < syllables[n].pending_splits.size()+n+1; j++) {
|
||||||
|
newDuration += syllables[j].length;
|
||||||
|
}
|
||||||
|
int k = n;
|
||||||
|
while (newDuration < originalDuration) {
|
||||||
|
syllables[k].length++;
|
||||||
|
k++;
|
||||||
|
if (k >= syllables.size()) {
|
||||||
|
k = n;
|
||||||
|
}
|
||||||
|
newDuration++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare for return and clear pending splits
|
||||||
|
int numsplits = syllables[n].pending_splits.size();
|
||||||
|
syllables[n].pending_splits.clear();
|
||||||
|
return numsplits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ public:
|
||||||
wxString tag;
|
wxString tag;
|
||||||
bool selected;
|
bool selected;
|
||||||
|
|
||||||
|
std::vector<int> pending_splits;
|
||||||
|
|
||||||
KaraokeSyllable();
|
KaraokeSyllable();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,6 +82,9 @@ private:
|
||||||
AssDialogue *diag;
|
AssDialogue *diag;
|
||||||
int startClickSyl;
|
int startClickSyl;
|
||||||
|
|
||||||
|
int split_cursor_syl;
|
||||||
|
int split_cursor_x;
|
||||||
|
|
||||||
int GetKaraokeLength(AssDialogueBlockOverride *block);
|
int GetKaraokeLength(AssDialogueBlockOverride *block);
|
||||||
wxString GetSyllableTag(AssDialogueBlockOverride *block,int n);
|
wxString GetSyllableTag(AssDialogueBlockOverride *block,int n);
|
||||||
void AutoSplit();
|
void AutoSplit();
|
||||||
|
@ -98,8 +103,8 @@ public:
|
||||||
|
|
||||||
int curSyllable;
|
int curSyllable;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
bool splitting;
|
||||||
SylVector syllables;
|
SylVector syllables;
|
||||||
SylVector origSyl;
|
|
||||||
|
|
||||||
AudioKaraoke(wxWindow *parent);
|
AudioKaraoke(wxWindow *parent);
|
||||||
bool LoadFromDialogue(AssDialogue *diag);
|
bool LoadFromDialogue(AssDialogue *diag);
|
||||||
|
@ -109,7 +114,8 @@ public:
|
||||||
bool SyllableDelta(int n,int delta,int mode);
|
bool SyllableDelta(int n,int delta,int mode);
|
||||||
|
|
||||||
void Join();
|
void Join();
|
||||||
void Split();
|
void BeginSplit();
|
||||||
|
void EndSplit(bool commit=true);
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,8 @@ Please visit http://aegisub.net to download latest version
|
||||||
o Fixed bug, triggered when a line had a style not defined in the subs. A warning is now shown instead.
|
o Fixed bug, triggered when a line had a style not defined in the subs. A warning is now shown instead.
|
||||||
- Fixed bug in parser that would cause Aegisub to crash if you had a \fn without parameters and tried to pick font. (AMZ)
|
- Fixed bug in parser that would cause Aegisub to crash if you had a \fn without parameters and tried to pick font. (AMZ)
|
||||||
- Fixed crash when opening audio that appeared in 1.08 (Myrsloik)
|
- Fixed crash when opening audio that appeared in 1.08 (Myrsloik)
|
||||||
|
- Implemented new graphical, mouse-controlled karaoke syllable splitter (jfs)
|
||||||
|
|
||||||
|
|
||||||
= 1.09 beta - 2006.01.16 ===========================
|
= 1.09 beta - 2006.01.16 ===========================
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,8 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr
|
||||||
MainSizer->SetSizeHints(this);
|
MainSizer->SetSizeHints(this);
|
||||||
SetSizer(MainSizer);
|
SetSizer(MainSizer);
|
||||||
|
|
||||||
|
CenterOnParent();
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
UpdateControls();
|
UpdateControls();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue