diff options
77 files changed, 1465 insertions, 486 deletions
diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..d3437d7 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,35 @@ +--- +Checks: "*, + -abseil-*, + -altera-*, + -android-*, + -fuchsia-*, + -google-*, + -llvm*, + -modernize-use-trailing-return-type, + -zircon-*, + -readability-else-after-return, + -readability-static-accessed-through-instance, + -readability-avoid-const-params-in-decls, + -cppcoreguidelines-non-private-member-variables-in-classes, + -misc-non-private-member-variables-in-classes, + -misc-include-cleaner, + -cppcoreguidelines-avoid-do-while, + -bugprone-easily-swappable-parameters, + -hicpp-uppercase-literal-suffix, + -readability-uppercase-literal-suffix, +" +WarningsAsErrors: '' +HeaderFilterRegex: '' +FormatStyle: none + +CheckOptions: + - key: readability-identifier-length.IgnoredVariableNames + value: 'x|y|z' + - key: readability-identifier-length.IgnoredParameterNames + value: 'x|y|z' + + + + + @@ -1,3 +1,6 @@ +build/* +tools/performance_test/* +vst-tmp/* Makefile Makefile.in Makefile.mingw32 @@ -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..62b527e 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 @@ -139,6 +137,8 @@ static std::string arguments() "Sample selection parameters:\n" " close: The importance given to choosing a sample close to\n" " the actual velocity value (after humanization). [0,1]\n" + " position: The importance given to choosing a sample close to\n" + " the actual position value (after humanization). [0,1]\n" " diverse: The importance given to choosing samples\n" " which haven't been played recently. [0,1]\n" " random: The amount of randomness added. [0,1]\n" @@ -617,6 +617,16 @@ int main(int argc, char* argv[]) } settings.sample_selection_f_close.store(val); } + else if(token.key == "position") + { + auto val = atof_nol(token.value.data()); + if(val < 0 || val > 1) + { + std::cerr << "position range is [0, 1].\n"; + return 1; + } + settings.sample_selection_f_position.store(val); + } else if(token.key == "diverse") { auto val = atof_nol(token.value.data()); 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/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 1b8c848..7fbc3f5 100644 --- a/plugin/Makefile.mingw32.in +++ b/plugin/Makefile.mingw32.in @@ -50,6 +50,7 @@ DG_SRC = \ @top_srcdir@/src/translation.cc \ @top_srcdir@/src/velocityfilter.cc \ @top_srcdir@/src/positionfilter.cc \ + @top_srcdir@/src/position_power.cc \ @top_srcdir@/src/versionstr.cc DG_CFLAGS = -I@top_srcdir@ -I@top_srcdir@/src \ -I@top_srcdir@/zita-resampler/libs \ 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/sampleselectionframecontent.cc b/plugingui/sampleselectionframecontent.cc index 61b816f..448eca5 100644 --- a/plugingui/sampleselectionframecontent.cc +++ b/plugingui/sampleselectionframecontent.cc @@ -63,9 +63,17 @@ SampleselectionframeContent::SampleselectionframeContent(dggui::Widget* parent, f_random.setControl(&f_random_knob); layout.addItem(&f_random); + f_position.resize(80, 80); + f_position_knob.resize(30, 30); + f_position_knob.showValue(false); + f_position_knob.setDefaultValue(Settings::sample_selection_f_position_default); + f_position.setControl(&f_position_knob); + layout.addItem(&f_position); + layout.setPosition(&f_close, dggui::GridLayout::GridRange{0, 1, 0, 1}); layout.setPosition(&f_diverse, dggui::GridLayout::GridRange{1, 2, 0, 1}); layout.setPosition(&f_random, dggui::GridLayout::GridRange{2, 3, 0, 1}); + layout.setPosition(&f_position, dggui::GridLayout::GridRange{3, 4, 0, 1}); CONNECT(this, settings_notifier.sample_selection_f_close, this, &SampleselectionframeContent::fCloseSettingsValueChanged); @@ -73,6 +81,8 @@ SampleselectionframeContent::SampleselectionframeContent(dggui::Widget* parent, this, &SampleselectionframeContent::fDiverseSettingsValueChanged); CONNECT(this, settings_notifier.sample_selection_f_random, this, &SampleselectionframeContent::fRandomSettingsValueChanged); + CONNECT(this, settings_notifier.sample_selection_f_position, + this, &SampleselectionframeContent::fPositionSettingsValueChanged); CONNECT(&f_close_knob, valueChangedNotifier, this, &SampleselectionframeContent::fCloseKnobValueChanged); @@ -80,6 +90,8 @@ SampleselectionframeContent::SampleselectionframeContent(dggui::Widget* parent, this, &SampleselectionframeContent::fDiverseKnobValueChanged); CONNECT(&f_random_knob, valueChangedNotifier, this, &SampleselectionframeContent::fRandomKnobValueChanged); + CONNECT(&f_position_knob, valueChangedNotifier, + this, &SampleselectionframeContent::fPositionKnobValueChanged); } void SampleselectionframeContent::fCloseKnobValueChanged(float value) @@ -97,6 +109,11 @@ void SampleselectionframeContent::fRandomKnobValueChanged(float value) settings.sample_selection_f_random.store(value); } +void SampleselectionframeContent::fPositionKnobValueChanged(float value) +{ + settings.sample_selection_f_position.store(value); +} + void SampleselectionframeContent::fCloseSettingsValueChanged(float value) { f_close_knob.setValue(value); @@ -112,4 +129,9 @@ void SampleselectionframeContent::fRandomSettingsValueChanged(float value) f_random_knob.setValue(value); } +void SampleselectionframeContent::fPositionSettingsValueChanged(float value) +{ + f_position_knob.setValue(value); +} + } // GUI:: diff --git a/plugingui/sampleselectionframecontent.h b/plugingui/sampleselectionframecontent.h index ab1be04..d3834f6 100644 --- a/plugingui/sampleselectionframecontent.h +++ b/plugingui/sampleselectionframecontent.h @@ -52,20 +52,24 @@ private: void fCloseKnobValueChanged(float value); void fDiverseKnobValueChanged(float value); void fRandomKnobValueChanged(float value); + void fPositionKnobValueChanged(float value); void fCloseSettingsValueChanged(float value); void fDiverseSettingsValueChanged(float value); void fRandomSettingsValueChanged(float value); + void fPositionSettingsValueChanged(float value); - dggui::GridLayout layout{this, 3, 1}; + dggui::GridLayout layout{this, 4, 1}; LabeledControl f_close{this, _("pClose")}; LabeledControl f_diverse{this, _("pDiverse")}; LabeledControl f_random{this, _("pRandom")}; + LabeledControl f_position{this, _("pPosition")}; dggui::Knob f_close_knob{&f_close}; dggui::Knob f_diverse_knob{&f_diverse}; dggui::Knob f_random_knob{&f_random}; + dggui::Knob f_position_knob{&f_position}; Settings& settings; SettingsNotifier& settings_notifier; diff --git a/src/DGDOM.h b/src/DGDOM.h index a03f0ef..b4e861f 100644 --- a/src/DGDOM.h +++ b/src/DGDOM.h @@ -59,7 +59,7 @@ struct SampleDOM { std::string name; double power; // >= v2.0 only - double position; // >=v2.0 only + double position; // >= v2.0 only bool normalized; // >= v2.0 only std::vector<AudioFileDOM> audiofiles; }; diff --git a/src/Makefile.am b/src/Makefile.am index cecb49b..eb6f214 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,50 +33,52 @@ 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 \ - positionfilter.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/powermap.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/positionfilter.cc \ + $(top_srcdir)/src/position_power.cc \ + $(top_srcdir)/src/versionstr.cc EXTRA_DIST = \ $(libzr_la_SOURCES) \ @@ -107,7 +109,7 @@ EXTRA_DIST = \ drumgizmoconf.h \ drumkit.h \ drumkitloader.h \ - event.h \ + engineevent.h \ events.h \ events_ds.h \ grid.h \ @@ -122,6 +124,7 @@ EXTRA_DIST = \ midimapper.h \ nolocale.h \ notifier.h \ + owner.h \ path.h \ platform.h \ powerlist.h \ @@ -142,3 +145,10 @@ EXTRA_DIST = \ positionfilter.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..6fcdcb5 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,7 +62,7 @@ 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; @@ -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,7 +163,7 @@ 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; diff --git a/src/audiofile.h b/src/audiofile.h index 504d0ae..9fdd8c5 100644 --- a/src/audiofile.h +++ b/src/audiofile.h @@ -35,24 +35,26 @@ #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; @@ -70,7 +72,7 @@ private: friend class DOMLoaderTest; friend class InstrumentParserTest; - void* magic{nullptr}; + void* magic{}; volatile bool is_loaded{false}; - InstrumentChannel* instrument_channel; + 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 0dee346..240acc3 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,16 +91,13 @@ 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; -static const std::uint8_t ControlChange = 0xB0; +constexpr std::uint8_t NoteOff{0x80}; +constexpr std::uint8_t NoteOn{0x90}; +constexpr std::uint8_t NoteAftertouch{0xA0}; +constexpr std::uint8_t ControlChange{0xB0}; // Note type mask: -static const std::uint8_t TypeMask = 0xF0; - -// See: -// https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message +constexpr std::uint8_t NoteMask{0xF0}; void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer, std::size_t midi_buffer_length, @@ -118,7 +109,7 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer, return; } - switch(midi_buffer[0] & TypeMask) + switch(midi_buffer[0] & NoteMask) // NOLINT - span { case NoteOff: // Ignore for now @@ -126,15 +117,19 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer, case NoteOn: { - 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 instruments = mmap.lookup(key); for(const auto& instrument_idx : instruments) { 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, positional_information}); } @@ -144,8 +139,8 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer, case NoteAftertouch: { - 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 instruments = mmap.lookup(key); for(const auto& instrument_idx : instruments) { @@ -160,8 +155,8 @@ void AudioInputEngineMidi::processNote(const std::uint8_t* midi_buffer, case ControlChange: { - auto controller_number = midi_buffer[1]; - auto value = midi_buffer[2]; + auto controller_number = midi_buffer[1]; // NOLINT - span + auto value = midi_buffer[2]; // NOLINT - span if(controller_number == 16) // positional information { // Store value for use in next NoteOn event. diff --git a/src/audioinputenginemidi.h b/src/audioinputenginemidi.h index 12efd66..28da538 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,9 +68,9 @@ protected: private: std::string midimap; - bool is_valid; + bool is_valid{false}; - ConfigFile refs; + ConfigFile refs{REFSFILE}; float positional_information{0.0f}; }; 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/dgxmlparser.cc b/src/dgxmlparser.cc index bd9af66..837cc4e 100644 --- a/src/dgxmlparser.cc +++ b/src/dgxmlparser.cc @@ -365,8 +365,8 @@ bool parseInstrumentFile(const std::string& filename, InstrumentDOM& dom, LogFun res &= attrcpy(dom.samples.back().position, sample, "position", logger, filename, true); // Clamp to [0; 1] range. - dom.samples.back().position = - std::min(1.0, std::max(dom.samples.back().position, 0.0)); + //dom.samples.back().position = + // std::min(1.0, std::max(dom.samples.back().position, 0.0)); dom.samples.back().normalized = false; // optional - defaults to false res &= attrcpy(dom.samples.back().normalized, sample, "normalized", 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..85624ca 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -32,8 +32,7 @@ #include <cstring> #include <mutex> -#include <event.h> -#include <audiotypes.h> +#include "audiotypes.h" #include <config.h> #include <hugin.hpp> @@ -312,7 +311,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) @@ -392,7 +391,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 5780cc9..bf2b712 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 00374d4..29c4ac5 100644 --- a/src/inputprocessor.cc +++ b/src/inputprocessor.cc @@ -37,7 +37,7 @@ #include "staminafilter.h" #include "velocityfilter.h" #include "positionfilter.h" - +#include <iostream> #include "cpp11fix.h" class VelocityStorer @@ -141,20 +141,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() == "") @@ -177,16 +175,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()) { @@ -204,7 +201,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); } } } @@ -247,17 +244,20 @@ 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); + + const auto power_range = instr->getPowers(event.position); + const auto power_span = power_range.max - power_range.min; + const auto note_power = power_range.min + event.velocity * power_span; + + const auto position_range = instr->getPositionRange(); + const auto position_span = position_range.max - position_range.min; + const auto note_position = position_range.min + event.position * position_span; - auto const power_max = instr->getMaxPower(); - auto const power_min = instr->getMinPower(); - float const power_span = power_max - power_min; - float const instrument_level = power_min + event.velocity*power_span; - // FIXME: bad variable naming of parameters - const auto sample = instr->sample(instrument_level, event.position, event.offset + pos); + const auto sample = instr->sample(note_power, power_span, note_position, position_span, event.offset + pos); if(sample == nullptr) { @@ -269,7 +269,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 @@ -359,7 +359,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); } } } @@ -400,7 +400,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); @@ -421,7 +421,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; @@ -435,7 +435,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) { @@ -459,6 +458,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/instrument.cc b/src/instrument.cc index ac6aa28..af96ab6 100644 --- a/src/instrument.cc +++ b/src/instrument.cc @@ -29,6 +29,7 @@ #include <hugin.hpp> #include "sample.h" +#include "position_power.h" Instrument::Instrument(Settings& settings, Random& rand) : settings(settings) @@ -36,7 +37,6 @@ Instrument::Instrument(Settings& settings, Random& rand) , sample_selection(settings, rand, powerlist) { DEBUG(instrument, "new %p\n", this); - mod = 1.0; lastpos = 0; magic = this; @@ -55,17 +55,19 @@ bool Instrument::isValid() const } // FIXME: very bad variable naming of parameters -const Sample* Instrument::sample(level_t level, float position , std::size_t pos) +const Sample* Instrument::sample(float power, float instrument_power_range, float position, + float instrument_position_range, std::size_t pos) { if(version >= VersionStr("2.0")) { // Version 2.0 - return sample_selection.get(level * mod, position, pos); + return sample_selection.get(power, instrument_power_range, + position, instrument_position_range, pos); } else { // Version 1.0 - auto s = samples.get(level * mod); + auto s = samples.get(power); if(s.size() == 0) { return nullptr; @@ -93,6 +95,18 @@ void Instrument::finalise() powerlist.finalise(); sample_selection.finalise(); + + position_range.min = std::numeric_limits<double>::max(); + position_range.max = std::numeric_limits<double>::min(); + if(samplelist.empty()) + { + position_range = {0,1}; + } + for(const auto& sample : samplelist) + { + position_range.min = std::min(sample->getPosition(), position_range.min); + position_range.max = std::max(sample->getPosition(), position_range.max); + } } } @@ -130,28 +144,21 @@ std::size_t Instrument::getNumberOfFiles() const return audiofiles.size(); } -float Instrument::getMaxPower() const +Instrument::PowerRange Instrument::getPowers(float position) const { if(version >= VersionStr("2.0")) { - return powerlist.getMaxPower(); + return positionPower(samplelist, position); } else { - return 1.0f; + return { 0.0f, 1.0f }; } } -float Instrument::getMinPower() const +Instrument::PowerRange Instrument::getPositionRange() const { - if(version >= VersionStr("2.0")) - { - return powerlist.getMinPower(); - } - else - { - return 0.0f; - } + return position_range; } const std::vector<Choke>& Instrument::getChokes() diff --git a/src/instrument.h b/src/instrument.h index 89918de..35f4e5b 100644 --- a/src/instrument.h +++ b/src/instrument.h @@ -50,7 +50,8 @@ public: ~Instrument(); // FIXME: variable naming - const Sample* sample(level_t level, float position, std::size_t pos); + const Sample* sample(float power, float instrument_power_range, float position, + float instrument_position_range, std::size_t pos); std::size_t getID() const; const std::string& getName() const; @@ -68,8 +69,13 @@ public: //! Get the number of audio files (as in single channel) in this instrument. std::size_t getNumberOfFiles() const; - float getMaxPower() const; - float getMinPower() const; + struct PowerRange + { + double min; + double max; + }; + PowerRange getPowers(float position) const; + PowerRange getPositionRange() const; const std::vector<Choke>& getChokes(); @@ -98,12 +104,12 @@ private: std::deque<InstrumentChannel> instrument_channels; size_t lastpos; - float mod; Settings& settings; Random& rand; PowerList powerlist; std::vector<Choke> chokes; SampleSelection sample_selection; + PowerRange position_range{}; }; using Instruments = std::vector<std::unique_ptr<Instrument>>; 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/position_power.cc b/src/position_power.cc new file mode 100644 index 0000000..0dc369b --- /dev/null +++ b/src/position_power.cc @@ -0,0 +1,99 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + * position_power.cc + * + * Wed Jul 24 15:05:27 CEST 2024 + * Copyright 2024 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * 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 "position_power.h" + +#include "sample.h" +#include "instrument.h" + +#include <set> +#include <algorithm> + +Instrument::PowerRange positionPower(const std::vector<Sample*>& samplelist, double position) +{ + if(samplelist.empty()) + { + return {0.0, 1.0}; + } + + struct PosPower + { + double position; + double power; + Sample* sample; + }; + auto dist_cmp = + [position](const PosPower& a, const PosPower& b) + { + auto position_delta = + std::abs(a.position - position) - std::abs(b.position - position); + if(position_delta != 0) + { + return position_delta < 0.0; + } + return a.sample < b.sample; + }; + std::set<PosPower, decltype(dist_cmp)> sorted_samples(dist_cmp); + + std::for_each(samplelist.begin(), samplelist.end(), + [&](Sample* s) + { + sorted_samples.insert({s->getPosition(), s->getPower(), s}); + }); + + // Find the smallest, closest set in terms of delta-position against the note position + // and find the contained power range. + double power_min{std::numeric_limits<double>::max()}; + double power_max{std::numeric_limits<double>::min()}; + auto sample_iter = sorted_samples.begin(); + auto final_position_boundary = sample_iter->position; + for(std::size_t i = 0; i < std::max(sorted_samples.size() / 4, std::size_t(1)); ++i) + { + auto power = sample_iter->power; + final_position_boundary = sample_iter->position; + power_min = std::min(power_min, power); + power_max = std::max(power_max, power); + ++sample_iter; + } + + // Include upcoming samples from the list as long as their distances are contained in + // the final position range. + while(sample_iter != sorted_samples.end()) + { + if(sample_iter->position != final_position_boundary) + { + // Position has left the range - and since the list is sorted; stop. + break; + } + + auto power = sample_iter->power; + power_min = std::min(power_min, power); + power_max = std::max(power_max, power); + ++sample_iter; + } + + return {power_min, power_max}; +} diff --git a/src/position_power.h b/src/position_power.h new file mode 100644 index 0000000..9b92a4f --- /dev/null +++ b/src/position_power.h @@ -0,0 +1,87 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + * position_power.h + * + * Wed Jul 24 15:05:26 CEST 2024 + * Copyright 2024 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * 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 "instrument.h" + +#include <vector> + +class Sample; + +//! +//! Consider samples in the samplelist as a two dimensional "point cloud" - each +//! also pointing to sample data (which is not used here): +//! +//! (vel) +//! S_v +//! max ^ +//! |x x +//! | x x x +//! | x x +//! | x x +//! | x x x +//! min |________________> S_p (pos) +//! center rim +//! +//! N: is the total number of samples +//! +//! S, is a specific sample +//! S_v, is the sample's velocity +//! S_p, is the sample's position +//! +//! I_v, is the input note velocity +//! I_p, is the input note position +//! +//! ----- +//! +//! Define the range R with width R_w around I_p, such that at least N/4 samples are +//! included (note the count N/4 probably needs narrowing): +//! +//! (vel) +//! S_v +//! max ^ +//! |x x +//! | x . +. x +//! | . + . x +//! | x. . x +//! | x . +.x +//! min |____._____._____> S_p (pos) +//! center . ^ . rim +//! . I_p . +//! { R } +//! x is a sample that is not included in the set, + is a sample that is. +//! +//! Now for the range R, find the R_max velocity and the R_min velocity. +//! Use these as the boundaries for the velocity [0; 1] range. +//! +//! If no position information is available, the range will include all samples in +//! the range, because all have the default value 0. +//! This mimics perfectly the behaviour we have today. +//! +//! \param samplelist is the search space, \param position is the search origo (S_p) +//! \returns a tuple {R_min, R_max}, which defaults to {0, 1} if the samplelist is empty +Instrument::PowerRange positionPower(const std::vector<Sample*>& samplelist, double position); 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/sample_selection.cc b/src/sample_selection.cc index eb13e55..5c19ae1 100644 --- a/src/sample_selection.cc +++ b/src/sample_selection.cc @@ -33,6 +33,7 @@ #include "settings.h" #include <algorithm> +#include <iostream> namespace { @@ -45,7 +46,9 @@ float pow2(float f) } // end anonymous namespace SampleSelection::SampleSelection(Settings& settings, Random& rand, const PowerList& powerlist) - : settings(settings), rand(rand), powerlist(powerlist) + : settings(settings) + , rand(rand) + , powerlist(powerlist) { } @@ -56,7 +59,8 @@ void SampleSelection::finalise() // FIXME: For the position, weird hacks via the powerlist are necessary. Refactor! // FIXME: bad variable naming -const Sample* SampleSelection::get(level_t level, float position, std::size_t pos) +const Sample* SampleSelection::get(float power, float instrument_power_span, + float position, float instrument_positon_span, std::size_t pos) { const auto& samples = powerlist.getPowerListItems(); if(!samples.size()) @@ -73,34 +77,39 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po float closepos_opt = 0.; float random_opt = 0.; float diverse_opt = 0.; - + std::cout << "Input position: " << position << " power: " << power << "\n"; // Note the magic values in front of the settings factors. const float f_close = 4.*settings.sample_selection_f_close.load(); - const float f_position = 1000.*settings.sample_selection_f_position.load(); // FIXME: huge factor for now + const float f_position = 4.*settings.sample_selection_f_position.load(); const float f_diverse = (1./2.)*settings.sample_selection_f_diverse.load(); const float f_random = (1./3.)*settings.sample_selection_f_random.load(); - float power_range = powerlist.getMaxPower() - powerlist.getMinPower(); - // If all power values are the same then power_range is invalid but we want + // If all power values are the same then instrument_power_span is invalid but we want // to avoid division by zero. - if (power_range == 0.) { power_range = 1.0; } + if (instrument_power_span == 0.) + { + instrument_power_span = 1.0; + } +#if 0 // start with most promising power value and then stop when reaching far values // which cannot become opt anymore - auto closest_it = std::lower_bound(samples.begin(), samples.end(), level); + auto closest_it = std::lower_bound(samples.begin(), samples.end(), power); std::size_t up_index = std::distance(samples.begin(), closest_it); std::size_t down_index = (up_index == 0 ? 0 : up_index - 1); float up_value_lb; - if (up_index < samples.size()) { - auto const close_up = (samples[up_index].power-level)/power_range; + if (up_index < samples.size()) + { + auto const close_up = (samples[up_index].power-power)/instrument_power_span; up_value_lb = f_close*pow2(close_up); } - else { + else + { --up_index; up_value_lb = std::numeric_limits<float>::max(); } - auto const close_down = (samples[down_index].power-level)/power_range; + auto const close_down = (samples[down_index].power-power)/instrument_power_span; float down_value_lb = (up_index != 0 ? f_close*pow2(close_down) : std::numeric_limits<float>::max()); std::size_t count = 0; @@ -117,7 +126,7 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po if (up_index != samples.size()-1) { ++up_index; - up_value_lb = f_close*pow2((samples[up_index].power-level)/power_range); + up_value_lb = f_close*pow2((samples[up_index].power-power)/instrument_power_span); } else { @@ -130,7 +139,7 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po if (down_index != 0) { --down_index; - down_value_lb = f_close*pow2((samples[down_index].power-level)/power_range); + down_value_lb = f_close*pow2((samples[down_index].power-power)/instrument_power_span); } else { @@ -139,9 +148,9 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po } auto random = rand.floatInRange(0.,1.); - auto close = (samples[current_index].power - level)/power_range; + auto close = (samples[current_index].power - power)/instrument_power_span; auto diverse = 1./(1. + (float)(pos - last[current_index])/settings.samplerate); - auto closepos = samples[current_index].sample->getPosition() - position; + auto closepos = (samples[current_index].sample->getPosition() - position) / instrument_positon_span; // note that the value below for close and closepos is actually the weighted squared l2 distance in 2d auto value = f_close*pow2(close) + f_position*pow2(closepos) + f_diverse*diverse + f_random*random; @@ -159,6 +168,30 @@ const Sample* SampleSelection::get(level_t level, float position, std::size_t po ++count; } while (up_value_lb <= value_opt || down_value_lb <= value_opt); +#else + for(std::size_t current_index = 0; current_index < samples.size(); ++current_index) + { + auto random = rand.floatInRange(0.,1.); + auto close = (samples[current_index].power - power)/instrument_power_span; + auto diverse = 1./(1. + (float)(pos - last[current_index])/settings.samplerate); + auto closepos = (samples[current_index].sample->getPosition() - position) / instrument_positon_span; + // note that the value below for close and closepos is actually the weighted squared l2 distance in 2d + auto value = f_close*pow2(close) + f_position*pow2(closepos) + f_diverse*diverse + f_random*random; + + if (value < value_opt) + { + index_opt = current_index; + power_opt = samples[current_index].power; + pos_opt = samples[current_index].sample->getPosition(); + value_opt = value; + random_opt = random; + close_opt = close; + diverse_opt = diverse; + closepos_opt = closepos; + } + } + int count{}; // not used +#endif DEBUG(rand, "Chose sample with index: %d, value: %f, power: %f, position: %f, random: %f, close: %f, diverse: %f, closepos: %f, count: %d", (int)index_opt, value_opt, power_opt, pos_opt, random_opt, close_opt, diverse_opt, closepos_opt, (int)count); diff --git a/src/sample_selection.h b/src/sample_selection.h index 1f6b290..be93bd8 100644 --- a/src/sample_selection.h +++ b/src/sample_selection.h @@ -40,7 +40,8 @@ public: SampleSelection(Settings& settings, Random& rand, const PowerList& powerlist); void finalise(); - const Sample* get(level_t level, float position, std::size_t pos); + const Sample* get(float power, float instrument_power_span, float position, + float instrument_position_span, std::size_t pos); private: Settings& settings; @@ -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/settings.h b/src/settings.h index 5c2e4ee..074c7bc 100644 --- a/src/settings.h +++ b/src/settings.h @@ -76,9 +76,9 @@ struct Settings static float constexpr velocity_modifier_falloff_default = 0.5f; static float constexpr velocity_modifier_weight_default = 0.25f; static float constexpr velocity_stddev_default = .45f; - static float constexpr position_stddev_default = 0.f; // FIXME: set to something sensible + static float constexpr position_stddev_default = .45f; static float constexpr sample_selection_f_close_default = .85f; - static float constexpr sample_selection_f_position_default = 1.f; + static float constexpr sample_selection_f_position_default = .85f; static float constexpr sample_selection_f_diverse_default = .16f; static float constexpr sample_selection_f_random_default = .07f; Atomic<float> velocity_modifier_falloff{velocity_modifier_falloff_default}; 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..64b2462 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 powermaptest midimappertest positionpowertest 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 \ @@ -350,6 +354,17 @@ midimappertest_SOURCES = \ midimappertest.cc \ uunit/uunit.cc +positionpowertest_CXXFLAGS = \ + -I$(top_srcdir)/test/uunit -DOUTPUT=\"positionpowertest\" \ + $(DEBUG_FLAGS) \ + -I$(top_srcdir)/src +positionpowertest_LDFLAGS = +positionpowertest_SOURCES = \ + $(top_srcdir)/src/sample.cc \ + $(top_srcdir)/src/position_power.cc \ + position_power_test.cc \ + uunit/uunit.cc + RES = \ $(top_srcdir)/test/locale/da.mo 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/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/position_power_test.cc b/test/position_power_test.cc new file mode 100644 index 0000000..bd8906d --- /dev/null +++ b/test/position_power_test.cc @@ -0,0 +1,165 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + * position_power_test.cc + * + * Wed Jul 24 15:24:53 CEST 2024 + * Copyright 2024 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * 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/position_power.h" + +class test_position_powertest + : public uUnit +{ +public: + test_position_powertest() + { + uTEST(test_position_powertest::empty); + uTEST(test_position_powertest::boundary); + } + + void empty() + { + std::vector<Sample*> samplelist; + auto res = positionPower(samplelist, 0); + uASSERT_EQUAL(0.0, res.min); + uASSERT_EQUAL(1.0, res.max); + } + + void boundary() + { + // Sig: nam, pwr, pos + Sample s1_1{{}, 1.1, 1.0}; + Sample s2_1{{}, 2.1, 1.0}; + Sample s3_1{{}, 3.1, 1.0}; + Sample s4_1{{}, 4.1, 1.0}; + Sample s5_1{{}, 5.1, 1.0}; + + Sample s1_2{{}, 1.2, 2.0}; + Sample s2_2{{}, 2.2, 2.0}; + Sample s3_2{{}, 3.2, 2.0}; + Sample s4_2{{}, 4.2, 2.0}; + Sample s5_2{{}, 5.2, 2.0}; + Sample s6_2{{}, 6.2, 2.0}; + Sample s7_2{{}, 7.2, 2.0}; + + Sample s1_3{{}, 1.3, 3.0}; + Sample s2_3{{}, 2.3, 3.0}; + Sample s3_3{{}, 3.3, 3.0}; + Sample s4_3{{}, 4.3, 3.0}; + Sample s5_3{{}, 5.3, 3.0}; + Sample s6_3{{}, 6.3, 3.0}; + Sample s7_3{{}, 7.3, 3.0}; + + { // one [s1_1, s1_1] + std::vector<Sample*> samplelist{&s1_1}; + auto res = positionPower(samplelist, 1.0); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(1.1, res.max); + } + + { // two with same position [s1_1, s2_1] + std::vector<Sample*> samplelist{&s1_1, &s2_1}; + auto res = positionPower(samplelist, 1.0); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(2.1, res.max); + } + + { // two with different position [s1_1, s2_2] + std::vector<Sample*> samplelist{&s1_1, &s2_2}; + auto res = positionPower(samplelist, 1.0); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(1.1, res.max); + } + + { // three [s1, (s2), s3] - one "hidden" inside range + std::vector<Sample*> samplelist{&s1_1, &s2_1, &s3_1}; + auto res = positionPower(samplelist, 1.0); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(3.1, res.max); + } + + { // six [s1, (s2), s3] - one "hidden" inside range and three ouside boundary + std::vector<Sample*> samplelist{&s1_1, &s2_1, &s3_1, &s1_2, &s2_2, &s3_2}; + auto res = positionPower(samplelist, 1.0); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(3.1, res.max); + } + + { // six [s1, (s2), s3] - one "hidden" inside range and three ouside boundary + std::vector<Sample*> samplelist{&s1_1, &s2_1, &s3_1, &s1_2, &s2_2, &s3_2}; + auto res = positionPower(samplelist, 2.0); + uASSERT_EQUAL(1.2, res.min); + uASSERT_EQUAL(3.2, res.max); + } + + { // again, six in two position groups (1 and 2), lower three is the closest to 1.49 + std::vector<Sample*> samplelist{&s1_1, &s2_1, &s3_1, &s1_2, &s2_2, &s3_2}; + auto res = positionPower(samplelist, 1.49); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(3.1, res.max); + } + + { // again, six in two position groups (1 and 2), upper three is the closest to 1.51 + std::vector<Sample*> samplelist{&s1_1, &s2_1, &s3_1, &s1_2, &s2_2, &s3_2}; + auto res = positionPower(samplelist, 1.51); + uASSERT_EQUAL(1.2, res.min); + uASSERT_EQUAL(3.2, res.max); + } + + { // 8, first one at position the remaining at other position + // 1/4th of the samples are 2, and the second one belongs to group 2, which + // will drag in the rest of group 2 with it + std::vector<Sample*> samplelist{&s1_1, &s1_2, &s2_2, &s3_2, + &s4_2, &s5_2, &s6_2, &s7_2}; + auto res = positionPower(samplelist, 1); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(7.2, res.max); + } + + { // 9, first one at position the remaining at other position + one from group 3 + // at the end which is ignored + // 1/4th of the samples are 2, and the second one belongs to group 2, which + // will drag in the rest of group 2 with it + std::vector<Sample*> samplelist{&s1_1, &s1_2, &s2_2, &s3_2, + &s4_2, &s5_2, &s6_2, &s7_2, &s7_3}; + auto res = positionPower(samplelist, 1); + uASSERT_EQUAL(1.1, res.min); + uASSERT_EQUAL(7.2, res.max); + } + + { // 8, first one from group 1, then 6 from group 2 and finally one from group 3 + // first and last should be ignored - input pos is closest to group 2 + std::vector<Sample*> samplelist{&s1_1, + &s1_2, &s2_2, &s3_2, &s4_2, + &s7_3}; + auto res = positionPower(samplelist, 2.1); + uASSERT_EQUAL(1.2, res.min); + uASSERT_EQUAL(4.2, res.max); + } + + } +}; + +// Registers the fixture into the 'registry' +static test_position_powertest test; 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" |