1 #include "core/inthread.hpp"
2 #include "core/project.hpp"
5 #include "platform/wxwidgets/platform.hpp"
6 #include "platform/wxwidgets/loadsave.hpp"
10 #include <wx/control.h>
11 #include <wx/combobox.h>
13 #include "core/dispatch.hpp"
14 #include "library/string.hpp"
17 #define NOTHING 0xFFFFFFFFFFFFFFFFULL
21 bool voicesub_open
= false;
24 class wxeditor_voicesub
: public wxDialog
27 wxeditor_voicesub(wxWindow
* parent
);
28 ~wxeditor_voicesub() throw();
29 bool ShouldPreventAppExit() const;
30 void on_select(wxCommandEvent
& e
);
31 void on_play(wxCommandEvent
& e
);
32 void on_delete(wxCommandEvent
& e
);
33 void on_export(wxCommandEvent
& e
);
34 void on_export_s(wxCommandEvent
& e
);
35 void on_import(wxCommandEvent
& e
);
36 void on_change_ts(wxCommandEvent
& e
);
37 void on_change_gain(wxCommandEvent
& e
);
38 void on_load(wxCommandEvent
& e
);
39 void on_unload(wxCommandEvent
& e
);
40 void on_refresh(wxCommandEvent
& e
);
41 void on_close(wxCommandEvent
& e
);
42 void on_wclose(wxCloseEvent
& e
);
47 std::map
<int, uint64_t> smap
;
50 wxButton
* deletebutton
;
51 wxButton
* exportpbutton
;
52 wxButton
* exportsbutton
;
53 wxButton
* importpbutton
;
54 wxButton
* changetsbutton
;
55 wxButton
* changegainbutton
;
57 wxButton
* unloadbutton
;
58 wxButton
* refreshbutton
;
59 wxButton
* closebutton
;
60 struct dispatch_target
<> corechange
;
61 struct dispatch_target
<> vstreamchange
;
64 wxeditor_voicesub::wxeditor_voicesub(wxWindow
* parent
)
65 : wxDialog(parent
, wxID_ANY
, wxT("lsnes: Edit commentary track"), wxDefaultPosition
, wxSize(-1, -1))
69 wxFlexGridSizer
* top_s
= new wxFlexGridSizer(6, 1, 0, 0);
72 top_s
->Add(subtitles
= new wxListBox(this, wxID_ANY
, wxDefaultPosition
, wxSize(300, 400), 0, NULL
,
73 wxLB_SINGLE
), 1, wxGROW
);
75 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
76 pbutton_s
->Add(new wxStaticText(this, wxID_ANY
, wxT("Stream")), 0, wxGROW
);
77 pbutton_s
->Add(playbutton
= new wxButton(this, wxID_ANY
, wxT("Play")), 0, wxGROW
);
78 pbutton_s
->Add(deletebutton
= new wxButton(this, wxID_ANY
, wxT("Delete")), 0, wxGROW
);
79 top_s
->Add(pbutton_s
, 1, wxGROW
);
80 pbutton_s
->SetSizeHints(this);
82 pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
83 pbutton_s
->Add(new wxStaticText(this, wxID_ANY
, wxT("I/O")), 0, wxGROW
);
84 pbutton_s
->Add(importpbutton
= new wxButton(this, wxID_ANY
, wxT("Import")), 0, wxGROW
);
85 pbutton_s
->Add(exportpbutton
= new wxButton(this, wxID_ANY
, wxT("Export")), 0, wxGROW
);
86 pbutton_s
->Add(exportsbutton
= new wxButton(this, wxID_ANY
, wxT("Export all")), 0, wxGROW
);
87 top_s
->Add(pbutton_s
, 1, wxGROW
);
88 pbutton_s
->SetSizeHints(this);
90 pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
91 pbutton_s
->Add(new wxStaticText(this, wxID_ANY
, wxT("Misc.")), 0, wxGROW
);
92 pbutton_s
->Add(changetsbutton
= new wxButton(this, wxID_ANY
, wxT("Change time")), 0, wxGROW
);
93 pbutton_s
->Add(changegainbutton
= new wxButton(this, wxID_ANY
, wxT("Change gain")), 0, wxGROW
);
94 top_s
->Add(pbutton_s
, 1, wxGROW
);
95 pbutton_s
->SetSizeHints(this);
97 pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
98 pbutton_s
->Add(new wxStaticText(this, wxID_ANY
, wxT("Collection")), 0, wxGROW
);
99 pbutton_s
->Add(loadbutton
= new wxButton(this, wxID_ANY
, wxT("Load")), 0, wxGROW
);
100 pbutton_s
->Add(unloadbutton
= new wxButton(this, wxID_ANY
, wxT("Unload")), 0, wxGROW
);
101 top_s
->Add(pbutton_s
, 1, wxGROW
);
102 pbutton_s
->SetSizeHints(this);
104 pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
105 pbutton_s
->AddStretchSpacer();
106 pbutton_s
->Add(refreshbutton
= new wxButton(this, wxID_OK
, wxT("Refresh")), 0, wxGROW
);
107 pbutton_s
->Add(closebutton
= new wxButton(this, wxID_OK
, wxT("Close")), 0, wxGROW
);
108 top_s
->Add(pbutton_s
, 1, wxGROW
);
109 pbutton_s
->SetSizeHints(this);
111 playbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
112 wxCommandEventHandler(wxeditor_voicesub::on_play
), NULL
, this);
113 deletebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
114 wxCommandEventHandler(wxeditor_voicesub::on_delete
), NULL
, this);
115 exportpbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
116 wxCommandEventHandler(wxeditor_voicesub::on_export
), NULL
, this);
117 exportsbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
118 wxCommandEventHandler(wxeditor_voicesub::on_export_s
), NULL
, this);
119 importpbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
120 wxCommandEventHandler(wxeditor_voicesub::on_import
), NULL
, this);
121 changetsbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
122 wxCommandEventHandler(wxeditor_voicesub::on_change_ts
), NULL
, this);
123 changegainbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
124 wxCommandEventHandler(wxeditor_voicesub::on_change_gain
), NULL
, this);
125 loadbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
126 wxCommandEventHandler(wxeditor_voicesub::on_load
), NULL
, this);
127 unloadbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
128 wxCommandEventHandler(wxeditor_voicesub::on_unload
), NULL
, this);
129 refreshbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
130 wxCommandEventHandler(wxeditor_voicesub::on_refresh
), NULL
, this);
131 closebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
132 wxCommandEventHandler(wxeditor_voicesub::on_close
), NULL
, this);
133 subtitles
->Connect(wxEVT_COMMAND_LISTBOX_SELECTED
,
134 wxCommandEventHandler(wxeditor_voicesub::on_select
), NULL
, this);
135 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(wxeditor_voicesub::on_wclose
));
137 top_s
->SetSizeHints(this);
139 vstreamchange
.set(notify_voice_stream_change
, [this]() { runuifun([this]() -> void { this->refresh(); }); });
140 corechange
.set(notify_core_change
, [this]() { runuifun([this]() -> void { this->refresh(); }); });
144 wxeditor_voicesub::~wxeditor_voicesub() throw()
148 void wxeditor_voicesub::on_select(wxCommandEvent
& e
)
152 uint64_t id
= get_id();
153 bool valid
= (id
!= NOTHING
);
154 playbutton
->Enable(valid
);
155 deletebutton
->Enable(valid
);
156 exportpbutton
->Enable(valid
);
157 changetsbutton
->Enable(valid
);
158 changegainbutton
->Enable(valid
);
161 void wxeditor_voicesub::on_play(wxCommandEvent
& e
)
163 uint64_t id
= get_id();
167 voicesub_play_stream(id
);
168 } catch(std::exception
& e
) {
169 show_message_ok(this, "Error playing", e
.what(), wxICON_EXCLAMATION
);
173 void wxeditor_voicesub::on_delete(wxCommandEvent
& e
)
175 uint64_t id
= get_id();
179 voicesub_delete_stream(id
);
180 } catch(std::exception
& e
) {
181 show_message_ok(this, "Error deleting", e
.what(), wxICON_EXCLAMATION
);
190 typedef std::pair
<std::string
, enum external_stream_format
> returntype
;
192 filedialog_input_params
input(bool save
) const
194 filedialog_input_params p
;
195 p
.types
.push_back(filedialog_type_entry("Opus streams", "*.opus", "opus"));
196 p
.types
.push_back(filedialog_type_entry("SoX files", "*.sox", "sox"));
200 std::pair
<std::string
, enum external_stream_format
> output(const filedialog_output_params
& p
,
203 return std::make_pair(p
.path
, (p
.typechoice
== 1) ? EXTFMT_SOX
: EXTFMT_OGGOPUS
);
209 void wxeditor_voicesub::on_export(wxCommandEvent
& e
)
211 uint64_t id
= get_id();
215 auto filename
= choose_file_save(this, "Select file to epxort", project_otherpath(),
217 voicesub_export_stream(id
, filename
.first
, filename
.second
);
218 } catch(canceled_exception
& e
) {
219 } catch(std::exception
& e
) {
220 show_message_ok(this, "Error exporting", e
.what(), wxICON_EXCLAMATION
);
224 void wxeditor_voicesub::on_export_s(wxCommandEvent
& e
)
227 std::string filename
;
228 filename
= choose_file_save(this, "Select file to export superstream", project_otherpath(),
230 voicesub_export_superstream(filename
);
231 } catch(canceled_exception
& e
) {
232 } catch(std::exception
& e
) {
233 show_message_ok(this, "Error exporting superstream", e
.what(), wxICON_EXCLAMATION
);
237 void wxeditor_voicesub::on_import(wxCommandEvent
& e
)
241 ts
= voicesub_parse_timebase(pick_text(this, "Enter timebase", "Enter position for newly "
243 auto filename
= choose_file_save(this, "Select file to import", project_otherpath(),
245 voicesub_import_stream(ts
, filename
.first
, filename
.second
);
246 } catch(canceled_exception
& e
) {
247 } catch(std::exception
& e
) {
248 show_message_ok(this, "Error importing", e
.what(), wxICON_EXCLAMATION
);
252 void wxeditor_voicesub::on_change_ts(wxCommandEvent
& e
)
254 uint64_t id
= get_id();
259 ts
= voicesub_parse_timebase(pick_text(this, "Enter timebase", "Enter new position for "
261 voicesub_alter_timebase(id
, ts
);
262 } catch(canceled_exception
& e
) {
263 } catch(std::exception
& e
) {
264 show_message_ok(this, "Error changing timebase", e
.what(), wxICON_EXCLAMATION
);
268 void wxeditor_voicesub::on_change_gain(wxCommandEvent
& e
)
270 uint64_t id
= get_id();
275 std::string old
= (stringfmt() << voicesub_get_gain(id
)).str();
276 gain
= parse_value
<float>(pick_text(this, "Enter gain", "Enter new gain (dB) for stream", old
));
277 voicesub_set_gain(id
, gain
);
278 } catch(canceled_exception
& e
) {
279 } catch(std::exception
& e
) {
280 show_message_ok(this, "Error changing gain", e
.what(), wxICON_EXCLAMATION
);
284 void wxeditor_voicesub::on_load(wxCommandEvent
& e
)
286 if(project_get() != NULL
)
289 std::string filename
;
291 //Use "." here because there can't be active project.
292 filename
= choose_file_load(this, "Select collection to load", ".", filetype_commentary
);
296 voicesub_load_collection(filename
);
297 } catch(canceled_exception
& e
) {
298 } catch(std::exception
& e
) {
299 show_message_ok(this, "Error loading collection", e
.what(), wxICON_EXCLAMATION
);
303 void wxeditor_voicesub::on_unload(wxCommandEvent
& e
)
305 if(project_get() != NULL
)
307 voicesub_unload_collection();
310 void wxeditor_voicesub::on_refresh(wxCommandEvent
& e
)
315 void wxeditor_voicesub::on_close(wxCommandEvent
& e
)
318 voicesub_open
= false;
321 void wxeditor_voicesub::refresh()
325 bool cflag
= voicesub_collection_loaded();
326 bool pflag
= (project_get() != NULL
);
327 unloadbutton
->Enable(cflag
&& !pflag
);
328 loadbutton
->Enable(!pflag
);
329 exportsbutton
->Enable(cflag
);
330 importpbutton
->Enable(cflag
);
331 int sel
= subtitles
->GetSelection();
335 for(auto i
: voicesub_get_stream_info()) {
337 std::ostringstream tmp
;
338 tmp
<< "#" << i
.id
<< " " << voicesub_ts_seconds(i
.length
) << "s@" << voicesub_ts_seconds(i
.base
)
340 float gain
= voicesub_get_gain(i
.id
);
341 if(gain
< -1e-5 || gain
> 1e-5)
342 tmp
<< " (gain " << gain
<< "dB)";
343 std::string text
= tmp
.str();
344 subtitles
->Append(towxstring(text
));
346 if(sel
!= wxNOT_FOUND
&& sel
< (ssize_t
)subtitles
->GetCount())
347 subtitles
->SetSelection(sel
);
348 else if(subtitles
->GetCount())
349 subtitles
->SetSelection(0);
354 uint64_t wxeditor_voicesub::get_id()
356 int id
= subtitles
->GetSelection();
357 return smap
.count(id
) ? smap
[id
] : NOTHING
;
360 void wxeditor_voicesub::on_wclose(wxCloseEvent
& e
)
366 voicesub_open
= false;
369 bool wxeditor_voicesub::ShouldPreventAppExit() const { return false; }
371 void show_wxeditor_voicesub(wxWindow
* parent
)
375 wxeditor_voicesub
* v
= new wxeditor_voicesub(parent
);
377 voicesub_open
= true;