diff options
76 files changed, 1434 insertions, 641 deletions
@@ -1,3 +1,82 @@ +Version 0.9.20 +============== +Release date: September 8th 2022 +Contributors: chaot4, corrados, trebmuh, deva + +This release was originally intended as a bugfix release, but quite a few +features also managed to find their way in. + +Noteworthy bugs that has been fixed: + - Software regression error in cymbal choke code has been fixed. So now +   choking of cymbals using both directed chokes and after-touch midi +   events work again as expected. + - A compilation error due to an update in LV2 API (we used an +   obsolete LV2 type) has been fixed, so now compilation should work for +   everybody again. + - Code can now properly be compiled with NSL support disabled at +   configure time. + - Compilation with the modern gcc-11 compiler has been fixed. + +On top of this a lot of crash-bugs has been fixed. + +Thanks to corrados, this version adds support for midi input through +the alsa seq driver for the command line version of drumgizmo. So now +drumgizmo can be run from the commandline entirely without the need +for jack. + +Compilation Bugs: + - Fix compilation with gcc-11 + - Fix compilation issue when compiling without nls enabled. + - Remove sndfile.h from audiofile header + - Fix missing backslash in libdg includepaths + - Fix compiler warning. + - Add missing include + - Make configure fail if nls is enabled but gettext tools not found. + +Crash Bugs: +  - Fix crash when loading a kit with more channels than the engine +    was compiled for. +  - Fix crash when loading Crocell kit in ardour (stack allocation +    issue) - see Ardour bug report. +    - Get rid of big stack allocation during resampler (re-)configuration. +  - Prevent processing jack clients that are being deleted. +  - Fix crash when pressing play while loading a drumkit. +    - Skip events whose audio-files has not yet been loaded. +  - Fix crash when doing async-load in cli. + +Other Bugs: + - Fixed directed-chokes regression error. + - Fix after-touch chokes regression error. + - Fix wrong sample selection with instruments having only two samples. + - Make aftertouch choke if velocities > 0 instead of == 0 as this +   seem to be the vdrum vendor concensus. + - Clear all active events (ie. stop playing samples) when loading a new kit. + - Fix ALSA output frame size change. +   - added getBufferSize function for alsa out + +Features: + - Record and measure real cymbal choke-time and use this value +   instead of the current 68ms. +   - Adjust choke ramp-down time to better reflect the actual +     dampening time of a hand-dampened cymbal. + - Add support for triggering multiple instruments with one midi note. + - Add voice-limit parameters to cli + - Add setting for controlling ALSA periods to output module. + - Add ALSA MIDI seq input support + +Other: + - Add unit-test for EventsDS::clear() method. + - Add clear member function to EventsDS. + - Add assert to break infinite loop in case of a bug. + - Add -Wextra to debug compilation flags. + - Make it possible to (only) build unit-test in parrallel. + - Add dggui namespace to libdggui components. + - Split UI code into application/plugin UI and UI library. + - Run and fix unit-tests on windows. + - Make rcgen compile and work on windows again through autotools. + - Improve cocoa/macOS rendering speed by removing redraw on all events. + - Reduce UI window height to fit on low-res displays. +  Version 0.9.19  ==============  Release date: November 22nd 2020 diff --git a/RELEASE-CHECKLIST b/RELEASE-CHECKLIST index eb51141..a46ffc7 100644 --- a/RELEASE-CHECKLIST +++ b/RELEASE-CHECKLIST @@ -4,7 +4,7 @@ Check list for releasing:   [ ]  Update man page - [ ]  Bump version in version.h + [ ]  Bump version in version.h and in man pages and po/pot files.   [ ]  Update ChangeLog @@ -16,6 +16,7 @@ mkdir -p actest  cat << EOF > actest/configure.ac  AC_INIT([actest], [1.0.0])  AC_PROG_OBJCXX +AC_OUTPUT([])  EOF  [ -f acinclude.m4 ] && rm acinclude.m4  autoreconf -W error actest 2>/dev/null || echo "AC_DEFUN([AC_PROG_OBJCXX],[echo ' - ObjC++ hack - not support by this platform, but not needed either.'])" > acinclude.m4 diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc index 8eba4c9..bca55d2 100644 --- a/drumgizmo/drumgizmoc.cc +++ b/drumgizmo/drumgizmoc.cc @@ -46,8 +46,6 @@  #include "enginefactory.h"  #include "bytesizeparser.h" -#include "event.h" -  #include "nolocale.h"  struct ParmToken diff --git a/drumgizmo/input/jackmidi.cc b/drumgizmo/input/jackmidi.cc index 445678b..7081bf1 100644 --- a/drumgizmo/input/jackmidi.cc +++ b/drumgizmo/input/jackmidi.cc @@ -122,6 +122,6 @@ void JackMidiInputEngine::process(jack_nframes_t num_frames)  		jack_midi_event_get(&event, buffer, i);  		processNote(event.buffer, event.size, event.time, events);  	} -	jack_midi_clear_buffer(buffer); +  	pos += num_frames;  } diff --git a/drumgizmo/input/midifile.h b/drumgizmo/input/midifile.h index 5756718..a8cf574 100644 --- a/drumgizmo/input/midifile.h +++ b/drumgizmo/input/midifile.h @@ -25,9 +25,9 @@   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.   */  #pragma once +  #include <string> -#include <event.h>  #include <smf.h>  #include "audioinputenginemidi.h" diff --git a/drumgizmo/input/test.cc b/drumgizmo/input/test.cc index 955d218..bc88c48 100644 --- a/drumgizmo/input/test.cc +++ b/drumgizmo/input/test.cc @@ -27,7 +27,6 @@  #include <stdlib.h>  #include <string> -#include "event.h"  #include "test.h"  TestInputEngine::TestInputEngine() diff --git a/drumgizmo/input/test.h b/drumgizmo/input/test.h index baf7c95..f1e0b42 100644 --- a/drumgizmo/input/test.h +++ b/drumgizmo/input/test.h @@ -27,7 +27,6 @@  #pragma once  #include <string> -#include "event.h"  #include "audioinputengine.h"  class TestInputEngine diff --git a/drumgizmo/jackclient.cc b/drumgizmo/jackclient.cc index 8bf0939..0b05358 100644 --- a/drumgizmo/jackclient.cc +++ b/drumgizmo/jackclient.cc @@ -28,12 +28,6 @@  #include "jackclient.h" -JackProcess::~JackProcess() -{ -} - -// -------------------------------------------------------------------- -  JackPort::JackPort(JackClient& client, const std::string& name,                     const char* type, JackPortFlags flags)  	: client{client.client} // register jack port for given client @@ -57,8 +51,7 @@ int JackClient::wrapJackProcess(jack_nframes_t nframes, void* arg)  	return static_cast<JackClient*>(arg)->process(nframes);  } -void JackClient::latencyCallback(jack_latency_callback_mode_t mode, -                                 void* arg) +void JackClient::latencyCallback(jack_latency_callback_mode_t mode, void* arg)  {  	static_cast<JackClient*>(arg)->jackLatencyCallback(mode);  } @@ -92,12 +85,23 @@ JackClient::~JackClient()  void JackClient::add(JackProcess& process)  { -	processes.insert(&process); +	JackProcessContainer c; +	c.process = &process; +	processes.push_back(std::move(c));  }  void JackClient::remove(JackProcess& process)  { -	processes.erase(&process); +	// Do not erase here. Instead mark as disabled - it will be erased at next +	// JackClient::process call. +	for(auto& ptr : processes) +	{ +		if(ptr.process == &process) +		{ +			ptr.active = false; +		} +	} +	dirty = true;  }  void JackClient::activate() @@ -111,10 +115,30 @@ void JackClient::activate()  int JackClient::process(jack_nframes_t num_frames)  { +	// Clear out any inactive processes before iterating +	if(dirty) +	{ +		auto it = processes.begin(); +		while(it != processes.end()) +		{ +			if(it->active == false) +			{ +				it = processes.erase(it); +			} +			else +			{ +				it++; +			} +		} + +		dirty = false; +	} +  	for(auto& ptr : processes)  	{ -		ptr->process(num_frames); +		ptr.process->process(num_frames);  	} +  	return 0;  } @@ -122,7 +146,7 @@ void JackClient::jackLatencyCallback(jack_latency_callback_mode_t mode)  {  	for(auto& ptr : processes)  	{ -		ptr->jackLatencyCallback(mode); +		ptr.process->jackLatencyCallback(mode);  	}  } diff --git a/drumgizmo/jackclient.h b/drumgizmo/jackclient.h index f769ab4..04d6654 100644 --- a/drumgizmo/jackclient.h +++ b/drumgizmo/jackclient.h @@ -27,7 +27,7 @@  #pragma once  #include <vector>  #include <string> -#include <set> +#include <list>  #include <jack/jack.h> @@ -38,7 +38,7 @@ class JackClient;  class JackProcess  {  public: -	virtual ~JackProcess(); +	virtual ~JackProcess() = default;  	virtual void process(jack_nframes_t num_frames) = 0;  	virtual void jackLatencyCallback(jack_latency_callback_mode_t mode) {}  }; @@ -76,7 +76,13 @@ public:  private:  	jack_client_t* client; -	std::set<JackProcess*> processes; +	bool dirty{false}; +	struct JackProcessContainer +	{ +		JackProcess *process; +		bool active{true}; +	}; +	std::list<JackProcessContainer> processes;  	bool is_active;  	bool is_freewheeling; diff --git a/man/drumgizmo.fr.1 b/man/drumgizmo.fr.1 index 1d7f891..794d762 100644 --- a/man/drumgizmo.fr.1 +++ b/man/drumgizmo.fr.1 @@ -155,21 +155,55 @@ Options du timing de l'humaniseur.  \fBregain\fR=<val> (Contrôle la rapidité avec laquelle le batteur se rattrape au tempo. [0; 1])  .RE +\fB-t, --velocity-humanizer\fR +.RS 7 +Permet d'adapter les vitesses d'entrée pour obtenir un son plus réaliste. + +.RE +\fB-T, --velocity-humanizerparms parmlist\fR +.RS 7 +Options de l'humaniseur de vélocité. + +.P +\fBattack\fR=<val> (La vitesse à laquelle la vélocité est réduite lorsque vous jouez des notes rapides. +Des valeurs plus faibles entraînent une réduction plus rapide de la vitesse. [0,1]) +.P +\fBrelease\fR=<val> (La vitesse à laquelle le batteur retrouve la vélocité +lorsqu'il y a des espaces entre les notes. Des valeurs plus faibles entraînent une reprise plus rapide. [0,1]) +.P +\fBstddev\fR=<val> (L'écart-type pour l'humaniseur de vitesse. +Une valeur plus élevée rend plus probable qu'un échantillon +plus éloigné de la vélocité d'entrée soit joué. [0,4.5]) + +.RE +\fB-l, --voice-limit\fR +.RS 7 +Activer la limite vocale. + +.RE +\fB-L, --voice-limitparms parmlist\fR +.RS 7 +Options de limite de voix. + +.P +\fBmax\fR=<val> (Nombre maximum de voix pour chaque instrument avant +que les anciens échantillons ne soient réduits. [1,30]) +.P +\fBrampdown\fR=<val> (Temps qu'il faut à un ancien échantillon pour +devenir complètement silencieux. [0.01,2.0]) + +.RE  \fB-p, --parameters parmlist\fR  .RS 7  Paramètres de l'algorithme de sélection des échantillons.  .P  \fBclose\fR=<val> (L'importance accordée au choix d'un échantillon proche de  -la valeur réelle de la vitesse (après humanisation) [0; 16]) +la valeur réelle de la vitesse (après humanisation) [0,1])  .P  \fBdiverse\fR=<val> (L'importance accordée au choix d'échantillons qui -n'ont pas été joués récemment [0; 0.5]) -.P -\fBrandom\fR=<val> (La quantité d'aléatoire ajoutée [0; 0.5]) +n'ont pas été joués récemment [0,1])  .P -\fBstddev\fR=<val> (L'écart type pour la sélection de l'échantillon. -Plus la valeur est élevée, plus il est probable qu'un échantillon -plus éloigné de la vitesse d'entrée sera joué [0; 4.5]) +\fBrandom\fR=<val> (La quantité d'aléatoire ajoutée [0,1])  .RE  \fB-v, --version\fR diff --git a/plugin/Makefile.mingw32.in b/plugin/Makefile.mingw32.in index ad47bcc..9cfcc9e 100644 --- a/plugin/Makefile.mingw32.in +++ b/plugin/Makefile.mingw32.in @@ -39,7 +39,7 @@ DG_SRC = \  	@top_srcdir@/src/midimapper.cc \  	@top_srcdir@/src/path.cc \  	@top_srcdir@/src/powerlist.cc \ -	@top_srcdir@/src/powermap.cc \ +	@top_srcdir@/src/curvemap.cc \  	@top_srcdir@/src/powermapfilter.cc \  	@top_srcdir@/src/random.cc \  	@top_srcdir@/src/sample.cc \ diff --git a/plugin/plugingizmo b/plugin/plugingizmo -Subproject be64ddf9da525cd5c6757464efc966052731ba7 +Subproject a88c76afd8fbfe31b76010bac34c1437b192724 diff --git a/plugingui/diskstreamingframecontent.cc b/plugingui/diskstreamingframecontent.cc index 4c63817..5420afd 100644 --- a/plugingui/diskstreamingframecontent.cc +++ b/plugingui/diskstreamingframecontent.cc @@ -95,7 +95,7 @@ void DiskstreamingframeContent::resize(std::size_t width, std::size_t height)  void DiskstreamingframeContent::limitSettingsValueChanged(std::size_t value)  { -	float new_slider_value = (float)(value - min_limit)/(max_limit - min_limit); +	float new_slider_value = (float)(value - min_limit)/(float)(max_limit - min_limit);  	slider.setValue(new_slider_value);  	if(new_slider_value < 0.99) @@ -116,7 +116,7 @@ void DiskstreamingframeContent::limitSettingsValueChanged(std::size_t value)  void DiskstreamingframeContent::limitValueChanged(float value)  {  	std::size_t new_limit = value < 0.99 ? -		value * (max_limit - min_limit) + min_limit : +		value * (float)(max_limit - min_limit) + min_limit :  		std::numeric_limits<std::size_t>::max();  	settings.disk_cache_upper_limit.store(new_limit); diff --git a/plugingui/locale/da.po b/plugingui/locale/da.po index e25235f..e3904d0 100644 --- a/plugingui/locale/da.po +++ b/plugingui/locale/da.po @@ -6,7 +6,7 @@  #  msgid ""  msgstr "" -"Project-Id-Version: drumgizmo 0.9.17\n" +"Project-Id-Version: drumgizmo 0.9.20\n"  "Report-Msgid-Bugs-To: \n"  "POT-Creation-Date: 2019-09-13 21:07+0200\n"  "PO-Revision-Date: 2019-09-13 19:42+0200\n" diff --git a/plugingui/locale/drumgizmo.pot b/plugingui/locale/drumgizmo.pot index 72e600e..e93e387 100644 --- a/plugingui/locale/drumgizmo.pot +++ b/plugingui/locale/drumgizmo.pot @@ -6,7 +6,7 @@  #, fuzzy  msgid ""  msgstr "" -"Project-Id-Version: drumgizmo 0.9.19\n" +"Project-Id-Version: drumgizmo 0.9.20\n"  "Report-Msgid-Bugs-To: \n"  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" diff --git a/plugingui/locale/fr.po b/plugingui/locale/fr.po index b46174c..c2fbb63 100644 --- a/plugingui/locale/fr.po +++ b/plugingui/locale/fr.po @@ -7,7 +7,7 @@  #  msgid ""  msgstr "" -"Project-Id-Version: drumgizmo 0.9.18.1\n" +"Project-Id-Version: drumgizmo 0.9.20\n"  "Report-Msgid-Bugs-To: \n"  "POT-Creation-Date: 2019-09-13 21:07+0200\n"  "PO-Revision-Date: 2020-11-21 16:49+0200\n" diff --git a/plugingui/maintab.cc b/plugingui/maintab.cc index 5c5fd02..d95885e 100644 --- a/plugingui/maintab.cc +++ b/plugingui/maintab.cc @@ -131,7 +131,7 @@ MainTab::MainTab(dggui::Widget* parent,  	layout.setResizeChildren(true);  	//Left column... -	add(_("Drumkit"), drumkit_frame, drumkitframe_content, 14, 0); +	add(_("Drumkit"), drumkit_frame, drumkitframe_content, 15, 0);  	add(_("Status"), status_frame, statusframe_content, 12, 0);  	add(_("Resampling"), resampling_frame, resamplingframe_content, 10, 0);  	add(_("Voice Limit"), voicelimit_frame, voicelimit_content, 10, 0); @@ -153,7 +153,7 @@ MainTab::MainTab(dggui::Widget* parent,  	add(_("Visualizer"), visualizer_frame, visualizerframe_content, 14, 1);  	visualizer_frame.setHelpText(visualizer_tip); -	add(_("Velocity Curve"), power_frame, powerframe_content, 20, 1); +	add(_("Velocity Curve"), power_frame, powerframe_content, 21, 1);  	power_frame.setHelpText(power_tip);  	humanizer_frame.setOnSwitch(settings.enable_velocity_modifier); diff --git a/plugingui/mainwindow.h b/plugingui/mainwindow.h index ae0da8b..e517a0d 100644 --- a/plugingui/mainwindow.h +++ b/plugingui/mainwindow.h @@ -47,7 +47,7 @@ class MainWindow  public:  	static constexpr std::size_t main_width{750}; -	static constexpr std::size_t main_height{800}; +	static constexpr std::size_t main_height{740};  	MainWindow(Settings& settings, void* native_window);  	~MainWindow(); diff --git a/plugingui/powerwidget.cc b/plugingui/powerwidget.cc index 9be0c48..71ad74b 100644 --- a/plugingui/powerwidget.cc +++ b/plugingui/powerwidget.cc @@ -31,7 +31,6 @@  #include <notifier.h>  #include <settings.h> -#include <powermap.h>  #include <hugin.hpp>  #include <cmath> @@ -120,7 +119,7 @@ PowerWidget::Canvas::Canvas(dggui::Widget* parent,  void PowerWidget::Canvas::repaintEvent(dggui::RepaintEvent *repaintEvent)  { -	if(width() < 1 || height() < 1) +	if(width() < 4 || height() < 4)  	{  		return;  	} diff --git a/plugingui/powerwidget.h b/plugingui/powerwidget.h index 3a7bb8e..3d09e6b 100644 --- a/plugingui/powerwidget.h +++ b/plugingui/powerwidget.h @@ -34,7 +34,7 @@  #include <dggui/label.h>  #include <dggui/font.h> -#include <powermap.h> +#include <curvemap.h>  struct Settings;  class SettingsNotifier; @@ -75,7 +75,7 @@ private:  		virtual void mouseLeaveEvent() override;  	private: -		Powermap power_map; +		CurveMap power_map;  		void parameterChangedFloat(float);  		void parameterChangedBool(bool); diff --git a/plugingui/resamplingframecontent.cc b/plugingui/resamplingframecontent.cc index d92dc27..6e631c7 100644 --- a/plugingui/resamplingframecontent.cc +++ b/plugingui/resamplingframecontent.cc @@ -30,6 +30,8 @@  #include <translation.h> +#include <algorithm> +  namespace GUI  { @@ -70,9 +72,9 @@ ResamplingframeContent::ResamplingframeContent(dggui::Widget* parent,  void ResamplingframeContent::resize(std::size_t width, std::size_t height)  {  	Widget::resize(width, height); -	text_field.resize(width - 50, height); -	quality_knob.move(width - 36, 20); -	quality_label.move(width - 40, 0); +	text_field.resize(std::max(width, std::size_t{51}) - 50, height); +	quality_knob.move(std::max(width, std::size_t{37}) - 36, 20); +	quality_label.move(std::max(width, std::size_t{41}) - 40, 0);  }  void ResamplingframeContent::updateContent() diff --git a/src/Makefile.am b/src/Makefile.am index 85b10fa..e2a2583 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,49 +33,50 @@ libdg_la_CPPFLAGS = \  	$(DEBUG_FLAGS) \  	-I$(top_srcdir)/hugin -I$(top_srcdir)/pugixml/src \  	$(SSEFLAGS) -I$(top_srcdir)/zita-resampler/libs \ -	$(SNDFILE_CFLAGS) $(PTHREAD_CFLAGS) +	$(SNDFILE_CFLAGS) $(PTHREAD_CFLAGS) \ +	-Wno-deprecated-declarations  libdg_la_LIBADD = \  	$(SNDFILE_LIBS) $(PTHREAD_LIBS) libzr.la libpugi.la  libdg_la_SOURCES = \ -	audiocachefile.cc \ -	audiocache.cc \ -	audiocacheeventhandler.cc \ -	audiocacheidmanager.cc \ -	audioinputenginemidi.cc \ -	audiofile.cc \ -	bytesizeparser.cc \ -	channel.cc \ -	channelmixer.cc \ -	configfile.cc \ -	configparser.cc \ -	directory.cc \ -	domloader.cc \ -	dgxmlparser.cc \ -	drumgizmo.cc \ -	drumgizmoconf.cc \ -	drumkit.cc \ -	drumkitloader.cc \ -	events.cc \ -	events_ds.cc \ -	inputprocessor.cc \ -	instrument.cc \ -	latencyfilter.cc \ -	midimapparser.cc \ -	midimapper.cc \ -	path.cc \ -	powerlist.cc \ -	powermap.cc \ -	powermapfilter.cc \ -	random.cc \ -	sample.cc \ -	sample_selection.cc \ -	sem.cc \ -	staminafilter.cc \ -	thread.cc \ -	velocityfilter.cc \ -	versionstr.cc +	$(top_srcdir)/src/audiocachefile.cc \ +	$(top_srcdir)/src/audiocache.cc \ +	$(top_srcdir)/src/audiocacheeventhandler.cc \ +	$(top_srcdir)/src/audiocacheidmanager.cc \ +	$(top_srcdir)/src/audioinputenginemidi.cc \ +	$(top_srcdir)/src/audiofile.cc \ +	$(top_srcdir)/src/bytesizeparser.cc \ +	$(top_srcdir)/src/channel.cc \ +	$(top_srcdir)/src/channelmixer.cc \ +	$(top_srcdir)/src/configfile.cc \ +	$(top_srcdir)/src/configparser.cc \ +	$(top_srcdir)/src/directory.cc \ +	$(top_srcdir)/src/domloader.cc \ +	$(top_srcdir)/src/dgxmlparser.cc \ +	$(top_srcdir)/src/drumgizmo.cc \ +	$(top_srcdir)/src/drumgizmoconf.cc \ +	$(top_srcdir)/src/drumkit.cc \ +	$(top_srcdir)/src/drumkitloader.cc \ +	$(top_srcdir)/src/events.cc \ +	$(top_srcdir)/src/events_ds.cc \ +	$(top_srcdir)/src/inputprocessor.cc \ +	$(top_srcdir)/src/instrument.cc \ +	$(top_srcdir)/src/latencyfilter.cc \ +	$(top_srcdir)/src/midimapparser.cc \ +	$(top_srcdir)/src/midimapper.cc \ +	$(top_srcdir)/src/path.cc \ +	$(top_srcdir)/src/powerlist.cc \ +	$(top_srcdir)/src/curvemap.cc \ +	$(top_srcdir)/src/powermapfilter.cc \ +	$(top_srcdir)/src/random.cc \ +	$(top_srcdir)/src/sample.cc \ +	$(top_srcdir)/src/sample_selection.cc \ +	$(top_srcdir)/src/sem.cc \ +	$(top_srcdir)/src/staminafilter.cc \ +	$(top_srcdir)/src/thread.cc \ +	$(top_srcdir)/src/velocityfilter.cc \ +	$(top_srcdir)/src/versionstr.cc  EXTRA_DIST = \  	$(libzr_la_SOURCES) \ @@ -106,7 +107,7 @@ EXTRA_DIST = \  	drumgizmoconf.h \  	drumkit.h \  	drumkitloader.h \ -	event.h \ +	engineevent.h \  	events.h \  	events_ds.h \  	grid.h \ @@ -121,10 +122,11 @@ EXTRA_DIST = \  	midimapper.h \  	nolocale.h \  	notifier.h \ +	owner.h \  	path.h \  	platform.h \  	powerlist.h \ -	powermap.h \ +	curvemap.h \  	powermapfilter.h \  	random.h \  	range.h \ @@ -140,3 +142,10 @@ EXTRA_DIST = \  	velocityfilter.h \  	versionstr.h \  	zrwrapper.h + +%.lint: %.cc +	clang-tidy --quiet $< -- $(libdg_la_CPPFLAGS) $(CXXFLAGS) + +LINT_FILES = $(libdg_la_SOURCES:.cc=.lint) + +lint: $(LINT_FILES) diff --git a/src/atomic.h b/src/atomic.h index 7ca5d1e..a29eeee 100644 --- a/src/atomic.h +++ b/src/atomic.h @@ -69,7 +69,7 @@ public:  		: data{}  		, mutex{}  	{ -		std::lock_guard<std::mutex> lock{other.mutex}; +		const std::lock_guard<std::mutex> lock{other.mutex};  		data = other.data;  	} @@ -77,13 +77,13 @@ public:  		: data{}  		, mutex{}  	{ -		std::lock_guard<std::mutex> lock{other.mutex}; +		const std::lock_guard<std::mutex> lock{other.mutex};  		std::swap(data, other.data);  	}  	T operator=(T data)  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		this->data = std::move(data);  		return this->data;  	} @@ -100,42 +100,42 @@ public:  	void store(T data)  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		this->data = std::move(data);  	}  	T load() const { -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		return data;  	}  	T exchange(T data){ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		std::swap(data, this->data);  		return data;  	}  	bool operator==(const T& other) const  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		return other == data;  	}  	bool operator!=(const T& other) const  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		return !(other == data);  	}  	bool operator==(const Atomic<T>& other) const  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		return other.load() == data;  	}  	bool operator!=(const Atomic<T>& other) const  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		return !(other.load() == data);  	} diff --git a/src/audio.h b/src/audio.h index d022147..289f662 100644 --- a/src/audio.h +++ b/src/audio.h @@ -26,4 +26,4 @@   */  #pragma once -#include <audiotypes.h> +#include "audiotypes.h" diff --git a/src/audiocache.cc b/src/audiocache.cc index a2d26d9..92d3d61 100644 --- a/src/audiocache.cc +++ b/src/audiocache.cc @@ -28,8 +28,8 @@  #include <mutex> -#include <stdio.h> -#include <assert.h> +#include <cstdio> +#include <cassert>  #include <hugin.hpp> @@ -64,9 +64,9 @@ void AudioCache::deinit()  }  // Invariant: initial_samples_needed < preloaded audio data -sample_t* AudioCache::open(const AudioFile& file, -                           std::size_t initial_samples_needed, -                           int channel, cacheid_t& id) +gsl::owner<sample_t*> AudioCache::open(const AudioFile& file, +                                       std::size_t initial_samples_needed, +                                       int channel, cacheid_t& new_cacheid)  {  	assert(chunk_size); // Assert updateChunkSize was called before processing. @@ -74,16 +74,16 @@ sample_t* AudioCache::open(const AudioFile& file,  	{  		settings.number_of_underruns.fetch_add(1);  		// File preload not yet ready - skip this sample. -		id = CACHE_DUMMYID; +		new_cacheid = CACHE_DUMMYID;  		assert(nodata);  		return nodata;  	}  	// Register a new id for this cache session. -	id = id_manager.registerID({}); +	new_cacheid = id_manager.registerID({});  	// If we are out of available ids we get CACHE_DUMMYID -	if(id == CACHE_DUMMYID) +	if(new_cacheid == CACHE_DUMMYID)  	{  		settings.number_of_underruns.fetch_add(1);  		// Use nodata buffer instead. @@ -91,20 +91,20 @@ sample_t* AudioCache::open(const AudioFile& file,  		return nodata;  	} -	// Get the cache_t connected with the registered id. -	cache_t& c = id_manager.getCache(id); +	// Get the CacheBuffer connected with the registered id. +	CacheBuffer& cache = id_manager.getCache(new_cacheid); -	c.afile = nullptr; // File is opened when needed. -	c.channel = channel; +	cache.afile = nullptr; // File is opened when needed. +	cache.channel = channel;  	// Next call to 'next()' will read from this point. -	c.localpos = initial_samples_needed; +	cache.localpos = initial_samples_needed; -	c.ready = false; -	c.front = nullptr; // This is allocated when needed. -	c.back = nullptr; // This is allocated when needed. +	cache.ready = false; +	cache.front = nullptr; // This is allocated when needed. +	cache.back = nullptr; // This is allocated when needed. -	std::size_t cropped_size; +	std::size_t cropped_size{};  	if(file.preloadedsize == file.size)  	{ @@ -122,162 +122,162 @@ sample_t* AudioCache::open(const AudioFile& file,  		//  \----------------------v-------------------/  		//                     cropped_size -		cropped_size = file.preloadedsize - c.localpos; +		cropped_size = file.preloadedsize - cache.localpos;  		cropped_size -= cropped_size % framesize;  		cropped_size += initial_samples_needed;  	} -	c.preloaded_samples = file.data; -	c.preloaded_samples_size = cropped_size; +	cache.preloaded_samples = file.data; +	cache.preloaded_samples_size = cropped_size;  	// Next potential read from disk will read from this point. -	c.pos = cropped_size; +	cache.pos = cropped_size;  	// Only load next buffer if there is more data in the file to be loaded... -	if(c.pos < file.size) +	if(cache.pos < file.size)  	{ -		c.afile = &event_handler.openFile(file.filename); +		cache.afile = &event_handler.openFile(file.filename); -		if(c.back == nullptr) +		if(cache.back == nullptr)  		{ -			c.back = new sample_t[chunk_size]; +			cache.allocBack(chunk_size);  		} -		event_handler.pushLoadNextEvent(c.afile, c.channel, c.pos, -		                                c.back, &c.ready); +		event_handler.pushLoadNextEvent(cache.afile, cache.channel, cache.pos, +		                                cache.back, &cache.ready);  	} -	return c.preloaded_samples; // return preloaded data +	return cache.preloaded_samples; // return preloaded data  } -sample_t* AudioCache::next(cacheid_t id, std::size_t& size) +gsl::owner<sample_t*> AudioCache::next(cacheid_t cacheid, std::size_t& size)  { -	if(id == CACHE_DUMMYID) +	if(cacheid == CACHE_DUMMYID)  	{  		settings.number_of_underruns.fetch_add(1);  		assert(nodata);  		return nodata;  	} -	cache_t& c = id_manager.getCache(id); +	CacheBuffer& cache = id_manager.getCache(cacheid); -	if(c.preloaded_samples) +	if(cache.preloaded_samples != nullptr)  	{  		// We are playing from memory: -		if(c.localpos < c.preloaded_samples_size) +		if(cache.localpos < cache.preloaded_samples_size)  		{ -			sample_t* s = c.preloaded_samples + c.localpos; +			sample_t* samples = cache.preloaded_samples + cache.localpos; // NOLINT: Fix with span?  			// If only a partial frame is returned. Reflect this in the size -			size = std::min(size, c.preloaded_samples_size - c.localpos); +			size = std::min(size, cache.preloaded_samples_size - cache.localpos); -			c.localpos += size; -			return s; +			cache.localpos += size; +			return samples;  		} -		c.preloaded_samples = nullptr; // Start using samples from disk. +		cache.preloaded_samples = nullptr; // Start using samples from disk.  	}  	else  	{  		// We are playing from cache: -		if(c.localpos < chunk_size) +		if(cache.localpos < chunk_size)  		{ -			if(c.front == nullptr) +			if(cache.front == nullptr)  			{  				// Just return silence.  				settings.number_of_underruns.fetch_add(1); -				c.localpos += size; // Skip these samples so we don't loose sync. +				cache.localpos += size; // Skip these samples so we don't loose sync.  				assert(nodata);  				return nodata;  			} -			sample_t* s = c.front + c.localpos; +			sample_t* samples = cache.front + cache.localpos;// NOLINT: Fix with span?  			// If only a partial frame is returned. Reflect this in the size -			size = std::min(size, chunk_size - c.localpos); -			c.localpos += size; -			return s; +			size = std::min(size, chunk_size - cache.localpos); +			cache.localpos += size; +			return samples;  		}  	}  	// Check for buffer underrun -	if(!c.ready) +	if(!cache.ready)  	{  		// Just return silence.  		settings.number_of_underruns.fetch_add(1); -		c.localpos += size; // Skip these samples so we don't loose sync. +		cache.localpos += size; // Skip these samples so we don't loose sync.  		assert(nodata);  		return nodata;  	}  	// Swap buffers -	std::swap(c.front, c.back); +	cache.swap();  	// Next time we go here we have already read the first frame. -	c.localpos = size; +	cache.localpos = size; -	c.pos += chunk_size; +	cache.pos += chunk_size;  	// Does the file have remaining unread samples? -	assert(c.afile); // Assert that we have an audio file. -	if(c.pos < c.afile->getSize()) +	assert(cache.afile); // Assert that we have an audio file. +	if(cache.pos < cache.afile->getSize())  	{  		// Do we have a back buffer to read into? -		if(c.back == nullptr) +		if(cache.back == nullptr)  		{ -			c.back = new sample_t[chunk_size]; +			cache.allocBack(chunk_size);  		} -		event_handler.pushLoadNextEvent(c.afile, c.channel, c.pos, -		                                c.back, &c.ready); +		event_handler.pushLoadNextEvent(cache.afile, cache.channel, cache.pos, +		                                cache.back, &cache.ready);  	}  	// We should always have a front buffer at this point. -	assert(c.front); -	return c.front; +	assert(cache.front); +	return cache.front;  } -bool AudioCache::isReady(cacheid_t id) +bool AudioCache::isReady(cacheid_t cacheid)  { -	if(id == CACHE_DUMMYID) +	if(cacheid == CACHE_DUMMYID)  	{  		return true;  	} -	cache_t& cache = id_manager.getCache(id); +	const CacheBuffer& cache = id_manager.getCache(cacheid);  	return cache.ready;  } -void AudioCache::close(cacheid_t id) +void AudioCache::close(cacheid_t cacheid)  { -	if(id == CACHE_DUMMYID) +	if(cacheid == CACHE_DUMMYID)  	{  		return;  	} -	event_handler.pushCloseEvent(id); +	event_handler.pushCloseEvent(cacheid);  }  void AudioCache::setFrameSize(std::size_t framesize)  {  	// Make sure the event handler thread is stalled while we set the framesize  	// state. -	std::lock_guard<AudioCacheEventHandler> event_handler_lock(event_handler); +	const std::lock_guard<AudioCacheEventHandler> event_handler_lock(event_handler);  	// NOTE: Not threaded...  	//std::lock_guard<AudioCacheIDManager> id_manager_lock(id_manager);  	if(framesize > nodata_framesize)  	{ -		if(nodata) +		if(nodata != nullptr)  		{ -			nodata_dirty.emplace_back(std::move(nodata)); // Store for later deletion. +			nodata_dirty.emplace_back(nodata); // Store for later deletion.  		}  		nodata = new sample_t[framesize];  		nodata_framesize = framesize;  		for(std::size_t i = 0; i < framesize; ++i)  		{ -			nodata[i] = 0.0f; +			nodata[i] = 0.0f;// NOLINT: Fix with span?  		}  	} @@ -292,9 +292,11 @@ std::size_t AudioCache::getFrameSize() const  void AudioCache::updateChunkSize(std::size_t output_channels)  {  	// Make sure we won't get out-of-range chunk sizes. -	std::size_t disk_cache_chunk_size = -		std::max(settings.disk_cache_chunk_size.load(), std::size_t(512u * 1024u)); -	output_channels = std::max(output_channels, std::size_t(1u)); +	constexpr std::size_t max_cache_chunk_size{512ul * 1024ul}; +	const auto disk_cache_chunk_size = +		std::max(settings.disk_cache_chunk_size.load(), max_cache_chunk_size); +	constexpr std::size_t min_output_channels{1}; +	output_channels = std::max(output_channels, min_output_channels);  	// 1MB pr. chunk divided over 16 channels, 4 bytes pr. sample.  	const auto ideal_chunk_size = diff --git a/src/audiocache.h b/src/audiocache.h index 9c6fa53..632aae9 100644 --- a/src/audiocache.h +++ b/src/audiocache.h @@ -38,6 +38,7 @@  #include "audiocacheidmanager.h"  #include "audiocacheeventhandler.h"  #include "settings.h" +#include "owner.h"  class AudioCache  { @@ -68,8 +69,10 @@ public:  	//! \param [out] new_id The newly created cache id.  	//! \return A pointer to the first buffer containing the  	//!  'initial_samples_needed' number of samples. -	sample_t* open(const AudioFile& file, std::size_t initial_samples_needed, int channel, -	               cacheid_t& new_id); +	gsl::owner<sample_t*> open(const AudioFile& file, +	                           std::size_t initial_samples_needed, +	                           int channel, +	                           cacheid_t& new_cacheid);  	//! Get next buffer.  	//! Returns the next buffer for reading based on cache id. @@ -78,9 +81,9 @@ public:  	//! \param id The cache id to read from.  	//! \param [out] size The size of the returned buffer.  	//! \return A pointer to the buffer. -	sample_t* next(cacheid_t id, std::size_t &size); +	gsl::owner<sample_t*> next(cacheid_t id, std::size_t &size); -	//! Returns true iff the next chunk of the supplied id has been read from disk. +	//! Returns true iff next chunk of the supplied id has been read from disk.  	bool isReady(cacheid_t id);  	//! Unregister cache entry. @@ -103,10 +106,10 @@ public:  	bool isAsyncMode() const;  private: -	std::size_t framesize{0}; -	sample_t* nodata{nullptr}; -	std::size_t nodata_framesize{0}; -	std::size_t chunk_size{0}; +	std::size_t framesize{}; +	gsl::owner<sample_t*> nodata{}; +	std::size_t nodata_framesize{}; +	std::size_t chunk_size{};  	std::list<std::unique_ptr<sample_t[]>> nodata_dirty;  	AudioCacheIDManager id_manager; diff --git a/src/audiocacheeventhandler.cc b/src/audiocacheeventhandler.cc index a0327b5..ffd183c 100644 --- a/src/audiocacheeventhandler.cc +++ b/src/audiocacheeventhandler.cc @@ -26,7 +26,7 @@   */  #include "audiocacheeventhandler.h" -#include <assert.h> +#include <cassert>  #include <hugin.hpp> @@ -34,13 +34,14 @@  #include "audiocache.h"  #include "audiocacheidmanager.h" -enum class EventType { +enum class EventType +{  	LoadNext,  	Close,  }; -class CacheEvent { -public: +struct CacheEvent +{  	EventType event_type;  	// For close event: @@ -63,9 +64,9 @@ AudioCacheEventHandler::~AudioCacheEventHandler()  	clearEvents();  	auto active_ids = id_manager.getActiveIDs(); -	for(auto id : active_ids) +	for(auto active_id : active_ids)  	{ -		handleCloseCache(id); +		handleCloseCache(active_id);  	}  } @@ -115,32 +116,32 @@ void AudioCacheEventHandler::unlock()  }  void AudioCacheEventHandler::pushLoadNextEvent(AudioCacheFile* afile, -                                               size_t channel, +                                               size_t channel_index,                                                 size_t pos, sample_t* buffer,                                                 volatile bool* ready)  { -	CacheEvent cache_event; +	CacheEvent cache_event{};  	cache_event.event_type = EventType::LoadNext;  	cache_event.pos = pos;  	cache_event.afile = afile; -	CacheChannel c; -	c.channel = channel; -	c.samples = buffer; +	CacheChannel cache_channel{}; +	cache_channel.channel_index = channel_index; +	cache_channel.samples = buffer;  	*ready = false; -	c.ready = ready; +	cache_channel.ready = ready; -	cache_event.channels.insert(cache_event.channels.end(), c); +	cache_event.channels.insert(cache_event.channels.end(), cache_channel);  	pushEvent(cache_event);  } -void AudioCacheEventHandler::pushCloseEvent(cacheid_t id) +void AudioCacheEventHandler::pushCloseEvent(cacheid_t cacheid)  { -	CacheEvent cache_event; +	CacheEvent cache_event{};  	cache_event.event_type = EventType::Close; -	cache_event.id = id; +	cache_event.id = cacheid;  	pushEvent(cache_event);  } @@ -179,7 +180,7 @@ size_t AudioCacheEventHandler::getChunkSize() const  AudioCacheFile& AudioCacheEventHandler::openFile(const std::string& filename)  { -	std::lock_guard<std::mutex> lock(mutex); +	const std::lock_guard<std::mutex> lock(mutex);  	return files.getFile(filename);  } @@ -197,7 +198,7 @@ void AudioCacheEventHandler::clearEvents()  	eventqueue.clear();  } -void AudioCacheEventHandler::handleLoadNextEvent(CacheEvent& cache_event) +void AudioCacheEventHandler::handleLoadNextEvent(CacheEvent& cache_event) const  {  	assert(cache_event.afile); // Assert that we have an audio file @@ -207,24 +208,25 @@ void AudioCacheEventHandler::handleLoadNextEvent(CacheEvent& cache_event)  void AudioCacheEventHandler::handleCloseEvent(CacheEvent& cache_event)  { -	std::lock_guard<std::mutex> lock(mutex); +	const std::lock_guard<std::mutex> lock(mutex);  	handleCloseCache(cache_event.id);  } -void AudioCacheEventHandler::handleCloseCache(cacheid_t id) +void AudioCacheEventHandler::handleCloseCache(cacheid_t cacheid)  { -	auto& cache = id_manager.getCache(id); +	auto& cache = id_manager.getCache(cacheid);  	// Only close the file if we have also opened it. -	if(cache.afile) +	if(cache.afile != nullptr)  	{  		files.releaseFile(cache.afile->getFilename());  	} -	delete[] cache.front; -	delete[] cache.back; +	//delete[] cache.front; +	//delete[] cache.back; +	cache.deleteChunks(); -	id_manager.releaseID(id); +	id_manager.releaseID(cacheid);  }  void AudioCacheEventHandler::handleEvent(CacheEvent& cache_event) @@ -272,7 +274,7 @@ void AudioCacheEventHandler::pushEvent(CacheEvent& cache_event)  	}  	{ -		std::lock_guard<std::mutex> lock(mutex); +		const std::lock_guard<std::mutex> lock(mutex);  		bool found = false; diff --git a/src/audiocacheeventhandler.h b/src/audiocacheeventhandler.h index f80b4c8..e676f6e 100644 --- a/src/audiocacheeventhandler.h +++ b/src/audiocacheeventhandler.h @@ -36,7 +36,7 @@  #include "audiocachefile.h"  #include "audiocacheidmanager.h" -class CacheEvent; +struct CacheEvent;  class AudioCacheEventHandler  	: protected Thread @@ -68,10 +68,10 @@ public:  	//! This methods are supplied to make this class lockable by std::lock_guard  	void unlock(); -	void pushLoadNextEvent(AudioCacheFile* afile, size_t channel, +	void pushLoadNextEvent(AudioCacheFile* afile, size_t channel_index,  	                       size_t pos, sample_t* buffer,  	                       volatile bool* ready); -	void pushCloseEvent(cacheid_t id); +	void pushCloseEvent(cacheid_t cacheid);  	void setChunkSize(size_t chunksize);  	size_t getChunkSize() const; @@ -81,13 +81,13 @@ public:  protected:  	void clearEvents(); -	void handleLoadNextEvent(CacheEvent& cache_event); +	void handleLoadNextEvent(CacheEvent& cache_event) const;  	//! Lock the mutex and calls handleCloseCache  	void handleCloseEvent(CacheEvent& cache_event);  	//! Close decrease the file ref and release the cache id. -	void handleCloseCache(cacheid_t id); +	void handleCloseCache(cacheid_t cacheid);  	void handleEvent(CacheEvent& cache_event); diff --git a/src/audiocachefile.cc b/src/audiocachefile.cc index 2c2888c..daf4fc1 100644 --- a/src/audiocachefile.cc +++ b/src/audiocachefile.cc @@ -26,23 +26,19 @@   */  #include "audiocachefile.h" -#include <assert.h> - -#include <hugin.hpp> - +#include <cassert>  #include <cstring> +#include <functional> -#include "audiocache.h" +#include <hugin.hpp>  AudioCacheFile::AudioCacheFile(const std::string& filename,                                 std::vector<sample_t>& read_buffer)  	: filename(filename)  	, read_buffer(read_buffer)  { -	std::memset(&sf_info, 0, sizeof(SF_INFO)); -  	fh = sf_open(filename.c_str(), SFM_READ, &sf_info); -	if(!fh) +	if(fh == nullptr)  	{  		ERR(audiofile,"SNDFILE Error (%s): %s\n",  		    filename.c_str(), sf_strerror(fh)); @@ -57,7 +53,7 @@ AudioCacheFile::AudioCacheFile(const std::string& filename,  AudioCacheFile::~AudioCacheFile()  { -	if(fh) +	if(fh != nullptr)  	{  		sf_close(fh);  		fh = nullptr; @@ -80,10 +76,10 @@ size_t AudioCacheFile::getChannelCount() const  }  void AudioCacheFile::readChunk(const CacheChannels& channels, -                               size_t pos, size_t num_samples) +                               std::size_t pos, std::size_t num_samples)  {  	//assert(fh != nullptr); // File handle must never be nullptr -	if(!fh) +	if(fh == nullptr)  	{  		return;  	} @@ -95,9 +91,9 @@ void AudioCacheFile::readChunk(const CacheChannels& channels,  		return;  	} -	sf_seek(fh, pos, SEEK_SET); +	sf_seek(fh, static_cast<sf_count_t>(pos), SEEK_SET); -	size_t size = sf_info.frames - pos; +	auto size = sf_info.frames - pos;  	if(size > num_samples)  	{  		size = num_samples; @@ -108,38 +104,42 @@ void AudioCacheFile::readChunk(const CacheChannels& channels,  		read_buffer.resize(size * sf_info.channels);  	} -	size_t read_size = sf_readf_float(fh, read_buffer.data(), size); -	(void)read_size; +	const size_t read_size = sf_readf_float(fh, read_buffer.data(), +	                                        static_cast<sf_count_t>(size)); +	assert(read_size == size); -	for(auto it = channels.begin(); it != channels.end(); ++it) +	for(const auto& channel : channels)  	{ -		size_t channel = it->channel; -		sample_t* data = it->samples; +		auto channel_index = channel.channel_index; +		auto* data = channel.samples;  		for (size_t i = 0; i < size; ++i)  		{ -			data[i] = read_buffer[(i * sf_info.channels) + channel]; +			data[i] = read_buffer[(i * sf_info.channels) + channel_index]; // NOLINT: will be fixed with std::span  		}  	} -	for(auto it = channels.begin(); it != channels.end(); ++it) +	for(const auto & channel : channels)  	{ -		*(it->ready) = true; +		*(channel.ready) = true;  	}  }  AudioCacheFile& AudioCacheFiles::getFile(const std::string& filename)  { -	std::lock_guard<std::mutex> lock(mutex); +	const std::lock_guard<std::mutex> lock(mutex); -	auto it = audiofiles.find(filename); -	if(it == audiofiles.end()) +	auto audiofile_it = audiofiles.find(filename); +	if(audiofile_it == audiofiles.end())  	{  		// Construct a new AudioCacheFile in place. The in place construction is relevant. -		it = audiofiles.emplace(std::piecewise_construct, std::make_tuple(filename), -		                        std::make_tuple(filename, std::ref(read_buffer))).first; +		audiofile_it = +			audiofiles.emplace(std::piecewise_construct, +			                   std::make_tuple(filename), +			                   std::make_tuple(filename, +			                                   std::ref(read_buffer))).first; // FIXME: This must be possible to do in a more easy-to-read way!  	} -	auto& cache_audio_file = it->second; +	auto& cache_audio_file = audiofile_it->second;  	// Increase ref count.  	++cache_audio_file.ref; @@ -149,22 +149,22 @@ AudioCacheFile& AudioCacheFiles::getFile(const std::string& filename)  void AudioCacheFiles::releaseFile(const std::string& filename)  { -	std::lock_guard<std::mutex> lock(mutex); +	const std::lock_guard<std::mutex> lock(mutex); -	auto it = audiofiles.find(filename); -	if(it == audiofiles.end()) +	auto audiofile_it = audiofiles.find(filename); +	if(audiofile_it == audiofiles.end())  	{  		assert(false); // This should never happen!  		return; // not open  	} -	auto& audiofile = it->second; +	auto& audiofile = audiofile_it->second;  	assert(audiofile.ref); // If ref is not > 0 it shouldn't be in the map.  	--audiofile.ref;  	if(audiofile.ref == 0)  	{ -		audiofiles.erase(it); +		audiofiles.erase(audiofile_it);  	}  } diff --git a/src/audiocachefile.h b/src/audiocachefile.h index 66a6529..63170cf 100644 --- a/src/audiocachefile.h +++ b/src/audiocachefile.h @@ -31,16 +31,17 @@  #include <map>  #include <vector>  #include <mutex> +#include <cstddef>  #include <sndfile.h> -#include <audiotypes.h> +#include "audiotypes.h"  //! Channel data container in the cache world.  class CacheChannel  {  public: -	size_t channel; //< Channel number +	size_t channel_index; //< Channel number  	sample_t* samples; //< Sample buffer pointer.  	size_t num_samples; //< Number of samples in the sample buffer  	volatile bool* ready; //< Is set to true when the loading is done. @@ -72,12 +73,13 @@ public:  	size_t getChannelCount() const;  	//! Read audio data from the file into the supplied channel caches. -	void readChunk(const CacheChannels& channels, size_t pos, size_t num_samples); +	void readChunk(const CacheChannels& channels, std::size_t pos, +	               std::size_t num_samples);  private: -	int ref{0}; -	SNDFILE* fh{nullptr}; -	SF_INFO sf_info; +	int ref{}; +	SNDFILE* fh{}; +	SF_INFO sf_info{};  	std::string filename;  	std::vector<sample_t>& read_buffer;  }; diff --git a/src/audiocacheidmanager.cc b/src/audiocacheidmanager.cc index efef17e..80b0f98 100644 --- a/src/audiocacheidmanager.cc +++ b/src/audiocacheidmanager.cc @@ -27,7 +27,23 @@  #include "audiocacheidmanager.h"  #include <limits> -#include <assert.h> +#include <cassert> + +void CacheBuffer::allocBack(std::size_t chunk_size) +{ +	back = new sample_t[chunk_size]; +} + +void CacheBuffer::deleteChunks() const +{ +	delete[] front; +	delete[] back; +} + +void CacheBuffer::swap() noexcept +{ +	std::swap(front, back); +}  AudioCacheIDManager::~AudioCacheIDManager()  { @@ -36,34 +52,34 @@ AudioCacheIDManager::~AudioCacheIDManager()  void AudioCacheIDManager::init(unsigned int capacity)  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex);  	id2cache.resize(capacity);  	available_ids.resize(capacity); -	for(size_t i = 0; i < capacity; ++i) +	for(int i = 0; i < static_cast<int>(capacity); ++i)  	{  		available_ids[i] = i;  	}  } -cache_t& AudioCacheIDManager::getCache(cacheid_t id) +CacheBuffer& AudioCacheIDManager::getCache(cacheid_t cacheid)  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex); -	assert(id != CACHE_NOID); -	assert(id != CACHE_DUMMYID); -	assert(id >= 0); -	assert(id < (int)id2cache.size()); -	assert(id2cache[id].id == id); +	assert(cacheid != CACHE_NOID); +	assert(cacheid != CACHE_DUMMYID); +	assert(cacheid >= 0); +	assert(cacheid < (int)id2cache.size()); +	assert(id2cache[cacheid].id == cacheid); -	return id2cache[id]; +	return id2cache[cacheid];  } -cacheid_t AudioCacheIDManager::registerID(const cache_t& cache) +cacheid_t AudioCacheIDManager::registerID(const CacheBuffer& cache)  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex); -	cacheid_t id = CACHE_NOID; +	cacheid_t cacheid = CACHE_NOID;  	if(available_ids.empty())  	{ @@ -71,32 +87,32 @@ cacheid_t AudioCacheIDManager::registerID(const cache_t& cache)  	}  	else  	{ -		id = available_ids.back(); +		cacheid = available_ids.back();  		available_ids.pop_back();  	} -	assert(id2cache[id].id == CACHE_NOID); // Make sure it is not already in use +	assert(id2cache[cacheid].id == CACHE_NOID); // Make sure it is not already in use -	id2cache[id] = cache; -	id2cache[id].id = id; +	id2cache[cacheid] = cache; +	id2cache[cacheid].id = cacheid; -	return id; +	return cacheid;  } -void AudioCacheIDManager::releaseID(cacheid_t id) +void AudioCacheIDManager::releaseID(cacheid_t cacheid)  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex); -	assert(id2cache[id].id != CACHE_NOID); // Test if it wasn't already released. +	assert(id2cache[cacheid].id != CACHE_NOID); // Test if it wasn't already released. -	id2cache[id].id = CACHE_NOID; +	id2cache[cacheid].id = CACHE_NOID; -	available_ids.push_back(id); +	available_ids.push_back(cacheid);  }  void AudioCacheIDManager::disableActive()  { -	// Run through all active cache_ts and disable them. +	// Run through all active CacheBuffers and disable them.  	for(auto& cache : id2cache)  	{  		if(cache.id != CACHE_NOID) diff --git a/src/audiocacheidmanager.h b/src/audiocacheidmanager.h index 0aa40e3..d440415 100644 --- a/src/audiocacheidmanager.h +++ b/src/audiocacheidmanager.h @@ -26,35 +26,40 @@   */  #pragma once -#include <stdlib.h> +#include <cstdlib>  #include <vector> - -#include <audiotypes.h> -  #include <mutex> +#include "audiotypes.h" +#include "owner.h" +  class AudioCacheFile; -#define CACHE_DUMMYID -2 -#define CACHE_NOID -1 +using cacheid_t = int; -typedef int cacheid_t; +constexpr cacheid_t CACHE_DUMMYID{-2}; +constexpr cacheid_t CACHE_NOID{-1}; -struct cache_t +class CacheBuffer  { -	cacheid_t id{CACHE_NOID}; //< Current id of this cache_t. CACHE_NOID means not in use. +public: +	void allocBack(std::size_t chunk_size); +	void deleteChunks() const; +	void swap() noexcept; + +	cacheid_t id{CACHE_NOID}; //< Current id of this CacheBuffer. CACHE_NOID means not in use. -	AudioCacheFile* afile{nullptr}; -	size_t channel{0}; -	size_t pos{0}; //< File position +	AudioCacheFile* afile{}; +	size_t channel{}; +	size_t pos{}; //< File position  	volatile bool ready{false}; -	sample_t* front{nullptr}; -	sample_t* back{nullptr}; -	size_t localpos{0}; //< Intra buffer (front) position. +	gsl::owner<sample_t*> front{}; +	gsl::owner<sample_t*> back{}; +	size_t localpos{}; //< Intra buffer (front) position. -	sample_t* preloaded_samples{nullptr}; // nullptr means preload buffer not active. -	size_t preloaded_samples_size{0}; +	sample_t* preloaded_samples{}; // nullptr means preload buffer not active. +	size_t preloaded_samples_size{};  };  class AudioCacheIDManager @@ -71,16 +76,16 @@ public:  	//! Get the cache object connected with the specified cacheid.  	//! Note: The cacheid MUST be active. -	cache_t& getCache(cacheid_t id); +	CacheBuffer& getCache(cacheid_t cacheid);  	//! Reserve a new cache object and return its cacheid.  	//! The contents of the supplied cache object will be copied to the new  	//! cache object. -	cacheid_t registerID(const cache_t& cache); +	cacheid_t registerID(const CacheBuffer& cache);  	//! Release a cache object and its correseponding cacheid.  	//! After this call the cacheid can no longer be used. -	void releaseID(cacheid_t id); +	void releaseID(cacheid_t cacheid);  protected:  	// For AudioCacheEventHandler @@ -89,6 +94,6 @@ protected:  	std::mutex mutex; -	std::vector<cache_t> id2cache; +	std::vector<CacheBuffer> id2cache;  	std::vector<cacheid_t> available_ids;  }; diff --git a/src/audiofile.cc b/src/audiofile.cc index 2d61eb5..1228044 100644 --- a/src/audiofile.cc +++ b/src/audiofile.cc @@ -30,6 +30,7 @@  #include <cassert>  #include <sndfile.h> +#include <array>  #include <config.h> @@ -37,9 +38,9 @@  #include "channel.h" -AudioFile::AudioFile(const std::string& filename, std::size_t filechannel, +AudioFile::AudioFile(std::string filename, std::size_t filechannel,                       InstrumentChannel* instrument_channel) -	: filename(filename) +	: filename(std::move(filename))  	, filechannel(filechannel)  	, magic{this}  	, instrument_channel(instrument_channel) @@ -61,9 +62,9 @@ bool AudioFile::isValid() const  void AudioFile::unload()  {  	// Make sure we don't unload the object while loading it... -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex); -	is_loaded = false; +	is_loaded.store(false);  	preloadedsize = 0;  	size = 0; @@ -71,28 +72,28 @@ void AudioFile::unload()  	data = nullptr;  } -#define BUFFER_SIZE 4096 +constexpr std::size_t buffer_size{4096}; -void AudioFile::load(LogFunction logger, std::size_t sample_limit) +void AudioFile::load(const LogFunction& logger, std::size_t sample_limit)  {  	// Make sure we don't unload the object while loading it... -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex); -	if(this->data) // already loaded +	if(this->data != nullptr) // already loaded  	{  		return;  	}  	SF_INFO sf_info{}; -	SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); -	if(!fh) +	SNDFILE *file_handle = sf_open(filename.c_str(), SFM_READ, &sf_info); +	if(file_handle == nullptr)  	{  		ERR(audiofile,"SNDFILE Error (%s): %s\n", -		    filename.c_str(), sf_strerror(fh)); +		    filename.c_str(), sf_strerror(file_handle));  		if(logger)  		{  			logger(LogLevel::Warning, "Could not load '" + filename + -			       "': " + sf_strerror(fh)); +			       "': " + sf_strerror(file_handle));  		}  		return;  	} @@ -108,7 +109,7 @@ void AudioFile::load(LogFunction logger, std::size_t sample_limit)  		return;  	} -	std::size_t size = sf_info.frames; +	const std::size_t size = sf_info.frames;  	std::size_t preloadedsize = sf_info.frames;  	if(preloadedsize > sample_limit) @@ -116,10 +117,12 @@ void AudioFile::load(LogFunction logger, std::size_t sample_limit)  		preloadedsize = sample_limit;  	} -	sample_t* data = new sample_t[preloadedsize]; +	gsl::owner<sample_t*> data{}; +	data = new sample_t[preloadedsize];  	if(sf_info.channels == 1)  	{ -		preloadedsize = sf_read_float(fh, data, preloadedsize); +		preloadedsize = +			sf_read_float(file_handle, data, static_cast<sf_count_t>(preloadedsize));  	}  	else  	{ @@ -134,19 +137,22 @@ void AudioFile::load(LogFunction logger, std::size_t sample_limit)  			filechannel = sf_info.channels - 1;  		} -		sample_t buffer[BUFFER_SIZE]; -		std::size_t frame_count = BUFFER_SIZE / sf_info.channels; -		std::size_t total_frames_read = 0; -		int frames_read; +		std::array<sample_t, buffer_size> buffer{}; +		const sf_count_t frame_count{static_cast<sf_count_t>(buffer.size()) / +		                             sf_info.channels}; +		std::size_t total_frames_read{}; +		std::size_t frames_read{};  		do  		{ -	    frames_read = sf_readf_float(fh, buffer, frame_count); -	    for(int i = 0; +			frames_read = static_cast<std::size_t>( +				sf_readf_float(file_handle, buffer.data(), frame_count)); +			for(std::size_t i = 0;  	        (i < frames_read) && (total_frames_read < sample_limit);  	        ++i)  	    { -		    data[total_frames_read++] = buffer[i * sf_info.channels + filechannel]; +		    data[total_frames_read++] = +			    buffer[i * sf_info.channels + filechannel]; // NOLINT - span  	    }  		}  		while( (frames_read > 0) && @@ -157,17 +163,17 @@ void AudioFile::load(LogFunction logger, std::size_t sample_limit)  		preloadedsize = total_frames_read;  	} -	sf_close(fh); +	sf_close(file_handle);  	this->data = data;  	this->size = size;  	this->preloadedsize = preloadedsize; -	is_loaded = true; +	is_loaded.store(true);  }  bool AudioFile::isLoaded() const  { -	return is_loaded; +	return is_loaded.load();  }  main_state_t AudioFile::mainState() const diff --git a/src/audiofile.h b/src/audiofile.h index e20d91f..cff4f3b 100644 --- a/src/audiofile.h +++ b/src/audiofile.h @@ -31,30 +31,31 @@  #include <vector>  #include <limits>  #include <mutex> - -#include <sndfile.h> +#include <atomic>  #include "audio.h"  #include "channel.h"  #include "logger.h" +#include "owner.h"  class InstrumentChannel;  class AudioFile  {  public: -	AudioFile(const std::string& filename, std::size_t filechannel, +	AudioFile(std::string filename, std::size_t filechannel,  	          InstrumentChannel* instrument_channel = nullptr);  	~AudioFile(); -	void load(LogFunction logger, std::size_t sample_limit = std::numeric_limits<std::size_t>::max()); +	void load(const LogFunction& logger, +	          std::size_t sample_limit = std::numeric_limits<std::size_t>::max());  	void unload();  	bool isLoaded() const;  	volatile std::size_t size{0}; // Full size of the file  	volatile std::size_t preloadedsize{0}; // Number of samples preloaded (in data) -	sample_t* data{nullptr}; +	gsl::owner<sample_t*> data{nullptr};  	std::string filename; @@ -72,7 +73,7 @@ private:  	friend class DOMLoaderTest;  	friend class InstrumentParserTest; -	void* magic{nullptr}; -	volatile bool is_loaded{false}; -	InstrumentChannel* instrument_channel; +	void* magic{}; +	std::atomic<bool> is_loaded{false}; +	InstrumentChannel* instrument_channel{};  }; diff --git a/src/audioinputengine.h b/src/audioinputengine.h index 71a86c2..55a06ae 100644 --- a/src/audioinputengine.h +++ b/src/audioinputengine.h @@ -29,7 +29,7 @@  #include <string>  #include <vector> -#include <event.h> +#include "engineevent.h"  #include "instrument.h" diff --git a/src/audioinputenginemidi.cc b/src/audioinputenginemidi.cc index 69aeeb6..2e794f4 100644 --- a/src/audioinputenginemidi.cc +++ b/src/audioinputenginemidi.cc @@ -28,26 +28,20 @@  #include "midimapparser.h" -#include "drumgizmo.h" +#include <cassert>  #include <hugin.hpp> -AudioInputEngineMidi::AudioInputEngineMidi() -	: refs(REFSFILE) -{ -	is_valid = false; -} - -bool AudioInputEngineMidi::loadMidiMap(const std::string& file, +bool AudioInputEngineMidi::loadMidiMap(const std::string& midimap_file,                                         const Instruments& instruments)  { -	std::string f = file; +	std::string file = midimap_file;  	if(refs.load())  	{  		if(file.size() > 1 && file[0] == '@')  		{ -			f = refs.getValue(file.substr(1)); +			file = refs.getValue(file.substr(1));  		}  	}  	else @@ -58,16 +52,16 @@ bool AudioInputEngineMidi::loadMidiMap(const std::string& file,  	midimap = "";  	is_valid = false; -	DEBUG(mmap, "loadMidiMap(%s, i.size() == %d)\n", f.c_str(), +	DEBUG(mmap, "loadMidiMap(%s, i.size() == %d)\n", file.c_str(),  	      (int)instruments.size()); -	if(f == "") +	if(file.empty())  	{  		return false;  	}  	MidiMapParser midimap_parser; -	if(!midimap_parser.parseFile(f)) +	if(!midimap_parser.parseFile(file))  	{  		return false;  	} @@ -75,7 +69,7 @@ bool AudioInputEngineMidi::loadMidiMap(const std::string& file,  	instrmap_t instrmap;  	for(size_t i = 0; i < instruments.size(); i++)  	{ -		instrmap[instruments[i]->getName()] = i; +		instrmap[instruments[i]->getName()] = static_cast<int>(i);  	}  	mmap.swap(instrmap, midimap_parser.midimap); @@ -97,12 +91,12 @@ bool AudioInputEngineMidi::isValid() const  }  // Note types: -static const std::uint8_t NoteOff = 0x80; -static const std::uint8_t NoteOn = 0x90; -static const std::uint8_t NoteAftertouch = 0xA0; +constexpr std::uint8_t NoteOff{0x80}; +constexpr std::uint8_t NoteOn{0x90}; +constexpr std::uint8_t NoteAftertouch{0xA0};  // Note type mask: -static int const NoteMask = 0xF0; +constexpr std::uint8_t NoteMask{0xF0};  void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,                                         std::size_t midi_buffer_length, @@ -114,13 +108,13 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,  		return;  	} -	auto key = midi_buffer[1]; -	auto velocity = midi_buffer[2]; +	auto key = midi_buffer[1]; // NOLINT - span +	auto velocity = midi_buffer[2]; // NOLINT - span  	auto instrument_idx = mmap.lookup(key);  	auto instruments = mmap.lookup(key);  	for(const auto& instrument_idx : instruments)  	{ -		switch(midi_buffer[0] & NoteMask) +		switch(midi_buffer[0] & NoteMask) // NOLINT - span  		{  		case NoteOff:  			// Ignore for now @@ -129,8 +123,12 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer,  		case NoteOn:  			if(velocity != 0)  			{ +				constexpr float lower_offset{0.5f}; +				constexpr float midi_velocity_max{127.0f};  				// maps velocities to [.5/127, 126.5/127] -				auto centered_velocity = (velocity-.5f)/127.0f; +				assert(velocity <= 127); // MIDI only support up to 127 +				auto centered_velocity = +					(static_cast<float>(velocity) - lower_offset) / midi_velocity_max;  				events.push_back({EventType::OnSet, (std::size_t)instrument_idx,  				                  offset, centered_velocity});  			} diff --git a/src/audioinputenginemidi.h b/src/audioinputenginemidi.h index 8da7bd2..386a055 100644 --- a/src/audioinputenginemidi.h +++ b/src/audioinputenginemidi.h @@ -37,7 +37,7 @@ class AudioInputEngineMidi  	: public AudioInputEngine  {  public: -	AudioInputEngineMidi(); +	AudioInputEngineMidi() = default;  	virtual ~AudioInputEngineMidi() = default;  	virtual bool init(const Instruments &instruments) = 0; @@ -51,14 +51,15 @@ public:  	virtual void run(size_t pos, size_t len, std::vector<event_t>& events) = 0;  	virtual void post() = 0; -	virtual bool loadMidiMap(const std::string& file, const Instruments& i); +	virtual bool loadMidiMap(const std::string& midimap_file, +	                         const Instruments& i);  	std::string getMidimapFile() const;  	bool isValid() const; -	void processNote(const std::uint8_t* note_data, -	                 std::size_t note_data_size, +	void processNote(const std::uint8_t* midi_buffer, +	                 std::size_t midi_buffer_length,  	                 std::size_t offset,  	                 std::vector<event_t>& events); @@ -67,7 +68,7 @@ protected:  private:  	std::string midimap; -	bool is_valid; +	bool is_valid{false}; -	ConfigFile refs; +	ConfigFile refs{REFSFILE};  }; diff --git a/src/audiooutputengine.h b/src/audiooutputengine.h index f69fd75..a69c56d 100644 --- a/src/audiooutputengine.h +++ b/src/audiooutputengine.h @@ -29,7 +29,7 @@  #include <cstddef>  #include <string> -#include <audiotypes.h> +#include "audiotypes.h"  #include "channel.h" diff --git a/src/bytesizeparser.cc b/src/bytesizeparser.cc index 08c7b5b..78a525b 100644 --- a/src/bytesizeparser.cc +++ b/src/bytesizeparser.cc @@ -25,23 +25,28 @@   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.   */  #include "bytesizeparser.h" +  #include <iostream>  #include <stdexcept> - -static std::size_t suffixToSize(const char& suffix) +namespace { +std::size_t suffixToSize(const char& suffix)  { -	int size = 1; +	constexpr std::size_t kilo{10}; +	constexpr std::size_t mega{20}; +	constexpr std::size_t giga{30}; + +	std::size_t size{1};  	switch(suffix)  	{  	case 'k': -		size <<= 10; +		size <<= kilo;  		break;  	case 'M': -		size <<= 20; +		size <<= mega;  		break;  	case 'G': -		size <<= 30; +		size <<= giga;  		break;  	default:  		size = 0; @@ -49,14 +54,14 @@ static std::size_t suffixToSize(const char& suffix)  	}  	return size;  } - +}  std::size_t byteSizeParser(const std::string& argument)  { -	std::string::size_type suffix_index; -	std::size_t size; +	std::string::size_type suffix_index{}; +	std::size_t size{};  	std::string suffix; -	bool error = false; +	bool error{false};  	if(argument.find('-') != std::string::npos)  	{ @@ -69,14 +74,15 @@ std::size_t byteSizeParser(const std::string& argument)  	}  	catch(std::invalid_argument&)  	{ -		std::cerr << "Invalid argument for diskstreamsize" << std::endl; +		std::cerr << "Invalid argument for diskstreamsize\n";  		error = true;  	}  	catch(std::out_of_range&)  	{ -		std::cerr << "Number too big. Try using bigger suffix for diskstreamsize" << std::endl; +		std::cerr << "Number too big. Try using bigger suffix for diskstreamsize\n";  		error = true;  	} +  	if(!error)  	{  		suffix = argument.substr(suffix_index); @@ -85,14 +91,17 @@ std::size_t byteSizeParser(const std::string& argument)  			error = true;  		}  	} -	if(!error && suffix.size() > 0) + +	if(!error && !suffix.empty())  	{ -		std::size_t suffix_size = suffixToSize(suffix[0]); +		const std::size_t suffix_size = suffixToSize(suffix[0]);  		size *= suffix_size;  	} +  	if(error)  	{  		return 0;  	} +  	return size;  } diff --git a/src/bytesizeparser.h b/src/bytesizeparser.h index 3007454..e1ffeab 100644 --- a/src/bytesizeparser.h +++ b/src/bytesizeparser.h @@ -25,8 +25,8 @@   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.   */  #pragma once -#include <string> +#include <string>  //! Returns size in bytes  //! \param argument The size in n{k,M,G} format diff --git a/src/configfile.h b/src/configfile.h index c17811b..49dbdee 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -30,6 +30,8 @@  #include <map>  #include <fstream> +static const std::string REFSFILE{"refs.conf"}; +  class ConfigFile  {  public: diff --git a/src/powermap.cc b/src/curvemap.cc index 2bb45b7..073dde4 100644 --- a/src/powermap.cc +++ b/src/curvemap.cc @@ -24,7 +24,7 @@   *  along with DrumGizmo; if not, write to the Free Software   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.   */ -#include "powermap.h" +#include "curvemap.h"  #include <cassert>  #include <cmath> @@ -32,31 +32,31 @@  namespace  { -using Power = Powermap::Power; -using PowerPair = Powermap::PowerPair; +using CurveValue = CurveMap::CurveValue; +using CurveValuePair = CurveMap::CurveValuePair; -Power h00(Power x) +CurveValue h00(CurveValue x)  {  	return (1 + 2 * x) * pow(1 - x, 2);  } -Power h10(Power x) +CurveValue h10(CurveValue x)  {  	return x * pow(1 - x, 2);  } -Power h01(Power x) +CurveValue h01(CurveValue x)  {  	return x * x * (3 - 2 * x);  } -Power h11(Power x) +CurveValue h11(CurveValue x)  {  	return x * x * (x - 1);  } -Power computeValue(const Power x, const PowerPair& P0, const PowerPair& P1, -                   const Power m0, const Power m1) +CurveValue computeValue(const CurveValue x, const CurveValuePair& P0, const CurveValuePair& P1, +                        const CurveValue m0, const CurveValue m1)  {  	const auto x0 = P0.in;  	const auto x1 = P1.in; @@ -74,21 +74,22 @@ Power computeValue(const Power x, const PowerPair& P0, const PowerPair& P1,  } // end anonymous namespace -Powermap::Powermap() -{ -	reset(); -} +constexpr std::array<CurveValuePair, 3> CurveMap::default_fixed; -Power Powermap::map(Power in) +CurveValue CurveMap::map(CurveValue in)  {  	assert(in >= 0. && in <= 1.); +	if (invert) +	{ +		in = 1.0 - in; +	}  	if (spline_needs_update)  	{  		updateSpline();  	} -	Power out; +	CurveValue out;  	if (in < fixed[0].in)  	{  		out = shelf ? fixed[0].out @@ -113,84 +114,100 @@ Power Powermap::map(Power in)  	return out;  } -void Powermap::reset() +void CurveMap::reset()  { -	setFixed0({eps, eps}); -	setFixed1({.5, .5}); -	setFixed2({1 - eps, 1 - eps}); -	// FIXME: better false? -	shelf = true; +	*this = CurveMap{};  	updateSpline();  } -void Powermap::setFixed0(PowerPair new_value) +void CurveMap::setFixed0(CurveValuePair new_value)  { -	if (fixed[0] != new_value) +	auto prev = fixed[0]; +	fixed[0].in = clamp(new_value.in, eps, fixed[1].in - eps); +	fixed[0].out = clamp(new_value.out, eps, fixed[1].out - eps); +	if (fixed[0] != prev)  	{  		spline_needs_update = true; -		fixed[0].in = clamp(new_value.in, eps, fixed[1].in - eps); -		fixed[0].out = clamp(new_value.out, eps, fixed[1].out - eps);  	}  } -void Powermap::setFixed1(PowerPair new_value) +void CurveMap::setFixed1(CurveValuePair new_value)  { -	if (fixed[1] != new_value) +	auto prev = fixed[1]; +	fixed[1].in = clamp(new_value.in, fixed[0].in + eps, fixed[2].in - eps); +	fixed[1].out = clamp(new_value.out, fixed[0].out + eps, fixed[2].out - eps); +	if (fixed[1] != prev)  	{  		spline_needs_update = true; -		fixed[1].in = clamp(new_value.in, fixed[0].in + eps, fixed[2].in - eps); -		fixed[1].out = clamp(new_value.out, fixed[0].out + eps, fixed[2].out - eps);  	}  } -void Powermap::setFixed2(PowerPair new_value) +void CurveMap::setFixed2(CurveValuePair new_value)  { -	if (fixed[2] != new_value) +	auto prev = fixed[2]; +	fixed[2].in = clamp(new_value.in, fixed[1].in + eps, 1 - eps); +	fixed[2].out = clamp(new_value.out, fixed[1].out + eps, 1 - eps); +	if (fixed[2] != prev)  	{  		spline_needs_update = true; -		fixed[2].in = clamp(new_value.in, fixed[1].in + eps, 1 - eps); -		fixed[2].out = clamp(new_value.out, fixed[1].out + eps, 1 - eps);  	}  } -void Powermap::setShelf(bool enable) +void CurveMap::setInvert(bool enable) +{ +	if (invert != enable) +	{ +		spline_needs_update = true; +		invert = enable; +	} +} + +void CurveMap::setShelf(bool enable)  {  	if (shelf != enable)  	{  		spline_needs_update = true; -		this->shelf = enable; +		shelf = enable;  	}  } -PowerPair Powermap::getFixed0() const +CurveValuePair CurveMap::getFixed0() const  {  	return fixed[0];  } -PowerPair Powermap::getFixed1() const +CurveValuePair CurveMap::getFixed1() const  {  	return fixed[1];  } -PowerPair Powermap::getFixed2() const +CurveValuePair CurveMap::getFixed2() const  {  	return fixed[2];  } +bool CurveMap::getInvert() const { +	return invert; +} + +bool CurveMap::getShelf() const { +	return shelf; +} +  // This mostly followes the wikipedia article for monotone cubic splines:  // https://en.wikipedia.org/wiki/Monotone_cubic_interpolation -void Powermap::updateSpline() +void CurveMap::updateSpline()  {  	assert(0. <= fixed[0].in && fixed[0].in < fixed[1].in &&  	       fixed[1].in < fixed[2].in && fixed[2].in <= 1.);  	assert(0. <= fixed[0].out && fixed[0].out <= fixed[1].out &&  	       fixed[1].out <= fixed[2].out && fixed[2].out <= 1.); -	Powers X = shelf ? Powers{fixed[0].in, fixed[1].in, fixed[2].in} -	                 : Powers{0., fixed[0].in, fixed[1].in, fixed[2].in, 1.}; -	Powers Y = shelf ? Powers{fixed[0].out, fixed[1].out, fixed[2].out} -	                 : Powers{0., fixed[0].out, fixed[1].out, fixed[2].out, 1.}; +	CurveValues X = shelf ? CurveValues{fixed[0].in, fixed[1].in, fixed[2].in} +	                 : CurveValues{0., fixed[0].in, fixed[1].in, fixed[2].in, 1.}; +	CurveValues Y = shelf ? CurveValues{fixed[0].out, fixed[1].out, fixed[2].out} +	                 : CurveValues{0., fixed[0].out, fixed[1].out, fixed[2].out, 1.};  	auto slopes = calcSlopes(X, Y); @@ -215,12 +232,12 @@ void Powermap::updateSpline()  // This follows the monotone cubic spline algorithm of Steffen, from:  // "A Simple Method for Monotonic Interpolation in One Dimension" -std::vector<float> Powermap::calcSlopes(const Powers& X, const Powers& Y) +std::vector<float> CurveMap::calcSlopes(const CurveValues& X, const CurveValues& Y)  { -	Powers m(X.size()); +	CurveValues m(X.size()); -	Powers d(X.size() - 1); -	Powers h(X.size() - 1); +	CurveValues d(X.size() - 1); +	CurveValues h(X.size() - 1);  	for (std::size_t i = 0; i < d.size(); ++i)  	{  		h[i] = X[i + 1] - X[i]; @@ -245,7 +262,16 @@ std::vector<float> Powermap::calcSlopes(const Powers& X, const Powers& Y)  	return m;  } -Power Powermap::clamp(Power in, Power min, Power max) const +CurveValue CurveMap::clamp(CurveValue in, CurveValue min, CurveValue max) const  {  	return std::max(min, std::min(in, max));  } + +bool CurveMap::operator==(const CurveMap& other) const +{ +	return getFixed0() == other.getFixed0() && +		getFixed1() == other.getFixed1() && +		getFixed2() == other.getFixed2() && +		getShelf() == other.getShelf() && +		getInvert() == other.getInvert(); +} diff --git a/src/curvemap.h b/src/curvemap.h new file mode 100644 index 0000000..926543d --- /dev/null +++ b/src/curvemap.h @@ -0,0 +1,94 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + *            curvemap.h + * + *  Fri Apr 17 23:06:12 CEST 2020 + *  Copyright 2020 André Nusser + *  andre.nusser@googlemail.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 <array> +#include <vector> + +class CurveMap +{ +public: +	using CurveValue = float; +	using CurveValues = std::vector<CurveValue>; + +	bool operator==(const CurveMap& other) const; + +	struct CurveValuePair +	{ +		CurveValue in; +		CurveValue out; + +		bool operator==(const CurveValuePair& other) +		{ +			return in == other.in || out == other.out; +		} +		bool operator!=(const CurveValuePair& other) +		{ +			return !(*this == other); +		} +	}; + +	CurveValue map(CurveValue in); +	void reset(); + +	void setFixed0(CurveValuePair new_value); +	void setFixed1(CurveValuePair new_value); +	void setFixed2(CurveValuePair new_value); +	void setShelf(bool enable); + +	//! If enabled, inversion inverts (1 - x) the input value before mapping +	//! it through the curve. +	void setInvert(bool enable); + +	CurveValuePair getFixed0() const; +	CurveValuePair getFixed1() const; +	CurveValuePair getFixed2() const; +	bool getShelf() const; +	bool getInvert() const; + +private: +	static constexpr CurveValue eps = 1e-4; +	static constexpr std::array<CurveValuePair, 3> default_fixed { +		CurveValuePair {eps, eps}, +		CurveValuePair {.5, .5}, +		CurveValuePair {1 - eps, 1 - eps} +	}; + +	// input parameters (state of this class) +	std::array<CurveValuePair, 3> fixed { default_fixed }; +	bool shelf { true }; +	bool invert { false }; + +	// spline parameters (deterministically computed from the input parameters) +	bool spline_needs_update { true }; +	std::array<float, 5> m { 0, 0, 0, 0, 0 }; + +	void updateSpline(); +	std::vector<float> calcSlopes(const CurveValues& X, const CurveValues& P); + +	CurveValue clamp(CurveValue in, CurveValue min, CurveValue max) const; +};
\ No newline at end of file diff --git a/src/directory.cc b/src/directory.cc index 596b045..27637a9 100644 --- a/src/directory.cc +++ b/src/directory.cc @@ -27,14 +27,14 @@  #include "directory.h"  #include <dirent.h> -#include <stdio.h> +#include <cstdio>  #include <string>  #include <algorithm>  #include <vector> -#include <string.h> +#include <cstring>  #include <unistd.h> -#include <platform.h> +#include "platform.h"  #if DG_PLATFORM == DG_PLATFORM_WINDOWS  #include <direct.h> diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index abe57be..093b0bf 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -31,9 +31,10 @@  #include <cassert>  #include <cstring>  #include <mutex> +#include <thread> +#include <chrono> -#include <event.h> -#include <audiotypes.h> +#include "audiotypes.h"  #include <config.h>  #include <hugin.hpp> @@ -312,7 +313,7 @@ repeat:  		assert(t >= 0);  		assert(t < evt.buffer_size - evt.buffer_ptr); -		if(evt.rampdownInProgress() && evt.rampdown_offset < (evt.t + t) && +		if(evt.hasRampdown() && evt.rampdown_offset < (pos + t) &&  		   evt.rampdown_count > 0)  		{  			if(evt.ramp_length > 0) @@ -362,6 +363,11 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t* s, size_t sz)  		AudioFile& af = *sample_event.file; +		while(freewheel && !af.isLoaded()) +		{ +			std::this_thread::sleep_for(std::chrono::milliseconds(10)); +		} +  		if(!af.isLoaded() || !af.isValid() || (s == nullptr))  		{  			// This event cannot be played - schedule for deletion and continue. @@ -392,7 +398,7 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t* s, size_t sz)  		{  			// TODO: We should make all audiofiles reference counted and get rid of this lock. -			std::lock_guard<std::mutex> guard(af.mutex); +			const std::lock_guard<std::mutex> guard(af.mutex);  			renderSampleEvent(sample_event, pos, s, sz); diff --git a/src/drumgizmo.h b/src/drumgizmo.h index 89c2960..a47898b 100644 --- a/src/drumgizmo.h +++ b/src/drumgizmo.h @@ -46,8 +46,6 @@  #include "inputprocessor.h"  #include "zrwrapper.h" -#define REFSFILE "refs.conf" -  class DrumGizmo  {  public: @@ -105,7 +103,7 @@ protected:  	Random rand;  	std::array<ZRWrapper, NUM_CHANNELS> zita; -	std::array<std::unique_ptr<sample_t>, NUM_CHANNELS> resampler_input_buffer; +	std::array<std::unique_ptr<sample_t[]>, NUM_CHANNELS> resampler_input_buffer;  	double ratio = 1.0;  	std::vector<sample_t> scratch_buffer;  }; diff --git a/src/drumgizmoconf.h b/src/drumgizmoconf.h index f031730..ee14ec6 100644 --- a/src/drumgizmoconf.h +++ b/src/drumgizmoconf.h @@ -26,7 +26,7 @@   */  #pragma once -#include <configfile.h> +#include "configfile.h"  class DrumgizmoConfig  	: public ConfigFile diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index 9167201..b3a0e5b 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -38,8 +38,6 @@  #include "domloader.h"  #include "directory.h" -#define REFSFILE "refs.conf" -  DrumKitLoader::DrumKitLoader(Settings& settings, DrumKit& kit,                               AudioInputEngine& ie,                               Random& rand, @@ -93,7 +91,7 @@ void DrumKitLoader::deinit()  		framesize_semaphore.post();  		{ -			std::lock_guard<std::mutex> guard(mutex); +			const std::lock_guard<std::mutex> guard(mutex);  			load_queue.clear();  		} @@ -301,13 +299,13 @@ void DrumKitLoader::loadKitAudio(const DrumKit& kit)  void DrumKitLoader::skip()  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex);  	load_queue.clear();  }  void DrumKitLoader::setFrameSize(std::size_t framesize)  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex);  	this->framesize = framesize;  	framesize_semaphore.post(); // Signal that the framesize has been set.  } @@ -324,7 +322,7 @@ void DrumKitLoader::thread_main()  	{  		std::size_t size;  		{ -			std::lock_guard<std::mutex> guard(mutex); +			const std::lock_guard<std::mutex> guard(mutex);  			size = load_queue.size();  		} @@ -367,7 +365,7 @@ void DrumKitLoader::thread_main()  		std::string filename;  		{ -			std::lock_guard<std::mutex> guard(mutex); +			const std::lock_guard<std::mutex> guard(mutex);  			if(load_queue.size() == 0)  			{ diff --git a/src/event.h b/src/engineevent.h index 737fb18..9c60a4a 100644 --- a/src/event.h +++ b/src/engineevent.h @@ -1,6 +1,6 @@  /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */  /*************************************************************************** - *            event.h + *            engineevent.h   *   *  Fri Jun  3 12:10:50 CEST 2011   *  Copyright 2011 Bent Bisballe Nyeng diff --git a/src/events.h b/src/events.h index 9e3cae1..538127b 100644 --- a/src/events.h +++ b/src/events.h @@ -84,11 +84,12 @@ public:  	{  	} -	bool rampdownInProgress() const +	bool hasRampdown() const  	{  		return rampdown_count != -1;  	} +  	cacheid_t cache_id;  	sample_t* buffer;  	std::size_t buffer_size; diff --git a/src/inputfilter.h b/src/inputfilter.h index 45dd01e..128dfb0 100644 --- a/src/inputfilter.h +++ b/src/inputfilter.h @@ -26,7 +26,7 @@   */  #pragma once -#include <event.h> +#include "engineevent.h"  //! An abstract filter component for the InputProcessor class filter chain.  class InputFilter diff --git a/src/inputprocessor.cc b/src/inputprocessor.cc index 7d12bdd..c0c0e92 100644 --- a/src/inputprocessor.cc +++ b/src/inputprocessor.cc @@ -139,20 +139,18 @@ std::size_t InputProcessor::getLatency() const  	return latency;  } -//! Applies choke with rampdown time in ms to event starting at offset. -static void applyChoke(Settings& settings, SampleEvent& event, -                       double length_ms, timepos_t offset) +void InputProcessor::applyChoke(Settings& settings, SampleEvent& event, +                                double length_ms, timepos_t offset, std::size_t pos)  {  	std::size_t ramp_length = (length_ms / 1000.) * settings.samplerate.load();  	event.rampdown_count = ramp_length; -	event.rampdown_offset = offset; +	event.rampdown_offset = offset + pos;  	event.ramp_length = ramp_length;  } -//! Applies choke group actions to active events based on the input event -static void applyChokeGroup(Settings& settings, DrumKit& kit, -                            Instrument& instr, event_t& event, -                            EventsDS& events_ds) +void InputProcessor::applyChokeGroup(Settings& settings, DrumKit& kit, +                                     Instrument& instr, event_t& event, +                                     EventsDS& events_ds, std::size_t pos)  {  	std::size_t instrument_id = event.instrument;  	if(instr.getGroup() == "") @@ -175,16 +173,15 @@ static void applyChokeGroup(Settings& settings, DrumKit& kit,  			   event_sample.rampdown_count == -1) // Only if not already ramping.  			{  				// Fixed group rampdown time of 68ms, independent of samplerate -				applyChoke(settings, event_sample, 68, event.offset); +				applyChoke(settings, event_sample, 68, event.offset, pos);  			}  		}  	}  } -//! Applies directed choke actions to active events based on the input event -static void applyDirectedChoke(Settings& settings, DrumKit& kit, -                               Instrument& instr, event_t& event, -                               EventsDS& events_ds) +void InputProcessor::applyDirectedChoke(Settings& settings, DrumKit& kit, +                                        Instrument& instr, event_t& event, +                                        EventsDS& events_ds, std::size_t pos)  {  	for(const auto& choke : instr.getChokes())  	{ @@ -202,7 +199,7 @@ static void applyDirectedChoke(Settings& settings, DrumKit& kit,  				   event_sample.rampdown_count == -1) // Only if not already ramping.  				{  					// choke.choketime is in ms -					applyChoke(settings, event_sample, choke.choketime, event.offset); +					applyChoke(settings, event_sample, choke.choketime, event.offset, pos);  				}  			}  		} @@ -245,10 +242,10 @@ bool InputProcessor::processOnset(event_t& event, std::size_t pos,  	}  	// Mute other instruments in the same instrument/choke group -	applyChokeGroup(settings, kit, *instr, event, events_ds); +	applyChokeGroup(settings, kit, *instr, event, events_ds, pos);  	// Apply directed chokes to mute other instruments if needed -	applyDirectedChoke(settings, kit, *instr, event, events_ds); +	applyDirectedChoke(settings, kit, *instr, event, events_ds, pos);  	auto const power_max = instr->getMaxPower();  	auto const power_min = instr->getMinPower(); @@ -266,7 +263,7 @@ bool InputProcessor::processOnset(event_t& event, std::size_t pos,  	{  		limitVoices(instrument_id,  		            settings.voice_limit_max.load(), -		            settings.voice_limit_rampdown.load()); +		            settings.voice_limit_rampdown.load(), pos);  	}  	//Given that audio files could be invalid, maybe we must add the new @@ -356,7 +353,7 @@ bool InputProcessor::processChoke(event_t& event,  			   event_sample.rampdown_count == -1) // Only if not already ramping.  			{  				// Fixed group rampdown time of 68ms, independent of samplerate -				applyChoke(settings, event_sample, 450, event.offset); +				applyChoke(settings, event_sample, 450, event.offset, pos);  			}  		}  	} @@ -397,7 +394,7 @@ bool InputProcessor::processStop(event_t& event)  void InputProcessor::limitVoices(std::size_t instrument_id,                                   std::size_t max_voices, -                                 float rampdown_time) +                                 float rampdown_time, std::size_t pos)  {  	const auto& group_ids=events_ds.getSampleEventGroupIDsOf(instrument_id); @@ -418,7 +415,7 @@ void InputProcessor::limitVoices(std::size_t instrument_id,  			}  			const auto&	sample=events_ds.get<SampleEvent>(event_ids[0]); -			return !sample.rampdownInProgress(); +			return !sample.hasRampdown();  		};  	EventGroupIDs non_ramping; @@ -432,7 +429,6 @@ void InputProcessor::limitVoices(std::size_t instrument_id,  	}  	//Let us get the eldest... -	//TODO: where is the playhead? Should we add it to the offset?  	auto compare_event_offsets =  		[this](EventGroupID a, EventGroupID b)  		{ @@ -456,6 +452,6 @@ void InputProcessor::limitVoices(std::size_t instrument_id,  	for(const auto& event_id : event_ids)  	{  		auto& sample=events_ds.get<SampleEvent>(event_id); -		applyChoke(settings, sample, rampdown_time, sample.offset); +		applyChoke(settings, sample, rampdown_time, sample.offset, pos);  	}  } diff --git a/src/inputprocessor.h b/src/inputprocessor.h index 971cc85..a8dc45b 100644 --- a/src/inputprocessor.h +++ b/src/inputprocessor.h @@ -30,13 +30,13 @@  #include <list>  #include <memory> -#include <event.h>  #include "drumkit.h"  #include "events.h"  #include "events_ds.h"  #include "id.h"  #include "inputfilter.h" +#include "engineevent.h"  struct Settings;  class Random; @@ -64,10 +64,23 @@ private:  	bool processChoke(event_t& event, std::size_t pos, double resample_ratio);  	bool processStop(event_t& event); +	//! Applies choke with rampdown time in ms to event starting at offset. +	void applyChoke(Settings& settings, SampleEvent& event, +	                double length_ms, timepos_t offset, std::size_t pos); + +	//! Applies choke group actions to active events based on the input event +	void applyChokeGroup(Settings& settings, DrumKit& kit, +	                     Instrument& instr, event_t& event, +	                     EventsDS& events_ds, std::size_t pos); +	//! Applies directed choke actions to active events based on the input event +	void applyDirectedChoke(Settings& settings, DrumKit& kit, +	                        Instrument& instr, event_t& event, +	                        EventsDS& events_ds, std::size_t pos); +  	//! Ramps down samples from events_ds is there are more groups playing than  	//! max_voices for a given instrument.  	void limitVoices(std::size_t instrument_id, std::size_t max_voices, -	                 float rampdown_time); +	                 float rampdown_time, std::size_t pos);  	std::vector<std::unique_ptr<InputFilter>> filters; diff --git a/src/midimapper.cc b/src/midimapper.cc index b9316c5..345ce2f 100644 --- a/src/midimapper.cc +++ b/src/midimapper.cc @@ -30,7 +30,7 @@ std::vector<int> MidiMapper::lookup(int note_id)  {  	std::vector<int> instruments; -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex);  	for(const auto& map_entry : midimap)  	{ @@ -49,7 +49,7 @@ std::vector<int> MidiMapper::lookup(int note_id)  void MidiMapper::swap(instrmap_t& instrmap, midimap_t& midimap)  { -	std::lock_guard<std::mutex> guard(mutex); +	const std::lock_guard<std::mutex> guard(mutex);  	std::swap(this->instrmap, instrmap);  	std::swap(this->midimap, midimap); diff --git a/src/nolocale.h b/src/nolocale.h index 430c38c..7a10a9c 100644 --- a/src/nolocale.h +++ b/src/nolocale.h @@ -27,7 +27,7 @@  #pragma once  #include <locale.h> -#include <stdarg.h> +#include <cstdarg>  #include <cstdlib>  static inline double atof_nol(const char* nptr) diff --git a/src/owner.h b/src/owner.h new file mode 100644 index 0000000..0c67ae5 --- /dev/null +++ b/src/owner.h @@ -0,0 +1,24 @@ +//! -*- c++ -*- +#pragma once + +//#include <type_traits>  // for enable_if_t, is_convertible, is_assignable + +// Taken from the GSL Core Guidelines Support Library +namespace gsl +{ + +// +// owner +// +// `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory. +// Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used +// as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers. +// +// T must be a pointer type +// - disallow construction from any type other than pointer type +// +//template <class T, class = std::enable_if_t<std::is_pointer<T>::value>> +template<typename T> +using owner = T; + +}// gsl:: diff --git a/src/path.cc b/src/path.cc index 993f9a6..eaa1e04 100644 --- a/src/path.cc +++ b/src/path.cc @@ -30,8 +30,8 @@  #include <libgen.h>  #endif/*__MINGW32__*/ -#include <string.h> -#include <stdlib.h> +#include <cstring> +#include <cstdlib>  std::string getPath(const std::string& file)  { diff --git a/src/powerlist.cc b/src/powerlist.cc index 23d9795..f852ac9 100644 --- a/src/powerlist.cc +++ b/src/powerlist.cc @@ -27,8 +27,8 @@  #include "powerlist.h"  #include <algorithm> -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring>  #include <hugin.hpp> @@ -36,7 +36,7 @@  #ifdef __STRICT_ANSI__  #undef __STRICT_ANSI__  #endif -#include <math.h> +#include <cmath>  #include "random.h"  #include "settings.h" @@ -84,6 +84,7 @@ const Channel* PowerList::getMasterChannel()  			af->load(nullptr, LOAD_SIZE);  			float silence{0.f}; +			(void)silence;  			std::size_t silence_length{4u};  			for (auto s = af->size; s > 0 && s > af->size - silence_length; --s)  			{ diff --git a/src/powermap.h b/src/powermap.h deleted file mode 100644 index 3a406cc..0000000 --- a/src/powermap.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: c++ -*- */ -/*************************************************************************** - *            powermap.h - * - *  Fri Apr 17 23:06:12 CEST 2020 - *  Copyright 2020 André Nusser - *  andre.nusser@googlemail.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 <array> -#include <vector> - -class Powermap -{ -public: -	using Power = float; -	using Powers = std::vector<Power>; -	struct PowerPair -	{ -		Power in; -		Power out; - -		bool operator!=(const PowerPair& other) -		{ -			return in != other.in || out != other.out; -		} -	}; - -	Powermap(); - -	Power map(Power in); -	void reset(); - -	void setFixed0(PowerPair new_value); -	void setFixed1(PowerPair new_value); -	void setFixed2(PowerPair new_value); -	void setShelf(bool enable); - -	PowerPair getFixed0() const; -	PowerPair getFixed1() const; -	PowerPair getFixed2() const; - -private: -	// input parameters (state of this class) -	std::array<PowerPair, 3> fixed; -	bool shelf; - -	// spline parameters (deterministically computed from the input parameters) -	bool spline_needs_update; -	std::array<float, 5> m; -	const Power eps = 1e-4; - -	void updateSpline(); -	std::vector<float> calcSlopes(const Powers& X, const Powers& P); - -	Power clamp(Power in, Power min, Power max) const; -}; diff --git a/src/powermapfilter.h b/src/powermapfilter.h index 263f809..b9dfe5b 100644 --- a/src/powermapfilter.h +++ b/src/powermapfilter.h @@ -27,7 +27,7 @@  #pragma once  #include "inputfilter.h" -#include "powermap.h" +#include "curvemap.h"  struct Settings; @@ -43,5 +43,5 @@ public:  private:  	Settings& settings; -	Powermap powermap; +	CurveMap powermap;  }; @@ -28,8 +28,8 @@  #include <hugin.hpp>  #include <limits> -#include <assert.h> -#include <string.h> +#include <cassert> +#include <cstring>  #include <chrono>  #include <thread> @@ -37,8 +37,8 @@  #if DG_PLATFORM != DG_PLATFORM_WINDOWS  #include <semaphore.h> -#include <errno.h> -#include <stdio.h> +#include <cerrno> +#include <cstdio>  #include <sys/time.h>  #endif diff --git a/src/syncedsettings.h b/src/syncedsettings.h index 0fe5efd..d12277a 100644 --- a/src/syncedsettings.h +++ b/src/syncedsettings.h @@ -64,7 +64,7 @@ public:  		: mutex{}  		, data{}  	{ -		std::lock_guard<std::mutex> lock{other.mutex}; +		const std::lock_guard<std::mutex> lock{other.mutex};  		data = other.data;  	} @@ -72,7 +72,7 @@ public:  		: mutex{}  		, data{}  	{ -		std::lock_guard<std::mutex> lock{other.mutex}; +		const std::lock_guard<std::mutex> lock{other.mutex};  		std::swap(data, other.data);  	} @@ -80,19 +80,19 @@ public:  	{  		if (*this != &other)  		{ -			std::lock_guard<std::mutex> lock{mutex}; -			std::lock_guard<std::mutex> lock2{other.mutex}; +			const std::lock_guard<std::mutex> lock{mutex}; +			const std::lock_guard<std::mutex> lock2{other.mutex};  			data = other.data;  		}  		return *this;  	} -	 +  	Group<T>& operator=(Group<T>&& other)  	{  		if (*this != &other)  		{ -			std::lock_guard<std::mutex> lock{mutex}; -			std::lock_guard<std::mutex> lock2{other.mutex}; +			const std::lock_guard<std::mutex> lock{mutex}; +			const std::lock_guard<std::mutex> lock2{other.mutex};  			std::swap(data, other.data);  		}  		return *this; @@ -100,7 +100,7 @@ public:  	operator T() const  	{ -		std::lock_guard<std::mutex> lock{mutex}; +		const std::lock_guard<std::mutex> lock{mutex};  		return data;  	}  }; diff --git a/src/translation.cc b/src/translation.cc index 18763e4..c71f6c0 100644 --- a/src/translation.cc +++ b/src/translation.cc @@ -62,13 +62,13 @@ bool comparator(const Text& a, const Text& b)  Translation::Translation()  { -	std::lock_guard<std::mutex>(singleton.mutex); +	const std::lock_guard<std::mutex> lock(singleton.mutex);  	++singleton.refcnt;  }  Translation::~Translation()  { -	std::lock_guard<std::mutex>(singleton.mutex); +	const std::lock_guard<std::mutex> lock(singleton.mutex);  	--singleton.refcnt; @@ -219,7 +219,7 @@ bool Translation::load(const char* catalog, std::size_t size)  	std::sort(texts.begin(), texts.end(), comparator);  	{ -		std::lock_guard<std::mutex>(singleton.mutex); +		const std::lock_guard<std::mutex> lock(singleton.mutex);  		std::swap(singleton.texts, texts);  	} @@ -228,7 +228,7 @@ bool Translation::load(const char* catalog, std::size_t size)  const char* Translation::gettext(std::uint64_t msgid, const char* original)  { -	std::lock_guard<std::mutex>(singleton.mutex); +	const std::lock_guard<std::mutex> lock(singleton.mutex);  	if(singleton.refcnt == 0)  	{  		return original; diff --git a/src/versionstr.cc b/src/versionstr.cc index 8c6c66f..ac16e41 100644 --- a/src/versionstr.cc +++ b/src/versionstr.cc @@ -26,9 +26,8 @@   */  #include "versionstr.h" -#include <memory.h> -#include <stdlib.h> -#include <stdio.h> +#include <cstdlib> +#include <cstdio>  #include <hugin.hpp> diff --git a/test/Makefile.am b/test/Makefile.am index 6441fd3..0827cae 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -8,7 +8,7 @@ TESTS = resource enginetest paintertest configfile audiocache \  	randomtest atomictest syncedsettingstest imagecachetest \  	semaphoretest drumkitcreatortest bytesizeparsertest notifiertest \  	dgxmlparsertest domloadertest configparsertest midimapparsertest \ -	eventsdstest powermaptest midimappertest +	eventsdstest curvemaptest midimappertest  if WITH_NLS  TESTS += translationtest @@ -51,7 +51,8 @@ audiocache_CXXFLAGS = \  	-I$(top_srcdir)/src \  	-I$(top_srcdir)/hugin -DDISABLE_HUGIN \  	$(PTHREAD_CFLAGS) \ -	$(SNDFILE_CFLAGS) +	$(SNDFILE_CFLAGS)  \ +	-Wno-deprecated-declarations  audiocache_LDFLAGS = $(PTHREAD_LIBS) $(SNDFILE_LIBS)  audiocache_SOURCES = \  	$(top_srcdir)/src/audiocache.cc \ @@ -72,7 +73,8 @@ audiocachefile_CXXFLAGS = \  	-I$(top_srcdir)/src \  	-I$(top_srcdir)/hugin -DDISABLE_HUGIN \  	$(PTHREAD_CFLAGS) \ -	$(SNDFILE_CFLAGS) +	$(SNDFILE_CFLAGS) \ +	-Wno-deprecated-declarations  audiocachefile_LDFLAGS = $(PTHREAD_LIBS) $(SNDFILE_LIBS)  audiocachefile_SOURCES = \  	$(top_srcdir)/src/audiocachefile.cc \ @@ -102,7 +104,8 @@ audiocacheeventhandler_CXXFLAGS = \  	-I$(top_srcdir)/src \  	-I$(top_srcdir)/hugin -DDISABLE_HUGIN \  	$(PTHREAD_CFLAGS) \ -	$(SNDFILE_CFLAGS) +	$(SNDFILE_CFLAGS) \ +	-Wno-deprecated-declarations  audiocacheeventhandler_LDFLAGS = $(PTHREAD_LIBS) $(SNDFILE_LIBS)  audiocacheeventhandler_SOURCES = \  	$(top_srcdir)/src/audiocacheeventhandler.cc \ @@ -218,7 +221,8 @@ semaphoretest_CXXFLAGS = \  	$(DEBUG_FLAGS) \  	-I$(top_srcdir)/src \  	-I$(top_srcdir)/hugin \ -	$(PTHREAD_CFLAGS) +	$(PTHREAD_CFLAGS) \ +	-Wno-deprecated-declarations  semaphoretest_LDFLAGS = $(PTHREAD_LIBS)  semaphoretest_SOURCES = \  	$(top_srcdir)/hugin/hugin.c \ @@ -325,14 +329,14 @@ eventsdstest_SOURCES = \  	eventsdstest.cc \  	uunit/uunit.cc -powermaptest_CXXFLAGS = \ -	-I$(top_srcdir)/test/uunit -DOUTPUT=\"powermaptest\" \ +curvemaptest_CXXFLAGS = \ +	-I$(top_srcdir)/test/uunit -DOUTPUT=\"curvemaptest\" \  	$(DEBUG_FLAGS) \  	-I$(top_srcdir)/src -powermaptest_LDFLAGS = -powermaptest_SOURCES = \ -	$(top_srcdir)/src/powermap.cc \ -	powermaptest.cc \ +curvemaptest_LDFLAGS = +curvemaptest_SOURCES = \ +	$(top_srcdir)/src/curvemap.cc \ +	curvemaptest.cc \  	uunit/uunit.cc  midimappertest_CXXFLAGS = \ diff --git a/test/audiocacheidmanagertest.cc b/test/audiocacheidmanagertest.cc index c84926b..9d8be25 100644 --- a/test/audiocacheidmanagertest.cc +++ b/test/audiocacheidmanagertest.cc @@ -52,39 +52,39 @@ public:  		TestableAudioCacheIDManager manager;  		manager.init(2); -		cache_t c1; c1.afile = (AudioCacheFile*)1; +		CacheBuffer c1; c1.afile = (AudioCacheFile*)1;  		auto id1 = manager.registerID(c1);  		uUNIT_ASSERT(id1 != CACHE_DUMMYID);  		uUNIT_ASSERT(id1 != CACHE_NOID);  		uUNIT_ASSERT_EQUAL(1, manager.getAvailableIDs()); -		cache_t c2; c2.afile = (AudioCacheFile*)2; +		CacheBuffer c2; c2.afile = (AudioCacheFile*)2;  		auto id2 = manager.registerID(c2);  		uUNIT_ASSERT(id2 != CACHE_DUMMYID);  		uUNIT_ASSERT(id2 != CACHE_NOID);  		uUNIT_ASSERT_EQUAL(0, manager.getAvailableIDs()); -		cache_t c3; c3.afile = (AudioCacheFile*)3; +		CacheBuffer c3; c3.afile = (AudioCacheFile*)3;  		auto id3 = manager.registerID(c3);  		uUNIT_ASSERT(id3 == CACHE_DUMMYID);  		uUNIT_ASSERT_EQUAL(0, manager.getAvailableIDs()); -		cache_t& tc1 = manager.getCache(id1); +		CacheBuffer& tc1 = manager.getCache(id1);  		uUNIT_ASSERT_EQUAL(c1.afile, tc1.afile); -		cache_t& tc2 = manager.getCache(id2); +		CacheBuffer& tc2 = manager.getCache(id2);  		uUNIT_ASSERT_EQUAL(c2.afile, tc2.afile);  		manager.releaseID(id1);  		uUNIT_ASSERT_EQUAL(1, manager.getAvailableIDs()); -		cache_t c4; c4.afile = (AudioCacheFile*)4; +		CacheBuffer c4; c4.afile = (AudioCacheFile*)4;  		auto id4 = manager.registerID(c4);  		uUNIT_ASSERT(id4 != CACHE_DUMMYID);  		uUNIT_ASSERT(id4 != CACHE_NOID);  		uUNIT_ASSERT_EQUAL(0, manager.getAvailableIDs()); -		cache_t& tc4 = manager.getCache(id4); +		CacheBuffer& tc4 = manager.getCache(id4);  		uUNIT_ASSERT_EQUAL(c4.afile, tc4.afile);  		manager.releaseID(id2); diff --git a/test/curvemaptest.cc b/test/curvemaptest.cc new file mode 100644 index 0000000..cb90d1b --- /dev/null +++ b/test/curvemaptest.cc @@ -0,0 +1,267 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + *            curvemaptest.cc + * + *  Fri Jul 26 19:43:32 CEST 2024 + *  Copyright 2024 Sander Vocke + *  sandervocke@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 <uunit.h> +#include <map> + +#include "../src/curvemap.h" +#include <iostream> +#include <iomanip> + +class test_curvemaptest +	: public uUnit +{ +public: +	test_curvemaptest() +	{ +		uUNIT_TEST(test_curvemaptest::check_default); +		uUNIT_TEST(test_curvemaptest::check_default_invert); +		uUNIT_TEST(test_curvemaptest::check_default_disabled_shelf); +		uUNIT_TEST(test_curvemaptest::check_default_disabled_shelf_invert); +		uUNIT_TEST(test_curvemaptest::check_fixed1_075_025); +		uUNIT_TEST(test_curvemaptest::check_fixed1_075_025_invert); +		uUNIT_TEST(test_curvemaptest::check_shelf_060); +		uUNIT_TEST(test_curvemaptest::check_shelf_060_invert); +		uUNIT_TEST(test_curvemaptest::check_reset); +	} + +	const std::map<double, double> default_map = { +		{0.0, 1e-4}, +		{1e-4, 1e-4}, +		{0.1, 0.1}, +		{0.2, 0.2}, +		{0.3, 0.3}, +		{0.4, 0.4}, +		{0.5, 0.5}, +		{0.6, 0.6}, +		{0.7, 0.7}, +		{0.8, 0.8}, +		{0.9, 0.9}, +		{1.0 - 1e-4, 1.0 - 1e-4}, +		{1.0, 1.0 - 1e-4} +	}; + +	const std::map<double, double> identity_map = { +		{0.0, 0.0}, +		{0.1, 0.1}, +		{0.2, 0.2}, +		{0.3, 0.3}, +		{0.4, 0.4}, +		{0.5, 0.5}, +		{0.6, 0.6}, +		{0.7, 0.7}, +		{0.8, 0.8}, +		{0.9, 0.9}, +		{1.0, 1.0} +	}; + +	const std::map<double, double> fixed1_075_025_map = { +		{0.0, 1e-4}, +		{1e-4, 1e-4}, +		{0, 0.0001}, +		{0.1, 0.0295469705015421}, +		{0.2, 0.0536915548145771}, +		{0.3, 0.0760560110211372}, +		{0.4, 0.100195862352848}, +		{0.5, 0.129666686058044}, +		{0.6, 0.168024003505707}, +		{0.7, 0.218823373317719}, +		{0.8, 0.325357049703598}, +		{0.9, 0.64416378736496}, +		{1.0 - 1e-4, 1.0 - 1e-4}, +		{1.0, 1.0 - 1e-4} +	}; + +	const std::map<double, double> shelf_060_map = { +		{0.0, 1e-4}, +		{1e-4, 1e-4}, +		{0.1, 0.1}, +		{0.2, 0.2}, +		{0.3, 0.3}, +		{0.4, 0.4}, +		{0.5, 0.5}, +		{0.6, 0.6}, +		{0.7, 0.6}, +		{0.8, 0.6}, +		{0.9, 0.6}, +		{1.0, 0.6} +	}; + +	void check_default() +	{ +		auto dataset = this->default_map; + +		CurveMap map; + +		for (auto& entry : dataset) { +			auto in = entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_reset() +	{ +		auto dataset = this->default_map; + +		CurveMap map; +		map.setFixed0({0.1, 0.2}); +		map.setFixed1({0.2, 0.3}); +		map.setFixed2({0.3, 0.4}); +		map.setInvert(!map.getInvert()); +		map.setShelf(!map.getShelf()); + +		bool any_difference = false; +		for (auto& entry : dataset) { +			auto in = entry.first; +			auto expect = entry.second; +			if (expect != map.map(in)) { +				any_difference = true; +				break; +			} +		} + +		uASSERT(any_difference); + +		map.reset(); +		 +		for (auto& entry : dataset) { +			auto in = entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_default_invert() +	{ +		auto dataset = this->default_map; + +		CurveMap map; +		map.setInvert(true); + +		for (auto& entry : dataset) { +			auto in = 1.0 - entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_default_disabled_shelf() +	{ +		auto dataset = this->identity_map; + +		CurveMap map; +		map.setShelf(false); +		map.setFixed2({0.6, 0.6}); + +		for (auto& entry : dataset) { +			auto in = entry.first; +			auto expect = entry.second; +			// std::cout << "{" << in << ", " << std::setprecision (15) << map.map(in) << "}," << std::endl; // FIXME +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_default_disabled_shelf_invert() +	{ +		auto dataset = this->identity_map; + +		CurveMap map; +		map.setShelf(false); +		map.setFixed2({0.6, 0.6}); +		map.setInvert(true); + +		for (auto& entry : dataset) { +			auto in = 1.0 - entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_fixed1_075_025() +	{ +		auto dataset = this->fixed1_075_025_map; + +		CurveMap map; +		map.setFixed1({0.75, 0.25}); + +		for (auto& entry : dataset) { +			auto in = entry.first; +			auto expect = entry.second; +			// std::cout << "{" << in << ", " << std::setprecision (15) << map.map(in) << "}," << std::endl; // FIXME +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_fixed1_075_025_invert() +	{ +		auto dataset = this->fixed1_075_025_map; + +		CurveMap map; +		map.setFixed1({0.75, 0.25}); +		map.setInvert(true); + +		for (auto& entry : dataset) { +			auto in = 1.0 - entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_shelf_060() +	{ +		auto dataset = this->shelf_060_map; + +		CurveMap map; +		map.setFixed2({0.6, 0.6}); +		map.setShelf(true); + +		for (auto& entry : dataset) { +			auto in = entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} + +	void check_shelf_060_invert() +	{ +		auto dataset = this->shelf_060_map; + +		CurveMap map; +		map.setFixed2({0.6, 0.6}); +		map.setShelf(true); +		map.setInvert(true); + +		for (auto& entry : dataset) { +			auto in = 1.0 - entry.first; +			auto expect = entry.second; +			uASSERT_EQUAL(expect, map.map(in)); +		} +	} +}; + +// Registers the fixture into the 'registry' +static test_curvemaptest test; diff --git a/test/dgreftest/midiinputengine.h b/test/dgreftest/midiinputengine.h index ffd22f8..e76a182 100644 --- a/test/dgreftest/midiinputengine.h +++ b/test/dgreftest/midiinputengine.h @@ -26,15 +26,15 @@   */  #pragma once -#include <audioinputenginemidi.h> -#include <midimapper.h> -#include <midimapparser.h>  #include <string>  #include <vector> -#include <event.h>  #include <smf.h> +#include <audioinputenginemidi.h> +#include <midimapper.h> +#include <midimapparser.h> +  class MidifileInputEngine  	: public AudioInputEngineMidi  { diff --git a/test/paintertest.cc b/test/paintertest.cc index 5a1c44a..10b96dc 100644 --- a/test/paintertest.cc +++ b/test/paintertest.cc @@ -91,7 +91,7 @@ public:  		has_alpha = alpha;  		image_data.resize(_width * _height); -		image_data_raw.resize(_width * _height); +		image_data_raw.resize(4 * _width * _height);  		// Store x and y coordinates as red and green colour components  		for(std::uint8_t x = 0; x < _width; ++x) diff --git a/test/powermaptest.cc b/test/powermaptest.cc deleted file mode 100644 index bef5bdc..0000000 --- a/test/powermaptest.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: c++ -*- */ -/*************************************************************************** - *            powermaptest.cc - * - *  Sun Apr 19 23:23:37 CEST 2020 - *  Copyright 2020 André Nusser - *  andre.nusser@googlemail.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 <uunit.h> - -#include "../src/powermap.h" - -class test_powermaptest -	: public uUnit -{ -public: -	test_powermaptest() -	{ -		uUNIT_TEST(test_powermaptest::check_values); -	} - -	void check_values() -	{ -		Powermap powermap; - -		// TODO -		// std::cout << powermap.map(.8) << std::endl; -		// uUNIT_ASSERT_EQUAL(powermap.map(.8), .8); -	} -}; - -// Registers the fixture into the 'registry' -static test_powermaptest test; diff --git a/tools/add_file b/tools/add_file index a704029..51d50b4 100755 --- a/tools/add_file +++ b/tools/add_file @@ -26,6 +26,10 @@ function allfile() {    then      NAME="Goran Mekić"; EMAIL="meka@tilda.center"    fi +  if [ "$USER" == "sander" ] +  then +    NAME="Sander Vocke"; EMAIL="sandervocke@gmail.com" +  fi    echo "/* -*- Mode: c++ -*- */" > $1;    echo "/***************************************************************************" >> $1; diff --git a/tools/macos/build-dg.sh b/tools/macos/build-dg.sh new file mode 100755 index 0000000..84585d4 --- /dev/null +++ b/tools/macos/build-dg.sh @@ -0,0 +1,264 @@ +#!/bin/bash + +# --------------------------------------------------------------------------------------------------------------------- +# stop on error + +set -e + +# --------------------------------------------------------------------------------------------------------------------- +# stop on error + +TARGETDIR=$PWD/builds/drumgizmo + +DOWNLOADS=$PWD/downloads + +PKG_CONFIG_VERSION=0.28 +LIBOGG_VERSION=1.3.3 +LIBVORBIS_VERSION=1.3.6 +FLAC_VERSION=1.3.2 +LIBSNDFILE_VERSION=1.0.28 +ZITA_RESAMPLER_VERSION=1.6.2 + +DRUMGIZMO_VERSION=0.9.20 + +# --------------------------------------------------------------------------------------------------------------------- +# function to remove old stuff + +cleanup() +{ + +rm -rf $TARGETDIR +rm -rf flac-* +rm -rf libogg-* +rm -rf libsndfile-* +rm -rf libvorbis-* +rm -rf pkg-config-* +exit 0 + +} + +# --------------------------------------------------------------------------------------------------------------------- +# setup build vars + +export CC=clang +export CXX=clang++ + +export PREFIX=${TARGETDIR} +export PATH=${PREFIX}/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin +export PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig + +export CFLAGS="-O3 -mtune=generic -msse -msse2 -fvisibility=hidden" +export CFLAGS="${CFLAGS} -fPIC -DPIC -DNDEBUG -I${PREFIX}/include" +export CXXFLAGS="${CFLAGS} -fvisibility-inlines-hidden -stdlib=libc++" + +export LDFLAGS="-Wl,-dead_strip -Wl,-dead_strip_dylibs" +export LDFLAGS="${LDFLAGS} -L${PREFIX}/lib" + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package pkgconfig ==== + +if [ ! -f ${DOWNLOADS}/pkg-config-${PKG_CONFIG_VERSION}.tar.gz ]; then +  pushd ${DOWNLOADS} +  curl -O https://pkg-config.freedesktop.org/releases/pkg-config-${PKG_CONFIG_VERSION}.tar.gz || \ +  curl -k -O https://drumgizmo.org/mirror/pkg-config-${PKG_CONFIG_VERSION}.tar.gz +  popd +fi + +if [ ! -d pkg-config-${PKG_CONFIG_VERSION} ]; then +  tar -xf ${DOWNLOADS}/pkg-config-${PKG_CONFIG_VERSION}.tar.gz +fi + +if [ ! -f pkg-config-${PKG_CONFIG_VERSION}/build-done ]; then +  cd pkg-config-${PKG_CONFIG_VERSION} +  ./configure --enable-indirect-deps --with-internal-glib --with-pc-path=$PKG_CONFIG_PATH --prefix=${PREFIX} +  make ${MAKE_ARGS} +  make install +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package libogg ==== + +if [ ! -f ${DOWNLOADS}/libogg-${LIBOGG_VERSION}.tar.gz ]; then +  pushd ${DOWNLOADS} +  curl -O http://ftp.osuosl.org/pub/xiph/releases/ogg/libogg-${LIBOGG_VERSION}.tar.gz || \ +  curl -k -O https://drumgizmo.org/mirror/libogg-${LIBOGG_VERSION}.tar.gz +  popd +fi + +if [ ! -d libogg-${LIBOGG_VERSION} ]; then +  tar -xf ${DOWNLOADS}/libogg-${LIBOGG_VERSION}.tar.gz +fi + +if [ ! -f libogg-${LIBOGG_VERSION}/build-done ]; then +  cd libogg-${LIBOGG_VERSION} +  ./configure --enable-static --disable-shared --prefix=${PREFIX} +  make ${MAKE_ARGS} +  make install +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package libvorbis ==== + +if [ ! -f ${DOWNLOADS}/libvorbis-${LIBVORBIS_VERSION}.tar.gz ]; then +  pushd ${DOWNLOADS} +  curl -O http://ftp.osuosl.org/pub/xiph/releases/vorbis/libvorbis-${LIBVORBIS_VERSION}.tar.gz || \ +  curl -k -O https://drumgizmo.org/mirror/libvorbis-${LIBVORBIS_VERSION}.tar.gz +  popd +fi + +if [ ! -d libvorbis-${LIBVORBIS_VERSION} ]; then +  tar -xf ${DOWNLOADS}/libvorbis-${LIBVORBIS_VERSION}.tar.gz +fi + +if [ ! -f libvorbis-${LIBVORBIS_VERSION}/build-done ]; then +  cd libvorbis-${LIBVORBIS_VERSION} +  ./configure --enable-static --disable-shared --prefix=${PREFIX} +  make ${MAKE_ARGS} +  make install +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package flac ==== + +if [ ! -f ${DOWNLOADS}/flac-${FLAC_VERSION}.tar.xz ]; then +  pushd ${DOWNLOADS} +  curl -O http://ftp.osuosl.org/pub/xiph/releases/flac/flac-${FLAC_VERSION}.tar.xz || \ +  curl -k -O https://drumgizmo.org/mirror/flac-${FLAC_VERSION}.tar.xz +  popd +fi +if [ ! -d flac-${FLAC_VERSION} ]; then +  tar -xf ${DOWNLOADS}/flac-${FLAC_VERSION}.tar.xz +fi + +if [ ! -f flac-${FLAC_VERSION}/build-done ]; then +  cd flac-${FLAC_VERSION} +  sed -i -e "s/HAVE_CPUID_H/HAVE_CPUID_H_NOT/" src/libFLAC/cpu.c +  chmod +x configure install-sh +  ./configure --enable-static --disable-shared --prefix=${PREFIX} \ +    --disable-cpplibs +  echo "exit 0" > missing +  make ${MAKE_ARGS} +  make install +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package libsndfile ==== + +if [ ! -f ${DOWNLOADS}/libsndfile-${LIBSNDFILE_VERSION}.tar.gz ]; then +  pushd ${DOWNLOADS} +  curl -O http://www.mega-nerd.com/libsndfile/files/libsndfile-${LIBSNDFILE_VERSION}.tar.gz || \ +  curl -k -O https://drumgizmo.org/mirror/libsndfile-${LIBSNDFILE_VERSION}.tar.gz +  popd +fi + +if [ ! -d libsndfile-${LIBSNDFILE_VERSION} ]; then +  tar -xf ${DOWNLOADS}/libsndfile-${LIBSNDFILE_VERSION}.tar.gz +fi + +if [ ! -f libsndfile-${LIBSNDFILE_VERSION}/build-done ]; then +  cd libsndfile-${LIBSNDFILE_VERSION} +  ./configure --enable-static --disable-shared --prefix=${PREFIX} \ +    --disable-full-suite --disable-sqlite +  make ${MAKE_ARGS} +  make install +  sed -i -e "s|-lsndfile|-lsndfile -lFLAC -lvorbisenc -lvorbis -logg -lm|" ${PREFIX}/lib/pkgconfig/sndfile.pc +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package zita-resampler ==== + +if [ ! -f ${DOWNLOADS}/zita-resampler-${ZITA_RESAMPLER_VERSION}.tar.bz2 ]; then +  pushd ${DOWNLOADS} +  curl -O http://kokkinizita.linuxaudio.org/linuxaudio/downloads/zita-resampler-${ZITA_RESAMPLER_VERSION}.tar.bz2 || \ +  curl -k -O https://drumgizmo.org/mirror/zita-resampler-${ZITA_RESAMPLER_VERSION}.tar.bz2 +  popd +fi + +if [ ! -d zita-resampler-${ZITA_RESAMPLER_VERSION} ]; then +  tar -xf ${DOWNLOADS}/zita-resampler-${ZITA_RESAMPLER_VERSION}.tar.bz2 +fi + +if [ ! -f zita-resampler-${ZITA_RESAMPLER_VERSION}/build-done ]; then +  cd zita-resampler-${ZITA_RESAMPLER_VERSION} +  if [ ! -f patched ]; then +    patch -p1 -i ../zita-resampler-static-build.patch +    touch patched +  fi +  make ${MAKE_ARGS} -C source +  mkdir ${PREFIX}/include/zita-resampler +  cp source/*.a ${PREFIX}/lib/ +  cp source/zita-resampler/*.h ${PREFIX}/include/zita-resampler/ +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- +echo ==== Package drumgizmo ==== + +if [ ! -f ${DOWNLOADS}/drumgizmo-${DRUMGIZMO_VERSION}.tar.gz ]; then +  pushd ${DOWNLOADS} +  curl -O https://www.drumgizmo.org/releases/drumgizmo-${DRUMGIZMO_VERSION}/drumgizmo-${DRUMGIZMO_VERSION}.tar.gz +  popd +fi + +if [ ! -d drumgizmo-${DRUMGIZMO_VERSION} ]; then +  tar -xf ${DOWNLOADS}/drumgizmo-${DRUMGIZMO_VERSION}.tar.gz +fi + +if [ ! -f drumgizmo-${DRUMGIZMO_VERSION}/build-done ]; then +  PATH=/usr/local/opt/gettext/bin:$PATH +  cd drumgizmo-${DRUMGIZMO_VERSION} +  ./configure --prefix=${PREFIX} \ +    --disable-input-midifile \ +    --disable-input-jackmidi \ +    --disable-output-jackaudio \ +    --disable-input-alsamidi \ +    --disable-output-alsa \ +    --enable-cli \ +    --without-debug \ +    --with-test \ +    --disable-lv2 \ +    --enable-vst \ +    --with-vst-sources=$HOME/VST3_SDK +  make ${MAKE_ARGS} +  make install +  touch build-done +  cd .. +fi + +# --------------------------------------------------------------------------------------------------------------------- + +echo Make macOS package: + +otool -L ${PREFIX}/lib/vst/drumgizmo_vst.so + +if [ ! -f drumgizmo.vst.tar.gz ]; then +  exit "Missing VST package template: drumgizmo.vst.tar.gz " +fi + +if [ ! -d ${DRUMGIZMO_VERSION}/drumgizmo.vst ]; then +  mkdir -p ${DRUMGIZMO_VERSION} +  pushd ${DRUMGIZMO_VERSION} +  tar -xvzf ../drumgizmo.vst.tar.gz +  popd +fi + +cp -a ${PREFIX}/lib/vst/drumgizmo_vst.so ${DRUMGIZMO_VERSION}/drumgizmo.vst/Contents/MacOS/drumgizmo +sed -e "s/@VERSION@/${DRUMGIZMO_VERSION}/g" -i .bak ${DRUMGIZMO_VERSION}/drumgizmo.vst/Contents/Info.plist +rm -f ${DRUMGIZMO_VERSION}/drumgizmo.vst/Contents/Info.plist.bak + +pushd ${DRUMGIZMO_VERSION} +tar cvzf ../drumgizmo_vst-osx-${DRUMGIZMO_VERSION}.tar.gz drumgizmo.vst/ +popd + +echo Package is now ready in drumgizmo_vst-osx-${DRUMGIZMO_VERSION}.tar.gz diff --git a/tools/macos/drumgizmo.vst.tar.gz b/tools/macos/drumgizmo.vst.tar.gz Binary files differnew file mode 100644 index 0000000..0db45db --- /dev/null +++ b/tools/macos/drumgizmo.vst.tar.gz diff --git a/tools/macos/zita-resampler-static-build.patch b/tools/macos/zita-resampler-static-build.patch new file mode 100644 index 0000000..5b894e1 --- /dev/null +++ b/tools/macos/zita-resampler-static-build.patch @@ -0,0 +1,28 @@ +--- zita-resampler-static-1.6.2.orig/source/Makefile ++++ zita-resampler-static-1.6.2/source/Makefile +@@ -32,12 +32,12 @@ DISTDIR = zita-resampler-$(VERSION) +  +  + CPPFLAGS += -I. -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS +-CXXFLAGS += -Wall -fPIC -O2 -ffast-math +-CXXFLAGS += -march=native ++CXXFLAGS += -Wall -fPIC -O3 -ffast-math + LDFLAGS +=  + LDLIBS += +  +  ++ZITA-RESAMPLER_A = libzita-resampler.a + ZITA-RESAMPLER_SO = libzita-resampler.so + ZITA-RESAMPLER_MAJ = $(ZITA-RESAMPLER_SO).$(MAJVERS) + ZITA-RESAMPLER_MIN = $(ZITA-RESAMPLER_MAJ).$(MINVERS) +@@ -47,6 +47,10 @@ ZITA-RESAMPLER_H = zita-resampler/resamp + 	zita-resampler/vresampler.h zita-resampler/cresampler.h +  +  ++$(ZITA-RESAMPLER_A): $(ZITA-RESAMPLER_O) ++	rm -f $@ ++	ar cr $@ $^ ++ + $(ZITA-RESAMPLER_MIN): $(ZITA-RESAMPLER_O) + 	$(CXX) -shared $(LDFLAGS) -Wl,-soname,$(ZITA-RESAMPLER_MAJ) -o $(ZITA-RESAMPLER_MIN) $(ZITA-RESAMPLER_O) $(ZITA-RESAMPLER_DEP) +  @@ -1 +1 @@ -#define VERSION "0.9.19" +#define VERSION "0.9.20"  | 
