summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/drumgizmo.cc1
-rw-r--r--src/events.h9
-rw-r--r--src/inputprocessor.cc236
-rw-r--r--src/inputprocessor.h6
-rw-r--r--src/tracer.cc37
-rw-r--r--src/tracer.h84
7 files changed, 305 insertions, 70 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index aad6cbf..44500e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -63,6 +63,7 @@ libdg_la_SOURCES = \
sem.cc \
staminafilter.cc \
thread.cc \
+ tracer.cc \
velocityfilter.cc \
versionstr.cc
@@ -118,6 +119,7 @@ EXTRA_DIST = \
staminafilter.h \
syncedsettings.h \
thread.h \
+ tracer.h \
velocityfilter.h \
versionstr.h \
zrwrapper.h
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index 65af878..591fcda 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -31,6 +31,7 @@
#include <cassert>
#include <cstring>
#include <mutex>
+#include <fstream>
#include <event.h>
#include <audiotypes.h>
diff --git a/src/events.h b/src/events.h
index 18f9af3..f005566 100644
--- a/src/events.h
+++ b/src/events.h
@@ -65,7 +65,10 @@ class EventSample
{
public:
EventSample(channel_t c, float g, AudioFile* af,
- const std::string& grp, std::size_t instrument_id)
+ const std::string& grp,
+ std::size_t instrument_id,
+ std::size_t insert_group_id
+)
: Event(c)
, cache_id(CACHE_NOID)
, gain(g)
@@ -75,6 +78,7 @@ public:
, rampdown_count(-1)
, ramp_length(0)
, instrument_id(instrument_id)
+ , insert_group_id(insert_group_id)
{
}
@@ -92,7 +96,7 @@ public:
sample_t* buffer;
std::size_t buffer_size;
std::size_t buffer_ptr{0}; //< Internal pointer into the current buffer
- std::size_t sample_size{0}; //< Total number of audio samples in this sample.
+ std::size_t sample_size{0}; //< Total number of audio samples in this sample.
float gain;
unsigned int t; //< Internal sample position.
@@ -103,6 +107,7 @@ public:
std::size_t rampdown_offset{0};
float scale{1.0f};
std::size_t instrument_id;
+ std::size_t insert_group_id; //< All EventSample instances created from the same event_t will share this value.
};
class EventQueue
diff --git a/src/inputprocessor.cc b/src/inputprocessor.cc
index 3530128..4514f38 100644
--- a/src/inputprocessor.cc
+++ b/src/inputprocessor.cc
@@ -3,7 +3,7 @@
* inputprocessor.cc
*
* Sat Apr 23 20:39:30 CEST 2016
- * Copyright 2016 André Nusser
+ * Copyright 2016 Andr� Nusser
* andre.nusser@googlemail.com
****************************************************************************/
@@ -29,6 +29,8 @@
#include <list>
#include <hugin.hpp>
+#include <fstream>
+#include <algorithm>
#include "instrument.h"
@@ -38,63 +40,12 @@
#include "cpp11fix.h"
-InputProcessor::InputProcessor(Settings& settings,
- DrumKit& kit,
- std::list<Event*>* activeevents,
- Random& random)
- : kit(kit)
- , activeevents(activeevents)
- , is_stopping(false)
- , settings(settings)
-{
- // Build filter list
- filters.emplace_back(std::make_unique<StaminaFilter>(settings));
- filters.emplace_back(std::make_unique<LatencyFilter>(settings, random));
- filters.emplace_back(std::make_unique<VelocityFilter>(settings, random));
-}
-
-bool InputProcessor::process(std::vector<event_t>& events,
- std::size_t pos,
- double resample_ratio)
-{
- for(auto& event: events)
- {
- if(event.type == EventType::OnSet)
- {
- if(!processOnset(event, pos, resample_ratio))
- {
- continue;
- }
- }
-
- if(event.type == EventType::Choke)
- {
- if(!processChoke(event, pos, resample_ratio))
- {
- continue;
- }
- }
-
- if(!processStop(event))
- {
- return false;
- }
- }
-
- return true;
-}
+//TODO: This is just for development purposes. Remove when done.
+#include "tracer.h"
-std::size_t InputProcessor::getLatency() const
+//Anonymous namespace for local functions.
+namespace
{
- std::size_t latency = 0;
-
- for(const auto& filter : filters)
- {
- latency += filter->getLatency();
- }
-
- return latency;
-}
//! Applies choke with rampdown time in ms to event starting at offset.
static void applyChoke(Settings& settings, EventSample& event,
@@ -164,10 +115,74 @@ static void applyDirectedChoke(Settings& settings, DrumKit& kit,
}
}
+} //End of anonymous namespace.
+
+InputProcessor::InputProcessor(Settings& settings,
+ DrumKit& kit,
+ std::list<Event*>* activeevents,
+ Random& random)
+ : kit(kit)
+ , activeevents(activeevents)
+ , is_stopping(false)
+ , settings(settings)
+ , insert_group_id(0)
+{
+ tracer::trace("building InputProcessor", '\n');
+
+ // Build filter list
+ filters.emplace_back(std::make_unique<StaminaFilter>(settings));
+ filters.emplace_back(std::make_unique<LatencyFilter>(settings, random));
+ filters.emplace_back(std::make_unique<VelocityFilter>(settings, random));
+}
+
+bool InputProcessor::process(std::vector<event_t>& events,
+ std::size_t pos,
+ double resample_ratio)
+{
+ for(auto& event: events)
+ {
+ if(event.type == EventType::OnSet)
+ {
+ if(!processOnset(event, pos, resample_ratio))
+ {
+ continue;
+ }
+ }
+
+ if(event.type == EventType::Choke)
+ {
+ if(!processChoke(event, pos, resample_ratio))
+ {
+ continue;
+ }
+ }
+
+ if(!processStop(event))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+std::size_t InputProcessor::getLatency() const
+{
+ std::size_t latency = 0;
+
+ for(const auto& filter : filters)
+ {
+ latency += filter->getLatency();
+ }
+
+ return latency;
+}
bool InputProcessor::processOnset(event_t& event, std::size_t pos,
double resample_ratio)
{
+ tracer::trace("processOnset was called", '\n');
+
if(!kit.isValid())
{
return false;
@@ -198,6 +213,11 @@ bool InputProcessor::processOnset(event_t& event, std::size_t pos,
return false; // Skip event completely
}
}
+
+ //TODO: A lookup map would be much better...
+ const size_t max_voices=getMaxVoicesForInstrument(instrument_id);
+ //TODO: Somehow this seems like a very specific case of a group.
+ applyVoiceLimit(event, max_voices);
// Mute other instruments in the same group
applyChokeGroup(settings, kit, *instr, event, activeevents);
@@ -220,26 +240,29 @@ bool InputProcessor::processOnset(event_t& event, std::size_t pos,
auto const selected_level = (sample->getPower() - power_min)/power_span;
settings.velocity_modifier_current.store(selected_level/original_level);
+ ++insert_group_id; //Insert group id 0 is not allowed.
for(Channel& ch: kit.channels)
{
const auto af = sample->getAudioFile(ch);
if(af == nullptr || !af->isValid())
{
//DEBUG(inputprocessor, "Missing AudioFile.\n");
+ continue;
}
- else
+
+ //DEBUG(inputprocessor, "Adding event %d.\n", event.offset);
+ auto evt = new EventSample(ch.num, 1.0, af, instr->getGroup(),
+ instrument_id,
+ insert_group_id);
+ evt->offset = (event.offset + pos) * resample_ratio;
+ if(settings.normalized_samples.load() && sample->getNormalized())
{
- //DEBUG(inputprocessor, "Adding event %d.\n", event.offset);
- auto evt = new EventSample(ch.num, 1.0, af, instr->getGroup(),
- instrument_id);
- evt->offset = (event.offset + pos) * resample_ratio;
- if(settings.normalized_samples.load() && sample->getNormalized())
- {
- evt->scale *= event.velocity;
- }
-
- activeevents[ch.num].push_back(evt);
+ evt->scale *= event.velocity;
}
+
+ tracer::trace("event added to channel ", ch.num, " for instrument id ", instrument_id, '\n');
+
+ activeevents[ch.num].push_back(evt);
}
return true;
@@ -325,3 +348,82 @@ bool InputProcessor::processStop(event_t& event)
return true;
}
+
+//TODO: Document.
+void InputProcessor::applyVoiceLimit(const event_t& event, size_t max_voices)
+{
+ //Find out how many voices for the instrument we are currently playing...
+ const auto instrument_id = event.instrument;
+ size_t current_count{0};
+
+ tracer::trace("applyVoiceLimit will count for instrument id ", instrument_id, '\n');
+
+ for(const auto& ch : kit.channels)
+ {
+ current_count+=std::count_if(std::begin(activeevents[ch.num]),
+ std::end(activeevents[ch.num]),
+ [instrument_id](Event const * active_event)
+ {
+ return active_event->getType() == Event::sample
+ && static_cast<EventSample const *>(active_event)->instrument_id == instrument_id;
+ });
+ }
+
+ //Early exit if the max number of voices has yet to be reached...
+ tracer::trace("found ", current_count, " for instrument id ", instrument_id, '\n');
+ if(current_count <= max_voices)
+ {
+ return;
+ }
+
+ //Locate the earliest sample group for this instrument that is not ramping.
+ tracer::trace("locating earliest sample group\n");
+ std::size_t earliest_group{0};
+
+ for(const auto& ch : kit.channels)
+ {
+ for(const auto active_event : activeevents[ch.num])
+ {
+ if(active_event->getType() == Event::sample)
+ {
+ auto& event_sample = *static_cast<EventSample*>(active_event);
+
+ //Same instrument, not ramping, with a lesser group.
+ if(event_sample.instrument_id != instrument_id
+ && -1 == event_sample.rampdown_count
+ //TODO: Not proud of this, not proud of it at all.
+ && (event_sample.insert_group_id < earliest_group
+ || 0 == earliest_group))
+ {
+ earliest_group=event_sample.insert_group_id;
+ }
+ }
+ }
+ }
+
+ tracer::trace("earliest sample group was ", earliest_group, '\n');
+
+ //Ramp down everyone belonging to that group...
+ for(const auto& ch : kit.channels)
+ {
+ for(auto active_event : activeevents[ch.num])
+ {
+ if(active_event->getType() == Event::sample)
+ {
+ auto& event_sample = *static_cast<EventSample*>(active_event);
+ if(event_sample.insert_group_id == earliest_group)
+ {
+ tracer::trace("found and ramping in channel ", ch.num, '\n');
+ applyChoke(settings, event_sample, 68, event.offset);
+ }
+ }
+ }
+ }
+}
+
+//TODO: Document.
+size_t InputProcessor::getMaxVoicesForInstrument(size_t instrument_id) const
+{
+ //TODO: This would depend on the configuration set on the GUI.
+ return 16;
+} \ No newline at end of file
diff --git a/src/inputprocessor.h b/src/inputprocessor.h
index 2101a25..5516146 100644
--- a/src/inputprocessor.h
+++ b/src/inputprocessor.h
@@ -3,7 +3,7 @@
* inputprocessor.h
*
* Sat Apr 23 20:39:30 CEST 2016
- * Copyright 2016 André Nusser
+ * Copyright 2016 Andr� Nusser
* andre.nusser@googlemail.com
****************************************************************************/
@@ -61,8 +61,12 @@ private:
bool processOnset(event_t& event, std::size_t pos, double resample_ratio);
bool processChoke(event_t& event, std::size_t pos, double resample_ratio);
bool processStop(event_t& event);
+ void applyVoiceLimit(const event_t& event, size_t max_voices);
+ size_t getMaxVoicesForInstrument(size_t instrument_id) const;
std::vector<std::unique_ptr<InputFilter>> filters;
Settings& settings;
+
+ size_t insert_group_id; ///< Identifier for all Events added in all different channels from the same event_t.
};
diff --git a/src/tracer.cc b/src/tracer.cc
new file mode 100644
index 0000000..adc621f
--- /dev/null
+++ b/src/tracer.cc
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * tracer.cc
+ *
+ * Sun Dec 29 18:04:28 CET 2019
+ * Copyright 2019 Daniel Pastor
+ * marlborometal@gmail.com
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "tracer.h"
+
+//Instantiation of the static file stream.
+std::unique_ptr<std::ofstream> tracer::tracer_manager::outfile=nullptr;
+
+void tracer::trace()
+{
+ std::flush(tracer_manager::get());
+ return;
+} \ No newline at end of file
diff --git a/src/tracer.h b/src/tracer.h
new file mode 100644
index 0000000..e42c29e
--- /dev/null
+++ b/src/tracer.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * tracer.h
+ *
+ * Sun Dec 29 18:04:28 CET 2019
+ * Copyright 2019 Daniel Pastor
+ * marlborometal@gmail.com
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#pragma once
+
+#include <fstream>
+#include <memory>
+#include <stdexcept>
+
+//! This file contains the trace tool for developmnent purposes. The trace tool
+//! just prints messages to a given file.
+namespace tracer
+{
+
+//! This class takes care of the output stream where trace messages will be
+//! printed. Its methods are not supposed to be called by anyone else than the
+//! "trace" functions.
+class tracer_manager
+{
+ public:
+
+ //! Returns a reference to the file stream.
+ static std::ofstream& get()
+ {
+ if(nullptr==outfile.get())
+ {
+//TODO: This should not be fixed, but either depend on the OS or be able to
+//specified somehow.
+ outfile.reset(new std::ofstream("/tmp/drumgizmo.trace",
+ std::ios::app));
+ }
+
+ if(nullptr==outfile.get())
+ {
+ throw std::runtime_error("the tracer file could not be initialized");
+ }
+
+ return *(outfile.get());
+ }
+
+ private:
+
+ //! Single output file. Will be initialized to nullptr when the program
+ //! starts and freed when the program ends.
+ static std::unique_ptr<std::ofstream> outfile;
+};
+
+//! Trace function without parameters, used on the last call to the variadic
+//! templace "trace".
+void trace();
+
+//! Variadic trace function. Obtains a reference to the file stream and prints
+//! its arguments there.
+template<typename T, typename... Args>
+void trace(T val, Args... args)
+{
+ tracer_manager::get()<<val;
+ trace(args...);
+}
+
+}//End of tracer namespace. \ No newline at end of file