mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 07:14:56 +01:00
Move strum operation from GUI to libardour as MidiOperator
- Create new Strum class in libardour inheriting from MidiOperator - Add strum.cc to build configuration (wscript) - Refactor MidiView::strum_notes() to use new ARDOUR::Strum operator - Follow same pattern as quantize, transpose, and legatize operations - Preserve original behavior while improving architecture This addresses feedback to move strum logic from GUI layer to proper business logic layer, making it consistent with other MIDI operators and enabling reuse throughout the codebase.
This commit is contained in:
parent
51e3a94aa8
commit
c8df8ca7e4
4 changed files with 147 additions and 35 deletions
|
|
@ -47,6 +47,7 @@
|
||||||
#include "ardour/operations.h"
|
#include "ardour/operations.h"
|
||||||
#include "ardour/quantize.h"
|
#include "ardour/quantize.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
|
#include "ardour/strum.h"
|
||||||
|
|
||||||
#include "evoral/Parameter.h"
|
#include "evoral/Parameter.h"
|
||||||
#include "evoral/Event.h"
|
#include "evoral/Event.h"
|
||||||
|
|
@ -5371,44 +5372,17 @@ MidiView::strum_notes (bool forward, bool fine)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_note_diff_command (_("Strum"));
|
ARDOUR::Strum strum(forward, fine);
|
||||||
|
|
||||||
Notes notes;
|
PBD::Command* cmd = _editing_context.apply_midi_note_edit_op_to_region (strum, *this);
|
||||||
selection_as_notelist (notes, false);
|
|
||||||
|
|
||||||
if (notes.size() < 2) {
|
if (cmd) {
|
||||||
abort_note_diff();
|
_editing_context.begin_reversible_command (strum.name ());
|
||||||
return;
|
(*cmd)();
|
||||||
|
_editing_context.add_command (cmd);
|
||||||
|
_editing_context.commit_reversible_command ();
|
||||||
|
_editing_context.session()->set_dirty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Temporal::Beats total_offset;
|
|
||||||
Temporal::Beats offset;
|
|
||||||
|
|
||||||
if (fine) {
|
|
||||||
offset = Temporal::Beats::ticks (Temporal::ticks_per_beat / 128);
|
|
||||||
} else {
|
|
||||||
offset = Temporal::Beats::ticks (Temporal::ticks_per_beat / 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forward) {
|
|
||||||
for (auto const & n : notes) {
|
|
||||||
NoteBase* cne = find_canvas_note (n);
|
|
||||||
if (cne) {
|
|
||||||
change_note_time (cne, total_offset, true);
|
|
||||||
total_offset += offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { // backward
|
|
||||||
for (auto it = notes.rbegin(); it != notes.rend(); ++it) {
|
|
||||||
NoteBase* cne = find_canvas_note (*it);
|
|
||||||
if (cne) {
|
|
||||||
change_note_time (cne, total_offset, true);
|
|
||||||
total_offset += offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_note_diff ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
51
libs/ardour/ardour/strum.h
Normal file
51
libs/ardour/ardour/strum.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ardour/libardour_visibility.h"
|
||||||
|
#include "ardour/midi_model.h"
|
||||||
|
#include "ardour/midi_operator.h"
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
/** Strum notes (add progressive timing offset to notes).
|
||||||
|
*
|
||||||
|
* This operator applies a progressive timing offset to selected notes,
|
||||||
|
* creating a strumming effect where notes are offset by a specified
|
||||||
|
* amount in either forward or backward direction.
|
||||||
|
*/
|
||||||
|
class LIBARDOUR_API Strum : public MidiOperator {
|
||||||
|
public:
|
||||||
|
typedef Evoral::Sequence<Temporal::Beats>::NotePtr NotePtr;
|
||||||
|
typedef Evoral::Sequence<Temporal::Beats>::Notes Notes;
|
||||||
|
|
||||||
|
Strum (bool forward, bool fine);
|
||||||
|
|
||||||
|
PBD::Command* operator() (std::shared_ptr<ARDOUR::MidiModel> model,
|
||||||
|
Temporal::Beats position,
|
||||||
|
std::vector<Notes>& seqs);
|
||||||
|
|
||||||
|
std::string name () const { return std::string ("strum"); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _forward;
|
||||||
|
bool _fine;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace */
|
||||||
86
libs/ardour/strum.cc
Normal file
86
libs/ardour/strum.cc
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ardour/strum.h"
|
||||||
|
#include "ardour/midi_model.h"
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
Strum::Strum(bool forward, bool fine)
|
||||||
|
: _forward(forward)
|
||||||
|
, _fine(fine)
|
||||||
|
{}
|
||||||
|
|
||||||
|
PBD::Command*
|
||||||
|
Strum::operator()(std::shared_ptr<ARDOUR::MidiModel> model,
|
||||||
|
Temporal::Beats position,
|
||||||
|
std::vector<Strum::Notes>& seqs)
|
||||||
|
{
|
||||||
|
typedef MidiModel::NoteDiffCommand Command;
|
||||||
|
|
||||||
|
Command* cmd = new Command(model, name());
|
||||||
|
|
||||||
|
if (seqs.empty()) {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all notes from all sequences and sort them by start time
|
||||||
|
Notes all_notes;
|
||||||
|
for (std::vector<Notes>::iterator s = seqs.begin(); s != seqs.end(); ++s) {
|
||||||
|
all_notes.insert(all_notes.end(), (*s).begin(), (*s).end());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_notes.size() < 2) {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort notes by start time
|
||||||
|
std::sort(all_notes.begin(), all_notes.end(),
|
||||||
|
[](const NotePtr& a, const NotePtr& b) {
|
||||||
|
return a->time() < b->time();
|
||||||
|
});
|
||||||
|
|
||||||
|
Temporal::Beats total_offset;
|
||||||
|
Temporal::Beats offset;
|
||||||
|
|
||||||
|
if (_fine) {
|
||||||
|
offset = Temporal::Beats::ticks(Temporal::ticks_per_beat / 128);
|
||||||
|
} else {
|
||||||
|
offset = Temporal::Beats::ticks(Temporal::ticks_per_beat / 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_forward) {
|
||||||
|
for (Notes::const_iterator i = all_notes.begin(); i != all_notes.end(); ++i) {
|
||||||
|
const NotePtr note = *i;
|
||||||
|
Temporal::Beats new_start = note->time() + total_offset;
|
||||||
|
cmd->change(note, MidiModel::NoteDiffCommand::StartTime, new_start);
|
||||||
|
total_offset += offset;
|
||||||
|
}
|
||||||
|
} else { // backward
|
||||||
|
for (Notes::const_reverse_iterator i = all_notes.rbegin(); i != all_notes.rend(); ++i) {
|
||||||
|
const NotePtr note = *i;
|
||||||
|
Temporal::Beats new_start = note->time() + total_offset;
|
||||||
|
cmd->change(note, MidiModel::NoteDiffCommand::StartTime, new_start);
|
||||||
|
total_offset += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace */
|
||||||
|
|
@ -250,6 +250,7 @@ libardour_sources = [
|
||||||
'stripable.cc',
|
'stripable.cc',
|
||||||
# 'step_sequencer.cc',
|
# 'step_sequencer.cc',
|
||||||
'strip_silence.cc',
|
'strip_silence.cc',
|
||||||
|
'strum.cc',
|
||||||
'surround_pannable.cc',
|
'surround_pannable.cc',
|
||||||
'surround_return.cc',
|
'surround_return.cc',
|
||||||
'surround_send.cc',
|
'surround_send.cc',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue