Fix #383 and pray it didn't subtly break something else (reusable struct+function for properly splitting and handling karaoke)

Originally committed to SVN as r1290.
This commit is contained in:
Niels Martin Hansen 2007-06-23 00:21:20 +00:00
parent 2b8fc2a2d5
commit f205d35a5a
5 changed files with 284 additions and 167 deletions

119
aegisub/ass_karaoke.cpp Normal file
View File

@ -0,0 +1,119 @@
// Copyright (c) 2006-2007, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:jiifurusu@gmail.com
//
#include "ass_karaoke.h"
#include "ass_override.h"
AssKaraokeSyllable::AssKaraokeSyllable()
{
duration = 0;
text = _T("");
unstripped_text = _T("");
type = _T("");
tag = 0;
}
void ParseAssKaraokeTags(AssDialogue *line, AssKaraokeVector &syls)
{
// Assume line already has tags parsed
AssKaraokeSyllable syl;
bool brackets_open = false;
for (int i = 0; i < (int)line->Blocks.size(); i++) {
AssDialogueBlock *block = line->Blocks[i];
switch (block->type) {
case BLOCK_BASE:
assert(block->type != BLOCK_BASE);
break;
case BLOCK_PLAIN:
syl.text += block->text;
syl.unstripped_text += block->text;
break;
case BLOCK_DRAWING:
// Regard drawings as tags
syl.unstripped_text += block->text;
break;
case BLOCK_OVERRIDE: {
AssDialogueBlockOverride *ovr = block->GetAsOverride(block);
for (int j = 0; j < (int)ovr->Tags.size(); j++) {
AssOverrideTag *tag = ovr->Tags[j];
if (tag->IsValid() && tag->Name.Mid(0,2).CmpNoCase(_T("\\k")) == 0) {
// karaoke tag
if (brackets_open) {
syl.unstripped_text += _T("}");
brackets_open = false;
}
// Store syllable
syls.push_back(syl);
syl.text = _T("");
syl.unstripped_text = _T("");
syl.tag = tag;
syl.type = tag->Name;
syl.duration = tag->Params[0]->AsInt();
} else {
// not karaoke tag
if (!brackets_open) {
syl.unstripped_text += _T("{");
brackets_open = true;
}
syl.unstripped_text += tag->ToString();
}
}
if (brackets_open) {
brackets_open = false;
syl.unstripped_text += _T("}");
}
break;
}
}
}
syls.push_back(syl);
}

53
aegisub/ass_karaoke.h Normal file
View File

@ -0,0 +1,53 @@
// Copyright (c) 2007, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:jiifurusu@gmail.com
//
#pragma once
#include "ass_dialogue.h"
#include <vector>
struct AssKaraokeSyllable {
int duration; // centiseconds
wxString text; // stripped text of syllable
wxString unstripped_text; // including misc. tags
wxString type; // highlight type, \k \K \kf \ko (backslash included)
AssOverrideTag *tag; // parsed override tag for direct modification
AssKaraokeSyllable();
};
typedef std::vector<AssKaraokeSyllable> AssKaraokeVector;
void ParseAssKaraokeTags(AssDialogue *line, AssKaraokeVector &syls);

View File

