diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 5e69194..e8b4be2 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -4,5 +4,6 @@ + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 58b2825..704dc7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ add_executable(bmhelper WIN32 src/smf_event.cpp src/smf_io.h src/srcview.cpp - src/srcview.h src/AudioSplitter.cpp src/AudioSplitter.h src/wavsplit.cpp src/wavsplit.h) + src/srcview.h src/AudioSplitter.cpp src/AudioSplitter.h src/wavsplit.cpp src/wavsplit.h src/divsettingdialog.h) include(${wxWidgets_USE_FILE}) target_link_libraries(bmhelper ${wxWidgets_LIBRARIES} ${LIBSNDFILE_LIBRARIES}) diff --git a/src/divedit.cpp b/src/divedit.cpp index e6a73ca..645fb24 100644 --- a/src/divedit.cpp +++ b/src/divedit.cpp @@ -6,6 +6,7 @@ #include "AudioSplitter.h" #include #include +#include "divsettingdialog.h" enum { ID_SmfOutput, @@ -387,4 +388,17 @@ void DivisionEditor::OnOpenAudioSplitter(wxCommandEvent &event) { splitter->Show(); } +bool DivisionEditor::OnDivRegenerate(wxMenuEvent &event) { + if (!division) return false; + DivisionSetting setting(division->get_name(), division->get_quantize()); + + DivisionSettingDialog dialog(frame, setting, division->get_quantize()); + if (dialog.ShowModal() != wxID_OK) + return false; + + dialog.GetSetting(setting); + division->change_division_settings(setting); + return true; +} + diff --git a/src/division.cpp b/src/division.cpp index 6cd9890..c1bb6c0 100644 --- a/src/division.cpp +++ b/src/division.cpp @@ -190,6 +190,17 @@ static void sort_notes( Division::Division(Project *_project, MidiData &src, const DivisionSetting &setting) : MidiData(src.get_quantize()), project(_project), name(setting.name), zz_enabled(setting.zz_definition) { + divide_from_data(src, setting); +} + +void Division::divide_from_data(MidiData &src, const DivisionSetting &setting, bool copy) { + if (copy) + src_data = src; // store a copy of the src data... + + init(); /* clean ourselves up */ + + name = setting.name; + std::vector temp_divs; std::vector src2div(src.notes_count()); src2def.resize(src.notes_count()); @@ -205,21 +216,27 @@ Division::Division(Project *_project, MidiData &src, const DivisionSetting &sett note.referrers.push_back(i); src2div[i] = i; } + // Midiデータにそのまま配置 for (size_t i = 0; i < temp_divs.size(); i++) { note_push_back( MidiNoteEvent(src.notes(i).position + setting.head_margin, temp_divs[i].gate, temp_divs[i].nn, temp_divs[i].vel)); } - if (src.notes_count() > 0) head_margin = src.notes(0).position+setting.head_margin; + + if (src.notes_count() > 0) head_margin = src.notes(0).position + setting.head_margin; } else { // 分割 - ThresholdSetting thresholds{}; - thresholds.gate = setting.gate_threshold; - thresholds.vel = setting.velocity_threshold; + ThresholdSetting thresholds { + static_cast(setting.gate_threshold), + static_cast(setting.velocity_threshold) + }; + divide_notes(src, src2div, temp_divs, thresholds); + // ソート sort_notes(temp_divs, src2div, setting.sort_type); + // Midiデータに流し込み int position = setting.head_margin; for (auto & temp_div : temp_divs) { @@ -228,6 +245,7 @@ Division::Division(Project *_project, MidiData &src, const DivisionSetting &sett int b = position % get_quantize(); if (b) position += get_quantize() - b; } + head_margin = setting.head_margin; } @@ -258,18 +276,19 @@ Division::Division(Project *_project, MidiData &src, const DivisionSetting &sett } else { mln = 1; // 多重定義しない } + size_t id_i = definitions.size(); for (size_t b = 0; b < mln; b++) { definitions.push_back(Definition(zz, i)); if (setting.zz_definition) zz++; else zz.increment_in_ff(); } + size_t b = 0; for (int referrer : temp_divs[i].referrers) { src2def[referrer] = id_i + b; if (++b == mln) b = 0; } } - } @@ -366,6 +385,7 @@ static const NodeName _name_ = StringToNodeName("name"); static const NodeName _s2df_ = StringToNodeName("s2df"); static const NodeName _dfnt_ = StringToNodeName("dfnt"); static const NodeName _zzen_ = StringToNodeName("zzen"); +static const NodeName _srcd_ = StringToNodeName("Srcd"); /* source data (first letter caps = list) */ struct BmsOffsetData { bool zz_enabled; @@ -400,6 +420,8 @@ bool Division::read_tree(TreeNode &node) { sub.get_data(&data, sizeof(BmsOffsetData)); zz_enabled = data.zz_enabled; } + } else if (sub.get_name() == _srcd_) { + src_data.read_tree(sub); } } return true; @@ -430,8 +452,28 @@ bool Division::write_tree(TreeNode &node) { node.push_back(_zzen_); node.back().set_data(&offset_data, sizeof(BmsOffsetData)); + + node.push_back(_srcd_); + src_data.write_tree(node.back()); + return true; } +void Division::change_division_settings(const DivisionSetting &setting) { + divide_from_data(src_data, setting, false); +} +DivisionSetting::DivisionSetting(const wxString &name, size_t quantize) { + this->name = name; + src_copy = false; + head_margin = 0; + min_interval = quantize*1; + sort_type = DivisionSetting::SORT_NN_GATE_V; + gate_threshold = quantize/8; + velocity_threshold = 5; + zz_definition = true; + ml_definition = true; + start_definition = 1; + ml_threshold = quantize/2; +} diff --git a/src/division.h b/src/division.h index 6f1b20d..f7e0b12 100644 --- a/src/division.h +++ b/src/division.h @@ -33,6 +33,7 @@ struct DivisionSetting{ ZZNumber start_definition; // �J�n��`�ԍ� int ml_threshold; // ���d��`���邩�ǂ����̃m�[�g�Ԋu��臒l(���l���ݒ�B���x�̏ꍇ�͑��d��`���Ȃ�) + DivisionSetting(const wxString &name, size_t quantize); }; @@ -60,6 +61,8 @@ class Division : public MidiData{ int head_margin; bool zz_enabled; + MidiData src_data; + //void _divide_notes(std::vector &src2div, std::vector &temp_divs, ThresholdSetting &thresholds); //void _sort_notes(std::vector &temp_divs, DivisionSetting::SortType sort_type); @@ -67,7 +70,7 @@ class Division : public MidiData{ Division(Project *_project); Division(Project *_project, MidiData &src, const DivisionSetting &setting); void init() override { - //MidiData::init(); + MidiData::init(); name.clear(); src2def.clear(); definitions.clear(); @@ -94,6 +97,9 @@ class Division : public MidiData{ void def_transpose_up(); void def_transpose_down(); void def_transpose_to(ZZNumber nbegin); + + void divide_from_data(MidiData &src, const DivisionSetting &setting, bool copy = true); + void change_division_settings(const DivisionSetting &setting); }; diff --git a/src/divsettingdialog.h b/src/divsettingdialog.h new file mode 100644 index 0000000..262463f --- /dev/null +++ b/src/divsettingdialog.h @@ -0,0 +1,64 @@ +#ifndef BMHELPER_DIVSETTINGDIALOG_H +#define BMHELPER_DIVSETTINGDIALOG_H + +class DivisionSettingDialog : public wxDialog{ + enum{ + ID_NameLabel = 1, + ID_NameInput = 2, + ID_MidiBox = 30, + ID_ScpyCheck = 29, + ID_MhmgLabel = 32, + ID_MhmgInput = 33, + ID_MintLabel = 3, + ID_MintInput = 4, + ID_SortLabel = 5, + ID_SortCombo = 6, + ID_ThrsLabel = 20, + ID_TgatLabel = 7, + ID_TgatInput = 8, + ID_TvelLabel = 9, + ID_TvelInput = 10, + ID_DefnBox = 31, +// ID_DfzzLabel = 11, + ID_DfzzCheck = 12, + ID_DfmlCheck = 21, + ID_DfstLabel = 13, + ID_DfstInput = 14, + ID_DfmtLabel = 22, + ID_DfmtInput = 23 + }; + wxStaticText *name_label; + wxTextCtrl *name_input; + wxStaticBox *midi_box; + wxCheckBox *scpy_check; + wxStaticText *mhmg_label; + wxTextCtrl *mhmg_input; + wxStaticText *mint_label; + wxTextCtrl *mint_input; + wxStaticText *sort_label; + wxComboBox *sort_combo; + wxStaticText *thrs_label; + wxStaticText *tgat_label; + wxTextCtrl *tgat_input; + wxStaticText *tvel_label; + wxTextCtrl *tvel_input; + wxStaticBox *defn_box; +// wxStaticText *dfzz_label; + wxCheckBox *dfzz_check; + wxCheckBox *dfml_check; + wxStaticText *dfst_label; + wxTextCtrl *dfst_input; + wxStaticText *dfmt_label; + wxTextCtrl *dfmt_input; + wxButton *button_ok, *button_cancel; + int quantize; + static const int _lm=15, _tm=5, _lw=25, _lb=30, _fc=150, _sc=130, _bw=5, _cw=25; +public: + DivisionSettingDialog(wxWindow *owner, DivisionSetting setting, int _quantize); + void GetSetting(DivisionSetting &setting); + void OnScpyCheck(wxCommandEvent &WXUNUSED(ev)); + void OnOK(wxCommandEvent &WXUNUSED(ev)); + wxDECLARE_EVENT_TABLE(); +}; + +#endif //BMHELPER_DIVSETTINGDIALOG_H diff --git a/src/divview.cpp b/src/divview.cpp index f45e01c..539529b 100644 --- a/src/divview.cpp +++ b/src/divview.cpp @@ -4,6 +4,7 @@ #include "divview.h" #include +#include "divsettingdialog.h" enum{ @@ -24,7 +25,7 @@ END_EVENT_TABLE() DivisionsView::DivisionsView(FrameWindow *_frame, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxWindow(parent, id, pos, size, style, name), frame(_frame), -new_div(0), divisions(0), editor(0) +new_div(nullptr), divisions(nullptr), editor(nullptr) { SetWindowStyle(wxBORDER_SIMPLE | wxCLIP_CHILDREN); @@ -116,9 +117,10 @@ void DivisionsView::OnDeleteDivision(wxMenuEvent &WXUNUSED(event)){ void DivisionsView::DivisionChanged(){ int selection = divisions->GetSelection(); if (selection == wxNOT_FOUND){ - editor->SetDivision(0); - frame->UpdateDivision(0); + editor->SetDivision(nullptr); + frame->UpdateDivision(nullptr); frame->m_div_rename->Enable(false); + frame->m_div_divregen->Enable(false); frame->m_div_delete->Enable(false); frame->m_div_smfout->Enable(false); frame->m_div_divcopy->Enable(false); @@ -130,6 +132,7 @@ void DivisionsView::DivisionChanged(){ editor->SetDivision(&div); frame->UpdateDivision(&div); frame->m_div_rename->Enable(true); + frame->m_div_divregen->Enable(true); frame->m_div_delete->Enable(true); frame->m_div_smfout->Enable(true); frame->m_div_divcopy->Enable(true); @@ -142,233 +145,166 @@ void DivisionsView::DivisionChanged(){ //====================================== +wxBEGIN_EVENT_TABLE(DivisionSettingDialog, wxDialog) + EVT_CHECKBOX(DivisionSettingDialog::ID_ScpyCheck, DivisionSettingDialog::OnScpyCheck) + EVT_COMMAND(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, DivisionSettingDialog::OnOK) +wxEND_EVENT_TABLE() -class DivisionSettingDialog : public wxDialog{ - enum{ - ID_NameLabel = 1, - ID_NameInput = 2, - ID_MidiBox = 30, - ID_ScpyCheck = 29, - ID_MhmgLabel = 32, - ID_MhmgInput = 33, - ID_MintLabel = 3, - ID_MintInput = 4, - ID_SortLabel = 5, - ID_SortCombo = 6, - ID_ThrsLabel = 20, - ID_TgatLabel = 7, - ID_TgatInput = 8, - ID_TvelLabel = 9, - ID_TvelInput = 10, - ID_DefnBox = 31, -// ID_DfzzLabel = 11, - ID_DfzzCheck = 12, - ID_DfmlCheck = 21, - ID_DfstLabel = 13, - ID_DfstInput = 14, - ID_DfmtLabel = 22, - ID_DfmtInput = 23 - }; - wxStaticText *name_label; - wxTextCtrl *name_input; - wxStaticBox *midi_box; - wxCheckBox *scpy_check; - wxStaticText *mhmg_label; - wxTextCtrl *mhmg_input; - wxStaticText *mint_label; - wxTextCtrl *mint_input; - wxStaticText *sort_label; - wxComboBox *sort_combo; - wxStaticText *thrs_label; - wxStaticText *tgat_label; - wxTextCtrl *tgat_input; - wxStaticText *tvel_label; - wxTextCtrl *tvel_input; - wxStaticBox *defn_box; -// wxStaticText *dfzz_label; - wxCheckBox *dfzz_check; - wxCheckBox *dfml_check; - wxStaticText *dfst_label; - wxTextCtrl *dfst_input; - wxStaticText *dfmt_label; - wxTextCtrl *dfmt_input; - wxButton *button_ok, *button_cancel; - int quantize; - static const int _lm=15, _tm=5, _lw=25, _lb=30, _fc=150, _sc=130, _bw=5, _cw=25; -public: - DivisionSettingDialog(wxWindow *owner, DivisionSetting setting, int _quantize) : - wxDialog(owner, -1, _("Division settings"), wxDefaultPosition, wxSize(_lm*2+_fc+_sc+_bw*2+10, _tm*2+_lw*15+_lb+_bw+_cw+10)), quantize(_quantize) - { - static wxString sort_choices[] = { - _("None"), - _("nn/gate/vel"), - _("nn/vel/gate"), - _("gate/nn/vel"), - _("gate/vel/nn"), - _("vel/nn/gate"), - _("vel/gate/nn"), - }; - - auto spacing = 10; - auto this_sizer = new wxBoxSizer(wxVERTICAL); - auto main_flags = wxSizerFlags().Border(wxALL, 10).Expand(); - - auto name_row = new wxBoxSizer(wxHORIZONTAL); - name_label = new wxStaticText(this, ID_NameLabel, _("Name (&N):")); - name_input = new wxTextCtrl(this, ID_NameInput, setting.name); - name_row->Add(name_label); - name_row->AddSpacer(spacing); - name_row->Add(name_input, 1); - - this_sizer->Add(name_row, main_flags); - - auto settings_row = new wxStaticBoxSizer(wxVERTICAL, this, _("MIDI settings")); - auto settings_row_flags = wxSizerFlags().Border(wxALL, spacing).Expand(); - - scpy_check = new wxCheckBox(this, ID_ScpyCheck, _("Leave MIDI unaltered (&C)")); - scpy_check->SetValue(setting.src_copy); - settings_row->Add(scpy_check, settings_row_flags); - - auto midi_settings_sizer = new wxGridSizer(3, 2, 10, 10); - - mhmg_label = new wxStaticText(this, ID_MhmgLabel, _("Leading silence (&H):")); - mhmg_input = new wxTextCtrl(this, ID_MhmgInput, wxString::Format(_("%f"), (double)setting.head_margin/quantize)); - mint_label = new wxStaticText(this, ID_MintLabel, _("Min. interval gap (&I):")); - mint_input = new wxTextCtrl(this, ID_MintInput, wxString::Format(_("%f"), (double)setting.min_interval/quantize)); - sort_label = new wxStaticText(this, ID_SortLabel, _("Sorting method (&S):")); - sort_combo = new wxComboBox(this, ID_SortCombo, sort_choices[(int)setting.sort_type], wxDefaultPosition, wxDefaultSize, 7, sort_choices, wxCB_DROPDOWN | wxCB_READONLY); - - midi_settings_sizer->Add(mhmg_label); - midi_settings_sizer->Add(mhmg_input, wxSizerFlags().Expand()); - midi_settings_sizer->Add(mint_label); - midi_settings_sizer->Add(mint_input, wxSizerFlags().Expand()); - midi_settings_sizer->Add(sort_label); - midi_settings_sizer->Add(sort_combo, wxSizerFlags().Expand()); - - settings_row->Add(midi_settings_sizer, settings_row_flags); - - auto min_difference_settings_sizer_outer = new wxStaticBoxSizer(wxVERTICAL, this, _("Minimum difference in:")); - settings_row->Add(min_difference_settings_sizer_outer, wxSizerFlags().Expand()); - - auto min_difference_settings_sizer = new wxGridSizer(2, 2, 10, 10); - min_difference_settings_sizer_outer->Add(min_difference_settings_sizer, wxSizerFlags().Border(wxALL, spacing).Expand()); - - tgat_label = new wxStaticText(this, ID_TgatLabel, _(" Length (&G):")); - tgat_input = new wxTextCtrl(this, ID_TgatInput, wxString::Format(_("%f"), (double)setting.gate_threshold/quantize)); - tvel_label = new wxStaticText(this, ID_TvelLabel, _(" Velocity (&V):")); - tvel_input = new wxTextCtrl(this, ID_TvelInput, wxString::Format(_("%zu"), setting.velocity_threshold)); - min_difference_settings_sizer->Add(tgat_label); - min_difference_settings_sizer->Add(tgat_input, wxSizerFlags().Expand()); - min_difference_settings_sizer->Add(tvel_label); - min_difference_settings_sizer->Add(tvel_input, wxSizerFlags().Expand()); - - this_sizer->Add(settings_row, main_flags); - - auto def_settings_sizer_outer = new wxStaticBoxSizer(wxVERTICAL, this, _("Definition settings")); - this_sizer->Add(def_settings_sizer_outer, main_flags); - - auto def_settings_sizer = new wxGridSizer(3, 2, 15, 15); - def_settings_sizer_outer->Add(def_settings_sizer, wxSizerFlags().Border(wxALL, spacing)); +DivisionSettingDialog::DivisionSettingDialog(wxWindow *owner, DivisionSetting setting, int _quantize) : + wxDialog(owner, -1, _("Division settings"), wxDefaultPosition, wxSize(_lm*2+_fc+_sc+_bw*2+10, _tm*2+_lw*15+_lb+_bw+_cw+10)), quantize(_quantize) +{ + static wxString sort_choices[] = { + _("None"), + _("nn/gate/vel"), + _("nn/vel/gate"), + _("gate/nn/vel"), + _("gate/vel/nn"), + _("vel/nn/gate"), + _("vel/gate/nn"), + }; + + auto spacing = 10; + auto this_sizer = new wxBoxSizer(wxVERTICAL); + auto main_flags = wxSizerFlags().Border(wxALL, 10).Expand(); + + auto name_row = new wxBoxSizer(wxHORIZONTAL); + name_label = new wxStaticText(this, ID_NameLabel, _("Name (&N):")); + name_input = new wxTextCtrl(this, ID_NameInput, setting.name); + name_row->Add(name_label); + name_row->AddSpacer(spacing); + name_row->Add(name_input, 1); + + this_sizer->Add(name_row, main_flags); + + auto settings_row = new wxStaticBoxSizer(wxVERTICAL, this, _("MIDI settings")); + auto settings_row_flags = wxSizerFlags().Border(wxALL, spacing).Expand(); + + scpy_check = new wxCheckBox(this, ID_ScpyCheck, _("Leave MIDI unaltered (&C)")); + scpy_check->SetValue(setting.src_copy); + settings_row->Add(scpy_check, settings_row_flags); + + auto midi_settings_sizer = new wxGridSizer(3, 2, 10, 10); + + mhmg_label = new wxStaticText(this, ID_MhmgLabel, _("Leading silence (&H):")); + mhmg_input = new wxTextCtrl(this, ID_MhmgInput, wxString::Format(_("%f"), (double)setting.head_margin/quantize)); + mint_label = new wxStaticText(this, ID_MintLabel, _("Min. interval gap (&I):")); + mint_input = new wxTextCtrl(this, ID_MintInput, wxString::Format(_("%f"), (double)setting.min_interval/quantize)); + sort_label = new wxStaticText(this, ID_SortLabel, _("Sorting method (&S):")); + sort_combo = new wxComboBox(this, ID_SortCombo, sort_choices[(int)setting.sort_type], wxDefaultPosition, wxDefaultSize, 7, sort_choices, wxCB_DROPDOWN | wxCB_READONLY); + + midi_settings_sizer->Add(mhmg_label); + midi_settings_sizer->Add(mhmg_input, wxSizerFlags().Expand()); + midi_settings_sizer->Add(mint_label); + midi_settings_sizer->Add(mint_input, wxSizerFlags().Expand()); + midi_settings_sizer->Add(sort_label); + midi_settings_sizer->Add(sort_combo, wxSizerFlags().Expand()); + + settings_row->Add(midi_settings_sizer, settings_row_flags); + + auto min_difference_settings_sizer_outer = new wxStaticBoxSizer(wxVERTICAL, this, _("Minimum difference in:")); + settings_row->Add(min_difference_settings_sizer_outer, wxSizerFlags().Expand()); + + auto min_difference_settings_sizer = new wxGridSizer(2, 2, 10, 10); + min_difference_settings_sizer_outer->Add(min_difference_settings_sizer, wxSizerFlags().Border(wxALL, spacing).Expand()); + + tgat_label = new wxStaticText(this, ID_TgatLabel, _(" Length (&G):")); + tgat_input = new wxTextCtrl(this, ID_TgatInput, wxString::Format(_("%f"), (double)setting.gate_threshold/quantize)); + tvel_label = new wxStaticText(this, ID_TvelLabel, _(" Velocity (&V):")); + tvel_input = new wxTextCtrl(this, ID_TvelInput, wxString::Format(_("%zu"), setting.velocity_threshold)); + min_difference_settings_sizer->Add(tgat_label); + min_difference_settings_sizer->Add(tgat_input, wxSizerFlags().Expand()); + min_difference_settings_sizer->Add(tvel_label); + min_difference_settings_sizer->Add(tvel_input, wxSizerFlags().Expand()); + + this_sizer->Add(settings_row, main_flags); + + auto def_settings_sizer_outer = new wxStaticBoxSizer(wxVERTICAL, this, _("Definition settings")); + this_sizer->Add(def_settings_sizer_outer, main_flags); + + auto def_settings_sizer = new wxGridSizer(3, 2, 15, 15); + def_settings_sizer_outer->Add(def_settings_sizer, wxSizerFlags().Border(wxALL, spacing)); // dfzz_label = new wxStaticText(this, ID_DfzzLabel, _("ZZ定義を有効にする(&Z):"), wxPoint(_lm,_tm+_lw*11+3), wxSize(_fc,15)); - dfzz_check = new wxCheckBox(this, ID_DfzzCheck, _("Use base-36 range(00-ZZ) (&Z)")); dfzz_check->SetValue(setting.zz_definition); - dfml_check = new wxCheckBox(this, ID_DfmlCheck, _("Use overloading (&M)")); dfml_check->SetValue(setting.ml_definition); - dfst_label = new wxStaticText(this, ID_DfstLabel, _("Starting BMS Index (&D):")); - dfst_input = new wxTextCtrl(this, ID_DfstInput, setting.start_definition.to_string()); - dfmt_label = new wxStaticText(this, ID_DfmtLabel, _("Overloading Interval (&L):")); - dfmt_input = new wxTextCtrl(this, ID_DfmtInput, wxString::Format(_("%f"), (double)setting.ml_threshold/quantize)); - - def_settings_sizer->Add(dfzz_check); - def_settings_sizer->Add(dfml_check); - def_settings_sizer->Add(dfst_label); - def_settings_sizer->Add(dfst_input, wxSizerFlags().Expand()); - def_settings_sizer->Add(dfmt_label); - def_settings_sizer->Add(dfmt_input, wxSizerFlags().Expand()); - - - auto dialog_bottom_sizer = new wxBoxSizer(wxHORIZONTAL); - this_sizer->Add(dialog_bottom_sizer, wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxALL)); - - button_ok = new wxButton(this, wxID_OK, _("OK")); - button_cancel = new wxButton(this, wxID_CANCEL, _("Cancel")); - dialog_bottom_sizer->Add(button_ok); - dialog_bottom_sizer->Add(button_cancel); - - SetSizerAndFit(this_sizer); - button_ok->SetDefault(); - SetEscapeId(wxID_CANCEL); - } - void GetSetting(DivisionSetting &setting){ - double db; - long lb; - setting.name = name_input->GetValue(); - setting.src_copy = scpy_check->GetValue(); - if (mhmg_input->GetValue().ToDouble(&db)) setting.head_margin = (int)(db*quantize); - if (mint_input->GetValue().ToDouble(&db)) setting.min_interval = (int)(db*quantize); - setting.sort_type = (DivisionSetting::SortType)sort_combo->GetSelection(); - if (tgat_input->GetValue().ToDouble(&db)) setting.gate_threshold = (int)(db*quantize); - if (tvel_input->GetValue().ToLong(&lb)) setting.velocity_threshold = lb; - setting.zz_definition = dfzz_check->GetValue(); - setting.ml_definition = dfml_check->GetValue(); - setting.start_definition.from_string(dfst_input->GetValue()); - if (dfmt_input->GetValue().ToDouble(&db)) setting.ml_threshold = (int)(db*quantize); - } - void OnScpyCheck(wxCommandEvent &WXUNUSED(ev)){ - bool enabled = !scpy_check->GetValue(); - mint_input->Enable(enabled); - sort_combo->Enable(enabled); - tgat_input->Enable(enabled); - tvel_input->Enable(enabled); - } - void OnOK(wxCommandEvent &WXUNUSED(ev)){ - wxString s = dfst_input->GetValue(); - ZZNumber zz; - bool zz_enabled = dfzz_check->GetValue(); - if (s.length() != 2 || !zz.from_string(s) || (!zz_enabled && !zz.in_ff())){ - MessageBeep(0); // windows - return; - } - this->EndDialog(wxID_OK); - } - wxDECLARE_EVENT_TABLE(); -}; + dfzz_check = new wxCheckBox(this, ID_DfzzCheck, _("Use base-36 range(00-ZZ) (&Z)")); dfzz_check->SetValue(setting.zz_definition); + dfml_check = new wxCheckBox(this, ID_DfmlCheck, _("Use overloading (&M)")); dfml_check->SetValue(setting.ml_definition); + dfst_label = new wxStaticText(this, ID_DfstLabel, _("Starting BMS Index (&D):")); + dfst_input = new wxTextCtrl(this, ID_DfstInput, setting.start_definition.to_string()); + dfmt_label = new wxStaticText(this, ID_DfmtLabel, _("Overloading Interval (&L):")); + dfmt_input = new wxTextCtrl(this, ID_DfmtInput, wxString::Format(_("%f"), (double)setting.ml_threshold/quantize)); + + def_settings_sizer->Add(dfzz_check); + def_settings_sizer->Add(dfml_check); + def_settings_sizer->Add(dfst_label); + def_settings_sizer->Add(dfst_input, wxSizerFlags().Expand()); + def_settings_sizer->Add(dfmt_label); + def_settings_sizer->Add(dfmt_input, wxSizerFlags().Expand()); + + + auto dialog_bottom_sizer = new wxBoxSizer(wxHORIZONTAL); + this_sizer->Add(dialog_bottom_sizer, wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxALL)); + + button_ok = new wxButton(this, wxID_OK, _("OK")); + button_cancel = new wxButton(this, wxID_CANCEL, _("Cancel")); + dialog_bottom_sizer->Add(button_ok); + dialog_bottom_sizer->Add(button_cancel); + + SetSizerAndFit(this_sizer); + button_ok->SetDefault(); + SetEscapeId(wxID_CANCEL); +} +void DivisionSettingDialog::GetSetting(DivisionSetting &setting) { + double db; + long lb; + setting.name = name_input->GetValue(); + setting.src_copy = scpy_check->GetValue(); + if (mhmg_input->GetValue().ToDouble(&db)) setting.head_margin = (int)(db*quantize); + if (mint_input->GetValue().ToDouble(&db)) setting.min_interval = (int)(db*quantize); + setting.sort_type = (DivisionSetting::SortType)sort_combo->GetSelection(); + if (tgat_input->GetValue().ToDouble(&db)) setting.gate_threshold = (int)(db*quantize); + if (tvel_input->GetValue().ToLong(&lb)) setting.velocity_threshold = lb; + setting.zz_definition = dfzz_check->GetValue(); + setting.ml_definition = dfml_check->GetValue(); + setting.start_definition.from_string(dfst_input->GetValue()); + if (dfmt_input->GetValue().ToDouble(&db)) setting.ml_threshold = (int)(db*quantize); +} -wxBEGIN_EVENT_TABLE(DivisionSettingDialog, wxDialog) - EVT_CHECKBOX(DivisionSettingDialog::ID_ScpyCheck, DivisionSettingDialog::OnScpyCheck) - EVT_COMMAND(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, DivisionSettingDialog::OnOK) -wxEND_EVENT_TABLE() +void DivisionSettingDialog::OnScpyCheck(wxCommandEvent &) { + bool enabled = !scpy_check->GetValue(); + mint_input->Enable(enabled); + sort_combo->Enable(enabled); + tgat_input->Enable(enabled); + tvel_input->Enable(enabled); +} +void DivisionSettingDialog::OnOK(wxCommandEvent &) { + wxString s = dfst_input->GetValue(); + ZZNumber zz; + bool zz_enabled = dfzz_check->GetValue(); + if (s.length() != 2 || !zz.from_string(s) || (!zz_enabled && !zz.in_ff())){ + MessageBeep(0); // windows + return; + } + this->EndDialog(wxID_OK); +} void DivisionsView::_NewDivision(){ if (!frame->project) return; int quantize = frame->project->GetSource().get_quantize(); - DivisionSetting setting; wxFileName fn(frame->project->GetSource().source_filename); auto fn_no_ext = fn.GetName(); - setting.name = fn_no_ext; - setting.src_copy = false; - setting.head_margin = 0; - setting.min_interval = quantize*1; - setting.sort_type = DivisionSetting::SORT_NN_GATE_V; - setting.gate_threshold = quantize/8; - setting.velocity_threshold = 5; - setting.zz_definition = true; - setting.ml_definition = true; - setting.start_definition = 1; - setting.ml_threshold = quantize/2; - DivisionSettingDialog *dialog = new DivisionSettingDialog(frame, setting, quantize); - int ret = dialog->ShowModal(); + DivisionSetting setting(fn_no_ext, quantize); + + DivisionSettingDialog dialog (frame, setting, quantize); + int ret = dialog.ShowModal(); if (ret != wxID_OK){ - dialog->Destroy(); return; } - dialog->GetSetting(setting); - dialog->Destroy(); - size_t i = frame->project->CreateDivision(setting); + dialog.GetSetting(setting); + frame->project->CreateDivision(setting); divisions->SetSelection(divisions->Append(setting.name)); DivisionChanged(); } @@ -389,6 +325,13 @@ void DivisionsView::OnDivRename(wxMenuEvent &event) { } } +void DivisionsView::OnDivRegenerate(wxMenuEvent &event) { + if (editor->OnDivRegenerate(event)) { + frame->project->SetChangeFlag(); + DivisionChanged(); + } +} + diff --git a/src/divview.h b/src/divview.h index dc67c41..4416a11 100644 --- a/src/divview.h +++ b/src/divview.h @@ -46,6 +46,7 @@ class DivisionEditor : public wxWindow{ void OnSeqCopy(wxCommandEvent &event){ _SeqCopy(); } void OnSmfOut(wxMenuEvent &event){ _SmfOut(); } void OnDivCopy(wxMenuEvent &event){ _DivCopy(); } + bool OnDivRegenerate(wxMenuEvent &event); void OnDefOut(wxMenuEvent &event){ DefOut(); } bool OnDivRename(wxMenuEvent &event) { return DivRename(); } void OnSeqCopy(wxMenuEvent &event){ _SeqCopy(); } @@ -83,6 +84,7 @@ class DivisionsView : public wxWindow{ void OnNewDivision(wxMenuEvent &event); void OnDeleteDivision(wxMenuEvent &event); void OnDivRename(wxMenuEvent &event); + void OnDivRegenerate(wxMenuEvent &event); void OnSelectDivision(wxCommandEvent &event); void ProjectChanged(); void DivisionChanged(); diff --git a/src/frame.cpp b/src/frame.cpp index 9a86290..2abeb26 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -20,6 +20,7 @@ enum { ID_DivDefOut = 0x0205, ID_DivSeqCopy = 0x0206, ID_DivRename = 0x0207, + ID_DivDivRegen = 0x208, ID_Help = 0x0901, ID_About = 0x0903 }; @@ -42,7 +43,7 @@ wxEND_EVENT_TABLE() FrameWindow::FrameWindow(const wxPoint &pos, const wxSize &size) -: wxFrame(NULL, -1, app_name, pos, size), +: wxFrame(nullptr, -1, app_name, pos, size), menu_bar(new wxMenuBar), status_bar(CreateStatusBar()), m_file(new wxMenu), m_div(new wxMenu), m_help(new wxMenu), m_file_new(new wxMenuItem(m_file, ID_New, _("New project (&N)...\tCtrl+N"))), @@ -56,26 +57,29 @@ m_div_rename(new wxMenuItem(m_div, ID_DivRename, _("Rename division (&R)...\tF2" m_div_delete(new wxMenuItem(m_div, ID_DivDelete, _("Delete division (&D)"))), m_div_smfout(new wxMenuItem(m_div, ID_DivSmfOut, _("Write modified MIDI File (&M)..."))), m_div_divcopy(new wxMenuItem(m_div, ID_DivDivCopy, _("Copy division (&W)"))), +m_div_divregen(new wxMenuItem(m_div, ID_DivDivRegen, _("Regenerate division (&E)...\tCtrl+R"))), m_div_defout(new wxMenuItem(m_div, ID_DivDefOut, _("Definition information (&D)..."))), m_div_seqcopy(new wxMenuItem(m_div, ID_DivSeqCopy, _("Copy BMS sequence to clipboard (&S)"))), m_help_help(new wxMenuItem(m_help, ID_Help, _("Help (&H)...\tF1"))), m_help_about(new wxMenuItem(m_help, ID_About, _("About (&I)..."))), -splitter(0), src(0), div(0), -project(0) +splitter(nullptr), src(nullptr), div(nullptr), +project(nullptr) { // init gui wxIcon ico("BMHICON", wxBITMAP_TYPE_ICO_RESOURCE); SetIcon(ico); - wxAcceleratorEntry acs[7]; + wxAcceleratorEntry acs[9]; acs[0].Set(wxACCEL_CTRL, (int)'N', ID_New); acs[1].Set(wxACCEL_CTRL, (int)'O', ID_Open); acs[2].Set(wxACCEL_CTRL, (int)'S', ID_Save); acs[3].Set(wxACCEL_CTRL | wxACCEL_SHIFT, (int)'S', ID_SaveAs); acs[4].Set(wxACCEL_CTRL, (int)'Q', ID_Quit); acs[5].Set(wxACCEL_NORMAL, WXK_F5, ID_DivNew); - acs[6].Set(wxACCEL_NORMAL, WXK_F2, ID_Help); - wxAcceleratorTable accel(7, acs); + acs[6].Set(wxACCEL_NORMAL, WXK_F1, ID_Help); + acs[7].Set(wxACCEL_NORMAL, WXK_F2, ID_DivRename); + acs[8].Set(wxACCEL_CTRL, (int)'R', ID_DivDivRegen); + wxAcceleratorTable accel(9, acs); SetAcceleratorTable(accel); m_file->Append(m_file_new); @@ -86,8 +90,10 @@ project(0) m_file->AppendSeparator(); m_file->Append(m_file_quit); menu_bar->Append(m_file, _("File (&F)")); + m_div->Append(m_div_new); m_div->Append(m_div_rename); + m_div->Append(m_div_divregen); m_div->Append(m_div_delete); m_div->AppendSeparator(); m_div->Append(m_div_smfout); @@ -95,9 +101,11 @@ project(0) m_div->Append(m_div_defout); m_div->Append(m_div_seqcopy); menu_bar->Append(m_div, _("Divisions (&D)")); + m_help->Append(m_help_help); m_help->Append(m_help_about); menu_bar->Append(m_help, _("Help (&H)")); + SetMenuBar(menu_bar); status_bar->SetFieldsCount(3); @@ -115,6 +123,7 @@ project(0) Connect(ID_DivDelete, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionsView::OnDeleteDivision), 0, div); Connect(ID_DivSmfOut, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionEditor::OnSmfOut), 0, div->editor); Connect(ID_DivDivCopy, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionEditor::OnDivCopy), 0, div->editor); + Connect(ID_DivDivRegen, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionsView::OnDivRegenerate), 0, div); Connect(ID_DivDefOut, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionEditor::OnDefOut), 0, div->editor); Connect(ID_DivSeqCopy, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionEditor::OnSeqCopy), 0, div->editor); Connect(ID_DivRename, wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(DivisionsView::OnDivRename), 0, div); @@ -123,7 +132,7 @@ project(0) } FrameWindow::~FrameWindow(){ - SetProject(0); + SetProject(nullptr); } void FrameWindow::OpenFiles(int nFiles, std::vector FileNames){ diff --git a/src/frame.h b/src/frame.h index 0d2083d..ee38635 100644 --- a/src/frame.h +++ b/src/frame.h @@ -19,7 +19,17 @@ class FrameWindow : public wxFrame, public ProjectObserver{ wxStatusBar *status_bar; wxMenu *m_file, *m_div, *m_help; wxMenuItem *m_file_new, *m_file_open, *m_file_save, *m_file_save_as, *m_file_close, *m_file_quit; - wxMenuItem *m_div_new, *m_div_delete, *m_div_smfout, *m_div_divcopy, *m_div_defout, *m_div_seqcopy, *m_div_rename; + + wxMenuItem + *m_div_new, + *m_div_delete, + *m_div_smfout, + *m_div_divcopy, + *m_div_divregen, + *m_div_defout, + *m_div_seqcopy, + *m_div_rename; + wxMenuItem *m_help_help, *m_help_about; wxSplitterWindow *splitter; SourceView *src; diff --git a/src/midi_sr.cpp b/src/midi_sr.cpp index 0c9e04d..4a9bc38 100644 --- a/src/midi_sr.cpp +++ b/src/midi_sr.cpp @@ -8,66 +8,66 @@ static const NodeName _note_ = StringToNodeName("note"); static const NodeName _ptch_ = StringToNodeName("ptch"); static const NodeName _cchg_ = StringToNodeName("ccgh"); -struct _MidiCCEvent : public MidiParamEvent{ - int cc_num; +struct _MidiCCEvent : public MidiParamEvent { + int cc_num; }; -bool MidiData::read_tree(TreeNode &node){ - init(); - for (auto & sub : node){ - if (sub.get_name() == _qntz_){ - if (sub.get_data_size() == sizeof(int)) sub.get_data(&quantize, sizeof(int)); - }else if (sub.get_name() == _note_){ - MidiNoteEvent e; - if (sub.get_data_size() == sizeof(MidiNoteEvent)){ - sub.get_data(&e, sizeof(MidiNoteEvent)); - note_events.push_back(e); - } - }else if (sub.get_name() == _ptch_){ - MidiParamEvent e; - if (sub.get_data_size() == sizeof(MidiParamEvent)){ - sub.get_data(&e, sizeof(MidiParamEvent)); - pb_events.push_back(e); - } - }else if (sub.get_name() == _cchg_){ - _MidiCCEvent e; - if (sub.get_data_size() == sizeof(_MidiCCEvent)){ - sub.get_data(&e, sizeof(_MidiCCEvent)); - auto i = cc_lanes.find(e.cc_num); - if (i == cc_lanes.end()){ - std::pair< MidiCCLanesMap::iterator, bool > x; - x = cc_lanes.insert(MidiCCLanePair(e.cc_num, MidiParamsLane())); - i = x.first; - } - i->second.push_back(*static_cast(&e)); - } - } - } - return true; +bool MidiData::read_tree(TreeNode &node) { + init(); + for (auto &sub : node) { + if (sub.get_name() == _qntz_) { + if (sub.get_data_size() == sizeof(int)) sub.get_data(&quantize, sizeof(int)); + } else if (sub.get_name() == _note_) { + MidiNoteEvent e; + if (sub.get_data_size() == sizeof(MidiNoteEvent)) { + sub.get_data(&e, sizeof(MidiNoteEvent)); + note_events.push_back(e); + } + } else if (sub.get_name() == _ptch_) { + MidiParamEvent e; + if (sub.get_data_size() == sizeof(MidiParamEvent)) { + sub.get_data(&e, sizeof(MidiParamEvent)); + pb_events.push_back(e); + } + } else if (sub.get_name() == _cchg_) { + _MidiCCEvent e; + if (sub.get_data_size() == sizeof(_MidiCCEvent)) { + sub.get_data(&e, sizeof(_MidiCCEvent)); + auto i = cc_lanes.find(e.cc_num); + if (i == cc_lanes.end()) { + std::pair x; + x = cc_lanes.insert(MidiCCLanePair(e.cc_num, MidiParamsLane())); + i = x.first; + } + i->second.push_back(*static_cast(&e)); + } + } + } + return true; } -bool MidiData::write_tree(TreeNode &node){ - node.push_back(_qntz_); - node.back().set_data(&quantize, sizeof(int)); - for (auto & note_event : note_events){ - node.push_back(_note_); - node.back().set_data(¬e_event, sizeof(MidiNoteEvent)); - } - for (MidiParamsLane::iterator i=pb_events.begin(); i!=pb_events.end(); i++){ - node.push_back(_ptch_); - node.back().set_data(&(*i), sizeof(MidiParamEvent)); - } - for (MidiCCLanesMap::iterator lane=cc_lanes.begin(); lane!=cc_lanes.end(); lane++){ - for (MidiParamsLane::iterator i=lane->second.begin(); i!=lane->second.end(); i++){ - _MidiCCEvent e; - e.position = i->position; - e.value = i->value; - e.cc_num = lane->first; - node.push_back(_cchg_); - node.back().set_data(&e, sizeof(_MidiCCEvent)); - } - } - return true; +bool MidiData::write_tree(TreeNode &node) { + node.push_back(_qntz_); + node.back().set_data(&quantize, sizeof(int)); + for (auto ¬e_event : note_events) { + node.push_back(_note_); + node.back().set_data(¬e_event, sizeof(MidiNoteEvent)); + } + for (auto & pb_event : pb_events) { + node.push_back(_ptch_); + node.back().set_data(&pb_event, sizeof(MidiParamEvent)); + } + for (auto &cc_lane : cc_lanes) { + for (auto i = cc_lane.second.begin(); i != cc_lane.second.end(); i++) { + _MidiCCEvent e; + e.position = i->position; + e.value = i->value; + e.cc_num = cc_lane.first; + node.push_back(_cchg_); + node.back().set_data(&e, sizeof(_MidiCCEvent)); + } + } + return true; } diff --git a/src/serialize.h b/src/serialize.h index 749fd08..eb3052b 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -5,10 +5,10 @@ #include "common.h" #include -// f[^̊ȈՐK􂢍 -// قRIFFƓKw^`NVXeBgGfBAB -// RIFFłƂRIFF/LIST`N͑啶pŎn܂`N(m[h)ŕ\BȊO͒ʏ`N -// ẻɓm[h̃m[hĂ悢 +// データの簡易尻洗い座 +// ほぼRIFFと同じ階層型チャンクシステム。リトルエンディアン。 +// RIFFでいうところのRIFF/LISTチャンクは大文字英数で始まるチャンク名(ノード名)で表す。それ以外は通常チャンク +// 同じ親の下に同じノード名のノードが複数あってもよい typedef unsigned long NodeName; @@ -63,7 +63,7 @@ class TreeNode : public std::vector{ NodeSizeType size; file.Read(&size, sizeof(NodeSizeType)); if (is_list()){ - // XgñAȂqvfǂݍ + // リスト系のアレなら子要素を読み込む wxFileOffset inner_head = file.Tell(); wxFileOffset inner_tail = inner_head + size; while (file.Tell() < inner_tail){ @@ -72,7 +72,7 @@ class TreeNode : public std::vector{ } file.Seek(inner_tail); }else{ - // XgłȂΎdataɓǂݍ + // リストでなければ自分のdataに読み込む if (size){ data = new char[data_size = size]; file.Read(data, data_size); @@ -84,8 +84,8 @@ class TreeNode : public std::vector{ if (is_list()){ file.Seek(sizeof(NodeSizeType), wxFromCurrent); wxFileOffset inner_head = file.Tell(); - for (std::vector::const_iterator i=begin(); i!=end(); i++){ - i->write(file); + for (const auto & i : *this){ + i.write(file); } wxFileOffset inner_tail = file.Tell(); NodeSizeType size = inner_tail - inner_head;