Various Unicode-related fixes.

Changed some types to lower the amount of int/size_t inconsistencies. This might have introduced some stupid bugs... beware!
Removed old, unused "project file" code. (cleanup)

Fixed bug #195: "Join (as karaoke)" is broken when 2 lines don't follow immediately after another

Implemented feature req #184: Text Only Export

Fixed bug #180: conversion from srt to ass doesn't specify WrapStyle

Implemented feature req #188: highlighting of currently selected style in the styles manager

Originally committed to SVN as r537.
This commit is contained in:
Niels Martin Hansen 2006-10-19 22:53:06 +00:00
parent e3d0a51c81
commit e5ef7b4be2
13 changed files with 159 additions and 105 deletions

View file

@ -539,6 +539,7 @@ void AssDialogue::StripTags () {
for (vector<AssDialogueBlock*>::iterator cur=Blocks.begin();cur!=Blocks.end();cur=next) {
next = cur;
next++;
// FIXME: doesn't this crash when there's too many override blocks in one line?
if ((*cur)->type == BLOCK_OVERRIDE) {
delete *cur;
Blocks.erase(cur);

View file

@ -76,12 +76,16 @@ void AssFile::Load (const wxString _filename,const wxString charset) {
try {
// Try to open file
std::ifstream file;
file.open(_filename.mb_str(wxConvLocal));
if (!file.is_open()) {
FILE *file;
#ifdef WIN32
file = _tfopen(_filename.c_str(), _T("r"));
#else
file = fopen(_filrname.mb_str(wxConvFileName), "r");
#endif
if (!file) {
throw _T("Unable to open file \"") + _filename + _T("\". Check if it exists and if you have permissions to read it.");
}
file.close();
fclose(file);
// Find file encoding
wxString enc;
@ -411,6 +415,7 @@ void AssFile::LoadDefault (bool defline) {
AddLine(_T("[Script Info]"),_T("[Script Info]"),-1,IsSSA);
AddLine(_T("Title: Default Aegisub file"),_T("[Script Info]"),-1,IsSSA);
AddLine(_T("ScriptType: v4.00+"),_T("[Script Info]"),-1,IsSSA);
AddLine(_T("WrapStyle: 1"), _T("[Script Info]"),-1,IsSSA);
AddLine(_T("PlayResX: 640"),_T("[Script Info]"),-1,IsSSA);
AddLine(_T("PlayResY: 480"),_T("[Script Info]"),-1,IsSSA);
AddLine(_T(""),_T("[Script Info]"),-1,IsSSA);

View file

@ -40,6 +40,8 @@
#include "ass_style.h"
#include "ass_file.h"
#include "main.h"
#include "text_file_reader.h"
#include "text_file_writer.h"
#include <fstream>
@ -48,20 +50,16 @@
void AssStyleStorage::Save(wxString name) {
if (name.IsEmpty()) return;
using namespace std;
ofstream file;
wxString filename = AegisubApp::folderName;
filename += _T("/catalog/");
filename += name;
filename += _T(".sty");
file.open(filename.mb_str(wxConvLocal));
for (list<AssStyle*>::iterator cur=style.begin();cur!=style.end();cur++) {
file << (*cur)->GetEntryData().mb_str(wxConvUTF8) << endl;
}
TextFileWriter file(filename, _T("UTF-8"));
file.close();
for (std::list<AssStyle*>::iterator cur=style.begin();cur!=style.end();cur++) {
file.WriteLineToFile((*cur)->GetEntryData());
}
}
@ -70,26 +68,18 @@ void AssStyleStorage::Save(wxString name) {
void AssStyleStorage::Load(wxString name) {
if (name.IsEmpty()) return;
using namespace std;
char buffer[65536];
ifstream file;
wxString filename = AegisubApp::folderName;
filename += _T("/catalog/");
filename += name;
filename += _T(".sty");
Clear();
file.open(filename.mb_str(wxConvLocal));
if (!file.is_open()) {
throw _T("Failed opening file.");
}
TextFileReader file(filename, _T("UTF-8"));
AssStyle *curStyle;
while (!file.eof()) {
file.getline(buffer,65536);
wxString data(buffer,wxConvUTF8);
data.Trim();
while (file.HasMoreLines()) {
wxString data = file.ReadLineFromFile();
if (data.substr(0,6) == _T("Style:")) {
try {
curStyle = new AssStyle(data);
@ -99,8 +89,6 @@ void AssStyleStorage::Load(wxString name) {
}
}
}
file.close();
}

View file

@ -182,8 +182,8 @@ END_EVENT_TABLE()
// Process start
void DialogExport::OnProcess(wxCommandEvent &event) {
// Get destination
//wxString filename = wxFileSelector(_("Export subtitles file"),_T(""),_T(""),_T(""),_T("All Supported Types (*.ass,*.ssa,*.srt,*.prs)|*.ass;*.ssa;*.srt;*.prs|Advanced Substation Alpha (*.ass)|*.ass|Substation Alpha (*.ssa)|*.ssa|SubRip (*.srt)|*.srt|Pre-Rendered Subtitles (*.prs)|*.prs"),wxSAVE | wxOVERWRITE_PROMPT,this);
wxString filename = wxFileSelector(_("Export subtitles file"),_T(""),_T(""),_T(""),_T("All Supported Types (*.ass,*.ssa,*.srt)|*.ass;*.ssa;*.srt|Advanced Substation Alpha (*.ass)|*.ass|Substation Alpha (*.ssa)|*.ssa|SubRip (*.srt)|*.srt"),wxSAVE | wxOVERWRITE_PROMPT,this);
//wxString filename = wxFileSelector(_("Export subtitles file"),_T(""),_T(""),_T(""),_T("All Supported Types (*.ass,*.ssa,*.srt,*.prs)|*.ass;*.ssa;*.srt;*.prs|Advanced Substation Alpha (*.ass)|*.ass|Substation Alpha (*.ssa)|*.ssa|SubRip (*.srt)|*.srt|Plain-text (*.txt)|*.txt|Pre-Rendered Subtitles (*.prs)|*.prs"),wxSAVE | wxOVERWRITE_PROMPT,this);
wxString filename = wxFileSelector(_("Export subtitles file"),_T(""),_T(""),_T(""),_T("All Supported Types (*.ass,*.ssa,*.srt,*.txt)|*.ass;*.ssa;*.srt;*.txt|Advanced Substation Alpha (*.ass)|*.ass|Substation Alpha (*.ssa)|*.ssa|SubRip (*.srt)|*.srt|Plain-text (*.txt)|*.txt"),wxSAVE | wxOVERWRITE_PROMPT,this);
if (filename.empty()) return;
// Add filters

View file

@ -41,6 +41,7 @@
#include "dialog_style_editor.h"
#include "ass_style.h"
#include "ass_file.h"
#include "ass_dialogue.h"
#include "main.h"
#include "options.h"
#include "subs_grid.h"
@ -64,38 +65,44 @@ DialogStyleManager::DialogStyleManager (wxWindow *parent,SubtitlesGrid *_grid)
CatalogBox->Add(CatalogDelete,0,0,0);
// Storage styles list
StorageList = new wxListBox(this, LIST_STORAGE, wxDefaultPosition, wxSize(185,250), 0, NULL, wxLB_EXTENDED);
StorageList = new wxListBox(this, LIST_STORAGE, wxDefaultPosition, wxSize(205,250), 0, NULL, wxLB_EXTENDED);
wxSizer *StorageBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Storage"));
wxSizer *StorageButtons = new wxBoxSizer(wxHORIZONTAL);
MoveToLocal = new wxButton(this, BUTTON_STORAGE_COPYTO, _("Copy to current script ->"), wxDefaultPosition, wxSize(185,25));
MoveToLocal = new wxButton(this, BUTTON_STORAGE_COPYTO, _("Copy to current script ->"), wxDefaultPosition, wxSize(205,25));
StorageNew = new wxButton(this, BUTTON_STORAGE_NEW, _("New"), wxDefaultPosition, wxSize(40,25));
StorageEdit = new wxButton(this, BUTTON_STORAGE_EDIT, _("Edit"), wxDefaultPosition, wxSize(40,25));
StorageCopy = new wxButton(this, BUTTON_STORAGE_COPY, _("Copy"), wxDefaultPosition, wxSize(40,25));
StorageDelete = new wxButton(this, BUTTON_STORAGE_DELETE, _("Delete"), wxDefaultPosition, wxSize(40,25));
StorageButtons->Add(StorageNew,1,wxEXPAND | wxALL,0);
StorageButtons->Add(StorageEdit,1,wxEXPAND | wxALL,0);
StorageButtons->Add(StorageCopy,1,wxEXPAND | wxALL,0);
StorageButtons->Add(StorageDelete,1,wxEXPAND | wxALL,0);
StorageBox->Add(StorageList,0,wxEXPAND | wxALL,0);
StorageBox->Add(MoveToLocal,0,wxEXPAND | wxALL,0);
StorageBox->Add(StorageButtons,0,wxEXPAND | wxALL,0);
MoveToLocal->Disable();
StorageEdit->Disable();
StorageCopy->Disable();
StorageDelete->Disable();
// Local styles list
CurrentList = new wxListBox(this, LIST_CURRENT, wxDefaultPosition, wxSize(185,250), 0, NULL, wxLB_EXTENDED);
CurrentList = new wxListBox(this, LIST_CURRENT, wxDefaultPosition, wxSize(205,250), 0, NULL, wxLB_EXTENDED);
wxSizer *CurrentBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Current script"));
wxSizer *CurrentButtons = new wxBoxSizer(wxHORIZONTAL);
MoveToStorage = new wxButton(this, BUTTON_CURRENT_COPYTO, _("<- Copy to storage"), wxDefaultPosition, wxSize(185,25));
MoveToStorage = new wxButton(this, BUTTON_CURRENT_COPYTO, _("<- Copy to storage"), wxDefaultPosition, wxSize(205,25));
CurrentNew = new wxButton(this, BUTTON_CURRENT_NEW, _("New"), wxDefaultPosition, wxSize(40,25));
CurrentEdit = new wxButton(this, BUTTON_CURRENT_EDIT, _("Edit"), wxDefaultPosition, wxSize(40,25));
CurrentCopy = new wxButton(this, BUTTON_CURRENT_COPY, _("Copy"), wxDefaultPosition, wxSize(40,25));
CurrentDelete = new wxButton(this, BUTTON_CURRENT_DELETE, _("Delete"), wxDefaultPosition, wxSize(40,25));
CurrentButtons->Add(CurrentNew,1,wxEXPAND | wxALL,0);
CurrentButtons->Add(CurrentEdit,1,wxEXPAND | wxALL,0);
CurrentButtons->Add(CurrentCopy,1,wxEXPAND | wxALL,0);
CurrentButtons->Add(CurrentDelete,1,wxEXPAND | wxALL,0);
CurrentBox->Add(CurrentList,0,wxEXPAND | wxALL,0);
CurrentBox->Add(MoveToStorage,0,wxEXPAND | wxALL,0);
CurrentBox->Add(CurrentButtons,0,wxEXPAND | wxALL,0);
MoveToStorage->Disable();
CurrentEdit->Disable();
CurrentCopy->Disable();
CurrentDelete->Disable();
@ -123,6 +130,26 @@ DialogStyleManager::DialogStyleManager (wxWindow *parent,SubtitlesGrid *_grid)
// Populate lists
LoadCatalog();
LoadCurrentStyles(AssFile::top);
// Select default item
wxString selected_style;
if (_grid) {
AssDialogue *dia = _grid->GetDialogue(_grid->GetFirstSelRow());
selected_style = dia->Style;
}
if (StorageList->SetStringSelection(selected_style)) {
StorageEdit->Enable();
StorageCopy->Enable();
StorageDelete->Enable();
MoveToLocal->Enable();
}
if (CurrentList->SetStringSelection(selected_style)) {
CurrentEdit->Enable();
CurrentCopy->Enable();
CurrentDelete->Enable();
MoveToStorage->Enable();
}
}
@ -261,6 +288,8 @@ BEGIN_EVENT_TABLE(DialogStyleManager, wxDialog)
EVT_LISTBOX_DCLICK(LIST_CURRENT, DialogStyleManager::OnCurrentEdit)
EVT_BUTTON(BUTTON_CURRENT_COPYTO, DialogStyleManager::OnCopyToStorage)
EVT_BUTTON(BUTTON_STORAGE_COPYTO, DialogStyleManager::OnCopyToCurrent)
EVT_BUTTON(BUTTON_CURRENT_EDIT, DialogStyleManager::OnCurrentEdit)
EVT_BUTTON(BUTTON_STORAGE_EDIT, DialogStyleManager::OnStorageEdit)
EVT_BUTTON(BUTTON_CURRENT_COPY, DialogStyleManager::OnCurrentCopy)
EVT_BUTTON(BUTTON_STORAGE_COPY, DialogStyleManager::OnStorageCopy)
EVT_BUTTON(BUTTON_CURRENT_NEW, DialogStyleManager::OnCurrentNew)
@ -390,21 +419,11 @@ void DialogStyleManager::OnCurrentEdit (wxCommandEvent &event) {
void DialogStyleManager::OnCurrentChange (wxCommandEvent &event) {
wxArrayInt selections;
int n = CurrentList->GetSelections(selections);
if (n == 0) {
CurrentCopy->Disable();
CurrentDelete->Disable();
MoveToStorage->Disable();
}
else if (n == 1) {
CurrentCopy->Enable();
CurrentDelete->Enable();
MoveToStorage->Enable();
}
else {
CurrentDelete->Enable();
MoveToStorage->Enable();
CurrentCopy->Disable();
}
CurrentEdit->Enable(n == 1);
CurrentCopy->Enable(n == 1);
CurrentDelete->Enable(n > 0);
MoveToStorage->Enable(n > 0);
}
@ -413,21 +432,11 @@ void DialogStyleManager::OnCurrentChange (wxCommandEvent &event) {
void DialogStyleManager::OnStorageChange (wxCommandEvent &event) {
wxArrayInt selections;
int n = StorageList->GetSelections(selections);
if (n == 0) {
StorageCopy->Disable();
StorageDelete->Disable();
MoveToLocal->Disable();
}
else if (n == 1) {
StorageCopy->Enable();
StorageDelete->Enable();
MoveToLocal->Enable();
}
else {
StorageDelete->Enable();
MoveToLocal->Enable();
StorageCopy->Disable();
}
StorageEdit->Enable(n == 1);
StorageCopy->Enable(n == 1);
StorageDelete->Enable(n > 0);
MoveToLocal->Enable(n > 0);
}

View file

@ -66,10 +66,12 @@ private:
wxListBox *CurrentList;
wxButton *MoveToLocal;
wxButton *StorageNew;
wxButton *StorageEdit;
wxButton *StorageCopy;
wxButton *StorageDelete;
wxButton *MoveToStorage;
wxButton *CurrentNew;
wxButton *CurrentEdit;
wxButton *CurrentCopy;
wxButton *CurrentDelete;
@ -116,10 +118,12 @@ enum {
BUTTON_CATALOG_DELETE,
BUTTON_STORAGE_COPYTO,
BUTTON_STORAGE_NEW,
BUTTON_STORAGE_EDIT,
BUTTON_STORAGE_COPY,
BUTTON_STORAGE_DELETE,
BUTTON_CURRENT_COPYTO,
BUTTON_CURRENT_NEW,
BUTTON_CURRENT_EDIT,
BUTTON_CURRENT_COPY,
BUTTON_CURRENT_DELETE,
LIST_CATALOG,

View file

@ -457,11 +457,11 @@ void FrameMain::MenuItemEnable (int id, bool state,wxBitmap &bmp1,wxBitmap &bmp2
// Helper to rebuild menu items
wxMenuItem *FrameMain::RebuildMenuItem(wxMenu *menu,int findId,wxBitmap bmp1,wxBitmap bmp2,bool state) {
// Find pos
wxMenuItemList items = menu->GetMenuItems();
wxMenuItemList &items = menu->GetMenuItems();
int pos = -1;
for (size_t i=0;i<items.GetCount();i++) {
if (items[i]->GetId() == findId) {
pos = i;
pos = (int)i;
break;
}
}

View file

@ -135,9 +135,6 @@ private:
void OnBugTracker (wxCommandEvent &event);
void OnIRCChannel (wxCommandEvent &event);
void OnOpenProject (wxCommandEvent &event);
void OnSaveProject (wxCommandEvent &event);
void OnSaveProjectAs (wxCommandEvent &event);
void OnNewSubtitles (wxCommandEvent &event);
void OnOpenSubtitles (wxCommandEvent &event);
void OnOpenSubtitlesCharset (wxCommandEvent &event);

View file

@ -121,9 +121,6 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame)
EVT_MENU_RANGE(Menu_Audio_Recent,Menu_Audio_Recent+99, FrameMain::OnOpenRecentAudio)
EVT_MENU_RANGE(Menu_Timecodes_Recent,Menu_Timecodes_Recent+99, FrameMain::OnOpenRecentTimecodes)
EVT_MENU(Menu_File_Open, FrameMain::OnOpenProject)
EVT_MENU(Menu_File_Save, FrameMain::OnSaveProject)
EVT_MENU(Menu_File_SaveAs, FrameMain::OnSaveProjectAs)
EVT_MENU(Menu_File_Exit, FrameMain::OnExit)
EVT_MENU(Menu_File_Open_Video, FrameMain::OnOpenVideo)
EVT_MENU(Menu_File_Close_Video, FrameMain::OnCloseVideo)
@ -226,7 +223,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
// File menu
if (curMenu == fileMenu) {
// Wipe recent
int count = RecentSubs->GetMenuItemCount();
int count = (int)RecentSubs->GetMenuItemCount();
for (int i=count;--i>=0;) {
RecentSubs->Destroy(RecentSubs->FindItemByPosition(i));
}
@ -305,11 +302,11 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
}
// Wipe recent
int count = RecentVids->GetMenuItemCount();
int count = (int)RecentVids->GetMenuItemCount();
for (int i=count;--i>=0;) {
RecentVids->Destroy(RecentVids->FindItemByPosition(i));
}
count = RecentTimecodes->GetMenuItemCount();
count = (int)RecentTimecodes->GetMenuItemCount();
for (int i=count;--i>=0;) {
RecentTimecodes->Destroy(RecentTimecodes->FindItemByPosition(i));
}
@ -351,7 +348,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
MenuBar->Enable(Menu_Audio_Close,state);
// Wipe recent
int count = RecentAuds->GetMenuItemCount();
int count = (int)RecentAuds->GetMenuItemCount();
for (int i=count;--i>=0;) {
RecentAuds->Destroy(RecentAuds->FindItemByPosition(i));
}
@ -491,29 +488,6 @@ void FrameMain::OnIRCChannel(wxCommandEvent& WXUNUSED(event)) {
}
////////////////
// Open project
void FrameMain::OnOpenProject(wxCommandEvent& WXUNUSED(event)) {
// TODO
//wxString filename = wxFileSelector(_T("Open file"),_T(""),_T(""),_T(""),_T("Aegisub Project (*.vsa)|*.vsa|All Files (*.*)|*.*"),wxOPEN | wxFILE_MUST_EXIST);
}
////////////////
// Save project
void FrameMain::OnSaveProject(wxCommandEvent& WXUNUSED(event)) {
// TODO: Maybe? Perhaps autosave is better
}
///////////////////
// Save project as
void FrameMain::OnSaveProjectAs(wxCommandEvent& WXUNUSED(event)) {
// TODO: Read above note
wxString filename = wxFileSelector(_("Save file"),_T(""),_T(""),_T(""),_T("Aegisub Project (*.vsa)|*.vsa|All Files (*.*)|*.*"),wxSAVE | wxOVERWRITE_PROMPT);
}
//////////////
// Open video
void FrameMain::OnOpenVideo(wxCommandEvent& WXUNUSED(event)) {
@ -943,7 +917,7 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &event) {
if (videoBox->videoDisplay->loaded) {
// Get selection
wxArrayInt sels = SubsBox->GetSelection();
int n=sels.Count();
size_t n=sels.Count();
if (n == 0) return;
// Get shifting in ms
@ -952,7 +926,7 @@ void FrameMain::OnShiftToFrame (wxCommandEvent &event) {
int shiftBy = VFR_Output.GetTimeAtFrame(videoBox->videoDisplay->frame_n,true) - cur->Start.GetMS();
// Update
for (int i=0;i<n;i++) {
for (size_t i=0;i<n;i++) {
cur = SubsBox->GetDialogue(sels[i]);
if (cur) {
cur->Start.SetMS(cur->Start.GetMS()+shiftBy);

View file

@ -978,7 +978,7 @@ void SubtitlesGrid::JoinAsKaraoke(int n1,int n2) {
firststart = start;
}
len1 = (start - lastend) / 10;
len2 = (end - lastend) / 10;
len2 = (end - start) / 10;
// Create text
if (len1 != 0) finalText += _T("{\\k") + wxString::Format(_T("%i"),len1) + _T("}");

View file

@ -38,8 +38,10 @@
// Headers
#include "subtitle_format_txt.h"
#include "text_file_reader.h"
#include "text_file_writer.h"
#include "ass_dialogue.h"
#include "options.h"
#include "version.h"
/////////////
@ -49,6 +51,13 @@ bool TXTSubtitleFormat::CanReadFile(wxString filename) {
}
//////////////
// Can write?
bool TXTSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Right(4).Lower() == _T(".txt"));
}
/////////////
// Read file
void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using namespace std;
@ -122,3 +131,68 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na
Line->push_back(line);
}
}
/////////////
// Write file
void TXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { using namespace std;
size_t num_actor_names = 0, num_dialogue_lines = 0;
// Detect number of lines with Actor field filled out
for (list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) {
AssDialogue *dia = AssEntry::GetAsDialogue(*l);
if (dia && !dia->Comment) {
num_dialogue_lines++;
if (!dia->Actor.IsEmpty())
num_actor_names++;
}
}
// If too few lines have Actor filled out, don't write it
bool write_actors = num_actor_names > num_dialogue_lines/2;
bool strip_formatting = true;
TextFileWriter file(filename, encoding);
file.WriteLineToFile(_T("# Exported by Aegisub ") + GetAegisubShortVersionString());
// Write the file
for (list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) {
AssDialogue *dia = AssEntry::GetAsDialogue(*l);
if (dia) {
wxString out_line;
if (dia->Comment) {
out_line = _T("# ");
}
if (write_actors) {
out_line += dia->Actor + _T(": ");
}
wxString out_text;
if (strip_formatting) {
dia->ParseASSTags();
for (std::vector<AssDialogueBlock*>::iterator block = dia->Blocks.begin(); block != dia->Blocks.end(); ++block) {
if ((*block)->type == BLOCK_PLAIN) {
out_text += (*block)->GetText();
}
}
dia->ClearBlocks();
}
else {
out_text = dia->Text;
}
out_line += out_text;
if (!out_text.IsEmpty()) {
file.WriteLineToFile(out_line);
}
}
else {
// Not a dialogue line
// TODO: should any non-dia lines cause blank lines in output?
//file.WriteLineToFile(_T(""));
}
}
}

View file

@ -54,5 +54,7 @@ private:
public:
bool CanReadFile(wxString filename);
bool CanWriteFile(wxString filename);
void ReadFile(wxString filename,wxString forceEncoding);
void WriteFile(wxString filename, wxString encoding = _T(""));
};

View file

@ -165,7 +165,7 @@ void FrameRate::Load(wxString filename) {
}
last_time = currenttime;
last_frame = Frame.size();
last_frame = (int)Frame.size();
}
// V2
@ -196,7 +196,7 @@ void FrameRate::Load(wxString filename) {
}
last_time = cftime;
last_frame = Frame.size();
last_frame = (int)Frame.size();
CalcAverage();
@ -259,7 +259,7 @@ void FrameRate::SetVFR(std::vector<int> newTimes) {
Frame = newTimes;
CalcAverage();
last_time = newTimes.back();
last_frame = newTimes.size();
last_frame = (int)newTimes.size();
}
@ -306,8 +306,8 @@ int FrameRate::PFrameAtTime(int ms,bool useceil) {
// If it is, is the previous smaller?
// If so, this is the frame we're looking for
if (largerEqual && (cur == 0 || Frame[cur-1] < ms)) {
if (useceil) return cur;
return cur-1;
if (useceil) return (int)cur;
return (int)(cur)-1;
}
// Not found, continue search