@ -302,19 +302,19 @@ void AudioDisplay::UpdateImage(bool weak) {
__int64 pos1,pos2;
int len,curpos;
wxCoord tw=0,th=0;
KaraokeSyllable *curSyl;
AudioKaraokeSyllable *curSyl;
wxString temptext;
// Draw syllables
for (size_t i=0;i<karn;i++) {
curSyl = &karaoke->syllables.at(i);
len = curSyl->length*10;
curpos = curSyl->position*10;
len = curSyl->duration*10;
curpos = curSyl->start_time*10;
if (len != -1) {
pos1 = GetXAtMS(curStartMS+curpos);
pos2 = GetXAtMS(curStartMS+len+curpos);
dc.DrawLine(pos2,0,pos2,h);
temptext = curSyl->contents;
temptext = curSyl->text;
temptext.Trim(true);
temptext.Trim(false);
GetTextExtent(temptext,&tw,&th,NULL,NULL,&curFont);
@ -639,8 +639,8 @@ void AudioDisplay::GetKaraokePos(__int64 &karStart,__int64 &karEnd, bool cap) {
if (karaoke->curSyllable >= nsyls) karaoke->curSyllable = nsyls-1;
// Get positions
int pos = karaoke->syllables.at(karaoke->curSyllable).position;
int len = karaoke->syllables.at(karaoke->curSyllable).length;
int pos = karaoke->syllables.at(karaoke->curSyllable).start_time;
int len = karaoke->syllables.at(karaoke->curSyllable).duration;
karStart = GetXAtMS(curStartMS+pos*10);
karEnd = GetXAtMS(curStartMS+pos*10+len*10);
@ -1025,8 +1025,8 @@ void AudioDisplay::GetTimesSelection(int &start,int &end) {
try {
if (karaoke->enabled) {
int pos = karaoke->syllables.at(karaoke->curSyllable).position;
int len = karaoke->syllables.at(karaoke->curSyllable).length;
int pos = karaoke->syllables.at(karaoke->curSyllable).start_time;
int len = karaoke->syllables.at(karaoke->curSyllable).duration;
start = curStartMS+pos*10;
end = curStartMS+pos*10+len*10;
}
@ -1394,8 +1394,8 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
if (karaoke->enabled) {
int syl = GetSyllableAtX(x);
if (syl != -1) {
int start = karaoke->syllables.at(syl).position * 10 + dialogue->Start.GetMS();
int count = karaoke->syllables.at(syl).length * 10;
int start = karaoke->syllables.at(syl).start_time * 10 + dialogue->Start.GetMS();
int count = karaoke->syllables.at(syl).duration * 10;
player->Play(GetSampleAtMS(start),GetSampleAtMS(count));
//return;
}
@ -1458,12 +1458,12 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
else {
// Look for a syllable
__int64 pos,len,curpos;
KaraokeSyllable *curSyl;
AudioKaraokeSyllable *curSyl;
size_t karn = karaoke->syllables.size();
for (size_t i=0;i<karn;i++) {
curSyl = &karaoke->syllables.at(i);
len = curSyl->length*10;
curpos = curSyl->position*10;
len = curSyl->duration*10;
curpos = curSyl->start_time*10;
if (len != -1) {
pos = GetXAtMS(curStartMS+len+curpos);
@ -1560,14 +1560,14 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
if (hold == 4 && leftIsDown) {
// Set new value
int curpos,len,pos,nkar;
KaraokeSyllable *curSyl=NULL,*nextSyl=NULL;
AudioKaraokeSyllable *curSyl=NULL,*nextSyl=NULL;
curSyl = &karaoke->syllables.at(holdSyl);
nkar = (int)karaoke->syllables.size();
if (holdSyl < nkar-1) {
nextSyl = &karaoke->syllables.at(holdSyl+1);
}
curpos = curSyl->position;
len = curSyl->length;
curpos = curSyl->start_time;
len = curSyl->duration;
pos = GetXAtMS(curStartMS+(len+curpos)*10);
if (x != pos) {
// Calculate delta in centiseconds
@ -2226,8 +2226,8 @@ int AudioDisplay::GetSyllableAtX(int x) {
// Find a matching syllable
for (size_t i=0;i<syllables;i++) {
sylstart = karaoke->syllables.at(i).position*10 + curStartMS;
sylend = karaoke->syllables.at(i).length*10 + sylstart;
sylstart = karaoke->syllables.at(i).start_time*10 + curStartMS;
sylend = karaoke->syllables.at(i).duration*10 + sylstart;
if (ms >= sylstart && ms < sylend) {
return (int)i;
}

View File

@ -45,19 +45,25 @@
#include <algorithm>
////////////////////////
// Syllable constructor
KaraokeSyllable::KaraokeSyllable() {
length = 0;
position = 0;
display_w = 0;
display_x = 0;
tag = _T("\\k");
pending_splits.clear();
selected = false;
original_tagdata = 0;
/////////////////////
// Empty constructor
AudioKaraokeSyllable::AudioKaraokeSyllable()
: AssKaraokeSyllable()
, start_time(0), selected(false)
, display_w(0), display_x(0)
{
}
//////////////////////////////
// Copy-from-base constructor
AudioKaraokeSyllable::AudioKaraokeSyllable(const AssKaraokeSyllable &base)
: AssKaraokeSyllable(base)
, start_time(0), selected(false)
, display_w(0), display_x(0)
{
}
///////////////
// Constructor
@ -125,28 +131,6 @@ bool AudioKaraoke::LoadFromDialogue(AssDialogue *_diag) {
}
///////////////////////////////
// Calculate length of karaoke
AssOverrideTag * AudioKaraoke::GetKaraokeLength(AssDialogueBlockOverride *block) {
AssOverrideTag *tag, *len = 0;
size_t n = block->Tags.size();
for (size_t i=0;i<n;i++) {
tag = block->Tags.at(i);
if (tag->Name == _T("\\k") || tag->Name == _T("\\K") || tag->Name == _T("\\kf") || tag->Name == _T("\\ko")) {
len = tag;
}
}
return len;
}
////////////////////////////
// Gets tag of nth syllable
wxString AudioKaraoke::GetSyllableTag(AssDialogueBlockOverride *block,int n) {
return block->Tags.at(n)->Name;
}
////////////////////
// Writes line back
void AudioKaraoke::Commit() {
@ -156,7 +140,7 @@ void AudioKaraoke::Commit() {
EndSplit(true);
}
wxString finalText = _T("");
KaraokeSyllable *syl;
AudioKaraokeSyllable *syl;
size_t n = syllables.size();
wxLogDebug(_T("AudioKaraoke::Commit: syllables.size() = %u"), n);
if (must_rebuild) {
@ -164,7 +148,7 @@ void AudioKaraoke::Commit() {
workDiag->ClearBlocks();
for (size_t i=0;i<n;i++) {
syl = &syllables.at(i);
finalText += wxString::Format(_T("{%s%i}"), syl->tag.c_str(), syl->length) + syl->contents;
finalText += wxString::Format(_T("{%s%i}"), syl->type.c_str(), syl->duration) + syl->text;
}
workDiag->Text = finalText;
workDiag->ParseASSTags();
@ -174,11 +158,11 @@ void AudioKaraoke::Commit() {
for (size_t i = 0; i < n; i++) {
wxLogDebug(_T("AudioKaraoke::Commit: Updating syllable %d"), i);
syl = &syllables.at(i);
wxLogDebug(_T("AudioKaraoke::Commit: Syllable pointer: %p; tagdata pointer: %p; length: %d"), syl, syl->original_tagdata, syl->length);
wxLogDebug(_T("AudioKaraoke::Commit: Syllable pointer: %p; tagdata pointer: %p; length: %d"), syl, syl->tag, syl->duration);
// Some weird people have text before the first karaoke tag on a line.
// Check that a karaoke tag actually exists for the (non-)syllable to avoid a crash.
if (syl->original_tagdata)
syl->original_tagdata->SetInt(syl->length);
if (syl->tag && syl->tag->Params.size()>0)
syl->tag->Params[0]->SetInt(syl->duration);
// Of course, if the user changed the duration of such a non-syllable, its timing can't be updated and will stay zero.
// There is no way to check for that right now, and I can't bother to fix it.
}
@ -222,7 +206,7 @@ void AudioKaraoke::AutoSplit() {
must_rebuild = true;
AssDialogue newDiag(diag->GetEntryData());
newDiag.Text = newText;
//newDiag.ParseASSTags();
newDiag.ParseASSTags();
ParseDialogue(&newDiag);
wxLogDebug(_T("AudioKaraoke::AutoSplit: returning"));
@ -232,61 +216,31 @@ void AudioKaraoke::AutoSplit() {
//////////////////////////////////
// Parses text to extract karaoke
bool AudioKaraoke::ParseDialogue(AssDialogue *curDiag) {
wxLogDebug(_T("AudioKaraoke::ParseDialogue(curDiag=%p)"), curDiag);
// parse the tagdata
AssKaraokeVector tempsyls;
ParseAssKaraokeTags(curDiag, tempsyls);
// Wipe
bool found_kara = tempsyls.size() > 1;
// copy base syllables to real
syllables.clear();
// Prepare syllable data
AssDialogueBlock *block;
AssDialogueBlockOverride *override;
AssDialogueBlockPlain *plain;
KaraokeSyllable temp;
temp.contents = _T("");
int pos = 0;
temp.length = 0;
temp.position = 0;
curDiag->ParseASSTags();
size_t n = curDiag->Blocks.size();
bool foundOne = false;
bool foundBlock = false;
// Load syllable data
for (size_t i=0;i<n;i++) {
block = curDiag->Blocks.at(i);
if (override = AssDialogueBlock::GetAsOverride(block)) {
AssOverrideTag *len = GetKaraokeLength(override);
if (len) {
if (foundOne) syllables.push_back(temp);
foundOne = true;
foundBlock = true;
pos += temp.length;
temp.length = len->Params.at(0)->AsInt();
temp.position = pos;
temp.contents = _T("");
temp.tag = len->Name;
temp.original_tagdata = len->Params.at(0);
}
}
else if (plain = AssDialogueBlock::GetAsPlain(block)) {
temp.contents += plain->text;
if (plain->text != _T("")) foundOne = true;
}
syllables.reserve(tempsyls.size());
int cur_time = 0;
for (AssKaraokeVector::iterator base = tempsyls.begin(); base != tempsyls.end(); ++base) {
AudioKaraokeSyllable fullsyl(*base);
fullsyl.start_time = cur_time;
cur_time += fullsyl.duration;
syllables.push_back(fullsyl);
}
// Empty?
if (curDiag->Text.IsEmpty()) {
temp.length = (curDiag->End.GetMS() - curDiag->Start.GetMS())/10;
temp.contents = curDiag->Text;
temp.position = 0;
foundBlock = true;
// if first syllable is empty, remove it
if (!syllables[0].unstripped_text) {
syllables.erase(syllables.begin());
found_kara = syllables.size() > 0;
}
// Last syllable
if (foundBlock) syllables.push_back(temp);
wxLogDebug(_T("AudioKaraoke::ParseDialogue: returning %d"), foundBlock?1:0);
return foundBlock;
//curDiag->ClearBlocks();
// if there's more than one syllable in the list, at least one karaoke tag was found
return found_kara;
}
@ -341,9 +295,9 @@ void AudioKaraoke::OnPaint(wxPaintEvent &event) {
int delta;
int dlen;
for (size_t i=0;i<syln;i++) {
KaraokeSyllable &syl = syllables.at(i);
AudioKaraokeSyllable &syl = syllables.at(i);
// Calculate text length
temptext = syl.contents;
temptext = syl.text;
// If we're splitting, every character must be drawn
if (!splitting) {
temptext.Trim(true);
@ -486,21 +440,21 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
// Valid syllable
if (syli != -1) {
KaraokeSyllable &syl = syllables.at(syli);
AudioKaraokeSyllable &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);
dc.GetPartialTextExtents(syl.text, widths);
// Find the character closest to the mouse
int rx = x - syl.display_x - 4;
int split_cursor_char = -2;
split_cursor_syl = -1;
split_cursor_x = -1;
if (syl.contents.Len() > 0) {
if (syl.text.Len() > 0) {
int lastx = 0;
split_cursor_syl = syli;
for (unsigned int i = 0; i < widths.size(); i++) {
@ -622,7 +576,7 @@ void AudioKaraoke::Join() {
// Variables
bool gotOne = false;
size_t syls = syllables.size();
KaraokeSyllable *curSyl;
AudioKaraokeSyllable *curSyl;
int first = 0;
// Loop
@ -634,8 +588,8 @@ void AudioKaraoke::Join() {
first = i;
}
else {
syllables.at(i-1).length += curSyl->length;
syllables.at(i-1).contents += curSyl->contents;
syllables.at(i-1).duration += curSyl->duration;
syllables.at(i-1).unstripped_text += curSyl->unstripped_text;
syllables.erase(syllables.begin()+i);
i--;
syls--;
@ -707,36 +661,38 @@ int AudioKaraoke::SplitSyl (unsigned int n) {
syllables.reserve(syllables.size() + syllables[n].pending_splits.size());
// The syllable we're splitting
KaraokeSyllable &basesyl = syllables[n];
wxLogDebug(_T("AudioKaraoke::SplitSyl: basesyl. contents='%s' selected=%d"), basesyl.contents.c_str(), basesyl.selected?1:0);
AudioKaraokeSyllable &basesyl = syllables[n];
wxLogDebug(_T("AudioKaraoke::SplitSyl: basesyl. contents='%s' selected=%d"), basesyl.unstripped_text.c_str(), basesyl.selected?1:0);
// Start by sorting the split points
std::sort(basesyl.pending_splits.begin(), basesyl.pending_splits.end());
wxString originalText = basesyl.contents;
int originalDuration = basesyl.length;
wxString originalText = basesyl.text;
int originalDuration = basesyl.duration;
// Fixup the first syllable
basesyl.contents = originalText.Mid(0, basesyl.pending_splits[0] + 1);
syllables[n].length = originalDuration * basesyl.contents.Length() / originalText.Length();
int curpos = basesyl.position + basesyl.length;
basesyl.text = originalText.Mid(0, basesyl.pending_splits[0] + 1);
basesyl.unstripped_text = basesyl.text;
syllables[n].duration = originalDuration * basesyl.text.Length() / originalText.Length();
int curpos = basesyl.start_time + basesyl.duration;
// For each split, make a new syllable
for (unsigned int i = 0; i < basesyl.pending_splits.size(); i++) {
KaraokeSyllable newsyl;
AudioKaraokeSyllable newsyl;
if (i < basesyl.pending_splits.size()-1) {
// in the middle
newsyl.contents = originalText.Mid(basesyl.pending_splits[i]+1, basesyl.pending_splits[i+1] - basesyl.pending_splits[i]);
newsyl.text = originalText.Mid(basesyl.pending_splits[i]+1, basesyl.pending_splits[i+1] - basesyl.pending_splits[i]);
} else {
// the last one (take the rest)
newsyl.contents = originalText.Mid(basesyl.pending_splits[i]+1);
newsyl.text = originalText.Mid(basesyl.pending_splits[i]+1);
}
newsyl.length = originalDuration * newsyl.contents.Length() / originalText.Length();
newsyl.position = curpos;
newsyl.tag = basesyl.tag;
newsyl.unstripped_text = newsyl.text;
newsyl.duration = originalDuration * newsyl.text.Length() / originalText.Length();
newsyl.start_time = curpos;
newsyl.type = basesyl.type;
newsyl.selected = basesyl.selected;
wxLogDebug(_T("AudioKaraoke::SplitSyl: newsyl. contents='%s' selected=%d"), newsyl.contents.c_str(), newsyl.selected?1:0);
curpos += newsyl.length;
wxLogDebug(_T("AudioKaraoke::SplitSyl: newsyl. contents='%s' selected=%d"), newsyl.text.c_str(), newsyl.selected?1:0);
curpos += newsyl.duration;
syllables.insert(syllables.begin()+n+i+1, newsyl);
}
@ -745,11 +701,11 @@ int AudioKaraoke::SplitSyl (unsigned int n) {
// Use an unfair method, just adding 1 to each syllable one after another, until it's correct
int newDuration = 0;
for (unsigned int j = n; j < basesyl.pending_splits.size()+n+1; j++) {
newDuration += syllables[j].length;
newDuration += syllables[j].duration;
}
unsigned int k = n;
while (newDuration < originalDuration) {
syllables[k].length++;
syllables[k].duration++;
k++;
if (k >= syllables.size()) {
k = n;
@ -766,10 +722,11 @@ int AudioKaraoke::SplitSyl (unsigned int n) {
//////////////////////////////////
// Apply delta length to syllable
// FIXME: is this even used?
bool AudioKaraoke::SyllableDelta(int n,int delta,int mode) {
wxLogDebug(_T("AudioKaraoke::SyllableDelta(n=%d, delta=%d, mode=%d)"), n, delta, mode);
// Get syllable and next
KaraokeSyllable *curSyl=NULL,*nextSyl=NULL;
AudioKaraokeSyllable *curSyl=NULL,*nextSyl=NULL;
curSyl = &syllables.at(n);
int nkar = syllables.size();
if (n < nkar-1) {
@ -777,32 +734,32 @@ bool AudioKaraoke::SyllableDelta(int n,int delta,int mode) {
}
// Get variables
int len = curSyl->length;
int len = curSyl->duration;
// Cap delta
int minLen = 0;
if (len + delta < minLen) delta = minLen-len;
if (mode == 0 && nextSyl && (nextSyl->length - delta) < minLen) delta = nextSyl->length - minLen;
if (mode == 0 && nextSyl && (nextSyl->duration - delta) < minLen) delta = nextSyl->duration - minLen;
wxLogDebug(_T("AudioKaraoke::SyllableDelta: nkar=%d, len=%d, minLen=%d, delta=%d"), nkar, len, minLen, delta);
// Apply
if (delta != 0) {
wxLogDebug(_T("AudioKaraoke::SyllableDelta: delta != 0"));
curSyl->length += delta;
curSyl->duration += delta;
// Normal mode
if (mode == 0 && nextSyl) {
wxLogDebug(_T("AudioKaraoke::SyllableDelta: normal mode"));
nextSyl->length -= delta;
nextSyl->position += delta;
nextSyl->duration -= delta;
nextSyl->start_time += delta;
}
// Shift mode
if (mode == 1) {
wxLogDebug(_T("AudioKaraoke::SyllableDelta: shift mode"));
for (int i=n+1;i<nkar;i++) {
syllables.at(i).position += delta;
syllables.at(i).start_time += delta;
}
}
@ -828,13 +785,13 @@ AudioKaraokeTagMenu::AudioKaraokeTagMenu(AudioKaraoke *_kara)
// Find out what kinds of tags are in use atm
for (size_t i = 0; i < kara->syllables.size(); i++) {
KaraokeSyllable &syl = kara->syllables[i];
AudioKaraokeSyllable &syl = kara->syllables[i];
if (syl.selected) {
if (syl.tag == _T("\\k")) {
if (syl.type == _T("\\k")) {
Check(10001, true);
} else if (syl.tag == _T("\\kf") || syl.tag == _T("\\K")) {
} else if (syl.type == _T("\\kf") || syl.type == _T("\\K")) {
Check(10002, true);
} else if (syl.tag == _T("\\ko")) {
} else if (syl.type == _T("\\ko")) {
Check(10003, true);
}
}
@ -871,11 +828,11 @@ void AudioKaraokeTagMenu::OnSelectItem(wxCommandEvent &event) {
size_t firstsel = kara->syllables.size();
int lastsel = -1;
for (size_t i = 0; i < kara->syllables.size(); i++) {
KaraokeSyllable &syl = kara->syllables[i];
AudioKaraokeSyllable &syl = kara->syllables[i];
if (syl.selected) {
if (firstsel > i) firstsel = i;
lastsel = i;
syl.tag = newtag;
syl.type = newtag;
}
}

View File

@ -42,6 +42,7 @@
// Headers
#include <wx/wxprec.h>
#include <vector>
#include "ass_karaoke.h"
//////////////
@ -54,30 +55,19 @@ class AudioDisplay;
class AudioBox;
class AudioKaraokeTagMenu;
//////////////////
// Syllable class
class KaraokeSyllable {
public:
int length;
int position;
///////////////////////////////////
// Karaoke syllable with more info
struct AudioKaraokeSyllable : AssKaraokeSyllable {
int start_time; // centiseconds
bool selected;
std::vector<int> pending_splits;
int display_w;
int display_x;
wxString contents;
wxString tag;
bool selected;
AssOverrideParameter *original_tagdata;
std::vector<int> pending_splits;
KaraokeSyllable();
AudioKaraokeSyllable();
AudioKaraokeSyllable(const AssKaraokeSyllable &base);
};
////////////
// Typedefs
typedef std::vector<KaraokeSyllable> SylVector;
typedef std::vector<AudioKaraokeSyllable> AudioKaraokeVector;
/////////
@ -93,8 +83,6 @@ private:
int split_cursor_syl;
int split_cursor_x;
AssOverrideTag *GetKaraokeLength(AssDialogueBlockOverride *block);
wxString GetSyllableTag(AssDialogueBlockOverride *block,int n);
void AutoSplit();
bool ParseDialogue(AssDialogue *diag);
@ -113,7 +101,7 @@ public:
int selectionCount;
bool enabled;
bool splitting;
SylVector syllables;
AudioKaraokeVector syllables;
AudioKaraoke(wxWindow *parent);
virtual ~AudioKaraoke();