From 44a5f5d8805449c008924cca65c16837245825e0 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Mon, 23 May 2011 16:24:51 +0000 Subject: implemented legato function added all the new functions to the score editor --- muse2/muse/functions.cpp | 69 ++++++ muse2/muse/functions.h | 4 + muse2/muse/midiedit/pianoroll.cpp | 12 +- muse2/muse/midiedit/prcanvas.h | 2 +- muse2/muse/midiedit/scoreedit.cpp | 25 ++- muse2/muse/midiedit/scoreedit.h | 3 +- muse2/muse/widgets/function_dialogs/CMakeLists.txt | 3 + muse2/muse/widgets/function_dialogs/legato.cpp | 88 ++++++++ muse2/muse/widgets/function_dialogs/legato.h | 42 ++++ muse2/muse/widgets/function_dialogs/legatobase.ui | 233 +++++++++++++++++++++ 10 files changed, 474 insertions(+), 7 deletions(-) create mode 100644 muse2/muse/widgets/function_dialogs/legato.cpp create mode 100644 muse2/muse/widgets/function_dialogs/legato.h create mode 100644 muse2/muse/widgets/function_dialogs/legatobase.ui (limited to 'muse2') diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index 1ad81693..89a66fa7 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -27,6 +27,7 @@ Setlen* set_notelen_dialog=NULL; Move* move_notes_dialog=NULL; Transpose* transpose_dialog=NULL; Crescendo* crescendo_dialog=NULL; +Legato* legato_dialog=NULL; void init_function_dialogs(QWidget* parent) { @@ -39,6 +40,7 @@ void init_function_dialogs(QWidget* parent) move_notes_dialog = new Move(parent); transpose_dialog = new Transpose(parent); crescendo_dialog = new Crescendo(parent); + legato_dialog = new Legato(parent); } set partlist_to_set(PartList* pl) @@ -181,6 +183,16 @@ bool crescendo(const set& parts) return true; } +bool legato(const set& parts) +{ + if (!legato_dialog->exec()) + return false; + + legato(parts,legato_dialog->range, legato_dialog->min_len, !legato_dialog->allow_shortening); + + return true; +} + void modify_velocity(const set& parts, int range, int rate, int offset) @@ -535,6 +547,60 @@ void delete_overlaps(const set& parts, int range) } } +void legato(const set& parts, int range, int min_len, bool dont_shorten) +{ + map events = get_events(parts, range); + bool undo_started=false; + + if (min_len<=0) min_len=1; + + if (!events.empty()) + { + for (map::iterator it1=events.begin(); it1!=events.end(); it1++) + { + Event& event1=*(it1->first); + Part* part1=it1->second; + + unsigned len=MAXINT; + // we may NOT optimize by letting it2 start at (it1 +1); this optimisation + // is only allowed when events was sorted by time. it is, however, sorted + // randomly by pointer. + for (map::iterator it2=events.begin(); it2!=events.end(); it2++) + { + Event& event2=*(it2->first); + Part* part2=it2->second; + + bool relevant = (event2.tick() >= event1.tick() + min_len); + if (dont_shorten) + relevant = relevant && (event2.tick() >= event1.endTick()); + + if ( (part1->events()==part2->events()) && // part1 and part2 are the same or are duplicates + relevant && // they're not too near (respect min_len and dont_shorten) + (event2.tick()-event1.tick() < len ) ) // that's the nearest relevant following note + len=event2.tick()-event1.tick(); + } + + if (len==MAXINT) len=event1.lenTick(); // if no following note was found, keep the length + + if (event1.lenTick() != len) + { + if (undo_started==false) + { + song->startUndo(); + undo_started=true; + } + + Event new_event1 = event1.clone(); + new_event1.setLenTick(len); + + audio->msgChangeEvent(event1, new_event1, part1, false, false, false); + } + } + + if (undo_started) song->endUndo(SC_EVENT_MODIFIED); + } +} + void read_function_dialog_config(Xml& xml) @@ -574,6 +640,8 @@ void read_function_dialog_config(Xml& xml) transpose_dialog->read_configuration(xml); else if (tag == "crescendo") crescendo_dialog->read_configuration(xml); + else if (tag == "legato") + legato_dialog->read_configuration(xml); else xml.unknown("function_dialogs"); break; @@ -601,6 +669,7 @@ void write_function_dialog_config(int level, Xml& xml) move_notes_dialog->write_configuration(level, xml); transpose_dialog->write_configuration(level, xml); crescendo_dialog->write_configuration(level, xml); + legato_dialog->write_configuration(level, xml); xml.tag(level, "/dialogs"); } diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h index 18f6e3ec..40e5f0e0 100644 --- a/muse2/muse/functions.h +++ b/muse2/muse/functions.h @@ -17,6 +17,7 @@ #include "widgets/function_dialogs/setlen.h" #include "widgets/function_dialogs/move.h" #include "widgets/function_dialogs/deloverlaps.h" +#include "widgets/function_dialogs/legato.h" #include #include "part.h" @@ -31,6 +32,7 @@ extern Setlen* set_notelen_dialog; extern Move* move_notes_dialog; extern Transpose* transpose_dialog; extern Crescendo* crescendo_dialog; +extern Legato* legato_dialog; void init_function_dialogs(QWidget* parent); @@ -49,6 +51,7 @@ void set_notelen(const std::set& parts, int range, int len); void move_notes(const std::set& parts, int range, signed int ticks); void transpose_notes(const std::set& parts, int range, signed int halftonesteps); void crescendo(const std::set& parts, int range, int start_val, int end_val, bool absolute); +void legato(const std::set& parts, int range, int min_len=1, bool dont_shorten=false); //the below functions automatically open the dialog @@ -62,6 +65,7 @@ bool transpose_notes(const std::set& parts); bool crescendo(const std::set& parts); bool erase_notes(const std::set& parts); bool delete_overlaps(const std::set& parts); +bool legato(const std::set& parts); diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp index 9105a446..ab83e85f 100644 --- a/muse2/muse/midiedit/pianoroll.cpp +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -198,11 +198,11 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i mapper->setMapping(funcTransposeAction, PianoCanvas::CMD_TRANSPOSE); connect(funcTransposeAction, SIGNAL(triggered()), mapper, SLOT(map())); - funcEraseEventAction = menuFunctions->addAction(tr("Erase Event")); + funcEraseEventAction = menuFunctions->addAction(tr("Erase Events")); mapper->setMapping(funcEraseEventAction, PianoCanvas::CMD_ERASE_EVENT); connect(funcEraseEventAction, SIGNAL(triggered()), mapper, SLOT(map())); - funcNoteShiftAction = menuFunctions->addAction(tr("Note Shift")); + funcNoteShiftAction = menuFunctions->addAction(tr("Move Notes")); mapper->setMapping(funcNoteShiftAction, PianoCanvas::CMD_NOTE_SHIFT); connect(funcNoteShiftAction, SIGNAL(triggered()), mapper, SLOT(map())); @@ -213,7 +213,12 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i funcDelOverlapsAction = menuFunctions->addAction(tr("Delete Overlaps")); mapper->setMapping(funcDelOverlapsAction, PianoCanvas::CMD_DELETE_OVERLAPS); connect(funcDelOverlapsAction, SIGNAL(triggered()), mapper, SLOT(map())); - + + QAction* funcLegatoAction = menuFunctions->addAction(tr("Legato")); + mapper->setMapping(funcLegatoAction, PianoCanvas::CMD_LEGATO); + connect(funcLegatoAction, SIGNAL(triggered()), mapper, SLOT(map())); + + menuPlugins = menuBar()->addMenu(tr("&Plugins")); song->populateScriptMenu(menuPlugins, this); @@ -610,6 +615,7 @@ void PianoRoll::cmd(int cmd) case PianoCanvas::CMD_NOTE_SHIFT: move_notes(partlist_to_set(parts())); break; case PianoCanvas::CMD_FIXED_LEN: set_notelen(partlist_to_set(parts())); break; case PianoCanvas::CMD_DELETE_OVERLAPS: delete_overlaps(partlist_to_set(parts())); break; + case PianoCanvas::CMD_LEGATO: legato(partlist_to_set(parts())); break; default: ((PianoCanvas*)canvas)->cmd(cmd); } diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index a04ca514..3ca9ab52 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -98,7 +98,7 @@ class PianoCanvas : public EventCanvas { CMD_TRANSPOSE, CMD_THIN_OUT, CMD_ERASE_EVENT, CMD_NOTE_SHIFT, CMD_MOVE_CLOCK, CMD_COPY_MEASURE, CMD_ERASE_MEASURE, CMD_DELETE_MEASURE, CMD_CREATE_MEASURE, - CMD_FIXED_LEN, CMD_DELETE_OVERLAPS + CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO }; PianoCanvas(MidiEditor*, QWidget*, int, int); diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 2636d4f2..0019de91 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -365,10 +365,23 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) QAction* func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map())); QAction* func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map())); QAction* func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map())); + QAction* func_transpose_action = functions_menu->addAction(tr("Transpose"), menu_mapper, SLOT(map())); + QAction* func_erase_action = functions_menu->addAction(tr("Erase Events"), menu_mapper, SLOT(map())); + QAction* func_move_action = functions_menu->addAction(tr("Move Notes"), menu_mapper, SLOT(map())); + QAction* func_fixed_len_action = functions_menu->addAction(tr("Set Fixed Length"), menu_mapper, SLOT(map())); + QAction* func_del_overlaps_action = functions_menu->addAction(tr("Delete Overlaps"), menu_mapper, SLOT(map())); + QAction* func_legato_action = functions_menu->addAction(tr("Legato"), menu_mapper, SLOT(map())); menu_mapper->setMapping(func_quantize_action, CMD_QUANTIZE); menu_mapper->setMapping(func_notelen_action, CMD_NOTELEN); menu_mapper->setMapping(func_velocity_action, CMD_VELOCITY); menu_mapper->setMapping(func_cresc_action, CMD_CRESCENDO); + menu_mapper->setMapping(func_transpose_action, CMD_TRANSPOSE); + menu_mapper->setMapping(func_erase_action, CMD_ERASE); + menu_mapper->setMapping(func_move_action, CMD_MOVE); + menu_mapper->setMapping(func_fixed_len_action, CMD_FIXED_LEN); + menu_mapper->setMapping(func_del_overlaps_action, CMD_DELETE_OVERLAPS); + menu_mapper->setMapping(func_legato_action, CMD_LEGATO); + if (!default_toolbar_state.isEmpty()) restoreState(default_toolbar_state); @@ -572,7 +585,13 @@ void ScoreEdit::menu_command(int cmd) case CMD_VELOCITY: modify_velocity(score_canvas->get_all_parts()); break; case CMD_CRESCENDO: crescendo(score_canvas->get_all_parts()); break; case CMD_NOTELEN: modify_notelen(score_canvas->get_all_parts()); break; - + case CMD_TRANSPOSE: transpose_notes(score_canvas->get_all_parts()); break; + case CMD_ERASE: erase_notes(score_canvas->get_all_parts()); break; + case CMD_MOVE: move_notes(score_canvas->get_all_parts()); break; + case CMD_FIXED_LEN: set_notelen(score_canvas->get_all_parts()); break; + case CMD_DELETE_OVERLAPS: delete_overlaps(score_canvas->get_all_parts()); break; + case CMD_LEGATO: legato(score_canvas->get_all_parts()); break; + default: score_canvas->menu_command(cmd); } @@ -4261,7 +4280,9 @@ void staff_t::apply_lasso(QRect rect, set& already_processed) * between, for example, when a cis is tied to a des * * CURRENT TODO - * o legato: extend length to next note + * > o legato: extend length to next note + * o add music-keyboard-bindings for "insert rest" and "increase note length" + * o maybe support step-recording in score editor as well? * * IMPORTANT TODO * o do partial recalculating; recalculating can take pretty long diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index f587483a..2ce8d645 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -58,7 +58,8 @@ enum {CMD_COLOR_BLACK, CMD_COLOR_VELO, CMD_COLOR_PART, CMD_NOTELEN_1, CMD_NOTELEN_2, CMD_NOTELEN_4, CMD_NOTELEN_8, CMD_NOTELEN_16, CMD_NOTELEN_32, CMD_NOTELEN_LAST, - CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN }; + CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN, CMD_TRANSPOSE, + CMD_ERASE, CMD_MOVE, CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO }; class ScoreCanvas; diff --git a/muse2/muse/widgets/function_dialogs/CMakeLists.txt b/muse2/muse/widgets/function_dialogs/CMakeLists.txt index 7ddc6bee..db1f3229 100644 --- a/muse2/muse/widgets/function_dialogs/CMakeLists.txt +++ b/muse2/muse/widgets/function_dialogs/CMakeLists.txt @@ -30,6 +30,7 @@ QT4_WRAP_CPP (widgets_functiondialogs_mocs remove.h setlen.h transpose.h + legato.h velocity.h ) @@ -45,6 +46,7 @@ file (GLOB widgets_functiondialogs_ui_files removebase.ui setlenbase.ui transposebase.ui + legatobase.ui velocitybase.ui ) @@ -62,6 +64,7 @@ file (GLOB widgets_functiondialogs_source_files remove.cpp setlen.cpp transpose.cpp + legato.cpp velocity.cpp ) diff --git a/muse2/muse/widgets/function_dialogs/legato.cpp b/muse2/muse/widgets/function_dialogs/legato.cpp new file mode 100644 index 00000000..0a181106 --- /dev/null +++ b/muse2/muse/widgets/function_dialogs/legato.cpp @@ -0,0 +1,88 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: legato.cpp,v 1.1.1.1 2011/05/05 18:51:04 flo93 Exp $ +// (C) Copyright 2011 Florian Jung (flo93@sourceforge.net) +//========================================================= + +#include +#include "legato.h" +#include "xml.h" + +Legato::Legato(QWidget* parent) + : QDialog(parent) +{ + setupUi(this); + range_group = new QButtonGroup; + range_group->addButton(all_events_button,0); + range_group->addButton(selected_events_button,1); + range_group->addButton(looped_events_button,2); + range_group->addButton(selected_looped_button,3); + + pull_values(); +} + +void Legato::pull_values() +{ + range = range_group->checkedId(); + min_len = len_spinbox->value(); + allow_shortening = allow_shorten_checkbox->isChecked(); +} + +void Legato::accept() +{ + pull_values(); + QDialog::accept(); +} + +int Legato::exec() +{ + if ((range < 0) || (range > 3)) range=0; + + range_group->button(range)->setChecked(true); + len_spinbox->setValue(min_len); + allow_shorten_checkbox->setChecked(allow_shortening); + + return QDialog::exec(); +} + +void Legato::read_configuration(Xml& xml) +{ + for (;;) + { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + + const QString& tag = xml.s1(); + switch (token) + { + case Xml::TagStart: + if (tag == "range") + range=xml.parseInt(); + else if (tag == "min_len") + min_len=xml.parseInt(); + else if (tag == "allow_shortening") + allow_shortening=xml.parseInt(); + else + xml.unknown("Legato"); + break; + + case Xml::TagEnd: + if (tag == "legato") + return; + + default: + break; + } + } +} + +void Legato::write_configuration(int level, Xml& xml) +{ + xml.tag(level++, "legato"); + xml.intTag(level, "range", range); + xml.intTag(level, "min_len", min_len); + xml.intTag(level, "allow_shortening", allow_shortening); + xml.tag(level, "/legato"); +} diff --git a/muse2/muse/widgets/function_dialogs/legato.h b/muse2/muse/widgets/function_dialogs/legato.h new file mode 100644 index 00000000..80b371ca --- /dev/null +++ b/muse2/muse/widgets/function_dialogs/legato.h @@ -0,0 +1,42 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: legato.h,v 1.1.1.1 2011/05/05 18:51:04 flo93 Exp $ +// (C) Copyright 2011 Florian Jung (flo93@sourceforge.net) +//========================================================= + +#ifndef __LEGATO_H__ +#define __LEGATO_H__ + +#include "ui_legatobase.h" + +class QButtonGroup; +class Xml; + +class Legato : public QDialog, public Ui::LegatoBase +{ + private: + Q_OBJECT + QButtonGroup* range_group; + + protected slots: + void accept(); + void pull_values(); + + public: + Legato(QWidget* parent = 0); + + int range; + int min_len; + bool allow_shortening; + + void read_configuration(Xml& xml); + void write_configuration(int level, Xml& xml); + + + public slots: + int exec(); +}; + +#endif + diff --git a/muse2/muse/widgets/function_dialogs/legatobase.ui b/muse2/muse/widgets/function_dialogs/legatobase.ui new file mode 100644 index 00000000..7bc406df --- /dev/null +++ b/muse2/muse/widgets/function_dialogs/legatobase.ui @@ -0,0 +1,233 @@ + + + LegatoBase + + + true + + + + 0 + 0 + 275 + 289 + + + + MusE: Legato + + + + 6 + + + 11 + + + + + Range + + + + 6 + + + 11 + + + + + All Events + + + + + + + Selected Events + + + true + + + + + + + Looped Events + + + + + + + Selected Looped + + + + + + + + + + Settings + + + false + + + false + + + + 11 + + + 6 + + + + + true + + + true + + + ticks + + + 0 + + + 10000 + + + 1 + + + 0 + + + + + + + Minimum Length + + + + + + + + + + 0 + 0 + + + + Allow shortening notes + + + + + + + Qt::RightToLeft + + + + + + + + + + + + + + + 6 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + OK + + + false + + + true + + + + + + + Cancel + + + + + + + + + + + + okButton + clicked() + LegatoBase + accept() + + + 20 + 20 + + + 20 + 20 + + + + + cancelButton + clicked() + LegatoBase + reject() + + + 20 + 20 + + + 20 + 20 + + + + + -- cgit v1.2.3