Merge branch 'tap-to-time-tt-fork' of github.com:EaterOA/Aegisub into ttt

This commit is contained in:
odrling 2019-08-24 01:41:50 +02:00
commit bd6383a4cc
29 changed files with 481 additions and 29 deletions

View File

@ -891,6 +891,14 @@ void AudioDisplay::PaintMarkers(wxDC &dc, TimeRange updtime)
if (marker->GetFeet() & AudioMarker::Feet_Right)
PaintFoot(dc, marker_x, 1);
}
if (OPT_GET("Timing/Tap To Time")->GetBool()) {
dc.SetBrush(wxBrush(*wxGREEN));
dc.SetPen(*wxTRANSPARENT_PEN);
int marker_x = RelativeXFromTime(controller->GetTimingController()->GetTapMarkerPosition());
PaintTapMarker(dc, marker_x);
}
}
void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir)
@ -901,6 +909,12 @@ void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir)
dc.DrawPolygon(3, foot_bot, marker_x, audio_top+audio_height);
}
void AudioDisplay::PaintTapMarker(wxDC &dc, int marker_x)
{
wxPoint arrow[3] = { wxPoint(-foot_size * 2, 0), wxPoint(0, -foot_size * 2), wxPoint(foot_size * 2, 0) };
dc.DrawPolygon(3, arrow, marker_x, audio_top+audio_height);
}
void AudioDisplay::PaintLabels(wxDC &dc, TimeRange updtime)
{
std::vector<AudioLabelProvider::AudioLabel> labels;
@ -1229,6 +1243,7 @@ void AudioDisplay::OnAudioOpen(agi::AudioProvider *provider)
OPT_SUB("Colour/Audio Display/Spectrum", &AudioDisplay::ReloadRenderingSettings, this),
OPT_SUB("Colour/Audio Display/Waveform", &AudioDisplay::ReloadRenderingSettings, this),
OPT_SUB("Audio/Renderer/Spectrum/Quality", &AudioDisplay::ReloadRenderingSettings, this),
OPT_SUB("Timing/Tap To Time", &AudioDisplay::OnTapMarkerChanged, this),
});
OnTimingController();
}
@ -1254,10 +1269,12 @@ void AudioDisplay::OnTimingController()
timing_controller->AddMarkerMovedListener(&AudioDisplay::OnMarkerMoved, this);
timing_controller->AddUpdatedPrimaryRangeListener(&AudioDisplay::OnSelectionChanged, this);
timing_controller->AddUpdatedStyleRangesListener(&AudioDisplay::OnStyleRangesChanged, this);
timing_controller->AddUpdatedTapMarkerListener(&AudioDisplay::OnTapMarkerChanged, this);
OnStyleRangesChanged();
OnMarkerMoved();
OnSelectionChanged();
OnTapMarkerChanged();
}
}
@ -1341,6 +1358,12 @@ void AudioDisplay::OnStyleRangesChanged()
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);
}
void AudioDisplay::OnTapMarkerChanged()
{
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);
}
void AudioDisplay::OnMarkerMoved()
{
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);

View File

@ -169,6 +169,11 @@ class AudioDisplay: public wxWindow {
/// @param dir -1 for left, 1 for right
void PaintFoot(wxDC &dc, int marker_x, int dir);
/// Draw an indicator for the tap marker
/// @param dc DC to paint to
/// @param marker_x Position of the tap marker
void PaintTapMarker(wxDC &dc, int marker_x);
/// Paint the labels in a time range
/// @param dc DC to paint to
/// @param updtime Time range to repaint
@ -205,6 +210,7 @@ class AudioDisplay: public wxWindow {
void OnStyleRangesChanged();
void OnTimingController();
void OnMarkerMoved();
void OnTapMarkerChanged();
public:
AudioDisplay(wxWindow *parent, AudioController *controller, agi::Context *context);

View File

@ -64,6 +64,7 @@ AudioKaraoke::AudioKaraoke(wxWindow *parent, agi::Context *c)
, file_changed(c->ass->AddCommitListener(&AudioKaraoke::OnFileChanged, this))
, audio_opened(c->project->AddAudioProviderListener(&AudioKaraoke::OnAudioOpened, this))
, active_line_changed(c->selectionController->AddActiveLineListener(&AudioKaraoke::OnActiveLineChanged, this))
, tap_to_time_toggled(OPT_SUB("Timing/Tap To Time", &AudioKaraoke::OnTapMarkerChanged, this))
, kara(agi::make_unique<AssKaraoke>())
{
using std::bind;
@ -134,6 +135,7 @@ void AudioKaraoke::SetEnabled(bool en) {
if (enabled) {
LoadFromLine();
c->audioController->SetTimingController(CreateKaraokeTimingController(c, kara.get(), file_changed));
c->audioController->GetTimingController()->AddUpdatedTapMarkerListener(&AudioKaraoke::OnTapMarkerChanged, this);
Refresh(false);
}
else {
@ -218,7 +220,16 @@ void AudioKaraoke::RenderText() {
// Draw each character in the line
int y = (bmp_size.GetHeight() - char_height) / 2;
for (size_t i = 0; i < spaced_text.size(); ++i)
for (size_t i = 0; i < spaced_text.size(); ++i) {
if (!(tap_syl_start <= i && i < tap_syl_end)) {
// Only draw with normal color if _not_ the tap syllable
dc.DrawText(spaced_text[i], char_x[i], y);
}
}
// Draw marked syllable
dc.SetTextForeground(*wxGREEN);
for (size_t i = tap_syl_start; i < tap_syl_end; ++i)
dc.DrawText(spaced_text[i], char_x[i], y);
// Draw the lines between each syllable
@ -329,6 +340,26 @@ void AudioKaraoke::OnScrollTimer(wxTimerEvent &) {
split_area->Refresh(false);
}
void AudioKaraoke::OnTapMarkerChanged() {
tap_syl_start = 0;
tap_syl_end = 0;
if (OPT_GET("Timing/Tap To Time")->GetBool() && kara->size() > 0) {
const AudioTimingController *tc = c->audioController->GetTimingController();
const size_t marker_idx = tc->GetTapMarkerIndex();
if (marker_idx > 0) {
tap_syl_start = syl_start_points[marker_idx - 1];
tap_syl_end =
(marker_idx < syl_start_points.size() ?
syl_start_points[marker_idx] :
spaced_text.size());
}
}
RenderText();
Refresh(false);
}
void AudioKaraoke::LoadFromLine() {
scroll_x = 0;
scroll_timer.Stop();

View File

@ -67,6 +67,7 @@ class AudioKaraoke final : public wxWindow {
agi::signal::Connection audio_opened; ///< Audio opened connection
agi::signal::Connection audio_closed; ///< Audio closed connection
agi::signal::Connection active_line_changed;
agi::signal::Connection tap_to_time_toggled;
/// Currently active dialogue line
AssDialogue *active_line = nullptr;
@ -105,6 +106,9 @@ class AudioKaraoke final : public wxWindow {
wxFont split_font; ///< Font used in the split/join interface
size_t tap_syl_start = 0; ///< Tap-to-time syllable start character index
size_t tap_syl_end = 0; ///< Tap-to-time syllable end character index
bool enabled = false; ///< Is karaoke mode enabled?
wxButton *accept_button; ///< Accept pending splits button
@ -143,6 +147,7 @@ class AudioKaraoke final : public wxWindow {
void OnSize(wxSizeEvent &event);
void OnAudioOpened(agi::AudioProvider *provider);
void OnScrollTimer(wxTimerEvent &event);
void OnTapMarkerChanged();
public:
/// Constructor

View File

@ -57,6 +57,9 @@ protected:
/// One or more rendering style ranges have changed in the timing controller.
agi::signal::Signal<> AnnounceUpdatedStyleRanges;
/// The tap marker has changed in the timing controller.
agi::signal::Signal<> AnnounceUpdatedTapMarker;
public:
/// @brief Get any warning message to show in the audio display
/// @return The warning message to show, may be empty if there is none
@ -86,6 +89,12 @@ public:
/// @param[out] ranges Rendering ranges will be added to this
virtual void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const = 0;
/// @brief Return the position of the tap marker
virtual int GetTapMarkerPosition() const = 0;
/// @brief Return the index of the tap marker
virtual size_t GetTapMarkerIndex() const = 0;
enum NextMode {
/// Advance to the next timing unit, whether it's a line or a sub-part
/// of a line such as a karaoke syllable
@ -138,6 +147,15 @@ public:
/// @param delta Amount to add in centiseconds
virtual void ModifyStart(int delta) = 0;
/// Move tap marker position to given position
/// @param position to move marker to
virtual void MoveTapMarker(int ms) = 0;
/// Go to next tap marker
/// @return True if moved to the next marker, False if tap marker is already
/// the last marker of the line
virtual bool NextTapMarker() = 0;
/// @brief Determine if a position is close to a draggable marker
/// @param ms The time in milliseconds to test
/// @param sensitivity Distance in milliseconds to consider markers as nearby
@ -150,6 +168,7 @@ public:
/// @brief The user pressed the left mouse button on the audio
/// @param ms The time in milliseconds the user clicked
/// @param ctrl_down Is the user currently holding the ctrl key down?
/// @param alt_down Is the user currently holding the alt key down?
/// @param sensitivity Distance in milliseconds to consider existing markers
/// @param snap_range Maximum snapping range in milliseconds
/// @return All audio markers at the clicked position which are eligible
@ -177,6 +196,7 @@ public:
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedPrimaryRange, AddUpdatedPrimaryRangeListener)
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedStyleRanges, AddUpdatedStyleRangesListener)
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedTapMarker, AddUpdatedTapMarkerListener)
};
/// @brief Create a standard dialogue audio timing controller

View File

@ -29,6 +29,7 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "audio_controller.h"
#include "audio_marker.h"
#include "audio_rendering_style.h"
#include "audio_timing.h"
@ -327,6 +328,12 @@ class AudioTimingControllerDialogue final : public AudioTimingController {
/// The time which was clicked on for alt-dragging mode
int clicked_ms;
/// Index of marker serving as tap marker
/// For AudioTimingControllerDialogue:
/// - 0 is left marker
/// - 1 is right marker
size_t tap_marker_idx = 0;
/// Autocommit option
const agi::OptionValue *auto_commit = OPT_GET("Audio/Auto/Commit");
const agi::OptionValue *inactive_line_mode = OPT_GET("Audio/Inactive Lines Display Mode");
@ -384,6 +391,8 @@ class AudioTimingControllerDialogue final : public AudioTimingController {
public:
// AudioMarkerProvider interface
void GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const override;
int GetTapMarkerPosition() const override;
size_t GetTapMarkerIndex() const override;
// AudioTimingController interface
void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const override;
@ -395,9 +404,11 @@ public:
void AddLeadOut() override;
void ModifyLength(int delta, bool shift_following) override;
void ModifyStart(int delta) override;
void MoveTapMarker(int ms) override;
bool NextTapMarker() override;
bool IsNearbyMarker(int ms, int sensitivity, bool alt_down) const override;
std::vector<AudioMarker*> OnLeftClick(int ms, bool ctrl_down, bool alt_down, int sensitivity, int snap_range) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool, int sensitivity, int snap_range) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool ctrl_down, int sensitivity, int snap_range) override;
void OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range) override;
// We have no warning messages currently, maybe add the old "Modified" message back later?
@ -447,6 +458,24 @@ void AudioTimingControllerDialogue::GetMarkers(const TimeRange &range, AudioMark
video_position_provider.GetMarkers(range, out_markers);
}
int AudioTimingControllerDialogue::GetTapMarkerPosition() const
{
assert(tap_marker_idx <= 1);
if (tap_marker_idx == 0) {
return *active_line.GetLeftMarker();
}
else {
return *active_line.GetRightMarker();
}
}
size_t AudioTimingControllerDialogue::GetTapMarkerIndex() const
{
assert(tap_marker_idx <= 1);
return tap_marker_idx;
}
void AudioTimingControllerDialogue::OnSelectedSetChanged()
{
RegenerateSelectedLines();
@ -526,6 +555,7 @@ void AudioTimingControllerDialogue::DoCommit(bool user_triggered)
void AudioTimingControllerDialogue::Revert()
{
commit_id = -1;
tap_marker_idx = 0;
if (AssDialogue *line = context->selectionController->GetActiveLine())
{
@ -535,6 +565,7 @@ void AudioTimingControllerDialogue::Revert()
AnnounceUpdatedPrimaryRange();
if (inactive_line_mode->GetInt() == 0)
AnnounceUpdatedStyleRanges();
AnnounceUpdatedTapMarker();
}
else
{
@ -570,6 +601,35 @@ void AudioTimingControllerDialogue::ModifyStart(int delta) {
std::min<int>(*m + delta * 10, *active_line.GetRightMarker()), 0);
}
void AudioTimingControllerDialogue::MoveTapMarker(int ms) {
// Fix rounding error
ms = (ms + 5) / 10 * 10;
DialogueTimingMarker *left = active_line.GetLeftMarker();
DialogueTimingMarker *right = active_line.GetRightMarker();
clicked_ms = INT_MIN;
if (tap_marker_idx == 0) {
// Moving left marker (start time of the line)
if (ms > *right) SetMarkers({ right }, ms, 0);
SetMarkers({ left }, ms, 0);
}
else {
// Moving right marker (end time of the line)
if (ms < *left) SetMarkers({ left }, ms, 0);
SetMarkers({ right }, ms, 0);
}
}
bool AudioTimingControllerDialogue::NextTapMarker() {
if (tap_marker_idx == 0) {
tap_marker_idx = 1;
AnnounceUpdatedTapMarker();
return true;
}
return false;
}
bool AudioTimingControllerDialogue::IsNearbyMarker(int ms, int sensitivity, bool alt_down) const
{
assert(sensitivity >= 0);
@ -609,6 +669,8 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, boo
ret = drag_timing->GetBool() ? GetRightMarkers() : jump;
// Get ret before setting as setting may swap left/right
SetMarkers(jump, ms, snap_range);
// Also change tap marker to left marker
tap_marker_idx = 0;
return ret;
}
@ -627,18 +689,36 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, boo
// Left-click within drag range should still move the left marker to the
// clicked position, but not the right marker
if (clicked == left)
if (clicked == left) {
SetMarkers(ret, ms, snap_range);
}
// Also change tap marker
if (clicked == left) {
tap_marker_idx = 0;
}
else {
tap_marker_idx = 1;
}
return ret;
}
std::vector<AudioMarker*> AudioTimingControllerDialogue::OnRightClick(int ms, bool, int sensitivity, int snap_range)
std::vector<AudioMarker*> AudioTimingControllerDialogue::OnRightClick(int ms, bool ctrl_down, int sensitivity, int snap_range)
{
clicked_ms = INT_MIN;
std::vector<AudioMarker*> ret = GetRightMarkers();
SetMarkers(ret, ms, snap_range);
return ret;
if (ctrl_down) {
// Ctrl-right-click: play audio
context->audioController->PlayToEnd(ms);
return {};
}
else {
// Normal right-click: move right marker
clicked_ms = INT_MIN;
std::vector<AudioMarker*> ret = GetRightMarkers();
SetMarkers(ret, ms, snap_range);
tap_marker_idx = 1;
return ret;
}
}
void AudioTimingControllerDialogue::OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range)

View File

@ -81,6 +81,13 @@ class AudioTimingControllerKaraoke final : public AudioTimingController {
size_t cur_syl = 0; ///< Index of currently selected syllable in the line
/// Index of marker serving as tap marker
/// For AudioControllerTimingKaraoke:
/// - 0 is start marker
/// - 1 to markers.size() is a regular syllable marker
/// - markers.size() + 1 is end marker
size_t tap_marker_idx = 0;
/// Pen used for the mid-syllable markers
Pen separator_pen{"Colour/Audio Display/Syllable Boundaries", "Audio/Line Boundaries Thickness", wxPENSTYLE_DOT};
/// Pen used for the start-of-line marker
@ -112,11 +119,16 @@ class AudioTimingControllerKaraoke final : public AudioTimingController {
void DoCommit();
void ApplyLead(bool announce_primary);
int MoveMarker(KaraokeMarker *marker, int new_position);
void AnnounceChanges(int syl);
void MoveStartMarker(int new_position);
void MoveEndMarker(int new_position);
void CompressMarkers(size_t from, size_t to, int new_position);
void AnnounceChanges(bool announce_primary);
public:
// AudioTimingController implementation
void GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const override;
int GetTapMarkerPosition() const override;
size_t GetTapMarkerIndex() const override;
wxString GetWarningMessage() const override { return ""; }
TimeRange GetIdealVisibleTimeRange() const override;
void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const override;
@ -131,9 +143,11 @@ public:
void AddLeadOut() override;
void ModifyLength(int delta, bool shift_following) override;
void ModifyStart(int delta) override;
void MoveTapMarker(int ms) override;
bool NextTapMarker() override;
bool IsNearbyMarker(int ms, int sensitivity, bool) const override;
std::vector<AudioMarker*> OnLeftClick(int ms, bool, bool, int sensitivity, int) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool, int, int) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool ctrl_down, int, int) override;
void OnMarkerDrag(std::vector<AudioMarker*> const& marker, int new_position, int) override;
AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed);
@ -235,10 +249,29 @@ void AudioTimingControllerKaraoke::GetMarkers(TimeRange const& range, AudioMarke
video_position_provider.GetMarkers(range, out);
}
int AudioTimingControllerKaraoke::GetTapMarkerPosition() const {
assert(tap_marker_idx <= markers.size() + 1);
if (tap_marker_idx == 0) {
return start_marker;
}
else if (tap_marker_idx < markers.size() + 1) {
return markers[tap_marker_idx-1];
}
else {
return end_marker;
}
}
size_t AudioTimingControllerKaraoke::GetTapMarkerIndex() const {
assert(tap_marker_idx <= markers.size() + 1);
return tap_marker_idx;
}
void AudioTimingControllerKaraoke::DoCommit() {
active_line->Text = kara->GetText();
file_changed_slot.Block();
commit_id = c->ass->Commit(_("karaoke timing"), AssFile::COMMIT_DIAG_TEXT, commit_id, active_line);
commit_id = c->ass->Commit(_("karaoke timing"), AssFile::COMMIT_DIAG_TEXT | AssFile::COMMIT_DIAG_TIME, commit_id, active_line);
file_changed_slot.Unblock();
pending_changes = false;
}
@ -254,6 +287,7 @@ void AudioTimingControllerKaraoke::Revert() {
cur_syl = 0;
commit_id = -1;
pending_changes = false;
tap_marker_idx = 0;
start_marker.Move(active_line->Start);
end_marker.Move(active_line->End);
@ -273,6 +307,7 @@ void AudioTimingControllerKaraoke::Revert() {
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
AnnounceMarkerMoved();
AnnounceUpdatedTapMarker();
}
void AudioTimingControllerKaraoke::AddLeadIn() {
@ -293,7 +328,7 @@ void AudioTimingControllerKaraoke::ApplyLead(bool announce_primary) {
kara->SetLineTimes(start_marker, end_marker);
if (!announce_primary)
AnnounceUpdatedStyleRanges();
AnnounceChanges(announce_primary ? cur_syl : cur_syl + 2);
AnnounceChanges(announce_primary);
}
void AudioTimingControllerKaraoke::ModifyLength(int delta, bool shift_following) {
@ -314,13 +349,63 @@ void AudioTimingControllerKaraoke::ModifyLength(int delta, bool shift_following)
for (; cur != end; cur += step) {
MoveMarker(&markers[cur], markers[cur] + delta * 10);
}
AnnounceChanges(cur_syl);
AnnounceChanges(true);
}
void AudioTimingControllerKaraoke::ModifyStart(int delta) {
if (cur_syl == 0) return;
MoveMarker(&markers[cur_syl - 1], markers[cur_syl - 1] + delta * 10);
AnnounceChanges(cur_syl);
AnnounceChanges(true);
}
void AudioTimingControllerKaraoke::MoveTapMarker(int ms) {
// Fix rounding error
ms = (ms + 5) / 10 * 10;
// Get syllable this time falls within
const size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
// Tapping automatically moves all of the necessary markers for the tap
// marker to land at the current audio position. Intuitively, it "pushes" or
// "compresses" the markers blocking the tap marker's way so they all end up
// in the same position. The expectation is that the markers will reach their
// proper position once the user finishes tapping to the line
if (tap_marker_idx == 0) {
// Moving the start time of first syllable (i.e. start time of the line)
if (ms > end_marker) MoveEndMarker(ms);
if (syl > 0) CompressMarkers(syl-1, 0, ms);
MoveStartMarker(ms);
}
else if (tap_marker_idx < markers.size() + 1) {
// Moving the end time of a non-end syllable
if (ms < start_marker) MoveStartMarker(ms);
else if (ms > end_marker) MoveEndMarker(ms);
if (syl < tap_marker_idx) {
// Moving markers left
CompressMarkers(syl, tap_marker_idx-1, ms);
}
else {
// Moving markers right
CompressMarkers(syl-1, tap_marker_idx-1, ms);
}
}
else {
// Moving the end time of last syllable (i.e. end time of the line)
if (ms < start_marker) MoveStartMarker(ms);
if (syl < markers.size()) CompressMarkers(0, markers.size()-1, ms);
MoveEndMarker(ms);
}
AnnounceChanges(true);
}
bool AudioTimingControllerKaraoke::NextTapMarker() {
if (tap_marker_idx < markers.size() + 1) {
++tap_marker_idx;
AnnounceUpdatedTapMarker();
return true;
}
return false;
}
bool AudioTimingControllerKaraoke::IsNearbyMarker(int ms, int sensitivity, bool) const {
@ -350,18 +435,36 @@ std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnLeftClick(int ms, bool
cur_syl = syl;
// Change tap marker
// Selecting a syllable moves the marker to the _end_ of that syllable, such
// that the next tap determines when that syllable ends. This behavior is
// more intuitive when coupled with AudioKaraoke's tap syllable highlight.
if (ms < start_marker.GetPosition()) {
tap_marker_idx = 0;
}
else {
tap_marker_idx = cur_syl + 1;
}
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
AnnounceUpdatedTapMarker();
return {};
}
std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnRightClick(int ms, bool, int, int) {
cur_syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
c->audioController->PlayPrimaryRange();
std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnRightClick(int ms, bool ctrl_down, int, int) {
if (ctrl_down) {
// Ctrl-right-click: play audio
c->audioController->PlayToEnd(ms);
}
else {
// Normal right-click: select new syllable and play range
cur_syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
c->audioController->PlayPrimaryRange();
}
return {};
}
@ -379,7 +482,7 @@ int AudioTimingControllerKaraoke::MoveMarker(KaraokeMarker *marker, int new_posi
marker->Move(new_position);
size_t syl = marker - &markers.front() + 1;
kara->SetStartTime(syl, (new_position + 5) / 10 * 10);
kara->SetStartTime(syl, new_position);
labels[syl - 1].range = TimeRange(labels[syl - 1].range.begin(), new_position);
labels[syl].range = TimeRange(new_position, labels[syl].range.end());
@ -387,10 +490,58 @@ int AudioTimingControllerKaraoke::MoveMarker(KaraokeMarker *marker, int new_posi
return syl;
}
void AudioTimingControllerKaraoke::AnnounceChanges(int syl) {
if (syl < 0) return;
void AudioTimingControllerKaraoke::MoveStartMarker(int new_position) {
// No rearranging of syllables allowed
new_position = mid(
0,
new_position,
markers[0].GetPosition());
if (syl == cur_syl || syl == cur_syl + 1) {
if (new_position == start_marker.GetPosition())
return;
start_marker.Move(new_position);
active_line->Start = (int)start_marker;
kara->SetLineTimes(start_marker, end_marker);
labels.front().range = TimeRange(start_marker, labels.front().range.end());
}
void AudioTimingControllerKaraoke::MoveEndMarker(int new_position) {
// No rearranging of syllables allowed
new_position = mid(
markers.back().GetPosition(),
new_position,
INT_MAX);
if (new_position == end_marker.GetPosition())
return;
end_marker.Move(new_position);
active_line->End = (int)end_marker;
kara->SetLineTimes(start_marker, end_marker);
labels.back().range = TimeRange(labels.back().range.begin(), end_marker);
}
void AudioTimingControllerKaraoke::CompressMarkers(size_t from, size_t to, int new_position) {
int incr = (from < to ? 1 : -1);
size_t i = from;
for (;;) {
MoveMarker(&markers[i], new_position);
if (i == to) {
break;
}
else {
i += incr;
}
}
}
void AudioTimingControllerKaraoke::AnnounceChanges(bool announce_primary) {
if (announce_primary) {
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
}
@ -406,18 +557,21 @@ void AudioTimingControllerKaraoke::AnnounceChanges(int syl) {
}
void AudioTimingControllerKaraoke::OnMarkerDrag(std::vector<AudioMarker*> const& m, int new_position, int) {
// Fix rounding error
new_position = (new_position + 5) / 10 * 10;
int old_position = m[0]->GetPosition();
int syl = MoveMarker(static_cast<KaraokeMarker *>(m[0]), new_position);
if (syl < 0) return;
bool announce_primary = (syl == cur_syl || syl == cur_syl + 1);
if (m.size() > 1) {
int delta = m[0]->GetPosition() - old_position;
for (AudioMarker *marker : m | boost::adaptors::sliced(1, m.size()))
MoveMarker(static_cast<KaraokeMarker *>(marker), marker->GetPosition() + delta);
syl = cur_syl;
announce_primary = true;
}
AnnounceChanges(syl);
AnnounceChanges(announce_primary);
}
void AudioTimingControllerKaraoke::GetLabels(TimeRange const& range, std::vector<AudioLabel> &out) const {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -441,6 +441,21 @@ button/substart_to_video_24.png
button/substart_to_video_32.png
button/substart_to_video_48.png
button/substart_to_video_64.png
button/time_tap_connect_16.png
button/time_tap_connect_24.png
button/time_tap_connect_32.png
button/time_tap_connect_48.png
button/time_tap_connect_64.png
button/time_tap_no_connect_16.png
button/time_tap_no_connect_24.png
button/time_tap_no_connect_32.png
button/time_tap_no_connect_48.png
button/time_tap_no_connect_64.png
button/time_opt_tap_to_time_16.png
button/time_opt_tap_to_time_24.png
button/time_opt_tap_to_time_32.png
button/time_opt_tap_to_time_48.png
button/time_opt_tap_to_time_64.png
button/timing_processor_toolbutton_16.png
button/timing_processor_toolbutton_24.png
button/timing_processor_toolbutton_32.png

View File

@ -39,6 +39,7 @@
#include "../dialogs.h"
#include "../include/aegisub/context.h"
#include "../libresrc/libresrc.h"
#include "../options.h"
#include "../project.h"
#include "../selection_controller.h"
#include "../video_controller.h"
@ -50,6 +51,10 @@
namespace {
using cmd::Command;
static inline void toggle(const char *opt) {
OPT_SET(opt)->SetBool(!OPT_GET(opt)->GetBool());
}
struct validate_video_loaded : public Command {
CMD_TYPE(COMMAND_VALIDATE)
bool Validate(const agi::Context *c) override {
@ -373,6 +378,93 @@ struct time_prev final : public Command {
c->audioController->GetTimingController()->Prev();
}
};
struct time_tap_connect final : public Command {
CMD_NAME("time/tap/connect")
CMD_ICON(time_tap_connect)
STR_MENU("Time tap connect")
STR_DISP("Time tap connect")
STR_HELP("Set tap marker to audio position, connect next line's start")
CMD_TYPE(COMMAND_VALIDATE)
bool Validate(const agi::Context *c) override {
return
OPT_GET("Timing/Tap To Time")->GetBool() &&
c->audioController->IsPlaying();
}
void operator()(agi::Context *c) override {
if (c->audioController->IsPlaying()) {
AudioTimingController *tc = c->audioController->GetTimingController();
if (tc) {
int ms = c->audioController->GetPlaybackPosition();
tc->MoveTapMarker(ms);
bool moved_marker = tc->NextTapMarker();
if (!moved_marker &&
OPT_GET("Audio/Auto/Commit")->GetBool() &&
OPT_GET("Audio/Next Line on Commit")->GetBool()) {
// go to next line, and then tap again to connect start to the same
// time
c->selectionController->NextLine();
tc->MoveTapMarker(ms);
tc->NextTapMarker();
}
}
}
}
};
struct time_tap_no_connect final : public Command {
CMD_NAME("time/tap/no_connect")
CMD_ICON(time_tap_no_connect)
STR_MENU("Tap marker no connect")
STR_DISP("Tap marker no connect")
STR_HELP("Set tap marker to audio position, do not connect next line's start")
CMD_TYPE(COMMAND_VALIDATE)
bool Validate(const agi::Context *c) override {
return
OPT_GET("Timing/Tap To Time")->GetBool() &&
c->audioController->IsPlaying();
}
void operator()(agi::Context *c) override {
if (c->audioController->IsPlaying()) {
AudioTimingController *tc = c->audioController->GetTimingController();
if (tc) {
int ms = c->audioController->GetPlaybackPosition();
tc->MoveTapMarker(ms);
bool moved_marker = tc->NextTapMarker();
if (!moved_marker &&
OPT_GET("Audio/Auto/Commit")->GetBool() &&
OPT_GET("Audio/Next Line on Commit")->GetBool()) {
// go to next line, but don't do anything more
c->selectionController->NextLine();
}
}
}
}
};
struct time_opt_tap_to_time final : public Command {
CMD_NAME("time/opt/tap_to_time")
CMD_ICON(time_opt_tap_to_time)
STR_MENU("Enable tap-to-time UI")
STR_DISP("Enable tap-to-time UI")
STR_HELP("Enable tap-to-time UI")
CMD_TYPE(COMMAND_TOGGLE)
bool IsActive(const agi::Context *) override {
return OPT_GET("Timing/Tap To Time")->GetBool();
}
void operator()(agi::Context *) override {
toggle("Timing/Tap To Time");
}
};
}
namespace cmd {
@ -387,7 +479,10 @@ namespace cmd {
reg(agi::make_unique<time_length_decrease_shift>());
reg(agi::make_unique<time_length_increase>());
reg(agi::make_unique<time_length_increase_shift>());
reg(agi::make_unique<time_tap_connect>());
reg(agi::make_unique<time_tap_no_connect>());
reg(agi::make_unique<time_next>());
reg(agi::make_unique<time_opt_tap_to_time>());
reg(agi::make_unique<time_prev>());
reg(agi::make_unique<time_shift>());
reg(agi::make_unique<time_snap_end_video>());

View File

@ -52,6 +52,12 @@ namespace {
{nullptr}
};
const char *added_hotkeys_time_tap[][3] = {
{"time/tap/connect", "Audio", "I"},
{"time/tap/no_connect", "Audio", "O"},
{nullptr}
};
void migrate_hotkeys(const char *added[][3]) {
auto hk_map = hotkey::inst->GetHotkeyMap();
bool changed = false;
@ -121,6 +127,11 @@ void init() {
}
#endif
if (boost::find(migrations, "time/tap") == end(migrations)) {
migrate_hotkeys(added_hotkeys_time_tap);
migrations.emplace_back("time/tap");
}
OPT_SET("App/Hotkey Migrations")->SetListString(std::move(migrations));
}

View File

@ -428,7 +428,8 @@
},
"Timing" : {
"Default Duration" : 3000
"Default Duration" : 3000,
"Tap To Time" : false
},
"Tool" : {

View File

@ -32,6 +32,12 @@
],
"time/start/increase" : [
"Shift-E"
],
"time/mark/connect" : [
"I"
],
"time/mark/no_connect" : [
"O"
]
},
"Audio" : {
@ -386,4 +392,4 @@
"J"
]
}
}
}

View File

@ -15,6 +15,9 @@
"time/lead/in",
"time/lead/out",
"",
"time/tap/connect",
"time/tap/no_connect",
"",
"audio/commit",
"audio/go_to",
"",
@ -23,6 +26,7 @@
"audio/opt/autoscroll",
"audio/opt/spectrum",
"app/toggle/global_hotkeys",
"time/opt/tap_to_time",
"",
"audio/karaoke"
],

View File

@ -428,7 +428,8 @@
},
"Timing" : {
"Default Duration" : 3000
"Default Duration" : 3000,
"Tap To Time" : false
},
"Tool" : {