Remove old and unused Actions class
This commit is contained in:
parent
930da9752d
commit
ce339e2d0f
|
@ -62,7 +62,6 @@ list(APPEND SOURCES
|
|||
src/core/patch.cpp
|
||||
src/core/actions/actionFactory.cpp
|
||||
src/core/actions/actionRecorder.cpp
|
||||
src/core/actions/actions.cpp
|
||||
src/core/mixer.cpp
|
||||
src/core/jackSynchronizer.cpp
|
||||
src/core/midiSynchronizer.cpp
|
||||
|
|
|
@ -1,322 +0,0 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Giada - Your Hardcore Loopmachine
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (C) 2010-2023 Giovanni A. Zuliani | Monocasual Laboratories
|
||||
*
|
||||
* This file is part of Giada - Your Hardcore Loopmachine.
|
||||
*
|
||||
* Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#include "core/actions/actions.h"
|
||||
#include "core/actions/action.h"
|
||||
#include "core/actions/actionFactory.h"
|
||||
#include "core/idManager.h"
|
||||
#include "core/model/model.h"
|
||||
#include "utils/log.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
namespace giada::m
|
||||
{
|
||||
Actions::Actions(model::Model& model)
|
||||
: m_model(model)
|
||||
{
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::clearAll()
|
||||
{
|
||||
model::DataLock lock = m_model.lockData();
|
||||
m_model.getAllActions().clear();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::clearChannel(ID channelId)
|
||||
{
|
||||
removeIf([=](const Action& a) { return a.channelId == channelId; });
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::clearActions(ID channelId, int type)
|
||||
{
|
||||
removeIf([=](const Action& a) {
|
||||
return a.channelId == channelId && a.event.getStatus() == type;
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::deleteAction(ID id)
|
||||
{
|
||||
removeIf([=](const Action& a) { return a.id == id; });
|
||||
}
|
||||
|
||||
void Actions::deleteAction(ID currId, ID nextId)
|
||||
{
|
||||
removeIf([=](const Action& a) { return a.id == currId || a.id == nextId; });
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::updateKeyFrames(std::function<Frame(Frame old)> f)
|
||||
{
|
||||
Map temp;
|
||||
|
||||
/* Copy all existing actions in local map by cloning them, with just a
|
||||
difference: they have a new frame value. */
|
||||
|
||||
for (const auto& [oldFrame, actions] : m_model.getAllActions())
|
||||
{
|
||||
Frame newFrame = f(oldFrame);
|
||||
for (const Action& a : actions)
|
||||
{
|
||||
Action copy = a;
|
||||
copy.frame = newFrame;
|
||||
temp[newFrame].push_back(copy);
|
||||
}
|
||||
G_DEBUG("{} -> {}", oldFrame, newFrame);
|
||||
}
|
||||
|
||||
updateMapPointers(temp);
|
||||
|
||||
model::DataLock lock = m_model.lockData();
|
||||
m_model.getAllActions() = std::move(temp);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::updateEvent(ID id, MidiEvent e)
|
||||
{
|
||||
model::DataLock lock = m_model.lockData();
|
||||
|
||||
findAction(m_model.getAllActions(), id)->event = e;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::updateSiblings(ID id, ID prevId, ID nextId)
|
||||
{
|
||||
model::DataLock lock = m_model.lockData();
|
||||
|
||||
Action* pcurr = findAction(m_model.getAllActions(), id);
|
||||
Action* pprev = findAction(m_model.getAllActions(), prevId);
|
||||
Action* pnext = findAction(m_model.getAllActions(), nextId);
|
||||
|
||||
pcurr->prev = pprev;
|
||||
pcurr->prevId = pprev->id;
|
||||
pcurr->next = pnext;
|
||||
pcurr->nextId = pnext->id;
|
||||
|
||||
if (pprev != nullptr)
|
||||
{
|
||||
pprev->next = pcurr;
|
||||
pprev->nextId = pcurr->id;
|
||||
}
|
||||
if (pnext != nullptr)
|
||||
{
|
||||
pnext->prev = pcurr;
|
||||
pnext->prevId = pcurr->id;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool Actions::hasActions(ID channelId, int type) const
|
||||
{
|
||||
for (const auto& [frame, actions] : m_model.getAllActions())
|
||||
for (const Action& a : actions)
|
||||
if (a.channelId == channelId && (type == 0 || type == a.event.getStatus()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
Action Actions::rec(ID channelId, Frame frame, MidiEvent event)
|
||||
{
|
||||
/* Skip duplicates. */
|
||||
|
||||
if (exists(channelId, frame, event))
|
||||
return {};
|
||||
|
||||
Action a = actionFactory::makeAction(0, channelId, frame, event);
|
||||
|
||||
/* If key frame doesn't exist yet, the [] operator in std::map is smart
|
||||
enough to insert a new item first. No plug-in data for now. */
|
||||
|
||||
model::DataLock lock = m_model.lockData();
|
||||
|
||||
m_model.getAllActions()[frame].push_back(a);
|
||||
updateMapPointers(m_model.getAllActions());
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::rec(std::vector<Action>& actions)
|
||||
{
|
||||
if (actions.size() == 0)
|
||||
return;
|
||||
|
||||
model::DataLock lock = m_model.lockData();
|
||||
|
||||
Map& map = m_model.getAllActions();
|
||||
|
||||
for (const Action& a : actions)
|
||||
if (!exists(a.channelId, a.frame, a.event, map))
|
||||
map[a.frame].push_back(a);
|
||||
updateMapPointers(map);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::rec(ID channelId, Frame f1, Frame f2, MidiEvent e1, MidiEvent e2)
|
||||
{
|
||||
model::DataLock lock = m_model.lockData();
|
||||
|
||||
Map& map = m_model.getAllActions();
|
||||
|
||||
map[f1].push_back(actionFactory::makeAction(0, channelId, f1, e1));
|
||||
map[f2].push_back(actionFactory::makeAction(0, channelId, f2, e2));
|
||||
|
||||
Action* a1 = findAction(map, map[f1].back().id);
|
||||
Action* a2 = findAction(map, map[f2].back().id);
|
||||
a1->nextId = a2->id;
|
||||
a2->prevId = a1->id;
|
||||
|
||||
updateMapPointers(map);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
const std::vector<Action>* Actions::getActionsOnFrame(Frame frame) const
|
||||
{
|
||||
if (m_model.getAllActions().count(frame) == 0)
|
||||
return nullptr;
|
||||
return &m_model.getAllActions().at(frame);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
Action Actions::getClosestAction(ID channelId, Frame f, int type) const
|
||||
{
|
||||
Action out = {};
|
||||
forEachAction([&](const Action& a) {
|
||||
if (a.event.getStatus() != type || a.channelId != channelId)
|
||||
return;
|
||||
if (!out.isValid() || (a.frame <= f && a.frame > out.frame))
|
||||
out = a;
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
std::vector<Action> Actions::getActionsOnChannel(ID channelId) const
|
||||
{
|
||||
std::vector<Action> out;
|
||||
forEachAction([&](const Action& a) {
|
||||
if (a.channelId == channelId)
|
||||
out.push_back(a);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::forEachAction(std::function<void(const Action&)> f) const
|
||||
{
|
||||
for (auto& [_, actions] : m_model.getAllActions())
|
||||
for (const Action& action : actions)
|
||||
f(action);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
Action* Actions::findAction(Map& src, ID id)
|
||||
{
|
||||
for (auto& [frame, actions] : src)
|
||||
for (Action& a : actions)
|
||||
if (a.id == id)
|
||||
return &a;
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::updateMapPointers(Map& src)
|
||||
{
|
||||
for (auto& kv : src)
|
||||
{
|
||||
for (Action& action : kv.second)
|
||||
{
|
||||
if (action.nextId != 0)
|
||||
action.next = findAction(src, action.nextId);
|
||||
if (action.prevId != 0)
|
||||
action.prev = findAction(src, action.prevId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::optimize(Map& map)
|
||||
{
|
||||
for (auto it = map.cbegin(); it != map.cend();)
|
||||
it->second.size() == 0 ? it = map.erase(it) : ++it;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void Actions::removeIf(std::function<bool(const Action&)> f)
|
||||
{
|
||||
model::DataLock lock = m_model.lockData();
|
||||
|
||||
Map& map = m_model.getAllActions();
|
||||
for (auto& [frame, actions] : map)
|
||||
actions.erase(std::remove_if(actions.begin(), actions.end(), f), actions.end());
|
||||
optimize(map);
|
||||
updateMapPointers(map);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool Actions::exists(ID channelId, Frame frame, const MidiEvent& event, const Map& target) const
|
||||
{
|
||||
for (const auto& [_, actions] : target)
|
||||
for (const Action& a : actions)
|
||||
if (a.channelId == channelId && a.frame == frame && a.event.getRaw() == event.getRaw())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool Actions::exists(ID channelId, Frame frame, const MidiEvent& event) const
|
||||
{
|
||||
return exists(channelId, frame, event, m_model.getAllActions());
|
||||
}
|
||||
} // namespace giada::m
|
|
@ -1,164 +0,0 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Giada - Your Hardcore Loopmachine
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (C) 2010-2023 Giovanni A. Zuliani | Monocasual Laboratories
|
||||
*
|
||||
* This file is part of Giada - Your Hardcore Loopmachine.
|
||||
*
|
||||
* Giada - Your Hardcore Loopmachine 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 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef G_ACTIONS_H
|
||||
#define G_ACTIONS_H
|
||||
|
||||
#include "action.h"
|
||||
#include "core/idManager.h"
|
||||
#include "core/midiEvent.h"
|
||||
#include "core/patch.h"
|
||||
#include "core/types.h"
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace giada::m::model
|
||||
{
|
||||
class Model;
|
||||
}
|
||||
|
||||
namespace giada::m
|
||||
{
|
||||
class Actions
|
||||
{
|
||||
public:
|
||||
using Map = std::map<Frame, std::vector<Action>>;
|
||||
|
||||
Actions(model::Model& model);
|
||||
|
||||
/* forEachAction
|
||||
Applies a read-only callback on each action recorded. NEVER do anything
|
||||
inside the callback that might alter the ActionMap. */
|
||||
|
||||
void forEachAction(std::function<void(const Action&)> f) const;
|
||||
|
||||
/* getActionsOnChannel
|
||||
Returns a vector of actions belonging to channel 'ch'. */
|
||||
|
||||
std::vector<Action> getActionsOnChannel(ID channelId) const;
|
||||
|
||||
/* getClosestAction
|
||||
Given a frame 'f' returns the closest action. */
|
||||
|
||||
Action getClosestAction(ID channelId, Frame f, int type) const;
|
||||
|
||||
/* getActionsOnFrame
|
||||
Returns a pointer to a vector of actions recorded on frame 'f', or nullptr
|
||||
if the frame has no actions. */
|
||||
|
||||
const std::vector<Action>* getActionsOnFrame(Frame f) const;
|
||||
|
||||
/* hasActions
|
||||
Checks if the channel has at least one action recorded. */
|
||||
|
||||
bool hasActions(ID channelId, int type = 0) const;
|
||||
|
||||
/* clearAll
|
||||
Deletes all recorded actions. */
|
||||
|
||||
void clearAll();
|
||||
|
||||
/* clearChannel
|
||||
Clears all actions from a channel. */
|
||||
|
||||
void clearChannel(ID channelId);
|
||||
|
||||
/* clearActions
|
||||
Clears the actions by type from a channel. */
|
||||
|
||||
void clearActions(ID channelId, int type);
|
||||
|
||||
/* deleteAction (1)
|
||||
Deletes a specific action. */
|
||||
|
||||
void deleteAction(ID id);
|
||||
|
||||
/* deleteAction (2)
|
||||
Deletes a specific pair of actions. Useful for composite stuff (i.e. MIDI). */
|
||||
|
||||
void deleteAction(ID currId, ID nextId);
|
||||
|
||||
/* updateKeyFrames
|
||||
Update all the key frames in the internal map of actions, according to a
|
||||
lambda function 'f'. */
|
||||
|
||||
void updateKeyFrames(std::function<Frame(Frame old)> f);
|
||||
|
||||
/* updateEvent
|
||||
Changes the event in action 'a'. */
|
||||
|
||||
void updateEvent(ID id, MidiEvent e);
|
||||
|
||||
/* updateSiblings
|
||||
Changes previous and next actions in action with id 'id'. Mostly used for
|
||||
chained actions such as envelopes. */
|
||||
|
||||
void updateSiblings(ID id, ID prevId, ID nextId);
|
||||
|
||||
/* rec (1)
|
||||
Records an action and returns it. Used by the Action Editor. */
|
||||
|
||||
Action rec(ID channelId, Frame frame, MidiEvent e);
|
||||
|
||||
/* rec (2)
|
||||
Transfer a vector of actions into the current ActionMap. This is called by
|
||||
recordHandler when a live session is over and consolidation is required. */
|
||||
|
||||
void rec(std::vector<Action>& actions);
|
||||
|
||||
/* rec (3)
|
||||
Records two actions on channel 'channel'. Useful when recording composite
|
||||
actions in the Action Editor. */
|
||||
|
||||
void rec(ID channelId, Frame f1, Frame f2, MidiEvent e1, MidiEvent e2);
|
||||
|
||||
private:
|
||||
bool exists(ID channelId, Frame frame, const MidiEvent& event, const Map& target) const;
|
||||
bool exists(ID channelId, Frame frame, const MidiEvent& event) const;
|
||||
|
||||
Action* findAction(Map& src, ID id);
|
||||
|
||||
/* updateMapPointers
|
||||
Updates all prev/next actions pointers into the action map. This is required
|
||||
after an action has been recorded, since pushing back new actions in a Action
|
||||
vector makes it reallocating the existing ones. */
|
||||
|
||||
void updateMapPointers(Map& src);
|
||||
|
||||
/* optimize
|
||||
Removes frames without actions. */
|
||||
|
||||
void optimize(Map& map);
|
||||
|
||||
void removeIf(std::function<bool(const Action&)> f);
|
||||
|
||||
model::Model& m_model;
|
||||
};
|
||||
} // namespace giada::m
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue