mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 15:25:01 +01:00
Add MIDI note strumming operator
- Implement strum_notes functionality to apply progressive timing offsets to selected MIDI notes - Provides guitar-style strumming for creating realistic note sequences The feature applies 1/32 beat timing offsets progressively to selected notes, creating a strummed effect where notes play in sequence rather than simultaneously.
This commit is contained in:
parent
4dbacf0cb6
commit
0581f29f5f
3 changed files with 140 additions and 0 deletions
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 */
|
||||||
88
libs/ardour/strum.cc
Normal file
88
libs/ardour/strum.cc
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
std::vector<NotePtr> all_notes;
|
||||||
|
for (std::vector<Notes>::iterator s = seqs.begin(); s != seqs.end(); ++s) {
|
||||||
|
for (Notes::const_iterator i = (*s).begin(); i != (*s).end(); ++i) {
|
||||||
|
all_notes.push_back(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (std::vector<NotePtr>::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 (std::vector<NotePtr>::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