forked from mia/Aegisub
Merge audio_display_rewrite branch to trunk. This is not a complete work, don't expect to time anything for a while.
Originally committed to SVN as r4903.
This commit is contained in:
parent
0e6d8631fd
commit
c15777f844
84 changed files with 4483 additions and 3724 deletions
|
@ -47,6 +47,7 @@
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
UsePrecompiledHeader="2"
|
UsePrecompiledHeader="2"
|
||||||
PrecompiledHeaderThrough="agi_pre.h"
|
PrecompiledHeaderThrough="agi_pre.h"
|
||||||
|
DebugInformationFormat="3"
|
||||||
DisableSpecificWarnings="4267"
|
DisableSpecificWarnings="4267"
|
||||||
ForcedIncludeFiles="agi_pre.h"
|
ForcedIncludeFiles="agi_pre.h"
|
||||||
/>
|
/>
|
||||||
|
@ -113,6 +114,7 @@
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
UsePrecompiledHeader="2"
|
UsePrecompiledHeader="2"
|
||||||
PrecompiledHeaderThrough="agi_pre.h"
|
PrecompiledHeaderThrough="agi_pre.h"
|
||||||
|
DebugInformationFormat="3"
|
||||||
DisableSpecificWarnings="4267"
|
DisableSpecificWarnings="4267"
|
||||||
ForcedIncludeFiles="agi_pre.h"
|
ForcedIncludeFiles="agi_pre.h"
|
||||||
/>
|
/>
|
||||||
|
@ -715,6 +717,14 @@
|
||||||
RelativePath="..\..\src\aegisublocale.h"
|
RelativePath="..\..\src\aegisublocale.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\block_cache.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\block_cache.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\charset_conv.cpp"
|
RelativePath="..\..\src\charset_conv.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1699,6 +1709,22 @@
|
||||||
RelativePath="..\..\src\audio_box.h"
|
RelativePath="..\..\src\audio_box.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_colorscheme.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_colorscheme.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_colorscheme.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_colorscheme.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\audio_display.cpp"
|
RelativePath="..\..\src\audio_display.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1731,10 +1757,34 @@
|
||||||
RelativePath="..\..\src\audio_renderer_spectrum.h"
|
RelativePath="..\..\src\audio_renderer_spectrum.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_renderer_waveform.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_renderer_waveform.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_timing_dialogue.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Video UI"
|
Name="Video UI"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_renderer_waveform.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_renderer_waveform.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_timing_dialogue.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\video_box.cpp"
|
RelativePath="..\..\src\video_box.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1799,6 +1849,18 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="Controllers"
|
Name="Controllers"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_controller.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_controller.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\audio_timing.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\selection_controller.h"
|
RelativePath="..\..\src\selection_controller.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
>
|
>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
|
AdditionalOptions="/Zm120"
|
||||||
EnableIntrinsicFunctions="true"
|
EnableIntrinsicFunctions="true"
|
||||||
RuntimeLibrary="2"
|
RuntimeLibrary="2"
|
||||||
OpenMP="true"
|
OpenMP="true"
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
OutputDirectory="$(SolutionDir)build/$(ProjectName)/$(PlatformName)/$(ConfigurationName)/"
|
OutputDirectory="$(SolutionDir)build/$(ProjectName)/$(PlatformName)/$(ConfigurationName)/"
|
||||||
IntermediateDirectory="$(OutDir)"
|
IntermediateDirectory="$(OutDir)"
|
||||||
>
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
AdditionalIncludeDirectories=""$(SolutionDir)include/";"$(SolutionDir)include/$(PlatformName)/";"$(SolutionDir)include/$(ConfigurationName)/";"$(SolutionDir)include/$(PlatformName)/$(ConfigurationName)/""
|
||||||
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLibrarianTool"
|
Name="VCLibrarianTool"
|
||||||
OutputFile="$(LibraryOutDir)/$(ProjectName).lib"
|
OutputFile="$(LibraryOutDir)/$(ProjectName).lib"
|
||||||
|
|
|
@ -86,7 +86,6 @@
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCPostBuildEventTool"
|
Name="VCPostBuildEventTool"
|
||||||
CommandLine="cd "$(ExecutableOutDir)"
"$(ProjectDir)\..\..\tests\setup.bat" "$(ProjectDir)\..\..\tests"
"
|
|
||||||
/>
|
/>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
<Configuration
|
<Configuration
|
||||||
|
|
|
@ -157,6 +157,7 @@
|
||||||
#include <wx/dataobj.h>
|
#include <wx/dataobj.h>
|
||||||
#include <wx/datetime.h>
|
#include <wx/datetime.h>
|
||||||
#include <wx/dc.h>
|
#include <wx/dc.h>
|
||||||
|
#include <wx/dcbuffer.h>
|
||||||
#include <wx/dcclient.h>
|
#include <wx/dcclient.h>
|
||||||
#include <wx/dcmemory.h>
|
#include <wx/dcmemory.h>
|
||||||
#include <wx/dcscreen.h>
|
#include <wx/dcscreen.h>
|
||||||
|
@ -199,6 +200,7 @@
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
#include <wx/notebook.h>
|
#include <wx/notebook.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
|
#include <wx/power.h>
|
||||||
#include <wx/protocol/http.h>
|
#include <wx/protocol/http.h>
|
||||||
#include <wx/radiobox.h>
|
#include <wx/radiobox.h>
|
||||||
#include <wx/radiobut.h>
|
#include <wx/radiobut.h>
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "ass_export_filter.h"
|
#include "ass_export_filter.h"
|
||||||
#include "ass_exporter.h"
|
#include "ass_exporter.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
|
|
|
@ -47,9 +47,13 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "include/aegisub/audio_player.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
#include "audio_display.h"
|
||||||
#include "audio_karaoke.h"
|
#include "audio_karaoke.h"
|
||||||
|
#include "audio_timing.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "hotkeys.h"
|
#include "hotkeys.h"
|
||||||
#include "include/aegisub/audio_player.h"
|
#include "include/aegisub/audio_player.h"
|
||||||
|
@ -58,60 +62,79 @@
|
||||||
#include "toggle_bitmap.h"
|
#include "toggle_bitmap.h"
|
||||||
#include "tooltip_manager.h"
|
#include "tooltip_manager.h"
|
||||||
|
|
||||||
|
// Stuff defines "min" and "max" as macros and breaks std::min and std::max in the process
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
|
||||||
|
enum AudioBoxControlIDs {
|
||||||
|
Audio_Scrollbar = 1600,
|
||||||
|
Audio_Horizontal_Zoom,
|
||||||
|
Audio_Vertical_Zoom,
|
||||||
|
Audio_Volume,
|
||||||
|
Audio_Sash,
|
||||||
|
Audio_Vertical_Link,
|
||||||
|
Audio_Button_Play,
|
||||||
|
Audio_Button_Stop,
|
||||||
|
Audio_Button_Prev,
|
||||||
|
Audio_Button_Next,
|
||||||
|
Audio_Button_Play_500ms_Before,
|
||||||
|
Audio_Button_Play_500ms_After,
|
||||||
|
Audio_Button_Play_500ms_First,
|
||||||
|
Audio_Button_Play_500ms_Last,
|
||||||
|
Audio_Button_Play_Row,
|
||||||
|
Audio_Button_Play_To_End,
|
||||||
|
Audio_Button_Commit,
|
||||||
|
Audio_Button_Karaoke,
|
||||||
|
Audio_Button_Goto,
|
||||||
|
|
||||||
|
Audio_Button_Join, /// Karaoke -> Enter join mode.
|
||||||
|
Audio_Button_Split, /// Karaoke -> Enter split mode.
|
||||||
|
Audio_Button_Accept, /// Karaoke -> Split/Join mode -> Accept.
|
||||||
|
Audio_Button_Cancel, /// KAraoke -> Split/Join mode -> Cancel.
|
||||||
|
|
||||||
|
Audio_Button_Leadin,
|
||||||
|
Audio_Button_Leadout,
|
||||||
|
|
||||||
|
Audio_Check_AutoCommit,
|
||||||
|
Audio_Check_NextCommit,
|
||||||
|
Audio_Check_AutoGoto,
|
||||||
|
Audio_Check_Medusa,
|
||||||
|
Audio_Check_Spectrum
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
/// @param parent
|
/// @param parent
|
||||||
///
|
///
|
||||||
AudioBox::AudioBox(wxWindow *parent, SubtitlesGrid *grid) :
|
AudioBox::AudioBox(wxWindow *parent, AudioController *_controller, SelectionController<AssDialogue> *selection_controller)
|
||||||
wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISED)
|
: wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISED)
|
||||||
|
, selection_controller(selection_controller)
|
||||||
|
, controller(_controller)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
loaded = false;
|
|
||||||
karaokeMode = false;
|
karaokeMode = false;
|
||||||
|
|
||||||
// Sash and Display
|
// Sash and Display
|
||||||
audioScroll = new wxScrollBar(this,Audio_Scrollbar);
|
audioDisplay = new AudioDisplay(this, controller);
|
||||||
audioScroll->PushEventHandler(new FocusEvent());
|
|
||||||
audioScroll->SetToolTip(_("Seek bar"));
|
|
||||||
Sash = new wxSashWindow(this,Audio_Sash,wxDefaultPosition,wxDefaultSize,wxCLIP_CHILDREN | wxSW_3DBORDER);
|
|
||||||
sashSizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
audioDisplay = new AudioDisplay(Sash, grid);
|
|
||||||
sashSizer->Add(audioDisplay,1,wxEXPAND,0);
|
|
||||||
Sash->SetSizer(sashSizer);
|
|
||||||
Sash->SetSashVisible(wxSASH_BOTTOM,true);
|
|
||||||
//Sash->SetSashBorder(wxSASH_BOTTOM,true);
|
|
||||||
Sash->SetMinimumSizeY(50);
|
|
||||||
audioDisplay->ScrollBar = audioScroll;
|
|
||||||
audioDisplay->box = this;
|
|
||||||
int _w,_h;
|
|
||||||
audioDisplay->GetSize(&_w,&_h);
|
|
||||||
audioDisplay->SetSizeHints(-1,_h,-1,_h);
|
|
||||||
|
|
||||||
// Zoom
|
// Zoom
|
||||||
HorizontalZoom = new wxSlider(this,Audio_Horizontal_Zoom,50,0,100,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH);
|
HorizontalZoom = new wxSlider(this,Audio_Horizontal_Zoom,0,-50,30,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH);
|
||||||
HorizontalZoom->PushEventHandler(new FocusEvent());
|
|
||||||
HorizontalZoom->SetToolTip(_("Horizontal zoom"));
|
HorizontalZoom->SetToolTip(_("Horizontal zoom"));
|
||||||
VerticalZoom = new wxSlider(this,Audio_Vertical_Zoom,50,0,100,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE);
|
VerticalZoom = new wxSlider(this,Audio_Vertical_Zoom,50,0,100,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE);
|
||||||
VerticalZoom->PushEventHandler(new FocusEvent());
|
|
||||||
VerticalZoom->SetToolTip(_("Vertical zoom"));
|
VerticalZoom->SetToolTip(_("Vertical zoom"));
|
||||||
VolumeBar = new wxSlider(this,Audio_Volume,50,0,100,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE);
|
VolumeBar = new wxSlider(this,Audio_Volume,50,0,100,wxDefaultPosition,wxSize(-1,20),wxSL_VERTICAL|wxSL_BOTH|wxSL_INVERSE);
|
||||||
VolumeBar->PushEventHandler(new FocusEvent());
|
|
||||||
VolumeBar->SetToolTip(_("Audio Volume"));
|
VolumeBar->SetToolTip(_("Audio Volume"));
|
||||||
bool link = OPT_GET("Audio/Link")->GetBool();
|
bool link = OPT_GET("Audio/Link")->GetBool();
|
||||||
if (link) {
|
if (link) {
|
||||||
VolumeBar->SetValue(VerticalZoom->GetValue());
|
VolumeBar->SetValue(VerticalZoom->GetValue());
|
||||||
VolumeBar->Enable(false);
|
VolumeBar->Enable(false);
|
||||||
}
|
}
|
||||||
VerticalLink = new ToggleBitmap(this,Audio_Vertical_Link,GETIMAGE(toggle_audio_link_24));
|
VerticalLink = new ToggleBitmap(this,Audio_Vertical_Link,GETIMAGE(toggle_audio_link_16));
|
||||||
VerticalLink->SetToolTip(_("Link vertical zoom and volume sliders"));
|
VerticalLink->SetToolTip(_("Link vertical zoom and volume sliders"));
|
||||||
VerticalLink->SetValue(link);
|
VerticalLink->SetValue(link);
|
||||||
|
|
||||||
// Display sizer
|
|
||||||
DisplaySizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
//DisplaySizer->Add(audioDisplay,1,wxEXPAND,0);
|
|
||||||
DisplaySizer->Add(Sash,0,wxEXPAND,0);
|
|
||||||
DisplaySizer->Add(audioScroll,0,wxEXPAND,0);
|
|
||||||
|
|
||||||
// VertVol sider
|
// VertVol sider
|
||||||
wxSizer *VertVol = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer *VertVol = new wxBoxSizer(wxHORIZONTAL);
|
||||||
VertVol->Add(VerticalZoom,1,wxEXPAND,0);
|
VertVol->Add(VerticalZoom,1,wxEXPAND,0);
|
||||||
|
@ -122,99 +145,93 @@ wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISE
|
||||||
|
|
||||||
// Top sizer
|
// Top sizer
|
||||||
TopSizer = new wxBoxSizer(wxHORIZONTAL);
|
TopSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
TopSizer->Add(DisplaySizer,1,wxEXPAND,0);
|
TopSizer->Add(audioDisplay,1,wxEXPAND,0);
|
||||||
TopSizer->Add(HorizontalZoom,0,wxEXPAND,0);
|
TopSizer->Add(HorizontalZoom,0,wxEXPAND,0);
|
||||||
TopSizer->Add(VertVolArea,0,wxEXPAND,0);
|
TopSizer->Add(VertVolArea,0,wxEXPAND,0);
|
||||||
|
|
||||||
// Buttons sizer
|
// Buttons sizer
|
||||||
wxSizer *ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
|
wxSizer *ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
wxButton *temp;
|
wxButton *temp;
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Prev,GETIMAGE(button_prev_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Prev,GETIMAGE(button_prev_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Previous line or syllable (%KEY%/%KEY%)"),_T("Audio Prev Line"),_T("Audio Prev Line Alt"));
|
ToolTipManager::Bind(temp,_("Previous line or syllable (%KEY%/%KEY%)"),_T("Audio Prev Line"),_T("Audio Prev Line Alt"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Next,GETIMAGE(button_next_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Next,GETIMAGE(button_next_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Next line/syllable (%KEY%/%KEY%)"),_T("Audio Next Line"),_T("Audio Next Line Alt"));
|
ToolTipManager::Bind(temp,_("Next line/syllable (%KEY%/%KEY%)"),_T("Audio Next Line"),_T("Audio Next Line Alt"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play,GETIMAGE(button_playsel_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play,GETIMAGE(button_playsel_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play selection (%KEY%/%KEY%)"),_T("Audio Play"),_T("Audio Play Alt"));
|
ToolTipManager::Bind(temp,_("Play selection (%KEY%/%KEY%)"),_T("Audio Play"),_T("Audio Play Alt"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play_Row,GETIMAGE(button_playline_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play_Row,GETIMAGE(button_playline_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play current line (%KEY%)"),_T("Audio Play Original Line"));
|
ToolTipManager::Bind(temp,_("Play current line (%KEY%)"),_T("Audio Play Original Line"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Stop,GETIMAGE(button_stop_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Stop,GETIMAGE(button_stop_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Stop (%KEY%)"),_T("Audio Stop"));
|
ToolTipManager::Bind(temp,_("Stop (%KEY%)"),_T("Audio Stop"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
||||||
|
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_Before,GETIMAGE(button_playfivehbefore_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_Before,GETIMAGE(button_playfivehbefore_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play 500 ms before selection (%KEY%)"),_T("Audio Play 500ms Before"));
|
ToolTipManager::Bind(temp,_("Play 500 ms before selection (%KEY%)"),_T("Audio Play 500ms Before"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_After,GETIMAGE(button_playfivehafter_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_After,GETIMAGE(button_playfivehafter_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play 500 ms after selection (%KEY%)"),_T("Audio Play 500ms after"));
|
ToolTipManager::Bind(temp,_("Play 500 ms after selection (%KEY%)"),_T("Audio Play 500ms after"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_First,GETIMAGE(button_playfirstfiveh_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_First,GETIMAGE(button_playfirstfiveh_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play first 500ms of selection (%KEY%)"),_T("Audio Play First 500ms"));
|
ToolTipManager::Bind(temp,_("Play first 500ms of selection (%KEY%)"),_T("Audio Play First 500ms"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_Last,GETIMAGE(button_playlastfiveh_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play_500ms_Last,GETIMAGE(button_playlastfiveh_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play last 500ms of selection (%KEY%)"),_T("Audio Play Last 500ms"));
|
ToolTipManager::Bind(temp,_("Play last 500ms of selection (%KEY%)"),_T("Audio Play Last 500ms"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Play_To_End,GETIMAGE(button_playtoend_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Play_To_End,GETIMAGE(button_playtoend_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Play from selection start to end of file (%KEY%)"),_T("Audio Play To End"));
|
ToolTipManager::Bind(temp,_("Play from selection start to end of file (%KEY%)"),_T("Audio Play To End"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
||||||
|
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Leadin,GETIMAGE(button_leadin_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Leadin,GETIMAGE(button_leadin_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Add lead in (%KEY%)"),_T("Audio Add Lead In"));
|
ToolTipManager::Bind(temp,_("Add lead in (%KEY%)"),_T("Audio Add Lead In"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Leadout,GETIMAGE(button_leadout_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Leadout,GETIMAGE(button_leadout_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Add lead out (%KEY%)"),_T("Audio Add Lead Out"));
|
ToolTipManager::Bind(temp,_("Add lead out (%KEY%)"),_T("Audio Add Lead Out"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
||||||
|
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Commit,GETIMAGE(button_audio_commit_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Commit,GETIMAGE(button_audio_commit_16),wxDefaultPosition,wxDefaultSize);
|
||||||
ToolTipManager::Bind(temp,_("Commit changes (%KEY%/%KEY%)"),_T("Audio Commit (Stay)"),_T("Audio Commit Alt"));
|
ToolTipManager::Bind(temp,_("Commit changes (%KEY%/%KEY%)"),_T("Audio Commit (Stay)"),_T("Audio Commit Alt"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
ButtonSizer->Add(temp,0,wxRIGHT,0);
|
||||||
temp = new wxBitmapButton(this,Audio_Button_Goto,GETIMAGE(button_audio_goto_24),wxDefaultPosition,wxSize(30,-1));
|
temp = new wxBitmapButton(this,Audio_Button_Goto,GETIMAGE(button_audio_goto_16),wxDefaultPosition,wxDefaultSize);
|
||||||
temp->SetToolTip(_("Go to selection"));
|
temp->SetToolTip(_("Go to selection"));
|
||||||
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
ButtonSizer->Add(temp,0,wxRIGHT,10);
|
||||||
|
|
||||||
AutoCommit = new ToggleBitmap(this,Audio_Check_AutoCommit,GETIMAGE(toggle_audio_autocommit_24),wxSize(30,-1));
|
AutoCommit = new ToggleBitmap(this,Audio_Check_AutoCommit,GETIMAGE(toggle_audio_autocommit_16), wxSize(20, -1));
|
||||||
AutoCommit->SetToolTip(_("Automatically commit all changes"));
|
AutoCommit->SetToolTip(_("Automatically commit all changes"));
|
||||||
AutoCommit->SetValue(OPT_GET("Audio/Auto/Commit")->GetBool());
|
AutoCommit->SetValue(OPT_GET("Audio/Auto/Commit")->GetBool());
|
||||||
ButtonSizer->Add(AutoCommit,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
ButtonSizer->Add(AutoCommit,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
||||||
NextCommit = new ToggleBitmap(this,Audio_Check_NextCommit,GETIMAGE(toggle_audio_nextcommit_24),wxSize(30,-1));
|
NextCommit = new ToggleBitmap(this,Audio_Check_NextCommit,GETIMAGE(toggle_audio_nextcommit_16), wxSize(20, -1));
|
||||||
NextCommit->SetToolTip(_("Auto goes to next line on commit"));
|
NextCommit->SetToolTip(_("Auto goes to next line on commit"));
|
||||||
NextCommit->SetValue(OPT_GET("Audio/Next Line on Commit")->GetBool());
|
NextCommit->SetValue(OPT_GET("Audio/Next Line on Commit")->GetBool());
|
||||||
ButtonSizer->Add(NextCommit,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
ButtonSizer->Add(NextCommit,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
||||||
AutoScroll = new ToggleBitmap(this,Audio_Check_AutoGoto,GETIMAGE(toggle_audio_autoscroll_24),wxSize(30,-1));
|
AutoScroll = new ToggleBitmap(this,Audio_Check_AutoGoto,GETIMAGE(toggle_audio_autoscroll_16), wxSize(20, -1));
|
||||||
AutoScroll->SetToolTip(_("Auto scrolls audio display to selected line"));
|
AutoScroll->SetToolTip(_("Auto scrolls audio display to selected line"));
|
||||||
AutoScroll->SetValue(OPT_GET("Audio/Auto/Scroll")->GetBool());
|
AutoScroll->SetValue(OPT_GET("Audio/Auto/Scroll")->GetBool());
|
||||||
ButtonSizer->Add(AutoScroll,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
ButtonSizer->Add(AutoScroll,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,10);
|
||||||
SpectrumMode = new ToggleBitmap(this,Audio_Check_Spectrum,GETIMAGE(toggle_audio_spectrum_24),wxSize(30,-1));
|
|
||||||
SpectrumMode->SetToolTip(_("Spectrum analyzer mode"));
|
|
||||||
SpectrumMode->SetValue(OPT_GET("Audio/Spectrum")->GetBool());
|
|
||||||
ButtonSizer->Add(SpectrumMode,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
|
||||||
MedusaMode = new ToggleBitmap(this,Audio_Check_Medusa,GETIMAGE(toggle_audio_medusa_24),wxSize(30,-1));
|
|
||||||
MedusaMode->SetToolTip(_("Enable Medusa-Style Timing Shortcuts"));
|
|
||||||
MedusaMode->SetValue(OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool());
|
|
||||||
ButtonSizer->Add(MedusaMode,0,wxRIGHT | wxALIGN_CENTER | wxEXPAND,0);
|
|
||||||
ButtonSizer->AddStretchSpacer(1);
|
ButtonSizer->AddStretchSpacer(1);
|
||||||
|
|
||||||
|
KaraokeButton = new wxBitmapToggleButton(this,Audio_Button_Karaoke,GETIMAGE(kara_mode_16),wxDefaultPosition,wxDefaultSize);
|
||||||
|
KaraokeButton->SetToolTip(_("Toggle karaoke mode"));
|
||||||
|
ButtonSizer->Add(KaraokeButton,0,wxRIGHT|wxEXPAND,0);
|
||||||
|
|
||||||
// Karaoke sizer
|
// Karaoke sizer
|
||||||
karaokeSizer = new wxBoxSizer(wxHORIZONTAL);
|
karaokeSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
KaraokeButton = new wxBitmapToggleButton(this,Audio_Button_Karaoke,GETIMAGE(kara_mode_24),wxDefaultPosition,wxSize(33,30));
|
|
||||||
KaraokeButton->SetToolTip(_("Toggle karaoke mode"));
|
|
||||||
karaokeSizer->Add(KaraokeButton,0,wxRIGHT|wxEXPAND,0);
|
|
||||||
|
|
||||||
JoinSplitSizer = new wxBoxSizer(wxHORIZONTAL);
|
JoinSplitSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
JoinButton = new wxBitmapButton(this,Audio_Button_Join,GETIMAGE(kara_join_24),wxDefaultPosition,wxSize(33,30));
|
JoinButton = new wxBitmapButton(this,Audio_Button_Join,GETIMAGE(kara_join_16),wxDefaultPosition,wxDefaultSize);
|
||||||
JoinButton->SetToolTip(_("Join selected syllables"));
|
JoinButton->SetToolTip(_("Join selected syllables"));
|
||||||
SplitButton = new wxBitmapButton(this,Audio_Button_Split,GETIMAGE(kara_split_24),wxDefaultPosition,wxSize(33,30));
|
SplitButton = new wxBitmapButton(this,Audio_Button_Split,GETIMAGE(kara_split_16),wxDefaultPosition,wxDefaultSize);
|
||||||
SplitButton->SetToolTip(_("Enter split-mode"));
|
SplitButton->SetToolTip(_("Enter split-mode"));
|
||||||
JoinSplitSizer->Add(JoinButton,0,wxRIGHT|wxEXPAND,0);
|
JoinSplitSizer->Add(JoinButton,0,wxRIGHT|wxEXPAND,0);
|
||||||
JoinSplitSizer->Add(SplitButton,0,wxRIGHT|wxEXPAND,0);
|
JoinSplitSizer->Add(SplitButton,0,wxRIGHT|wxEXPAND,0);
|
||||||
|
|
||||||
CancelAcceptSizer = new wxBoxSizer(wxHORIZONTAL);
|
CancelAcceptSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
CancelButton = new wxBitmapButton(this,Audio_Button_Cancel,GETIMAGE(kara_split_accept_24),wxDefaultPosition,wxSize(33,30));
|
CancelButton = new wxBitmapButton(this,Audio_Button_Cancel,GETIMAGE(kara_split_accept_16),wxDefaultPosition,wxDefaultSize);
|
||||||
CancelButton->SetToolTip(_("Commit splits and leave split-mode"));
|
CancelButton->SetToolTip(_("Commit splits and leave split-mode"));
|
||||||
AcceptButton = new wxBitmapButton(this,Audio_Button_Accept,GETIMAGE(kara_split_cancel_24),wxDefaultPosition,wxSize(33,30));
|
AcceptButton = new wxBitmapButton(this,Audio_Button_Accept,GETIMAGE(kara_split_cancel_16),wxDefaultPosition,wxDefaultSize);
|
||||||
AcceptButton->SetToolTip(_("Discard all splits and leave split-mode"));
|
AcceptButton->SetToolTip(_("Discard all splits and leave split-mode"));
|
||||||
CancelAcceptSizer->Add(CancelButton,0,wxRIGHT|wxEXPAND,0);
|
CancelAcceptSizer->Add(CancelButton,0,wxRIGHT|wxEXPAND,0);
|
||||||
CancelAcceptSizer->Add(AcceptButton,0,wxRIGHT|wxEXPAND,0);
|
CancelAcceptSizer->Add(AcceptButton,0,wxRIGHT|wxEXPAND,0);
|
||||||
|
@ -225,70 +242,40 @@ wxPanel(parent,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL|wxBORDER_RAISE
|
||||||
audioKaraoke = new AudioKaraoke(this);
|
audioKaraoke = new AudioKaraoke(this);
|
||||||
audioKaraoke->box = this;
|
audioKaraoke->box = this;
|
||||||
audioKaraoke->display = audioDisplay;
|
audioKaraoke->display = audioDisplay;
|
||||||
audioDisplay->karaoke = audioKaraoke;
|
|
||||||
karaokeSizer->Add(audioKaraoke,1,wxEXPAND,0);
|
karaokeSizer->Add(audioKaraoke,1,wxEXPAND,0);
|
||||||
|
|
||||||
SetKaraokeButtons(); // Decide which one to show or hide.
|
|
||||||
|
|
||||||
// Main sizer
|
// Main sizer
|
||||||
MainSizer = new wxBoxSizer(wxVERTICAL);
|
MainSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
MainSizer->Add(TopSizer,0,wxEXPAND,0);
|
MainSizer->Add(TopSizer,1,wxEXPAND|wxALL,3);
|
||||||
MainSizer->Add(ButtonSizer,0,wxEXPAND,0);
|
MainSizer->Add(ButtonSizer,0,wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT,3);
|
||||||
MainSizer->Add(new wxStaticLine(this),0,wxEXPAND|wxTOP|wxBOTTOM,2);
|
//MainSizer->Add(new wxStaticLine(this),0,wxEXPAND|wxTOP|wxBOTTOM,2);
|
||||||
MainSizer->Add(karaokeSizer,0,wxEXPAND,0);
|
MainSizer->Add(karaokeSizer,0,wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT,3);
|
||||||
|
MainSizer->AddSpacer(3);
|
||||||
//MainSizer->SetSizeHints(this);
|
//MainSizer->SetSizeHints(this);
|
||||||
SetSizer(MainSizer);
|
SetSizer(MainSizer);
|
||||||
|
|
||||||
|
SetKaraokeButtons(); // Decide which one to show or hide.
|
||||||
|
|
||||||
|
timing_controller_dialogue = CreateDialogueTimingController(controller, selection_controller);
|
||||||
|
controller->SetTimingController(timing_controller_dialogue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
///
|
///
|
||||||
AudioBox::~AudioBox() {
|
AudioBox::~AudioBox()
|
||||||
audioScroll->PopEventHandler(true);
|
{
|
||||||
HorizontalZoom->PopEventHandler(true);
|
|
||||||
VerticalZoom->PopEventHandler(true);
|
|
||||||
VolumeBar->PopEventHandler(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Set file
|
|
||||||
/// @param file
|
|
||||||
/// @param FromVideo
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void AudioBox::SetFile(wxString file,bool FromVideo) {
|
|
||||||
LOG_D("audio/box") << "file=" << file << " FromVideo: " << FromVideo;
|
|
||||||
loaded = false;
|
|
||||||
|
|
||||||
if (FromVideo) {
|
|
||||||
audioDisplay->SetFromVideo();
|
|
||||||
loaded = audioDisplay->loaded;
|
|
||||||
audioName = _T("?video");
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
audioDisplay->SetFile(file);
|
|
||||||
if (file != _T("")) loaded = audioDisplay->loaded;
|
|
||||||
audioName = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_D("audio/box") << "setting up acceleraters in frameMain";
|
|
||||||
frameMain->SetAccelerators();
|
|
||||||
LOG_D("audio/box") << "finished setting up accelerators in frameMain";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Event table
|
// Event table
|
||||||
BEGIN_EVENT_TABLE(AudioBox,wxPanel)
|
BEGIN_EVENT_TABLE(AudioBox,wxPanel)
|
||||||
EVT_COMMAND_SCROLL(Audio_Scrollbar, AudioBox::OnScrollbar)
|
|
||||||
EVT_COMMAND_SCROLL(Audio_Horizontal_Zoom, AudioBox::OnHorizontalZoom)
|
EVT_COMMAND_SCROLL(Audio_Horizontal_Zoom, AudioBox::OnHorizontalZoom)
|
||||||
EVT_COMMAND_SCROLL(Audio_Vertical_Zoom, AudioBox::OnVerticalZoom)
|
EVT_COMMAND_SCROLL(Audio_Vertical_Zoom, AudioBox::OnVerticalZoom)
|
||||||
EVT_COMMAND_SCROLL(Audio_Volume, AudioBox::OnVolume)
|
EVT_COMMAND_SCROLL(Audio_Volume, AudioBox::OnVolume)
|
||||||
EVT_SASH_DRAGGED(Audio_Sash,AudioBox::OnSash)
|
|
||||||
|
|
||||||
EVT_BUTTON(Audio_Button_Play, AudioBox::OnPlaySelection)
|
EVT_BUTTON(Audio_Button_Play, AudioBox::OnPlaySelection)
|
||||||
EVT_BUTTON(Audio_Button_Play_Row, AudioBox::OnPlayDialogue)
|
EVT_BUTTON(Audio_Button_Play_Row, AudioBox::OnPlayDialogue)
|
||||||
|
@ -312,28 +299,19 @@ BEGIN_EVENT_TABLE(AudioBox,wxPanel)
|
||||||
EVT_TOGGLEBUTTON(Audio_Vertical_Link, AudioBox::OnVerticalLink)
|
EVT_TOGGLEBUTTON(Audio_Vertical_Link, AudioBox::OnVerticalLink)
|
||||||
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_Check_Medusa,AudioBox::OnMedusaMode)
|
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_Spectrum,AudioBox::OnSpectrumMode)
|
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_AutoCommit,AudioBox::OnAutoCommit)
|
EVT_TOGGLEBUTTON(Audio_Check_AutoCommit,AudioBox::OnAutoCommit)
|
||||||
EVT_TOGGLEBUTTON(Audio_Check_NextCommit,AudioBox::OnNextLineCommit)
|
EVT_TOGGLEBUTTON(Audio_Check_NextCommit,AudioBox::OnNextLineCommit)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Scrollbar changed
|
|
||||||
/// @param event
|
|
||||||
///
|
|
||||||
void AudioBox::OnScrollbar(wxScrollEvent &event) {
|
|
||||||
audioDisplay->SetPosition(event.GetPosition()*12);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Horizontal zoom bar changed
|
/// @brief Horizontal zoom bar changed
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnHorizontalZoom(wxScrollEvent &event) {
|
void AudioBox::OnHorizontalZoom(wxScrollEvent &event) {
|
||||||
audioDisplay->SetSamplesPercent(event.GetPosition());
|
// Negate the value, we want zoom out to be on bottom and zoom in on top,
|
||||||
|
// but the control doesn't want negative on bottom and positive on top.
|
||||||
|
audioDisplay->SetZoomLevel(-event.GetPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -346,9 +324,9 @@ void AudioBox::OnVerticalZoom(wxScrollEvent &event) {
|
||||||
if (pos < 1) pos = 1;
|
if (pos < 1) pos = 1;
|
||||||
if (pos > 100) pos = 100;
|
if (pos > 100) pos = 100;
|
||||||
float value = pow(float(pos)/50.0f,3);
|
float value = pow(float(pos)/50.0f,3);
|
||||||
audioDisplay->SetScale(value);
|
audioDisplay->SetAmplitudeScale(value);
|
||||||
if (VerticalLink->GetValue()) {
|
if (VerticalLink->GetValue()) {
|
||||||
audioDisplay->player->SetVolume(value);
|
controller->SetVolume(value);
|
||||||
VolumeBar->SetValue(pos);
|
VolumeBar->SetValue(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,7 +341,7 @@ void AudioBox::OnVolume(wxScrollEvent &event) {
|
||||||
int pos = event.GetPosition();
|
int pos = event.GetPosition();
|
||||||
if (pos < 1) pos = 1;
|
if (pos < 1) pos = 1;
|
||||||
if (pos > 100) pos = 100;
|
if (pos > 100) pos = 100;
|
||||||
audioDisplay->player->SetVolume(pow(float(pos)/50.0f,3));
|
controller->SetVolume(pow(float(pos)/50.0f,3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +356,7 @@ void AudioBox::OnVerticalLink(wxCommandEvent &event) {
|
||||||
if (pos > 100) pos = 100;
|
if (pos > 100) pos = 100;
|
||||||
float value = pow(float(pos)/50.0f,3);
|
float value = pow(float(pos)/50.0f,3);
|
||||||
if (VerticalLink->GetValue()) {
|
if (VerticalLink->GetValue()) {
|
||||||
audioDisplay->player->SetVolume(value);
|
controller->SetVolume(value);
|
||||||
VolumeBar->SetValue(pos);
|
VolumeBar->SetValue(pos);
|
||||||
}
|
}
|
||||||
VolumeBar->Enable(!VerticalLink->GetValue());
|
VolumeBar->Enable(!VerticalLink->GetValue());
|
||||||
|
@ -388,63 +366,11 @@ void AudioBox::OnVerticalLink(wxCommandEvent &event) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Sash
|
|
||||||
/// @param event
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void AudioBox::OnSash(wxSashEvent& event) {
|
|
||||||
// OK?
|
|
||||||
if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE) return;
|
|
||||||
|
|
||||||
// Recursion guard
|
|
||||||
static wxRecursionGuardFlag inside;
|
|
||||||
wxRecursionGuard guard(inside);
|
|
||||||
if (guard.IsInside()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get size
|
|
||||||
wxRect newSize = event.GetDragRect();
|
|
||||||
int w = newSize.GetWidth();
|
|
||||||
int h = newSize.GetHeight();
|
|
||||||
if (h < 50) h = 50;
|
|
||||||
int oldh = audioDisplay->GetSize().GetHeight();
|
|
||||||
if (oldh == h) return;
|
|
||||||
|
|
||||||
// Resize
|
|
||||||
audioDisplay->SetSizeHints(w,h,-1,h);
|
|
||||||
audioDisplay->SetSize(w,h);
|
|
||||||
sashSizer->Layout();
|
|
||||||
Sash->GetParent()->Layout();
|
|
||||||
|
|
||||||
// Store new size
|
|
||||||
OPT_SET("Audio/Display Height")->SetInt(h);
|
|
||||||
|
|
||||||
// Fix layout
|
|
||||||
frameMain->Freeze();
|
|
||||||
DisplaySizer->Layout();
|
|
||||||
//TopSizer->Layout();
|
|
||||||
//MainSizer->Layout();
|
|
||||||
Layout();
|
|
||||||
frameMain->ToolSizer->Layout();
|
|
||||||
frameMain->MainSizer->Layout();
|
|
||||||
frameMain->Layout();
|
|
||||||
frameMain->Refresh();
|
|
||||||
frameMain->Thaw();
|
|
||||||
|
|
||||||
//event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Play selection
|
/// @brief Play selection
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlaySelection(wxCommandEvent &event) {
|
void AudioBox::OnPlaySelection(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
controller->PlayPrimaryRange();
|
||||||
audioDisplay->SetFocus();
|
|
||||||
audioDisplay->GetTimesSelection(start,end);
|
|
||||||
audioDisplay->Play(start,end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -453,11 +379,9 @@ void AudioBox::OnPlaySelection(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlayDialogue(wxCommandEvent &event) {
|
void AudioBox::OnPlayDialogue(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
if (controller->GetTimingController())
|
||||||
audioDisplay->SetFocus();
|
controller->GetTimingController()->Revert();
|
||||||
audioDisplay->GetTimesDialogue(start,end);
|
controller->PlayPrimaryRange();
|
||||||
audioDisplay->SetSelection(start, end);
|
|
||||||
audioDisplay->Play(start,end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -466,8 +390,7 @@ void AudioBox::OnPlayDialogue(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnStop(wxCommandEvent &event) {
|
void AudioBox::OnStop(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
controller->Stop();
|
||||||
audioDisplay->Stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -476,9 +399,11 @@ void AudioBox::OnStop(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnNext(wxCommandEvent &event) {
|
void AudioBox::OnNext(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
//audioDisplay->SetFocus();
|
||||||
audioDisplay->Stop();
|
controller->Stop();
|
||||||
audioDisplay->Next();
|
if (controller->GetTimingController())
|
||||||
|
controller->GetTimingController()->Next();
|
||||||
|
controller->PlayPrimaryRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -487,9 +412,11 @@ void AudioBox::OnNext(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPrev(wxCommandEvent &event) {
|
void AudioBox::OnPrev(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
//audioDisplay->SetFocus();
|
||||||
audioDisplay->Stop();
|
controller->Stop();
|
||||||
audioDisplay->Prev();
|
if (controller->GetTimingController())
|
||||||
|
controller->GetTimingController()->Prev();
|
||||||
|
controller->PlayPrimaryRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -498,10 +425,10 @@ void AudioBox::OnPrev(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500Before(wxCommandEvent &event) {
|
void AudioBox::OnPlay500Before(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
audioDisplay->SetFocus();
|
controller->PlayRange(AudioController::SampleRange(
|
||||||
audioDisplay->GetTimesSelection(start,end);
|
times.begin() - controller->SamplesFromMilliseconds(500),
|
||||||
audioDisplay->Play(start-500,start);
|
times.begin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -510,10 +437,10 @@ void AudioBox::OnPlay500Before(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500After(wxCommandEvent &event) {
|
void AudioBox::OnPlay500After(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
audioDisplay->SetFocus();
|
controller->PlayRange(AudioController::SampleRange(
|
||||||
audioDisplay->GetTimesSelection(start,end);
|
times.end(),
|
||||||
audioDisplay->Play(end,end+500);
|
times.end() + controller->SamplesFromMilliseconds(500)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -522,12 +449,12 @@ void AudioBox::OnPlay500After(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500First(wxCommandEvent &event) {
|
void AudioBox::OnPlay500First(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
audioDisplay->SetFocus();
|
controller->PlayRange(AudioController::SampleRange(
|
||||||
audioDisplay->GetTimesSelection(start,end);
|
times.begin(),
|
||||||
int endp = start+500;
|
times.begin() + std::min(
|
||||||
if (endp > end) endp = end;
|
controller->SamplesFromMilliseconds(500),
|
||||||
audioDisplay->Play(start,endp);
|
times.length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -536,12 +463,12 @@ void AudioBox::OnPlay500First(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500Last(wxCommandEvent &event) {
|
void AudioBox::OnPlay500Last(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
audioDisplay->SetFocus();
|
controller->PlayRange(AudioController::SampleRange(
|
||||||
audioDisplay->GetTimesSelection(start,end);
|
times.end() - std::min(
|
||||||
int startp = end-500;
|
controller->SamplesFromMilliseconds(500),
|
||||||
if (startp < start) startp = start;
|
times.length()),
|
||||||
audioDisplay->Play(startp,end);
|
times.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -550,10 +477,7 @@ void AudioBox::OnPlay500Last(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlayToEnd(wxCommandEvent &event) {
|
void AudioBox::OnPlayToEnd(wxCommandEvent &event) {
|
||||||
int start=0,end=0;
|
controller->PlayToEnd(controller->GetPrimaryPlaybackRange().begin());
|
||||||
audioDisplay->SetFocus();
|
|
||||||
audioDisplay->GetTimesSelection(start,end);
|
|
||||||
audioDisplay->Play(start,-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -566,7 +490,8 @@ void AudioBox::OnCommit(wxCommandEvent &event) {
|
||||||
LOG_D("audio/box") << "OnCommit";
|
LOG_D("audio/box") << "OnCommit";
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
LOG_D("audio/box") << "has set focus, now committing changes";
|
LOG_D("audio/box") << "has set focus, now committing changes";
|
||||||
audioDisplay->CommitChanges(true);
|
/// @todo Commit changes and go to next line if appropriate
|
||||||
|
//audioDisplay->CommitChanges(true);
|
||||||
LOG_D("audio/box") << "returning";
|
LOG_D("audio/box") << "returning";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,7 +511,8 @@ void AudioBox::OnKaraoke(wxCommandEvent &event) {
|
||||||
}
|
}
|
||||||
karaokeMode = false;
|
karaokeMode = false;
|
||||||
audioKaraoke->enabled = false;
|
audioKaraoke->enabled = false;
|
||||||
audioDisplay->SetDialogue();
|
/// @todo Replace this with changing timing controller
|
||||||
|
//audioDisplay->SetDialogue();
|
||||||
audioKaraoke->Refresh(false);
|
audioKaraoke->Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,7 +520,8 @@ void AudioBox::OnKaraoke(wxCommandEvent &event) {
|
||||||
LOG_D("audio/box") << "karaoke disabled, enabling";
|
LOG_D("audio/box") << "karaoke disabled, enabling";
|
||||||
karaokeMode = true;
|
karaokeMode = true;
|
||||||
audioKaraoke->enabled = true;
|
audioKaraoke->enabled = true;
|
||||||
audioDisplay->SetDialogue();
|
/// @todo Replace this with changing timing controller
|
||||||
|
//audioDisplay->SetDialogue();
|
||||||
}
|
}
|
||||||
|
|
||||||
SetKaraokeButtons();
|
SetKaraokeButtons();
|
||||||
|
@ -618,15 +545,9 @@ void AudioBox::SetKaraokeButtons() {
|
||||||
|
|
||||||
JoinButton->Enable(join);
|
JoinButton->Enable(join);
|
||||||
SplitButton->Enable(split);
|
SplitButton->Enable(split);
|
||||||
if (audioKaraoke->splitting) {
|
|
||||||
karaokeSizer->Show(CancelAcceptSizer);
|
karaokeSizer->Show(CancelAcceptSizer, audioKaraoke->splitting);
|
||||||
karaokeSizer->Hide(JoinSplitSizer);
|
karaokeSizer->Show(JoinSplitSizer, !audioKaraoke->splitting);
|
||||||
karaokeSizer->Layout();
|
|
||||||
} else {
|
|
||||||
karaokeSizer->Hide(CancelAcceptSizer);
|
|
||||||
karaokeSizer->Show(JoinSplitSizer);
|
|
||||||
karaokeSizer->Layout();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Join button in karaoke mode
|
/// @brief Join button in karaoke mode
|
||||||
|
@ -671,7 +592,8 @@ void AudioBox::OnAccept(wxCommandEvent &event) {
|
||||||
///
|
///
|
||||||
void AudioBox::OnGoto(wxCommandEvent &event) {
|
void AudioBox::OnGoto(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
audioDisplay->MakeDialogueVisible(true);
|
if (controller->GetTimingController())
|
||||||
|
audioDisplay->ScrollSampleRangeInView(controller->GetTimingController()->GetIdealVisibleSampleRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -706,26 +628,14 @@ void AudioBox::OnNextLineCommit(wxCommandEvent &event) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Medusa Mode
|
/// @todo Put global audio hotkeys toggling into the menu bar
|
||||||
/// @param event
|
/*
|
||||||
///
|
|
||||||
void AudioBox::OnMedusaMode(wxCommandEvent &event) {
|
void AudioBox::OnMedusaMode(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
OPT_SET("Audio/Medusa Timing Hotkeys")->SetBool(MedusaMode->GetValue());
|
OPT_SET("Audio/Medusa Timing Hotkeys")->SetBool(MedusaMode->GetValue());
|
||||||
frameMain->SetAccelerators();
|
frameMain->SetAccelerators();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// @brief Spectrum Analyzer Mode
|
|
||||||
/// @param event
|
|
||||||
///
|
|
||||||
void AudioBox::OnSpectrumMode(wxCommandEvent &event) {
|
|
||||||
OPT_SET("Audio/Spectrum")->SetBool(SpectrumMode->GetValue());
|
|
||||||
audioDisplay->UpdateImage(false);
|
|
||||||
audioDisplay->SetFocus();
|
|
||||||
audioDisplay->Refresh(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -734,7 +644,7 @@ void AudioBox::OnSpectrumMode(wxCommandEvent &event) {
|
||||||
///
|
///
|
||||||
void AudioBox::OnLeadIn(wxCommandEvent &event) {
|
void AudioBox::OnLeadIn(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
audioDisplay->AddLead(true,false);
|
//audioDisplay->AddLead(true,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -743,21 +653,6 @@ void AudioBox::OnLeadIn(wxCommandEvent &event) {
|
||||||
///
|
///
|
||||||
void AudioBox::OnLeadOut(wxCommandEvent &event) {
|
void AudioBox::OnLeadOut(wxCommandEvent &event) {
|
||||||
audioDisplay->SetFocus();
|
audioDisplay->SetFocus();
|
||||||
audioDisplay->AddLead(false,true);
|
//audioDisplay->AddLead(false,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////
|
|
||||||
// Focus event handling for the scrollbar
|
|
||||||
BEGIN_EVENT_TABLE(FocusEvent,wxEvtHandler)
|
|
||||||
EVT_SET_FOCUS(FocusEvent::OnSetFocus)
|
|
||||||
END_EVENT_TABLE()
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param event
|
|
||||||
///
|
|
||||||
void FocusEvent::OnSetFocus(wxFocusEvent &event) {
|
|
||||||
wxWindow *previous = event.GetWindow();
|
|
||||||
if (previous) previous->SetFocus();
|
|
||||||
}
|
|
||||||
|
|
|
@ -54,9 +54,14 @@
|
||||||
#include <wx/tglbtn.h>
|
#include <wx/tglbtn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef AGI_AUDIO_CONTROLLER_INCLUDED
|
||||||
|
#error You must include "audio_controller.h" before "audio_box.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
// Prototypes
|
// Prototypes
|
||||||
|
class AssDialogue;
|
||||||
class AudioDisplay;
|
class AudioDisplay;
|
||||||
class AudioKaraoke;
|
class AudioKaraoke;
|
||||||
class FrameMain;
|
class FrameMain;
|
||||||
|
@ -66,18 +71,21 @@ class ToggleBitmap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class AudioBox
|
/// @class AudioBox
|
||||||
/// @brief DOCME
|
/// @brief Panel with audio playback and timing controls, also containing an AudioDisplay
|
||||||
///
|
|
||||||
/// DOCME
|
|
||||||
class AudioBox : public wxPanel {
|
class AudioBox : public wxPanel {
|
||||||
friend class AudioDisplay;
|
/// @todo Get rid of this ASAP, currently required for FrameMain to be able to notify
|
||||||
|
/// audio display about renderer having changed.
|
||||||
|
friend class FrameMain;
|
||||||
|
|
||||||
private:
|
/// The audio display in the box
|
||||||
|
AudioDisplay *audioDisplay;
|
||||||
|
|
||||||
/// DOCME
|
/// Selection controller used for timing controllers
|
||||||
wxScrollBar *audioScroll;
|
SelectionController<AssDialogue> *selection_controller;
|
||||||
|
|
||||||
|
/// The regular dalogue timing controller
|
||||||
|
AudioTimingController *timing_controller_dialogue;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxSlider *HorizontalZoom;
|
wxSlider *HorizontalZoom;
|
||||||
|
@ -100,9 +108,6 @@ private:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxSizer *DisplaySizer;
|
wxSizer *DisplaySizer;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxSashWindow *Sash;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
ToggleBitmap *VerticalLink;
|
ToggleBitmap *VerticalLink;
|
||||||
|
|
||||||
|
@ -133,21 +138,13 @@ private:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
ToggleBitmap *NextCommit;
|
ToggleBitmap *NextCommit;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
ToggleBitmap *MedusaMode;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
ToggleBitmap *AutoCommit;
|
ToggleBitmap *AutoCommit;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
ToggleBitmap *SpectrumMode;
|
|
||||||
|
|
||||||
void OnScrollbar(wxScrollEvent &event);
|
|
||||||
void OnHorizontalZoom(wxScrollEvent &event);
|
void OnHorizontalZoom(wxScrollEvent &event);
|
||||||
void OnVerticalZoom(wxScrollEvent &event);
|
void OnVerticalZoom(wxScrollEvent &event);
|
||||||
void OnVolume(wxScrollEvent &event);
|
void OnVolume(wxScrollEvent &event);
|
||||||
void OnVerticalLink(wxCommandEvent &event);
|
void OnVerticalLink(wxCommandEvent &event);
|
||||||
void OnSash(wxSashEvent &event);
|
|
||||||
|
|
||||||
void OnPlaySelection(wxCommandEvent &event);
|
void OnPlaySelection(wxCommandEvent &event);
|
||||||
void OnPlayDialogue(wxCommandEvent &event);
|
void OnPlayDialogue(wxCommandEvent &event);
|
||||||
|
@ -171,14 +168,13 @@ private:
|
||||||
|
|
||||||
void OnAutoGoto(wxCommandEvent &event);
|
void OnAutoGoto(wxCommandEvent &event);
|
||||||
void OnAutoCommit(wxCommandEvent &event);
|
void OnAutoCommit(wxCommandEvent &event);
|
||||||
void OnMedusaMode(wxCommandEvent &event);
|
|
||||||
void OnSpectrumMode(wxCommandEvent &event);
|
|
||||||
void OnNextLineCommit(wxCommandEvent &event);
|
void OnNextLineCommit(wxCommandEvent &event);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// DOCME
|
/// The controller controlling this audio box
|
||||||
AudioDisplay *audioDisplay;
|
AudioController *controller;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
AudioKaraoke *audioKaraoke;
|
AudioKaraoke *audioKaraoke;
|
||||||
|
@ -189,124 +185,15 @@ public:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
FrameMain *frameMain;
|
FrameMain *frameMain;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxString audioName;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool loaded;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
bool karaokeMode;
|
bool karaokeMode;
|
||||||
|
|
||||||
AudioBox(wxWindow *parent, SubtitlesGrid *grid);
|
AudioBox(wxWindow *parent, AudioController *controller, SelectionController<AssDialogue> *selection_controller);
|
||||||
~AudioBox();
|
~AudioBox();
|
||||||
|
|
||||||
void SetFile(wxString file,bool FromVideo);
|
|
||||||
void SetKaraokeButtons();
|
void SetKaraokeButtons();
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class FocusEvent
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
/// DOCME
|
|
||||||
class FocusEvent : public wxEvtHandler {
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSetFocus(wxFocusEvent &event);
|
|
||||||
DECLARE_EVENT_TABLE()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////
|
|
||||||
// IDs
|
|
||||||
enum {
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Scrollbar = 1600,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Horizontal_Zoom,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Vertical_Zoom,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Volume,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Sash,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Vertical_Link,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Stop,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Prev,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Next,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play_500ms_Before,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play_500ms_After,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play_500ms_First,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play_500ms_Last,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play_Row,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Play_To_End,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Commit,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Karaoke,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Goto,
|
|
||||||
|
|
||||||
Audio_Button_Join, /// Karaoke -> Enter join mode.
|
|
||||||
Audio_Button_Split, /// Karaoke -> Enter split mode.
|
|
||||||
Audio_Button_Accept, /// Karaoke -> Split/Join mode -> Accept.
|
|
||||||
Audio_Button_Cancel, /// KAraoke -> Split/Join mode -> Cancel.
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Leadin,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Button_Leadout,
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Check_AutoCommit,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Check_NextCommit,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Check_AutoGoto,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Check_Medusa,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Audio_Check_Spectrum
|
|
||||||
};
|
|
||||||
|
|
79
aegisub/src/audio_colorscheme.cpp
Normal file
79
aegisub/src/audio_colorscheme.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright (c) 2009-2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_colorscheme.cpp
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
///
|
||||||
|
/// Manage colour schemes for the audio display
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <algorithm>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "audio_colorscheme.h"
|
||||||
|
#include "colorspace.h"
|
||||||
|
|
||||||
|
// Something is defining "min" and "max" macros, and they interfere with using std::min and std::max
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioColorScheme::InitIcyBlue_Normal()
|
||||||
|
{
|
||||||
|
unsigned char *palptr = palette;
|
||||||
|
for (size_t i = 0; i <= factor; ++i)
|
||||||
|
{
|
||||||
|
float t = (float)i / factor;
|
||||||
|
int H = (int)(255 * (1.5 - t) / 2);
|
||||||
|
int S = (int)(255 * (0.5 + t/2));
|
||||||
|
int L = std::min(255, (int)(128 * 2 * t));
|
||||||
|
hsl_to_rgb(H, S, L, palptr + 0, palptr + 1, palptr + 2);
|
||||||
|
palptr += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioColorScheme::InitIcyBlue_Selected()
|
||||||
|
{
|
||||||
|
unsigned char *palptr = palette;
|
||||||
|
for (size_t i = 0; i <= factor; ++i)
|
||||||
|
{
|
||||||
|
float t = (float)i / factor;
|
||||||
|
int H = (int)(255 * (1.5 - t) / 2);
|
||||||
|
int S = (int)(255 * (0.5 + t/2));
|
||||||
|
int L = std::min(255, (int)(128 * (3 * t/2 + 0.5)));
|
||||||
|
hsl_to_rgb(H, S, L, palptr + 0, palptr + 1, palptr + 2);
|
||||||
|
palptr += 4;
|
||||||
|
}
|
||||||
|
}
|
118
aegisub/src/audio_colorscheme.h
Normal file
118
aegisub/src/audio_colorscheme.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
// Copyright (c) 2009-2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_colorscheme.h
|
||||||
|
/// @see audio_colorscheme.cpp
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
///
|
||||||
|
/// Manage colour schemes for the audio display
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <wx/colour.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioSpectrumColorMap
|
||||||
|
/// @brief Provides colour maps for audio display rendering
|
||||||
|
///
|
||||||
|
/// Maps values from floats in range 0..1 into RGB colour values.
|
||||||
|
///
|
||||||
|
/// First create an instance of this class, then call an initialisation function
|
||||||
|
/// in it to fill the palette with a colour map.
|
||||||
|
///
|
||||||
|
/// @todo Let consumers of this class specify their own palette generation function.
|
||||||
|
class AudioColorScheme {
|
||||||
|
/// The palette data for the map
|
||||||
|
unsigned char *palette;
|
||||||
|
|
||||||
|
/// Factor to multiply 0..1 values by to map them into the palette range
|
||||||
|
size_t factor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Constructor
|
||||||
|
/// @param prec Bit precision to create the colour map with
|
||||||
|
///
|
||||||
|
/// Allocates the palette array to 2^prec entries
|
||||||
|
AudioColorScheme(int prec)
|
||||||
|
: palette(new unsigned char[(4<<prec) + 4])
|
||||||
|
, factor(1<<prec)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
|
///
|
||||||
|
/// De-allocates the palette array
|
||||||
|
~AudioColorScheme()
|
||||||
|
{
|
||||||
|
delete[] palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Initialise the palette to the Aegisub 2.1 "Icy Blue" scheme (unselected)
|
||||||
|
void InitIcyBlue_Normal();
|
||||||
|
/// @brief Initialise the palette to the Aegisub 2.1 "Icy Blue" scheme (selected)
|
||||||
|
void InitIcyBlue_Selected();
|
||||||
|
|
||||||
|
/// @brief Map a floating point value to RGB
|
||||||
|
/// @param val [in] The value to map from
|
||||||
|
/// @param pixel [out] First byte of the pixel to write
|
||||||
|
///
|
||||||
|
/// Writes into the XRGB pixel (assumed 32 bit without alpha) passed.
|
||||||
|
/// The pixel format is assumed to be the same as that in the palette.
|
||||||
|
inline void map(float val, unsigned char *pixel)
|
||||||
|
{
|
||||||
|
if (val < 0.0) val = 0.0;
|
||||||
|
if (val > 1.0) val = 1.0;
|
||||||
|
// Find the colour in the palette
|
||||||
|
unsigned char *color = palette + ((int)(val*factor) * 4);
|
||||||
|
// Copy to the destination.
|
||||||
|
// Has to be done one byte at a time since we're writing RGB and not RGBX or RGBA
|
||||||
|
// data, and we otherwise write past the end of the pixel we're writing, possibly
|
||||||
|
// hitting adjacent memory blocks or just overwriting the start of the following
|
||||||
|
// scanline in the image.
|
||||||
|
// As the image is 24 bpp, 3 of every 4 uint32_t writes would be unaligned anyway.
|
||||||
|
pixel[0] = color[0];
|
||||||
|
pixel[1] = color[1];
|
||||||
|
pixel[2] = color[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get a floating point value's colour as a wxColour
|
||||||
|
/// @param val The value to map from
|
||||||
|
/// @return The corresponding wxColour
|
||||||
|
wxColour get(float val)
|
||||||
|
{
|
||||||
|
if (val < 0.0) val = 0.0;
|
||||||
|
if (val > 1.0) val = 1.0;
|
||||||
|
unsigned char *color = palette + ((int)(val*factor) * 4);
|
||||||
|
return wxColour(color[0], color[1], color[2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
568
aegisub/src/audio_controller.cpp
Normal file
568
aegisub/src/audio_controller.cpp
Normal file
|
@ -0,0 +1,568 @@
|
||||||
|
// Copyright (c) 2009-2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_controller.cpp
|
||||||
|
/// @brief Manage open audio and abstract state away from display
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
///
|
||||||
|
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <wx/filename.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
#include "include/aegisub/audio_player.h"
|
||||||
|
#include "audio_provider_dummy.h"
|
||||||
|
#include "audio_timing.h"
|
||||||
|
#include "compat.h"
|
||||||
|
#include "video_context.h"
|
||||||
|
|
||||||
|
class AudioMarkerKeyframe : public AudioMarker {
|
||||||
|
int64_t position;
|
||||||
|
static wxPen style;
|
||||||
|
public:
|
||||||
|
AudioMarkerKeyframe(int64_t position) : position(position) { }
|
||||||
|
int64_t GetPosition() const { return position; }
|
||||||
|
FeetStyle GetFeet() const { return Feet_None; }
|
||||||
|
bool CanSnap() const { return true; }
|
||||||
|
wxPen GetStyle() const
|
||||||
|
{
|
||||||
|
if (!style.IsOk())
|
||||||
|
/// @todo Make this colour configurable
|
||||||
|
style = wxPen(wxColour(255,0,255), 1);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
bool operator < (const AudioMarkerKeyframe &other) const { return position < other.position; }
|
||||||
|
operator int64_t() const { return position; }
|
||||||
|
};
|
||||||
|
bool operator < (int64_t a, const AudioMarkerKeyframe &b) { return a < b.GetPosition(); }
|
||||||
|
bool operator < (const AudioMarkerKeyframe &a, int64_t b) { return a.GetPosition() < b; }
|
||||||
|
wxPen AudioMarkerKeyframe::style;
|
||||||
|
|
||||||
|
class AudioMarkerProviderKeyframes : public AudioMarkerProvider, private AudioControllerAudioEventListener {
|
||||||
|
// GetMarkers needs to be const but still needs to modify this state, which is really
|
||||||
|
// just a cache... use the mutable "hack".
|
||||||
|
mutable int last_keyframes_revision;
|
||||||
|
mutable std::vector<AudioMarkerKeyframe> keyframe_samples;
|
||||||
|
AudioController *controller;
|
||||||
|
int64_t samplerate;
|
||||||
|
|
||||||
|
void ReloadKeyframes() const
|
||||||
|
{
|
||||||
|
keyframe_samples.clear();
|
||||||
|
|
||||||
|
VideoContext *vc = VideoContext::Get();
|
||||||
|
if (!vc) return;
|
||||||
|
|
||||||
|
last_keyframes_revision = vc->GetKeyframesRevision();
|
||||||
|
const std::vector<int> &raw_keyframes = vc->GetKeyFrames();
|
||||||
|
keyframe_samples.reserve(raw_keyframes.size());
|
||||||
|
for (size_t i = 0; i < raw_keyframes.size(); ++i)
|
||||||
|
{
|
||||||
|
keyframe_samples.push_back(AudioMarkerKeyframe(
|
||||||
|
vc->TimeAtFrame(raw_keyframes[i]) * samplerate / 1000));
|
||||||
|
}
|
||||||
|
std::sort(keyframe_samples.begin(), keyframe_samples.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// AudioControllerAudioEventListener implementation
|
||||||
|
virtual void OnAudioOpen(AudioProvider *provider)
|
||||||
|
{
|
||||||
|
samplerate = provider->GetSampleRate();
|
||||||
|
ReloadKeyframes();
|
||||||
|
}
|
||||||
|
virtual void OnAudioClose() { }
|
||||||
|
virtual void OnPlaybackPosition(int64_t sample_position) { }
|
||||||
|
virtual void OnPlaybackStop() { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioMarkerProviderKeyframes(AudioController *controller)
|
||||||
|
: controller(controller)
|
||||||
|
{
|
||||||
|
// Assume that a video context with keyframes revision 0 never has keyframes loaded
|
||||||
|
last_keyframes_revision = 0;
|
||||||
|
samplerate = 44100;
|
||||||
|
controller->AddAudioListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~AudioMarkerProviderKeyframes()
|
||||||
|
{
|
||||||
|
controller->RemoveAudioListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out) const
|
||||||
|
{
|
||||||
|
VideoContext *vc = VideoContext::Get();
|
||||||
|
if (!vc) return;
|
||||||
|
|
||||||
|
// Re-read keyframe data if the revision number changed, the keyframe data probably did too
|
||||||
|
if (vc->GetKeyframesRevision() != last_keyframes_revision)
|
||||||
|
ReloadKeyframes();
|
||||||
|
|
||||||
|
// Find first and last keyframes inside the range
|
||||||
|
std::vector<AudioMarkerKeyframe>::iterator a = std::lower_bound(
|
||||||
|
keyframe_samples.begin(), keyframe_samples.end(), range.begin());
|
||||||
|
std::vector<AudioMarkerKeyframe>::iterator b = std::upper_bound(
|
||||||
|
keyframe_samples.begin(), keyframe_samples.end(), range.end());
|
||||||
|
|
||||||
|
// Place pointers to the markers in the output vector
|
||||||
|
for (; a != b; ++a)
|
||||||
|
out.push_back(&*a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Type of the audio event listener container in AudioController
|
||||||
|
typedef std::set<AudioControllerAudioEventListener *> AudioEventListenerSet;
|
||||||
|
/// Type of the timing event listener container in AudioController
|
||||||
|
typedef std::set<AudioControllerTimingEventListener *> TimingEventListenerSet;
|
||||||
|
|
||||||
|
/// Macro to iterate audio event listeners in AudioController implementation
|
||||||
|
#define AUDIO_LISTENERS(listener) for (AudioEventListenerSet::iterator listener = audio_event_listeners.begin(); listener != audio_event_listeners.end(); ++listener)
|
||||||
|
/// Macro to iterate audio event listeners in AudioController implementation
|
||||||
|
#define TIMING_LISTENERS(listener) for (TimingEventListenerSet::iterator listener = timing_event_listeners.begin(); listener != timing_event_listeners.end(); ++listener)
|
||||||
|
|
||||||
|
|
||||||
|
AudioController::AudioController()
|
||||||
|
: player(0)
|
||||||
|
, provider(0)
|
||||||
|
, timing_controller(0)
|
||||||
|
, keyframes_marker_provider(new AudioMarkerProviderKeyframes(this))
|
||||||
|
, playback_mode(PM_NotPlaying)
|
||||||
|
, playback_timer(this)
|
||||||
|
{
|
||||||
|
Connect(playback_timer.GetId(), wxEVT_TIMER, (wxObjectEventFunction)&AudioController::OnPlaybackTimer);
|
||||||
|
|
||||||
|
#ifdef wxHAS_POWER_EVENTS
|
||||||
|
Connect(wxEVT_POWER_SUSPENDED, (wxObjectEventFunction)&AudioController::OnComputerSuspending);
|
||||||
|
Connect(wxEVT_POWER_RESUME, (wxObjectEventFunction)&AudioController::OnComputerResuming);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioController::~AudioController()
|
||||||
|
{
|
||||||
|
CloseAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::OnPlaybackTimer(wxTimerEvent &event)
|
||||||
|
{
|
||||||
|
int64_t pos = player->GetCurrentPosition();
|
||||||
|
|
||||||
|
if (!player->IsPlaying() ||
|
||||||
|
(playback_mode != PM_ToEnd && pos >= player->GetEndPosition()+200))
|
||||||
|
{
|
||||||
|
// The +200 is to allow the player to end the sound output cleanly, otherwise a popping
|
||||||
|
// artifact can sometimes be heard.
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AUDIO_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnPlaybackPosition(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef wxHAS_POWER_EVENTS
|
||||||
|
void AudioController::OnComputerSuspending(wxPowerEvent &event)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
player->CloseStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::OnComputerResuming(wxPowerEvent &event)
|
||||||
|
{
|
||||||
|
if (provider)
|
||||||
|
player->OpenStream();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::OpenAudio(const wxString &url)
|
||||||
|
{
|
||||||
|
CloseAudio();
|
||||||
|
|
||||||
|
if (!url)
|
||||||
|
throw agi::InternalError("AudioController::OpenAudio() was passed an empty string. This must not happen.", 0);
|
||||||
|
|
||||||
|
wxString path_part;
|
||||||
|
|
||||||
|
if (url.StartsWith(_T("dummy-audio:"), &path_part))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* scheme ::= "dummy-audio" ":" signal-specifier "?" signal-parameters
|
||||||
|
* signal-specifier ::= "silence" | "noise" | "sine" "/" frequency
|
||||||
|
* frequency ::= integer
|
||||||
|
* signal-parameters ::= signal-parameter [ "&" signal-parameters ]
|
||||||
|
* signal-parameter ::= signal-parameter-name "=" integer
|
||||||
|
* signal-parameter-name ::= "sr" | "bd" | "ch" | "ln"
|
||||||
|
*
|
||||||
|
* Signal types:
|
||||||
|
* "silence", a silent signal is generated.
|
||||||
|
* "noise", a white noise signal is generated.
|
||||||
|
* "sine", a sine wave is generated at the specified frequency.
|
||||||
|
*
|
||||||
|
* Signal parameters:
|
||||||
|
* "sr", sample rate to generate signal at.
|
||||||
|
* "bd", bit depth to generate signal at (usually 16).
|
||||||
|
* "ch", number of channels to generate, usually 1 or 2. The same signal is generated
|
||||||
|
* in every channel even if one would be LFE.
|
||||||
|
* "ln", length of signal in samples. ln/sr gives signal length in seconds.
|
||||||
|
*/
|
||||||
|
provider = new DummyAudioProvider(5*30*60*1000, true);
|
||||||
|
}
|
||||||
|
else if (url.StartsWith(_T("video-audio:"), &path_part))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* scheme ::= "video-audio" ":" stream-type
|
||||||
|
* stream-type ::= "stream" | "cache"
|
||||||
|
*
|
||||||
|
* Stream types:
|
||||||
|
*
|
||||||
|
* "stream", the audio is streamed as required directly from the video provider,
|
||||||
|
* and cannot be used to drive an audio display. Seeking is unreliable.
|
||||||
|
*
|
||||||
|
* "cache", the entire audio is cached to memory or disk. Audio displays can be
|
||||||
|
* driven and seeking is reliable. Opening takes longer because the entire audio
|
||||||
|
* stream has to be decoded and stored.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if (url.StartsWith(_T("file:"), &path_part))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* scheme ::= "file" ":" "//" file-system-path
|
||||||
|
*
|
||||||
|
* On Unix-like systems, the file system path is regular. On Windows-systems, the
|
||||||
|
* path uses forward slashes instead of back-slashes and the drive letter is
|
||||||
|
* preceded by a slash.
|
||||||
|
*
|
||||||
|
* URL-encoding??
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Assume it's not a URI but instead a filename in the platform's native format.
|
||||||
|
*/
|
||||||
|
wxFileName fn(url);
|
||||||
|
if (!fn.FileExists())
|
||||||
|
{
|
||||||
|
agi::FileNotFoundError fnf(STD_STR(url));
|
||||||
|
throw agi::AudioOpenError(
|
||||||
|
"Failed opening audio file (parsing as plain filename)",
|
||||||
|
&fnf);
|
||||||
|
}
|
||||||
|
provider = AudioProviderFactory::GetProvider(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
player = AudioPlayerFactory::GetAudioPlayer();
|
||||||
|
player->SetProvider(provider);
|
||||||
|
player->OpenStream();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete player;
|
||||||
|
delete provider;
|
||||||
|
player = 0;
|
||||||
|
provider = 0;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell listeners about this.
|
||||||
|
AUDIO_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnAudioOpen(provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::CloseAudio()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
delete player;
|
||||||
|
delete provider;
|
||||||
|
player = 0;
|
||||||
|
provider = 0;
|
||||||
|
|
||||||
|
AUDIO_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnAudioClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AudioController::IsAudioOpen() const
|
||||||
|
{
|
||||||
|
return player && provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString AudioController::GetAudioURL() const
|
||||||
|
{
|
||||||
|
/// @todo figure out how to get the url
|
||||||
|
return _T("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::AddAudioListener(AudioControllerAudioEventListener *listener)
|
||||||
|
{
|
||||||
|
audio_event_listeners.insert(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::RemoveAudioListener(AudioControllerAudioEventListener *listener)
|
||||||
|
{
|
||||||
|
audio_event_listeners.erase(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::AddTimingListener(AudioControllerTimingEventListener *listener)
|
||||||
|
{
|
||||||
|
timing_event_listeners.insert(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::RemoveTimingListener(AudioControllerTimingEventListener *listener)
|
||||||
|
{
|
||||||
|
timing_event_listeners.erase(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::SetTimingController(AudioTimingController *new_controller)
|
||||||
|
{
|
||||||
|
delete timing_controller;
|
||||||
|
timing_controller = new_controller;
|
||||||
|
|
||||||
|
TIMING_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnTimingControllerChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::OnTimingControllerUpdatedPrimaryRange(AudioTimingController *sending_controller)
|
||||||
|
{
|
||||||
|
assert(sending_controller != 0);
|
||||||
|
if (sending_controller != timing_controller)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (playback_mode == PM_PrimaryRange)
|
||||||
|
{
|
||||||
|
player->SetEndPosition(timing_controller->GetPrimaryPlaybackRange().end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMING_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnSelectionChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::OnTimingControllerUpdatedStyleRanges(AudioTimingController *sending_controller)
|
||||||
|
{
|
||||||
|
assert(sending_controller != 0);
|
||||||
|
if (sending_controller != timing_controller)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/// @todo redraw and stuff, probably
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::OnTimingControllerMarkerMoved(AudioTimingController *sending_controller, AudioMarker *marker)
|
||||||
|
{
|
||||||
|
assert(sending_controller != 0);
|
||||||
|
if (sending_controller != timing_controller)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/// @todo shouldn't this be more detailed?
|
||||||
|
TIMING_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnMarkersMoved();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::PlayRange(const AudioController::SampleRange &range)
|
||||||
|
{
|
||||||
|
if (!IsAudioOpen()) return;
|
||||||
|
|
||||||
|
player->Play(range.begin(), range.length());
|
||||||
|
playback_mode = PM_Range;
|
||||||
|
playback_timer.Start(20);
|
||||||
|
|
||||||
|
AUDIO_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnPlaybackPosition(range.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::PlayPrimaryRange()
|
||||||
|
{
|
||||||
|
PlayRange(GetPrimaryPlaybackRange());
|
||||||
|
if (playback_mode == PM_Range)
|
||||||
|
playback_mode = PM_PrimaryRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::PlayToEnd(int64_t start_sample)
|
||||||
|
{
|
||||||
|
if (!IsAudioOpen()) return;
|
||||||
|
|
||||||
|
player->Play(start_sample, provider->GetNumSamples()-start_sample);
|
||||||
|
playback_mode = PM_ToEnd;
|
||||||
|
playback_timer.Start(20);
|
||||||
|
|
||||||
|
AUDIO_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnPlaybackPosition(start_sample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::Stop()
|
||||||
|
{
|
||||||
|
if (!IsAudioOpen()) return;
|
||||||
|
|
||||||
|
player->Stop();
|
||||||
|
playback_mode = PM_NotPlaying;
|
||||||
|
playback_timer.Stop();
|
||||||
|
|
||||||
|
AUDIO_LISTENERS(l)
|
||||||
|
{
|
||||||
|
(*l)->OnPlaybackStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AudioController::IsPlaying()
|
||||||
|
{
|
||||||
|
return IsAudioOpen() && playback_mode != PM_NotPlaying;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64_t AudioController::GetPlaybackPosition()
|
||||||
|
{
|
||||||
|
if (!IsPlaying()) return 0;
|
||||||
|
|
||||||
|
return player->GetCurrentPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::ResyncPlaybackPosition(int64_t new_position)
|
||||||
|
{
|
||||||
|
if (!IsPlaying()) return;
|
||||||
|
|
||||||
|
player->SetCurrentPosition(new_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioController::SampleRange AudioController::GetPrimaryPlaybackRange() const
|
||||||
|
{
|
||||||
|
if (timing_controller != 0)
|
||||||
|
{
|
||||||
|
return timing_controller->GetPrimaryPlaybackRange();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SampleRange(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::GetMarkers(const SampleRange &range, AudioMarkerVector &markers) const
|
||||||
|
{
|
||||||
|
/// @todo Find all sources of markers
|
||||||
|
keyframes_marker_provider->GetMarkers(range, markers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double AudioController::GetVolume() const
|
||||||
|
{
|
||||||
|
if (!IsAudioOpen()) return 1.0;
|
||||||
|
return player->GetVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioController::SetVolume(double volume)
|
||||||
|
{
|
||||||
|
if (!IsAudioOpen()) return;
|
||||||
|
player->SetVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64_t AudioController::SamplesFromMilliseconds(int64_t ms) const
|
||||||
|
{
|
||||||
|
/// @todo There might be some subtle rounding errors here.
|
||||||
|
|
||||||
|
if (!provider) return 0;
|
||||||
|
|
||||||
|
int64_t sr = provider->GetSampleRate();
|
||||||
|
|
||||||
|
int64_t millisamples = ms * sr;
|
||||||
|
|
||||||
|
return (millisamples + 999) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64_t AudioController::MillisecondsFromSamples(int64_t samples) const
|
||||||
|
{
|
||||||
|
/// @todo There might be some subtle rounding errors here.
|
||||||
|
|
||||||
|
if (!provider) return 0;
|
||||||
|
|
||||||
|
int64_t sr = provider->GetSampleRate();
|
||||||
|
|
||||||
|
int64_t millisamples = samples * 1000;
|
||||||
|
|
||||||
|
return millisamples / sr;
|
||||||
|
}
|
||||||
|
|
439
aegisub/src/audio_controller.h
Normal file
439
aegisub/src/audio_controller.h
Normal file
|
@ -0,0 +1,439 @@
|
||||||
|
// Copyright (c) 2009-2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_controller.h
|
||||||
|
/// @see audio_controller.cpp
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wx/event.h>
|
||||||
|
#include <wx/string.h>
|
||||||
|
#include <wx/timer.h>
|
||||||
|
#include <wx/pen.h>
|
||||||
|
#include <wx/power.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <libaegisub/exception.h>
|
||||||
|
|
||||||
|
#define AGI_AUDIO_CONTROLLER_INCLUDED 1
|
||||||
|
|
||||||
|
|
||||||
|
class AudioPlayer;
|
||||||
|
class AudioProvider;
|
||||||
|
|
||||||
|
// Declared below
|
||||||
|
class AudioControllerAudioEventListener;
|
||||||
|
class AudioControllerTimingEventListener;
|
||||||
|
class AudioTimingController;
|
||||||
|
class AudioMarker;
|
||||||
|
class AudioMarkerProvider;
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::vector<const AudioMarker*> AudioMarkerVector;
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioController
|
||||||
|
/// @brief Manage an open audio stream and UI state for it
|
||||||
|
///
|
||||||
|
/// Keeps track of the UI interaction state of the open audio for a project, ie. what the current
|
||||||
|
/// selection is, what moveable markers are on the audio, and any secondary non-moveable markers
|
||||||
|
/// that are present.
|
||||||
|
///
|
||||||
|
/// Changes in interaction are broadcast to all managed audio displays so they can redraw, and
|
||||||
|
/// the audio displays report all interactions back to the controller. There is a one to many
|
||||||
|
/// relationship between controller and audio displays. There is at most one audio controller
|
||||||
|
/// for an open subtitling project.
|
||||||
|
///
|
||||||
|
/// Creates and destroys audio providers and players. This behaviour should at some point be moved
|
||||||
|
/// to a separate class, as it adds too many responsibilities to this class, but at the time of
|
||||||
|
/// writing, it would extend the scope of reworking components too much.
|
||||||
|
///
|
||||||
|
/// There is not supposed to be a way to get direct access to the audio providers or players owned
|
||||||
|
/// by a controller. If some operation that isn't possible in the existing design is needed, the
|
||||||
|
/// controller should be extended in some way to allow it.
|
||||||
|
class AudioController : public wxEvtHandler {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @class SampleRange
|
||||||
|
/// @brief Represents an immutable range of audio samples
|
||||||
|
class SampleRange {
|
||||||
|
int64_t _begin;
|
||||||
|
int64_t _end;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Constructor
|
||||||
|
/// @param begin Index of the first sample to include in the range
|
||||||
|
/// @param end Index of one past the last sample to include in the range
|
||||||
|
SampleRange(int64_t begin, int64_t end)
|
||||||
|
: _begin(begin)
|
||||||
|
, _end(end)
|
||||||
|
{
|
||||||
|
assert(end >= begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Copy constructor, optionally adjusting the range
|
||||||
|
/// @param src The range to duplicate
|
||||||
|
/// @param begin_adjust Number of samples to add to the start of the range
|
||||||
|
/// @param end_adjust Number of samples to add to the end of the range
|
||||||
|
SampleRange(const SampleRange &src, int64_t begin_adjust = 0, int64_t end_adjust = 0)
|
||||||
|
{
|
||||||
|
_begin = src._begin + begin_adjust;
|
||||||
|
_end = src._end + end_adjust;
|
||||||
|
assert(_end >= _begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the number of samples in the range
|
||||||
|
int64_t length() const { return _end - _begin; }
|
||||||
|
/// Get the index of the first sample in the range
|
||||||
|
int64_t begin() const { return _begin; }
|
||||||
|
/// Get the index of one past the last sample in the range
|
||||||
|
int64_t end() const { return _end; }
|
||||||
|
|
||||||
|
/// Determine whether the range contains a given sample index
|
||||||
|
bool contains(int64_t sample) const { return sample >= begin() && sample < end(); }
|
||||||
|
|
||||||
|
/// Determine whether there is an overlap between two ranges
|
||||||
|
bool overlaps(const SampleRange &other) const
|
||||||
|
{
|
||||||
|
return other.contains(_begin)
|
||||||
|
|| other.contains(_end)
|
||||||
|
|| contains(other._begin)
|
||||||
|
|| contains(other._end);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// Listeners for audio-related events
|
||||||
|
std::set<AudioControllerAudioEventListener *> audio_event_listeners;
|
||||||
|
|
||||||
|
/// Listeners for timing-related events
|
||||||
|
std::set<AudioControllerTimingEventListener *> timing_event_listeners;
|
||||||
|
|
||||||
|
/// The audio output object
|
||||||
|
AudioPlayer *player;
|
||||||
|
|
||||||
|
/// The audio provider
|
||||||
|
AudioProvider *provider;
|
||||||
|
|
||||||
|
/// The current timing mode, if any; owned by the audio controller
|
||||||
|
AudioTimingController *timing_controller;
|
||||||
|
|
||||||
|
/// Provide keyframe data for audio displays
|
||||||
|
std::auto_ptr<AudioMarkerProvider> keyframes_marker_provider;
|
||||||
|
|
||||||
|
|
||||||
|
enum PlaybackMode {
|
||||||
|
PM_NotPlaying,
|
||||||
|
PM_Range,
|
||||||
|
PM_PrimaryRange,
|
||||||
|
PM_ToEnd
|
||||||
|
};
|
||||||
|
/// The current playback mode
|
||||||
|
PlaybackMode playback_mode;
|
||||||
|
|
||||||
|
|
||||||
|
/// Timer used for playback position updates
|
||||||
|
wxTimer playback_timer;
|
||||||
|
|
||||||
|
/// Event handler for the playback timer
|
||||||
|
void OnPlaybackTimer(wxTimerEvent &event);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef wxHAS_POWER_EVENTS
|
||||||
|
/// Handle computer going into suspend mode by stopping audio and closing device
|
||||||
|
void OnComputerSuspending(wxPowerEvent &event);
|
||||||
|
/// Handle computer resuming from suspend by re-opening the audio device
|
||||||
|
void OnComputerResuming(wxPowerEvent &event);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @brief Constructor
|
||||||
|
AudioController();
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
|
~AudioController();
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Open an audio stream
|
||||||
|
/// @param url URL of the stream to open
|
||||||
|
///
|
||||||
|
/// The URL can either be a plain filename (with no qualifiers) or one
|
||||||
|
/// recognised by various providers.
|
||||||
|
void OpenAudio(const wxString &url);
|
||||||
|
|
||||||
|
/// @brief Closes the current audio stream
|
||||||
|
void CloseAudio();
|
||||||
|
|
||||||
|
/// @brief Determine whether audio is currently open
|
||||||
|
/// @return True if an audio stream is open and can be played back
|
||||||
|
bool IsAudioOpen() const;
|
||||||
|
|
||||||
|
/// @brief Get the URL for the current open audio stream
|
||||||
|
/// @return The URL for the audio stream
|
||||||
|
///
|
||||||
|
/// The returned URL can be passed into OpenAudio() later to open the same stream again.
|
||||||
|
wxString GetAudioURL() const;
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Add an audio event listener
|
||||||
|
/// @param listener The listener to add
|
||||||
|
void AddAudioListener(AudioControllerAudioEventListener *listener);
|
||||||
|
|
||||||
|
/// @brief Remove an audio event listener
|
||||||
|
/// @param listener The listener to remove
|
||||||
|
void RemoveAudioListener(AudioControllerAudioEventListener *listener);
|
||||||
|
|
||||||
|
/// @brief Add a timing event listener
|
||||||
|
/// @param listener The listener to add
|
||||||
|
void AddTimingListener(AudioControllerTimingEventListener *listener);
|
||||||
|
|
||||||
|
/// @brief Remove a timing event listener
|
||||||
|
/// @param listener The listener to remove
|
||||||
|
void RemoveTimingListener(AudioControllerTimingEventListener *listener);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Start or restart audio playback, playing a range
|
||||||
|
/// @param range The range of audio to play back
|
||||||
|
///
|
||||||
|
/// The end of the played back range may be requested changed, but is not changed
|
||||||
|
/// automatically from any other operations.
|
||||||
|
void PlayRange(const SampleRange &range);
|
||||||
|
|
||||||
|
/// @brief Start or restart audio playback, playing the primary playback range
|
||||||
|
///
|
||||||
|
/// If the primary playback range is updated during playback, the end of the
|
||||||
|
/// active playback range will be updated to match the new selection. The playback
|
||||||
|
/// end can not be changed in any other way.
|
||||||
|
void PlayPrimaryRange();
|
||||||
|
|
||||||
|
/// @brief Start or restart audio playback, playing from a point to the end of stream
|
||||||
|
/// @param start_sample Index of the sample to start playback at
|
||||||
|
///
|
||||||
|
/// Playback to end cannot be converted to a range playback like range playback can,
|
||||||
|
/// it will continue until the end is reached, it is stopped, or restarted.
|
||||||
|
void PlayToEnd(int64_t start_sample);
|
||||||
|
|
||||||
|
/// @brief Stop all audio playback
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
/// @brief Determine whether playback is ongoing
|
||||||
|
/// @return True if audio is being played back
|
||||||
|
bool IsPlaying();
|
||||||
|
|
||||||
|
/// @brief Get the current playback position
|
||||||
|
/// @return Approximate current sample index being heard by the user
|
||||||
|
///
|
||||||
|
/// Returns 0 if playback is stopped. The return value is only approximate.
|
||||||
|
int64_t GetPlaybackPosition();
|
||||||
|
|
||||||
|
/// @brief If playing, restart playback from the specified position
|
||||||
|
/// @param new_position Sample index to restart playback from
|
||||||
|
///
|
||||||
|
/// This function can be used to re-synchronise audio playback to another source that
|
||||||
|
/// might not be able to keep up with the full speed, such as video playback in high
|
||||||
|
/// resolution or with complex subtitles.
|
||||||
|
///
|
||||||
|
/// This function only does something if audio is already playing.
|
||||||
|
void ResyncPlaybackPosition(int64_t new_position);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Get the primary playback range
|
||||||
|
/// @return An immutable SampleRange object
|
||||||
|
SampleRange GetPrimaryPlaybackRange() const;
|
||||||
|
|
||||||
|
/// @brief Get all static markers inside a range
|
||||||
|
/// @param range The sample range to retrieve markers for
|
||||||
|
/// @param markers Vector to fill found markers into
|
||||||
|
///
|
||||||
|
/// The markers retrieved are static markers the user can't interact with.
|
||||||
|
/// Markers for user interaction are obtained through the timing controller.
|
||||||
|
void GetMarkers(const SampleRange &range, AudioMarkerVector &markers) const;
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Get the playback audio volume
|
||||||
|
/// @return The amplification factor for the audio
|
||||||
|
double GetVolume() const;
|
||||||
|
|
||||||
|
/// @brief Set the playback audio volume
|
||||||
|
/// @param volume The new amplification factor for the audio
|
||||||
|
void SetVolume(double volume);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Return the current audio provider
|
||||||
|
/// @return A const pointer to the current audio provider
|
||||||
|
const AudioProvider * GetAudioProvider() const { return provider; }
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Return the current timing controller
|
||||||
|
/// @return The current timing controller or 0
|
||||||
|
AudioTimingController * GetTimingController() const { return timing_controller; }
|
||||||
|
|
||||||
|
/// @brief Change the current timing controller
|
||||||
|
/// @param new_mode The new timing controller or 0. This may be the same object as
|
||||||
|
/// the current timing controller, to signal that the timing controller has changed
|
||||||
|
/// the object being timed, eg. changed to a new dialogue line.
|
||||||
|
void SetTimingController(AudioTimingController *new_controller);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Timing controller signals primary playback range changed
|
||||||
|
/// @param timing_controller The timing controller sending this notification
|
||||||
|
///
|
||||||
|
/// Only timing controllers should call this function. This function must be called
|
||||||
|
/// when the primary playback range is changed in the timing controller, usually
|
||||||
|
/// as a result of user interaction.
|
||||||
|
void OnTimingControllerUpdatedPrimaryRange(AudioTimingController *timing_controller);
|
||||||
|
|
||||||
|
/// @brief Timing controller signals that the rendering style ranges have changed
|
||||||
|
/// @param timing_controller The timing controller sending this notification
|
||||||
|
///
|
||||||
|
/// Only timing controllers should call this function. This function must be called
|
||||||
|
/// when one or more rendering style ranges have changed in the timing controller.
|
||||||
|
void OnTimingControllerUpdatedStyleRanges(AudioTimingController *timing_controller);
|
||||||
|
|
||||||
|
/// @brief Timing controller signals that an audio marker has moved
|
||||||
|
/// @param timing_controller The timing controller sending this notification
|
||||||
|
/// @param marker The marker that was moved
|
||||||
|
///
|
||||||
|
/// Only timing controllers should call this function. This function must be called
|
||||||
|
/// when a marker owned by the timing controller has been updated in some way.
|
||||||
|
void OnTimingControllerMarkerMoved(AudioTimingController *timing_controller, AudioMarker *marker);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Convert a count of audio samples to a time in milliseconds
|
||||||
|
/// @param samples Sample count to convert
|
||||||
|
/// @return The number of milliseconds equivalent to the sample-count, rounded down
|
||||||
|
int64_t MillisecondsFromSamples(int64_t samples) const;
|
||||||
|
|
||||||
|
/// @brief Convert a time in milliseconds to a count of audio samples
|
||||||
|
/// @param ms Time in milliseconds to convert
|
||||||
|
/// @return The index of the first sample that is wholly inside the millisecond
|
||||||
|
int64_t SamplesFromMilliseconds(int64_t ms) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioControllerAudioEventListener
|
||||||
|
/// @brief Abstract interface for objects that want audio events
|
||||||
|
class AudioControllerAudioEventListener {
|
||||||
|
public:
|
||||||
|
/// A new audio stream was opened (and any previously open was closed)
|
||||||
|
virtual void OnAudioOpen(AudioProvider *) = 0;
|
||||||
|
|
||||||
|
/// The current audio stream was closed
|
||||||
|
virtual void OnAudioClose() = 0;
|
||||||
|
|
||||||
|
/// Playback is in progress and ths current position was updated
|
||||||
|
virtual void OnPlaybackPosition(int64_t sample_position) = 0;
|
||||||
|
|
||||||
|
/// Playback has stopped
|
||||||
|
virtual void OnPlaybackStop() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioControllerTimingEventListener
|
||||||
|
/// @brief Abstract interface for objects that want audio timing events
|
||||||
|
class AudioControllerTimingEventListener {
|
||||||
|
public:
|
||||||
|
/// One or more moveable markers were moved
|
||||||
|
virtual void OnMarkersMoved() = 0;
|
||||||
|
|
||||||
|
/// The selection was changed
|
||||||
|
virtual void OnSelectionChanged() = 0;
|
||||||
|
|
||||||
|
/// The timing controller was replaced
|
||||||
|
virtual void OnTimingControllerChanged() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioMarkerProvider
|
||||||
|
/// @brief Abstract interface for audio marker providers
|
||||||
|
class AudioMarkerProvider {
|
||||||
|
public:
|
||||||
|
/// Virtual destructor, does nothing
|
||||||
|
virtual ~AudioMarkerProvider() { }
|
||||||
|
|
||||||
|
/// @brief Return markers in a sample range
|
||||||
|
virtual void GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioMarker
|
||||||
|
/// @brief A marker on the audio display
|
||||||
|
class AudioMarker {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Describe which directions a marker has feet in
|
||||||
|
enum FeetStyle {
|
||||||
|
Feet_None = 0,
|
||||||
|
Feet_Left,
|
||||||
|
Feet_Right,
|
||||||
|
Feet_Both // Conveniently Feet_Left|Feet_Right
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Get the marker's position
|
||||||
|
/// @return The marker's position in samples
|
||||||
|
virtual int64_t GetPosition() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get the marker's drawing style
|
||||||
|
/// @return A pen object describing the marker's drawing style
|
||||||
|
virtual wxPen GetStyle() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get the marker's feet style
|
||||||
|
/// @return The marker's feet style
|
||||||
|
virtual FeetStyle GetFeet() const = 0;
|
||||||
|
|
||||||
|
/// @brief Retrieve whether this marker participates in snapping
|
||||||
|
/// @return True if this marker may snap to other snappable markers
|
||||||
|
///
|
||||||
|
/// If a marker being dragged returns true from this method, and another marker which also
|
||||||
|
/// returns true from this method is within range, the marker being dragged will be positioned
|
||||||
|
/// at the position of the other marker if it is released while it is inside snapping range.
|
||||||
|
virtual bool CanSnap() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace agi {
|
||||||
|
DEFINE_BASE_EXCEPTION(AudioControllerError, Exception);
|
||||||
|
DEFINE_SIMPLE_EXCEPTION(AudioOpenError, AudioControllerError, "audio_controller/open_failed");
|
||||||
|
};
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,5 @@
|
||||||
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
||||||
|
// Copyright (c) 2009-2010, 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
|
||||||
|
@ -45,247 +46,285 @@
|
||||||
#include <wx/window.h>
|
#include <wx/window.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libaegisub/signals.h>
|
|
||||||
|
|
||||||
#include "audio_renderer_spectrum.h"
|
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
|
|
||||||
class AudioBox;
|
#ifndef AGI_AUDIO_CONTROLLER_INCLUDED
|
||||||
|
#error You must include "audio_controller.h" before "audio_display.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class AudioRenderer;
|
||||||
|
class AudioSpectrumRenderer;
|
||||||
|
class AudioWaveformRenderer;
|
||||||
class AudioKaraoke;
|
class AudioKaraoke;
|
||||||
class AudioPlayer;
|
|
||||||
class AudioProvider;
|
class AudioProvider;
|
||||||
class AssDialogue;
|
class AudioPlayer;
|
||||||
class FrameMain;
|
|
||||||
class SubtitlesGrid;
|
class SubtitlesGrid;
|
||||||
class VideoProvider;
|
class VideoProvider;
|
||||||
|
|
||||||
/// DOCME
|
class AudioBox;
|
||||||
|
class SubtitlesGrid;
|
||||||
|
class AssDialogue;
|
||||||
|
class wxScrollBar;
|
||||||
|
|
||||||
|
// Helper classes used in implementation of the audio display
|
||||||
|
class AudioDisplayScrollbar;
|
||||||
|
class AudioDisplayTimeline;
|
||||||
|
class AudioDisplaySelection;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioDisplayInteractionObject
|
||||||
|
/// @brief Interface for objects on the audio display that can respond to mouse events
|
||||||
|
class AudioDisplayInteractionObject {
|
||||||
|
public:
|
||||||
|
/// @brief The user is interacting with the object using the mouse
|
||||||
|
/// @param event Mouse event data
|
||||||
|
/// @return True to take mouse capture, false to release mouse capture
|
||||||
|
///
|
||||||
|
/// Assuming no object has the mouse capture, the audio display uses other methods
|
||||||
|
/// in the object implementing this interface to deterine whether a mouse event
|
||||||
|
/// should go to the object. If the mouse event goes to the object, this method
|
||||||
|
/// is called.
|
||||||
|
///
|
||||||
|
/// If this method returns true, the audio display takes the mouse capture and
|
||||||
|
/// stores a pointer to the AudioDisplayInteractionObject interface for the object
|
||||||
|
/// and redirects the next mouse event to that object.
|
||||||
|
///
|
||||||
|
/// If the object that has the mouse capture returns false from this method, the
|
||||||
|
/// capture is released and regular processing is done for the next event.
|
||||||
|
///
|
||||||
|
/// If the object does not have mouse capture and returns false from this method,
|
||||||
|
/// no capture is taken or released and regular processing is done for the next
|
||||||
|
/// mouse event.
|
||||||
|
virtual bool OnMouseEvent(wxMouseEvent &event) = 0;
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
|
///
|
||||||
|
/// Empty virtual destructor for the cases that need it.
|
||||||
|
virtual ~AudioDisplayInteractionObject() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioDisplay
|
/// @class AudioDisplay
|
||||||
/// @brief DOCME
|
/// @brief Primary view/UI for interaction with audio timing
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// The audio display is the common view that allows the user to interact with the active
|
||||||
class AudioDisplay: public wxWindow, private SelectionListener<AssDialogue> {
|
/// timing controller. The audio display also renders audio according to the audio controller
|
||||||
friend class FrameMain;
|
/// and the timing controller, using an audio renderer instance.
|
||||||
|
class AudioDisplay: public wxWindow, private AudioControllerAudioEventListener, private AudioControllerTimingEventListener {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// DOCME
|
/// The audio renderer manager
|
||||||
SubtitlesGrid *grid;
|
AudioRenderer *audio_renderer;
|
||||||
|
|
||||||
/// DOCME
|
/// The renderer for audio spectrums
|
||||||
int line_n;
|
AudioSpectrumRenderer *audio_spectrum_renderer;
|
||||||
|
|
||||||
/// DOCME
|
/// The renderer for audio waveforms
|
||||||
AssDialogue *dialogue;
|
AudioWaveformRenderer *audio_waveform_renderer;
|
||||||
|
|
||||||
/// DOCME
|
/// Our current audio provider
|
||||||
AudioSpectrum *spectrumRenderer;
|
AudioProvider *provider;
|
||||||
|
|
||||||
/// DOCME
|
/// The controller managing us
|
||||||
wxBitmap *origImage;
|
AudioController *controller;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxBitmap *spectrumDisplay;
|
|
||||||
|
|
||||||
/// DOCME
|
/// Scrollbar helper object
|
||||||
wxBitmap *spectrumDisplaySelected;
|
AudioDisplayScrollbar *scrollbar;
|
||||||
|
|
||||||
/// DOCME
|
/// Timeline helper object
|
||||||
int64_t PositionSample;
|
AudioDisplayTimeline *timeline;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
float scale;
|
|
||||||
|
|
||||||
/// DOCME
|
/// Current object on display being dragged, if any
|
||||||
int samples;
|
AudioDisplayInteractionObject *dragged_object;
|
||||||
|
/// Change the dragged object and update mouse capture
|
||||||
|
void SetDraggedObject(AudioDisplayInteractionObject *new_obj);
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t Position;
|
|
||||||
|
|
||||||
/// DOCME
|
/// Leftmost pixel in the vitual audio image being displayed
|
||||||
int samplesPercent;
|
int scroll_left;
|
||||||
|
|
||||||
/// DOCME
|
/// Total width of the audio in pixels
|
||||||
int oldCurPos;
|
int pixel_audio_width;
|
||||||
|
|
||||||
/// DOCME
|
/// Horizontal zoom measured in audio samples per pixel
|
||||||
bool hasFocus;
|
int pixel_samples;
|
||||||
|
|
||||||
/// DOCME
|
/// Amplitude scaling ("vertical zoom") as a factor, 1.0 is neutral
|
||||||
bool blockUpdate;
|
float scale_amplitude;
|
||||||
|
|
||||||
/// DOCME
|
/// Top of the main audio area in pixels
|
||||||
bool dontReadTimes;
|
int audio_top;
|
||||||
|
|
||||||
/// DOCME
|
/// Height of main audio area in pixels
|
||||||
bool playingToEnd;
|
int audio_height;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool needImageUpdate;
|
|
||||||
|
|
||||||
/// DOCME
|
/// Zoom level given as a number, see SetZoomLevel for details
|
||||||
bool needImageUpdateWeak;
|
int zoom_level;
|
||||||
|
// Mouse wheel zoom accumulator
|
||||||
|
int mouse_zoom_accum;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool hasSel;
|
|
||||||
|
|
||||||
/// DOCME
|
/// Absolute pixel position of the tracking cursor (mouse or playback)
|
||||||
bool hasKaraoke;
|
int track_cursor_pos;
|
||||||
|
/// Label to show by track cursor
|
||||||
|
wxString track_cursor_label;
|
||||||
|
/// Bounding rectangle last drawn track cursor label
|
||||||
|
wxRect track_cursor_label_rect;
|
||||||
|
/// @brief Move the tracking cursor
|
||||||
|
/// @param new_pos New absolute pixel position of the tracking cursor
|
||||||
|
/// @param show_time Display timestamp by the tracking cursor?
|
||||||
|
void SetTrackCursor(int new_pos, bool show_time);
|
||||||
|
/// @brief Remove the tracking cursor from the display
|
||||||
|
void RemoveTrackCursor();
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool diagUpdated;
|
|
||||||
|
|
||||||
/// DOCME
|
/// Previous audio selection for optimising redraw when selection changes
|
||||||
bool holding;
|
AudioController::SampleRange old_selection;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool draggingScale;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t selStart;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t selEnd;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t lineStart;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t lineEnd;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t selStartCap;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t selEndCap;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int hold;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int lastX;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int lastDragX;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int curStartMS;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int curEndMS;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int holdSyl;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int *peak;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int *min;
|
|
||||||
|
|
||||||
|
/// wxWidgets paint event
|
||||||
void OnPaint(wxPaintEvent &event);
|
void OnPaint(wxPaintEvent &event);
|
||||||
|
/// wxWidgets mouse input event
|
||||||
void OnMouseEvent(wxMouseEvent &event);
|
void OnMouseEvent(wxMouseEvent &event);
|
||||||
|
/// wxWidgets control size changed event
|
||||||
void OnSize(wxSizeEvent &event);
|
void OnSize(wxSizeEvent &event);
|
||||||
void OnUpdateTimer(wxTimerEvent &event);
|
/// wxWidgets input focus changed event
|
||||||
void OnKeyDown(wxKeyEvent &event);
|
void OnFocus(wxFocusEvent &event);
|
||||||
void OnGetFocus(wxFocusEvent &event);
|
|
||||||
void OnLoseFocus(wxFocusEvent &event);
|
|
||||||
|
|
||||||
void UpdateSamples();
|
|
||||||
void Reset();
|
|
||||||
void DrawTimescale(wxDC &dc);
|
|
||||||
void DrawKeyframes(wxDC &dc);
|
|
||||||
void DrawInactiveLines(wxDC &dc);
|
|
||||||
void DrawWaveform(wxDC &dc,bool weak);
|
|
||||||
void DrawSpectrum(wxDC &dc,bool weak);
|
|
||||||
void GetDialoguePos(int64_t &start,int64_t &end,bool cap);
|
|
||||||
void GetKaraokePos(int64_t &start,int64_t &end,bool cap);
|
|
||||||
void UpdatePosition(int pos,bool IsSample=false);
|
|
||||||
|
|
||||||
int GetBoundarySnap(int x,int range,bool shiftHeld,bool start=true);
|
private:
|
||||||
void DoUpdateImage();
|
// AudioControllerAudioEventListener implementation
|
||||||
|
virtual void OnAudioOpen(AudioProvider *provider);
|
||||||
|
virtual void OnAudioClose();
|
||||||
|
virtual void OnPlaybackPosition(int64_t sample_position);
|
||||||
|
virtual void OnPlaybackStop();
|
||||||
|
|
||||||
|
// AudioControllerTimingEventListener implementation
|
||||||
|
virtual void OnMarkersMoved();
|
||||||
|
virtual void OnSelectionChanged();
|
||||||
|
virtual void OnTimingControllerChanged();
|
||||||
|
|
||||||
void OnActiveLineChanged(AssDialogue *new_line);
|
|
||||||
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
|
||||||
void OnCommit(int);
|
|
||||||
agi::signal::Connection commitListener;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// DOCME
|
AudioDisplay(wxWindow *parent, AudioController *controller);
|
||||||
AudioProvider *provider;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
AudioPlayer *player;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool NeedCommit;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool loaded;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool temporary;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int w,h;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
AudioBox *box;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
AudioKaraoke *karaoke;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxScrollBar *ScrollBar;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxTimer UpdateTimer;
|
|
||||||
|
|
||||||
AudioDisplay(wxWindow *parent, SubtitlesGrid *grid);
|
|
||||||
~AudioDisplay();
|
~AudioDisplay();
|
||||||
|
|
||||||
void UpdateImage(bool weak=false);
|
|
||||||
void Update();
|
|
||||||
void RecreateImage();
|
|
||||||
void SetPosition(int pos);
|
|
||||||
void SetSamplesPercent(int percent,bool update=true,float pivot=0.5);
|
|
||||||
void SetScale(float scale);
|
|
||||||
void UpdateScrollbar();
|
|
||||||
void SetDialogue(SubtitlesGrid *_grid=NULL,AssDialogue *diag=NULL,int n=-1);
|
|
||||||
void MakeDialogueVisible(bool force=false);
|
|
||||||
void ChangeLine(int delta, bool block=false);
|
|
||||||
void Next(bool play=true);
|
|
||||||
void Prev(bool play=true);
|
|
||||||
|
|
||||||
void CommitChanges(bool nextLine=false);
|
/// @brief Scroll the audio display
|
||||||
void AddLead(bool in,bool out);
|
/// @param pixel_amount Number of pixels to scroll the view
|
||||||
|
///
|
||||||
|
/// A positive amount moves the display to the right, making later parts of the audio visible.
|
||||||
|
void ScrollBy(int pixel_amount);
|
||||||
|
|
||||||
void SetFile(wxString file);
|
/// @brief Scroll the audio display
|
||||||
void SetFromVideo();
|
/// @param pixel_position Absolute pixel to put at left edge of the audio display
|
||||||
void Reload();
|
///
|
||||||
|
/// This is the principal scrolling function. All other scrolling functions eventually
|
||||||
|
/// call this function to perform the actual scrolling.
|
||||||
|
void ScrollPixelToLeft(int pixel_position);
|
||||||
|
|
||||||
void Play(int start,int end);
|
/// @brief Scroll the audio display
|
||||||
void Stop();
|
/// @param pixel_position Absolute pixel to put in center of the audio display
|
||||||
|
void ScrollPixelToCenter(int pixel_position);
|
||||||
|
|
||||||
int64_t GetSampleAtX(int x);
|
/// @brief Scroll the audio display
|
||||||
int GetXAtSample(int64_t n);
|
/// @param sample_position Audio sample to put at left edge of the audio display
|
||||||
int GetMSAtX(int64_t x);
|
void ScrollSampleToLeft(int64_t sample_position);
|
||||||
int GetXAtMS(int64_t ms);
|
|
||||||
int GetMSAtSample(int64_t x);
|
/// @brief Scroll the audio display
|
||||||
int64_t GetSampleAtMS(int64_t ms);
|
/// @param sample_position Audio sample to put in center of the audio display
|
||||||
int GetSyllableAtX(int x);
|
void ScrollSampleToCenter(int64_t sample_position);
|
||||||
|
|
||||||
|
/// @brief Scroll the audio display
|
||||||
|
/// @param range Range of audio samples to ensure is in view
|
||||||
|
///
|
||||||
|
/// If the entire range is already visible inside the display, nothing is scrolled. If
|
||||||
|
/// just one of the two endpoints is visible, the display is scrolled such that the
|
||||||
|
/// visible endpoint stays in view but more of the rest of the range becomes visible.
|
||||||
|
///
|
||||||
|
/// If the entire range fits inside the display, the display is centered over the range.
|
||||||
|
/// For this calculation, the display is considered smaller by some margins, see below.
|
||||||
|
///
|
||||||
|
/// If the range does not fit within the display with margins subtracted, the start of
|
||||||
|
/// the range is ensured visible and as much of the rest of the range is brought into
|
||||||
|
/// view.
|
||||||
|
///
|
||||||
|
/// For the purpose of this function, a 5 percent margin is assumed at each end of the
|
||||||
|
/// audio display such that a range endpoint that is ensured to be in view never gets
|
||||||
|
/// closer to the edge of the display than the margin. The edge that is not ensured to
|
||||||
|
/// be in view might be outside of view or might be closer to the display edge than the
|
||||||
|
/// margin.
|
||||||
|
void ScrollSampleRangeInView(const AudioController::SampleRange &range);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Change the zoom level
|
||||||
|
/// @param new_zoom_level The new zoom level to use
|
||||||
|
///
|
||||||
|
/// A zoom level of 0 is the default zoom level, all other levels are based on this.
|
||||||
|
/// Negative zoom levels zoom out, positive zoom in.
|
||||||
|
///
|
||||||
|
/// The zoom levels generally go from +30 to -30. It is possible to zoom in more than
|
||||||
|
/// +30
|
||||||
|
void SetZoomLevel(int new_zoom_level);
|
||||||
|
|
||||||
|
/// @brief Get the zoom level
|
||||||
|
/// @return The zoom level
|
||||||
|
///
|
||||||
|
/// See SetZoomLevel for a description of zoom levels.
|
||||||
|
int GetZoomLevel() const;
|
||||||
|
|
||||||
|
/// @brief Get a textual description of a zoom level
|
||||||
|
/// @param level The zoom level to describe
|
||||||
|
/// @return A translated string describing a zoom level
|
||||||
|
///
|
||||||
|
/// The zoom level description can tell the user details about how much audio is
|
||||||
|
/// actually displayed.
|
||||||
|
wxString GetZoomLevelDescription(int level) const;
|
||||||
|
|
||||||
|
/// @brief Get the zoom factor in percent for a zoom level
|
||||||
|
/// @param level The zoom level to get the factor of
|
||||||
|
/// @return The zoom factor in percent
|
||||||
|
///
|
||||||
|
/// Positive: 125, 150, 175, 200, 225, ...
|
||||||
|
///
|
||||||
|
/// Negative: 90, 80, 70, 60, 50, 45, 40, 35, 30, 25, 20, 19, 18, 17, ..., 1
|
||||||
|
///
|
||||||
|
/// Too negative numbers get clamped.
|
||||||
|
static int GetZoomLevelFactor(int level);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Set amplitude scale factor
|
||||||
|
/// @param scale New amplitude scale factor, 1.0 is no scaling
|
||||||
|
void SetAmplitudeScale(float scale);
|
||||||
|
|
||||||
|
/// @brief Get amplitude scale factor
|
||||||
|
/// @return The amplitude scaling factor
|
||||||
|
float GetAmplitudeScale() const;
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Reload all rendering settings from Options and reset caches
|
||||||
|
///
|
||||||
|
/// This can be called if some rendering quality settings have been changed in Options
|
||||||
|
/// and need to be reloaded to take effect.
|
||||||
|
void ReloadRenderingSettings();
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Get a sample index from an X coordinate relative to current scroll
|
||||||
|
int64_t SamplesFromRelativeX(int x) const { return (scroll_left + x) * pixel_samples; }
|
||||||
|
/// @brief Get a sample index from an absolute X coordinate
|
||||||
|
int64_t SamplesFromAbsoluteX(int x) const { return x * pixel_samples; }
|
||||||
|
/// @brief Get an X coordinate relative to the current scroll from a sample index
|
||||||
|
int RelativeXFromSamples(int64_t samples) const { return samples/pixel_samples - scroll_left; }
|
||||||
|
/// @brief Get an absolute X coordinate from a sample index
|
||||||
|
int AbsoluteXFromSamples(int64_t samples) const { return samples/pixel_samples; }
|
||||||
|
|
||||||
void GetTimesDialogue(int &start,int &end);
|
|
||||||
void GetTimesSelection(int &start,int &end);
|
|
||||||
void SetSelection(int start, int end);
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
///////
|
|
||||||
// IDs
|
|
||||||
enum {
|
|
||||||
Audio_Update_Timer = 1700
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2005, 2006, 2007, Rodrigo Braz Monteiro, Niels Martin Hansen
|
// Copyright (c) 2005-2009, 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
|
||||||
|
@ -48,6 +48,8 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
#include "audio_display.h"
|
||||||
#include "audio_karaoke.h"
|
#include "audio_karaoke.h"
|
||||||
|
@ -634,7 +636,7 @@ void AudioKaraoke::Join() {
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
must_rebuild = true;
|
must_rebuild = true;
|
||||||
display->NeedCommit = true;
|
//display->NeedCommit = true;
|
||||||
display->Update();
|
display->Update();
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
|
|
||||||
|
@ -678,7 +680,7 @@ void AudioKaraoke::EndSplit(bool commit) {
|
||||||
if (hasSplit) {
|
if (hasSplit) {
|
||||||
LOG_D("karaoke/audio") << "hassplit";
|
LOG_D("karaoke/audio") << "hassplit";
|
||||||
must_rebuild = true;
|
must_rebuild = true;
|
||||||
display->NeedCommit = true;
|
//display->NeedCommit = true;
|
||||||
SetSelection(first_sel);
|
SetSelection(first_sel);
|
||||||
display->Update();
|
display->Update();
|
||||||
}
|
}
|
||||||
|
@ -879,8 +881,9 @@ void AudioKaraokeTagMenu::OnSelectItem(wxCommandEvent &event) {
|
||||||
// Update display
|
// Update display
|
||||||
kara->must_rebuild = true;
|
kara->must_rebuild = true;
|
||||||
//kara->Commit();
|
//kara->Commit();
|
||||||
kara->display->NeedCommit = true;
|
//kara->display->NeedCommit = true;
|
||||||
kara->display->CommitChanges();
|
/// @todo Commit changes and stay on current line
|
||||||
|
//kara->display->CommitChanges();
|
||||||
//kara->display->Update();
|
//kara->display->Update();
|
||||||
kara->SetSelection(firstsel, lastsel);
|
kara->SetSelection(firstsel, lastsel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_player_alsa.h"
|
#include "audio_player_alsa.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_player_dsound.h"
|
#include "audio_player_dsound.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -49,9 +49,10 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_player_dsound2.h"
|
#include "audio_player_dsound2.h"
|
||||||
#include "frame_main.h"
|
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_player_openal.h"
|
#include "audio_player_openal.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_player_oss.h"
|
#include "audio_player_oss.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
|
@ -65,77 +65,6 @@ AudioProvider::~AudioProvider() {
|
||||||
delete[] raw;
|
delete[] raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get waveform
|
|
||||||
/// @param min
|
|
||||||
/// @param peak
|
|
||||||
/// @param start
|
|
||||||
/// @param w
|
|
||||||
/// @param h
|
|
||||||
/// @param samples
|
|
||||||
/// @param scale
|
|
||||||
///
|
|
||||||
void AudioProvider::GetWaveForm(int *min,int *peak,int64_t start,int w,int h,int samples,float scale) {
|
|
||||||
// Setup
|
|
||||||
int channels = GetChannels();
|
|
||||||
int n = w * samples;
|
|
||||||
for (int i=0;i<w;i++) {
|
|
||||||
peak[i] = 0;
|
|
||||||
min[i] = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare waveform
|
|
||||||
int cur;
|
|
||||||
int curvalue;
|
|
||||||
|
|
||||||
// Prepare buffers
|
|
||||||
int needLen = n*channels*bytes_per_sample;
|
|
||||||
if (raw) {
|
|
||||||
if (raw_len < needLen) {
|
|
||||||
delete[] raw;
|
|
||||||
raw = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!raw) {
|
|
||||||
raw_len = needLen;
|
|
||||||
raw = new char[raw_len];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_per_sample == 1) {
|
|
||||||
// Read raw samples
|
|
||||||
unsigned char *raw_char = (unsigned char*) raw;
|
|
||||||
GetAudio(raw,start,n);
|
|
||||||
int amplitude = int(h*scale);
|
|
||||||
|
|
||||||
// Calculate waveform
|
|
||||||
for (int i=0;i<n;i++) {
|
|
||||||
cur = i/samples;
|
|
||||||
curvalue = h - (int(raw_char[i*channels])*amplitude)/0xFF;
|
|
||||||
if (curvalue > h) curvalue = h;
|
|
||||||
if (curvalue < 0) curvalue = 0;
|
|
||||||
if (curvalue < min[cur]) min[cur] = curvalue;
|
|
||||||
if (curvalue > peak[cur]) peak[cur] = curvalue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_per_sample == 2) {
|
|
||||||
// Read raw samples
|
|
||||||
short *raw_short = (short*) raw;
|
|
||||||
GetAudio(raw,start,n);
|
|
||||||
int half_h = h/2;
|
|
||||||
int half_amplitude = int(half_h * scale);
|
|
||||||
|
|
||||||
// Calculate waveform
|
|
||||||
for (int i=0;i<n;i++) {
|
|
||||||
cur = i/samples;
|
|
||||||
curvalue = half_h - (int(raw_short[i*channels])*half_amplitude)/0x8000;
|
|
||||||
if (curvalue > h) curvalue = h;
|
|
||||||
if (curvalue < 0) curvalue = 0;
|
|
||||||
if (curvalue < min[cur]) min[cur] = curvalue;
|
|
||||||
if (curvalue > peak[cur]) peak[cur] = curvalue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Get audio with volume
|
/// @brief Get audio with volume
|
||||||
/// @param buf
|
/// @param buf
|
||||||
/// @param start
|
/// @param start
|
||||||
|
@ -143,7 +72,7 @@ void AudioProvider::GetWaveForm(int *min,int *peak,int64_t start,int w,int h,int
|
||||||
/// @param volume
|
/// @param volume
|
||||||
/// @return
|
/// @return
|
||||||
///
|
///
|
||||||
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) {
|
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const {
|
||||||
try {
|
try {
|
||||||
GetAudio(buf,start,count);
|
GetAudio(buf,start,count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) {
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void AvisynthAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) {
|
void AvisynthAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
// Requested beyond the length of audio
|
// Requested beyond the length of audio
|
||||||
if (start+count > num_samples) {
|
if (start+count > num_samples) {
|
||||||
int64_t oldcount = count;
|
int64_t oldcount = count;
|
||||||
|
|
|
@ -57,15 +57,12 @@ class AvisynthAudioProvider : public AudioProvider, public AviSynthWrapper {
|
||||||
public:
|
public:
|
||||||
AvisynthAudioProvider(wxString _filename);
|
AvisynthAudioProvider(wxString _filename);
|
||||||
|
|
||||||
wxString GetFilename() { return filename; }
|
wxString GetFilename() const { return filename; }
|
||||||
|
|
||||||
/// @brief Only exists for x86 Windows, always delivers machine (little) endian
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
bool AreSamplesNativeEndian() const { return true; }
|
bool AreSamplesNativeEndian() const { return true; }
|
||||||
bool NeedsCache() const { return true; }
|
bool NeedsCache() const { return true; }
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
void GetWaveForm(int *min,int *peak,int64_t start,int w,int h,int samples,float scale);
|
void GetWaveForm(int *min,int *peak,int64_t start,int w,int h,int samples,float scale);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -62,7 +62,7 @@ ConvertAudioProvider::ConvertAudioProvider(AudioProvider *src) : source(src) {
|
||||||
/// @param dst
|
/// @param dst
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void ConvertAudioProvider::Make16Bit(const char *src, short *dst, int64_t count) {
|
void ConvertAudioProvider::Make16Bit(const char *src, short *dst, int64_t count) const {
|
||||||
for (int64_t i=0;i<count;i++) {
|
for (int64_t i=0;i<count;i++) {
|
||||||
dst[i] = (short(src[i])-128)*255;
|
dst[i] = (short(src[i])-128)*255;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ template<class SampleConverter>
|
||||||
/// @param count
|
/// @param count
|
||||||
/// @param converter
|
/// @param converter
|
||||||
///
|
///
|
||||||
void ConvertAudioProvider::ChangeSampleRate(const short *src, short *dst, int64_t count, const SampleConverter &converter) {
|
void ConvertAudioProvider::ChangeSampleRate(const short *src, short *dst, int64_t count, const SampleConverter &converter) const {
|
||||||
// Upsample by 2
|
// Upsample by 2
|
||||||
if (sampleMult == 2) {
|
if (sampleMult == 2) {
|
||||||
int64_t size = count/2;
|
int64_t size = count/2;
|
||||||
|
@ -139,7 +139,7 @@ struct EndianSwapSampleConverter {
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void ConvertAudioProvider::GetAudio(void *destination, int64_t start, int64_t count) {
|
void ConvertAudioProvider::GetAudio(void *destination, int64_t start, int64_t count) const {
|
||||||
// Bits per sample
|
// Bits per sample
|
||||||
int srcBps = source->GetBytesPerSample();
|
int srcBps = source->GetBytesPerSample();
|
||||||
|
|
||||||
|
|
|
@ -51,9 +51,9 @@ class ConvertAudioProvider : public AudioProvider {
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
std::tr1::shared_ptr<AudioProvider> source;
|
std::tr1::shared_ptr<AudioProvider> source;
|
||||||
void Make16Bit(const char *src, short *dst, int64_t count);
|
void Make16Bit(const char *src, short *dst, int64_t count) const;
|
||||||
template<class SampleConverter>
|
template<class SampleConverter>
|
||||||
void ChangeSampleRate(const short *src, short *dst, int64_t count, const SampleConverter &converter);
|
void ChangeSampleRate(const short *src, short *dst, int64_t count, const SampleConverter &converter) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConvertAudioProvider(AudioProvider *source);
|
ConvertAudioProvider(AudioProvider *source);
|
||||||
|
@ -62,9 +62,9 @@ public:
|
||||||
/// That's one of the points of it!
|
/// That's one of the points of it!
|
||||||
bool AreSamplesNativeEndian() const { return true; }
|
bool AreSamplesNativeEndian() const { return true; }
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
|
|
||||||
wxString GetFilename() { return source->GetFilename(); }
|
wxString GetFilename() const { return source->GetFilename(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider);
|
AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider);
|
||||||
|
|
|
@ -64,7 +64,7 @@ DownmixingAudioProvider::DownmixingAudioProvider(AudioProvider *source) : provid
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void DownmixingAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) {
|
void DownmixingAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
if (count == 0) return;
|
if (count == 0) return;
|
||||||
|
|
||||||
// We can do this ourselves
|
// We can do this ourselves
|
||||||
|
|
|
@ -57,5 +57,5 @@ public:
|
||||||
///
|
///
|
||||||
bool AreSamplesNativeEndian() const { return true; }
|
bool AreSamplesNativeEndian() const { return true; }
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,7 @@ DummyAudioProvider::~DummyAudioProvider() {
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void DummyAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) {
|
void DummyAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
short *workbuf = (short*)buf;
|
short *workbuf = (short*)buf;
|
||||||
|
|
||||||
if (noise) {
|
if (noise) {
|
||||||
|
|
|
@ -50,5 +50,5 @@ public:
|
||||||
~DummyAudioProvider();
|
~DummyAudioProvider();
|
||||||
|
|
||||||
bool AreSamplesNativeEndian() const { return true; }
|
bool AreSamplesNativeEndian() const { return true; }
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -228,7 +228,7 @@ void FFmpegSourceAudioProvider::Close() {
|
||||||
/// @param Start
|
/// @param Start
|
||||||
/// @param Count
|
/// @param Count
|
||||||
///
|
///
|
||||||
void FFmpegSourceAudioProvider::GetAudio(void *Buf, int64_t Start, int64_t Count) {
|
void FFmpegSourceAudioProvider::GetAudio(void *Buf, int64_t Start, int64_t Count) const {
|
||||||
uint8_t *Buf2 = static_cast<uint8_t*>(Buf);
|
uint8_t *Buf2 = static_cast<uint8_t*>(Buf);
|
||||||
Start -= delay;
|
Start -= delay;
|
||||||
if (Start < 0) {
|
if (Start < 0) {
|
||||||
|
|
|
@ -46,8 +46,8 @@ private:
|
||||||
FFMS_AudioSource *AudioSource; ///< audio source object
|
FFMS_AudioSource *AudioSource; ///< audio source object
|
||||||
bool COMInited; ///< COM initialization state
|
bool COMInited; ///< COM initialization state
|
||||||
|
|
||||||
char FFMSErrMsg[1024]; ///< FFMS error message
|
mutable char FFMSErrMsg[1024]; ///< FFMS error message
|
||||||
FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
|
mutable FFMS_ErrorInfo ErrInfo; ///< FFMS error codes/messages
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
void LoadAudio(wxString filename);
|
void LoadAudio(wxString filename);
|
||||||
|
@ -65,6 +65,6 @@ public:
|
||||||
bool AreSamplesNativeEndian() const { return true; }
|
bool AreSamplesNativeEndian() const { return true; }
|
||||||
bool NeedsCache() const { return true; }
|
bool NeedsCache() const { return true; }
|
||||||
|
|
||||||
virtual void GetAudio(void *buf, int64_t start, int64_t count);
|
virtual void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_provider_hd.h"
|
#include "audio_provider_hd.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "dialog_progress.h"
|
#include "dialog_progress.h"
|
||||||
|
@ -114,7 +115,7 @@ HDAudioProvider::~HDAudioProvider() {
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void HDAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) {
|
void HDAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
// Requested beyond the length of audio
|
// Requested beyond the length of audio
|
||||||
if (start+count > num_samples) {
|
if (start+count > num_samples) {
|
||||||
int64_t oldcount = count;
|
int64_t oldcount = count;
|
||||||
|
|
|
@ -48,10 +48,10 @@
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class HDAudioProvider : public AudioProvider {
|
class HDAudioProvider : public AudioProvider {
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxMutex diskmutex;
|
mutable wxMutex diskmutex;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxFile file_cache;
|
mutable wxFile file_cache;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxString diskCacheFilename;
|
wxString diskCacheFilename;
|
||||||
|
@ -71,5 +71,5 @@ public:
|
||||||
|
|
||||||
bool AreSamplesNativeEndian() const { return samples_native_endian; }
|
bool AreSamplesNativeEndian() const { return samples_native_endian; }
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -144,7 +144,7 @@ PCMAudioProvider::~PCMAudioProvider()
|
||||||
/// @param range_length
|
/// @param range_length
|
||||||
/// @return
|
/// @return
|
||||||
///
|
///
|
||||||
char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t range_length)
|
char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t range_length) const
|
||||||
{
|
{
|
||||||
if (range_start + range_length > file_size) {
|
if (range_start + range_length > file_size) {
|
||||||
throw AudioDecodeError("Attempted to map beyond end of file");
|
throw AudioDecodeError("Attempted to map beyond end of file");
|
||||||
|
@ -217,13 +217,13 @@ char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t rang
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void PCMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count)
|
void PCMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const
|
||||||
{
|
{
|
||||||
// Read blocks from the file
|
// Read blocks from the file
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
while (count > 0 && index < index_points.size()) {
|
while (count > 0 && index < index_points.size()) {
|
||||||
// Check if this index contains the samples we're looking for
|
// Check if this index contains the samples we're looking for
|
||||||
IndexPoint &ip = index_points[index];
|
const IndexPoint &ip = index_points[index];
|
||||||
if (ip.start_sample <= start && ip.start_sample+ip.num_samples > start) {
|
if (ip.start_sample <= start && ip.start_sample+ip.num_samples > start) {
|
||||||
|
|
||||||
// How many samples we can maximum take from this block
|
// How many samples we can maximum take from this block
|
||||||
|
|
|
@ -64,24 +64,24 @@ private:
|
||||||
HANDLE file_mapping;
|
HANDLE file_mapping;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
void *current_mapping;
|
mutable void *current_mapping;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int64_t mapping_start;
|
mutable int64_t mapping_start;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
size_t mapping_length;
|
mutable size_t mapping_length;
|
||||||
#else
|
#else
|
||||||
int file_handle;
|
int file_handle;
|
||||||
void *current_mapping;
|
mutable void *current_mapping;
|
||||||
off_t mapping_start;
|
mutable off_t mapping_start;
|
||||||
size_t mapping_length;
|
mutable size_t mapping_length;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PCMAudioProvider(const wxString &filename); // Create base object and open the file mapping
|
PCMAudioProvider(const wxString &filename); // Create base object and open the file mapping
|
||||||
virtual ~PCMAudioProvider(); // Closes the file mapping
|
virtual ~PCMAudioProvider(); // Closes the file mapping
|
||||||
char * EnsureRangeAccessible(int64_t range_start, int64_t range_length); // Ensure that the given range of bytes are accessible in the file mapping and return a pointer to the first byte of the requested range
|
char * EnsureRangeAccessible(int64_t range_start, int64_t range_length) const; // Ensure that the given range of bytes are accessible in the file mapping and return a pointer to the first byte of the requested range
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
@ -108,7 +108,7 @@ protected:
|
||||||
IndexVector index_points;
|
IndexVector index_points;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void GetAudio(void *buf, int64_t start, int64_t count);
|
virtual void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Construct the right PCM audio provider (if any) for the file
|
// Construct the right PCM audio provider (if any) for the file
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_provider_ram.h"
|
#include "audio_provider_ram.h"
|
||||||
#include "dialog_progress.h"
|
#include "dialog_progress.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
@ -131,7 +132,7 @@ void RAMAudioProvider::Clear() {
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param count
|
/// @param count
|
||||||
///
|
///
|
||||||
void RAMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) {
|
void RAMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
// Requested beyond the length of audio
|
// Requested beyond the length of audio
|
||||||
if (start+count > num_samples) {
|
if (start+count > num_samples) {
|
||||||
int64_t oldcount = count;
|
int64_t oldcount = count;
|
||||||
|
|
|
@ -58,5 +58,5 @@ public:
|
||||||
~RAMAudioProvider();
|
~RAMAudioProvider();
|
||||||
|
|
||||||
bool AreSamplesNativeEndian() const { return samples_native_endian; }
|
bool AreSamplesNativeEndian() const { return samples_native_endian; }
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count);
|
void GetAudio(void *buf, int64_t start, int64_t count) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2009, Niels Martin Hansen
|
// Copyright (c) 2009-2010, 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,9 +42,13 @@
|
||||||
#include <wx/dcmemory.h>
|
#include <wx/dcmemory.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "block_cache.h"
|
||||||
#include "audio_renderer.h"
|
#include "audio_renderer.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
|
||||||
AudioRendererBitmapCacheBitmapFactory::AudioRendererBitmapCacheBitmapFactory(AudioRenderer *_renderer)
|
AudioRendererBitmapCacheBitmapFactory::AudioRendererBitmapCacheBitmapFactory(AudioRenderer *_renderer)
|
||||||
{
|
{
|
||||||
|
@ -56,7 +60,7 @@ AudioRendererBitmapCacheBitmapFactory::AudioRendererBitmapCacheBitmapFactory(Aud
|
||||||
wxBitmap *AudioRendererBitmapCacheBitmapFactory::ProduceBlock(int i)
|
wxBitmap *AudioRendererBitmapCacheBitmapFactory::ProduceBlock(int i)
|
||||||
{
|
{
|
||||||
(void)i;
|
(void)i;
|
||||||
return new wxBitmap(renderer->cache_bitmap_width, renderer->pixel_height, 32);
|
return new wxBitmap(renderer->cache_bitmap_width, renderer->pixel_height, 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,7 +72,7 @@ void AudioRendererBitmapCacheBitmapFactory::DisposeBlock(wxBitmap *bmp)
|
||||||
|
|
||||||
size_t AudioRendererBitmapCacheBitmapFactory::GetBlockSize() const
|
size_t AudioRendererBitmapCacheBitmapFactory::GetBlockSize() const
|
||||||
{
|
{
|
||||||
return sizeof(wxBitmap) + renderer->cache_bitmap_width * renderer->pixel_height * 4;
|
return sizeof(wxBitmap) + renderer->cache_bitmap_width * renderer->pixel_height * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +82,8 @@ AudioRenderer::AudioRenderer()
|
||||||
: cache_bitmap_width(32) // arbitrary value for now
|
: cache_bitmap_width(32) // arbitrary value for now
|
||||||
, bitmaps_normal(256, AudioRendererBitmapCacheBitmapFactory(this))
|
, bitmaps_normal(256, AudioRendererBitmapCacheBitmapFactory(this))
|
||||||
, bitmaps_selected(256, AudioRendererBitmapCacheBitmapFactory(this))
|
, bitmaps_selected(256, AudioRendererBitmapCacheBitmapFactory(this))
|
||||||
, cache_maxsize(0)
|
, cache_bitmap_maxsize(0)
|
||||||
|
, cache_renderer_maxsize(0)
|
||||||
, renderer(0)
|
, renderer(0)
|
||||||
, provider(0)
|
, provider(0)
|
||||||
{
|
{
|
||||||
|
@ -166,7 +171,12 @@ void AudioRenderer::SetAudioProvider(AudioProvider *_provider)
|
||||||
|
|
||||||
void AudioRenderer::SetCacheMaxSize(size_t max_size)
|
void AudioRenderer::SetCacheMaxSize(size_t max_size)
|
||||||
{
|
{
|
||||||
cache_maxsize = max_size;
|
// Limit the bitmap cache sizes to 16 MB hard, to avoid the risk of exhausting
|
||||||
|
// system bitmap object resources and similar. Experimenting shows that 16 MB
|
||||||
|
// bitmap cache should be plenty even if working with a one hour audio clip.
|
||||||
|
cache_bitmap_maxsize = std::min(max_size/8, (size_t)0x1000000);
|
||||||
|
// The renderer gets whatever is left.
|
||||||
|
cache_renderer_maxsize = max_size - 2*cache_bitmap_maxsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,9 +184,10 @@ void AudioRenderer::ResetBlockCount()
|
||||||
{
|
{
|
||||||
if (provider)
|
if (provider)
|
||||||
{
|
{
|
||||||
size_t num_bitmaps = (size_t)((provider->GetNumSamples() + pixel_samples - 1) / pixel_samples);
|
size_t rendered_width = (size_t)((provider->GetNumSamples() + pixel_samples - 1) / pixel_samples);
|
||||||
bitmaps_normal.SetBlockCount(num_bitmaps);
|
cache_numblocks = rendered_width / cache_bitmap_width;
|
||||||
bitmaps_selected.SetBlockCount(num_bitmaps);
|
bitmaps_normal.SetBlockCount(cache_numblocks);
|
||||||
|
bitmaps_selected.SetBlockCount(cache_numblocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,16 +215,16 @@ wxBitmap AudioRenderer::GetCachedBitmap(int i, bool selected)
|
||||||
|
|
||||||
void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool selected)
|
void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool selected)
|
||||||
{
|
{
|
||||||
assert(start >= 0);
|
|
||||||
assert(length >= 0);
|
|
||||||
|
|
||||||
assert(start >= 0);
|
assert(start >= 0);
|
||||||
|
|
||||||
if (!provider) return;
|
if (!provider) return;
|
||||||
if (!renderer) return;
|
if (!renderer) return;
|
||||||
|
if (length <= 0) return;
|
||||||
|
|
||||||
// Last absolute pixel strip to render
|
// One past last absolute pixel strip to render
|
||||||
int end = start + length - 1;
|
int end = start + length;
|
||||||
|
// One past last X coordinate to render on
|
||||||
|
int lastx = origin.x + length;
|
||||||
// Figure out which range of bitmaps are required
|
// Figure out which range of bitmaps are required
|
||||||
int firstbitmap = start / cache_bitmap_width;
|
int firstbitmap = start / cache_bitmap_width;
|
||||||
// And the offset in it to start its use at
|
// And the offset in it to start its use at
|
||||||
|
@ -223,20 +234,36 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
|
||||||
// How many columns of the last bitmap to use
|
// How many columns of the last bitmap to use
|
||||||
int lastbitmapoffset = end % cache_bitmap_width;
|
int lastbitmapoffset = end % cache_bitmap_width;
|
||||||
|
|
||||||
// Two basic cases now: Either firstbitmap is the same as lastbitmap, or they're different.
|
// Check if we need to render any blank audio past the last bitmap from cache,
|
||||||
|
// this happens if we're asked to render more audio than the provider has.
|
||||||
|
if (lastbitmap >= (int)cache_numblocks)
|
||||||
|
{
|
||||||
|
lastbitmap = cache_numblocks - 1;
|
||||||
|
lastbitmapoffset = cache_bitmap_width;
|
||||||
|
|
||||||
|
if (firstbitmap > lastbitmap)
|
||||||
|
firstbitmap = lastbitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Three basic cases now:
|
||||||
|
// * Either we're just rendering blank audio,
|
||||||
|
// * Or there is exactly one bitmap to render,
|
||||||
|
// * Or there is more than one bitmap to render.
|
||||||
|
|
||||||
// origin is passed by value because we'll be using it as a local var to keep track
|
// origin is passed by value because we'll be using it as a local var to keep track
|
||||||
// of rendering progress!
|
// of rendering progress!
|
||||||
|
|
||||||
if (firstbitmap == lastbitmap)
|
if (start / cache_bitmap_width >= (int)cache_numblocks)
|
||||||
{
|
{
|
||||||
// These better be the same: The first to the last column of the single bitmap
|
// Do nothing, the blank audio rendering will happen later
|
||||||
// to use should equal the length of the area to render.
|
}
|
||||||
assert(lastbitmapoffset - firstbitmapoffset == length);
|
else if (firstbitmap == lastbitmap)
|
||||||
|
{
|
||||||
|
const int renderwidth = lastbitmapoffset - firstbitmapoffset;
|
||||||
wxBitmap bmp = GetCachedBitmap(firstbitmap, selected);
|
wxBitmap bmp = GetCachedBitmap(firstbitmap, selected);
|
||||||
wxMemoryDC bmpdc(bmp);
|
wxMemoryDC bmpdc(bmp);
|
||||||
dc.Blit(origin, wxSize(length, pixel_height), &bmpdc, wxPoint(firstbitmapoffset, 0));
|
dc.Blit(origin, wxSize(renderwidth, pixel_height), &bmpdc, wxPoint(firstbitmapoffset, 0));
|
||||||
|
origin.x += renderwidth;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -244,32 +271,40 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
|
||||||
|
|
||||||
{
|
{
|
||||||
bmp = GetCachedBitmap(firstbitmap, selected);
|
bmp = GetCachedBitmap(firstbitmap, selected);
|
||||||
|
// Can't use dc.DrawBitmap here because we need to clip the bitmap
|
||||||
wxMemoryDC bmpdc(bmp);
|
wxMemoryDC bmpdc(bmp);
|
||||||
dc.Blit(origin, wxSize(cache_bitmap_width-firstbitmapoffset, pixel_height),
|
dc.Blit(origin, wxSize(cache_bitmap_width-firstbitmapoffset, pixel_height),
|
||||||
&bmpdc, wxPoint(firstbitmapoffset, 0));
|
&bmpdc, wxPoint(firstbitmapoffset, 0));
|
||||||
origin.x += cache_bitmap_width-firstbitmapoffset;
|
origin.x += cache_bitmap_width-firstbitmapoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < lastbitmap; ++i)
|
for (int i = firstbitmap+1; i < lastbitmap; ++i)
|
||||||
{
|
{
|
||||||
bmp = GetCachedBitmap(i, selected);
|
bmp = GetCachedBitmap(i, selected);
|
||||||
wxMemoryDC bmpdc(bmp);
|
dc.DrawBitmap(bmp, origin);
|
||||||
dc.Blit(origin, wxSize(cache_bitmap_width, pixel_height), &bmpdc, wxPoint(0, 0));
|
|
||||||
origin.x += cache_bitmap_width;
|
origin.x += cache_bitmap_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
bmp = GetCachedBitmap(lastbitmap, selected);
|
bmp = GetCachedBitmap(lastbitmap, selected);
|
||||||
|
// We also need clipping here
|
||||||
wxMemoryDC bmpdc(bmp);
|
wxMemoryDC bmpdc(bmp);
|
||||||
dc.Blit(origin, wxSize(lastbitmapoffset, pixel_height), &bmpdc, wxPoint(0, 0));
|
dc.Blit(origin, wxSize(lastbitmapoffset+1, pixel_height), &bmpdc, wxPoint(0, 0));
|
||||||
|
origin.x += lastbitmapoffset+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now render blank audio from origin to end
|
||||||
|
if (origin.x < lastx)
|
||||||
|
{
|
||||||
|
renderer->RenderBlank(dc, wxRect(origin.x-1, origin.y, lastx-origin.x+1, pixel_height), selected);
|
||||||
|
}
|
||||||
|
|
||||||
if (selected)
|
if (selected)
|
||||||
bitmaps_selected.Age(cache_maxsize / 8);
|
bitmaps_selected.Age(cache_bitmap_maxsize);
|
||||||
else
|
else
|
||||||
bitmaps_normal.Age(cache_maxsize / 8);
|
bitmaps_normal.Age(cache_bitmap_maxsize);
|
||||||
renderer->AgeCache(3 * cache_maxsize / 4);
|
renderer->AgeCache(cache_renderer_maxsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2009, Niels Martin Hansen
|
// Copyright (c) 2009-2010, 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
|
||||||
|
@ -43,8 +43,6 @@
|
||||||
#include <wx/gdicmn.h>
|
#include <wx/gdicmn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "block_cache.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Some forward declarations for outside stuff
|
// Some forward declarations for outside stuff
|
||||||
class AudioProvider;
|
class AudioProvider;
|
||||||
|
@ -54,6 +52,11 @@ class AudioRendererBitmapProvider;
|
||||||
class AudioRenderer;
|
class AudioRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AGI_BLOCK_CACHE_INCLUDED
|
||||||
|
#error You much include "block_cache.h" before "audio_renderer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioRendererBitmapCacheBitmapFactory
|
/// @class AudioRendererBitmapCacheBitmapFactory
|
||||||
/// @brief Produces wxBitmap objects for DataBlockCache storage for the audio renderer
|
/// @brief Produces wxBitmap objects for DataBlockCache storage for the audio renderer
|
||||||
|
@ -111,8 +114,12 @@ class AudioRenderer {
|
||||||
AudioRendererBitmapCache bitmaps_normal;
|
AudioRendererBitmapCache bitmaps_normal;
|
||||||
/// Cached bitmaps for marked (selected) audio ranges
|
/// Cached bitmaps for marked (selected) audio ranges
|
||||||
AudioRendererBitmapCache bitmaps_selected;
|
AudioRendererBitmapCache bitmaps_selected;
|
||||||
/// The maximum allowed size of the cache, in bytes
|
/// Number of blocks in the bitmap caches
|
||||||
size_t cache_maxsize;
|
size_t cache_numblocks;
|
||||||
|
/// The maximum allowed size of each bitmap cache, in bytes
|
||||||
|
size_t cache_bitmap_maxsize;
|
||||||
|
/// The maximum allowed size of the renderer's cache, in bytes
|
||||||
|
size_t cache_renderer_maxsize;
|
||||||
|
|
||||||
/// Actual renderer for bitmaps
|
/// Actual renderer for bitmaps
|
||||||
AudioRendererBitmapProvider *renderer;
|
AudioRendererBitmapProvider *renderer;
|
||||||
|
@ -284,7 +291,7 @@ public:
|
||||||
AudioRendererBitmapProvider() : provider(0), pixel_samples(0) { };
|
AudioRendererBitmapProvider() : provider(0), pixel_samples(0) { };
|
||||||
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~AudioRendererBitmapProvider() { }
|
virtual ~AudioRendererBitmapProvider() { }
|
||||||
|
|
||||||
/// @brief Rendering function
|
/// @brief Rendering function
|
||||||
/// @param bmp Bitmap to render to
|
/// @param bmp Bitmap to render to
|
||||||
|
@ -295,6 +302,15 @@ public:
|
||||||
/// the width and height to render.
|
/// the width and height to render.
|
||||||
virtual void Render(wxBitmap &bmp, int start, bool selected) = 0;
|
virtual void Render(wxBitmap &bmp, int start, bool selected) = 0;
|
||||||
|
|
||||||
|
/// @brief Blank audio rendering function
|
||||||
|
/// @param dc The device context to render to
|
||||||
|
/// @param rect The rectangle to fill with the image of blank audio
|
||||||
|
/// @param selected Whether to render as being selected or not
|
||||||
|
///
|
||||||
|
/// Deriving classes must implement this method. The rectangle has the height
|
||||||
|
/// of the entire canvas the audio is being rendered in.
|
||||||
|
virtual void RenderBlank(wxDC &dc, const wxRect &rect, bool selected) = 0;
|
||||||
|
|
||||||
/// @brief Change audio provider
|
/// @brief Change audio provider
|
||||||
/// @param provider Audio provider to change to
|
/// @param provider Audio provider to change to
|
||||||
void SetProvider(AudioProvider *provider);
|
void SetProvider(AudioProvider *provider);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,4 @@
|
||||||
// Copyright (c) 2005, 2006, Rodrigo Braz Monteiro
|
// Copyright (c) 2009, Niels Martin Hansen
|
||||||
// Copyright (c) 2006, 2007, 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
|
||||||
|
@ -40,65 +39,102 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class AudioProvider;
|
#ifdef WITH_FFTW
|
||||||
|
#include <fftw3.h>
|
||||||
// Specified and implemented in cpp file, interface is private to spectrum code
|
#endif
|
||||||
class AudioSpectrumCacheManager;
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioSpectrum
|
|
||||||
|
// Specified and implemented in cpp file, to avoid pulling in too much
|
||||||
|
// complex template code in this header.
|
||||||
|
class AudioSpectrumCache;
|
||||||
|
struct AudioSpectrumCacheBlockFactory;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioSpectrumRenderer
|
||||||
/// @brief Render frequency-power spectrum graphs for audio data.
|
/// @brief Render frequency-power spectrum graphs for audio data.
|
||||||
///
|
///
|
||||||
/// Renders frequency-power spectrum graphs of PCM audio data using a fast fourier transform
|
/// Renders frequency-power spectrum graphs of PCM audio data using a derivation function
|
||||||
/// to derive the data. The frequency-power data are cached to avoid re-computing them
|
/// such as the fast fourier transform.
|
||||||
/// frequently, and the cache size is limited by a configuration setting.
|
class AudioSpectrumRenderer : public AudioRendererBitmapProvider {
|
||||||
///
|
friend struct AudioSpectrumCacheBlockFactory;
|
||||||
/// The spectrum image is rendered to a 32 bit RGB bitmap. Power data is scaled linearly
|
|
||||||
/// and not logarithmically, since the rendering is done with limited precision, but
|
|
||||||
/// an amplification factor can be specified to see different ranges.
|
|
||||||
class AudioSpectrum {
|
|
||||||
private:
|
|
||||||
|
|
||||||
/// Internal cache management for the spectrum
|
/// Internal cache management for the spectrum
|
||||||
AudioSpectrumCacheManager *cache;
|
AudioSpectrumCache *cache;
|
||||||
|
|
||||||
/// Colour table used for regular rendering
|
/// Colour table used for regular rendering
|
||||||
unsigned char colours_normal[256*3];
|
AudioColorScheme colors_normal;
|
||||||
|
|
||||||
/// Colour table used for rendering the audio selection
|
/// Colour table used for rendering the audio selection
|
||||||
unsigned char colours_selected[256*3];
|
AudioColorScheme colors_selected;
|
||||||
|
|
||||||
/// The audio provider to use as source
|
/// Binary logarithm of number of samples to use in deriving frequency-power data
|
||||||
AudioProvider *provider;
|
size_t derivation_size;
|
||||||
|
|
||||||
unsigned long line_length; ///< Number of frequency components per line (half of number of samples)
|
/// Binary logarithm of number of samples between the start of derivations
|
||||||
unsigned long num_lines; ///< Number of lines needed for the audio
|
size_t derivation_dist;
|
||||||
unsigned int fft_overlaps; ///< Number of overlaps used in FFT
|
|
||||||
float power_scale; ///< Amplification of displayed power
|
/// @brief Reset in response to changing audio provider
|
||||||
int minband; ///< Smallest frequency band displayed
|
///
|
||||||
int maxband; ///< Largest frequency band displayed
|
/// Overrides the OnSetProvider event handler in the base class, to reset things
|
||||||
|
/// when the audio provider is changed.
|
||||||
|
void OnSetProvider();
|
||||||
|
|
||||||
|
/// @brief Recreates the cache
|
||||||
|
///
|
||||||
|
/// To be called when the number of blocks in cache might have changed,
|
||||||
|
// eg. new audio provider or new resolution.
|
||||||
|
void RecreateCache();
|
||||||
|
|
||||||
|
/// @brief Fill a block with frequency-power data for a time range
|
||||||
|
/// @param block_index Index of the block to fill data for
|
||||||
|
/// @param[out] block Address to write the data to
|
||||||
|
void FillBlock(size_t block_index, float *block);
|
||||||
|
|
||||||
|
#ifdef WITH_FFTW
|
||||||
|
/// FFTW plan data
|
||||||
|
fftw_plan dft_plan;
|
||||||
|
/// Pre-allocated input array for FFTW
|
||||||
|
double *dft_input;
|
||||||
|
/// Pre-allocated output array for FFTW
|
||||||
|
fftw_complex *dft_output;
|
||||||
|
#else
|
||||||
|
/// Pre-allocated scratch area for doing FFT derivations
|
||||||
|
float *fft_scratch;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Pre-allocated scratch area for storing raw audio data
|
||||||
|
int16_t *audio_scratch;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
/// @param _provider Audio provider to render spectrum data for.
|
AudioSpectrumRenderer();
|
||||||
///
|
|
||||||
/// Reads configuration data for the spectrum display and initialises itself following that.
|
|
||||||
AudioSpectrum(AudioProvider *_provider);
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~AudioSpectrum();
|
virtual ~AudioSpectrumRenderer();
|
||||||
|
|
||||||
/// @brief Render a range of audio spectrum to a bitmap buffer.
|
/// @brief Render a range of audio spectrum
|
||||||
/// @param range_start First audio sample in the range to render.
|
/// @param bmp [in,out] Bitmap to render into, also carries lenght information
|
||||||
/// @param range_end Last audio sample in the range to render.
|
/// @param start First column of pixel data in display to render
|
||||||
/// @param selected Use the alternate colour palette?
|
/// @param selected Whether to use the alternate colour scheme
|
||||||
/// @param img Pointer to 32 bit RGBX data
|
void Render(wxBitmap &bmp, int start, bool selected);
|
||||||
/// @param imgleft Offset from left edge of bitmap to render to, in pixels
|
|
||||||
/// @param imgwidth Width of bitmap to render, in pixels
|
|
||||||
/// @param imgpitch Offset from one scanline to the next in the bitmap, in bytes
|
|
||||||
/// @param imgheight Number of lines in the bitmap
|
|
||||||
void RenderRange(int64_t range_start, int64_t range_end, bool selected, unsigned char *img, int imgleft, int imgwidth, int imgpitch, int imgheight);
|
|
||||||
|
|
||||||
/// @brief Set the amplification to use when rendering.
|
/// @brief Render blank area
|
||||||
/// @param _power_scale Amplification factor to use.
|
void RenderBlank(wxDC &dc, const wxRect &rect, bool selected);
|
||||||
void SetScaling(float _power_scale);
|
|
||||||
|
/// @brief Set the derivation resolution
|
||||||
|
/// @param derivation_size Binary logarithm of number of samples to use in deriving frequency-power data
|
||||||
|
/// @param derivation_dist Binary logarithm of number of samples between the start of derivations
|
||||||
|
///
|
||||||
|
/// The derivations done will each use 2^derivation_size audio samples and at a distance
|
||||||
|
/// of 2^derivation_dist samples.
|
||||||
|
///
|
||||||
|
/// The derivation distance must be smaller than or equal to the size. If the distance
|
||||||
|
/// is specified too large, it will be clamped to the size.
|
||||||
|
void SetResolution(size_t derivation_size, size_t derivation_dist);
|
||||||
|
|
||||||
|
/// @brief Cleans up the cache
|
||||||
|
/// @param max_size Maximum size in bytes for the cache
|
||||||
|
void AgeCache(size_t max_size);
|
||||||
};
|
};
|
||||||
|
|
178
aegisub/src/audio_renderer_waveform.cpp
Normal file
178
aegisub/src/audio_renderer_waveform.cpp
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
// Copyright (c) 2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_renderer_waveform.cpp
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
///
|
||||||
|
/// Render a waveform display of PCM audio data
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <wx/dcmemory.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "block_cache.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
#include "audio_colorscheme.h"
|
||||||
|
#include "audio_renderer.h"
|
||||||
|
#include "audio_renderer_waveform.h"
|
||||||
|
#include "colorspace.h"
|
||||||
|
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioWaveformRenderer::AudioWaveformRenderer()
|
||||||
|
: AudioRendererBitmapProvider()
|
||||||
|
, colors_normal(6)
|
||||||
|
, colors_selected(6)
|
||||||
|
, audio_buffer(0)
|
||||||
|
{
|
||||||
|
colors_normal.InitIcyBlue_Normal();
|
||||||
|
colors_selected.InitIcyBlue_Selected();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioWaveformRenderer::~AudioWaveformRenderer()
|
||||||
|
{
|
||||||
|
delete[] audio_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, bool selected)
|
||||||
|
{
|
||||||
|
wxMemoryDC dc(bmp);
|
||||||
|
wxRect rect(wxPoint(0, 0), bmp.GetSize());
|
||||||
|
int midpoint = rect.height / 2;
|
||||||
|
|
||||||
|
AudioColorScheme *pal = selected ? &colors_selected : &colors_normal;
|
||||||
|
|
||||||
|
// Fill the background
|
||||||
|
dc.SetBrush(wxBrush(pal->get(0.0f)));
|
||||||
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
dc.DrawRectangle(rect);
|
||||||
|
|
||||||
|
// Make sure we've got a buffer to fill with audio data
|
||||||
|
if (!audio_buffer)
|
||||||
|
{
|
||||||
|
// Buffer for one pixel strip of audio
|
||||||
|
size_t buffer_needed = pixel_samples * provider->GetChannels() * provider->GetSampleRate() * provider->GetBytesPerSample();
|
||||||
|
audio_buffer = new char[buffer_needed];
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t cur_sample = start * pixel_samples;
|
||||||
|
|
||||||
|
assert(provider->GetBytesPerSample() == 2);
|
||||||
|
assert(provider->GetChannels() == 1);
|
||||||
|
|
||||||
|
wxPen pen_peaks(wxPen(pal->get(0.4f)));
|
||||||
|
wxPen pen_avgs(wxPen(pal->get(0.7f)));
|
||||||
|
|
||||||
|
for (int x = 0; x < rect.width; ++x)
|
||||||
|
{
|
||||||
|
provider->GetAudio(audio_buffer, cur_sample, pixel_samples);
|
||||||
|
cur_sample += pixel_samples;
|
||||||
|
|
||||||
|
int peak_min = 0, peak_max = 0;
|
||||||
|
int64_t avg_min_accum = 0, avg_max_accum = 0;
|
||||||
|
const int16_t *aud = (const int16_t *)audio_buffer;
|
||||||
|
for (int si = pixel_samples; si > 0; --si, ++aud)
|
||||||
|
{
|
||||||
|
if (*aud > 0)
|
||||||
|
{
|
||||||
|
peak_max = std::max(peak_max, (int)*aud);
|
||||||
|
avg_max_accum += *aud;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
peak_min = std::min(peak_min, (int)*aud);
|
||||||
|
avg_min_accum += *aud;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// midpoint is half height
|
||||||
|
peak_min = std::max((int)(peak_min * amplitude_scale * midpoint) / 0x8000, -midpoint);
|
||||||
|
peak_max = std::min((int)(peak_max * amplitude_scale * midpoint) / 0x8000, midpoint);
|
||||||
|
int avg_min = std::max((int)(avg_min_accum * amplitude_scale * midpoint / pixel_samples) / 0x8000, -midpoint);
|
||||||
|
int avg_max = std::min((int)(avg_max_accum * amplitude_scale * midpoint / pixel_samples) / 0x8000, midpoint);
|
||||||
|
|
||||||
|
dc.SetPen(pen_peaks);
|
||||||
|
dc.DrawLine(x, midpoint - peak_max, x, midpoint - peak_min);
|
||||||
|
dc.SetPen(pen_avgs);
|
||||||
|
dc.DrawLine(x, midpoint - avg_max, x, midpoint - avg_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal zero-point line
|
||||||
|
dc.SetPen(wxPen(pal->get(1.0f)));
|
||||||
|
dc.DrawLine(0, midpoint, rect.width, midpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioWaveformRenderer::RenderBlank(wxDC &dc, const wxRect &rect, bool selected)
|
||||||
|
{
|
||||||
|
AudioColorScheme *pal = selected ? &colors_selected : &colors_normal;
|
||||||
|
|
||||||
|
wxColor line(pal->get(1.0));
|
||||||
|
wxColor bg(pal->get(0.0));
|
||||||
|
|
||||||
|
// Draw the line as background above and below, and line in the middle, to avoid
|
||||||
|
// overdraw flicker (the common theme in all of audio display direct drawing).
|
||||||
|
int halfheight = rect.height / 2;
|
||||||
|
|
||||||
|
dc.SetBrush(wxBrush(bg));
|
||||||
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
dc.DrawRectangle(rect.x, rect.y, rect.width, halfheight);
|
||||||
|
dc.DrawRectangle(rect.x, rect.y + halfheight + 1, rect.width, rect.height - halfheight - 1);
|
||||||
|
|
||||||
|
dc.SetPen(wxPen(line));
|
||||||
|
dc.DrawLine(rect.x, rect.y+halfheight, rect.x+rect.width, rect.y+halfheight);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioWaveformRenderer::OnSetProvider()
|
||||||
|
{
|
||||||
|
delete[] audio_buffer;
|
||||||
|
audio_buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioWaveformRenderer::OnSetSamplesPerPixel()
|
||||||
|
{
|
||||||
|
delete[] audio_buffer;
|
||||||
|
audio_buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
77
aegisub/src/audio_renderer_waveform.h
Normal file
77
aegisub/src/audio_renderer_waveform.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright (c) 2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_renderer_waveform.h
|
||||||
|
/// @see audio_renderer_waveform.cpp
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
///
|
||||||
|
/// Render a waveform display of PCM audio data
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AudioWaveformRenderer : public AudioRendererBitmapProvider {
|
||||||
|
/// Colour table used for regular rendering
|
||||||
|
AudioColorScheme colors_normal;
|
||||||
|
|
||||||
|
/// Colour table used for rendering the audio selection
|
||||||
|
AudioColorScheme colors_selected;
|
||||||
|
|
||||||
|
/// Pre-allocated buffer for audio fetched from provider
|
||||||
|
char *audio_buffer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnSetProvider();
|
||||||
|
virtual void OnSetSamplesPerPixel();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Constructor
|
||||||
|
AudioWaveformRenderer();
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
|
virtual ~AudioWaveformRenderer();
|
||||||
|
|
||||||
|
/// @brief Render a range of audio waveform
|
||||||
|
/// @param bmp [in,out] Bitmap to render into, also carries lenght information
|
||||||
|
/// @param start First column of pixel data in display to render
|
||||||
|
/// @param selected Whether to use the alternate colour scheme
|
||||||
|
void Render(wxBitmap &bmp, int start, bool selected);
|
||||||
|
|
||||||
|
/// @brief Render blank area
|
||||||
|
void RenderBlank(wxDC &dc, const wxRect &rect, bool selected);
|
||||||
|
|
||||||
|
/// @brief Cleans up the cache
|
||||||
|
/// @param max_size Maximum size in bytes for the cache
|
||||||
|
///
|
||||||
|
/// Does nothing for waveform renderer, since it does not have a backend cache
|
||||||
|
void AgeCache(size_t max_size) { }
|
||||||
|
};
|
136
aegisub/src/audio_timing.h
Normal file
136
aegisub/src/audio_timing.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
// Copyright (c) 2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_timing.h
|
||||||
|
/// @brief Construction-functions for timing controller objects
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AssDialogue;
|
||||||
|
class AudioController;
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioTimingController
|
||||||
|
/// @brief Base class for objects controlling audio timing
|
||||||
|
///
|
||||||
|
/// There is just one active audio timing controller at a time per audio controller.
|
||||||
|
/// The timing controller manages the timing mode and supplies markers that can be
|
||||||
|
/// manupulated to the audio display, as well as the current selection.
|
||||||
|
///
|
||||||
|
/// The timing controller must then be sent the marker drag events as well as clicks
|
||||||
|
/// in empty areas of the audio display.
|
||||||
|
class AudioTimingController : public AudioMarkerProvider {
|
||||||
|
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
|
||||||
|
virtual wxString GetWarningMessage() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get the sample range the user is most likely to want to see for the current state
|
||||||
|
/// @return A sample range
|
||||||
|
///
|
||||||
|
/// This is used for "bring working area into view" operations.
|
||||||
|
virtual AudioController::SampleRange GetIdealVisibleSampleRange() const = 0;
|
||||||
|
|
||||||
|
/// @brief Get the primary playback range
|
||||||
|
/// @return A sample range
|
||||||
|
///
|
||||||
|
/// Get the sample range the user is most likely to want to play back currently.
|
||||||
|
virtual AudioController::SampleRange GetPrimaryPlaybackRange() const = 0;
|
||||||
|
|
||||||
|
/// @brief Does this timing mode have labels on the audio display?
|
||||||
|
/// @return True if this timing mode needs labels on the audio display.
|
||||||
|
///
|
||||||
|
/// This is labels for things such as karaoke syllables. When labels are required, some vertical
|
||||||
|
/// space is set off for them in the drawing of the audio display.
|
||||||
|
virtual bool HasLabels() const = 0;
|
||||||
|
|
||||||
|
/// @brief Go to next timing unit
|
||||||
|
///
|
||||||
|
/// Advances the timing controller cursor to the next timing unit, for example the next dialogue
|
||||||
|
/// line or the next karaoke syllable.
|
||||||
|
virtual void Next() = 0;
|
||||||
|
|
||||||
|
/// @brief Go to the previous timing unit
|
||||||
|
///
|
||||||
|
/// Rewinds the timing controller to the previous timing unit.
|
||||||
|
virtual void Prev() = 0;
|
||||||
|
|
||||||
|
/// @brief Commit all changes
|
||||||
|
///
|
||||||
|
/// Stores all changes permanently.
|
||||||
|
virtual void Commit() = 0;
|
||||||
|
|
||||||
|
/// @brief Revert all changes
|
||||||
|
///
|
||||||
|
/// Revert all changes to the last committed state.
|
||||||
|
virtual void Revert() = 0;
|
||||||
|
|
||||||
|
/// @brief Determine if a position is close to a draggable marker
|
||||||
|
/// @param sample The audio sample index to test
|
||||||
|
/// @param sensitivity Distance in samples to consider markers as nearby
|
||||||
|
/// @return True if a marker is close by the given sample, as defined by sensitivity
|
||||||
|
///
|
||||||
|
/// This is solely for hit-testing against draggable markers, for controlling the mouse cursor.
|
||||||
|
virtual bool IsNearbyMarker(int64_t sample, int sensitivity) const = 0;
|
||||||
|
|
||||||
|
/// @brief The user pressed the left button down at an empty place in the audio
|
||||||
|
/// @param sample The audio sample index the user clicked
|
||||||
|
/// @param sensitivity Distance in samples to consider existing markers
|
||||||
|
/// @return An audio marker or 0. If a marker is returned and the user starts dragging
|
||||||
|
/// the mouse after pressing down the button, the returned marker is being dragged.
|
||||||
|
virtual AudioMarker * OnLeftClick(int64_t sample, int sensitivity) = 0;
|
||||||
|
|
||||||
|
/// @brief The user pressed the right button down at an empty place in the audio
|
||||||
|
/// @param sample The audio sample index the user clicked
|
||||||
|
/// @param sensitivity Distance in samples to consider existing markers
|
||||||
|
/// @return An audio marker or 0. If a marker is returned and the user starts dragging
|
||||||
|
/// the mouse after pressing down the button, the returned marker is being dragged.
|
||||||
|
virtual AudioMarker * OnRightClick(int64_t sample, int sensitivity) = 0;
|
||||||
|
|
||||||
|
/// @brief The user dragged a timing marker
|
||||||
|
/// @param marker The marker being dragged
|
||||||
|
/// @param new_position Sample position the marker was dragged to
|
||||||
|
virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position) = 0;
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
|
///
|
||||||
|
/// Does nothing in the base class, only present for virtual destruction.
|
||||||
|
virtual ~AudioTimingController() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Create a standard dialogue audio timing controller
|
||||||
|
/// @param audio_controller The audio controller to own the timing controller
|
||||||
|
/// @param selection_controller The selection controller to manage the set of lines being timed
|
||||||
|
AudioTimingController *CreateDialogueTimingController(AudioController *audio_controller, SelectionController<AssDialogue> *selection_controller);
|
||||||
|
|
478
aegisub/src/audio_timing_dialogue.cpp
Normal file
478
aegisub/src/audio_timing_dialogue.cpp
Normal file
|
@ -0,0 +1,478 @@
|
||||||
|
// Copyright (c) 2010, 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 Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file audio_timing_dialogue.cpp
|
||||||
|
/// @brief Default timing mode for dialogue subtitles
|
||||||
|
/// @ingroup audio_ui
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <wx/pen.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ass_time.h"
|
||||||
|
#include "ass_dialogue.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
|
#include "audio_timing.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioMarkerDialogueTiming
|
||||||
|
/// @brief AudioMarker implementation for AudioTimingControllerDialogue
|
||||||
|
///
|
||||||
|
/// Audio marker intended to live in pairs of two, taking styles depending
|
||||||
|
/// on which marker in the pair is to the left and which is to the right.
|
||||||
|
class AudioMarkerDialogueTiming : public AudioMarker {
|
||||||
|
/// The other marker for the dialogue line's pair
|
||||||
|
AudioMarkerDialogueTiming *other;
|
||||||
|
|
||||||
|
/// Current sample position of this marker
|
||||||
|
int64_t position;
|
||||||
|
|
||||||
|
/// Draw style for the marker
|
||||||
|
wxPen style;
|
||||||
|
/// Foot style for the marker
|
||||||
|
FeetStyle feet;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// AudioMarker interface
|
||||||
|
virtual int64_t GetPosition() const { return position; }
|
||||||
|
virtual wxPen GetStyle() const { return style; }
|
||||||
|
virtual FeetStyle GetFeet() const { return feet; }
|
||||||
|
virtual bool CanSnap() const { return true; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Specific interface
|
||||||
|
|
||||||
|
/// @brief Move the marker to a new position
|
||||||
|
/// @param new_position The position to move the marker to, in audio samples
|
||||||
|
///
|
||||||
|
/// If the marker moves to the opposite side of the ohter marker in the pair,
|
||||||
|
/// the styles of the two markers will be changed to match the new start/end
|
||||||
|
/// relationship of them.
|
||||||
|
void SetPosition(int64_t new_position);
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Constructor
|
||||||
|
///
|
||||||
|
/// Initialises the fields to default values.
|
||||||
|
AudioMarkerDialogueTiming();
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Initialise a pair of dialogue markers to be a pair
|
||||||
|
/// @param marker1 The first marker in the pair to make
|
||||||
|
/// @param marker2 The second marker in the pair to make
|
||||||
|
///
|
||||||
|
/// This checks that the markers aren't already part of a pair, and then sets their
|
||||||
|
/// "other" field. Positions and styles aren't affected.
|
||||||
|
static void InitPair(AudioMarkerDialogueTiming *marker1, AudioMarkerDialogueTiming *marker2);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioTimingControllerDialogue
|
||||||
|
/// @brief Default timing mode for dialogue subtitles
|
||||||
|
///
|
||||||
|
/// Displays a start and end marker for an active subtitle line, and allows
|
||||||
|
/// for those markers to be dragged. Dragging the start/end markers changes
|
||||||
|
/// the audio selection.
|
||||||
|
///
|
||||||
|
/// When the audio rendering code is expanded to support it, inactive lines
|
||||||
|
/// will also be shown as shaded lines that cannot be changed.
|
||||||
|
///
|
||||||
|
/// Another later expansion will be to affect the timing of multiple selected
|
||||||
|
/// lines at the same time, if they e.g. have end1==start2.
|
||||||
|
class AudioTimingControllerDialogue : public AudioTimingController, private SelectionListener<AssDialogue> {
|
||||||
|
/// Start and end markers for the active line
|
||||||
|
AudioMarkerDialogueTiming markers[2];
|
||||||
|
|
||||||
|
/// Has the timing been modified by the user?
|
||||||
|
bool timing_modified;
|
||||||
|
|
||||||
|
/// Get the leftmost of the markers
|
||||||
|
AudioMarkerDialogueTiming *GetLeftMarker();
|
||||||
|
const AudioMarkerDialogueTiming *GetLeftMarker() const;
|
||||||
|
/// Get the rightmost of the markers
|
||||||
|
AudioMarkerDialogueTiming *GetRightMarker();
|
||||||
|
const AudioMarkerDialogueTiming *GetRightMarker() const;
|
||||||
|
|
||||||
|
/// The owning audio controller
|
||||||
|
AudioController *audio_controller;
|
||||||
|
|
||||||
|
/// Update the audio controller's selection
|
||||||
|
void UpdateSelection();
|
||||||
|
|
||||||
|
/// Selection controller managing the set of lines currently being timed
|
||||||
|
SelectionController<AssDialogue> *selection_controller;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// SubtitleSelectionListener interface
|
||||||
|
virtual void OnActiveLineChanged(AssDialogue *new_line);
|
||||||
|
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// AudioMarkerProvider interface
|
||||||
|
virtual void GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out_markers) const;
|
||||||
|
|
||||||
|
// AudioTimingController interface
|
||||||
|
virtual wxString GetWarningMessage() const;
|
||||||
|
virtual AudioController::SampleRange GetIdealVisibleSampleRange() const;
|
||||||
|
virtual AudioController::SampleRange GetPrimaryPlaybackRange() const;
|
||||||
|
virtual bool HasLabels() const;
|
||||||
|
virtual void Next();
|
||||||
|
virtual void Prev();
|
||||||
|
virtual void Commit();
|
||||||
|
virtual void Revert();
|
||||||
|
virtual bool IsNearbyMarker(int64_t sample, int sensitivity) const;
|
||||||
|
virtual AudioMarker * OnLeftClick(int64_t sample, int sensitivity);
|
||||||
|
virtual AudioMarker * OnRightClick(int64_t sample, int sensitivity);
|
||||||
|
virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Specific interface
|
||||||
|
|
||||||
|
/// @brief Constructor
|
||||||
|
AudioTimingControllerDialogue(AudioController *audio_controller, SelectionController<AssDialogue> *selection_controller);
|
||||||
|
virtual ~AudioTimingControllerDialogue();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioTimingController *CreateDialogueTimingController(AudioController *audio_controller, SelectionController<AssDialogue> *selection_controller)
|
||||||
|
{
|
||||||
|
return new AudioTimingControllerDialogue(audio_controller, selection_controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// AudioMarkerDialogueTiming
|
||||||
|
|
||||||
|
void AudioMarkerDialogueTiming::SetPosition(int64_t new_position)
|
||||||
|
{
|
||||||
|
position = new_position;
|
||||||
|
|
||||||
|
if (other)
|
||||||
|
{
|
||||||
|
/// @todo Make this depend on configuration
|
||||||
|
wxPen style_left = wxPen(*wxRED, 2);
|
||||||
|
wxPen style_right = wxPen(*wxBLUE, 2);
|
||||||
|
if (position < other->position)
|
||||||
|
{
|
||||||
|
feet = Feet_Right;
|
||||||
|
other->feet = Feet_Left;
|
||||||
|
style = style_left;
|
||||||
|
other->style = style_right;
|
||||||
|
}
|
||||||
|
else if (position > other->position)
|
||||||
|
{
|
||||||
|
feet = Feet_Left;
|
||||||
|
other->feet = Feet_Right;
|
||||||
|
style = style_right;
|
||||||
|
other->style = style_left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioMarkerDialogueTiming::AudioMarkerDialogueTiming()
|
||||||
|
: other(0)
|
||||||
|
, position(0)
|
||||||
|
, style(*wxTRANSPARENT_PEN)
|
||||||
|
, feet(Feet_None)
|
||||||
|
{
|
||||||
|
// Nothing more to do
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioMarkerDialogueTiming::InitPair(AudioMarkerDialogueTiming *marker1, AudioMarkerDialogueTiming *marker2)
|
||||||
|
{
|
||||||
|
assert(marker1->other == 0);
|
||||||
|
assert(marker2->other == 0);
|
||||||
|
|
||||||
|
marker1->other = marker2;
|
||||||
|
marker2->other = marker1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// AudioTimingControllerDialogue
|
||||||
|
|
||||||
|
AudioTimingControllerDialogue::AudioTimingControllerDialogue(AudioController *audio_controller, SelectionController<AssDialogue> *selection_controller)
|
||||||
|
: timing_modified(false)
|
||||||
|
, audio_controller(audio_controller)
|
||||||
|
, selection_controller(selection_controller)
|
||||||
|
{
|
||||||
|
assert(audio_controller != 0);
|
||||||
|
|
||||||
|
AudioMarkerDialogueTiming::InitPair(&markers[0], &markers[1]);
|
||||||
|
|
||||||
|
selection_controller->AddSelectionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioTimingControllerDialogue::~AudioTimingControllerDialogue()
|
||||||
|
{
|
||||||
|
selection_controller->RemoveSelectionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetLeftMarker()
|
||||||
|
{
|
||||||
|
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[0] : &markers[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetLeftMarker() const
|
||||||
|
{
|
||||||
|
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[0] : &markers[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetRightMarker()
|
||||||
|
{
|
||||||
|
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[1] : &markers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetRightMarker() const
|
||||||
|
{
|
||||||
|
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[1] : &markers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out_markers) const
|
||||||
|
{
|
||||||
|
if (range.contains(markers[0].GetPosition()))
|
||||||
|
out_markers.push_back(&markers[0]);
|
||||||
|
if (range.contains(markers[1].GetPosition()))
|
||||||
|
out_markers.push_back(&markers[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::OnActiveLineChanged(AssDialogue *new_line)
|
||||||
|
{
|
||||||
|
/// @todo Need to change policy to default commit at some point
|
||||||
|
Revert(); // revert will read and reset the selection/markers
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed)
|
||||||
|
{
|
||||||
|
/// @todo Create new passive markers, perhaps
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
wxString AudioTimingControllerDialogue::GetWarningMessage() const
|
||||||
|
{
|
||||||
|
// We have no warning messages currently, maybe add the old "Modified" message back later?
|
||||||
|
return wxString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioController::SampleRange AudioTimingControllerDialogue::GetIdealVisibleSampleRange() const
|
||||||
|
{
|
||||||
|
return GetPrimaryPlaybackRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioController::SampleRange AudioTimingControllerDialogue::GetPrimaryPlaybackRange() const
|
||||||
|
{
|
||||||
|
return AudioController::SampleRange(
|
||||||
|
GetLeftMarker()->GetPosition(),
|
||||||
|
GetRightMarker()->GetPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool AudioTimingControllerDialogue::HasLabels() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::Next()
|
||||||
|
{
|
||||||
|
selection_controller->NextLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::Prev()
|
||||||
|
{
|
||||||
|
selection_controller->PrevLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::Commit()
|
||||||
|
{
|
||||||
|
/// @todo Make these depend on actual configuration
|
||||||
|
const bool next_line_on_commit = true;
|
||||||
|
const int default_duration = 5000; // milliseconds
|
||||||
|
|
||||||
|
int new_start_ms = audio_controller->MillisecondsFromSamples(GetLeftMarker()->GetPosition());
|
||||||
|
int new_end_ms = audio_controller->MillisecondsFromSamples(GetRightMarker()->GetPosition());
|
||||||
|
|
||||||
|
// Store back new times
|
||||||
|
if (timing_modified)
|
||||||
|
{
|
||||||
|
Selection sel;
|
||||||
|
selection_controller->GetSelectedSet(sel);
|
||||||
|
for (Selection::iterator sub = sel.begin(); sub != sel.end(); ++sub)
|
||||||
|
{
|
||||||
|
(*sub)->Start.SetMS(new_start_ms);
|
||||||
|
(*sub)->End.SetMS(new_end_ms);
|
||||||
|
}
|
||||||
|
/// @todo Set an undo point
|
||||||
|
timing_modified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that the next line might be zero-timed and should thus get a default timing
|
||||||
|
if (next_line_on_commit)
|
||||||
|
{
|
||||||
|
markers[0].SetPosition(audio_controller->SamplesFromMilliseconds(new_end_ms));
|
||||||
|
markers[1].SetPosition(audio_controller->SamplesFromMilliseconds(new_end_ms + default_duration));
|
||||||
|
UpdateSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::Revert()
|
||||||
|
{
|
||||||
|
AssDialogue *line = selection_controller->GetActiveLine();
|
||||||
|
if (line)
|
||||||
|
{
|
||||||
|
AssTime new_start = line->Start;
|
||||||
|
AssTime new_end = line->End;
|
||||||
|
|
||||||
|
if (new_start.GetMS() != 0 || new_end.GetMS() != 0)
|
||||||
|
{
|
||||||
|
markers[0].SetPosition(audio_controller->SamplesFromMilliseconds(new_start.GetMS()));
|
||||||
|
markers[1].SetPosition(audio_controller->SamplesFromMilliseconds(new_end.GetMS()));
|
||||||
|
timing_modified = false;
|
||||||
|
UpdateSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool AudioTimingControllerDialogue::IsNearbyMarker(int64_t sample, int sensitivity) const
|
||||||
|
{
|
||||||
|
AudioController::SampleRange range(sample-sensitivity, sample+sensitivity);
|
||||||
|
|
||||||
|
return range.contains(markers[0].GetPosition()) || range.contains(markers[1].GetPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity)
|
||||||
|
{
|
||||||
|
assert(sensitivity >= 0);
|
||||||
|
|
||||||
|
int64_t dist_l, dist_r;
|
||||||
|
|
||||||
|
AudioMarkerDialogueTiming *left = GetLeftMarker();
|
||||||
|
AudioMarkerDialogueTiming *right = GetRightMarker();
|
||||||
|
|
||||||
|
dist_l = tabs(left->GetPosition() - sample);
|
||||||
|
dist_r = tabs(right->GetPosition() - sample);
|
||||||
|
|
||||||
|
if (dist_l < dist_r && dist_l <= sensitivity)
|
||||||
|
{
|
||||||
|
// Clicked near the left marker:
|
||||||
|
// Insta-move it and start dragging it
|
||||||
|
left->SetPosition(sample);
|
||||||
|
audio_controller->OnTimingControllerMarkerMoved(this, left);
|
||||||
|
timing_modified = true;
|
||||||
|
UpdateSelection();
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dist_r < dist_l && dist_r <= sensitivity)
|
||||||
|
{
|
||||||
|
// Clicked near the right marker:
|
||||||
|
// Only drag it. For insta-move, the user must right-click.
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicked far from either marker:
|
||||||
|
// Insta-set the left marker to the clicked position and return the right as the dragged one,
|
||||||
|
// such that if the user does start dragging, he will create a new selection from scratch
|
||||||
|
left->SetPosition(sample);
|
||||||
|
audio_controller->OnTimingControllerMarkerMoved(this, left);
|
||||||
|
timing_modified = true;
|
||||||
|
UpdateSelection();
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int sensitivity)
|
||||||
|
{
|
||||||
|
AudioMarkerDialogueTiming *right = GetRightMarker();
|
||||||
|
|
||||||
|
right->SetPosition(sample);
|
||||||
|
audio_controller->OnTimingControllerMarkerMoved(this, right);
|
||||||
|
timing_modified = true;
|
||||||
|
UpdateSelection();
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t new_position)
|
||||||
|
{
|
||||||
|
assert(marker == &markers[0] || marker == &markers[1]);
|
||||||
|
|
||||||
|
static_cast<AudioMarkerDialogueTiming*>(marker)->SetPosition(new_position);
|
||||||
|
audio_controller->OnTimingControllerMarkerMoved(this, marker);
|
||||||
|
timing_modified = true;
|
||||||
|
|
||||||
|
UpdateSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AudioTimingControllerDialogue::UpdateSelection()
|
||||||
|
{
|
||||||
|
audio_controller->OnTimingControllerUpdatedPrimaryRange(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
#include "audio_display.h"
|
#include "audio_controller.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -1251,9 +1252,12 @@ void BaseGrid::OnKeyPress(wxKeyEvent &event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other events, send to audio display
|
// Other events, send to audio display
|
||||||
|
/// @todo Reinstate this, or make a better solution, when audio is getting stabler again
|
||||||
|
/*
|
||||||
if (context->audio->loaded) {
|
if (context->audio->loaded) {
|
||||||
context->audio->GetEventHandler()->ProcessEvent(event);
|
context->audio->GetEventHandler()->ProcessEvent(event);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
else event.Skip();
|
else event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,6 @@ public:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
SubsEditBox *editBox;
|
SubsEditBox *editBox;
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
bool byFrame;
|
bool byFrame;
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define AGI_BLOCK_CACHE_INCLUDED 1
|
||||||
|
|
||||||
|
|
||||||
/// @class BasicDataBlockFactory
|
/// @class BasicDataBlockFactory
|
||||||
/// @brief Simple factory for allocating blocks for DataBlockCache
|
/// @brief Simple factory for allocating blocks for DataBlockCache
|
||||||
|
@ -143,7 +145,7 @@ class DataBlockCache {
|
||||||
for (size_t bi = 0; bi < mb.blocks.size(); ++bi)
|
for (size_t bi = 0; bi < mb.blocks.size(); ++bi)
|
||||||
{
|
{
|
||||||
BlockT *b = mb.blocks[bi];
|
BlockT *b = mb.blocks[bi];
|
||||||
if (!b)
|
if (b)
|
||||||
factory.DisposeBlock(b);
|
factory.DisposeBlock(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,12 @@
|
||||||
//#define FINAL_RELEASE
|
//#define FINAL_RELEASE
|
||||||
|
|
||||||
|
|
||||||
|
// Use FFTW instead of shipped FFT code
|
||||||
|
// FFTW <http://fftw.org/> is a very fast library for computing the discrete fourier transform, but is a bit
|
||||||
|
// tricky to get working on Windows, and has the additional problem of being GPL licensed.
|
||||||
|
// Enable this option to use FFTW to get faster rendering of the audio spectrogram
|
||||||
|
//#define WITH_FFTW
|
||||||
|
//#pragma comment(lib,libfftw.lib)
|
||||||
// Specify tags the update checker accepts
|
// Specify tags the update checker accepts
|
||||||
// See <http://devel.aegisub.org/wiki/Technical/UpdateChecker> for details on tags.
|
// See <http://devel.aegisub.org/wiki/Technical/UpdateChecker> for details on tags.
|
||||||
// Depending on who will be using your build, you may or may not want to have the
|
// Depending on who will be using your build, you may or may not want to have the
|
||||||
|
|
|
@ -46,8 +46,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
namespace Automation4 {
|
||||||
namespace Automation4 { class ScriptManager; class Script; class AutoloadScriptManager; };
|
class ScriptManager;
|
||||||
|
class AutoloadScriptManager;
|
||||||
|
class Script;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <wx/display.h> /// Must be included last.
|
#include <wx/display.h> /// Must be included last.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "dialog_detached_video.h"
|
#include "dialog_detached_video.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "dialog_fonts_collector.h"
|
#include "dialog_fonts_collector.h"
|
||||||
#include "font_file_lister.h"
|
#include "font_file_lister.h"
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "scintilla_text_ctrl.h"
|
#include "scintilla_text_ctrl.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "validators.h"
|
#include "validators.h"
|
||||||
|
|
|
@ -47,9 +47,11 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "dialog_search_replace.h"
|
#include "dialog_search_replace.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "dialog_selection.h"
|
#include "dialog_selection.h"
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "dialog_spellchecker.h"
|
#include "dialog_spellchecker.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "include/aegisub/spellchecker.h"
|
#include "include/aegisub/spellchecker.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "subs_preview.h"
|
#include "subs_preview.h"
|
||||||
#include "include/aegisub/subtitles_provider.h"
|
#include "include/aegisub/subtitles_provider.h"
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "standard_paths.h"
|
#include "standard_paths.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
|
@ -46,8 +46,9 @@
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
|
||||||
#include "dialog_styling_assistant.h"
|
#include "dialog_styling_assistant.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
|
@ -72,8 +73,8 @@ wxDialog (parent, -1, _("Styling assistant"), wxDefaultPosition, wxDefaultSize,
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
grid = _grid;
|
grid = _grid;
|
||||||
audio = VideoContext::Get()->audio->box->audioDisplay;
|
audio = VideoContext::Get()->audio;
|
||||||
video = video->Get();
|
video = VideoContext::Get();
|
||||||
needCommit = false;
|
needCommit = false;
|
||||||
linen = -1;
|
linen = -1;
|
||||||
|
|
||||||
|
@ -269,7 +270,8 @@ void DialogStyling::OnActivate(wxActivateEvent &event) {
|
||||||
}
|
}
|
||||||
// Enable/disable play video/audio buttons
|
// Enable/disable play video/audio buttons
|
||||||
PlayVideoButton->Enable(video->IsLoaded());
|
PlayVideoButton->Enable(video->IsLoaded());
|
||||||
PlayAudioButton->Enable(audio->loaded);
|
/// @todo Reinstate this when the audio controller is made reachable from here
|
||||||
|
//PlayAudioButton->Enable(audio->loaded);
|
||||||
// Fix style list
|
// Fix style list
|
||||||
Styles->Set(grid->ass->GetStyles());
|
Styles->Set(grid->ass->GetStyles());
|
||||||
// Fix line selection
|
// Fix line selection
|
||||||
|
@ -377,7 +379,9 @@ void DialogStyling::OnPlayVideoButton(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void DialogStyling::OnPlayAudioButton(wxCommandEvent &event) {
|
void DialogStyling::OnPlayAudioButton(wxCommandEvent &event) {
|
||||||
audio->Play(line->Start.GetMS(),line->End.GetMS());
|
audio->PlayRange(AudioController::SampleRange(
|
||||||
|
audio->SamplesFromMilliseconds(line->Start.GetMS()),
|
||||||
|
audio->SamplesFromMilliseconds(line->End.GetMS())));
|
||||||
TypeBox->SetFocus();
|
TypeBox->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,9 +450,12 @@ void StyleEditBox::OnKeyDown(wxKeyEvent &event) {
|
||||||
|
|
||||||
// Play audio
|
// Play audio
|
||||||
if (Hotkeys.IsPressed(_T("Styling Assistant Play Audio"))) {
|
if (Hotkeys.IsPressed(_T("Styling Assistant Play Audio"))) {
|
||||||
|
/// @todo Reinstate this when the audio controller is made reachable from here
|
||||||
|
/*
|
||||||
if (diag->audio->loaded) {
|
if (diag->audio->loaded) {
|
||||||
diag->audio->Play(diag->line->Start.GetMS(),diag->line->End.GetMS());
|
diag->audio->Play(diag->line->Start.GetMS(),diag->line->End.GetMS());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ class SubtitlesGrid;
|
||||||
class DialogStyling;
|
class DialogStyling;
|
||||||
class AudioDisplay;
|
class AudioDisplay;
|
||||||
class VideoContext;
|
class VideoContext;
|
||||||
|
class AudioController;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,7 +143,7 @@ public:
|
||||||
AssDialogue *line;
|
AssDialogue *line;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
AudioDisplay *audio;
|
AudioController *audio;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
VideoContext *video;
|
VideoContext *video;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "validators.h"
|
#include "validators.h"
|
||||||
|
|
|
@ -45,12 +45,13 @@
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "audio_display.h"
|
#include "audio_controller.h"
|
||||||
#include "dialog_translation.h"
|
#include "dialog_translation.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "hotkeys.h"
|
#include "hotkeys.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
|
@ -78,7 +79,7 @@ DialogTranslation::DialogTranslation (wxWindow *parent,AssFile *_subs,SubtitlesG
|
||||||
subs = _subs;
|
subs = _subs;
|
||||||
grid = _grid;
|
grid = _grid;
|
||||||
audio = VideoContext::Get()->audio;
|
audio = VideoContext::Get()->audio;
|
||||||
video = video->Get();
|
video = VideoContext::Get();
|
||||||
|
|
||||||
// Translation controls
|
// Translation controls
|
||||||
OrigText = new ScintillaTextCtrl(this,TEXT_ORIGINAL,_T(""),wxDefaultPosition,wxSize(320,80));
|
OrigText = new ScintillaTextCtrl(this,TEXT_ORIGINAL,_T(""),wxDefaultPosition,wxSize(320,80));
|
||||||
|
@ -132,7 +133,8 @@ DialogTranslation::DialogTranslation (wxWindow *parent,AssFile *_subs,SubtitlesG
|
||||||
wxButton *PlayVideoButton = new wxButton(this,BUTTON_TRANS_PLAY_VIDEO,_("Play Video"));
|
wxButton *PlayVideoButton = new wxButton(this,BUTTON_TRANS_PLAY_VIDEO,_("Play Video"));
|
||||||
wxButton *PlayAudioButton = new wxButton(this,BUTTON_TRANS_PLAY_AUDIO,_("Play Audio"));
|
wxButton *PlayAudioButton = new wxButton(this,BUTTON_TRANS_PLAY_AUDIO,_("Play Audio"));
|
||||||
PlayVideoButton->Enable(video->IsLoaded());
|
PlayVideoButton->Enable(video->IsLoaded());
|
||||||
PlayAudioButton->Enable(audio->loaded);
|
/// @todo Reinstate this when the audio context is made reachable from here
|
||||||
|
//PlayAudioButton->Enable(audio->loaded);
|
||||||
ToolSizer->Add(PlayAudioButton,0,wxALL,5);
|
ToolSizer->Add(PlayAudioButton,0,wxALL,5);
|
||||||
ToolSizer->Add(PlayVideoButton,0,wxLEFT | wxRIGHT | wxBOTTOM,5);
|
ToolSizer->Add(PlayVideoButton,0,wxLEFT | wxRIGHT | wxBOTTOM,5);
|
||||||
|
|
||||||
|
@ -406,10 +408,13 @@ void DialogTranslation::OnTransBoxKey(wxKeyEvent &event) {
|
||||||
|
|
||||||
// Play audio
|
// Play audio
|
||||||
if (Hotkeys.IsPressed(_T("Translation Assistant Play Audio"))) {
|
if (Hotkeys.IsPressed(_T("Translation Assistant Play Audio"))) {
|
||||||
|
/// @todo Reinstate this when the audio controller is made reachable from here
|
||||||
|
/*
|
||||||
if (audio->loaded) {
|
if (audio->loaded) {
|
||||||
audio->Play(current->Start.GetMS(),current->End.GetMS());
|
audio->Play(current->Start.GetMS(),current->End.GetMS());
|
||||||
TransText->SetFocus();
|
TransText->SetFocus();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +444,9 @@ void DialogTranslation::OnPlayVideoButton(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void DialogTranslation::OnPlayAudioButton(wxCommandEvent &event) {
|
void DialogTranslation::OnPlayAudioButton(wxCommandEvent &event) {
|
||||||
audio->Play(current->Start.GetMS(),current->End.GetMS());
|
audio->PlayRange(AudioController::SampleRange(
|
||||||
|
audio->SamplesFromMilliseconds(current->Start.GetMS()),
|
||||||
|
audio->SamplesFromMilliseconds(current->End.GetMS())));
|
||||||
TransText->SetFocus();
|
TransText->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ class AudioDisplay;
|
||||||
class ScintillaTextCtrl;
|
class ScintillaTextCtrl;
|
||||||
class SubtitlesGrid;
|
class SubtitlesGrid;
|
||||||
class VideoContext;
|
class VideoContext;
|
||||||
|
class AudioController;
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
@ -56,7 +57,7 @@ class DialogTranslation : public wxDialog {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
AudioDisplay *audio;
|
AudioController *audio;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
VideoContext *video;
|
VideoContext *video;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "drop.h"
|
#include "drop.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "ffmpegsource_common.h"
|
#include "ffmpegsource_common.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -46,8 +46,9 @@
|
||||||
|
|
||||||
|
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
#include "auto4_base.h"
|
#include "auto4_base.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -114,8 +115,7 @@ FrameMain::FrameMain (wxArrayString args)
|
||||||
// Initialize flags
|
// Initialize flags
|
||||||
HasSelection = false;
|
HasSelection = false;
|
||||||
menuCreated = false;
|
menuCreated = false;
|
||||||
blockAudioLoad = false;
|
blockVideoLoad = false;
|
||||||
blockAudioLoad = false;
|
|
||||||
|
|
||||||
StartupLog(_T("Install PNG handler"));
|
StartupLog(_T("Install PNG handler"));
|
||||||
// Create PNG handler
|
// Create PNG handler
|
||||||
|
@ -130,6 +130,10 @@ FrameMain::FrameMain (wxArrayString args)
|
||||||
local_scripts = new Automation4::ScriptManager();
|
local_scripts = new Automation4::ScriptManager();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Contexts and controllers
|
||||||
|
audioController = new AudioController;
|
||||||
|
audioController->AddAudioListener(this);
|
||||||
|
|
||||||
// Create menu and tool bars
|
// Create menu and tool bars
|
||||||
StartupLog(_T("Apply saved Maximized state"));
|
StartupLog(_T("Apply saved Maximized state"));
|
||||||
if (OPT_GET("App/Maximized")->GetBool()) Maximize(true);
|
if (OPT_GET("App/Maximized")->GetBool()) Maximize(true);
|
||||||
|
@ -206,7 +210,10 @@ FrameMain::FrameMain (wxArrayString args)
|
||||||
|
|
||||||
/// @brief FrameMain destructor
|
/// @brief FrameMain destructor
|
||||||
FrameMain::~FrameMain () {
|
FrameMain::~FrameMain () {
|
||||||
|
VideoContext::Get()->SetVideo(_T(""));
|
||||||
|
audioController->CloseAudio();
|
||||||
DeInitContents();
|
DeInitContents();
|
||||||
|
delete audioController;
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
delete local_scripts;
|
delete local_scripts;
|
||||||
#endif
|
#endif
|
||||||
|
@ -492,6 +499,9 @@ void FrameMain::InitMenu() {
|
||||||
AppendBitmapMenuItem(audioMenu, Menu_Audio_Close, _("&Close Audio"), _("Closes the currently open audio file"), GETIMAGE(close_audio_menu_16));
|
AppendBitmapMenuItem(audioMenu, Menu_Audio_Close, _("&Close Audio"), _("Closes the currently open audio file"), GETIMAGE(close_audio_menu_16));
|
||||||
wxMenuItem *RecentAudParent = new wxMenuItem(audioMenu, Menu_File_Recent_Auds_Parent, _("Recent"), _T(""), wxITEM_NORMAL, RecentAuds);
|
wxMenuItem *RecentAudParent = new wxMenuItem(audioMenu, Menu_File_Recent_Auds_Parent, _("Recent"), _T(""), wxITEM_NORMAL, RecentAuds);
|
||||||
audioMenu->Append(RecentAudParent);
|
audioMenu->Append(RecentAudParent);
|
||||||
|
audioMenu->AppendSeparator();
|
||||||
|
audioMenu->Append(Menu_Audio_Spectrum, _("Spectrum display"), _("Display audio as a frequency-power spectrogrph"), wxITEM_RADIO);
|
||||||
|
audioMenu->Append(Menu_Audio_Waveform, _("Waveform display"), _("Display audio as a linear amplitude graph"), wxITEM_RADIO);
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
audioMenu->AppendSeparator();
|
audioMenu->AppendSeparator();
|
||||||
audioMenu->Append(Menu_Audio_Open_Dummy, _T("Open 2h30 Blank Audio"), _T("Open a 150 minutes blank audio clip, for debugging"));
|
audioMenu->Append(Menu_Audio_Open_Dummy, _T("Open 2h30 Blank Audio"), _T("Open a 150 minutes blank audio clip, for debugging"));
|
||||||
|
@ -557,45 +567,52 @@ void FrameMain::InitContents() {
|
||||||
StartupLog(_T("Create background panel"));
|
StartupLog(_T("Create background panel"));
|
||||||
Panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN);
|
Panel = new wxPanel(this,-1,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL | wxCLIP_CHILDREN);
|
||||||
|
|
||||||
// Initialize sizers
|
|
||||||
StartupLog(_T("Create main sizers"));
|
|
||||||
MainSizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
TopSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
BottomSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
|
|
||||||
// Video area;
|
// Video area;
|
||||||
StartupLog(_T("Create video box"));
|
StartupLog(_T("Create video box"));
|
||||||
videoBox = new VideoBox(Panel, false, ZoomBox, ass);
|
videoBox = new VideoBox(Panel, false, ZoomBox, ass);
|
||||||
TopSizer->Add(videoBox,0,wxEXPAND,0);
|
VideoContext::Get()->audio = audioController;
|
||||||
|
wxBoxSizer *videoSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
videoSizer->Add(videoBox, 0, wxEXPAND);
|
||||||
|
videoSizer->AddStretchSpacer(1);
|
||||||
|
|
||||||
// Subtitles area
|
// Subtitles area
|
||||||
StartupLog(_T("Create subtitles grid"));
|
StartupLog(_T("Create subtitles grid"));
|
||||||
SubsGrid = new SubtitlesGrid(this,Panel,-1,ass,wxDefaultPosition,wxSize(600,100),wxWANTS_CHARS | wxSUNKEN_BORDER,_T("Subs grid"));
|
SubsGrid = new SubtitlesGrid(this,Panel,-1,ass,wxDefaultPosition,wxSize(600,100),wxWANTS_CHARS | wxSUNKEN_BORDER,_T("Subs grid"));
|
||||||
BottomSizer->Add(SubsGrid,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,0);
|
|
||||||
videoBox->videoSlider->grid = SubsGrid;
|
videoBox->videoSlider->grid = SubsGrid;
|
||||||
VideoContext::Get()->grid = SubsGrid;
|
VideoContext::Get()->grid = SubsGrid;
|
||||||
Search.grid = SubsGrid;
|
Search.grid = SubsGrid;
|
||||||
|
|
||||||
|
// Tools area
|
||||||
|
StartupLog(_T("Create tool area splitter window"));
|
||||||
|
audioSash = new wxSashWindow(Panel, Main_AudioSash, wxDefaultPosition, wxDefaultSize, wxSW_3D|wxCLIP_CHILDREN);
|
||||||
|
wxBoxSizer *audioSashSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
audioSash->SetSashVisible(wxSASH_BOTTOM, true);
|
||||||
|
|
||||||
// Audio area
|
// Audio area
|
||||||
StartupLog(_T("Create audio box"));
|
StartupLog(_T("Create audio box"));
|
||||||
audioBox = new AudioBox(Panel, SubsGrid);
|
audioBox = new AudioBox(audioSash, audioController, SubsGrid);
|
||||||
audioBox->frameMain = this;
|
audioBox->frameMain = this;
|
||||||
VideoContext::Get()->audio = audioBox->audioDisplay;
|
audioSashSizer->Add(audioBox, 1, wxEXPAND);
|
||||||
|
audioSash->SetSizer(audioSashSizer);
|
||||||
|
audioBox->Fit();
|
||||||
|
audioSash->SetMinimumSizeY(audioBox->GetSize().GetHeight());
|
||||||
|
|
||||||
// Top sizer
|
// Editing area
|
||||||
StartupLog(_T("Create subtitle editing box"));
|
StartupLog(_T("Create subtitle editing box"));
|
||||||
EditBox = new SubsEditBox(Panel,SubsGrid);
|
EditBox = new SubsEditBox(Panel,SubsGrid);
|
||||||
StartupLog(_T("Arrange controls in sizers"));
|
|
||||||
ToolSizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
ToolSizer->Add(audioBox,0,wxEXPAND | wxBOTTOM,5);
|
|
||||||
ToolSizer->Add(EditBox,1,wxEXPAND,5);
|
|
||||||
TopSizer->Add(ToolSizer,1,wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM,5);
|
|
||||||
|
|
||||||
// Set sizers/hints
|
// Set sizers/hints
|
||||||
StartupLog(_T("Arrange main sizers"));
|
StartupLog(_T("Arrange main sizers"));
|
||||||
|
ToolsSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
ToolsSizer->Add(audioSash, 0, wxEXPAND);
|
||||||
|
ToolsSizer->Add(EditBox, 1, wxEXPAND);
|
||||||
|
TopSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
TopSizer->Add(videoSizer, 0, wxEXPAND, 0);
|
||||||
|
TopSizer->Add(ToolsSizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
||||||
|
MainSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
MainSizer->Add(new wxStaticLine(Panel),0,wxEXPAND | wxALL,0);
|
MainSizer->Add(new wxStaticLine(Panel),0,wxEXPAND | wxALL,0);
|
||||||
MainSizer->Add(TopSizer,0,wxEXPAND | wxALL,0);
|
MainSizer->Add(TopSizer,0,wxEXPAND | wxALL,0);
|
||||||
MainSizer->Add(BottomSizer,1,wxEXPAND | wxALL,0);
|
MainSizer->Add(SubsGrid,1,wxEXPAND | wxALL,0);
|
||||||
Panel->SetSizer(MainSizer);
|
Panel->SetSizer(MainSizer);
|
||||||
//MainSizer->SetSizeHints(Panel);
|
//MainSizer->SetSizeHints(Panel);
|
||||||
//SetSizer(MainSizer);
|
//SetSizer(MainSizer);
|
||||||
|
@ -828,7 +845,7 @@ void FrameMain::SetDisplayMode(int video, int audio) {
|
||||||
else if (video) sv = VideoContext::Get()->IsLoaded() && !detachedVideo;
|
else if (video) sv = VideoContext::Get()->IsLoaded() && !detachedVideo;
|
||||||
|
|
||||||
if (audio == -1) sa = showAudio;
|
if (audio == -1) sa = showAudio;
|
||||||
else if (audio) sa = audioBox->loaded;
|
else if (audio) sa = audioController->IsAudioOpen();
|
||||||
|
|
||||||
// See if anything changed
|
// See if anything changed
|
||||||
if (sv == showVideo && sa == showAudio) return;
|
if (sv == showVideo && sa == showAudio) return;
|
||||||
|
@ -842,8 +859,8 @@ void FrameMain::SetDisplayMode(int video, int audio) {
|
||||||
VideoContext::Get()->Stop();
|
VideoContext::Get()->Stop();
|
||||||
|
|
||||||
// Set display
|
// Set display
|
||||||
TopSizer->Show(videoBox,showVideo,true);
|
TopSizer->Show(videoBox, showVideo, true);
|
||||||
ToolSizer->Show(audioBox,showAudio,true);
|
ToolsSizer->Show(audioSash, showAudio, true);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
UpdateToolbar();
|
UpdateToolbar();
|
||||||
|
@ -881,7 +898,7 @@ void FrameMain::UpdateTitle() {
|
||||||
else newTitle << _("untitled");
|
else newTitle << _("untitled");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __WXMAC__
|
#if defined(__WXMAC__) && !defined(__LP64__)
|
||||||
// On Mac, set the mark in the close button
|
// On Mac, set the mark in the close button
|
||||||
OSXSetModified(subsMod);
|
OSXSetModified(subsMod);
|
||||||
#endif
|
#endif
|
||||||
|
@ -914,19 +931,19 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
||||||
// Get new state info
|
// Get new state info
|
||||||
ass->GetScriptInfo(_T("Video Position")).ToLong(&videoPos);
|
ass->GetScriptInfo(_T("Video Position")).ToLong(&videoPos);
|
||||||
ass->GetScriptInfo(_T("Video Zoom Percent")).ToDouble(&videoZoom);
|
ass->GetScriptInfo(_T("Video Zoom Percent")).ToDouble(&videoZoom);
|
||||||
wxString curassVideo = DecodeRelativePath(ass->GetScriptInfo(_T("Video File")),ass->filename);
|
wxString curSubsVideo = DecodeRelativePath(ass->GetScriptInfo(_T("Video File")),ass->filename);
|
||||||
wxString curassVFR = DecodeRelativePath(ass->GetScriptInfo(_T("VFR File")),ass->filename);
|
wxString curSubsVFR = DecodeRelativePath(ass->GetScriptInfo(_T("VFR File")),ass->filename);
|
||||||
wxString curassKeyframes = DecodeRelativePath(ass->GetScriptInfo(_T("Keyframes File")),ass->filename);
|
wxString curSubsKeyframes = DecodeRelativePath(ass->GetScriptInfo(_T("Keyframes File")),ass->filename);
|
||||||
wxString curassAudio = DecodeRelativePath(ass->GetScriptInfo(_T("Audio File")),ass->filename);
|
wxString curSubsAudio = DecodeRelativePath(ass->GetScriptInfo(_T("Audio URI")),ass->filename);
|
||||||
wxString AutoScriptString = ass->GetScriptInfo(_T("Automation Scripts"));
|
wxString AutoScriptString = ass->GetScriptInfo(_T("Automation Scripts"));
|
||||||
|
|
||||||
// Check if there is anything to change
|
// Check if there is anything to change
|
||||||
int autoLoadMode = OPT_GET("App/Auto/Load Linked Files")->GetInt();
|
int autoLoadMode = OPT_GET("App/Auto/Load Linked Files")->GetInt();
|
||||||
bool hasToLoad = false;
|
bool hasToLoad = false;
|
||||||
if (curassAudio != audioBox->audioName ||
|
if (curSubsAudio !=audioController->GetAudioURL() ||
|
||||||
curassVFR != VideoContext::Get()->GetTimecodesName() ||
|
curSubsVFR != VideoContext::Get()->GetTimecodesName() ||
|
||||||
curassVideo != VideoContext::Get()->videoName ||
|
curSubsVideo != VideoContext::Get()->videoName ||
|
||||||
curassKeyframes != VideoContext::Get()->GetKeyFramesName()
|
curSubsKeyframes != VideoContext::Get()->GetKeyFramesName()
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
|| !AutoScriptString.IsEmpty() || local_scripts->GetScripts().size() > 0
|
|| !AutoScriptString.IsEmpty() || local_scripts->GetScripts().size() > 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -946,8 +963,8 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
||||||
|
|
||||||
if (doLoad) {
|
if (doLoad) {
|
||||||
// Video
|
// Video
|
||||||
if (curassVideo != VideoContext::Get()->videoName) {
|
if (curSubsVideo != VideoContext::Get()->videoName) {
|
||||||
LoadVideo(curassVideo);
|
LoadVideo(curSubsVideo);
|
||||||
if (VideoContext::Get()->IsLoaded()) {
|
if (VideoContext::Get()->IsLoaded()) {
|
||||||
VideoContext::Get()->SetAspectRatio(videoAr,videoArValue);
|
VideoContext::Get()->SetAspectRatio(videoAr,videoArValue);
|
||||||
videoBox->videoDisplay->SetZoom(videoZoom);
|
videoBox->videoDisplay->SetZoom(videoZoom);
|
||||||
|
@ -955,13 +972,12 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoContext::Get()->LoadTimecodes(curassVFR);
|
VideoContext::Get()->LoadTimecodes(curSubsVFR);
|
||||||
VideoContext::Get()->LoadKeyframes(curassKeyframes);
|
VideoContext::Get()->LoadKeyframes(curSubsKeyframes);
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
if (curassAudio != audioBox->audioName) {
|
if (curSubsAudio != audioController->GetAudioURL()) {
|
||||||
if (curassAudio == _T("?video")) LoadAudio(_T(""),true);
|
audioController->OpenAudio(curSubsAudio);
|
||||||
else LoadAudio(curassAudio);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automation scripts
|
// Automation scripts
|
||||||
|
@ -1019,7 +1035,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store audio data
|
// Store audio data
|
||||||
ass->SetScriptInfo(_T("Audio File"),MakeRelativePath(audioBox->audioName,ass->filename));
|
ass->SetScriptInfo(_T("Audio URI"),MakeRelativePath(audioController->GetAudioURL(),ass->filename));
|
||||||
|
|
||||||
// Store video data
|
// Store video data
|
||||||
ass->SetScriptInfo(_T("Video File"),MakeRelativePath(VideoContext::Get()->videoName,ass->filename));
|
ass->SetScriptInfo(_T("Video File"),MakeRelativePath(VideoContext::Get()->videoName,ass->filename));
|
||||||
|
@ -1124,31 +1140,6 @@ void FrameMain::LoadVideo(wxString file,bool autoload) {
|
||||||
Thaw();
|
Thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Loads audio
|
|
||||||
/// @param filename
|
|
||||||
/// @param FromVideo
|
|
||||||
void FrameMain::LoadAudio(wxString filename,bool FromVideo) {
|
|
||||||
if (blockAudioLoad) return;
|
|
||||||
VideoContext::Get()->Stop();
|
|
||||||
try {
|
|
||||||
audioBox->SetFile(filename,FromVideo);
|
|
||||||
SetDisplayMode(-1,1);
|
|
||||||
}
|
|
||||||
catch (const wchar_t *error) {
|
|
||||||
wxString err(error);
|
|
||||||
wxMessageBox(err, _T("Error opening audio file"), wxOK | wxICON_ERROR, this);
|
|
||||||
}
|
|
||||||
#ifdef WITH_AVISYNTH
|
|
||||||
catch (AvisynthError err) {
|
|
||||||
wxMessageBox (wxString(_T("AviSynth error: ")) + wxString(err.msg,wxConvUTF8), _T("Error loading audio"), wxOK | wxICON_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
catch (...) {
|
|
||||||
wxMessageBox(_T("Unknown error"), _T("Error opening audio file"), wxOK | wxICON_ERROR, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameMain::LoadVFR(wxString filename) {
|
void FrameMain::LoadVFR(wxString filename) {
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
VideoContext::Get()->CloseTimecodes();
|
VideoContext::Get()->CloseTimecodes();
|
||||||
|
@ -1208,7 +1199,7 @@ void FrameMain::SetAccelerators() {
|
||||||
|
|
||||||
// Medusa
|
// Medusa
|
||||||
bool medusaPlay = OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool();
|
bool medusaPlay = OPT_GET("Audio/Medusa Timing Hotkeys")->GetBool();
|
||||||
if (medusaPlay && audioBox->audioDisplay->loaded) {
|
if (medusaPlay && audioController->IsAudioOpen()) {
|
||||||
entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Play"),Medusa_Play));
|
entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Play"),Medusa_Play));
|
||||||
entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Stop"),Medusa_Stop));
|
entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Stop"),Medusa_Stop));
|
||||||
entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Play Before"),Medusa_Play_Before));
|
entry.push_back(Hotkeys.GetAccelerator(_T("Audio Medusa Play Before"),Medusa_Play_Before));
|
||||||
|
@ -1294,7 +1285,6 @@ bool FrameMain::LoadList(wxArrayString list) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set blocking
|
// Set blocking
|
||||||
blockAudioLoad = (audio != _T(""));
|
|
||||||
blockVideoLoad = (video != _T(""));
|
blockVideoLoad = (video != _T(""));
|
||||||
|
|
||||||
// Load files
|
// Load files
|
||||||
|
@ -1305,10 +1295,8 @@ bool FrameMain::LoadList(wxArrayString list) {
|
||||||
blockVideoLoad = false;
|
blockVideoLoad = false;
|
||||||
LoadVideo(video);
|
LoadVideo(video);
|
||||||
}
|
}
|
||||||
if (blockAudioLoad) {
|
if (!audio.IsEmpty())
|
||||||
blockAudioLoad = false;
|
audioController->OpenAudio(audio);
|
||||||
LoadAudio(audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
return ((subs != _T("")) || (audio != _T("")) || (video != _T("")));
|
return ((subs != _T("")) || (audio != _T("")) || (video != _T("")));
|
||||||
|
|
|
@ -43,9 +43,14 @@
|
||||||
#include <wx/menu.h>
|
#include <wx/menu.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
|
#include <wx/sashwin.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef AGI_AUDIO_CONTROLLER_INCLUDED
|
||||||
|
#error You must include "audio_controller.h" before "frame_main.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class AssFile;
|
class AssFile;
|
||||||
class VideoDisplay;
|
class VideoDisplay;
|
||||||
class VideoSlider;
|
class VideoSlider;
|
||||||
|
@ -57,6 +62,7 @@ class VideoBox;
|
||||||
class DialogDetachedVideo;
|
class DialogDetachedVideo;
|
||||||
class DialogStyling;
|
class DialogStyling;
|
||||||
class AegisubFileDropTarget;
|
class AegisubFileDropTarget;
|
||||||
|
class AudioController;
|
||||||
|
|
||||||
namespace Automation4 { class FeatureMacro; class ScriptManager; }
|
namespace Automation4 { class FeatureMacro; class ScriptManager; }
|
||||||
|
|
||||||
|
@ -67,7 +73,7 @@ namespace Automation4 { class FeatureMacro; class ScriptManager; }
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class FrameMain: public wxFrame {
|
class FrameMain: public wxFrame, private AudioControllerAudioEventListener {
|
||||||
friend class AegisubFileDropTarget;
|
friend class AegisubFileDropTarget;
|
||||||
friend class AegisubApp;
|
friend class AegisubApp;
|
||||||
friend class SubtitlesGrid;
|
friend class SubtitlesGrid;
|
||||||
|
@ -93,9 +99,6 @@ private:
|
||||||
wxTimer StatusClear;
|
wxTimer StatusClear;
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool blockAudioLoad;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
bool blockVideoLoad;
|
bool blockVideoLoad;
|
||||||
|
|
||||||
|
@ -184,6 +187,8 @@ private:
|
||||||
|
|
||||||
void OnVideoPlay(wxCommandEvent &event);
|
void OnVideoPlay(wxCommandEvent &event);
|
||||||
|
|
||||||
|
void OnAudioBoxResize(wxSashEvent &event);
|
||||||
|
|
||||||
void OnOpenRecentSubs (wxCommandEvent &event);
|
void OnOpenRecentSubs (wxCommandEvent &event);
|
||||||
void OnOpenRecentVideo (wxCommandEvent &event);
|
void OnOpenRecentVideo (wxCommandEvent &event);
|
||||||
void OnOpenRecentAudio (wxCommandEvent &event);
|
void OnOpenRecentAudio (wxCommandEvent &event);
|
||||||
|
@ -239,6 +244,7 @@ private:
|
||||||
void OnOpenAudio (wxCommandEvent &event);
|
void OnOpenAudio (wxCommandEvent &event);
|
||||||
void OnOpenAudioFromVideo (wxCommandEvent &event);
|
void OnOpenAudioFromVideo (wxCommandEvent &event);
|
||||||
void OnCloseAudio (wxCommandEvent &event);
|
void OnCloseAudio (wxCommandEvent &event);
|
||||||
|
void OnAudioDisplayMode (wxCommandEvent &event);
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void OnOpenDummyAudio(wxCommandEvent &event);
|
void OnOpenDummyAudio(wxCommandEvent &event);
|
||||||
void OnOpenDummyNoiseAudio(wxCommandEvent &event);
|
void OnOpenDummyNoiseAudio(wxCommandEvent &event);
|
||||||
|
@ -313,7 +319,6 @@ private:
|
||||||
void OnMedusaPrev(wxCommandEvent &event);
|
void OnMedusaPrev(wxCommandEvent &event);
|
||||||
|
|
||||||
void LoadVideo(wxString filename,bool autoload=false);
|
void LoadVideo(wxString filename,bool autoload=false);
|
||||||
void LoadAudio(wxString filename,bool FromVideo=false);
|
|
||||||
void LoadVFR(wxString filename);
|
void LoadVFR(wxString filename);
|
||||||
void LoadSubtitles(wxString filename,wxString charset=_T(""));
|
void LoadSubtitles(wxString filename,wxString charset=_T(""));
|
||||||
bool SaveSubtitles(bool saveas=false,bool withCharset=false);
|
bool SaveSubtitles(bool saveas=false,bool withCharset=false);
|
||||||
|
@ -322,21 +327,33 @@ private:
|
||||||
void RebuildRecentList(wxString listName,wxMenu *menu,int startID);
|
void RebuildRecentList(wxString listName,wxMenu *menu,int startID);
|
||||||
void SynchronizeProject(bool FromSubs=false);
|
void SynchronizeProject(bool FromSubs=false);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// AudioControllerAudioEventListener implementation
|
||||||
|
virtual void OnAudioOpen(AudioProvider *provider);
|
||||||
|
virtual void OnAudioClose();
|
||||||
|
virtual void OnPlaybackPosition(int64_t sample_position);
|
||||||
|
virtual void OnPlaybackStop();
|
||||||
|
|
||||||
|
|
||||||
void OnSubtitlesFileChanged();
|
void OnSubtitlesFileChanged();
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// DOCME
|
/// The subtitle editing area
|
||||||
SubtitlesGrid *SubsGrid;
|
SubtitlesGrid *SubsGrid;
|
||||||
|
|
||||||
/// DOCME
|
/// The subtitle editing textbox
|
||||||
SubsEditBox *EditBox;
|
SubsEditBox *EditBox;
|
||||||
|
|
||||||
/// DOCME
|
/// Sash for resizing the audio area
|
||||||
|
wxSashWindow *audioSash;
|
||||||
|
|
||||||
|
/// The audio area
|
||||||
AudioBox *audioBox;
|
AudioBox *audioBox;
|
||||||
|
|
||||||
/// DOCME
|
/// The video area
|
||||||
VideoBox *videoBox;
|
VideoBox *videoBox;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
@ -345,18 +362,19 @@ public:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
DialogStyling *stylingAssistant;
|
DialogStyling *stylingAssistant;
|
||||||
|
|
||||||
|
/// The audio controller for the open project
|
||||||
|
AudioController *audioController;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
|
/// Arranges things from top to bottom in the window
|
||||||
wxBoxSizer *MainSizer;
|
wxBoxSizer *MainSizer;
|
||||||
|
|
||||||
/// DOCME
|
/// Arranges video box and tool box from left to right
|
||||||
wxBoxSizer *TopSizer;
|
wxBoxSizer *TopSizer;
|
||||||
|
|
||||||
/// DOCME
|
/// Arranges audio and editing areas top to bottom
|
||||||
wxBoxSizer *BottomSizer;
|
wxBoxSizer *ToolsSizer;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxBoxSizer *ToolSizer;
|
|
||||||
|
|
||||||
FrameMain (wxArrayString args);
|
FrameMain (wxArrayString args);
|
||||||
~FrameMain ();
|
~FrameMain ();
|
||||||
|
@ -435,6 +453,9 @@ enum {
|
||||||
Menu_Audio_Open_File,
|
Menu_Audio_Open_File,
|
||||||
Menu_Audio_Open_From_Video,
|
Menu_Audio_Open_From_Video,
|
||||||
Menu_Audio_Close,
|
Menu_Audio_Close,
|
||||||
|
|
||||||
|
Menu_Audio_Spectrum,
|
||||||
|
Menu_Audio_Waveform,
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Menu_Audio_Open_Dummy,
|
Menu_Audio_Open_Dummy,
|
||||||
Menu_Audio_Open_Dummy_Noise,
|
Menu_Audio_Open_Dummy_Noise,
|
||||||
|
@ -503,6 +524,12 @@ enum {
|
||||||
AutoSave_Timer,
|
AutoSave_Timer,
|
||||||
StatusClear_Timer,
|
StatusClear_Timer,
|
||||||
|
|
||||||
|
|
||||||
|
/// Id for the audio box resizing sash
|
||||||
|
Main_AudioSash,
|
||||||
|
|
||||||
|
|
||||||
|
/// DOCME
|
||||||
Video_Next_Frame,
|
Video_Next_Frame,
|
||||||
Video_Prev_Frame,
|
Video_Prev_Frame,
|
||||||
Video_Focus_Seek,
|
Video_Focus_Seek,
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
#include "audio_display.h"
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
|
@ -84,6 +86,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "standard_paths.h"
|
#include "standard_paths.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
|
@ -104,6 +107,8 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame)
|
||||||
|
|
||||||
EVT_CLOSE(FrameMain::OnCloseWindow)
|
EVT_CLOSE(FrameMain::OnCloseWindow)
|
||||||
|
|
||||||
|
EVT_SASH_DRAGGED(Main_AudioSash, FrameMain::OnAudioBoxResize)
|
||||||
|
|
||||||
EVT_MENU_OPEN(FrameMain::OnMenuOpen)
|
EVT_MENU_OPEN(FrameMain::OnMenuOpen)
|
||||||
EVT_MENU_RANGE(Menu_File_Recent,Menu_File_Recent+99, FrameMain::OnOpenRecentSubs)
|
EVT_MENU_RANGE(Menu_File_Recent,Menu_File_Recent+99, FrameMain::OnOpenRecentSubs)
|
||||||
EVT_MENU_RANGE(Menu_Video_Recent,Menu_Video_Recent+99, FrameMain::OnOpenRecentVideo)
|
EVT_MENU_RANGE(Menu_Video_Recent,Menu_Video_Recent+99, FrameMain::OnOpenRecentVideo)
|
||||||
|
@ -155,6 +160,8 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame)
|
||||||
EVT_MENU(Menu_Audio_Open_File, FrameMain::OnOpenAudio)
|
EVT_MENU(Menu_Audio_Open_File, FrameMain::OnOpenAudio)
|
||||||
EVT_MENU(Menu_Audio_Open_From_Video, FrameMain::OnOpenAudioFromVideo)
|
EVT_MENU(Menu_Audio_Open_From_Video, FrameMain::OnOpenAudioFromVideo)
|
||||||
EVT_MENU(Menu_Audio_Close, FrameMain::OnCloseAudio)
|
EVT_MENU(Menu_Audio_Close, FrameMain::OnCloseAudio)
|
||||||
|
EVT_MENU(Menu_Audio_Spectrum, FrameMain::OnAudioDisplayMode)
|
||||||
|
EVT_MENU(Menu_Audio_Waveform, FrameMain::OnAudioDisplayMode)
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
EVT_MENU(Menu_Audio_Open_Dummy, FrameMain::OnOpenDummyAudio)
|
EVT_MENU(Menu_Audio_Open_Dummy, FrameMain::OnOpenDummyAudio)
|
||||||
EVT_MENU(Menu_Audio_Open_Dummy_Noise, FrameMain::OnOpenDummyNoiseAudio)
|
EVT_MENU(Menu_Audio_Open_Dummy_Noise, FrameMain::OnOpenDummyNoiseAudio)
|
||||||
|
@ -294,7 +301,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
|
||||||
// View menu
|
// View menu
|
||||||
else if (curMenu == viewMenu) {
|
else if (curMenu == viewMenu) {
|
||||||
// Flags
|
// Flags
|
||||||
bool aud = audioBox->audioDisplay->loaded;
|
bool aud = audioController->IsAudioOpen();
|
||||||
bool vid = VideoContext::Get()->IsLoaded() && !detachedVideo;
|
bool vid = VideoContext::Get()->IsLoaded() && !detachedVideo;
|
||||||
|
|
||||||
// Set states
|
// Set states
|
||||||
|
@ -365,12 +372,16 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
|
||||||
|
|
||||||
// Audio menu
|
// Audio menu
|
||||||
else if (curMenu == audioMenu) {
|
else if (curMenu == audioMenu) {
|
||||||
bool state = audioBox->loaded;
|
bool state = audioController->IsAudioOpen();
|
||||||
bool vidstate = VideoContext::Get()->IsLoaded();
|
bool vidstate = VideoContext::Get()->IsLoaded();
|
||||||
|
|
||||||
MenuBar->Enable(Menu_Audio_Open_From_Video,vidstate);
|
MenuBar->Enable(Menu_Audio_Open_From_Video,vidstate);
|
||||||
MenuBar->Enable(Menu_Audio_Close,state);
|
MenuBar->Enable(Menu_Audio_Close,state);
|
||||||
|
|
||||||
|
bool spectrum_enabled = OPT_GET("Audio/Spectrum")->GetBool();
|
||||||
|
MenuBar->Check(Menu_Audio_Spectrum, spectrum_enabled);
|
||||||
|
MenuBar->Check(Menu_Audio_Waveform, !spectrum_enabled);
|
||||||
|
|
||||||
// Rebuild recent
|
// Rebuild recent
|
||||||
RebuildRecentList(_T("Audio"),RecentAuds,Menu_Audio_Recent);
|
RebuildRecentList(_T("Audio"),RecentAuds,Menu_Audio_Recent);
|
||||||
}
|
}
|
||||||
|
@ -541,7 +552,7 @@ void FrameMain::OnOpenRecentKeyframes(wxCommandEvent &event) {
|
||||||
/// @brief Open recent audio menu entry
|
/// @brief Open recent audio menu entry
|
||||||
/// @param event
|
/// @param event
|
||||||
void FrameMain::OnOpenRecentAudio(wxCommandEvent &event) {
|
void FrameMain::OnOpenRecentAudio(wxCommandEvent &event) {
|
||||||
LoadAudio(lagi_wxString(config::mru->GetEntry("Audio", event.GetId()-Menu_Audio_Recent)));
|
audioController->OpenAudio(lagi_wxString(config::mru->GetEntry("Audio", event.GetId()-Menu_Audio_Recent)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Open new Window
|
/// @brief Open new Window
|
||||||
|
@ -650,31 +661,40 @@ void FrameMain::OnOpenAudio (wxCommandEvent&) {
|
||||||
+ _("All files") + _T(" (*.*)|*.*");
|
+ _("All files") + _T(" (*.*)|*.*");
|
||||||
wxString filename = wxFileSelector(_("Open audio file"),path,_T(""),_T(""),str,wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
wxString filename = wxFileSelector(_("Open audio file"),path,_T(""),_T(""),str,wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
LoadAudio(filename);
|
audioController->OpenAudio(filename);
|
||||||
OPT_SET("Path/Last/Audio")->SetString(STD_STR(filename));
|
OPT_SET("Path/Last/Audio")->SetString(STD_STR(filename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnOpenAudioFromVideo (wxCommandEvent&) {
|
void FrameMain::OnOpenAudioFromVideo (wxCommandEvent&) {
|
||||||
LoadAudio(_T(""),true);
|
audioController->OpenAudio(_T("audio-video:cache"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnCloseAudio (wxCommandEvent&) {
|
void FrameMain::OnCloseAudio (wxCommandEvent&) {
|
||||||
LoadAudio(_T(""));
|
audioController->CloseAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Event handler for audio display renderer selection menu options
|
||||||
|
/// @param event wxWidgets event object
|
||||||
|
void FrameMain::OnAudioDisplayMode (wxCommandEvent &event) {
|
||||||
|
OPT_SET("Audio/Spectrum")->SetBool(event.GetId() == Menu_Audio_Spectrum);
|
||||||
|
/// @todo Remove this reload call when the audio display starts listening for option changes
|
||||||
|
audioBox->audioDisplay->ReloadRenderingSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnOpenDummyAudio (wxCommandEvent&) {
|
void FrameMain::OnOpenDummyAudio (wxCommandEvent&) {
|
||||||
LoadAudio(_T("?dummy"));
|
audioController->OpenAudio(_T("dummy-audio:silence?sr=44100&bd=16&ch=1&ln=396900000"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnOpenDummyNoiseAudio (wxCommandEvent&) {
|
void FrameMain::OnOpenDummyNoiseAudio (wxCommandEvent&) {
|
||||||
LoadAudio(_T("?noise"));
|
audioController->OpenAudio(_T("dummy-audio:noise?sr=44100&bd=16&ch=1&ln=396900000"));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1245,7 +1265,7 @@ void FrameMain::OnSetARCustom (wxCommandEvent &) {
|
||||||
void FrameMain::OnCloseWindow (wxCloseEvent &event) {
|
void FrameMain::OnCloseWindow (wxCloseEvent &event) {
|
||||||
// Stop audio and video
|
// Stop audio and video
|
||||||
VideoContext::Get()->Stop();
|
VideoContext::Get()->Stop();
|
||||||
audioBox->audioDisplay->Stop();
|
audioController->Stop();
|
||||||
|
|
||||||
// Ask user if he wants to save first
|
// Ask user if he wants to save first
|
||||||
bool canVeto = event.CanVeto();
|
bool canVeto = event.CanVeto();
|
||||||
|
@ -1465,6 +1485,7 @@ void FrameMain::OnChooseLanguage (wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief View standard
|
/// @brief View standard
|
||||||
void FrameMain::OnViewStandard (wxCommandEvent &) {
|
void FrameMain::OnViewStandard (wxCommandEvent &) {
|
||||||
|
if (!audioController->IsAudioOpen() || !VideoContext::Get()->IsLoaded()) return;
|
||||||
SetDisplayMode(1,1);
|
SetDisplayMode(1,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,6 +1496,7 @@ void FrameMain::OnViewVideo (wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief View audio
|
/// @brief View audio
|
||||||
void FrameMain::OnViewAudio (wxCommandEvent &) {
|
void FrameMain::OnViewAudio (wxCommandEvent &) {
|
||||||
|
if (!audioController->IsAudioOpen()) return;
|
||||||
SetDisplayMode(0,1);
|
SetDisplayMode(0,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1485,82 +1507,132 @@ void FrameMain::OnViewSubs (wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief Medusa shortcuts
|
/// @brief Medusa shortcuts
|
||||||
void FrameMain::OnMedusaPlay(wxCommandEvent &) {
|
void FrameMain::OnMedusaPlay(wxCommandEvent &) {
|
||||||
int start=0,end=0;
|
audioController->PlayPrimaryRange();
|
||||||
audioBox->audioDisplay->GetTimesSelection(start,end);
|
|
||||||
audioBox->audioDisplay->Play(start,end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaStop(wxCommandEvent &) {
|
void FrameMain::OnMedusaStop(wxCommandEvent &) {
|
||||||
// Playing, stop
|
// Playing, stop
|
||||||
if (audioBox->audioDisplay->player->IsPlaying()) {
|
if (audioController->IsPlaying()) {
|
||||||
audioBox->audioDisplay->Stop();
|
audioController->Stop();
|
||||||
audioBox->audioDisplay->Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, play the last 500 ms
|
// Otherwise, play the last 500 ms
|
||||||
else {
|
else {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
||||||
audioBox->audioDisplay->GetTimesSelection(start,end);
|
audioController->PlayRange(AudioController::SampleRange(
|
||||||
audioBox->audioDisplay->Play(end-500,end);
|
sel.end() - audioController->SamplesFromMilliseconds(500),
|
||||||
|
sel.end()));;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->curStartMS += 10;
|
AudioController::SampleRange newsel(
|
||||||
audioBox->audioDisplay->Update();
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
audioBox->audioDisplay->wxWindow::Update();
|
audioController->SamplesFromMilliseconds(10),
|
||||||
|
0);
|
||||||
|
/// @todo Make this use the timing controller instead
|
||||||
|
//audioController->SetSelection(newsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->curStartMS -= 10;
|
AudioController::SampleRange newsel(
|
||||||
audioBox->audioDisplay->Update();
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
audioBox->audioDisplay->wxWindow::Update();
|
-audioController->SamplesFromMilliseconds(10),
|
||||||
|
0);
|
||||||
|
/// @todo Make this use the timing controller instead
|
||||||
|
//audioController->SetSelection(newsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->curEndMS += 10;
|
AudioController::SampleRange newsel(
|
||||||
audioBox->audioDisplay->Update();
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
audioBox->audioDisplay->wxWindow::Update();
|
0,
|
||||||
|
audioController->SamplesFromMilliseconds(10));
|
||||||
|
/// @todo Make this use the timing controller instead
|
||||||
|
//audioController->SetSelection(newsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->curEndMS -= 10;
|
AudioController::SampleRange newsel(
|
||||||
audioBox->audioDisplay->Update();
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
audioBox->audioDisplay->wxWindow::Update();
|
0,
|
||||||
|
-audioController->SamplesFromMilliseconds(10));
|
||||||
|
/// @todo Make this use the timing controller instead
|
||||||
|
//audioController->SetSelection(newsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaPlayBefore(wxCommandEvent &) {
|
void FrameMain::OnMedusaPlayBefore(wxCommandEvent &) {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
||||||
audioBox->audioDisplay->GetTimesSelection(start,end);
|
audioController->PlayRange(AudioController::SampleRange(
|
||||||
audioBox->audioDisplay->Play(start-500,start);
|
sel.begin() - audioController->SamplesFromMilliseconds(500),
|
||||||
|
sel.begin()));;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaPlayAfter(wxCommandEvent &) {
|
void FrameMain::OnMedusaPlayAfter(wxCommandEvent &) {
|
||||||
int start=0,end=0;
|
AudioController::SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
||||||
audioBox->audioDisplay->GetTimesSelection(start,end);
|
audioController->PlayRange(AudioController::SampleRange(
|
||||||
audioBox->audioDisplay->Play(end,end+500);
|
sel.end(),
|
||||||
|
sel.end() + audioController->SamplesFromMilliseconds(500)));;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaNext(wxCommandEvent &) {
|
void FrameMain::OnMedusaNext(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->Next(false);
|
/// @todo Figure out how to handle this in the audio controller
|
||||||
|
//audioBox->audioDisplay->Next(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaPrev(wxCommandEvent &) {
|
void FrameMain::OnMedusaPrev(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->Prev(false);
|
/// @todo Figure out how to handle this in the audio controller
|
||||||
|
//audioBox->audioDisplay->Prev(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaEnter(wxCommandEvent &) {
|
void FrameMain::OnMedusaEnter(wxCommandEvent &) {
|
||||||
audioBox->audioDisplay->CommitChanges(true);
|
/// @todo Figure out how to handle this in the audio controller
|
||||||
|
//audioBox->audioDisplay->CommitChanges(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameMain::OnAudioBoxResize(wxSashEvent &event)
|
||||||
|
{
|
||||||
|
if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxRect rect = event.GetDragRect();
|
||||||
|
|
||||||
|
if (rect.GetHeight() < audioSash->GetMinimumSizeY())
|
||||||
|
rect.SetHeight(audioSash->GetMinimumSizeY());
|
||||||
|
|
||||||
|
audioBox->SetMinSize(wxSize(-1, rect.GetHeight()));
|
||||||
|
Panel->Layout();
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameMain::OnAudioOpen(AudioProvider *provider)
|
||||||
|
{
|
||||||
|
SetDisplayMode(-1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameMain::OnAudioClose()
|
||||||
|
{
|
||||||
|
SetDisplayMode(-1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameMain::OnPlaybackPosition(int64_t sample_position)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameMain::OnPlaybackStop()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameMain::OnSubtitlesFileChanged() {
|
void FrameMain::OnSubtitlesFileChanged() {
|
||||||
|
@ -1570,3 +1642,4 @@ void FrameMain::OnSubtitlesFileChanged() {
|
||||||
|
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,17 +79,15 @@ public:
|
||||||
virtual ~AudioProvider();
|
virtual ~AudioProvider();
|
||||||
|
|
||||||
virtual wxString GetFilename() const { return filename; };
|
virtual wxString GetFilename() const { return filename; };
|
||||||
virtual void GetAudio(void *buf, int64_t start, int64_t count)=0;
|
virtual void GetAudio(void *buf, int64_t start, int64_t count) const = 0;
|
||||||
void GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume);
|
void GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const;
|
||||||
|
|
||||||
int64_t GetNumSamples() const { return num_samples; }
|
int64_t GetNumSamples() const { return num_samples; }
|
||||||
int GetSampleRate() const { return sample_rate; }
|
int GetSampleRate() const { return sample_rate; }
|
||||||
int GetBytesPerSample() const { return bytes_per_sample; }
|
int GetBytesPerSample() const { return bytes_per_sample; }
|
||||||
int GetChannels() const { return channels; }
|
int GetChannels() const { return channels; }
|
||||||
virtual bool AreSamplesNativeEndian() const = 0;
|
virtual bool AreSamplesNativeEndian() const = 0;
|
||||||
|
|
||||||
void GetWaveForm(int *min,int *peak,int64_t start,int w,int h,int samples,float scale);
|
|
||||||
|
|
||||||
/// @brief Does this provider benefit from external caching?
|
/// @brief Does this provider benefit from external caching?
|
||||||
virtual bool NeedsCache() const { return false; }
|
virtual bool NeedsCache() const { return false; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,8 +54,9 @@
|
||||||
#include "ass_export_filter.h"
|
#include "ass_export_filter.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_time.h"
|
#include "ass_time.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
#include "auto4_base.h"
|
#include "auto4_base.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -68,7 +69,6 @@
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "plugin_manager.h"
|
#include "plugin_manager.h"
|
||||||
#include "standard_paths.h"
|
#include "standard_paths.h"
|
||||||
#include "subs_grid.h"
|
|
||||||
#include "subtitle_format.h"
|
#include "subtitle_format.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
|
@ -551,13 +551,14 @@ END_EVENT_TABLE()
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AegisubApp::OnMouseWheel(wxMouseEvent &event) {
|
void AegisubApp::OnMouseWheel(wxMouseEvent &event) {
|
||||||
|
if (event.WasProcessed()) return;
|
||||||
wxPoint pt;
|
wxPoint pt;
|
||||||
wxWindow *target = wxFindWindowAtPointer(pt);
|
wxWindow *target = wxFindWindowAtPointer(pt);
|
||||||
if (frame && (target == frame->audioBox->audioDisplay || target == frame->SubsGrid)) {
|
/*if (frame && (target == frame->audioBox->audioDisplay || target == frame->SubsGrid)) {
|
||||||
if (target->IsShownOnScreen()) target->GetEventHandler()->ProcessEvent(event);
|
if (target->IsShownOnScreen()) target->GetEventHandler()->ProcessEvent(event);
|
||||||
else event.Skip();
|
else event.Skip();
|
||||||
}
|
}
|
||||||
else event.Skip();
|
else event.Skip();*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,4 @@
|
||||||
#pragma comment(lib, "libass.lib")
|
#pragma comment(lib, "libass.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // VisualC
|
#endif // VisualC
|
||||||
|
|
||||||
|
|
|
@ -58,12 +58,13 @@
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
#include "audio_display.h"
|
#include "audio_controller.h"
|
||||||
#include "dialog_colorpicker.h"
|
#include "dialog_colorpicker.h"
|
||||||
#include "dialog_search_replace.h"
|
#include "dialog_search_replace.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
|
|
|
@ -55,6 +55,7 @@ class wxSpinCtrl;
|
||||||
class wxStyledTextCtrl;
|
class wxStyledTextCtrl;
|
||||||
class wxStyledTextEvent;
|
class wxStyledTextEvent;
|
||||||
class wxTextCtrl;
|
class wxTextCtrl;
|
||||||
|
class AudioController;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class SubsEditBox
|
/// @class SubsEditBox
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "include/aegisub/spellchecker.h"
|
#include "include/aegisub/spellchecker.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
|
|
|
@ -51,8 +51,10 @@
|
||||||
#include "ass_karaoke.h"
|
#include "ass_karaoke.h"
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#include "audio_display.h"
|
|
||||||
#include "charset_conv.h"
|
#include "charset_conv.h"
|
||||||
#include "dialog_paste_over.h"
|
#include "dialog_paste_over.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
@ -204,7 +206,7 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) {
|
||||||
menu.AppendSeparator();
|
menu.AppendSeparator();
|
||||||
|
|
||||||
//Make audio clip
|
//Make audio clip
|
||||||
state = parentFrame->audioBox->audioDisplay->loaded==true;
|
state = parentFrame->audioController->IsAudioOpen()==true;
|
||||||
menu.Append(MENU_AUDIOCLIP,_("Create audio clip"),_("Create an audio clip of the selected line"))->Enable(state);
|
menu.Append(MENU_AUDIOCLIP,_("Create audio clip"),_("Create an audio clip of the selected line"))->Enable(state);
|
||||||
menu.AppendSeparator();
|
menu.AppendSeparator();
|
||||||
|
|
||||||
|
@ -646,8 +648,8 @@ void SubtitlesGrid::OnRecombine(wxCommandEvent &) {
|
||||||
/// @brief Export audio clip of line
|
/// @brief Export audio clip of line
|
||||||
void SubtitlesGrid::OnAudioClip(wxCommandEvent &) {
|
void SubtitlesGrid::OnAudioClip(wxCommandEvent &) {
|
||||||
int64_t num_samples,start=0,end=0,temp;
|
int64_t num_samples,start=0,end=0,temp;
|
||||||
AudioDisplay *audioDisplay = parentFrame->audioBox->audioDisplay;
|
AudioController *audioController = parentFrame->audioController;
|
||||||
AudioProvider *provider = audioDisplay->provider;
|
const AudioProvider *provider = audioController->GetAudioProvider();
|
||||||
AssDialogue *cur;
|
AssDialogue *cur;
|
||||||
wxArrayInt sel = GetSelection();
|
wxArrayInt sel = GetSelection();
|
||||||
|
|
||||||
|
@ -656,9 +658,9 @@ void SubtitlesGrid::OnAudioClip(wxCommandEvent &) {
|
||||||
for(unsigned int i=0;i!=sel.GetCount();i++) {
|
for(unsigned int i=0;i!=sel.GetCount();i++) {
|
||||||
cur = GetDialogue(sel[i]);
|
cur = GetDialogue(sel[i]);
|
||||||
|
|
||||||
temp = audioDisplay->GetSampleAtMS(cur->Start.GetMS());
|
temp = audioController->SamplesFromMilliseconds(cur->Start.GetMS());
|
||||||
start = (i==0||temp<start)?temp:start;
|
start = (i==0||temp<start)?temp:start;
|
||||||
temp = audioDisplay->GetSampleAtMS(cur->End.GetMS());
|
temp = audioController->SamplesFromMilliseconds(cur->End.GetMS());
|
||||||
end = (i==0||temp>end)?temp:end;
|
end = (i==0||temp>end)?temp:end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "dialog_progress.h"
|
#include "dialog_progress.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -70,6 +70,10 @@ int AegiStringToFix(const wxString &str,size_t decimalPlaces,int start=0,int end
|
||||||
wxIcon BitmapToIcon(wxBitmap bmp);
|
wxIcon BitmapToIcon(wxBitmap bmp);
|
||||||
void RestartAegisub();
|
void RestartAegisub();
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Templated abs() function
|
||||||
|
template <typename T> T tabs(T x) { return x < 0 ? -x : x; }
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a,b) ((a)<(b))?(a):(b)
|
#define MIN(a,b) ((a)<(b))?(a):(b)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,10 +45,12 @@
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "audio_controller.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "toggle_bitmap.h"
|
#include "toggle_bitmap.h"
|
||||||
|
|
|
@ -53,11 +53,13 @@
|
||||||
#include <GL/glu.h>
|
#include <GL/glu.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "include/aegisub/audio_player.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
#include "ass_time.h"
|
#include "ass_time.h"
|
||||||
#include "audio_display.h"
|
#include "audio_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "include/aegisub/audio_player.h"
|
#include "include/aegisub/audio_player.h"
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
|
@ -67,6 +69,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mkv_wrap.h"
|
#include "mkv_wrap.h"
|
||||||
#include "standard_paths.h"
|
#include "standard_paths.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "threaded_frame_source.h"
|
#include "threaded_frame_source.h"
|
||||||
|
@ -119,10 +122,6 @@ VideoContext::VideoContext()
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoContext::~VideoContext () {
|
VideoContext::~VideoContext () {
|
||||||
if (audio && audio->temporary) {
|
|
||||||
delete audio->provider;
|
|
||||||
delete audio->player;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoContext *VideoContext::Get() {
|
VideoContext *VideoContext::Get() {
|
||||||
|
@ -135,15 +134,7 @@ void VideoContext::Reset() {
|
||||||
|
|
||||||
keyFrames.clear();
|
keyFrames.clear();
|
||||||
videoFPS = agi::vfr::Framerate();
|
videoFPS = agi::vfr::Framerate();
|
||||||
|
keyframesRevision++;
|
||||||
// Remove temporary audio provider
|
|
||||||
if (audio && audio->temporary) {
|
|
||||||
delete audio->provider;
|
|
||||||
audio->provider = NULL;
|
|
||||||
delete audio->player;
|
|
||||||
audio->player = NULL;
|
|
||||||
audio->temporary = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove video data
|
// Remove video data
|
||||||
frame_n = 0;
|
frame_n = 0;
|
||||||
|
@ -316,8 +307,11 @@ void VideoContext::PlayNextFrame() {
|
||||||
int thisFrame = frame_n;
|
int thisFrame = frame_n;
|
||||||
JumpToFrame(frame_n + 1);
|
JumpToFrame(frame_n + 1);
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
if (playAudioOnStep->GetBool())
|
if (playAudioOnStep->GetBool()) {
|
||||||
audio->Play(TimeAtFrame(thisFrame),TimeAtFrame(thisFrame + 1));
|
audio->PlayRange(AudioController::SampleRange(
|
||||||
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame)),
|
||||||
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame + 1))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::PlayPrevFrame() {
|
void VideoContext::PlayPrevFrame() {
|
||||||
|
@ -327,8 +321,11 @@ void VideoContext::PlayPrevFrame() {
|
||||||
int thisFrame = frame_n;
|
int thisFrame = frame_n;
|
||||||
JumpToFrame(frame_n -1);
|
JumpToFrame(frame_n -1);
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
if (playAudioOnStep->GetBool())
|
if (playAudioOnStep->GetBool()) {
|
||||||
audio->Play(TimeAtFrame(thisFrame - 1),TimeAtFrame(thisFrame));
|
audio->PlayRange(AudioController::SampleRange(
|
||||||
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame - 1)),
|
||||||
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::Play() {
|
void VideoContext::Play() {
|
||||||
|
@ -342,7 +339,7 @@ void VideoContext::Play() {
|
||||||
endFrame = -1;
|
endFrame = -1;
|
||||||
|
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
audio->Play(TimeAtFrame(startFrame),-1);
|
audio->PlayToEnd(audio->SamplesFromMilliseconds(TimeAtFrame(startFrame)));
|
||||||
|
|
||||||
//audio->Play will override this if we put it before, so put it after.
|
//audio->Play will override this if we put it before, so put it after.
|
||||||
isPlaying = true;
|
isPlaying = true;
|
||||||
|
@ -358,7 +355,9 @@ void VideoContext::PlayLine() {
|
||||||
if (!curline) return;
|
if (!curline) return;
|
||||||
|
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
audio->Play(curline->Start.GetMS(),curline->End.GetMS());
|
audio->PlayRange(AudioController::SampleRange(
|
||||||
|
audio->SamplesFromMilliseconds(curline->Start.GetMS()),
|
||||||
|
audio->SamplesFromMilliseconds(curline->End.GetMS())));
|
||||||
|
|
||||||
// Set variables
|
// Set variables
|
||||||
isPlaying = true;
|
isPlaying = true;
|
||||||
|
@ -417,7 +416,9 @@ void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
||||||
if (nextFrame == frame_n) return;
|
if (nextFrame == frame_n) return;
|
||||||
|
|
||||||
// Next frame is before or over 2 frames ahead, so force audio resync
|
// Next frame is before or over 2 frames ahead, so force audio resync
|
||||||
if (audio->player && keepAudioSync && (nextFrame < frame_n || nextFrame > frame_n + 2)) audio->player->SetCurrentPosition(audio->GetSampleAtMS(TimeAtFrame(nextFrame)));
|
if (audio->IsPlaying() && keepAudioSync && (nextFrame < frame_n || nextFrame > frame_n + 2)) {
|
||||||
|
audio->ResyncPlaybackPosition(audio->SamplesFromMilliseconds(TimeAtFrame(nextFrame)));
|
||||||
|
}
|
||||||
|
|
||||||
// Jump to next frame
|
// Jump to next frame
|
||||||
playNextFrame = nextFrame;
|
playNextFrame = nextFrame;
|
||||||
|
@ -425,13 +426,13 @@ void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
||||||
JumpToFrame(nextFrame);
|
JumpToFrame(nextFrame);
|
||||||
|
|
||||||
// Sync audio
|
// Sync audio
|
||||||
if (keepAudioSync && nextFrame % 10 == 0 && audio && audio->provider && audio->player) {
|
if (keepAudioSync && nextFrame % 10 == 0 && audio->IsPlaying()) {
|
||||||
int64_t audPos = audio->GetSampleAtMS(TimeAtFrame(nextFrame));
|
int64_t audPos = audio->SamplesFromMilliseconds(TimeAtFrame(nextFrame));
|
||||||
int64_t curPos = audio->player->GetCurrentPosition();
|
int64_t curPos = audio->GetPlaybackPosition();
|
||||||
int delta = int(audPos-curPos);
|
int delta = int(audPos-curPos);
|
||||||
if (delta < 0) delta = -delta;
|
if (delta < 0) delta = -delta;
|
||||||
int maxDelta = audio->provider->GetSampleRate();
|
int maxDelta = audio->SamplesFromMilliseconds(1000);
|
||||||
if (delta > maxDelta) audio->player->SetCurrentPosition(audPos);
|
if (delta > maxDelta) audio->ResyncPlaybackPosition(audPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,10 +469,12 @@ void VideoContext::LoadKeyframes(wxString filename) {
|
||||||
catch (...) {
|
catch (...) {
|
||||||
wxMessageBox(_T("Unknown error"), _T("Error opening keyframes file"), wxOK | wxICON_ERROR, NULL);
|
wxMessageBox(_T("Unknown error"), _T("Error opening keyframes file"), wxOK | wxICON_ERROR, NULL);
|
||||||
}
|
}
|
||||||
|
keyframesRevision++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::SaveKeyframes(wxString filename) {
|
void VideoContext::SaveKeyframes(wxString filename) {
|
||||||
KeyFrameFile::Save(filename, GetKeyFrames());
|
KeyFrameFile::Save(filename, GetKeyFrames());
|
||||||
|
keyframesRevision++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::CloseKeyframes() {
|
void VideoContext::CloseKeyframes() {
|
||||||
|
@ -483,6 +486,7 @@ void VideoContext::CloseKeyframes() {
|
||||||
keyFrames.clear();
|
keyFrames.clear();
|
||||||
}
|
}
|
||||||
KeyframesOpen(keyFrames);
|
KeyframesOpen(keyFrames);
|
||||||
|
keyframesRevision++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::LoadTimecodes(wxString filename) {
|
void VideoContext::LoadTimecodes(wxString filename) {
|
||||||
|
|
|
@ -62,6 +62,7 @@ class SubtitlesProviderErrorEvent;
|
||||||
class ThreadedFrameSource;
|
class ThreadedFrameSource;
|
||||||
class VideoProvider;
|
class VideoProvider;
|
||||||
class VideoProviderErrorEvent;
|
class VideoProviderErrorEvent;
|
||||||
|
class AudioController;
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
class OptionValue;
|
class OptionValue;
|
||||||
|
@ -101,6 +102,10 @@ private:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxString keyFramesFilename;
|
wxString keyFramesFilename;
|
||||||
|
|
||||||
|
/// Revision counter for keyframes, when the set of keyframes is changed this number changes
|
||||||
|
int keyframesRevision;
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxMutex playMutex;
|
wxMutex playMutex;
|
||||||
|
|
||||||
|
@ -161,8 +166,8 @@ public:
|
||||||
/// File name of currently open video, if any
|
/// File name of currently open video, if any
|
||||||
wxString videoName;
|
wxString videoName;
|
||||||
|
|
||||||
/// DOCME
|
/// The audio controller for this video context
|
||||||
AudioDisplay *audio;
|
AudioController *audio;
|
||||||
|
|
||||||
const agi::vfr::Framerate &VFR_Input;
|
const agi::vfr::Framerate &VFR_Input;
|
||||||
const agi::vfr::Framerate &VFR_Output;
|
const agi::vfr::Framerate &VFR_Output;
|
||||||
|
@ -265,6 +270,7 @@ public:
|
||||||
void CloseKeyframes();
|
void CloseKeyframes();
|
||||||
bool OverKeyFramesLoaded() const { return !keyFramesFilename.empty(); }
|
bool OverKeyFramesLoaded() const { return !keyFramesFilename.empty(); }
|
||||||
bool KeyFramesLoaded() const { return !keyFrames.empty(); }
|
bool KeyFramesLoaded() const { return !keyFrames.empty(); }
|
||||||
|
int GetKeyframesRevision() const { return keyframesRevision; }
|
||||||
|
|
||||||
wxString GetTimecodesName() const { return ovrTimecodeFile; }
|
wxString GetTimecodesName() const { return ovrTimecodeFile; }
|
||||||
void LoadTimecodes(wxString filename);
|
void LoadTimecodes(wxString filename);
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "video_display.h"
|
#include "video_display.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
#include "ass_time.h"
|
#include "ass_time.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_box.h"
|
#include "subs_edit_box.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
|
|
Loading…
Reference in a new issue