New upstream version 0.18.1+ds1
authorIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Mon, 30 Aug 2021 13:51:16 +0000 (15:51 +0200)
committerIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Mon, 30 Aug 2021 13:51:16 +0000 (15:51 +0200)
353 files changed:
.clang-format [new file with mode: 0644]
CMakeLists.txt
ChangeLog
Makefile.am [deleted file]
README.md
autogen.sh [deleted file]
configure.ac [deleted file]
extras/com.giadamusic.Giada.desktop [new file with mode: 0644]
extras/com.giadamusic.Giada.metainfo.xml [new file with mode: 0644]
src/core/action.h
src/core/audioBuffer.cpp
src/core/audioBuffer.h
src/core/channels/audioReceiver.cpp
src/core/channels/audioReceiver.h
src/core/channels/channel.cpp
src/core/channels/channel.h
src/core/channels/channelManager.cpp
src/core/channels/channelManager.h
src/core/channels/midiActionRecorder.cpp
src/core/channels/midiActionRecorder.h
src/core/channels/midiController.cpp
src/core/channels/midiController.h
src/core/channels/midiLearner.cpp
src/core/channels/midiLearner.h
src/core/channels/midiLighter.cpp
src/core/channels/midiLighter.h
src/core/channels/midiReceiver.cpp
src/core/channels/midiReceiver.h
src/core/channels/midiSender.cpp
src/core/channels/midiSender.h
src/core/channels/sampleActionRecorder.cpp
src/core/channels/sampleActionRecorder.h
src/core/channels/sampleAdvancer.cpp [new file with mode: 0644]
src/core/channels/sampleAdvancer.h [new file with mode: 0644]
src/core/channels/sampleController.cpp [deleted file]
src/core/channels/sampleController.h [deleted file]
src/core/channels/samplePlayer.cpp
src/core/channels/samplePlayer.h
src/core/channels/sampleReactor.cpp [new file with mode: 0644]
src/core/channels/sampleReactor.h [new file with mode: 0644]
src/core/channels/state.cpp [deleted file]
src/core/channels/state.h [deleted file]
src/core/channels/waveReader.cpp
src/core/channels/waveReader.h
src/core/clock.cpp
src/core/clock.h
src/core/conf.cpp
src/core/conf.h
src/core/const.h
src/core/eventDispatcher.cpp [new file with mode: 0644]
src/core/eventDispatcher.h [new file with mode: 0644]
src/core/graphics.cpp
src/core/graphics.h
src/core/idManager.cpp
src/core/idManager.h
src/core/init.cpp
src/core/init.h
src/core/kernelAudio.cpp
src/core/kernelAudio.h
src/core/kernelMidi.cpp
src/core/kernelMidi.h
src/core/metronome.cpp [new file with mode: 0644]
src/core/metronome.h [new file with mode: 0644]
src/core/midiDispatcher.cpp
src/core/midiDispatcher.h
src/core/midiEvent.cpp
src/core/midiEvent.h
src/core/midiLearnParam.cpp
src/core/midiLearnParam.h
src/core/midiMapConf.cpp
src/core/midiMapConf.h
src/core/mixer.cpp
src/core/mixer.h
src/core/mixerHandler.cpp
src/core/mixerHandler.h
src/core/model/model.cpp
src/core/model/model.h
src/core/model/storage.cpp
src/core/model/storage.h
src/core/model/traits.h [deleted file]
src/core/patch.cpp
src/core/patch.h
src/core/plugins/plugin.cpp
src/core/plugins/plugin.h
src/core/plugins/pluginHost.cpp
src/core/plugins/pluginHost.h
src/core/plugins/pluginManager.cpp
src/core/plugins/pluginManager.h
src/core/plugins/pluginState.cpp
src/core/plugins/pluginState.h
src/core/quantizer.cpp
src/core/quantizer.h
src/core/queue.h
src/core/range.h
src/core/rcuList.h [deleted file]
src/core/recManager.cpp
src/core/recManager.h
src/core/recorder.cpp
src/core/recorder.h
src/core/recorderHandler.cpp
src/core/recorderHandler.h
src/core/resampler.cpp [new file with mode: 0644]
src/core/resampler.h [new file with mode: 0644]
src/core/ringBuffer.h
src/core/sequencer.cpp
src/core/sequencer.h
src/core/swapper.h [new file with mode: 0644]
src/core/types.h
src/core/wave.cpp
src/core/wave.h
src/core/waveFx.cpp
src/core/waveFx.h
src/core/waveManager.cpp
src/core/waveManager.h
src/core/weakAtomic.h [new file with mode: 0644]
src/core/worker.cpp [new file with mode: 0644]
src/core/worker.h [new file with mode: 0644]
src/glue/actionEditor.cpp
src/glue/actionEditor.h
src/glue/channel.cpp
src/glue/channel.h
src/glue/config.cpp [new file with mode: 0644]
src/glue/config.h [new file with mode: 0644]
src/glue/events.cpp
src/glue/events.h
src/glue/io.cpp
src/glue/io.h
src/glue/main.cpp
src/glue/main.h
src/glue/plugin.cpp
src/glue/plugin.h
src/glue/recorder.cpp
src/glue/recorder.h
src/glue/sampleEditor.cpp
src/glue/sampleEditor.h
src/glue/storage.cpp
src/glue/storage.h
src/gui/dialogs/about.cpp
src/gui/dialogs/about.h
src/gui/dialogs/actionEditor/baseActionEditor.cpp
src/gui/dialogs/actionEditor/baseActionEditor.h
src/gui/dialogs/actionEditor/midiActionEditor.cpp
src/gui/dialogs/actionEditor/midiActionEditor.h
src/gui/dialogs/actionEditor/sampleActionEditor.cpp
src/gui/dialogs/actionEditor/sampleActionEditor.h
src/gui/dialogs/beatsInput.cpp
src/gui/dialogs/beatsInput.h
src/gui/dialogs/bpmInput.cpp
src/gui/dialogs/bpmInput.h
src/gui/dialogs/browser/browserBase.cpp
src/gui/dialogs/browser/browserBase.h
src/gui/dialogs/browser/browserDir.cpp
src/gui/dialogs/browser/browserDir.h
src/gui/dialogs/browser/browserLoad.cpp
src/gui/dialogs/browser/browserLoad.h
src/gui/dialogs/browser/browserSave.cpp
src/gui/dialogs/browser/browserSave.h
src/gui/dialogs/channelNameInput.cpp
src/gui/dialogs/channelNameInput.h
src/gui/dialogs/config.cpp
src/gui/dialogs/config.h
src/gui/dialogs/devInfo.cpp [deleted file]
src/gui/dialogs/devInfo.h [deleted file]
src/gui/dialogs/keyGrabber.cpp
src/gui/dialogs/keyGrabber.h
src/gui/dialogs/mainWindow.cpp
src/gui/dialogs/mainWindow.h
src/gui/dialogs/midiIO/midiInputBase.cpp
src/gui/dialogs/midiIO/midiInputBase.h
src/gui/dialogs/midiIO/midiInputChannel.cpp
src/gui/dialogs/midiIO/midiInputChannel.h
src/gui/dialogs/midiIO/midiInputMaster.cpp
src/gui/dialogs/midiIO/midiInputMaster.h
src/gui/dialogs/midiIO/midiOutputBase.cpp
src/gui/dialogs/midiIO/midiOutputBase.h
src/gui/dialogs/midiIO/midiOutputMidiCh.cpp
src/gui/dialogs/midiIO/midiOutputMidiCh.h
src/gui/dialogs/midiIO/midiOutputSampleCh.cpp
src/gui/dialogs/midiIO/midiOutputSampleCh.h
src/gui/dialogs/pluginChooser.cpp
src/gui/dialogs/pluginChooser.h
src/gui/dialogs/pluginList.cpp
src/gui/dialogs/pluginList.h
src/gui/dialogs/pluginWindow.cpp
src/gui/dialogs/pluginWindow.h
src/gui/dialogs/pluginWindowGUI.cpp
src/gui/dialogs/pluginWindowGUI.h
src/gui/dialogs/sampleEditor.cpp
src/gui/dialogs/sampleEditor.h
src/gui/dialogs/warnings.cpp
src/gui/dialogs/warnings.h
src/gui/dialogs/window.cpp
src/gui/dialogs/window.h
src/gui/dispatcher.cpp
src/gui/dispatcher.h
src/gui/drawing.cpp [new file with mode: 0644]
src/gui/drawing.h [new file with mode: 0644]
src/gui/elems/actionEditor/baseAction.cpp
src/gui/elems/actionEditor/baseAction.h
src/gui/elems/actionEditor/baseActionEditor.cpp
src/gui/elems/actionEditor/baseActionEditor.h
src/gui/elems/actionEditor/envelopeEditor.cpp
src/gui/elems/actionEditor/envelopeEditor.h
src/gui/elems/actionEditor/envelopePoint.cpp
src/gui/elems/actionEditor/envelopePoint.h
src/gui/elems/actionEditor/gridTool.cpp
src/gui/elems/actionEditor/gridTool.h
src/gui/elems/actionEditor/noteEditor.cpp
src/gui/elems/actionEditor/noteEditor.h
src/gui/elems/actionEditor/pianoItem.cpp
src/gui/elems/actionEditor/pianoItem.h
src/gui/elems/actionEditor/pianoRoll.cpp
src/gui/elems/actionEditor/pianoRoll.h
src/gui/elems/actionEditor/sampleAction.cpp
src/gui/elems/actionEditor/sampleAction.h
src/gui/elems/actionEditor/sampleActionEditor.cpp
src/gui/elems/actionEditor/sampleActionEditor.h
src/gui/elems/actionEditor/velocityEditor.cpp
src/gui/elems/actionEditor/velocityEditor.h
src/gui/elems/basics/box.cpp
src/gui/elems/basics/box.h
src/gui/elems/basics/boxtypes.cpp
src/gui/elems/basics/boxtypes.h
src/gui/elems/basics/button.cpp
src/gui/elems/basics/button.h
src/gui/elems/basics/check.cpp
src/gui/elems/basics/check.h
src/gui/elems/basics/choice.cpp
src/gui/elems/basics/choice.h
src/gui/elems/basics/dial.cpp
src/gui/elems/basics/dial.h
src/gui/elems/basics/group.cpp
src/gui/elems/basics/group.h
src/gui/elems/basics/input.cpp
src/gui/elems/basics/input.h
src/gui/elems/basics/liquidScroll.cpp
src/gui/elems/basics/liquidScroll.h
src/gui/elems/basics/pack.cpp
src/gui/elems/basics/pack.h
src/gui/elems/basics/progress.cpp
src/gui/elems/basics/progress.h
src/gui/elems/basics/radio.cpp [deleted file]
src/gui/elems/basics/radio.h [deleted file]
src/gui/elems/basics/resizerBar.cpp
src/gui/elems/basics/resizerBar.h
src/gui/elems/basics/scroll.cpp
src/gui/elems/basics/scroll.h
src/gui/elems/basics/scrollPack.cpp
src/gui/elems/basics/scrollPack.h
src/gui/elems/basics/slider.cpp
src/gui/elems/basics/slider.h
src/gui/elems/basics/statusButton.cpp
src/gui/elems/basics/statusButton.h
src/gui/elems/browser.cpp
src/gui/elems/browser.h
src/gui/elems/config/tabAudio.cpp
src/gui/elems/config/tabAudio.h
src/gui/elems/config/tabBehaviors.cpp
src/gui/elems/config/tabBehaviors.h
src/gui/elems/config/tabMidi.cpp
src/gui/elems/config/tabMidi.h
src/gui/elems/config/tabMisc.cpp
src/gui/elems/config/tabMisc.h
src/gui/elems/config/tabPlugins.cpp
src/gui/elems/config/tabPlugins.h
src/gui/elems/mainWindow/beatMeter.cpp [deleted file]
src/gui/elems/mainWindow/beatMeter.h [deleted file]
src/gui/elems/mainWindow/keyboard/channel.cpp
src/gui/elems/mainWindow/keyboard/channel.h
src/gui/elems/mainWindow/keyboard/channelButton.cpp
src/gui/elems/mainWindow/keyboard/channelButton.h
src/gui/elems/mainWindow/keyboard/channelMode.cpp
src/gui/elems/mainWindow/keyboard/channelMode.h
src/gui/elems/mainWindow/keyboard/channelStatus.cpp
src/gui/elems/mainWindow/keyboard/channelStatus.h
src/gui/elems/mainWindow/keyboard/column.cpp
src/gui/elems/mainWindow/keyboard/column.h
src/gui/elems/mainWindow/keyboard/keyboard.cpp
src/gui/elems/mainWindow/keyboard/keyboard.h
src/gui/elems/mainWindow/keyboard/midiChannel.cpp
src/gui/elems/mainWindow/keyboard/midiChannel.h
src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp
src/gui/elems/mainWindow/keyboard/midiChannelButton.h
src/gui/elems/mainWindow/keyboard/sampleChannel.cpp
src/gui/elems/mainWindow/keyboard/sampleChannel.h
src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp
src/gui/elems/mainWindow/keyboard/sampleChannelButton.h
src/gui/elems/mainWindow/mainIO.cpp
src/gui/elems/mainWindow/mainIO.h
src/gui/elems/mainWindow/mainMenu.cpp
src/gui/elems/mainWindow/mainMenu.h
src/gui/elems/mainWindow/mainTimer.cpp
src/gui/elems/mainWindow/mainTimer.h
src/gui/elems/mainWindow/mainTransport.cpp
src/gui/elems/mainWindow/mainTransport.h
src/gui/elems/mainWindow/sequencer.cpp [new file with mode: 0644]
src/gui/elems/mainWindow/sequencer.h [new file with mode: 0644]
src/gui/elems/midiIO/midiLearner.cpp
src/gui/elems/midiIO/midiLearner.h
src/gui/elems/midiIO/midiLearnerPack.cpp
src/gui/elems/midiIO/midiLearnerPack.h
src/gui/elems/plugin/pluginBrowser.cpp
src/gui/elems/plugin/pluginBrowser.h
src/gui/elems/plugin/pluginElement.cpp
src/gui/elems/plugin/pluginElement.h
src/gui/elems/plugin/pluginParameter.cpp
src/gui/elems/plugin/pluginParameter.h
src/gui/elems/sampleEditor/boostTool.cpp
src/gui/elems/sampleEditor/boostTool.h
src/gui/elems/sampleEditor/panTool.cpp
src/gui/elems/sampleEditor/panTool.h
src/gui/elems/sampleEditor/pitchTool.cpp
src/gui/elems/sampleEditor/pitchTool.h
src/gui/elems/sampleEditor/rangeTool.cpp
src/gui/elems/sampleEditor/rangeTool.h
src/gui/elems/sampleEditor/shiftTool.cpp
src/gui/elems/sampleEditor/shiftTool.h
src/gui/elems/sampleEditor/volumeTool.cpp
src/gui/elems/sampleEditor/volumeTool.h
src/gui/elems/sampleEditor/waveTools.cpp
src/gui/elems/sampleEditor/waveTools.h
src/gui/elems/sampleEditor/waveform.cpp
src/gui/elems/sampleEditor/waveform.h
src/gui/elems/soundMeter.cpp
src/gui/elems/soundMeter.h
src/gui/model.cpp
src/gui/model.h
src/gui/updater.cpp
src/gui/updater.h
src/main.cpp
src/utils/cocoa.h
src/utils/fs.cpp
src/utils/fs.h
src/utils/gui.cpp
src/utils/gui.h
src/utils/log.cpp
src/utils/log.h
src/utils/math.cpp
src/utils/math.h
src/utils/string.cpp
src/utils/string.h
src/utils/time.cpp
src/utils/time.h
src/utils/vector.h
src/utils/ver.cpp
src/utils/ver.h
tests/audioBuffer.cpp
tests/rcuList.cpp [deleted file]
tests/recorder.cpp
tests/utils.cpp
tests/wave.cpp
tests/waveFx.cpp
tests/waveManager.cpp

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..463096b
--- /dev/null
@@ -0,0 +1,16 @@
+---
+BasedOnStyle: Microsoft
+AccessModifierOffset: -4
+AlignAfterOpenBracket: 'false'
+AlignConsecutiveAssignments: 'true'
+AlignConsecutiveDeclarations: 'true'
+AllowShortFunctionsOnASingleLine: All
+BreakBeforeBraces: Allman
+BreakConstructorInitializers: BeforeComma
+ColumnLimit: 0
+ConstructorInitializerIndentWidth: '0'
+IndentWrappedFunctionNames: 'false'
+Language: Cpp
+NamespaceIndentation: None
+PointerAlignment: Left
+UseTab: ForIndentation
\ No newline at end of file
index 0a5118bb0d97babe052f0135dd7cee03324d814e..c1571c5815b0d2276a32a51206ed026026f52883 100644 (file)
@@ -33,6 +33,8 @@ project(giada LANGUAGES CXX)
 
 list(APPEND SOURCES
        src/main.cpp
+       src/core/worker.cpp
+       src/core/eventDispatcher.cpp
        src/core/midiDispatcher.cpp
        src/core/midiMapConf.cpp
        src/core/midiEvent.cpp
@@ -42,6 +44,7 @@ list(APPEND SOURCES
        src/core/kernelAudio.cpp
        src/core/mixerHandler.cpp
        src/core/sequencer.cpp
+       src/core/metronome.cpp
        src/core/init.cpp
        src/core/wave.cpp
        src/core/waveFx.cpp
@@ -55,16 +58,17 @@ list(APPEND SOURCES
        src/core/waveManager.cpp
        src/core/recManager.cpp
        src/core/midiLearnParam.cpp
+       src/core/resampler.cpp
        src/core/plugins/pluginHost.cpp
        src/core/plugins/pluginManager.cpp
        src/core/plugins/plugin.cpp
        src/core/plugins/pluginState.cpp
-       src/core/channels/state.cpp
        src/core/channels/sampleActionRecorder.cpp
        src/core/channels/midiActionRecorder.cpp
        src/core/channels/waveReader.cpp
        src/core/channels/midiController.cpp
-       src/core/channels/sampleController.cpp
+       src/core/channels/sampleReactor.cpp
+       src/core/channels/sampleAdvancer.cpp
        src/core/channels/samplePlayer.cpp
        src/core/channels/audioReceiver.cpp
        src/core/channels/midiLighter.cpp
@@ -85,10 +89,12 @@ list(APPEND SOURCES
        src/glue/recorder.cpp
        src/glue/sampleEditor.cpp
        src/glue/actionEditor.cpp
+       src/glue/config.cpp
        src/gui/dialogs/window.cpp
        src/gui/dispatcher.cpp
        src/gui/updater.cpp
        src/gui/model.cpp
+       src/gui/drawing.cpp
        src/gui/dialogs/keyGrabber.cpp
        src/gui/dialogs/about.cpp
        src/gui/dialogs/mainWindow.cpp
@@ -97,7 +103,6 @@ list(APPEND SOURCES
        src/gui/dialogs/bpmInput.cpp
        src/gui/dialogs/channelNameInput.cpp
        src/gui/dialogs/config.cpp
-       src/gui/dialogs/devInfo.cpp
        src/gui/dialogs/pluginList.cpp
        src/gui/dialogs/pluginWindow.cpp
        src/gui/dialogs/sampleEditor.cpp
@@ -146,7 +151,7 @@ list(APPEND SOURCES
        src/gui/elems/mainWindow/mainMenu.cpp
        src/gui/elems/mainWindow/mainTimer.cpp
        src/gui/elems/mainWindow/mainTransport.cpp
-       src/gui/elems/mainWindow/beatMeter.cpp
+       src/gui/elems/mainWindow/sequencer.cpp
        src/gui/elems/mainWindow/keyboard/channelMode.cpp
        src/gui/elems/mainWindow/keyboard/channelButton.cpp
        src/gui/elems/mainWindow/keyboard/channelStatus.cpp
@@ -178,7 +183,6 @@ list(APPEND SOURCES
        src/gui/elems/basics/slider.cpp
        src/gui/elems/basics/progress.cpp
        src/gui/elems/basics/check.cpp
-       src/gui/elems/basics/radio.cpp
        src/utils/log.cpp
        src/utils/time.cpp
        src/utils/math.cpp
@@ -231,6 +235,12 @@ option(WITH_VST2 "Enable VST2 support." OFF)
 option(WITH_VST3 "Enable VST3 support." OFF)
 option(WITH_TESTS "Include the test suite." OFF)
 
+if(DEFINED OS_LINUX)
+       option(WITH_ALSA "Enable ALSA support (Linux only)." ON)
+       option(WITH_PULSE "Enable PulseAudio support (Linux only)." ON)
+       option(WITH_JACK "Enable JACK support (Linux only)." ON)
+endif()
+
 if(WITH_TESTS)
        list(APPEND PREPROCESSOR_DEFS 
                WITH_TESTS
@@ -250,12 +260,25 @@ endif()
 find_package(Threads REQUIRED)
 list(APPEND LIBRARIES ${Threads_LIBRARY})
 
+# pkg-config/pkgconf, required to find some external dependencies on some
+# platforms
+find_package(PkgConfig)
+
 # RtMidi
 
 find_package(RtMidi CONFIG)
 if (RtMidi_FOUND)
        list(APPEND LIBRARIES RtMidi::rtmidi)
-else()
+       message("RtMidi library found in " ${RtMidi_DIR})
+elseif (PkgConfig_FOUND)
+       pkg_check_modules(RtMidi IMPORTED_TARGET rtmidi)
+       if (RtMidi_FOUND)
+               list(APPEND LIBRARIES PkgConfig::RtMidi)
+               message("RtMidi library found")
+       endif()
+endif()
+
+if (NOT RtMidi_FOUND)
        # Fallback to find_library mode (in case rtmidi is too old). 
        find_library(LIBRARY_RTMIDI NAMES rtmidi)
        list(APPEND LIBRARIES ${LIBRARY_RTMIDI})
@@ -269,10 +292,9 @@ else()
 
        find_path(LIBRARY_RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES rtmidi)
        list(APPEND INCLUDE_DIRS ${LIBRARY_RTMIDI_INCLUDE_DIR})
+       message("RtMidi library found in " ${RtMidi_DIR})
 endif()
 
-message("RtMidi library found in " ${RtMidi_DIR})
-
 # FLTK 
 
 set(FLTK_SKIP_FLUID TRUE)  # Don't search for FLTK's fluid
@@ -287,7 +309,15 @@ find_package(SndFile CONFIG)
 if (SndFile_FOUND)
        list(APPEND LIBRARIES SndFile::sndfile)
        message("Libsndfile library found in " ${SndFile_DIR})
-else()
+elseif(PkgConfig_FOUND)
+       pkg_check_modules(SndFile IMPORTED_TARGET sndfile)
+       if (SndFile_FOUND)
+               list(APPEND LIBRARIES PkgConfig::SndFile)
+               message("Libsndfile library found")
+       endif() 
+endif()
+
+if (NOT SndFile_FOUND)
        # Fallback to find_library mode (in case libsndfile is too old). 
        find_library(LIBRARY_SNDFILE NAMES sndfile libsndfile libsndfile-1)
        
@@ -324,13 +354,20 @@ else()
 endif()
 
 # Libsamplerate
-# TODO - new libsamplerate now provides CMake targets. Update it!
 
-find_library(LIBRARY_SAMPLERATE 
-       NAMES samplerate libsamplerate libsamplerate-0 liblibsamplerate-0
-       PATHS ${_VCPKG_ROOT_DIR}/installed/${VCPKG_TARGET_TRIPLET})
-list(APPEND LIBRARIES ${LIBRARY_SAMPLERATE})
-message("Libsamplerate library found in " ${LIBRARY_SAMPLERATE})
+find_package(SampleRate CONFIG)
+if (SampleRate_FOUND)
+       list(APPEND LIBRARIES SampleRate::samplerate)
+       message("Libsndfile library found in " ${SampleRate_DIR})
+else() 
+       # Fallback to find_library mode (in case Libsamplerate is too old). 
+       find_library(LIBRARY_SAMPLERATE 
+           NAMES samplerate libsamplerate libsamplerate-0 liblibsamplerate-0
+           PATHS ${_VCPKG_ROOT_DIR}/installed/${VCPKG_TARGET_TRIPLET}
+               REQUIRED)
+       list(APPEND LIBRARIES ${LIBRARY_SAMPLERATE})
+       message("Libsamplerate library found in " ${LIBRARY_SAMPLERATE})
+endif()
 
 # Catch (if tests enabled)
 
@@ -353,18 +390,22 @@ if(DEFINED OS_LINUX)
        find_library(LIBRARY_PULSE NAMES pulse REQUIRED)
        find_library(LIBRARY_PULSE_SIMPLE NAMES pulse-simple REQUIRED)
        find_library(LIBRARY_FONTCONFIG NAMES fontconfig REQUIRED)
-       find_library(LIBRARY_JACK NAMES jack REQUIRED)
+       pkg_check_modules(JACK REQUIRED jack)
        list(APPEND LIBRARIES
                ${X11_LIBRARIES} ${X11_Xrender_LIB} ${X11_Xft_LIB} ${X11_Xfixes_LIB}
                ${X11_Xinerama_LIB} ${X11_Xcursor_LIB} ${X11_Xpm_LIB} ${LIBRARY_PULSE}
-               ${LIBRARY_PULSE_SIMPLE} ${LIBRARY_FONTCONFIG} ${LIBRARY_JACK}
+               ${LIBRARY_PULSE_SIMPLE} ${LIBRARY_FONTCONFIG} ${JACK_LDFLAGS}
                ${CMAKE_DL_LIBS} ${ALSA_LIBRARIES} pthread stdc++fs)
 
-       list(APPEND PREPROCESSOR_DEFS
-               WITH_AUDIO_JACK
-               __LINUX_ALSA__
-               __LINUX_PULSE__
-               __UNIX_JACK__)
+       if (WITH_ALSA)
+               list(APPEND PREPROCESSOR_DEFS __LINUX_ALSA__)
+       endif()
+       if (WITH_PULSE)
+               list(APPEND PREPROCESSOR_DEFS __LINUX_PULSE__)
+       endif()
+       if (WITH_JACK)
+               list(APPEND PREPROCESSOR_DEFS WITH_AUDIO_JACK __UNIX_JACK__)
+       endif()
 
 elseif(DEFINED OS_WINDOWS)
 
@@ -431,6 +472,7 @@ elseif (DEFINED OS_FREEBSD)
                ${CMAKE_DL_LIBS} pthread)
        
        list(APPEND PREPROCESSOR_DEFS
+               WITH_AUDIO_JACK
                __LINUX_PULSE__
                __UNIX_JACK__)
 
@@ -500,16 +542,33 @@ target_compile_options(giada PRIVATE ${COMPILER_OPTIONS})
 # Install rules
 # ------------------------------------------------------------------------------
 
-install(TARGETS giada DESTINATION ${CMAKE_INSTALL_PREFIX})
+if(DEFINED OS_LINUX)
+       include(GNUInstallDirs)
+       install(TARGETS giada DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+       install(FILES ${CMAKE_SOURCE_DIR}/extras/com.giadamusic.Giada.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
+       install(FILES ${CMAKE_SOURCE_DIR}/extras/com.giadamusic.Giada.metainfo.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
+       install(FILES ${CMAKE_SOURCE_DIR}/extras/giada-logo.svg RENAME com.giadamusic.Giada.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
+endif()
 
 # ------------------------------------------------------------------------------
 # Extra
 # ------------------------------------------------------------------------------
 
-# Enable static linking of the MSVC runtime library on Windows
-# TODO - move this into the 'if windows' conditional (needs smarter list first)
+# TODO - move these into the 'if [OS]' conditionals (needs smarter list first)
 
 if(DEFINED OS_WINDOWS)
+
+       # Enable static linking of the MSVC runtime library on Windows
+       
        set_target_properties(giada PROPERTIES
                MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
-endif()
+
+elseif(DEFINED OS_MACOS)
+
+       # Enable hardened runtime:
+       # https://developer.apple.com/documentation/security/hardened_runtime
+       
+       set_target_properties(giada PROPERTIES
+               XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES)
+
+endif()
\ No newline at end of file
index 6cb225bb1b885c065502f1a91f453fffe24499e5..3665e3b18cc3070dd0119a1c960bacd6564f9e8a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
+0.18.1 --- 2021 . 07 . 25
+- New resampler architecture: allows for changing quality also for live rendering (#288)
+- Gracefully shutdown UI on close to random crashes on quit on Windows 
+- Fix 'one shot channels with actions as loops' mode not working correctly
+- Fix wrong sequencer signals while starting/stopping action recs with JACK (#397)
+- Fix extra dot in unique audio file name generation
+- Fix sample overflow when looping a sample with pitch != 1.0
+- [CMake, Linux] Detect JACK with pkg-config
+- [CMake, Linux] Install Freedesktop files and icon
+- [CMake, Linux] Add configure switches for ALSA, JACK and PulseAudio
+- [macOS] Enable hardened runtime
+
+
+0.18.0 --- 2021 . 05 . 18
+- New 'free loop-length' audio recording mode (#63)
+- Many AudioBuffer improvements
+- Audio configuration panel refactoring
+- KernelAudio improvements and cleanups
+- Relaxed BPM handling when working with JACK
+- Install executable to FHS compliant location (#450)
+- [CI] Don't UPX binaries on macOS (#459)
+- Fix Overdub protection ON by default not working (#460)
+- Fix crash when moving up from a deleted folder (#455)
+
+
+0.17.2 --- 2021 . 03 . 29
+- New double-buffered audio engine
+- Improved audio sample rendering precision
+- Show tooltips when hovering over UI components
+- Add .clang-format file 
+- Removed support for Autotools build system
+- Removed support for old raw patches
+- [CMake] Use find_package command for libsamplerate
+- Improved AudioBuffer move semantics
+- Send time + position information to plug-ins
+- Update JUCE library to version 6.0.7
+- Fix crash when saving project with plug-ins in invalid state
+
+
 0.17.1 --- 2021 . 02 . 01
 - Better CMake dependency management
 - Add CMake install rules (#422)
 - Switch to GitHub Actions for CI and release builds (#440)
-- Remove hardcored 'test' folder in test suite (#432)
+- Remove hardcoded 'test' folder in test suite (#432)
 - Make sure macOS minimum target is set to 10.14 (#444)
 - Fix crash when restarting after setting jack as an audio server (#409, #368)
 - Fix crash when clicking "Cancel" button in Browser dialog (#430)
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644 (file)
index ded463a..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-AUTOMAKE_OPTIONS = foreign
-
-# Define conditional variables -------------------------------------------------
-# WITH_VST, LINUX, WINDOWS and OSX are varibles defined via AM_CONDITIONAL 
-# inside configure.ac.
-
-
-cppFlags = -I$(top_srcdir)/src
-cxxFlags = -std=c++17 -Wall
-ldAdd =
-ldFlags =
-sourcesExtra = 
-sourcesMain = src/main.cpp 
-sourcesCore =                               \
-       src/core/const.h                        \
-       src/core/queue.h                        \
-       src/core/ringBuffer.h                   \
-       src/core/types.h                        \
-       src/core/range.h                        \
-       src/core/action.h                       \
-       src/core/midiDispatcher.h               \
-       src/core/midiDispatcher.cpp             \
-       src/core/midiMapConf.h                  \
-       src/core/midiMapConf.cpp                \
-       src/core/midiEvent.h                    \
-       src/core/midiEvent.cpp                  \
-       src/core/audioBuffer.h                  \
-       src/core/audioBuffer.cpp                \
-       src/core/quantizer.h                    \
-       src/core/quantizer.cpp                  \
-       src/core/conf.h                         \
-       src/core/conf.cpp                       \
-       src/core/kernelAudio.h                  \
-       src/core/kernelAudio.cpp                \
-       src/core/plugins/pluginHost.h                   \
-       src/core/plugins/pluginHost.cpp                 \
-       src/core/plugins/pluginManager.h                \
-       src/core/plugins/pluginManager.cpp              \
-       src/core/plugins/plugin.h                       \
-       src/core/plugins/plugin.cpp                     \
-       src/core/plugins/pluginState.h                       \
-       src/core/plugins/pluginState.cpp                     \
-       src/core/mixerHandler.h                 \
-       src/core/mixerHandler.cpp               \
-       src/core/sequencer.h                    \
-       src/core/sequencer.cpp                  \
-       src/core/init.h                         \
-       src/core/init.cpp                       \
-       src/core/wave.h                         \
-       src/core/wave.cpp                       \
-       src/core/waveFx.h                       \
-       src/core/waveFx.cpp                     \
-       src/core/kernelMidi.h                   \
-       src/core/kernelMidi.cpp                 \
-       src/core/graphics.h                     \
-       src/core/graphics.cpp                   \
-       src/core/midiLearnParam.cpp             \
-       src/core/patch.h                        \
-       src/core/patch.cpp                      \
-       src/core/recorderHandler.h              \
-       src/core/recorderHandler.cpp            \
-       src/core/recorder.h                     \
-       src/core/recorder.cpp                   \
-       src/core/mixer.h                        \
-       src/core/mixer.cpp                      \
-       src/core/clock.h                        \
-       src/core/clock.cpp                      \
-       src/core/waveManager.h                  \
-       src/core/waveManager.cpp                \
-       src/core/recManager.h                   \
-       src/core/recManager.cpp                 \
-       src/core/channels/state.h               \
-       src/core/channels/state.cpp             \
-       src/core/channels/sampleActionRecorder.h      \
-       src/core/channels/sampleActionRecorder.cpp    \
-       src/core/channels/midiActionRecorder.h      \
-       src/core/channels/midiActionRecorder.cpp    \
-       src/core/channels/waveReader.h          \
-       src/core/channels/waveReader.cpp        \
-       src/core/channels/midiController.h      \
-       src/core/channels/midiController.cpp    \
-       src/core/channels/sampleController.h    \
-       src/core/channels/sampleController.cpp  \
-       src/core/channels/samplePlayer.h        \
-       src/core/channels/samplePlayer.cpp      \
-       src/core/channels/audioReceiver.h       \
-       src/core/channels/audioReceiver.cpp     \
-       src/core/channels/midiLighter.h         \
-       src/core/channels/midiLighter.cpp       \
-       src/core/channels/midiLearner.h         \
-       src/core/channels/midiLearner.cpp       \
-       src/core/channels/midiSender.h          \
-       src/core/channels/midiSender.cpp        \
-       src/core/channels/midiReceiver.h        \
-       src/core/channels/midiReceiver.cpp      \
-       src/core/channels/channel.h             \
-       src/core/channels/channel.cpp           \
-       src/core/channels/channelManager.h      \
-       src/core/channels/channelManager.cpp    \
-       src/core/model/model.h                  \
-       src/core/model/model.cpp                \
-       src/core/model/storage.h                \
-       src/core/model/storage.cpp              \
-       src/core/idManager.h                    \
-       src/core/idManager.cpp                  \
-       src/glue/events.h                       \
-       src/glue/events.cpp                     \
-       src/glue/main.h                         \
-       src/glue/main.cpp                       \
-       src/glue/io.h                           \
-       src/glue/io.cpp                         \
-       src/glue/storage.h                      \
-       src/glue/storage.cpp                    \
-       src/glue/channel.h                      \
-       src/glue/channel.cpp                    \
-       src/glue/plugin.h                       \
-       src/glue/plugin.cpp                     \
-       src/glue/recorder.h                     \
-       src/glue/recorder.cpp                   \
-       src/glue/sampleEditor.h                 \
-       src/glue/sampleEditor.cpp               \
-       src/glue/actionEditor.h                 \
-       src/glue/actionEditor.cpp               \
-       src/gui/dialogs/window.h                \
-       src/gui/dialogs/window.cpp              \
-       src/gui/dispatcher.h                    \
-       src/gui/dispatcher.cpp                  \
-       src/gui/updater.h                       \
-       src/gui/updater.cpp                     \
-       src/gui/model.h                         \
-       src/gui/model.cpp                       \
-       src/gui/dialogs/keyGrabber.h            \
-       src/gui/dialogs/keyGrabber.cpp          \
-       src/gui/dialogs/about.h                 \
-       src/gui/dialogs/about.cpp               \
-       src/gui/dialogs/mainWindow.h            \
-       src/gui/dialogs/mainWindow.cpp          \
-       src/gui/dialogs/beatsInput.h            \
-       src/gui/dialogs/beatsInput.cpp          \
-       src/gui/dialogs/warnings.h              \
-       src/gui/dialogs/warnings.cpp            \
-       src/gui/dialogs/bpmInput.h              \
-       src/gui/dialogs/bpmInput.cpp            \
-       src/gui/dialogs/channelNameInput.h      \
-       src/gui/dialogs/channelNameInput.cpp    \
-       src/gui/dialogs/config.h                \
-       src/gui/dialogs/config.cpp              \
-       src/gui/dialogs/devInfo.h               \
-       src/gui/dialogs/devInfo.cpp             \
-       src/gui/dialogs/pluginList.h            \
-       src/gui/dialogs/pluginList.cpp          \
-       src/gui/dialogs/pluginWindow.h          \
-       src/gui/dialogs/pluginWindow.cpp        \
-       src/gui/dialogs/sampleEditor.h          \
-       src/gui/dialogs/sampleEditor.cpp        \
-       src/gui/dialogs/pluginWindowGUI.h       \
-       src/gui/dialogs/pluginWindowGUI.cpp     \
-       src/gui/dialogs/pluginChooser.h         \
-       src/gui/dialogs/pluginChooser.cpp       \
-       src/gui/dialogs/actionEditor/baseActionEditor.h     \
-       src/gui/dialogs/actionEditor/baseActionEditor.cpp   \
-       src/gui/dialogs/actionEditor/sampleActionEditor.h   \
-       src/gui/dialogs/actionEditor/sampleActionEditor.cpp \
-       src/gui/dialogs/actionEditor/midiActionEditor.h     \
-       src/gui/dialogs/actionEditor/midiActionEditor.cpp   \
-       src/gui/dialogs/browser/browserBase.h            \
-       src/gui/dialogs/browser/browserBase.cpp          \
-       src/gui/dialogs/browser/browserDir.h             \
-       src/gui/dialogs/browser/browserDir.cpp           \
-       src/gui/dialogs/browser/browserLoad.h            \
-       src/gui/dialogs/browser/browserLoad.cpp          \
-       src/gui/dialogs/browser/browserSave.h            \
-       src/gui/dialogs/browser/browserSave.cpp          \
-       src/gui/dialogs/midiIO/midiOutputBase.h          \
-       src/gui/dialogs/midiIO/midiOutputBase.cpp        \
-       src/gui/dialogs/midiIO/midiOutputSampleCh.h      \
-       src/gui/dialogs/midiIO/midiOutputSampleCh.cpp    \
-       src/gui/dialogs/midiIO/midiOutputMidiCh.h        \
-       src/gui/dialogs/midiIO/midiOutputMidiCh.cpp      \
-       src/gui/dialogs/midiIO/midiInputBase.h           \
-       src/gui/dialogs/midiIO/midiInputBase.cpp         \
-       src/gui/dialogs/midiIO/midiInputChannel.h        \
-       src/gui/dialogs/midiIO/midiInputChannel.cpp      \
-       src/gui/dialogs/midiIO/midiInputMaster.h         \
-       src/gui/dialogs/midiIO/midiInputMaster.cpp       \
-       src/gui/elems/midiIO/midiLearner.h               \
-       src/gui/elems/midiIO/midiLearner.cpp             \
-       src/gui/elems/midiIO/midiLearnerPack.h           \
-       src/gui/elems/midiIO/midiLearnerPack.cpp         \
-       src/gui/elems/browser.h                              \
-       src/gui/elems/browser.cpp                        \
-       src/gui/elems/soundMeter.h                               \
-       src/gui/elems/soundMeter.cpp                     \
-       src/gui/elems/plugin/pluginBrowser.h                \
-       src/gui/elems/plugin/pluginBrowser.cpp              \
-       src/gui/elems/plugin/pluginParameter.h              \
-       src/gui/elems/plugin/pluginParameter.cpp            \
-       src/gui/elems/plugin/pluginElement.h                \
-       src/gui/elems/plugin/pluginElement.cpp              \
-       src/gui/elems/sampleEditor/waveform.h               \
-       src/gui/elems/sampleEditor/waveform.cpp             \
-       src/gui/elems/sampleEditor/waveTools.h              \
-       src/gui/elems/sampleEditor/waveTools.cpp            \
-       src/gui/elems/sampleEditor/volumeTool.h             \
-       src/gui/elems/sampleEditor/volumeTool.cpp           \
-       src/gui/elems/sampleEditor/boostTool.h              \
-       src/gui/elems/sampleEditor/boostTool.cpp            \
-       src/gui/elems/sampleEditor/panTool.h                \
-       src/gui/elems/sampleEditor/panTool.cpp              \
-       src/gui/elems/sampleEditor/pitchTool.h              \
-       src/gui/elems/sampleEditor/pitchTool.cpp            \
-       src/gui/elems/sampleEditor/rangeTool.h              \
-       src/gui/elems/sampleEditor/rangeTool.cpp            \
-       src/gui/elems/sampleEditor/shiftTool.h              \
-       src/gui/elems/sampleEditor/shiftTool.cpp            \
-       src/gui/elems/actionEditor/baseActionEditor.h       \
-       src/gui/elems/actionEditor/baseActionEditor.cpp     \
-       src/gui/elems/actionEditor/baseAction.h             \
-       src/gui/elems/actionEditor/baseAction.cpp           \
-       src/gui/elems/actionEditor/envelopeEditor.h         \
-       src/gui/elems/actionEditor/envelopeEditor.cpp       \
-       src/gui/elems/actionEditor/velocityEditor.h         \
-       src/gui/elems/actionEditor/velocityEditor.cpp       \
-       src/gui/elems/actionEditor/envelopePoint.h          \
-       src/gui/elems/actionEditor/envelopePoint.cpp        \
-       src/gui/elems/actionEditor/pianoRoll.h              \
-       src/gui/elems/actionEditor/pianoRoll.cpp            \
-       src/gui/elems/actionEditor/noteEditor.h                 \
-       src/gui/elems/actionEditor/noteEditor.cpp           \
-       src/gui/elems/actionEditor/pianoItem.h              \
-       src/gui/elems/actionEditor/pianoItem.cpp            \
-       src/gui/elems/actionEditor/sampleActionEditor.h           \
-       src/gui/elems/actionEditor/sampleActionEditor.cpp         \
-       src/gui/elems/actionEditor/sampleAction.h                 \
-       src/gui/elems/actionEditor/sampleAction.cpp               \
-       src/gui/elems/actionEditor/gridTool.h               \
-       src/gui/elems/actionEditor/gridTool.cpp             \
-       src/gui/elems/mainWindow/mainIO.h          \
-       src/gui/elems/mainWindow/mainIO.cpp        \
-       src/gui/elems/mainWindow/mainMenu.h        \
-       src/gui/elems/mainWindow/mainMenu.cpp      \
-       src/gui/elems/mainWindow/mainTimer.h       \
-       src/gui/elems/mainWindow/mainTimer.cpp     \
-       src/gui/elems/mainWindow/mainTransport.h   \
-       src/gui/elems/mainWindow/mainTransport.cpp \
-       src/gui/elems/mainWindow/beatMeter.h       \
-       src/gui/elems/mainWindow/beatMeter.cpp     \
-       src/gui/elems/mainWindow/keyboard/channelMode.h           \
-       src/gui/elems/mainWindow/keyboard/channelMode.cpp         \
-       src/gui/elems/mainWindow/keyboard/channelButton.h         \
-       src/gui/elems/mainWindow/keyboard/channelButton.cpp       \
-       src/gui/elems/mainWindow/keyboard/channelStatus.h         \
-       src/gui/elems/mainWindow/keyboard/channelStatus.cpp       \
-       src/gui/elems/mainWindow/keyboard/keyboard.h              \
-       src/gui/elems/mainWindow/keyboard/keyboard.cpp            \
-       src/gui/elems/mainWindow/keyboard/column.h                \
-       src/gui/elems/mainWindow/keyboard/column.cpp              \
-       src/gui/elems/mainWindow/keyboard/sampleChannel.h         \
-       src/gui/elems/mainWindow/keyboard/sampleChannel.cpp       \
-       src/gui/elems/mainWindow/keyboard/midiChannel.h           \
-       src/gui/elems/mainWindow/keyboard/midiChannel.cpp         \
-       src/gui/elems/mainWindow/keyboard/channel.h               \
-       src/gui/elems/mainWindow/keyboard/channel.cpp             \
-       src/gui/elems/mainWindow/keyboard/sampleChannelButton.h   \
-       src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp \
-       src/gui/elems/mainWindow/keyboard/midiChannelButton.h     \
-       src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp   \
-       src/gui/elems/config/tabMisc.h         \
-       src/gui/elems/config/tabMisc.cpp       \
-       src/gui/elems/config/tabMidi.h         \
-       src/gui/elems/config/tabMidi.cpp       \
-       src/gui/elems/config/tabAudio.h        \
-       src/gui/elems/config/tabAudio.cpp      \
-       src/gui/elems/config/tabBehaviors.h    \
-       src/gui/elems/config/tabBehaviors.cpp  \
-       src/gui/elems/config/tabPlugins.h      \
-       src/gui/elems/config/tabPlugins.cpp    \
-       src/gui/elems/basics/scroll.h          \
-       src/gui/elems/basics/scroll.cpp        \
-       src/gui/elems/basics/pack.h            \
-       src/gui/elems/basics/pack.cpp          \
-       src/gui/elems/basics/group.h           \
-       src/gui/elems/basics/group.cpp         \
-       src/gui/elems/basics/scrollPack.h      \
-       src/gui/elems/basics/scrollPack.cpp    \
-       src/gui/elems/basics/boxtypes.h        \
-       src/gui/elems/basics/boxtypes.cpp      \
-       src/gui/elems/basics/statusButton.h    \
-       src/gui/elems/basics/statusButton.cpp  \
-       src/gui/elems/basics/button.h          \
-       src/gui/elems/basics/button.cpp        \
-       src/gui/elems/basics/resizerBar.h      \
-       src/gui/elems/basics/resizerBar.cpp    \
-       src/gui/elems/basics/input.h           \
-       src/gui/elems/basics/input.cpp         \
-       src/gui/elems/basics/liquidScroll.h    \
-       src/gui/elems/basics/liquidScroll.cpp  \
-       src/gui/elems/basics/choice.h          \
-       src/gui/elems/basics/choice.cpp        \
-       src/gui/elems/basics/dial.h            \
-       src/gui/elems/basics/dial.cpp          \
-       src/gui/elems/basics/box.h             \
-       src/gui/elems/basics/box.cpp           \
-       src/gui/elems/basics/slider.h          \
-       src/gui/elems/basics/slider.cpp        \
-       src/gui/elems/basics/progress.h        \
-       src/gui/elems/basics/progress.cpp      \
-       src/gui/elems/basics/check.h           \
-       src/gui/elems/basics/check.cpp         \
-       src/gui/elems/basics/radio.h           \
-       src/gui/elems/basics/radio.cpp         \
-       src/utils/log.h                        \
-       src/utils/log.cpp                      \
-       src/utils/time.h                       \
-       src/utils/time.cpp                     \
-       src/utils/math.h                       \
-       src/utils/math.cpp                     \
-       src/utils/gui.h                        \
-       src/utils/gui.cpp                      \
-       src/utils/gvector.h                    \
-       src/utils/fs.h                         \
-       src/utils/fs.cpp                       \
-       src/utils/vector.h                     \
-       src/utils/ver.h                        \
-       src/utils/ver.cpp                      \
-       src/utils/string.h                     \
-       src/utils/string.cpp                   \
-       src/deps/rtaudio/RtAudio.h             \
-       src/deps/rtaudio/RtAudio.cpp
-sourcesTests =                   \
-       tests/main.cpp               \
-       tests/rcuList.cpp            \
-       tests/wave.cpp               \
-       tests/waveManager.cpp        \
-       tests/utils.cpp              \
-       tests/recorder.cpp           \
-       tests/waveFx.cpp             \
-       tests/audioBuffer.cpp
-if WITH_VST
-
-sourcesExtra += \
-       src/deps/juce/modules/juce_audio_basics/juce_audio_basics.cpp         \
-       src/deps/juce/modules/juce_audio_processors/juce_audio_processors.cpp \
-       src/deps/juce/modules/juce_core/juce_core.cpp                         \
-       src/deps/juce/modules/juce_data_structures/juce_data_structures.cpp   \
-       src/deps/juce/modules/juce_events/juce_events.cpp                     \
-       src/deps/juce/modules/juce_graphics/juce_graphics.cpp                 \
-       src/deps/juce/modules/juce_gui_basics/juce_gui_basics.cpp             \
-       src/deps/juce/modules/juce_gui_extra/juce_gui_extra.cpp
-
-cppFlags += \
-       -I$(top_srcdir)/src/deps/juce/modules      \
-       -I$(top_srcdir)/src/deps/vst               \
-       -I/usr/include                             \
-       -I/usr/include/freetype2                   \
-       -DJUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1   \
-       -DJUCE_STANDALONE_APPLICATION=1            \
-       -DJUCE_PLUGINHOST_VST=1                    \
-       -DJUCE_PLUGINHOST_VST3=0                   \
-       -DJUCE_PLUGINHOST_AU=0                     \
-       -DJUCE_WEB_BROWSER=0 
-
-endif
-
-if !WITH_SYSTEM_CATCH
-
-cppFlags += -I$(top_srcdir)/tests/catch2/single_include
-
-endif
-
-if WINDOWS
-
-sourcesExtra += \
-       src/deps/rtaudio/include/asio.h                    \
-       src/deps/rtaudio/include/asio.cpp                  \
-       src/deps/rtaudio/include/asiolist.h                \
-       src/deps/rtaudio/include/asiolist.cpp              \
-       src/deps/rtaudio/include/asiodrivers.h             \
-       src/deps/rtaudio/include/asiodrivers.cpp           \
-       src/deps/rtaudio/include/iasiothiscallresolver.h   \
-       src/deps/rtaudio/include/iasiothiscallresolver.cpp \
-       resource.rc
-
-cppFlags += \
-       -I$(top_srcdir)/src/deps/rtaudio/include \
-       -D__WINDOWS_ASIO__                           \
-       -D__WINDOWS_WASAPI__                         \
-       -D__WINDOWS_DS__
-
-ldAdd += -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 -lshell32 -lvfw32 \
-       -lrpcrt4 -luuid -lcomctl32 -lws2_32 -lsndfile -lsamplerate -lrtmidi \
-       -lsetupapi -limm32 -lglu32 -lshell32 -lversion \
-       -lopengl32 -loleaut32 -lshlwapi -lcomdlg32 -lflac -lvorbis -logg -lvorbisenc \
-       -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid
-
-# Generate a GUI application (-mwindows), make the build static (-static).
-ldFlags += -mwindows -static
-
-endif
-
-if LINUX
-
-# Add preprocessor flags to enable ALSA, Pulse and JACK in RtAudio.
-cppFlags += -D__LINUX_ALSA__ -D__LINUX_PULSE__ -D__UNIX_JACK__
-
-ldAdd += -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \
-       -lpthread -ldl -lpulse-simple -lpulse -lsamplerate -lrtmidi \
-       -lfreetype -lfontconfig -lXrender -lXfixes -lXcursor -lXinerama
-
-endif
-
-if FREEBSD
-
-# Add preprocessor flags to enable ALSA, Pulse and JACK in RtAudio.
-cppFlags += -D__LINUX_PULSE__ -D__UNIX_JACK__
-
-ldAdd += -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \
-       -lpthread -lpulse-simple -lpulse -lsamplerate -lrtmidi \
-       -lfreetype
-
-endif
-
-if OSX
-
-sourcesExtra += src/utils/cocoa.mm src/utils/cocoa.h
-
-# Add preprocessor flags to enable CoreAudio in RtAudio.
-cppFlags += -D__MACOSX_CORE__
-
-# -ObjC++: Juce requires to build some Objective C code
-cxxFlags += -ObjC++
-
-ldAdd += -lsndfile -lfltk -lrtmidi -lsamplerate -lm -lpthread \
-       -lFLAC -logg -lvorbis -lvorbisenc -lopus
-
-ldFlags += -framework CoreAudio -framework Cocoa -framework Carbon \
-       -framework CoreMIDI -framework CoreFoundation -framework Accelerate \
-       -framework WebKit -framework QuartzCore -framework IOKit
-
-endif
-
-# make giada -------------------------------------------------------------------
-
-bin_PROGRAMS = giada
-
-giada_SOURCES = $(sourcesCore) $(sourcesExtra) $(sourcesMain)
-giada_CPPFLAGS = $(cppFlags)
-giada_CXXFLAGS = $(cxxFlags)
-giada_LDADD = $(ldAdd)
-giada_LDFLAGS = $(ldFlags)
-
-# Used only under MinGW to compile the resource.rc file (program icon)
-resource.o:
-       windres src/ext/resource.rc -o resource.o
-
-# make check -------------------------------------------------------------------
-
-TESTS = giada_tests
-
-check_PROGRAMS = giada_tests
-giada_tests_SOURCES = $(sourcesCore) $(sourcesExtra) $(sourcesTests)
-giada_tests_CPPFLAGS = $(cppFlags) 
-giada_tests_CPPFLAGS += -DTESTS
-giada_tests_CXXFLAGS = $(cxxFlags)
-giada_tests_LDADD = $(ldAdd)
-giada_tests_LDFLAGS = $(ldFlags)
-
-# make rename ------------------------------------------------------------------
-
-if LINUX
-rename:
-       mv giada giada_lin
-endif
-if WINDOWS
-rename:
-       mv giada giada_win.exe
-endif
-if OSX
-rename:
-       mv giada giada_osx
-endif
index 4d1978c6d8db61a99be8014e8efe21ae0f2a1846..e0859b01a5617581875b2952c816fcf730ef497a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -33,12 +33,12 @@ Giada is an open source, minimalistic and hardcore music production tool. Design
 * ALSA, JACK + Transport, CoreAudio, ASIO and DirectSound full support;
 * unlimited number of channels (optionally controllable via computer keyboard);
 * BPM and beat sync with sample-accurate loop engine;
-* MIDI output support, featuring custom [MIDI lightning messages](https://github.com/monocasual/giada-midimaps);
+* MIDI input and output support, featuring custom [MIDI lightning messages](https://github.com/monocasual/giada-midimaps);
 * super-sleek, built-in Wave Editor for audio samples and Piano Roll editor for MIDI messages;
 * automatic quantizer;
 * portable project storage system, based on super-hackable JSON files;
 * support for all major uncompressed file formats;
-* test-driven development style supported by [Travis CI](https://travis-ci.org/monocasual/giada) and [Catch](https://github.com/philsquared/Catch)
+* test-driven development style supported by [GitHub Actions](https://github.com/monocasual/giada/actions) and [Catch](https://github.com/philsquared/Catch)
 * under a constant stage of development;
 * 100% open-source GPL v3.
 
@@ -49,23 +49,23 @@ Take a look at the COPYING file for further informations.
 
 ## Documentation
 
-Docs are available online on [the official website](https://www.giadamusic.com/documentation-index).
+Documentation is available online in the [user guide page](https://www.giadamusic.com/documentation-index).
+
+An ever-growing collection of tutorials (both text and video) and live demos is available in the [tutorials & media page](https://www.giadamusic.com/media).
 
 Found a typo or a terrible mistake? Feel free to clone the [website repository](https://github.com/monocasual/giada-www) and send us your pull requests.
 
 ## Build Giada from source
 
-We do our best to make the compilation process as simple as possible. You can find all the information in the [official docs page](https://www.giadamusic.com/documentation-compiling-from-source).
-
-Something went wrong? Try our new [Docker image](https://github.com/monocasual/giada-docker) for building and running Giada without hurdles. 
+We do our best to make the compilation process as simple as possible. You can find all the information in the [compiling from source](https://www.giadamusic.com/documentation-compiling-from-source) chapter from the user guide.
 
 ## Bugs, requests and questions for non-developers
 
-Feel free to ask anything on [our end-user forum](https://www.giadamusic.com/forum).
+Feel free to ask anything in the [discussions area](https://github.com/monocasual/giada/discussions).
 
 ## Copyright
 
-Giada is Copyright (C) 2010-2020 by Giovanni A. Zuliani | Monocasual Laboratories
+Giada is Copyright (C) 2010-2021 by Giovanni A. Zuliani | Monocasual Laboratories
 
 Giada - Your Hardcore Loopmachine is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755 (executable)
index d1fea40..0000000
+++ /dev/null
@@ -1,1579 +0,0 @@
-#!/bin/sh
-#                        a u t o g e n . s h
-#
-# Copyright (c) 2005-2009 United States Government as represented by
-# the U.S. Army Research Laboratory.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials provided
-# with the distribution.
-#
-# 3. The name of the author may not be used to endorse or promote
-# products derived from this software without specific prior written
-# permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
-# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-###
-#
-# Script for automatically preparing the sources for compilation by
-# performing the myriad of necessary steps.  The script attempts to
-# detect proper version support, and outputs warnings about particular
-# systems that have autotool peculiarities.
-#
-# Basically, if everything is set up and installed correctly, the
-# script will validate that minimum versions of the GNU Build System
-# tools are installed, account for several common configuration
-# issues, and then simply run autoreconf for you.
-#
-# If autoreconf fails, which can happen for many valid configurations,
-# this script proceeds to run manual preparation steps effectively
-# providing a POSIX shell script (mostly complete) reimplementation of
-# autoreconf.
-#
-# The AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER
-# environment variables and corresponding _OPTIONS variables (e.g.
-# AUTORECONF_OPTIONS) may be used to override the default automatic
-# detection behaviors.  Similarly the _VERSION variables will override
-# the minimum required version numbers.
-#
-# Examples:
-#
-#   To obtain help on usage:
-#     ./autogen.sh --help
-#
-#   To obtain verbose output:
-#     ./autogen.sh --verbose
-#
-#   To skip autoreconf and prepare manually:
-#     AUTORECONF=false ./autogen.sh
-#
-#   To verbosely try running with an older (unsupported) autoconf:
-#     AUTOCONF_VERSION=2.50 ./autogen.sh --verbose
-#
-# Author:
-#   Christopher Sean Morrison <morrison@brlcad.org>
-#
-# Patches:
-#   Sebastian Pipping <sebastian@pipping.org>
-#
-######################################################################
-
-# set to minimum acceptable version of autoconf
-if [ "x$AUTOCONF_VERSION" = "x" ] ; then
-    AUTOCONF_VERSION=2.52
-fi
-# set to minimum acceptable version of automake
-if [ "x$AUTOMAKE_VERSION" = "x" ] ; then
-    AUTOMAKE_VERSION=1.6.0
-fi
-# set to minimum acceptable version of libtool
-if [ "x$LIBTOOL_VERSION" = "x" ] ; then
-    LIBTOOL_VERSION=1.4.2
-fi
-
-
-##################
-# ident function #
-##################
-ident ( ) {
-    # extract copyright from header
-    __copyright="`grep Copyright $AUTOGEN_SH | head -${HEAD_N}1 | awk '{print $4}'`"
-    if [ "x$__copyright" = "x" ] ; then
-       __copyright="`date +%Y`"
-    fi
-
-    # extract version from CVS Id string
-    __id="$Id: autogen.sh 33925 2009-03-01 23:27:06Z brlcad $"
-    __version="`echo $__id | sed 's/.*\([0-9][0-9][0-9][0-9]\)[-\/]\([0-9][0-9]\)[-\/]\([0-9][0-9]\).*/\1\2\3/'`"
-    if [ "x$__version" = "x" ] ; then
-       __version=""
-    fi
-
-    echo "autogen.sh build preparation script by Christopher Sean Morrison"
-    echo "  + config.guess download patch by Sebastian Pipping (2008-12-03)"
-    echo "revised 3-clause BSD-style license, copyright (c) $__copyright"
-    echo "script version $__version, ISO/IEC 9945 POSIX shell script"
-}
-
-
-##################
-# USAGE FUNCTION #
-##################
-usage ( ) {
-    echo "Usage: $AUTOGEN_SH [-h|--help] [-v|--verbose] [-q|--quiet] [-d|--download] [--version]"
-    echo "    --help      Help on $NAME_OF_AUTOGEN usage"
-    echo "    --verbose   Verbose progress output"
-    echo "    --quiet     Quiet suppressed progress output"
-    echo "    --download  Download the latest config.guess from gnulib"
-    echo "    --version   Only perform GNU Build System version checks"
-    echo
-    echo "Description: This script will validate that minimum versions of the"
-    echo "GNU Build System tools are installed and then run autoreconf for you."
-    echo "Should autoreconf fail, manual preparation steps will be run"
-    echo "potentially accounting for several common preparation issues.  The"
-
-    echo "AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER,"
-    echo "PROJECT, & CONFIGURE environment variables and corresponding _OPTIONS"
-    echo "variables (e.g. AUTORECONF_OPTIONS) may be used to override the"
-    echo "default automatic detection behavior."
-    echo
-
-    ident
-
-    return 0
-}
-
-
-##########################
-# VERSION_ERROR FUNCTION #
-##########################
-version_error ( ) {
-    if [ "x$1" = "x" ] ; then
-       echo "INTERNAL ERROR: version_error was not provided a version"
-       exit 1
-    fi
-    if [ "x$2" = "x" ] ; then
-       echo "INTERNAL ERROR: version_error was not provided an application name"
-       exit 1
-    fi
-    $ECHO
-    $ECHO "ERROR:  To prepare the ${PROJECT} build system from scratch,"
-    $ECHO "        at least version $1 of $2 must be installed."
-    $ECHO
-    $ECHO "$NAME_OF_AUTOGEN does not need to be run on the same machine that will"
-    $ECHO "run configure or make.  Either the GNU Autotools will need to be installed"
-    $ECHO "or upgraded on this system, or $NAME_OF_AUTOGEN must be run on the source"
-    $ECHO "code on another system and then transferred to here. -- Cheers!"
-    $ECHO
-}
-
-##########################
-# VERSION_CHECK FUNCTION #
-##########################
-version_check ( ) {
-    if [ "x$1" = "x" ] ; then
-       echo "INTERNAL ERROR: version_check was not provided a minimum version"
-       exit 1
-    fi
-    _min="$1"
-    if [ "x$2" = "x" ] ; then
-       echo "INTERNAL ERROR: version check was not provided a comparison version"
-       exit 1
-    fi
-    _cur="$2"
-
-    # needed to handle versions like 1.10 and 1.4-p6
-    _min="`echo ${_min}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`"
-    _cur="`echo ${_cur}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`"
-
-    _min_major="`echo $_min | cut -d. -f1`"
-    _min_minor="`echo $_min | cut -d. -f2`"
-    _min_patch="`echo $_min | cut -d. -f3`"
-
-    _cur_major="`echo $_cur | cut -d. -f1`"
-    _cur_minor="`echo $_cur | cut -d. -f2`"
-    _cur_patch="`echo $_cur | cut -d. -f3`"
-
-    if [ "x$_min_major" = "x" ] ; then
-       _min_major=0
-    fi
-    if [ "x$_min_minor" = "x" ] ; then
-       _min_minor=0
-    fi
-    if [ "x$_min_patch" = "x" ] ; then
-       _min_patch=0
-    fi
-    if [ "x$_cur_minor" = "x" ] ; then
-       _cur_major=0
-    fi
-    if [ "x$_cur_minor" = "x" ] ; then
-       _cur_minor=0
-    fi
-    if [ "x$_cur_patch" = "x" ] ; then
-       _cur_patch=0
-    fi
-
-    $VERBOSE_ECHO "Checking if ${_cur_major}.${_cur_minor}.${_cur_patch} is greater than ${_min_major}.${_min_minor}.${_min_patch}"
-
-    if [ $_min_major -lt $_cur_major ] ; then
-       return 0
-    elif [ $_min_major -eq $_cur_major ] ; then
-       if [ $_min_minor -lt $_cur_minor ] ; then
-           return 0
-       elif [ $_min_minor -eq $_cur_minor ] ; then
-           if [ $_min_patch -lt $_cur_patch ] ; then
-               return 0
-           elif [ $_min_patch -eq $_cur_patch ] ; then
-               return 0
-           fi
-       fi
-    fi
-    return 1
-}
-
-
-######################################
-# LOCATE_CONFIGURE_TEMPLATE FUNCTION #
-######################################
-locate_configure_template ( ) {
-    _pwd="`pwd`"
-    if test -f "./configure.ac" ; then
-       echo "./configure.ac"
-    elif test -f "./configure.in" ; then
-       echo "./configure.in"
-    elif test -f "$_pwd/configure.ac" ; then
-       echo "$_pwd/configure.ac"
-    elif test -f "$_pwd/configure.in" ; then
-       echo "$_pwd/configure.in"
-    elif test -f "$PATH_TO_AUTOGEN/configure.ac" ; then
-       echo "$PATH_TO_AUTOGEN/configure.ac"
-    elif test -f "$PATH_TO_AUTOGEN/configure.in" ; then
-       echo "$PATH_TO_AUTOGEN/configure.in"
-    fi
-}
-
-
-##################
-# argument check #
-##################
-ARGS="$*"
-PATH_TO_AUTOGEN="`dirname $0`"
-NAME_OF_AUTOGEN="`basename $0`"
-AUTOGEN_SH="$PATH_TO_AUTOGEN/$NAME_OF_AUTOGEN"
-
-LIBTOOL_M4="${PATH_TO_AUTOGEN}/misc/libtool.m4"
-
-if [ "x$HELP" = "x" ] ; then
-    HELP=no
-fi
-if [ "x$QUIET" = "x" ] ; then
-    QUIET=no
-fi
-if [ "x$VERBOSE" = "x" ] ; then
-    VERBOSE=no
-fi
-if [ "x$VERSION_ONLY" = "x" ] ; then
-    VERSION_ONLY=no
-fi
-if [ "x$DOWNLOAD" = "x" ] ; then
-    DOWNLOAD=no
-fi
-if [ "x$AUTORECONF_OPTIONS" = "x" ] ; then
-    AUTORECONF_OPTIONS="-i -f"
-fi
-if [ "x$AUTOCONF_OPTIONS" = "x" ] ; then
-    AUTOCONF_OPTIONS="-f"
-fi
-if [ "x$AUTOMAKE_OPTIONS" = "x" ] ; then
-    AUTOMAKE_OPTIONS="-a -c -f"
-fi
-ALT_AUTOMAKE_OPTIONS="-a -c"
-if [ "x$LIBTOOLIZE_OPTIONS" = "x" ] ; then
-    LIBTOOLIZE_OPTIONS="--automake -c -f"
-fi
-ALT_LIBTOOLIZE_OPTIONS="--automake --copy --force"
-if [ "x$ACLOCAL_OPTIONS" = "x" ] ; then
-    ACLOCAL_OPTIONS=""
-fi
-if [ "x$AUTOHEADER_OPTIONS" = "x" ] ; then
-    AUTOHEADER_OPTIONS=""
-fi
-if [ "x$CONFIG_GUESS_URL" = "x" ] ; then
-    CONFIG_GUESS_URL="http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=build-aux/config.guess;hb=HEAD"
-fi
-for arg in $ARGS ; do
-    case "x$arg" in
-       x--help) HELP=yes ;;
-       x-[hH]) HELP=yes ;;
-       x--quiet) QUIET=yes ;;
-       x-[qQ]) QUIET=yes ;;
-       x--verbose) VERBOSE=yes ;;
-       x-[dD]) DOWNLOAD=yes ;;
-       x--download) DOWNLOAD=yes ;;
-       x-[vV]) VERBOSE=yes ;;
-       x--version) VERSION_ONLY=yes ;;
-       *)
-           echo "Unknown option: $arg"
-           echo
-           usage
-           exit 1
-           ;;
-    esac
-done
-
-
-#####################
-# environment check #
-#####################
-
-# sanity check before recursions potentially begin
-if [ ! -f "$AUTOGEN_SH" ] ; then
-    echo "INTERNAL ERROR: $AUTOGEN_SH does not exist"
-    if [ ! "x$0" = "x$AUTOGEN_SH" ] ; then
-       echo "INTERNAL ERROR: dirname/basename inconsistency: $0 != $AUTOGEN_SH"
-    fi
-    exit 1
-fi
-
-# force locale setting to C so things like date output as expected
-LC_ALL=C
-
-# commands that this script expects
-for __cmd in echo head tail pwd ; do
-    echo "test" | $__cmd > /dev/null 2>&1
-    if [ $? != 0 ] ; then
-       echo "INTERNAL ERROR: '${__cmd}' command is required"
-       exit 2
-    fi
-done
-echo "test" | grep "test" > /dev/null 2>&1
-if test ! x$? = x0 ; then
-    echo "INTERNAL ERROR: grep command is required"
-    exit 1
-fi
-echo "test" | sed "s/test/test/" > /dev/null 2>&1
-if test ! x$? = x0 ; then
-    echo "INTERNAL ERROR: sed command is required"
-    exit 1
-fi
-
-
-# determine the behavior of echo
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
-    *c*,-n*) ECHO_N= ECHO_C='
-' ECHO_T='     ' ;;
-    *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
-    *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
-esac
-
-# determine the behavior of head
-case "x`echo 'head' | head -n 1 2>&1`" in
-    *xhead*) HEAD_N="n " ;;
-    *) HEAD_N="" ;;
-esac
-
-# determine the behavior of tail
-case "x`echo 'tail' | tail -n 1 2>&1`" in
-    *xtail*) TAIL_N="n " ;;
-    *) TAIL_N="" ;;
-esac
-
-VERBOSE_ECHO=:
-ECHO=:
-if [ "x$QUIET" = "xyes" ] ; then
-    if [ "x$VERBOSE" = "xyes" ] ; then
-       echo "Verbose output quelled by quiet option.  Further output disabled."
-    fi
-else
-    ECHO=echo
-    if [ "x$VERBOSE" = "xyes" ] ; then
-       echo "Verbose output enabled"
-       VERBOSE_ECHO=echo
-    fi
-fi
-
-
-# allow a recursive run to disable further recursions
-if [ "x$RUN_RECURSIVE" = "x" ] ; then
-    RUN_RECURSIVE=yes
-fi
-
-
-################################################
-# check for help arg and bypass version checks #
-################################################
-if [ "x`echo $ARGS | sed 's/.*[hH][eE][lL][pP].*/help/'`" = "xhelp" ] ; then
-    HELP=yes
-fi
-if [ "x$HELP" = "xyes" ] ; then
-    usage
-    $ECHO "---"
-    $ECHO "Help was requested.  No preparation or configuration will be performed."
-    exit 0
-fi
-
-
-#######################
-# set up signal traps #
-#######################
-untrap_abnormal ( ) {
-    for sig in 1 2 13 15; do
-       trap - $sig
-    done
-}
-
-# do this cleanup whenever we exit.
-trap '
-    # start from the root
-    if test -d "$START_PATH" ; then
-       cd "$START_PATH"
-    fi
-
-    # restore/delete backup files
-    if test "x$PFC_INIT" = "x1" ; then
-       recursive_restore
-    fi
-' 0
-
-# trap SIGHUP (1), SIGINT (2), SIGPIPE (13), SIGTERM (15)
-for sig in 1 2 13 15; do
-    trap '
-       $ECHO ""
-       $ECHO "Aborting $NAME_OF_AUTOGEN: caught signal '$sig'"
-
-       # start from the root
-       if test -d "$START_PATH" ; then
-           cd "$START_PATH"
-       fi
-
-       # clean up on abnormal exit
-       $VERBOSE_ECHO "rm -rf autom4te.cache"
-       rm -rf autom4te.cache
-
-       if test -f "acinclude.m4.$$.backup" ; then
-           $VERBOSE_ECHO "cat acinclude.m4.$$.backup > acinclude.m4"
-           chmod u+w acinclude.m4
-           cat acinclude.m4.$$.backup > acinclude.m4
-
-           $VERBOSE_ECHO "rm -f acinclude.m4.$$.backup"
-           rm -f acinclude.m4.$$.backup
-        fi
-
-       { (exit 1); exit 1; }
-' $sig
-done
-
-
-#############################
-# look for a configure file #
-#############################
-if [ "x$CONFIGURE" = "x" ] ; then
-    CONFIGURE="`locate_configure_template`"
-    if [ ! "x$CONFIGURE" = "x" ] ; then
-       $VERBOSE_ECHO "Found a configure template: $CONFIGURE"
-    fi
-else
-    $ECHO "Using CONFIGURE environment variable override: $CONFIGURE"
-fi
-if [ "x$CONFIGURE" = "x" ] ; then
-    if [ "x$VERSION_ONLY" = "xyes" ] ; then
-       CONFIGURE=/dev/null
-    else
-       $ECHO
-       $ECHO "A configure.ac or configure.in file could not be located implying"
-       $ECHO "that the GNU Build System is at least not used in this directory.  In"
-       $ECHO "any case, there is nothing to do here without one of those files."
-       $ECHO
-       $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`"
-       exit 1
-    fi
-fi
-
-####################
-# get project name #
-####################
-if [ "x$PROJECT" = "x" ] ; then
-    PROJECT="`grep AC_INIT $CONFIGURE | grep -v '.*#.*AC_INIT' | tail -${TAIL_N}1 | sed 's/^[  ]*AC_INIT(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    if [ "x$PROJECT" = "xAC_INIT" ] ; then
-       # projects might be using the older/deprecated arg-less AC_INIT .. look for AM_INIT_AUTOMAKE instead
-       PROJECT="`grep AM_INIT_AUTOMAKE $CONFIGURE | grep -v '.*#.*AM_INIT_AUTOMAKE' | tail -${TAIL_N}1 | sed 's/^[     ]*AM_INIT_AUTOMAKE(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    fi
-    if [ "x$PROJECT" = "xAM_INIT_AUTOMAKE" ] ; then
-       PROJECT="project"
-    fi
-    if [ "x$PROJECT" = "x" ] ; then
-       PROJECT="project"
-    fi
-else
-    $ECHO "Using PROJECT environment variable override: $PROJECT"
-fi
-$ECHO "Preparing the $PROJECT build system...please wait"
-$ECHO
-
-
-########################
-# check for autoreconf #
-########################
-HAVE_AUTORECONF=no
-if [ "x$AUTORECONF" = "x" ] ; then
-    for AUTORECONF in autoreconf ; do
-       $VERBOSE_ECHO "Checking autoreconf version: $AUTORECONF --version"
-       $AUTORECONF --version > /dev/null 2>&1
-       if [ $? = 0 ] ; then
-           HAVE_AUTORECONF=yes
-           break
-       fi
-    done
-else
-    HAVE_AUTORECONF=yes
-    $ECHO "Using AUTORECONF environment variable override: $AUTORECONF"
-fi
-
-
-##########################
-# autoconf version check #
-##########################
-_acfound=no
-if [ "x$AUTOCONF" = "x" ] ; then
-    for AUTOCONF in autoconf ; do
-       $VERBOSE_ECHO "Checking autoconf version: $AUTOCONF --version"
-       $AUTOCONF --version > /dev/null 2>&1
-       if [ $? = 0 ] ; then
-           _acfound=yes
-           break
-       fi
-    done
-else
-    _acfound=yes
-    $ECHO "Using AUTOCONF environment variable override: $AUTOCONF"
-fi
-
-_report_error=no
-if [ ! "x$_acfound" = "xyes" ] ; then
-    $ECHO "ERROR:  Unable to locate GNU Autoconf."
-    _report_error=yes
-else
-    _version="`$AUTOCONF --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`"
-    if [ "x$_version" = "x" ] ; then
-       _version="0.0.0"
-    fi
-    $ECHO "Found GNU Autoconf version $_version"
-    version_check "$AUTOCONF_VERSION" "$_version"
-    if [ $? -ne 0 ] ; then
-       _report_error=yes
-    fi
-fi
-if [ "x$_report_error" = "xyes" ] ; then
-    version_error "$AUTOCONF_VERSION" "GNU Autoconf"
-    exit 1
-fi
-
-
-##########################
-# automake version check #
-##########################
-_amfound=no
-if [ "x$AUTOMAKE" = "x" ] ; then
-    for AUTOMAKE in automake ; do
-       $VERBOSE_ECHO "Checking automake version: $AUTOMAKE --version"
-       $AUTOMAKE --version > /dev/null 2>&1
-       if [ $? = 0 ] ; then
-           _amfound=yes
-           break
-       fi
-    done
-else
-    _amfound=yes
-    $ECHO "Using AUTOMAKE environment variable override: $AUTOMAKE"
-fi
-
-
-_report_error=no
-if [ ! "x$_amfound" = "xyes" ] ; then
-    $ECHO
-    $ECHO "ERROR: Unable to locate GNU Automake."
-    _report_error=yes
-else
-    _version="`$AUTOMAKE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`"
-    if [ "x$_version" = "x" ] ; then
-       _version="0.0.0"
-    fi
-    $ECHO "Found GNU Automake version $_version"
-    version_check "$AUTOMAKE_VERSION" "$_version"
-    if [ $? -ne 0 ] ; then
-       _report_error=yes
-    fi
-fi
-if [ "x$_report_error" = "xyes" ] ; then
-    version_error "$AUTOMAKE_VERSION" "GNU Automake"
-    exit 1
-fi
-
-
-########################
-# check for libtoolize #
-########################
-HAVE_LIBTOOLIZE=yes
-HAVE_ALT_LIBTOOLIZE=no
-_ltfound=no
-if [ "x$LIBTOOLIZE" = "x" ] ; then
-    LIBTOOLIZE=libtoolize
-    $VERBOSE_ECHO "Checking libtoolize version: $LIBTOOLIZE --version"
-    $LIBTOOLIZE --version > /dev/null 2>&1
-    if [ ! $? = 0 ] ; then
-       HAVE_LIBTOOLIZE=no
-       $ECHO
-       if [ "x$HAVE_AUTORECONF" = "xno" ] ; then
-           $ECHO "Warning:  libtoolize does not appear to be available."
-       else
-           $ECHO "Warning:  libtoolize does not appear to be available.  This means that"
-           $ECHO "the automatic build preparation via autoreconf will probably not work."
-           $ECHO "Preparing the build by running each step individually, however, should"
-           $ECHO "work and will be done automatically for you if autoreconf fails."
-       fi
-
-       # look for some alternates
-       for tool in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do
-           $VERBOSE_ECHO "Checking libtoolize alternate: $tool --version"
-           _glibtoolize="`$tool --version > /dev/null 2>&1`"
-           if [ $? = 0 ] ; then
-               $VERBOSE_ECHO "Found $tool --version"
-               _glti="`which $tool`"
-               if [ "x$_glti" = "x" ] ; then
-                   $VERBOSE_ECHO "Cannot find $tool with which"
-                   continue;
-               fi
-               if test ! -f "$_glti" ; then
-                   $VERBOSE_ECHO "Cannot use $tool, $_glti is not a file"
-                   continue;
-               fi
-               _gltidir="`dirname $_glti`"
-               if [ "x$_gltidir" = "x" ] ; then
-                   $VERBOSE_ECHO "Cannot find $tool path with dirname of $_glti"
-                   continue;
-               fi
-               if test ! -d "$_gltidir" ; then
-                   $VERBOSE_ECHO "Cannot use $tool, $_gltidir is not a directory"
-                   continue;
-               fi
-               HAVE_ALT_LIBTOOLIZE=yes
-               LIBTOOLIZE="$tool"
-               $ECHO
-               $ECHO "Fortunately, $tool was found which means that your system may simply"
-               $ECHO "have a non-standard or incomplete GNU Autotools install.  If you have"
-               $ECHO "sufficient system access, it may be possible to quell this warning by"
-               $ECHO "running:"
-               $ECHO
-               sudo -V > /dev/null 2>&1
-               if [ $? = 0 ] ; then
-                   $ECHO "   sudo ln -s $_glti $_gltidir/libtoolize"
-                   $ECHO
-               else
-                   $ECHO "   ln -s $_glti $_gltidir/libtoolize"
-                   $ECHO
-                   $ECHO "Run that as root or with proper permissions to the $_gltidir directory"
-                   $ECHO
-               fi
-               _ltfound=yes
-               break
-           fi
-       done
-    else
-       _ltfound=yes
-    fi
-else
-    _ltfound=yes
-    $ECHO "Using LIBTOOLIZE environment variable override: $LIBTOOLIZE"
-fi
-
-
-############################
-# libtoolize version check #
-############################
-_report_error=no
-if [ ! "x$_ltfound" = "xyes" ] ; then
-    $ECHO
-    $ECHO "ERROR: Unable to locate GNU Libtool."
-    _report_error=yes
-else
-    _version="`$LIBTOOLIZE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`"
-    if [ "x$_version" = "x" ] ; then
-       _version="0.0.0"
-    fi
-    $ECHO "Found GNU Libtool version $_version"
-    version_check "$LIBTOOL_VERSION" "$_version"
-    if [ $? -ne 0 ] ; then
-       _report_error=yes
-    fi
-fi
-if [ "x$_report_error" = "xyes" ] ; then
-    version_error "$LIBTOOL_VERSION" "GNU Libtool"
-    exit 1
-fi
-
-
-#####################
-# check for aclocal #
-#####################
-if [ "x$ACLOCAL" = "x" ] ; then
-    for ACLOCAL in aclocal ; do
-       $VERBOSE_ECHO "Checking aclocal version: $ACLOCAL --version"
-       $ACLOCAL --version > /dev/null 2>&1
-       if [ $? = 0 ] ; then
-           break
-       fi
-    done
-else
-    $ECHO "Using ACLOCAL environment variable override: $ACLOCAL"
-fi
-
-
-########################
-# check for autoheader #
-########################
-if [ "x$AUTOHEADER" = "x" ] ; then
-    for AUTOHEADER in autoheader ; do
-       $VERBOSE_ECHO "Checking autoheader version: $AUTOHEADER --version"
-       $AUTOHEADER --version > /dev/null 2>&1
-       if [ $? = 0 ] ; then
-           break
-       fi
-    done
-else
-    $ECHO "Using AUTOHEADER environment variable override: $AUTOHEADER"
-fi
-
-
-#########################
-# check if version only #
-#########################
-$VERBOSE_ECHO "Checking whether to only output version information"
-if [ "x$VERSION_ONLY" = "xyes" ] ; then
-    $ECHO
-    ident
-    $ECHO "---"
-    $ECHO "Version requested.  No preparation or configuration will be performed."
-    exit 0
-fi
-
-
-#################################
-# PROTECT_FROM_CLOBBER FUNCTION #
-#################################
-protect_from_clobber ( ) {
-    PFC_INIT=1
-
-    # protect COPYING & INSTALL from overwrite by automake.  the
-    # automake force option will (inappropriately) ignore the existing
-    # contents of a COPYING and/or INSTALL files (depending on the
-    # version) instead of just forcing *missing* files like it does
-    # for AUTHORS, NEWS, and README. this is broken but extremely
-    # prevalent behavior, so we protect against it by keeping a backup
-    # of the file that can later be restored.
-
-    for file in COPYING INSTALL ; do
-       if test -f ${file} ; then
-           if test -f ${file}.$$.protect_from_automake.backup ; then
-               $VERBOSE_ECHO "Already backed up ${file} in `pwd`"
-           else
-               $VERBOSE_ECHO "Backing up ${file} in `pwd`"
-               $VERBOSE_ECHO "cp -p ${file} ${file}.$$.protect_from_automake.backup"
-               cp -p ${file} ${file}.$$.protect_from_automake.backup
-           fi
-       fi
-    done
-}
-
-
-##############################
-# RECURSIVE_PROTECT FUNCTION #
-##############################
-recursive_protect ( ) {
-
-    # for projects using recursive configure, run the build
-    # preparation steps for the subdirectories.  this function assumes
-    # START_PATH was set to pwd before recursion begins so that
-    # relative paths work.
-
-    # git 'r done, protect COPYING and INSTALL from being clobbered
-    protect_from_clobber
-
-    if test -d autom4te.cache ; then
-       $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it"
-       $VERBOSE_ECHO "rm -rf autom4te.cache"
-       rm -rf autom4te.cache
-    fi
-
-    # find configure template
-    _configure="`locate_configure_template`"
-    if [ "x$_configure" = "x" ] ; then
-       return
-    fi
-    # $VERBOSE_ECHO "Looking for configure template found `pwd`/$_configure"
-
-    # look for subdirs
-    # $VERBOSE_ECHO "Looking for subdirs in `pwd`"
-    _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[    ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    CHECK_DIRS=""
-    for dir in $_det_config_subdirs ; do
-       if test -d "`pwd`/$dir" ; then
-           CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\""
-       fi
-    done
-
-    # process subdirs
-    if [ ! "x$CHECK_DIRS" = "x" ] ; then
-       $VERBOSE_ECHO "Recursively scanning the following directories:"
-       $VERBOSE_ECHO "  $CHECK_DIRS"
-       for dir in $CHECK_DIRS ; do
-           $VERBOSE_ECHO "Protecting files from automake in $dir"
-           cd "$START_PATH"
-           eval "cd $dir"
-
-           # recursively git 'r done
-           recursive_protect
-       done
-    fi
-} # end of recursive_protect
-
-
-#############################
-# RESTORE_CLOBBERED FUNCION #
-#############################
-restore_clobbered ( ) {
-
-    # The automake (and autoreconf by extension) -f/--force-missing
-    # option may overwrite COPYING and INSTALL even if they do exist.
-    # Here we restore the files if necessary.
-
-    spacer=no
-
-    for file in COPYING INSTALL ; do
-       if test -f ${file}.$$.protect_from_automake.backup ; then
-           if test -f ${file} ; then
-           # compare entire content, restore if needed
-           if test "x`cat ${file}`" != "x`cat ${file}.$$.protect_from_automake.backup`" ; then
-               if test "x$spacer" = "xno" ; then
-                   $VERBOSE_ECHO
-                   spacer=yes
-               fi
-               # restore the backup
-               $VERBOSE_ECHO "Restoring ${file} from backup (automake -f likely clobbered it)"
-               $VERBOSE_ECHO "rm -f ${file}"
-               rm -f ${file}
-               $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}"
-               mv ${file}.$$.protect_from_automake.backup ${file}
-           fi # check contents
-           elif test -f ${file}.$$.protect_from_automake.backup ; then
-               $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}"
-               mv ${file}.$$.protect_from_automake.backup ${file}
-           fi # -f ${file}
-       
-           # just in case
-           $VERBOSE_ECHO "rm -f ${file}.$$.protect_from_automake.backup"
-           rm -f ${file}.$$.protect_from_automake.backup
-       fi # -f ${file}.$$.protect_from_automake.backup
-    done
-
-    CONFIGURE="`locate_configure_template`"
-    if [ "x$CONFIGURE" = "x" ] ; then
-       return
-    fi
-
-    _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[     ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    if test ! -d "$_aux_dir" ; then
-       _aux_dir=.
-    fi
-
-    for file in config.guess config.sub ltmain.sh ; do
-       if test -f "${_aux_dir}/${file}" ; then
-           $VERBOSE_ECHO "rm -f \"${_aux_dir}/${file}.backup\""
-           rm -f "${_aux_dir}/${file}.backup"
-       fi
-    done
-} # end of restore_clobbered
-
-
-##############################
-# RECURSIVE_RESTORE FUNCTION #
-##############################
-recursive_restore ( ) {
-
-    # restore COPYING and INSTALL from backup if they were clobbered
-    # for each directory recursively.
-
-    # git 'r undone
-    restore_clobbered
-
-    # find configure template
-    _configure="`locate_configure_template`"
-    if [ "x$_configure" = "x" ] ; then
-       return
-    fi
-
-    # look for subdirs
-    _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[    ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    CHECK_DIRS=""
-    for dir in $_det_config_subdirs ; do
-       if test -d "`pwd`/$dir" ; then
-           CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\""
-       fi
-    done
-
-    # process subdirs
-    if [ ! "x$CHECK_DIRS" = "x" ] ; then
-       $VERBOSE_ECHO "Recursively scanning the following directories:"
-       $VERBOSE_ECHO "  $CHECK_DIRS"
-       for dir in $CHECK_DIRS ; do
-           $VERBOSE_ECHO "Checking files for automake damage in $dir"
-           cd "$START_PATH"
-           eval "cd $dir"
-
-           # recursively git 'r undone
-           recursive_restore
-       done
-    fi
-} # end of recursive_restore
-
-
-#######################
-# INITIALIZE FUNCTION #
-#######################
-initialize ( ) {
-
-    # this routine performs a variety of directory-specific
-    # initializations.  some are sanity checks, some are preventive,
-    # and some are necessary setup detection.
-    #
-    # this function sets:
-    #   CONFIGURE
-    #   SEARCH_DIRS
-    #   CONFIG_SUBDIRS
-
-    ##################################
-    # check for a configure template #
-    ##################################
-    CONFIGURE="`locate_configure_template`"
-    if [ "x$CONFIGURE" = "x" ] ; then
-       $ECHO
-       $ECHO "A configure.ac or configure.in file could not be located implying"
-       $ECHO "that the GNU Build System is at least not used in this directory.  In"
-       $ECHO "any case, there is nothing to do here without one of those files."
-       $ECHO
-       $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`"
-       exit 1
-    fi
-
-    #####################
-    # detect an aux dir #
-    #####################
-    _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[     ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    if test ! -d "$_aux_dir" ; then
-       _aux_dir=.
-    else
-       $VERBOSE_ECHO "Detected auxillary directory: $_aux_dir"
-    fi
-
-    ################################
-    # detect a recursive configure #
-    ################################
-    CONFIG_SUBDIRS=""
-    _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $CONFIGURE | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[     ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`"
-    for dir in $_det_config_subdirs ; do
-       if test -d "`pwd`/$dir" ; then
-           $VERBOSE_ECHO "Detected recursive configure directory: `pwd`/$dir"
-           CONFIG_SUBDIRS="$CONFIG_SUBDIRS `pwd`/$dir"
-       fi
-    done
-
-    ###########################################################
-    # make sure certain required files exist for GNU projects #
-    ###########################################################
-    _marker_found=""
-    _marker_found_message_intro='Detected non-GNU marker "'
-    _marker_found_message_mid='" in '
-    for marker in foreign cygnus ; do
-       _marker_found_message=${_marker_found_message_intro}${marker}${_marker_found_message_mid}
-       _marker_found="`grep 'AM_INIT_AUTOMAKE.*'${marker} $CONFIGURE`"
-       if [ ! "x$_marker_found" = "x" ] ; then
-           $VERBOSE_ECHO "${_marker_found_message}`basename \"$CONFIGURE\"`"
-           break
-       fi
-       if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then
-           _marker_found="`grep 'AUTOMAKE_OPTIONS.*'${marker} Makefile.am`"
-           if [ ! "x$_marker_found" = "x" ] ; then
-               $VERBOSE_ECHO "${_marker_found_message}Makefile.am"
-               break
-           fi
-       fi
-    done
-    if [ "x${_marker_found}" = "x" ] ; then
-       _suggest_foreign=no
-       for file in AUTHORS COPYING ChangeLog INSTALL NEWS README ; do
-           if [ ! -f $file ] ; then
-               $VERBOSE_ECHO "Touching ${file} since it does not exist"
-               _suggest_foreign=yes
-               touch $file
-           fi
-       done
-
-       if [ "x${_suggest_foreign}" = "xyes" ] ; then
-           $ECHO
-           $ECHO "Warning: Several files expected of projects that conform to the GNU"
-           $ECHO "coding standards were not found.  The files were automatically added"
-           $ECHO "for you since you do not have a 'foreign' declaration specified."
-           $ECHO
-           $ECHO "Considered adding 'foreign' to AM_INIT_AUTOMAKE in `basename \"$CONFIGURE\"`"
-           if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then
-               $ECHO "or to AUTOMAKE_OPTIONS in your top-level Makefile.am file."
-           fi
-           $ECHO
-       fi
-    fi
-
-    ##################################################
-    # make sure certain generated files do not exist #
-    ##################################################
-    for file in config.guess config.sub ltmain.sh ; do
-       if test -f "${_aux_dir}/${file}" ; then
-           $VERBOSE_ECHO "mv -f \"${_aux_dir}/${file}\" \"${_aux_dir}/${file}.backup\""
-           mv -f "${_aux_dir}/${file}" "${_aux_dir}/${file}.backup"
-       fi
-    done
-
-    ############################
-    # search alternate m4 dirs #
-    ############################
-    SEARCH_DIRS=""
-    for dir in m4 ; do
-       if [ -d $dir ] ; then
-           $VERBOSE_ECHO "Found extra aclocal search directory: $dir"
-           SEARCH_DIRS="$SEARCH_DIRS -I $dir"
-       fi
-    done
-
-    ######################################
-    # remove any previous build products #
-    ######################################
-    if test -d autom4te.cache ; then
-       $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it"
-       $VERBOSE_ECHO "rm -rf autom4te.cache"
-       rm -rf autom4te.cache
-    fi
-# tcl/tk (and probably others) have a customized aclocal.m4, so can't delete it
-#     if test -f aclocal.m4 ; then
-#      $VERBOSE_ECHO "Found an aclocal.m4 file, deleting it"
-#      $VERBOSE_ECHO "rm -f aclocal.m4"
-#      rm -f aclocal.m4
-#     fi
-
-} # end of initialize()
-
-
-##############
-# initialize #
-##############
-
-# stash path
-START_PATH="`pwd`"
-
-# Before running autoreconf or manual steps, some prep detection work
-# is necessary or useful.  Only needs to occur once per directory, but
-# does need to traverse the entire subconfigure hierarchy to protect
-# files from being clobbered even by autoreconf.
-recursive_protect
-
-# start from where we started
-cd "$START_PATH"
-
-# get ready to process
-initialize
-
-
-#########################################
-# DOWNLOAD_GNULIB_CONFIG_GUESS FUNCTION #
-#########################################
-
-# TODO - should make sure wget/curl exist and/or work before trying to
-# use them.
-
-download_gnulib_config_guess () {
-    # abuse gitweb to download gnulib's latest config.guess via HTTP
-    config_guess_temp="config.guess.$$.download"
-    ret=1
-    for __cmd in wget curl fetch ; do
-       $VERBOSE_ECHO "Checking for command ${__cmd}"
-       ${__cmd} --version > /dev/null 2>&1
-       ret=$?
-       if [ ! $ret = 0 ] ; then
-           continue
-        fi
-
-       __cmd_version=`${__cmd} --version | head -n 1 | sed -e 's/^[^0-9]\+//' -e 's/ .*//'`
-       $VERBOSE_ECHO "Found ${__cmd} ${__cmd_version}"
-
-       opts=""
-       case ${__cmd} in
-           wget)
-               opts="-O" 
-               ;;
-           curl)
-               opts="-o"
-               ;;
-           fetch)
-               opts="-t 5 -f"
-               ;;
-       esac
-
-       $VERBOSE_ECHO "Running $__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\""
-       eval "$__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" > /dev/null 2>&1
-       if [ $? = 0 ] ; then
-           mv -f "${config_guess_temp}" ${_aux_dir}/config.guess
-           ret=0
-           break
-       fi
-    done
-
-    if [ ! $ret = 0 ] ; then
-       $ECHO "Warning: config.guess download failed from: $CONFIG_GUESS_URL"
-       rm -f "${config_guess_temp}"
-    fi
-}
-
-
-##############################
-# LIBTOOLIZE_NEEDED FUNCTION #
-##############################
-libtoolize_needed () {
-    ret=1 # means no, don't need libtoolize
-    for feature in AC_PROG_LIBTOOL AM_PROG_LIBTOOL LT_INIT ; do
-       $VERBOSE_ECHO "Searching for $feature in $CONFIGURE"
-       found="`grep \"^$feature.*\" $CONFIGURE`"
-       if [ ! "x$found" = "x" ] ; then
-           ret=0 # means yes, need to run libtoolize
-           break
-       fi
-    done
-    return ${ret}
-}
-
-
-
-############################################
-# prepare build via autoreconf or manually #
-############################################
-reconfigure_manually=no
-if [ "x$HAVE_AUTORECONF" = "xyes" ] ; then
-    $ECHO
-    $ECHO $ECHO_N "Automatically preparing build ... $ECHO_C"
-
-    $VERBOSE_ECHO "$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS"
-    autoreconf_output="`$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS 2>&1`"
-    ret=$?
-    $VERBOSE_ECHO "$autoreconf_output"
-
-    if [ ! $ret = 0 ] ; then
-       if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then
-           if [ ! "x`echo \"$autoreconf_output\" | grep libtoolize | grep \"No such file or directory\"`" = "x" ] ; then
-               $ECHO
-               $ECHO "Warning: autoreconf failed but due to what is usually a common libtool"
-               $ECHO "misconfiguration issue.  This problem is encountered on systems that"
-               $ECHO "have installed libtoolize under a different name without providing a"
-               $ECHO "symbolic link or without setting the LIBTOOLIZE environment variable."
-               $ECHO
-               $ECHO "Restarting the preparation steps with LIBTOOLIZE set to $LIBTOOLIZE"
-
-               export LIBTOOLIZE
-               RUN_RECURSIVE=no
-               export RUN_RECURSIVE
-               untrap_abnormal
-
-               $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
-               sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
-               exit $?
-           fi
-       fi
-
-       $ECHO "Warning: $AUTORECONF failed"
-
-       if test -f ltmain.sh ; then
-           $ECHO "libtoolize being run by autoreconf is not creating ltmain.sh in the auxillary directory like it should"
-       fi
-
-       $ECHO "Attempting to run the preparation steps individually"
-       reconfigure_manually=yes
-    else
-       if [ "x$DOWNLOAD" = "xyes" ] ; then
-           if libtoolize_needed ; then
-               download_gnulib_config_guess
-           fi
-       fi
-    fi
-else
-    reconfigure_manually=yes
-fi
-
-
-############################
-# LIBTOOL_FAILURE FUNCTION #
-############################
-libtool_failure ( ) {
-
-    # libtool is rather error-prone in comparison to the other
-    # autotools and this routine attempts to compensate for some
-    # common failures.  the output after a libtoolize failure is
-    # parsed for an error related to AC_PROG_LIBTOOL and if found, we
-    # attempt to inject a project-provided libtool.m4 file.
-
-    _autoconf_output="$1"
-
-    if [ "x$RUN_RECURSIVE" = "xno" ] ; then
-       # we already tried the libtool.m4, don't try again
-       return 1
-    fi
-
-    if test -f "$LIBTOOL_M4" ; then
-       found_libtool="`$ECHO $_autoconf_output | grep AC_PROG_LIBTOOL`"
-       if test ! "x$found_libtool" = "x" ; then
-           if test -f acinclude.m4 ; then
-               rm -f acinclude.m4.$$.backup
-               $VERBOSE_ECHO "cat acinclude.m4 > acinclude.m4.$$.backup"
-               cat acinclude.m4 > acinclude.m4.$$.backup
-           fi
-           $VERBOSE_ECHO "cat \"$LIBTOOL_M4\" >> acinclude.m4"
-           chmod u+w acinclude.m4
-           cat "$LIBTOOL_M4" >> acinclude.m4
-
-           # don't keep doing this
-           RUN_RECURSIVE=no
-           export RUN_RECURSIVE
-           untrap_abnormal
-
-           $ECHO
-           $ECHO "Restarting the preparation steps with libtool macros in acinclude.m4"
-           $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
-           sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
-           exit $?
-       fi
-    fi
-}
-
-
-###########################
-# MANUAL_AUTOGEN FUNCTION #
-###########################
-manual_autogen ( ) {
-
-    ##################################################
-    # Manual preparation steps taken are as follows: #
-    #   aclocal [-I m4]                              #
-    #   libtoolize --automake -c -f                  #
-    #   aclocal [-I m4]                              #
-    #   autoconf -f                                  #
-    #   autoheader                                   #
-    #   automake -a -c -f                            #
-    ##################################################
-
-    ###########
-    # aclocal #
-    ###########
-    $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS"
-    aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`"
-    ret=$?
-    $VERBOSE_ECHO "$aclocal_output"
-    if [ ! $ret = 0 ] ; then $ECHO "ERROR: $ACLOCAL failed" && exit 2 ; fi
-
-    ##############
-    # libtoolize #
-    ##############
-    if libtoolize_needed ; then
-       if [ "x$HAVE_LIBTOOLIZE" = "xyes" ] ; then
-           $VERBOSE_ECHO "$LIBTOOLIZE $LIBTOOLIZE_OPTIONS"
-           libtoolize_output="`$LIBTOOLIZE $LIBTOOLIZE_OPTIONS 2>&1`"
-           ret=$?
-           $VERBOSE_ECHO "$libtoolize_output"
-
-           if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi
-       else
-           if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then
-               $VERBOSE_ECHO "$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS"
-               libtoolize_output="`$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS 2>&1`"
-               ret=$?
-               $VERBOSE_ECHO "$libtoolize_output"
-
-               if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi
-           fi
-       fi
-
-       ###########
-       # aclocal #
-       ###########
-       # re-run again as instructed by libtoolize
-       $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS"
-       aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`"
-       ret=$?
-       $VERBOSE_ECHO "$aclocal_output"
-
-       # libtoolize might put ltmain.sh in the wrong place
-       if test -f ltmain.sh ; then
-           if test ! -f "${_aux_dir}/ltmain.sh" ; then
-               $ECHO
-               $ECHO "Warning:  $LIBTOOLIZE is creating ltmain.sh in the wrong directory"
-               $ECHO
-               $ECHO "Fortunately, the problem can be worked around by simply copying the"
-               $ECHO "file to the appropriate location (${_aux_dir}/).  This has been done for you."
-               $ECHO
-               $VERBOSE_ECHO "cp -p ltmain.sh \"${_aux_dir}/ltmain.sh\""
-               cp -p ltmain.sh "${_aux_dir}/ltmain.sh"
-               $ECHO $ECHO_N "Continuing build preparation ... $ECHO_C"
-           fi
-       fi # ltmain.sh
-
-       if [ "x$DOWNLOAD" = "xyes" ] ; then
-           download_gnulib_config_guess
-       fi
-    fi # libtoolize_needed
-
-    ############
-    # autoconf #
-    ############
-    $VERBOSE_ECHO
-    $VERBOSE_ECHO "$AUTOCONF $AUTOCONF_OPTIONS"
-    autoconf_output="`$AUTOCONF $AUTOCONF_OPTIONS 2>&1`"
-    ret=$?
-    $VERBOSE_ECHO "$autoconf_output"
-
-    if [ ! $ret = 0 ] ; then
-       # retry without the -f and check for usage of macros that are too new
-       ac2_59_macros="AC_C_RESTRICT AC_INCLUDES_DEFAULT AC_LANG_ASSERT AC_LANG_WERROR AS_SET_CATFILE"
-       ac2_55_macros="AC_COMPILER_IFELSE AC_FUNC_MBRTOWC AC_HEADER_STDBOOL AC_LANG_CONFTEST AC_LANG_SOURCE AC_LANG_PROGRAM AC_LANG_CALL AC_LANG_FUNC_TRY_LINK AC_MSG_FAILURE AC_PREPROC_IFELSE"
-       ac2_54_macros="AC_C_BACKSLASH_A AC_CONFIG_LIBOBJ_DIR AC_GNU_SOURCE AC_PROG_EGREP AC_PROG_FGREP AC_REPLACE_FNMATCH AC_FUNC_FNMATCH_GNU AC_FUNC_REALLOC AC_TYPE_MBSTATE_T"
-
-       macros_to_search=""
-       ac_major="`echo ${AUTOCONF_VERSION}. | cut -d. -f1 | sed 's/[^0-9]//g'`"
-       ac_minor="`echo ${AUTOCONF_VERSION}. | cut -d. -f2 | sed 's/[^0-9]//g'`"
-
-       if [ $ac_major -lt 2 ] ; then
-           macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros"
-       else
-           if [ $ac_minor -lt 54 ] ; then
-               macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros"
-           elif [ $ac_minor -lt 55 ] ; then
-               macros_to_search="$ac2_59_macros $ac2_55_macros"
-           elif [ $ac_minor -lt 59 ] ; then
-               macros_to_search="$ac2_59_macros"
-           fi
-       fi
-
-       configure_ac_macros=__none__
-       for feature in $macros_to_search ; do
-           $VERBOSE_ECHO "Searching for $feature in $CONFIGURE"
-           found="`grep \"^$feature.*\" $CONFIGURE`"
-           if [ ! "x$found" = "x" ] ; then
-               if [ "x$configure_ac_macros" = "x__none__" ] ; then
-                   configure_ac_macros="$feature"
-               else
-                   configure_ac_macros="$feature $configure_ac_macros"
-               fi
-           fi
-       done
-       if [ ! "x$configure_ac_macros" = "x__none__" ] ; then
-           $ECHO
-           $ECHO "Warning:  Unsupported macros were found in $CONFIGURE"
-           $ECHO
-           $ECHO "The `basename \"$CONFIGURE\"` file was scanned in order to determine if any"
-           $ECHO "unsupported macros are used that exceed the minimum version"
-           $ECHO "settings specified within this file.  As such, the following macros"
-           $ECHO "should be removed from configure.ac or the version numbers in this"
-           $ECHO "file should be increased:"
-           $ECHO
-           $ECHO "$configure_ac_macros"
-           $ECHO
-           $ECHO $ECHO_N "Ignorantly continuing build preparation ... $ECHO_C"
-       fi
-
-       ###################
-       # autoconf, retry #
-       ###################
-       $VERBOSE_ECHO
-       $VERBOSE_ECHO "$AUTOCONF"
-       autoconf_output="`$AUTOCONF 2>&1`"
-       ret=$?
-       $VERBOSE_ECHO "$autoconf_output"
-
-       if [ ! $ret = 0 ] ; then
-           # test if libtool is busted
-           libtool_failure "$autoconf_output"
-
-           # let the user know what went wrong
-           cat <<EOF
-$autoconf_output
-EOF
-           $ECHO "ERROR: $AUTOCONF failed"
-           exit 2
-       else
-           # autoconf sans -f and possibly sans unsupported options succeed so warn verbosely
-           $ECHO
-           $ECHO "Warning: autoconf seems to have succeeded by removing the following options:"
-           $ECHO "     AUTOCONF_OPTIONS=\"$AUTOCONF_OPTIONS\""
-           $ECHO
-           $ECHO "Removing those options should not be necessary and indicate some other"
-           $ECHO "problem with the build system.  The build preparation is highly suspect"
-           $ECHO "and may result in configuration or compilation errors.  Consider"
-           if [ "x$VERBOSE_ECHO" = "x:" ] ; then
-               $ECHO "rerunning the build preparation with verbose output enabled."
-               $ECHO " $AUTOGEN_SH --verbose"
-           else
-               $ECHO "reviewing the minimum GNU Autotools version settings contained in"
-               $ECHO "this script along with the macros being used in your `basename \"$CONFIGURE\"` file."
-           fi
-           $ECHO
-           $ECHO $ECHO_N "Continuing build preparation ... $ECHO_C"
-       fi # autoconf ret = 0
-    fi # autoconf ret = 0
-
-    ##############
-    # autoheader #
-    ##############
-    need_autoheader=no
-    for feature in AM_CONFIG_HEADER AC_CONFIG_HEADER ; do
-       $VERBOSE_ECHO "Searching for $feature in $CONFIGURE"
-       found="`grep \"^$feature.*\" $CONFIGURE`"
-       if [ ! "x$found" = "x" ] ; then
-           need_autoheader=yes
-           break
-       fi
-    done
-    if [ "x$need_autoheader" = "xyes" ] ; then
-       $VERBOSE_ECHO "$AUTOHEADER $AUTOHEADER_OPTIONS"
-       autoheader_output="`$AUTOHEADER $AUTOHEADER_OPTIONS 2>&1`"
-       ret=$?
-       $VERBOSE_ECHO "$autoheader_output"
-       if [ ! $ret = 0 ] ; then $ECHO "ERROR: $AUTOHEADER failed" && exit 2 ; fi
-    fi # need_autoheader
-
-    ############
-    # automake #
-    ############
-    need_automake=no
-    for feature in AM_INIT_AUTOMAKE ; do
-       $VERBOSE_ECHO "Searching for $feature in $CONFIGURE"
-       found="`grep \"^$feature.*\" $CONFIGURE`"
-       if [ ! "x$found" = "x" ] ; then
-           need_automake=yes
-           break
-       fi
-    done
-
-    if [ "x$need_automake" = "xyes" ] ; then
-       $VERBOSE_ECHO "$AUTOMAKE $AUTOMAKE_OPTIONS"
-       automake_output="`$AUTOMAKE $AUTOMAKE_OPTIONS 2>&1`"
-       ret=$?
-       $VERBOSE_ECHO "$automake_output"
-
-       if [ ! $ret = 0 ] ; then
-
-           ###################
-           # automake, retry #
-           ###################
-           ALT_AUTOMAKE_OPTIONS="$ALT_AUTOMAKE_OPTIONS --add-missing"
-           $VERBOSE_ECHO
-           $VERBOSE_ECHO "$AUTOMAKE $ALT_AUTOMAKE_OPTIONS"
-           # retry without the -f
-           automake_output="`$AUTOMAKE $ALT_AUTOMAKE_OPTIONS 2>&1`"
-           ret=$?
-           $VERBOSE_ECHO "$automake_output"
-
-           if [ ! $ret = 0 ] ; then
-               # test if libtool is busted
-               libtool_failure "$automake_output"
-
-               # let the user know what went wrong
-               cat <<EOF
-$automake_output
-EOF
-               $ECHO "ERROR: $AUTOMAKE failed"
-               exit 2
-           fi # automake retry
-       fi # automake ret = 0
-    fi # need_automake
-} # end of manual_autogen
-
-
-#####################################
-# RECURSIVE_MANUAL_AUTOGEN FUNCTION #
-#####################################
-recursive_manual_autogen ( ) {
-
-    # run the build preparation steps manually for this directory
-    manual_autogen
-
-    # for projects using recursive configure, run the build
-    # preparation steps for the subdirectories.
-    if [ ! "x$CONFIG_SUBDIRS" = "x" ] ; then
-       $VERBOSE_ECHO "Recursively configuring the following directories:"
-       $VERBOSE_ECHO "  $CONFIG_SUBDIRS"
-       for dir in $CONFIG_SUBDIRS ; do
-           $VERBOSE_ECHO "Processing recursive configure in $dir"
-           cd "$START_PATH"
-           cd "$dir"
-
-           # new directory, prepare
-           initialize
-
-           # run manual steps for the subdir and any others below
-           recursive_manual_autogen
-       done
-    fi
-}
-
-
-################################
-# run manual preparation steps #
-################################
-if [ "x$reconfigure_manually" = "xyes" ] ; then
-    $ECHO
-    $ECHO $ECHO_N "Preparing build ... $ECHO_C"
-
-    recursive_manual_autogen
-fi
-
-
-#########################
-# restore and summarize #
-#########################
-cd "$START_PATH"
-
-# restore COPYING and INSTALL from backup if necessary
-recursive_restore
-
-# make sure we end up with a configure script
-config_ac="`locate_configure_template`"
-config="`echo $config_ac | sed 's/\.ac$//' | sed 's/\.in$//'`"
-if [ "x$config" = "x" ] ; then
-    $VERBOSE_ECHO "Could not locate the configure template (from `pwd`)"
-fi
-
-# summarize
-$ECHO "done"
-$ECHO
-if test "x$config" = "x" -o ! -f "$config" ; then
-    $ECHO "WARNING: The $PROJECT build system should now be prepared but there"
-    $ECHO "does not seem to be a resulting configure file.  This is unexpected"
-    $ECHO "and likely the result of an error.  You should run $NAME_OF_AUTOGEN"
-    $ECHO "with the --verbose option to get more details on a potential"
-    $ECHO "misconfiguration."
-else
-    $ECHO "The $PROJECT build system is now prepared.  To build here, run:"
-    $ECHO "  $config"
-    $ECHO "  make"
-fi
-
-
-# Local Variables:
-# mode: sh
-# tab-width: 8
-# sh-basic-offset: 4
-# sh-indentation: 4
-# indent-tabs-mode: t
-# End:
-# ex: shiftwidth=4 tabstop=8
diff --git a/configure.ac b/configure.ac
deleted file mode 100644 (file)
index f9c7337..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-#                                               -*- Autoconf -*-
-# Process this file with autoconf to produce a configure script.
-
-# prereq & init
-
-AC_PREREQ(2.60)
-AC_INIT([giada], [0.16], [giadaloopmachine@gmail.com])
-AC_CONFIG_SRCDIR([src/main.cpp])
-AM_INIT_AUTOMAKE([subdir-objects])
-
-# ------------------------------------------------------------------------------
-
-# test the build environment. These vars are used in Makefile.am during
-# the linking of the libraries.
-# Usage: ./configure --target=[windows | linux | osx]
-
-if test "$target" = ""; then
-       AC_MSG_ERROR(["target OS not specified. Please run ./configure --target=<windows | linux | freebsd | osx>"])
-fi
-
-case "$target" in
-  linux)
-    os=linux
-    ;;
-  freebsd)
-    os=freebsd
-    ;;
-  windows)
-    os=windows
-    ;;
-  osx)
-    os=osx
-    ;;
-  freebsd)
-    os=freebsd
-    ;;
-  *)
-    AC_MSG_ERROR(["Unrecognised target OS: $target"])
-    ;;
-esac
-AM_CONDITIONAL(LINUX,   test "x$os" = "xlinux")
-AM_CONDITIONAL(WINDOWS, test "x$os" = "xwindows")
-AM_CONDITIONAL(OSX,     test "x$os" = "xosx")
-AM_CONDITIONAL(FREEBSD, test "x$os" = "xfreebsd")
-
-# ------------------------------------------------------------------------------
-
-# --enable-vst. VST compilation is disabled by default
-#
-# WITH_VST, if present, will be passed to gcc as -DWITH_VST
-#
-# AC_ARG_ENABLE (
-# feature,                [--enable-] + [feature], eg --enable-vst
-# help-string,
-# [action-if-given],      == gcc ... -DWITH_VST
-# [action-if-not-given])  not used here
-
-AC_ARG_ENABLE(
-       [vst],
-       AS_HELP_STRING([--enable-vst], [enable vst support]),
-       [AC_DEFINE(WITH_VST) AM_CONDITIONAL(WITH_VST, true)],
-       [AM_CONDITIONAL(WITH_VST, false)]
-)
-
-# ------------------------------------------------------------------------------
-
-# --enable-system-catch. If enabled, use the system-provided Catch. Use bundled
-# version otherwise (default mode).
-
-AC_ARG_ENABLE(
-       [system-catch],
-       AS_HELP_STRING([--enable-system-catch], [use system-provided Catch library]),
-       [AC_DEFINE(WITH_SYSTEM_CATCH) AM_CONDITIONAL(WITH_SYSTEM_CATCH, true)],
-       [AM_CONDITIONAL(WITH_SYSTEM_CATCH, false)]
-)
-
-# ------------------------------------------------------------------------------
-
-# --debug. Enable debug compilation
-
-AC_ARG_ENABLE(
-       [debug],
-       AS_HELP_STRING([--enable-debug], [enable debug mode (asserts, ...)]),
-       [],
-       [AC_DEFINE(NDEBUG)]
-)
-
-# ------------------------------------------------------------------------------
-
-# Check for C++ compiler
-
-AC_PROG_CXX
-
-# Check for Objective-C++ compiler
-
-AC_PROG_OBJCXX
-
-# Check for make
-
-AC_PROG_MAKE_SET
-
-# ------------------------------------------------------------------------------
-
-# Check for libraries.
-
-AC_CHECK_LIB(
-       [pthread],
-       [pthread_exit],
-       [],
-       [AC_MSG_ERROR([error: library 'pthread' not found!])]
-)
-
-# ------------------------------------------------------------------------------
-
-# Check for generic headers (fltk, rtaudio and libsndfile are static,
-# we ask if headers are available)
-
-AC_LANG_PUSH([C++])
-AC_CHECK_HEADER(
-       [FL/Fl.H],
-       [],
-       [AC_MSG_ERROR([library 'fltk' not found!])]
-)
-AC_LANG_POP
-
-if test "x$os" = "xosx"; then
-       AC_LANG_PUSH([C++])
-       AC_CHECK_HEADER(
-               [RtMidi.h],
-               [],
-               [AC_MSG_ERROR([library 'rtMidi' not found!])]
-       )
-       AC_LANG_POP
-else
-       AC_LANG_PUSH([C++])
-       AC_CHECK_HEADER(
-               [rtmidi/RtMidi.h],
-               [],
-               [AC_MSG_ERROR([library 'rtMidi' not found!])]
-       )
-       AC_LANG_POP
-fi
-
-AC_LANG_PUSH([C++])
-AC_CHECK_HEADER(
-       [sndfile.h],
-       [],
-       [AC_MSG_ERROR([library 'libsndfile' not found!])]
-)
-AC_LANG_POP
-
-AC_LANG_PUSH([C++])
-AC_CHECK_HEADER(
-       [samplerate.h],
-       [],
-       [AC_MSG_ERROR([library 'samplerate' not found!])]
-)
-AC_LANG_POP
-
-
-# ------------------------------------------------------------------------------
-
-# Check for linux header files.
-
-if test "x$os" = "xlinux" || test "x$os" = "xfreebsd"; then
-
-       AC_LANG_PUSH([C++])
-       AC_CHECK_HEADER(
-               [X11/xpm.h],
-               [],
-               [AC_MSG_ERROR([missing xpm.h, maybe you need to install the libxpm-dev package?])]
-       )
-       AC_LANG_POP
-fi
-
-# ------------------------------------------------------------------------------
-
-# finalizing
-
-AC_CONFIG_FILES([Makefile])
-AC_OUTPUT
diff --git a/extras/com.giadamusic.Giada.desktop b/extras/com.giadamusic.Giada.desktop
new file mode 100644 (file)
index 0000000..766bdfb
--- /dev/null
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Giada
+Name[es]=Giada
+GenericName=Drum machine and loop sequencer
+GenericName[es]=Caja de ritmos y secuenciador de loops
+Exec=giada %f
+Terminal=false
+Icon=giada-logo
+Categories=Music;AudioVideo;Audio;Midi;X-Digital_Processing;X-Jack;X-MIDI;
+Keywords=Giada;
\ No newline at end of file
diff --git a/extras/com.giadamusic.Giada.metainfo.xml b/extras/com.giadamusic.Giada.metainfo.xml
new file mode 100644 (file)
index 0000000..0786ef0
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2010-2021 Giovanni A. Zuliani | Monocasual Laboratories -->
+<component type="desktop">
+ <id>com.giadamusic.Giada</id>
+ <metadata_license>CC0</metadata_license>
+ <project_license>GPL-2.0+</project_license>
+ <name>Giada</name>
+ <summary>Your hardcore loop machine</summary>
+ <description>
+   <p>
+     Giada is an open source, minimalistic and hardcore music
+     production tool. Designed for DJs, live performers and electronic
+     musicians.
+   </p>
+ </description>
+ <content_rating type="oars-1.1" />
+ <launchable type="desktop-id">com.giadamusic.Giada.desktop</launchable>
+ <screenshots>
+  <screenshot type="default">
+    <image>
+      https://www.giadamusic.com/images/screenshots/giada-loop-machine-screenshot-03-large-project.png
+    </image>
+   <caption>A fairly large project with samples and MIDI events</caption>
+  </screenshot>
+  <screenshot>
+    <image>
+      https://www.giadamusic.com/images/screenshots/giada-loop-machine-screenshot-17-midi-action-editor.png
+    </image>
+   <caption>New Action Editor for MIDI events</caption>
+  </screenshot>
+  <screenshot>
+    <image>
+      https://www.giadamusic.com/images/screenshots/giada-loop-machine-screenshot-01-sample-editor.png
+    </image>
+   <caption>Chopping samples in the advanced Sample Editor</caption>
+  </screenshot>
+ </screenshots>
+ <update_contact>giadaloopmachine_AT_gmail.com</update_contact>
+ <url type="homepage">https://www.giadamusic.com/</url>
+ <url type="help">https://www.giadamusic.com/forum</url>
+ <releases>
+   <release version="0.18.0" date="2021-05-19">
+     <description>
+       <ul>
+         <li>New 'free loop-length' audio recording mode (#63)</li>
+         <li>Many AudioBuffer improvements</li>
+         <li>Audio configuration panel refactoring</li>
+         <li>KernelAudio improvements and cleanups</li>
+         <li>Relaxed BPM handling when working with JACK</li>
+         <li>Install executable to FHS compliant location (#450)</li>
+         <li>[CI] Don't UPX binaries on macOS (#459)</li>
+         <li>Fix Overdub protection ON by default not working (#460)</li>
+         <li>Fix crash when moving up from a deleted folder (#455)</li>
+       </ul>
+     </description>
+   </release>
+ </releases>
+</component>
index 3950fc7bdb1a5620808defcaefb1ae1514c94229..39384f855ae937544b318d022798e33c0434937c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_ACTION_H
 #define G_ACTION_H
 
-
-#include "types.h"
 #include "midiEvent.h"
+#include "types.h"
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 struct Action
 {
-       ID        id = 0;  // Invalid
+       ID        id = 0; // Invalid
        ID        channelId;
        Frame     frame;
        MidiEvent event;
        ID        pluginId    = -1;
        int       pluginParam = -1;
-       ID        prevId = 0;
-       ID        nextId = 0;
-       
+       ID        prevId      = 0;
+       ID        nextId      = 0;
+
        const Action* prev = nullptr;
        const Action* next = nullptr;
 
-       bool isValid() const 
+       bool isValid() const
        {
                return id != 0;
-       }    
+       }
 
        bool isVolumeEnvelope() const
-       { 
-               return event.getStatus() == MidiEvent::ENVELOPE && pluginId == -1; 
+       {
+               return event.getStatus() == MidiEvent::ENVELOPE && pluginId == -1;
        }
 };
-
-}} // giada::m::
+} // namespace giada::m
 
 #endif
\ No newline at end of file
index 483e3c45d9e4152c62b9fa8e3ab034bd1d3af8a6..c117c5862eaeab7562cc763703d861a5ce4497a8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <algorithm>
 #include "audioBuffer.h"
+#include <algorithm>
+#include <cassert>
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 AudioBuffer::AudioBuffer()
-: m_data    (nullptr)
-, m_size    (0)
+: m_data(nullptr)
+, m_size(0)
 , m_channels(0)
+, m_viewing(false)
 {
 }
 
+/* -------------------------------------------------------------------------- */
 
 AudioBuffer::AudioBuffer(Frame size, int channels)
 : AudioBuffer()
@@ -47,64 +46,88 @@ AudioBuffer::AudioBuffer(Frame size, int channels)
        alloc(size, channels);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+AudioBuffer::AudioBuffer(float* data, Frame size, int channels)
+: m_data(data)
+, m_size(size)
+, m_channels(channels)
+, m_viewing(true)
+{
+       assert(channels <= NUM_CHANS);
+}
+
+/* -------------------------------------------------------------------------- */
 
 AudioBuffer::AudioBuffer(const AudioBuffer& o)
-: m_data    (new float[o.m_size * o.m_channels])
-, m_size    (o.m_size)
-, m_channels(o.m_channels)
 {
-       std::copy(o.m_data, o.m_data + (o.m_size * o.m_channels), m_data); 
+       copy(o);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+AudioBuffer::AudioBuffer(AudioBuffer&& o)
+{
+       move(std::move(o));
+}
+
+/* -------------------------------------------------------------------------- */
 
 AudioBuffer::~AudioBuffer()
 {
-       free();
+       if (!m_viewing)
+               free();
 }
 
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer& AudioBuffer::operator=(const AudioBuffer& o)
+{
+       if (this == &o)
+               return *this;
+       copy(o);
+       return *this;
+}
 
 /* -------------------------------------------------------------------------- */
 
+AudioBuffer& AudioBuffer::operator=(AudioBuffer&& o)
+{
+       if (this == &o)
+               return *this;
+       move(std::move(o));
+       return *this;
+}
+
+/* -------------------------------------------------------------------------- */
 
-float* AudioBuffer::operator [](Frame offset) const
+float* AudioBuffer::operator[](Frame offset) const
 {
        assert(m_data != nullptr);
        assert(offset < m_size);
        return m_data + (offset * m_channels);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void AudioBuffer::clear(Frame a, Frame b)
 {
        if (m_data == nullptr)
                return;
-       if (b == -1) b = m_size;
+       if (b == -1)
+               b = m_size;
        std::fill_n(m_data + (a * m_channels), (b - a) * m_channels, 0.0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Frame AudioBuffer::countFrames()   const { return m_size; }
-int   AudioBuffer::countSamples()  const { return m_size * m_channels; }
+Frame AudioBuffer::countFrames() const { return m_size; }
+int   AudioBuffer::countSamples() const { return m_size * m_channels; }
 int   AudioBuffer::countChannels() const { return m_channels; }
-bool  AudioBuffer::isAllocd()      const { return m_data != nullptr; }
-
-
+bool  AudioBuffer::isAllocd() const { return m_data != nullptr; }
 
 /* -------------------------------------------------------------------------- */
 
-
 float AudioBuffer::getPeak() const
 {
        float peak = 0.0f;
@@ -113,10 +136,8 @@ float AudioBuffer::getPeak() const
        return peak;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void AudioBuffer::alloc(Frame size, int channels)
 {
        assert(channels <= NUM_CHANS);
@@ -124,98 +145,127 @@ void AudioBuffer::alloc(Frame size, int channels)
        free();
        m_size     = size;
        m_channels = channels;
-       m_data     = new float[m_size * m_channels];    
+       m_data     = new float[m_size * m_channels];
        clear();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void AudioBuffer::free()
 {
+       if (m_data == nullptr)
+               return;
        delete[] m_data;
-       setData(nullptr, 0, 0);
+       m_data     = nullptr;
+       m_size     = 0;
+       m_channels = 0;
+       m_viewing  = false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void AudioBuffer::setData(float* data, Frame size, int channels)
+void AudioBuffer::sum(const AudioBuffer& b, Frame framesToCopy, Frame srcOffset,
+    Frame destOffset, float gain, Pan pan)
 {
-       assert(channels <= NUM_CHANS);
-
-       m_data     = data;
-       m_size     = size;
-       m_channels = channels;
+       copyData<Operation::SUM>(b, framesToCopy, srcOffset, destOffset, gain, pan);
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void AudioBuffer::moveData(AudioBuffer& b)
+void AudioBuffer::set(const AudioBuffer& b, Frame framesToCopy, Frame srcOffset,
+    Frame destOffset, float gain, Pan pan)
 {
-       assert(b.countChannels() <= NUM_CHANS);
+       copyData<Operation::SET>(b, framesToCopy, srcOffset, destOffset, gain, pan);
+}
 
-       free();
-       m_data     = b[0];
-       m_size     = b.countFrames();
-       m_channels = b.countChannels();
-       b.setData(nullptr, 0, 0);
+void AudioBuffer::sum(const AudioBuffer& b, float gain, Pan pan)
+{
+       copyData<Operation::SUM>(b, -1, 0, 0, gain, pan);
 }
 
+void AudioBuffer::set(const AudioBuffer& b, float gain, Pan pan)
+{
+       copyData<Operation::SET>(b, -1, 0, 0, gain, pan);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void AudioBuffer::copyData(const float* data, Frame frames, int channels, int offset)
+template <AudioBuffer::Operation O>
+void AudioBuffer::copyData(const AudioBuffer& b, Frame framesToCopy,
+    Frame srcOffset, Frame destOffset, float gain, Pan pan)
 {
-       assert(m_data != nullptr);
-       assert(frames <= m_size - offset);
+       const int  srcChannels  = b.countChannels();
+       const int  destChannels = countChannels();
+       const bool sameChannels = srcChannels == destChannels;
 
-       if (channels < NUM_CHANS) // i.e. one channel, mono
-               for (int i = offset, k = 0; i < m_size; i++, k++)
-                       for (int j = 0; j < countChannels(); j++)
-                               (*this)[i][j] = data[k];
-       else
-       if (channels == NUM_CHANS)
-               std::copy_n(data, frames * channels, m_data + (offset * channels));
-       else
-               assert(false);
+       assert(m_data != nullptr);
+       assert(destOffset >= 0 && destOffset < m_size);
+       assert(srcChannels <= destChannels);
+
+       /* Make sure the amount of frames to copy lies within the current buffer 
+       size. */
+
+       framesToCopy = framesToCopy == -1 ? b.countFrames() : framesToCopy;
+       framesToCopy = std::min(framesToCopy, m_size - destOffset);
+
+       /* Case 1) source has less channels than this one: brutally spread source's
+       channel 0 over this one (TODO - maybe mixdown source channels first?)
+          Case 2) source has same amount of channels: copy them 1:1. */
+
+       for (int destF = 0, srcF = srcOffset; destF < framesToCopy && destF < b.countFrames(); destF++, srcF++)
+       {
+               for (int ch = 0; ch < destChannels; ch++)
+               {
+                       if constexpr (O == Operation::SUM)
+                               sum(destF + destOffset, ch, b[srcF][sameChannels ? ch : 0] * gain * pan[ch]);
+                       else
+                               set(destF + destOffset, ch, b[srcF][sameChannels ? ch : 0] * gain * pan[ch]);
+               }
+       }
 }
 
+/* -------------------------------------------------------------------------- */
 
-void AudioBuffer::copyData(const AudioBuffer& b, float gain)
+void AudioBuffer::applyGain(float g)
 {
-       copyData(b[0], b.countFrames(), b.countChannels());
-       if (gain != 1.0f)
-               applyGain(gain);
+       for (int i = 0; i < countSamples(); i++)
+               m_data[i] *= g;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+void AudioBuffer::sum(Frame f, int channel, float val) { (*this)[f][channel] += val; }
+void AudioBuffer::set(Frame f, int channel, float val) { (*this)[f][channel] = val; }
+
+/* -------------------------------------------------------------------------- */
 
-void AudioBuffer::addData(const AudioBuffer& b, float gain, Pan pan)
+void AudioBuffer::move(AudioBuffer&& o)
 {
-       assert(m_data != nullptr);
-       assert(countFrames() <= b.countFrames());
-       assert(b.countChannels() <= NUM_CHANS);
+       assert(o.countChannels() <= NUM_CHANS);
 
-       for (int i = 0; i < countFrames(); i++)
-               for (int j = 0; j < countChannels(); j++)
-                       (*this)[i][j] += b[i][j] * gain * pan[j];
-}
+       m_data     = o.m_data;
+       m_size     = o.m_size;
+       m_channels = o.m_channels;
+       m_viewing  = o.m_viewing;
 
+       o.m_data     = nullptr;
+       o.m_size     = 0;
+       o.m_channels = 0;
+       o.m_viewing  = false;
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void AudioBuffer::applyGain(float g)
+void AudioBuffer::copy(const AudioBuffer& o)
 {
-       for (int i = 0; i < countSamples(); i++)
-               m_data[i] *= g;
+       m_data     = new float[o.m_size * o.m_channels];
+       m_size     = o.m_size;
+       m_channels = o.m_channels;
+       m_viewing  = o.m_viewing;
+
+       std::copy(o.m_data, o.m_data + (o.m_size * o.m_channels), m_data);
 }
-}} // giada::m::
\ No newline at end of file
+
+/* -------------------------------------------------------------------------- */
+
+template void AudioBuffer::copyData<AudioBuffer::Operation::SUM>(const AudioBuffer&, Frame, Frame, Frame, float, Pan);
+template void AudioBuffer::copyData<AudioBuffer::Operation::SET>(const AudioBuffer&, Frame, Frame, Frame, float, Pan);
+} // namespace giada::m
\ No newline at end of file
index 67247aa56d7c19be453b803dea0d3ac28cf84ca3..3ff25ec0a40786706ca5a96883c89f1121b44c95 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_AUDIO_BUFFER_H
 #define G_AUDIO_BUFFER_H
 
-
-#include <array>
 #include "core/types.h"
+#include <array>
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 /* AudioBuffer
 A class that holds a buffer filled with audio data. NOTE: currently it only
@@ -44,7 +40,6 @@ stereo. Give it a multichannel stream and it will throw an assertion. */
 class AudioBuffer
 {
 public:
-       
        static constexpr int NUM_CHANS = 2;
 
        using Pan = std::array<float, NUM_CHANS>;
@@ -59,9 +54,37 @@ public:
 
        AudioBuffer(Frame size, int channels);
 
+       /* AudioBuffer (3)
+       Creates an audio buffer out of a raw pointer. AudioBuffer created this way
+       is instructed not to free the owned data on destruction. */
+
+       AudioBuffer(float* data, Frame size, int channels);
+
+       /* AudioBuffer(const AudioBuffer&)
+       Copy constructor. */
+
        AudioBuffer(const AudioBuffer& o);
+
+       /* AudioBuffer(AudioBuffer&&)
+       Move constructor. */
+
+       AudioBuffer(AudioBuffer&& o);
+
+       /* ~AudioBuffer
+       Destructor. */
+
        ~AudioBuffer();
 
+       /* operator = (const AudioBuffer& o)
+       Copy assignment operator. */
+
+       AudioBuffer& operator=(const AudioBuffer& o);
+
+       /* operator = (AudioBuffer&& o)
+       Move assignment operator. */
+
+       AudioBuffer& operator=(AudioBuffer&& o);
+
        /* operator []
        Given a frame 'offset', returns a pointer to it. This is useful for digging 
        inside a frame, i.e. parsing each channel. How to use it:
@@ -73,69 +96,69 @@ public:
        Also note that buffer[0] will give you a pointer to the whole internal data
        array. */
 
-       float* operator [](int offset) const;
+       float* operator[](int offset) const;
 
        Frame countFrames() const;
-       int countSamples() const;
-       int countChannels() const;
-       bool isAllocd() const;
+       int   countSamples() const;
+       int   countChannels() const;
+       bool  isAllocd() const;
 
        /* getPeak
        Returns the highest value from any channel. */
-       
+
        float getPeak() const;
 
        void alloc(Frame size, int channels);
        void free();
 
-       /* copyData (1)
-       Copies 'frames' frames from the new 'data' into m_data, and fills m_data 
-       starting from frame 'offset'. The new data MUST NOT contain more than
-       NUM_CHANS channels. If channels < NUM_CHANS, they will be spread over the
-       stereo buffer. */
-
-       void copyData(const float* data, Frame frames, int channels=NUM_CHANS, int offset=0);
+       /* sum, set (1)
+       Merges (sum) or copies (set) 'framesToCopy' frames of buffer 'b' onto this 
+       one. If 'framesToCopy' is -1 the whole buffer will be copied. If 'b' has 
+       less channels than this one, they will be spread over the current ones. 
+       Buffer 'b' MUST NOT contain more channels than this one. */
 
-       /* copyData (2)
-       Copies buffer 'b' onto this one. If 'b' has less channels than this one,
-       they will be spread over the current ones. Buffer 'b' MUST NOT contain more
-       channels than this one.  */
+       void sum(const AudioBuffer& b, Frame framesToCopy = -1, Frame srcOffset = 0,
+           Frame destOffset = 0, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
+       void set(const AudioBuffer& b, Frame framesToCopy = -1, Frame srcOffset = 0,
+           Frame destOffset = 0, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
 
-       void copyData(const AudioBuffer& b, float gain=1.0f);
+       /* sum, set (2)
+       Same as sum, set (1) without boundaries or offsets: it just copies as much
+       as possibile. */
 
-       /* addData
-       Merges audio data from buffer 'b' onto this one. Applies optional gain and
-       pan if needed. */
-
-       void addData(const AudioBuffer& b, float gain=1.0f, Pan pan={1.0f, 1.0f});
-
-       /* setData
-       Views 'data' as new m_data. Makes sure not to delete the data 'data' points
-       to while using it. Set it back to nullptr when done. */
-
-       void setData(float* data, Frame size, int channels);
-
-       /* moveData
-       Moves data held by 'b' into this buffer. Then 'b' becomes an empty buffer.
-       TODO - add move constructor instead! */
-        
-       void moveData(AudioBuffer& b);
+       void sum(const AudioBuffer& b, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
+       void set(const AudioBuffer& b, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
 
        /* clear
        Clears the internal data by setting all bytes to 0.0f. Optional parameters
        'a' and 'b' set the range. */
-       
-       void clear(Frame a=0, Frame b=-1);
+
+       void clear(Frame a = 0, Frame b = -1);
 
        void applyGain(float g);
 
 private:
+       enum class Operation
+       {
+               SUM,
+               SET
+       };
+
+       template <Operation O = Operation::SET>
+       void copyData(const AudioBuffer& b, Frame framesToCopy = -1,
+           Frame srcOffset = 0, Frame destOffset = 0, float gain = 1.0f,
+           Pan pan = {1.0f, 1.0f});
+
+       void move(AudioBuffer&& o);
+       void copy(const AudioBuffer& o);
+       void sum(Frame f, int channel, float val);
+       void set(Frame f, int channel, float val);
 
        float* m_data;
        Frame  m_size;
        int    m_channels;
+       bool   m_viewing;
 };
-
-}} // giada::m::
+} // namespace giada::m
 
 #endif
\ No newline at end of file
index dd222e65eec8d90a76b2f29cb244889b8e1261b0..dc785f60ce0d57704931d0e79276e07b0865fedb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/channels/state.h"
 #include "audioReceiver.h"
+#include "core/channels/channel.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m::audioReceiver
 {
-AudioReceiver::AudioReceiver(ChannelState* c, const conf::Conf& conf)
-: state         (std::make_unique<AudioReceiverState>(conf))
-, m_channelState(c)
+Data::Data(const patch::Channel& p)
+: inputMonitor(p.inputMonitor)
+, overdubProtection(p.overdubProtection)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-AudioReceiver::AudioReceiver(const patch::Channel& p, ChannelState* c)
-: state         (std::make_unique<AudioReceiverState>(p))
-, m_channelState(c)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-AudioReceiver::AudioReceiver(const AudioReceiver& o, ChannelState* c)
-: state         (std::make_unique<AudioReceiverState>(*o.state))
-, m_channelState(c)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void AudioReceiver::render(const AudioBuffer& in) const
+void render(const channel::Data& ch, const AudioBuffer& in)
 {
        /* If armed and input monitor is on, copy input buffer to channel buffer: 
        this enables the input monitoring. The channel buffer will be overwritten 
        later on by pluginHost::processStack, so that you would record "clean" audio 
        (i.e. not plugin-processed). */
 
-       bool armed        = m_channelState->armed.load();
-       bool inputMonitor = state->inputMonitor.load();
-
-       if (armed && inputMonitor)
-               m_channelState->buffer.addData(in);  // add, don't overwrite
+       if (ch.armed && ch.audioReceiver->inputMonitor)
+               ch.buffer->audio.set(in, /*gain=*/1.0f); // add, don't overwrite
 }
-}} // giada::m::
+} // namespace giada::m::audioReceiver
\ No newline at end of file
index 443bd3c09ec30b0f5000a8bf4f055a74fa073f3d..f04a1247d62946ddfed3545f6a770decdfc6f9f4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_AUDIO_RECEIVER_H
 #define G_CHANNEL_AUDIO_RECEIVER_H
 
-
-#include <memory>
-
-
-namespace giada {
-namespace m
+namespace giada::m
 {
-namespace conf
+class AudioBuffer;
+}
+namespace giada::m::channel
 {
-struct Conf;
+struct Data;
 }
-namespace patch
+namespace giada::m::patch
 {
-struct Channel; 
+struct Channel;
 }
-class  AudioBuffer;
-struct ChannelState;
-struct AudioReceiverState;
-
-/* AudioReceiver 
-Operates on input audio streams for audio recording and input monitor. */
-
-class AudioReceiver
+namespace giada::m::audioReceiver
 {
-public:
-
-    AudioReceiver(ChannelState*, const conf::Conf&);
-    AudioReceiver(const patch::Channel&, ChannelState*);
-    AudioReceiver(const AudioReceiver&, ChannelState* c=nullptr);
-
-    void render(const AudioBuffer& in) const;
-
-    /* state
-    Pointer to mutable AudioReceiverState state. */
-
-    std::unique_ptr<AudioReceiverState> state;
-
-private:
+struct Data
+{
+       Data() = default;
+       Data(const patch::Channel& p);
+       Data(const Data& o) = default;
 
-    ChannelState* m_channelState;
+       bool inputMonitor;
+       bool overdubProtection;
 };
-}} // giada::m::
 
+void render(const channel::Data& ch, const AudioBuffer& in);
+} // namespace giada::m::audioReceiver
 
 #endif
index 8c7845bbf2f16dc59f9d13c0d2a6365f0134ce03..2d90efcd87a6b8a133e012d065f65f9bff4927a6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/channels/state.h"
+#include "channel.h"
 #include "core/mixerHandler.h"
 #include "core/plugins/pluginHost.h"
-#include "channel.h"
-
+#include "core/plugins/pluginManager.h"
+#include <cassert>
 
-namespace giada {
-namespace m 
+namespace giada::m::channel
 {
-Channel::Channel(ChannelType type, ID id, ID columnId, Frame bufferSize, const conf::Conf& conf)
-: id         (id)
-, state      (std::make_unique<ChannelState>(id, bufferSize))
-, midiLighter(state.get())
-, m_type     (type)
-, m_columnId (columnId)
+namespace
 {
-       switch (m_type) {
-
-               case ChannelType::SAMPLE:
-                       samplePlayer.emplace(state.get());
-                       audioReceiver.emplace(state.get(), conf);
-                       sampleActionRecorder.emplace(state.get(), samplePlayer->state.get());   
-                       break;
-               
-               case ChannelType::PREVIEW:
-                       samplePlayer.emplace(state.get());
-                       break;
-               
-               case ChannelType::MIDI:
-                       midiController.emplace(state.get());
-#ifdef WITH_VST
-                       midiReceiver.emplace(state.get());
-#endif
-                       midiSender.emplace(state.get());
-                       midiActionRecorder.emplace(state.get());                
-                       break;  
-               
-               default: break;
-       }
-}
+AudioBuffer::Pan calcPanning_(float pan)
+{
+       /* TODO - precompute the AudioBuffer::Pan when pan value changes instead of
+       building it on the fly. */
 
+       /* Center pan (0.5f)? Pass-through. */
 
-/* -------------------------------------------------------------------------- */
+       if (pan == 0.5f)
+               return {1.0f, 1.0f};
+       return {1.0f - pan, pan};
+}
 
+/* -------------------------------------------------------------------------- */
 
-Channel::Channel(const Channel& o)
-: id            (o.id)
-#ifdef WITH_VST
-, pluginIds     (o.pluginIds)
-#endif
-, state         (std::make_unique<ChannelState>(*o.state))
-, midiLearner   (o.midiLearner)
-, midiLighter   (o.midiLighter, state.get())
-, m_type        (o.m_type)
-, m_columnId    (o.m_columnId)
+void react_(Data& d, const eventDispatcher::Event& e)
 {
-       switch (m_type) {
-
-               case ChannelType::SAMPLE:
-                       samplePlayer.emplace(o.samplePlayer.value(), state.get());
-                       audioReceiver.emplace(o.audioReceiver.value(), state.get());
-                       sampleActionRecorder.emplace(o.sampleActionRecorder.value(), state.get(), samplePlayer->state.get());
-                       break;
-               
-               case ChannelType::PREVIEW:
-                       samplePlayer.emplace(o.samplePlayer.value(), state.get());
-                       break;
-               
-               case ChannelType::MIDI:
-                       midiController.emplace(o.midiController.value(), state.get());
-#ifdef WITH_VST
-                       midiReceiver.emplace(o.midiReceiver.value(), state.get());
-#endif
-                       midiSender.emplace(o.midiSender.value(), state.get());
-                       midiActionRecorder.emplace(o.midiActionRecorder.value(), state.get());
-                       break;
-
-               default: break;
+       switch (e.type)
+       {
+       case eventDispatcher::EventType::CHANNEL_VOLUME:
+               d.volume = std::get<float>(e.data);
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_PAN:
+               d.pan = std::get<float>(e.data);
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_MUTE:
+               d.mute = !d.mute;
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_TOGGLE_ARM:
+               d.armed = !d.armed;
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_SOLO:
+               d.solo = !d.solo;
+               m::mh::updateSoloCount();
+               break;
+
+       default:
+               break;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Channel::Channel(const patch::Channel& p, Frame bufferSize)
-: id            (p.id)
-#ifdef WITH_VST
-, pluginIds     (p.pluginIds)
-#endif
-, state         (std::make_unique<ChannelState>(p, bufferSize))
-, midiLearner   (p)
-, midiLighter   (p, state.get())
-, m_type        (p.type)
-, m_columnId    (p.columnId)
+void renderMasterOut_(const Data& d, AudioBuffer& out)
 {
-       switch (m_type) {
-
-               case ChannelType::SAMPLE:
-                       samplePlayer.emplace(p, state.get());
-                       audioReceiver.emplace(p, state.get());
-                       sampleActionRecorder.emplace(state.get(), samplePlayer->state.get());
-                       break;
-               
-               case ChannelType::PREVIEW:
-                       samplePlayer.emplace(p, state.get());
-                       break;
-               
-               case ChannelType::MIDI:
-                       midiController.emplace(state.get());
+       d.buffer->audio.set(out, /*gain=*/1.0f);
 #ifdef WITH_VST
-                       midiReceiver.emplace(p, state.get());
+       if (d.plugins.size() > 0)
+               pluginHost::processStack(d.buffer->audio, d.plugins, nullptr);
 #endif
-                       midiSender.emplace(p, state.get());
-                       midiActionRecorder.emplace(state.get());        
-                       break;  
-               
-               default: break;
-       }
+       out.set(d.buffer->audio, d.volume);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void Channel::parse(const mixer::EventBuffer& events, bool audible) const
+void renderMasterIn_(const Data& d, AudioBuffer& in)
 {
-       for (const mixer::Event& e : events) {
-
-               if (e.action.channelId > 0 && e.action.channelId != id)
-                       continue;
-
-               parse(e);
-               midiLighter.parse(e, audible);
-
-               if (midiController)       midiController->parse(e);
 #ifdef WITH_VST
-               if (midiReceiver)         midiReceiver->parse(e);
+       if (d.plugins.size() > 0)
+               pluginHost::processStack(in, d.plugins, nullptr);
 #endif
-               if (midiSender)           midiSender->parse(e);
-               if (samplePlayer)         samplePlayer->parse(e);
-               if (midiActionRecorder)   midiActionRecorder->parse(e);
-               if (sampleActionRecorder && samplePlayer && samplePlayer->hasWave()) 
-                       sampleActionRecorder->parse(e);
-       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void Channel::advance(Frame bufferSize) const
+void renderChannel_(const Data& d, AudioBuffer& out, AudioBuffer& in, bool audible)
 {
-       /* TODO - this is used only to advance samplePlayer for its quantizer. Use
-       this to render actions in the future. */
-
-       if (samplePlayer) samplePlayer->advance(bufferSize);
-}
+       d.buffer->audio.clear();
 
+       if (d.samplePlayer)
+               samplePlayer::render(d);
+       if (d.audioReceiver)
+               audioReceiver::render(d, in);
 
-/* -------------------------------------------------------------------------- */
+               /* If MidiReceiver exists, let it process the plug-in stack, as it can 
+       contain plug-ins that take MIDI events (i.e. synths). Otherwise process the
+       plug-in stack internally with no MIDI events. */
 
+#ifdef WITH_VST
+       if (d.midiReceiver)
+               midiReceiver::render(d);
+       else if (d.plugins.size() > 0)
+               pluginHost::processStack(d.buffer->audio, d.plugins, nullptr);
+#endif
 
-void Channel::render(AudioBuffer* out, AudioBuffer* in, bool audible) const
-{
-       if (id == mixer::MASTER_OUT_CHANNEL_ID)
-               renderMasterOut(*out);
-       else
-       if (id == mixer::MASTER_IN_CHANNEL_ID)
-               renderMasterIn(*in);
-       else 
-               renderChannel(*out, *in, audible);
+       if (audible)
+               out.sum(d.buffer->audio, d.volume * d.volume_i, calcPanning_(d.pan));
 }
-
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void Channel::parse(const mixer::Event& e) const
+Buffer::Buffer(Frame bufferSize)
+: audio(bufferSize, G_MAX_IO_CHANS)
 {
-       switch (e.type) {
-
-               case mixer::EventType::CHANNEL_VOLUME:
-                       state->volume.store(e.action.event.getVelocityFloat()); break;
-
-               case mixer::EventType::CHANNEL_PAN:
-                       state->pan.store(e.action.event.getVelocityFloat()); break;
-
-               case mixer::EventType::CHANNEL_MUTE:
-                       state->mute.store(!state->mute.load()); break;
-
-               case mixer::EventType::CHANNEL_TOGGLE_ARM:
-                       state->armed.store(!state->armed.load()); break;
-                       
-               case mixer::EventType::CHANNEL_SOLO:
-                       state->solo.store(!state->solo.load()); 
-                       m::mh::updateSoloCount(); 
-                       break;
-
-               default: break;
-       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void Channel::renderMasterOut(AudioBuffer& out) const
+Data::Data(ChannelType type, ID id, ID columnId, State& state, Buffer& buffer)
+: state(&state)
+, buffer(&buffer)
+, id(id)
+, type(type)
+, columnId(columnId)
+, volume(G_DEFAULT_VOL)
+, volume_i(G_DEFAULT_VOL)
+, pan(G_DEFAULT_PAN)
+, mute(false)
+, solo(false)
+, armed(false)
+, key(0)
+, hasActions(false)
+, height(G_GUI_UNIT)
 {
-       state->buffer.copyData(out);
+       switch (type)
+       {
+       case ChannelType::SAMPLE:
+               samplePlayer.emplace(&state.resampler.value());
+               sampleReactor.emplace(id);
+               audioReceiver.emplace();
+               sampleActionRecorder.emplace();
+               break;
+
+       case ChannelType::PREVIEW:
+               samplePlayer.emplace(&state.resampler.value());
+               sampleReactor.emplace(id);
+               break;
+
+       case ChannelType::MIDI:
+               midiController.emplace();
+               midiSender.emplace();
+               midiActionRecorder.emplace();
 #ifdef WITH_VST
-       if (pluginIds.size() > 0)
-               pluginHost::processStack(state->buffer, pluginIds, nullptr);
+               midiReceiver.emplace();
 #endif
-       out.copyData(state->buffer, state->volume.load());
-}
+               break;
 
+       default:
+               break;
+       }
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void Channel::renderMasterIn(AudioBuffer& in) const
-{
+Data::Data(const patch::Channel& p, State& state, Buffer& buffer, float samplerateRatio)
+: state(&state)
+, buffer(&buffer)
+, id(p.id)
+, type(p.type)
+, columnId(p.columnId)
+, volume(p.volume)
+, volume_i(G_DEFAULT_VOL)
+, pan(p.pan)
+, mute(p.mute)
+, solo(p.solo)
+, armed(p.armed)
+, key(p.key)
+, hasActions(p.hasActions)
+, name(p.name)
+, height(p.height)
 #ifdef WITH_VST
-       if (pluginIds.size() > 0)
-               pluginHost::processStack(in, pluginIds, nullptr);
+, plugins(pluginManager::hydratePlugins(p.pluginIds))
 #endif
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Channel::renderChannel(AudioBuffer& out, AudioBuffer& in, bool audible) const
+, midiLearner(p)
 {
-       state->buffer.clear();
-
-       if (samplePlayer)  samplePlayer->render(out);
-       if (audioReceiver) audioReceiver->render(in);
-
-       /* If MidiReceiver exists, let it process the plug-in stack, as it can 
-       contain plug-ins that take MIDI events (i.e. synths). Otherwise process the
-       plug-in stack internally with no MIDI events. */
-
+       state.readActions.store(p.readActions);
+       state.recStatus.store(p.readActions ? ChannelStatus::PLAY : ChannelStatus::OFF);
+
+       switch (type)
+       {
+       case ChannelType::SAMPLE:
+               samplePlayer.emplace(p, samplerateRatio, &state.resampler.value());
+               sampleReactor.emplace(id);
+               audioReceiver.emplace(p);
+               sampleActionRecorder.emplace();
+               break;
+
+       case ChannelType::PREVIEW:
+               samplePlayer.emplace(p, samplerateRatio, &state.resampler.value());
+               sampleReactor.emplace(id);
+               break;
+
+       case ChannelType::MIDI:
+               midiController.emplace();
+               midiSender.emplace(p);
+               midiActionRecorder.emplace();
 #ifdef WITH_VST
-       if (midiReceiver)  
-               midiReceiver->render(pluginIds); 
-       else 
-       if (pluginIds.size() > 0)
-               pluginHost::processStack(state->buffer, pluginIds, nullptr);
+               midiReceiver.emplace();
 #endif
+               break;
 
-       if (audible)
-           out.addData(state->buffer, state->volume.load() * state->volume_i, calcPanning());
+       default:
+               break;
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-AudioBuffer::Pan Channel::calcPanning() const
+bool Data::operator==(const Data& other)
 {
-       /* TODO - precompute the AudioBuffer::Pan when pan value changes instead of
-       building it on the fly. */
-       
-       float pan = state->pan.load();
-
-       /* Center pan (0.5f)? Pass-through. */
-
-       if (pan == 0.5f) return { 1.0f, 1.0f };
-       return { 1.0f - pan, pan };
+       return id == other.id;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+bool Data::isInternal() const
+{
+       return type == ChannelType::MASTER || type == ChannelType::PREVIEW;
+}
 
-ID Channel::getColumnId() const { return m_columnId; }
-ChannelType Channel::getType() const { return m_type; }
+bool Data::isMuted() const
+{
+       /* Internals can't be muted. */
+       return !isInternal() && mute;
+}
 
+bool Data::canInputRec() const
+{
+       if (type != ChannelType::SAMPLE)
+               return false;
 
-/* -------------------------------------------------------------------------- */
+       bool hasWave     = samplePlayer->hasWave();
+       bool isProtected = audioReceiver->overdubProtection;
+       bool canOverdub  = !hasWave || (hasWave && !isProtected);
 
+       return armed && canOverdub;
+}
 
-bool Channel::isInternal() const
+bool Data::canActionRec() const
 {
-       return m_type == ChannelType::MASTER || m_type == ChannelType::PREVIEW;
+       return hasWave() && !samplePlayer->isAnyLoopMode();
 }
 
-
-bool Channel::isMuted() const
+bool Data::hasWave() const
 {
-       /* Internals can't be muted. */
-       return !isInternal() && state->mute.load() == true;
+       return samplePlayer && samplePlayer->hasWave();
 }
 
+bool Data::isPlaying() const
+{
+       ChannelStatus s = state->playStatus.load();
+       return s == ChannelStatus::PLAY || s == ChannelStatus::ENDING;
+}
 
-bool Channel::canInputRec() const
+bool Data::isReadingActions() const
 {
-       if (m_type != ChannelType::SAMPLE)
-               return false;
+       ChannelStatus s = state->recStatus.load();
+       return s == ChannelStatus::PLAY || s == ChannelStatus::ENDING;
+}
 
-       bool armed       = state->armed.load();
-       bool hasWave     = samplePlayer->hasWave();
-       bool isProtected = audioReceiver->state->overdubProtection.load();
-       bool canOverdub  = !hasWave || (hasWave && !isProtected);
+/* -------------------------------------------------------------------------- */
 
-       return armed && canOverdub;
+void advance(const Data& d, const sequencer::EventBuffer& events)
+{
+       for (const sequencer::Event& e : events)
+       {
+               if (d.midiController)
+                       midiController::advance(d, e);
+               if (d.samplePlayer)
+                       samplePlayer::advance(d, e);
+               if (d.midiSender)
+                       midiSender::advance(d, e);
+#ifdef WITH_VST
+               if (d.midiReceiver)
+                       midiReceiver::advance(d, e);
+#endif
+       }
 }
 
+/* -------------------------------------------------------------------------- */
 
-bool Channel::canActionRec() const
+void react(Data& d, const eventDispatcher::EventBuffer& events, bool audible)
 {
-       return hasWave() && !samplePlayer->state->isAnyLoopMode();
+       for (const eventDispatcher::Event& e : events)
+       {
+               if (e.channelId > 0 && e.channelId != d.id)
+                       continue;
+
+               react_(d, e);
+               midiLighter::react(d, e, audible);
+
+               if (d.midiController)
+                       midiController::react(d, e);
+               if (d.midiSender)
+                       midiSender::react(d, e);
+               if (d.samplePlayer)
+                       samplePlayer::react(d, e);
+               if (d.midiActionRecorder)
+                       midiActionRecorder::react(d, e);
+               if (d.sampleActionRecorder)
+                       sampleActionRecorder::react(d, e);
+               if (d.sampleReactor)
+                       sampleReactor::react(d, e);
+#ifdef WITH_VST
+               if (d.midiReceiver)
+                       midiReceiver::react(d, e);
+#endif
+       }
 }
 
+/* -------------------------------------------------------------------------- */
 
-bool Channel::hasWave() const
+void render(const Data& d, AudioBuffer* out, AudioBuffer* in, bool audible)
 {
-       return m_type == ChannelType::SAMPLE && samplePlayer->hasWave();
+       if (d.id == mixer::MASTER_OUT_CHANNEL_ID)
+               renderMasterOut_(d, *out);
+       else if (d.id == mixer::MASTER_IN_CHANNEL_ID)
+               renderMasterIn_(d, *in);
+       else
+               renderChannel_(d, *out, *in, audible);
 }
-}} // giada::m::
+} // namespace giada::m::channel
\ No newline at end of file
index 5e7b9127629dffbc1a1eef68091c9723f666597f..1273e00cebb00765b27861fc016abf34225fd1d1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_H
 #define G_CHANNEL_H
 
-
 #include <optional>
-#include "core/const.h"
-#include "core/mixer.h"
-#include "core/channels/state.h"
-#include "core/channels/samplePlayer.h"
-#include "core/channels/audioReceiver.h"
 #ifdef WITH_VST
-#include "core/channels/midiReceiver.h"
+#include "deps/juce-config.h"
 #endif
-#include "core/channels/midiLearner.h"
-#include "core/channels/midiSender.h"
+#include "core/audioBuffer.h"
+#include "core/channels/audioReceiver.h"
+#include "core/channels/midiActionRecorder.h"
 #include "core/channels/midiController.h"
+#include "core/channels/midiLearner.h"
 #include "core/channels/midiLighter.h"
+#include "core/channels/midiSender.h"
 #include "core/channels/sampleActionRecorder.h"
-#include "core/channels/midiActionRecorder.h"
-
+#include "core/channels/samplePlayer.h"
+#include "core/const.h"
+#include "core/eventDispatcher.h"
+#include "core/mixer.h"
+#include "core/resampler.h"
+#include "core/sequencer.h"
+#ifdef WITH_VST
+#include "core/channels/midiReceiver.h"
+#endif
 
-namespace giada {
-namespace m
-{
-namespace conf
+namespace giada::m
 {
-struct Conf;
+class Plugin;
 }
-class Channel final
+namespace giada::m::channel
 {
-public:
-
-    Channel(ChannelType t, ID id, ID columnId, Frame bufferSize, const conf::Conf& c);
-    Channel(const Channel&);
-    Channel(const patch::Channel& p, Frame bufferSize);
-    Channel(Channel&&)                 = default;
-    Channel& operator=(const Channel&) = delete;
-    Channel& operator=(Channel&&)      = delete;
-    ~Channel()                         = default;
-
-    /* parse
-    Parses live events. */
-
-    void parse(const mixer::EventBuffer& e, bool audible) const;
-
-    /* advance
-    Processes static events (e.g. actions) in the current block. */
-
-    void advance(Frame bufferSize) const;
-
-    /* render
-    Renders audio data to I/O buffers. */
-     
-    void render(AudioBuffer* out, AudioBuffer* in, bool audible) const;
+struct State
+{
+       WeakAtomic<Frame>         tracker     = 0;
+       WeakAtomic<ChannelStatus> playStatus  = ChannelStatus::OFF;
+       WeakAtomic<ChannelStatus> recStatus   = ChannelStatus::OFF;
+       WeakAtomic<bool>          readActions = false;
+       bool                      rewinding   = false;
+       Frame                     offset      = 0;
+
+       /* Optional resampler for sample-based channels. Unfortunately a Resampler
+       object (based on libsamplerate) doesn't like to get copied while rendering
+       audio, so can't live inside WaveReader object (which is copied on model 
+       changes by the Swapper mechanism). Let's put it in the shared state here. */
+
+       std::optional<Resampler> resampler = {};
+};
 
-    bool isInternal() const;
-    bool isMuted() const;
-    bool canInputRec() const;
-    bool canActionRec() const;
-    bool hasWave() const;
-    ID getColumnId() const;
-    ChannelType getType() const;
-    
-    ID id;
+struct Buffer
+{
+       Buffer(Frame bufferSize);
 
+       AudioBuffer audio;
 #ifdef WITH_VST
-    std::vector<ID> pluginIds;
+       juce::MidiBuffer midi;
 #endif
+};
 
-    /* state
-    Pointer to mutable Channel state. */
-
-    std::unique_ptr<ChannelState> state;
+struct Data
+{
+       Data(ChannelType t, ID id, ID columnId, State& state, Buffer& buffer);
+       Data(const patch::Channel& p, State& state, Buffer& buffer, float samplerateRatio);
+       Data(const Data& o) = default;
+       Data(Data&& o)      = default;
+       Data& operator=(const Data&) = default;
+       Data& operator=(Data&&) = default;
+
+       bool operator==(const Data&);
+
+       bool isPlaying() const;
+       bool isReadingActions() const;
+       bool isInternal() const;
+       bool isMuted() const;
+       bool canInputRec() const;
+       bool canActionRec() const;
+       bool hasWave() const;
+
+       State*      state;
+       Buffer*     buffer;
+       ID          id;
+       ChannelType type;
+       ID          columnId;
+       float       volume;
+       float       volume_i; // Internal volume used for velocity-drives-volume mode on Sample Channels
+       float       pan;
+       bool        mute;
+       bool        solo;
+       bool        armed;
+       int         key;
+       bool        hasActions;
+       std::string name;
+       Pixel       height;
+#ifdef WITH_VST
+       std::vector<Plugin*> plugins;
+#endif
 
-    MidiLearner midiLearner;
-    MidiLighter midiLighter;
+       midiLearner::Data midiLearner;
+       midiLighter::Data midiLighter;
 
-    std::optional<SamplePlayer>         samplePlayer;
-    std::optional<AudioReceiver>        audioReceiver;
-    std::optional<MidiController>       midiController;
+       std::optional<samplePlayer::Data>   samplePlayer;
+       std::optional<sampleReactor::Data>  sampleReactor;
+       std::optional<audioReceiver::Data>  audioReceiver;
+       std::optional<midiController::Data> midiController;
 #ifdef WITH_VST
-    std::optional<MidiReceiver>         midiReceiver;
+       std::optional<midiReceiver::Data> midiReceiver;
 #endif
-    std::optional<MidiSender>           midiSender;
-    std::optional<SampleActionRecorder> sampleActionRecorder;
-    std::optional<MidiActionRecorder>   midiActionRecorder;
+       std::optional<midiSender::Data>           midiSender;
+       std::optional<sampleActionRecorder::Data> sampleActionRecorder;
+       std::optional<midiActionRecorder::Data>   midiActionRecorder;
+};
 
-private:
+/* advance
+Advances internal state by processing static events (e.g. pre-recorded 
+actions or sequencer events) in the current block. */
 
-    void parse(const mixer::Event& e) const;
+void advance(const Data& d, const sequencer::EventBuffer& e);
 
-    void renderMasterOut(AudioBuffer& out) const;
-    void renderMasterIn(AudioBuffer& in) const;
-    void renderChannel(AudioBuffer& out, AudioBuffer& in, bool audible) const;
+/* react
+Reacts to live events coming from the EventDispatcher (human events) and
+updates itself accordingly. */
 
-    AudioBuffer::Pan calcPanning() const;
+void react(Data& d, const eventDispatcher::EventBuffer& e, bool audible);
 
-    ChannelType m_type;
-    ID m_columnId;
-};
-}} // giada::m::
+/* render
+Renders audio data to I/O buffers. */
 
+void render(const Data& d, AudioBuffer* out, AudioBuffer* in, bool audible);
+} // namespace giada::m::channel
 
 #endif
index bbf3bceec1341fc70cbf870eaa541b05969e3f40..489106f19c1641d42f66bac6b216eb8604efef49 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "utils/fs.h"
+#include "channelManager.h"
+#include "core/action.h"
 #include "core/channels/channel.h"
 #include "core/channels/samplePlayer.h"
+#include "core/conf.h"
 #include "core/const.h"
+#include "core/idManager.h"
 #include "core/kernelAudio.h"
-#include "core/patch.h"
 #include "core/mixer.h"
-#include "core/idManager.h"
-#include "core/wave.h"
-#include "core/waveManager.h"
+#include "core/model/model.h"
+#include "core/patch.h"
+#include "core/plugins/plugin.h"
 #include "core/plugins/pluginHost.h"
 #include "core/plugins/pluginManager.h"
-#include "core/plugins/plugin.h"
-#include "core/action.h"
 #include "core/recorderHandler.h"
-#include "channelManager.h"
-
+#include "core/wave.h"
+#include "core/waveManager.h"
+#include "utils/fs.h"
+#include <cassert>
 
-namespace giada {
-namespace m {
-namespace channelManager
+namespace giada::m::channelManager
 {
 namespace
 {
 IdManager channelId_;
-} // {anonymous}
 
+/* -------------------------------------------------------------------------- */
+
+channel::State& makeState_(ChannelType type)
+{
+       std::unique_ptr<channel::State> state = std::make_unique<channel::State>();
+
+       if (type == ChannelType::SAMPLE || type == ChannelType::PREVIEW)
+               state->resampler = Resampler(static_cast<Resampler::Quality>(conf::conf.rsmpQuality), G_MAX_IO_CHANS);
+
+       model::add(std::move(state));
+       return model::back<channel::State>();
+}
+
+/* -------------------------------------------------------------------------- */
+
+channel::Buffer& makeBuffer_()
+{
+       model::add(std::make_unique<channel::Buffer>(kernelAudio::getRealBufSize()));
+       return model::back<channel::Buffer>();
+}
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
-
 
 void init()
 {
        channelId_ = IdManager();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-std::unique_ptr<Channel> create(ChannelType type, ID columnId, const conf::Conf& conf)
+channel::Data create(ID channelId, ChannelType type, ID columnId)
 {
-       std::unique_ptr<Channel> ch = std::make_unique<Channel>(type, 
-               channelId_.get(), columnId, kernelAudio::getRealBufSize(), conf);
-       
-       return ch;
-}
+       channel::Data out = channel::Data(type, channelId_.generate(channelId),
+           columnId, makeState_(type), makeBuffer_());
 
+       if (out.audioReceiver)
+               out.audioReceiver->overdubProtection = conf::conf.overdubProtectionDefaultOn;
 
-/* -------------------------------------------------------------------------- */
+       return out;
+}
 
+/* -------------------------------------------------------------------------- */
 
-std::unique_ptr<Channel> create(const Channel& o)
+channel::Data create(const channel::Data& o)
 {
-       std::unique_ptr<Channel> ch = std::make_unique<Channel>(o);
-       ID id = channelId_.get();
-       ch->id        = id;
-       ch->state->id = id;
-       return ch;
-}
+       channel::Data out = channel::Data(o);
 
+       out.id     = channelId_.generate();
+       out.state  = &makeState_(o.type);
+       out.buffer = &makeBuffer_();
 
-/* -------------------------------------------------------------------------- */
+       return out;
+}
 
+/* -------------------------------------------------------------------------- */
 
-std::unique_ptr<Channel> deserializeChannel(const patch::Channel& pch, int bufferSize)
+channel::Data deserializeChannel(const patch::Channel& pch, float samplerateRatio)
 {
        channelId_.set(pch.id);
-       return std::make_unique<Channel>(pch, bufferSize);
+       return channel::Data(pch, makeState_(pch.type), makeBuffer_(), samplerateRatio);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-const patch::Channel serializeChannel(const Channel& c)
+const patch::Channel serializeChannel(const channel::Data& c)
 {
        patch::Channel pc;
 
 #ifdef WITH_VST
-       for (ID pid : c.pluginIds)
-               pc.pluginIds.push_back(pid);
+       for (const Plugin* p : c.plugins)
+               pc.pluginIds.push_back(p->id);
 #endif
 
        pc.id                = c.id;
-       pc.type              = c.getType();
-    pc.columnId          = c.getColumnId();
-    pc.height            = c.state->height;
-    pc.name              = c.state->name;
-    pc.key               = c.state->key.load();
-    pc.mute              = c.state->mute.load();
-    pc.solo              = c.state->solo.load();
-    pc.volume            = c.state->volume.load();
-    pc.pan               = c.state->pan.load();
-    pc.hasActions        = c.state->hasActions;
-    pc.readActions       = c.state->readActions.load();
-    pc.armed             = c.state->armed.load();
-    pc.midiIn            = c.midiLearner.state->enabled.load();
-    pc.midiInFilter      = c.midiLearner.state->filter.load();
-    pc.midiInKeyPress    = c.midiLearner.state->keyPress.getValue();
-    pc.midiInKeyRel      = c.midiLearner.state->keyRelease.getValue();
-    pc.midiInKill        = c.midiLearner.state->kill.getValue();
-    pc.midiInArm         = c.midiLearner.state->arm.getValue();
-    pc.midiInVolume      = c.midiLearner.state->volume.getValue();
-    pc.midiInMute        = c.midiLearner.state->mute.getValue();
-    pc.midiInSolo        = c.midiLearner.state->solo.getValue();
-       pc.midiInReadActions = c.midiLearner.state->readActions.getValue();
-       pc.midiInPitch       = c.midiLearner.state->pitch.getValue();
-    pc.midiOutL          = c.midiLighter.state->enabled.load(); 
-    pc.midiOutLplaying   = c.midiLighter.state->playing.getValue();
-    pc.midiOutLmute      = c.midiLighter.state->mute.getValue();
-    pc.midiOutLsolo      = c.midiLighter.state->solo.getValue();
-
-       if (c.getType() == ChannelType::SAMPLE) {
+       pc.type              = c.type;
+       pc.columnId          = c.columnId;
+       pc.height            = c.height;
+       pc.name              = c.name;
+       pc.key               = c.key;
+       pc.mute              = c.mute;
+       pc.solo              = c.solo;
+       pc.volume            = c.volume;
+       pc.pan               = c.pan;
+       pc.hasActions        = c.hasActions;
+       pc.readActions       = c.state->readActions.load();
+       pc.armed             = c.armed;
+       pc.midiIn            = c.midiLearner.enabled;
+       pc.midiInFilter      = c.midiLearner.filter;
+       pc.midiInKeyPress    = c.midiLearner.keyPress.getValue();
+       pc.midiInKeyRel      = c.midiLearner.keyRelease.getValue();
+       pc.midiInKill        = c.midiLearner.kill.getValue();
+       pc.midiInArm         = c.midiLearner.arm.getValue();
+       pc.midiInVolume      = c.midiLearner.volume.getValue();
+       pc.midiInMute        = c.midiLearner.mute.getValue();
+       pc.midiInSolo        = c.midiLearner.solo.getValue();
+       pc.midiInReadActions = c.midiLearner.readActions.getValue();
+       pc.midiInPitch       = c.midiLearner.pitch.getValue();
+       pc.midiOutL          = c.midiLighter.enabled;
+       pc.midiOutLplaying   = c.midiLighter.playing.getValue();
+       pc.midiOutLmute      = c.midiLighter.mute.getValue();
+       pc.midiOutLsolo      = c.midiLighter.solo.getValue();
+
+       if (c.type == ChannelType::SAMPLE)
+       {
                pc.waveId            = c.samplePlayer->getWaveId();
-               pc.mode              = c.samplePlayer->state->mode.load();
-               pc.begin             = c.samplePlayer->state->begin.load();
-               pc.end               = c.samplePlayer->state->end.load();
-               pc.pitch             = c.samplePlayer->state->pitch.load();
-               pc.shift             = c.samplePlayer->state->shift.load();
-               pc.midiInVeloAsVol   = c.samplePlayer->state->velocityAsVol.load();
-               pc.inputMonitor      = c.audioReceiver->state->inputMonitor.load();
-               pc.overdubProtection = c.audioReceiver->state->overdubProtection.load();
-
+               pc.mode              = c.samplePlayer->mode;
+               pc.begin             = c.samplePlayer->begin;
+               pc.end               = c.samplePlayer->end;
+               pc.pitch             = c.samplePlayer->pitch;
+               pc.shift             = c.samplePlayer->shift;
+               pc.midiInVeloAsVol   = c.samplePlayer->velocityAsVol;
+               pc.inputMonitor      = c.audioReceiver->inputMonitor;
+               pc.overdubProtection = c.audioReceiver->overdubProtection;
        }
-       else
-       if (c.getType() == ChannelType::MIDI) { 
-               pc.midiOut     = c.midiSender->state->enabled.load();
-               pc.midiOutChan = c.midiSender->state->filter.load();
+       else if (c.type == ChannelType::MIDI)
+       {
+               pc.midiOut     = c.midiSender->enabled;
+               pc.midiOutChan = c.midiSender->filter;
        }
 
        return pc;
 }
-}}} // giada::m::channelManager
+} // namespace giada::m::channelManager
index d7eb6f4e02e0bc6561b7db58b4d835155f0aa732..fd8598a625cae6e5cb8c9814741f83f775860432 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MANAGER_H
 #define G_CHANNEL_MANAGER_H
 
-
-#include <memory>
 #include "core/types.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m::channel
 {
-namespace conf
+struct Data;
+}
+namespace giada::m::conf
 {
 struct Conf;
 }
-namespace patch
+namespace giada::m::patch
 {
 struct Channel;
 }
-class  Channel;
-struct ChannelState;
-namespace channelManager
+namespace giada::m::channelManager
 {
 /* init
 Initializes internal data. */
-       
+
 void init();
 
 /* create (1)
-Creates a new Channel from scratch. */
+Creates a new channel. If channelId == 0 generates a new ID, reuse the one 
+passed in otherwise. */
 
-std::unique_ptr<Channel> create(ChannelType type, ID columnId, const conf::Conf& conf);
+channel::Data create(ID channelId, ChannelType type, ID columnId);
 
 /* create (2)
-Creates a new Channel given an existing one (i.e. clone). */
+Creates a new channel given an existing one (i.e. clone). */
 
-std::unique_ptr<Channel> create(const Channel& ch);
+channel::Data create(const channel::Data& ch);
 
 /* (de)serializeWave
-Creates a new Channel given the patch raw data and vice versa. */
-
-std::unique_ptr<Channel> deserializeChannel(const patch::Channel& c, int bufferSize);
-const patch::Channel     serializeChannel(const Channel& c);
-}}} // giada::m::channelManager
+Creates a new channel given the patch raw data and vice versa. */
 
+channel::Data        deserializeChannel(const patch::Channel& c, float samplerateRatio);
+const patch::Channel serializeChannel(const channel::Data& c);
+} // namespace giada::m::channelManager
 
 #endif
index 7d274336f1e69d7864c69018d598e57e9d33a085..a759159f4821acf3fb1512999b500c157cacd14e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
+#include "midiActionRecorder.h"
 #include "core/action.h"
+#include "core/channels/channel.h"
 #include "core/clock.h"
 #include "core/conf.h"
+#include "core/eventDispatcher.h"
 #include "core/mixer.h"
-#include "core/recorderHandler.h"
 #include "core/recManager.h"
-#include "core/channels/state.h"
-#include "midiActionRecorder.h"
-
+#include "core/recorderHandler.h"
+#include <cassert>
 
-namespace giada {
-namespace m
+namespace giada::m::midiActionRecorder
 {
-MidiActionRecorder::MidiActionRecorder(ChannelState* c)
-: m_channelState(c)
+namespace
 {
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-MidiActionRecorder::MidiActionRecorder(const MidiActionRecorder& /*o*/, ChannelState* c)
-: MidiActionRecorder(c)
+void record_(channel::Data& ch, const MidiEvent& e)
 {
+       MidiEvent flat(e);
+       flat.setChannel(0);
+       recorderHandler::liveRec(ch.id, flat, clock::quantize(clock::getCurrentFrame()));
+       ch.hasActions = true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiActionRecorder::parse(const mixer::Event& e) const
+bool canRecord_()
 {
-       assert(m_channelState != nullptr);
-
-       if (e.type == mixer::EventType::MIDI && canRecord()) 
-               record(e.action.event);
+       return recManager::isRecordingAction() &&
+              clock::isRunning() &&
+              !recManager::isRecordingInput();
 }
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
-
-
-void MidiActionRecorder::record(const MidiEvent& e) const
-{
-       MidiEvent flat(e);
-       flat.setChannel(0);
-       recorderHandler::liveRec(m_channelState->id, flat, clock::quantize(clock::getCurrentFrame()));
-       m_channelState->hasActions = true;
-}
-
-
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-bool MidiActionRecorder::canRecord() const
+void react(channel::Data& ch, const eventDispatcher::Event& e)
 {
-       return recManager::isRecordingAction() && 
-              clock::isRunning()              && 
-              !recManager::isRecordingInput();
+       if (e.type == eventDispatcher::EventType::MIDI && canRecord_())
+               record_(ch, std::get<Action>(e.data).event);
 }
-}} // giada::m::
-
+} // namespace giada::m::midiActionRecorder
\ No newline at end of file
index 50e3109117f901f0e7f12897a7d1a06b84d00ba7..3e08c9a83d86c4f3cb62aba2b270259f9566c47c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MIDI_ACTION_RECORDER_H
 #define G_CHANNEL_MIDI_ACTION_RECORDER_H
 
-
-#include "core/types.h"
-
-
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-namespace mixer
+struct Data;
+}
+namespace giada::m::eventDispatcher
 {
 struct Event;
 }
-struct ChannelState;
-class MidiActionRecorder
+namespace giada::m::midiActionRecorder
+{
+struct Data
 {
-public:
-
-    MidiActionRecorder(ChannelState*);
-    MidiActionRecorder(const MidiActionRecorder&, ChannelState* c=nullptr);
-
-    void parse(const mixer::Event& e) const;
-
-private:
-
-    bool canRecord() const;
-    void record(const MidiEvent& e) const;
-
-    ChannelState* m_channelState;
 };
-}} // giada::m::
 
+void react(channel::Data& ch, const eventDispatcher::Event& e);
+} // namespace giada::m::midiActionRecorder
 
 #endif
index 55dcd032134b2648ade5811d2efe8691fd471a55..3403eadbcdd74609ce53d7ccebc3c68a8f4e5244 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/conf.h"
-#include "core/channels/state.h"
 #include "midiController.h"
+#include "core/channels/channel.h"
+#include "core/conf.h"
+#include <cassert>
 
-
-namespace giada {
-namespace m 
+namespace giada::m::midiController
 {
-MidiController::MidiController(ChannelState* c)
-: m_channelState(c)
+namespace
 {
-}
-
-
-/* -------------------------------------------------------------------------- */
+ChannelStatus onFirstBeat_(const channel::Data& ch)
+{
+       ChannelStatus playStatus = ch.state->playStatus.load();
 
+       if (playStatus == ChannelStatus::ENDING)
+               playStatus = ChannelStatus::OFF;
+       else if (playStatus == ChannelStatus::WAIT)
+               playStatus = ChannelStatus::PLAY;
 
-MidiController::MidiController(const MidiController& /*o*/, ChannelState* c)
-: m_channelState(c)
-{
+       return playStatus;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiController::parse(const mixer::Event& e) const
+ChannelStatus press_(const channel::Data& ch)
 {
-       assert(m_channelState != nullptr);
+       ChannelStatus playStatus = ch.state->playStatus.load();
 
-       switch (e.type) {
+       switch (playStatus)
+       {
+       case ChannelStatus::PLAY:
+               playStatus = ChannelStatus::ENDING;
+               break;
 
-               case mixer::EventType::KEY_PRESS:
-                       press(); break;
-
-               case mixer::EventType::KEY_KILL:
-               case mixer::EventType::SEQUENCER_STOP:
-                       kill(); break;
+       case ChannelStatus::ENDING:
+       case ChannelStatus::WAIT:
+               playStatus = ChannelStatus::OFF;
+               break;
 
-               case mixer::EventType::SEQUENCER_FIRST_BEAT:
-               case mixer::EventType::SEQUENCER_REWIND:
-                       onFirstBeat();  
+       case ChannelStatus::OFF:
+               playStatus = ChannelStatus::WAIT;
+               break;
 
-               default: break;
+       default:
+               break;
        }
-}
 
+       return playStatus;
+}
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void MidiController::press() const
+void react(channel::Data& ch, const eventDispatcher::Event& e)
 {
-    ChannelStatus playStatus = m_channelState->playStatus.load();
+       switch (e.type)
+       {
 
-       switch (playStatus) {
-               case ChannelStatus::PLAY:
-                       playStatus = ChannelStatus::ENDING; break;
+       case eventDispatcher::EventType::KEY_PRESS:
+               ch.state->playStatus.store(press_(ch));
+               break;
 
-               case ChannelStatus::ENDING:
-               case ChannelStatus::WAIT:
-                       playStatus = ChannelStatus::OFF; break;
+       case eventDispatcher::EventType::KEY_KILL:
+       case eventDispatcher::EventType::SEQUENCER_STOP:
+               ch.state->playStatus.store(ChannelStatus::OFF);
+               break;
 
-               case ChannelStatus::OFF:
-                       playStatus = ChannelStatus::WAIT; break;
-
-               default: break;
-       }       
-       
-       m_channelState->playStatus.store(playStatus);
-}
-
-
-/* -------------------------------------------------------------------------- */
+       case eventDispatcher::EventType::SEQUENCER_REWIND:
+               ch.state->playStatus.store(onFirstBeat_(ch));
 
-
-void MidiController::kill() const
-{
-       m_channelState->playStatus.store(ChannelStatus::OFF);
+       default:
+               break;
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiController::onFirstBeat() const
+void advance(const channel::Data& ch, const sequencer::Event& e)
 {
-       ChannelStatus playStatus = m_channelState->playStatus.load();
-
-       if (playStatus == ChannelStatus::ENDING)
-               playStatus = ChannelStatus::OFF;
-       else
-       if (playStatus == ChannelStatus::WAIT)
-               playStatus = ChannelStatus::PLAY;
-       
-       m_channelState->playStatus.store(playStatus);
+       if (e.type == sequencer::EventType::FIRST_BEAT)
+               ch.state->playStatus.store(onFirstBeat_(ch));
 }
-}} // giada::m::
+} // namespace giada::m::midiController
index 7a437786bb4acbe02a80c05730ff8e17b6581c12..8f73435325eeb3554b9c0a284542f22a2d6513a5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MIDI_CONTROLLER_H
 #define G_CHANNEL_MIDI_CONTROLLER_H
 
-
-#include "core/types.h"
-#include "core/mixer.h"  // TODO - forward declare
-
-
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-/* MidiController
-Manages events for a MIDI Channel. */
-
-class MidiController
+struct Data;
+}
+namespace giada::m::eventDispatcher
+{
+struct Event;
+}
+namespace giada::m::sequencer
+{
+struct Event;
+}
+namespace giada::m::midiController
+{
+struct Data
 {
-public:
-
-    MidiController(ChannelState*);
-    MidiController(const MidiController&, ChannelState* c=nullptr);
-
-    void parse(const mixer::Event& e) const;
-
-private:
-
-    void press() const;
-    void kill() const;
-    void onFirstBeat() const;
-    
-    ChannelState* m_channelState;
 };
-}} // giada::m::
 
+void react(channel::Data& ch, const eventDispatcher::Event& e);
+void advance(const channel::Data& ch, const sequencer::Event& e);
+} // namespace giada::m::midiController
 
 #endif
index 038654689953c2f9bf85d668d6452930e3b782c6..48e2a9ff6a1dbb22dbd96f0b97dd76bc36578ed0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/channels/state.h"
 #include "midiLearner.h"
+#include "core/patch.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m::midiLearner
 {
-MidiLearner::MidiLearner()
-: state(std::make_unique<MidiLearnerState>())
+Data::Data(const patch::Channel& p)
+: enabled(p.midiIn)
+, filter(p.midiInFilter)
+, keyPress(p.midiInKeyPress)
+, keyRelease(p.midiInKeyRel)
+, kill(p.midiInKill)
+, arm(p.midiInArm)
+, volume(p.midiInVolume)
+, mute(p.midiInMute)
+, solo(p.midiInSolo)
+, readActions(p.midiInReadActions)
+, pitch(p.midiInPitch)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-MidiLearner::MidiLearner(const patch::Channel& p)
-: state(std::make_unique<MidiLearnerState>(p))
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-MidiLearner::MidiLearner(const MidiLearner& o)
-: state(std::make_unique<MidiLearnerState>(*o.state))
+bool Data::isAllowed(int c) const
 {
+       return enabled && (filter == -1 || filter == c);
 }
-}} // giada::m::
+} // namespace giada::m::midiLearner
\ No newline at end of file
index 5acb93d67f2b56f9dbc243978033339fa5ea4fab..e1e95c28ed5c71cc545ad36020550c5ab91adcc0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MIDI_LEARNER_H
 #define G_CHANNEL_MIDI_LEARNER_H
 
+#include "core/midiLearnParam.h"
 
-#include <memory>
-
-
-namespace giada {
-namespace m
+namespace giada::m::patch
 {
-struct MidiLearnerState;
-class MidiLearner
+struct Channel;
+}
+namespace giada::m::midiLearner
 {
-public:
+struct Data
+{
+       Data() = default;
+       Data(const patch::Channel&);
+       Data(const Data&) = default;
 
-    MidiLearner();
-    MidiLearner(const patch::Channel&);
-    MidiLearner(const MidiLearner&);
+       /* isAllowed
+    Tells whether the MIDI channel 'c' is enabled to receive MIDI data. */
 
-    /* state
-    Pointer to mutable MidiLearnerState state. */
+       bool isAllowed(int c) const;
 
-    std::unique_ptr<MidiLearnerState> state;
-};
-}} // giada::m::
+       /* enabled
+    Tells whether MIDI learning is enabled for the current channel. */
 
+       bool enabled;
+
+       /* filter
+    Which MIDI channel should be filtered out when receiving MIDI messages. 
+    If -1 means 'all'. */
+
+       int filter;
+
+       /* MIDI learning fields. */
+
+       MidiLearnParam keyPress;
+       MidiLearnParam keyRelease;
+       MidiLearnParam kill;
+       MidiLearnParam arm;
+       MidiLearnParam volume;
+       MidiLearnParam mute;
+       MidiLearnParam solo;
+       MidiLearnParam readActions; // Sample Channels only
+       MidiLearnParam pitch;       // Sample Channels only
+};
+} // namespace giada::m::midiLearner
 
 #endif
index a82a9c0838c9c2e81077703f91e780768bd7a73b..c6f2ca438192cedf2f8d6ca14352b7859b0a4b22 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/channels/state.h"
-#include "core/mixer.h"
+#include "midiLighter.h"
+#include "core/channels/channel.h"
 #include "core/kernelMidi.h"
 #include "core/midiMapConf.h"
-#include "midiLighter.h"
-
+#include "core/mixer.h"
 
-namespace giada {
-namespace m 
+namespace giada::m::midiLighter
 {
-MidiLighter::MidiLighter(ChannelState* c)
-: state         (std::make_unique<MidiLighterState>())
-, m_channelState(c)
+namespace
 {
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-MidiLighter::MidiLighter(const patch::Channel& p, ChannelState* c)
-: state         (std::make_unique<MidiLighterState>(p))
-, m_channelState(c)
+void sendMute_(channel::Data& ch, uint32_t l_mute)
 {
+       if (ch.mute)
+               kernelMidi::sendMidiLightning(l_mute, midimap::midimap.muteOn);
+       else
+               kernelMidi::sendMidiLightning(l_mute, midimap::midimap.muteOff);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-MidiLighter::MidiLighter(const MidiLighter& o, ChannelState* c)
-: state         (std::make_unique<MidiLighterState>(*o.state))
-, m_channelState(c)
+void sendSolo_(channel::Data& ch, uint32_t l_solo)
 {
+       if (ch.solo)
+               kernelMidi::sendMidiLightning(l_solo, midimap::midimap.soloOn);
+       else
+               kernelMidi::sendMidiLightning(l_solo, midimap::midimap.soloOff);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiLighter::parse(const mixer::Event& e, bool audible) const
+void sendStatus_(channel::Data& ch, uint32_t l_playing, bool audible)
 {
-    if (state->enabled.load() == false)
-        return;
-
-    uint32_t l_playing = state->playing.getValue();
-    uint32_t l_mute    = state->mute.getValue();
-    uint32_t l_solo    = state->solo.getValue();
+       switch (ch.state->playStatus.load())
+       {
 
-       switch (e.type) {
+       case ChannelStatus::OFF:
+               kernelMidi::sendMidiLightning(l_playing, midimap::midimap.stopped);
+               break;
 
-        case mixer::EventType::KEY_PRESS:
-        case mixer::EventType::KEY_RELEASE:
-        case mixer::EventType::KEY_KILL:
-        case mixer::EventType::SEQUENCER_STOP:
-            if (l_playing != 0x0) sendStatus(l_playing, audible); 
-            break;
+       case ChannelStatus::WAIT:
+               kernelMidi::sendMidiLightning(l_playing, midimap::midimap.waiting);
+               break;
 
-        case mixer::EventType::CHANNEL_MUTE:
-            if (l_mute != 0x0) sendMute(l_mute); 
-            break;
+       case ChannelStatus::ENDING:
+               kernelMidi::sendMidiLightning(l_playing, midimap::midimap.stopping);
+               break;
 
-        case mixer::EventType::CHANNEL_SOLO:
-            if (l_solo != 0x0) sendSolo(l_solo); 
-            break;
+       case ChannelStatus::PLAY:
+               kernelMidi::sendMidiLightning(l_playing, audible ? midimap::midimap.playing : midimap::midimap.playingInaudible);
+               break;
 
-        default: break;
-    }
+       default:
+               break;
+       }
 }
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
-
-
-void MidiLighter::sendMute(uint32_t l_mute) const
-{
-       if (m_channelState->mute.load() == true)
-               kernelMidi::sendMidiLightning(l_mute, midimap::midimap.muteOn);
-       else
-               kernelMidi::sendMidiLightning(l_mute, midimap::midimap.muteOff);    
-}
-
-
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void MidiLighter::sendSolo(uint32_t l_solo) const
+Data::Data(const patch::Channel& p)
+: enabled(p.midiOutL)
+, playing(p.midiOutLplaying)
+, mute(p.midiOutLmute)
+, solo(p.midiOutLsolo)
 {
-       if (m_channelState->solo.load() == true)
-               kernelMidi::sendMidiLightning(l_solo, midimap::midimap.soloOn);
-       else
-               kernelMidi::sendMidiLightning(l_solo, midimap::midimap.soloOff);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiLighter::sendStatus(uint32_t l_playing, bool audible) const
+void react(channel::Data& ch, const eventDispatcher::Event& e, bool audible)
 {
-    switch (m_channelState->playStatus.load()) {
-        
-        case ChannelStatus::OFF:
-            kernelMidi::sendMidiLightning(l_playing, midimap::midimap.stopped);
-            break;
-        
-        case ChannelStatus::WAIT:
-            kernelMidi::sendMidiLightning(l_playing, midimap::midimap.waiting);
-            break;
-
-        case ChannelStatus::ENDING:
-            kernelMidi::sendMidiLightning(l_playing, midimap::midimap.stopping);
-            break;
-
-        case ChannelStatus::PLAY:
-            kernelMidi::sendMidiLightning(l_playing, audible ? midimap::midimap.playing : midimap::midimap.playingInaudible);
-            break;
-
-        default: break;        
-    }
+       if (!ch.midiLighter.enabled)
+               return;
+
+       uint32_t l_playing = ch.midiLighter.playing.getValue();
+       uint32_t l_mute    = ch.midiLighter.mute.getValue();
+       uint32_t l_solo    = ch.midiLighter.solo.getValue();
+
+       switch (e.type)
+       {
+
+       case eventDispatcher::EventType::KEY_PRESS:
+       case eventDispatcher::EventType::KEY_RELEASE:
+       case eventDispatcher::EventType::KEY_KILL:
+       case eventDispatcher::EventType::SEQUENCER_STOP:
+               if (l_playing != 0x0)
+                       sendStatus_(ch, l_playing, audible);
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_MUTE:
+               if (l_mute != 0x0)
+                       sendMute_(ch, l_mute);
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_SOLO:
+               if (l_solo != 0x0)
+                       sendSolo_(ch, l_solo);
+               break;
+
+       default:
+               break;
+       }
 }
-}} // giada::m::
+} // namespace giada::m::midiLighter
\ No newline at end of file
index 8b77b294e0eff7a82ad542e86184745cf7ffe45e..483d21e8b08cb2fae6129d5a37aad5f54abdc013 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MIDI_LIGHTER_H
 #define G_CHANNEL_MIDI_LIGHTER_H
 
+#include "core/midiLearnParam.h"
 
-#include <memory>
-
-
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-namespace mixer
+struct Data;
+}
+namespace giada::m::patch
+{
+struct Channel;
+}
+namespace giada::m::eventDispatcher
 {
 struct Event;
 }
-struct MidiLighterState;
-
-/* MidiLighter
-Learns and emits MIDI lightning messages to physical hardware on events. */
-
-class MidiLighter
+namespace giada::m::midiLighter
 {
-public:
-
-    MidiLighter(ChannelState*);
-    MidiLighter(const patch::Channel&, ChannelState*);
-    MidiLighter(const MidiLighter&, ChannelState* c=nullptr);
-
-    void parse(const mixer::Event& e, bool audible) const;
-
-    /* state
-    Pointer to mutable MidiLighterState state. */
+struct Data
+{
+       Data() = default;
+       Data(const patch::Channel& p);
+       Data(const Data& o) = default;
 
-    std::unique_ptr<MidiLighterState> state;
+       /* enabled
+    Tells whether MIDI ligthing is enabled or not. */
 
-private:
+       bool enabled;
 
-    void sendMute(uint32_t l_mute) const;
-    void sendSolo(uint32_t l_solo) const;
-    void sendStatus(uint32_t l_playing, bool audible) const;
+       /* MIDI learning fields for MIDI ligthing. */
 
-    ChannelState* m_channelState;
+       MidiLearnParam playing;
+       MidiLearnParam mute;
+       MidiLearnParam solo;
 };
-}} // giada::m::
 
+void react(channel::Data& ch, const eventDispatcher::Event& e, bool audible);
+} // namespace giada::m::midiLighter
 
 #endif
index 2afa74aecd43eab11abde9cabb28a1ee4715f30f..595d682724a1c7ea5b602c7853acd07589640f18 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
+#include "midiReceiver.h"
+#include "core/channels/channel.h"
+#include "core/eventDispatcher.h"
 #include "core/mixer.h"
 #include "core/plugins/pluginHost.h"
-#include "core/channels/state.h"
-#include "midiReceiver.h"
-
 
-namespace giada {
-namespace m 
+namespace giada::m::midiReceiver
 {
-MidiReceiver::MidiReceiver(ChannelState* c)
-: state           (std::make_unique<MidiReceiverState>())
-, m_channelState  (c)
+namespace
 {
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-MidiReceiver::MidiReceiver(const patch::Channel& /*p*/, ChannelState* c)
-: state           (std::make_unique<MidiReceiverState>())
-, m_channelState  (c)
+void sendToPlugins_(const channel::Data& ch, const MidiEvent& e, Frame localFrame)
 {
+       juce::MidiMessage message = juce::MidiMessage(
+           e.getStatus(),
+           e.getNote(),
+           e.getVelocity());
+       ch.buffer->midi.addEvent(message, localFrame);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-MidiReceiver::MidiReceiver(const MidiReceiver& /*o*/, ChannelState* c)
-: state           (std::make_unique<MidiReceiverState>())
-, m_channelState  (c)
+void parseMidi_(const channel::Data& ch, const MidiEvent& e)
 {
-}
+       /* Now all messages are turned into Channel-0 messages. Giada doesn't care 
+       about holding MIDI channel information. Moreover, having all internal 
+       messages on channel 0 is way easier. Then send it to plug-ins. */
 
+       MidiEvent flat(e);
+       flat.setChannel(0);
+       sendToPlugins_(ch, flat, /*delta=*/0);
+}
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void MidiReceiver::parse(const mixer::Event& e) const
+void react(const channel::Data& ch, const eventDispatcher::Event& e)
 {
-       switch (e.type) {
-
-               case mixer::EventType::MIDI:
-                       parseMidi(e.action.event); break;
-
-               case mixer::EventType::ACTION:
-                       if (m_channelState->isPlaying())
-                               sendToPlugins(e.action.event, e.delta);
-                       break;
-               
-               case mixer::EventType::KEY_KILL:
-               case mixer::EventType::SEQUENCER_STOP:
-               case mixer::EventType::SEQUENCER_REWIND:
-                       sendToPlugins(MidiEvent(G_MIDI_ALL_NOTES_OFF), 0); break;
-               
-               default: break;
-       }
-}
+       switch (e.type)
+       {
 
+       case eventDispatcher::EventType::MIDI:
+               parseMidi_(ch, std::get<Action>(e.data).event);
+               break;
 
-/* -------------------------------------------------------------------------- */
+       case eventDispatcher::EventType::KEY_KILL:
+       case eventDispatcher::EventType::SEQUENCER_STOP:
+       case eventDispatcher::EventType::SEQUENCER_REWIND:
+               sendToPlugins_(ch, MidiEvent(G_MIDI_ALL_NOTES_OFF), 0);
+               break;
 
-
-void MidiReceiver::render(const std::vector<ID>& pluginIds) const
-{
-       pluginHost::processStack(m_channelState->buffer, pluginIds, &state->midiBuffer);
-       state->midiBuffer.clear();
+       default:
+               break;
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiReceiver::parseMidi(const MidiEvent& e) const
+void advance(const channel::Data& ch, const sequencer::Event& e)
 {
-       /* Now all messages are turned into Channel-0 messages. Giada doesn't care 
-       about holding MIDI channel information. Moreover, having all internal 
-       messages on channel 0 is way easier. Then send it to plug-ins. */
-
-       MidiEvent flat(e);
-       flat.setChannel(0);
-       sendToPlugins(flat, /*delta=*/0); 
+       if (e.type == sequencer::EventType::ACTIONS && ch.isPlaying())
+               for (const Action& action : *e.actions)
+                       if (action.channelId == ch.id)
+                               sendToPlugins_(ch, action.event, e.delta);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiReceiver::sendToPlugins(const MidiEvent& e, Frame localFrame) const
+void render(const channel::Data& ch)
 {
-       juce::MidiMessage message = juce::MidiMessage(
-               e.getStatus(), 
-               e.getNote(), 
-               e.getVelocity());
-       state->midiBuffer.addEvent(message, localFrame);
+       pluginHost::processStack(ch.buffer->audio, ch.plugins, &ch.buffer->midi);
+       ch.buffer->midi.clear();
 }
-}} // giada::m::
-
+} // namespace giada::m::midiReceiver
 
-#endif // WITH_VST
\ No newline at end of file
+#endif // WITH_VST
index dc83bbe9d87340822d5b3b908a2115903ab235c2..b2f7aa828f9620f65d57d44bb141f84cc5890019 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MIDI_RECEIVER_H
 #define G_CHANNEL_MIDI_RECEIVER_H
 
-
 #ifdef WITH_VST
 
-
-#include <memory>
-
-
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-namespace mixer
+struct Data;
+}
+namespace giada::m::eventDispatcher
 {
 struct Event;
 }
-struct MidiReceiverState;
-
-/* MidiReceiver 
-Takes live action gestures AND recorded actions and redirect them as MIDI events 
-to plug-in soft synths. */
-
-class MidiReceiver
+namespace giada::m::sequencer
+{
+struct Event;
+}
+namespace giada::m::midiReceiver
+{
+struct Data
 {
-public:
-
-    MidiReceiver(ChannelState*);
-    MidiReceiver(const patch::Channel&, ChannelState*);
-    MidiReceiver(const MidiReceiver&, ChannelState* c=nullptr);
-
-    void parse(const mixer::Event& e) const;
-    void render(const std::vector<ID>& pluginIds) const;
-
-    /* state
-    Pointer to mutable MidiReceiverState state. */
-
-    std::unique_ptr<MidiReceiverState> state;
-
-private:
-
-    /* parseMidi
-    Takes a live message (e.g. from a MIDI keyboard), strips it and sends it
-    to plug-ins. */
-
-    void parseMidi(const MidiEvent& e) const;
-
-       /* sendToPlugins
-    Enqueues the MIDI event for plug-ins processing. This will be read later on 
-    by the PluginHost. */
-
-    void sendToPlugins(const MidiEvent& e, Frame localFrame) const;
-
-    ChannelState* m_channelState;
 };
-}} // giada::m::
 
+void react(const channel::Data& ch, const eventDispatcher::Event& e);
+void advance(const channel::Data& ch, const sequencer::Event& e);
+void render(const channel::Data& ch);
+} // namespace giada::m::midiReceiver
 
 #endif // WITH_VST
 
-
 #endif
index a5a616af0a0f360654871cb9816d4f4dd8bcea8a..e4994ca2f318c0b3a22b8f5a53344622b42025dd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/mixer.h"
-#include "core/kernelMidi.h"
-#include "core/channels/state.h"
 #include "midiSender.h"
+#include "core/channels/channel.h"
+#include "core/kernelMidi.h"
+#include "core/mixer.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m::midiSender
 {
-MidiSender::MidiSender(ChannelState* c)
-: state(std::make_unique<MidiSenderState>())
-, m_channelState(c)
+namespace
 {
+void send_(const channel::Data& ch, MidiEvent e)
+{
+       e.setChannel(ch.midiSender->filter);
+       kernelMidi::send(e.getRaw());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-MidiSender::MidiSender(const patch::Channel& p, ChannelState* c)
-: state(std::make_unique<MidiSenderState>(p))
-, m_channelState(c)
+void parseActions_(const channel::Data& ch, const std::vector<Action>& as)
 {
+       for (const Action& a : as)
+               if (a.channelId == ch.id)
+                       send_(ch, a.event);
 }
-
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-MidiSender::MidiSender(const MidiSender& o, ChannelState* c)
-: state(std::make_unique<MidiSenderState>(*o.state))
-, m_channelState(c)
+Data::Data(const patch::Channel& p)
+: enabled(p.midiOut)
+, filter(p.midiOutChan)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiSender::parse(const mixer::Event& e) const
+void react(const channel::Data& ch, const eventDispatcher::Event& e)
 {
-       bool isPlaying = m_channelState->isPlaying();
-       bool isEnabled = state->enabled.load();
-
-       if (!isPlaying || !isEnabled)
+       if (!ch.isPlaying() || !ch.midiSender->enabled)
                return;
 
-       if (e.type == mixer::EventType::KEY_KILL || 
-           e.type == mixer::EventType::SEQUENCER_STOP)
-               send(MidiEvent(G_MIDI_ALL_NOTES_OFF));
-       else
-       if (e.type == mixer::EventType::ACTION)
-               send(e.action.event);
+       if (e.type == eventDispatcher::EventType::KEY_KILL ||
+           e.type == eventDispatcher::EventType::SEQUENCER_STOP)
+               send_(ch, MidiEvent(G_MIDI_ALL_NOTES_OFF));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void MidiSender::send(MidiEvent e) const
+void advance(const channel::Data& ch, const sequencer::Event& e)
 {
-       e.setChannel(state->filter.load());
-       kernelMidi::send(e.getRaw());
+       if (!ch.midiSender->enabled)
+               return;
+       if (e.type == sequencer::EventType::ACTIONS)
+               parseActions_(ch, *e.actions);
 }
-}} // giada::m::
+} // namespace giada::m::midiSender
index 5f2d51f9180f25ed3c5d59592b13058fc43150ee..dbecca398e71a6b930bcf51ccad5d68b31576e86 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_MIDI_SENDER_H
 #define G_CHANNEL_MIDI_SENDER_H
 
-
-namespace giada {
-namespace m
+namespace giada::m::channel
+{
+struct Data;
+}
+namespace giada::m::patch
 {
-namespace mixer
+struct Channel;
+}
+namespace giada::m::eventDispatcher
 {
 struct Event;
 }
-struct ChannelState;
-struct MidiSenderState;
-class MidiSender
+namespace giada::m::sequencer
 {
-public:
-
-    MidiSender(ChannelState*);
-    MidiSender(const patch::Channel&, ChannelState*);
-    MidiSender(const MidiSender&, ChannelState* c=nullptr);
-
-    void parse(const mixer::Event& e) const;
-
-    /* state
-    Pointer to mutable MidiSenderState state. */
+struct Event;
+}
+namespace giada::m::midiSender
+{
+struct Data
+{
+       Data() = default;
+       Data(const patch::Channel& p);
+       Data(const Data& o) = default;
 
-    std::unique_ptr<MidiSenderState> state;
+       /* enabled
+    Tells whether MIDI output is enabled or not. */
 
-private:
+       bool enabled;
 
-    void send(MidiEvent e) const;
+       /* filter
+    Which MIDI channel data should be sent to. */
 
-    ChannelState* m_channelState;
+       int filter;
 };
-}} // giada::m::
 
+void react(const channel::Data& ch, const eventDispatcher::Event& e);
+void advance(const channel::Data& ch, const sequencer::Event& e);
+} // namespace giada::m::midiSender
 
 #endif
index a5465567b0240aff9c8520273c65e887bbae33e4..cbfd7bd1a7d78039589935cc550b851cb433b5cf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
+#include "sampleActionRecorder.h"
 #include "core/action.h"
+#include "core/channels/channel.h"
 #include "core/clock.h"
 #include "core/conf.h"
+#include "core/eventDispatcher.h"
 #include "core/mixer.h"
-#include "core/recorderHandler.h"
 #include "core/recManager.h"
-#include "core/channels/state.h"
-#include "sampleActionRecorder.h"
-
+#include "core/recorderHandler.h"
+#include <cassert>
 
-namespace giada {
-namespace m
+namespace giada::m::sampleActionRecorder
 {
-SampleActionRecorder::SampleActionRecorder(ChannelState* c, SamplePlayerState* sc)
-: m_channelState(c)
-, m_samplePlayerState(sc)
+namespace
 {
-}
-
+void record_(channel::Data& ch, int note);
+void onKeyPress_(channel::Data& ch);
+void toggleReadActions_(channel::Data& ch);
+void startReadActions_(channel::Data& ch);
+void stopReadActions_(channel::Data& ch, ChannelStatus curRecStatus);
+void killReadActions_(channel::Data& ch);
+bool canRecord_(const channel::Data& ch);
 
 /* -------------------------------------------------------------------------- */
 
-
-SampleActionRecorder::SampleActionRecorder(const SampleActionRecorder& /*o*/, 
-       ChannelState* c, SamplePlayerState* sc)
-: SampleActionRecorder(c, sc)
+bool canRecord_(const channel::Data& ch)
 {
+       return recManager::isRecordingAction() &&
+              clock::isRunning() &&
+              !recManager::isRecordingInput() &&
+              !ch.samplePlayer->isAnyLoopMode();
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleActionRecorder::parse(const mixer::Event& e) const
-{
-       assert(m_channelState != nullptr);
-
-       switch (e.type) {
-
-               case mixer::EventType::KEY_PRESS:
-                       onKeyPress(); break;
-
-               /* Record a stop event only if channel is SINGLE_PRESS. For any other 
-               mode the key release event is meaningless. */
-
-               case mixer::EventType::KEY_RELEASE:
-                       if (canRecord() && m_samplePlayerState->mode.load() == SamplePlayerMode::SINGLE_PRESS) 
-                               record(MidiEvent::NOTE_OFF);
-                       break;
-
-               case mixer::EventType::KEY_KILL:
-                       if (canRecord()) 
-                               record(MidiEvent::NOTE_KILL);
-                       break;
-               
-               case mixer::EventType::SEQUENCER_FIRST_BEAT:
-                       onFirstBeat(); break;
-
-               case mixer::EventType::CHANNEL_TOGGLE_READ_ACTIONS:     
-                       toggleReadActions(); break;        
-
-               case mixer::EventType::CHANNEL_KILL_READ_ACTIONS:
-                       killReadActions(); break;      
-               
-               default: break;
-       }
-}
-
-
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::record(int note) const
+void onKeyPress_(channel::Data& ch)
 {
-       recorderHandler::liveRec(m_channelState->id, MidiEvent(note, 0, 0), 
-               clock::quantize(clock::getCurrentFrame()));
-
-       m_channelState->hasActions = true;
-}
-
-
-/* -------------------------------------------------------------------------- */
+       if (!canRecord_(ch))
+               return;
+       record_(ch, MidiEvent::NOTE_ON);
 
+       /* Skip reading actions when recording on ChannelMode::SINGLE_PRESS to 
+       prevent existing actions to interfere with the keypress/keyrel combo. */
 
-void SampleActionRecorder::startReadActions() const
-{
-       if (conf::conf.treatRecsAsLoops) 
-               m_channelState->recStatus.store(ChannelStatus::WAIT);
-       else {
-               m_channelState->recStatus.store(ChannelStatus::PLAY);
-               m_channelState->readActions.store(true);
-       }
+       if (ch.samplePlayer->mode == SamplePlayerMode::SINGLE_PRESS)
+               ch.state->readActions.store(false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::stopReadActions(ChannelStatus curRecStatus) const
+void record_(channel::Data& ch, int note)
 {
-       /* First of all, if the clock is not running or treatRecsAsLoops is off, 
-       just stop and disable everything. Otherwise make sure a channel with actions
-       behave like a dynamic one. */
+       recorderHandler::liveRec(ch.id, MidiEvent(note, 0, 0),
+           clock::quantize(clock::getCurrentFrame()));
 
-       if (!clock::isRunning() || !conf::conf.treatRecsAsLoops) {
-               m_channelState->recStatus.store(ChannelStatus::OFF);
-           m_channelState->readActions.store(false);
-       }
-       else
-       if (curRecStatus == ChannelStatus::WAIT)
-               m_channelState->recStatus.store(ChannelStatus::OFF);
-       else
-       if (curRecStatus == ChannelStatus::ENDING)
-               m_channelState->recStatus.store(ChannelStatus::PLAY);
-       else
-               m_channelState->recStatus.store(ChannelStatus::ENDING);
+       ch.hasActions = true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::toggleReadActions() const
+void toggleReadActions_(channel::Data& ch)
 {
        /* When you start reading actions while conf::treatRecsAsLoops is true, the
        value ch.state->readActions actually is not set to true immediately, because
@@ -158,96 +94,105 @@ void SampleActionRecorder::toggleReadActions() const
        handle the case of when you press 'R', the channel goes into REC_WAITING and
        then you press 'R' again to undo the status. */
 
-       if (!m_channelState->hasActions)
+       if (!ch.hasActions)
                return;
 
-       bool          readActions = m_channelState->readActions.load();
-       ChannelStatus recStatus   = m_channelState->recStatus.load();
+       const bool          readActions = ch.state->readActions.load();
+       const ChannelStatus recStatus   = ch.state->recStatus.load();
 
        if (readActions || (!readActions && recStatus == ChannelStatus::WAIT))
-               stopReadActions(recStatus);
+               stopReadActions_(ch, recStatus);
        else
-               startReadActions();
+               startReadActions_(ch);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::killReadActions() const
+void startReadActions_(channel::Data& ch)
 {
-       /* Killing Read Actions, i.e. shift + click on 'R' button is meaninful only 
-       when the conf::treatRecsAsLoops is true. */
-
-       if (!conf::conf.treatRecsAsLoops)
-               return;
-       m_channelState->recStatus.store(ChannelStatus::OFF);
-       m_channelState->readActions.store(false);
+       if (conf::conf.treatRecsAsLoops)
+               ch.state->recStatus.store(ChannelStatus::WAIT);
+       else
+       {
+               ch.state->recStatus.store(ChannelStatus::PLAY);
+               ch.state->readActions.store(true);
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::onKeyPress() const
+void stopReadActions_(channel::Data& ch, ChannelStatus curRecStatus)
 {
-       if (!canRecord()) 
-               return;
-       record(MidiEvent::NOTE_ON);
-
-       /* Skip reading actions when recording on ChannelMode::SINGLE_PRESS to 
-       prevent existing actions to interfere with the keypress/keyrel combo. */
+       /* First of all, if the clock is not running or treatRecsAsLoops is off, 
+       just stop and disable everything. Otherwise make sure a channel with actions
+       behave like a dynamic one. */
 
-       if (m_samplePlayerState->mode.load() == SamplePlayerMode::SINGLE_PRESS)
-               m_channelState->readActions = false;
+       if (!clock::isRunning() || !conf::conf.treatRecsAsLoops)
+       {
+               ch.state->recStatus.store(ChannelStatus::OFF);
+               ch.state->readActions.store(false);
+       }
+       else if (curRecStatus == ChannelStatus::WAIT)
+               ch.state->recStatus.store(ChannelStatus::OFF);
+       else if (curRecStatus == ChannelStatus::ENDING)
+               ch.state->recStatus.store(ChannelStatus::PLAY);
+       else
+               ch.state->recStatus.store(ChannelStatus::ENDING);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::onKeyRelease() const
+void killReadActions_(channel::Data& ch)
 {
-       if (canRecord() && m_samplePlayerState->mode.load() == SamplePlayerMode::SINGLE_PRESS) {
-               record(MidiEvent::NOTE_OFF);
-               m_channelState->readActions = true;
-       }
-}
+       /* Killing Read Actions, i.e. shift + click on 'R' button is meaninful only 
+       when the conf::treatRecsAsLoops is true. */
 
+       if (!conf::conf.treatRecsAsLoops)
+               return;
+       ch.state->recStatus.store(ChannelStatus::OFF);
+       ch.state->readActions.store(false);
+}
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void SampleActionRecorder::onFirstBeat() const
+void react(channel::Data& ch, const eventDispatcher::Event& e)
 {
-       ChannelStatus recStatus = m_channelState->recStatus.load();
+       if (!ch.hasWave())
+               return;
 
-       switch (recStatus) { 
+       switch (e.type)
+       {
 
-               case ChannelStatus::ENDING:
-            m_channelState->recStatus.store(ChannelStatus::OFF);
-                       m_channelState->readActions = false;
-                       break;
+       case eventDispatcher::EventType::KEY_PRESS:
+               onKeyPress_(ch);
+               break;
 
-               case ChannelStatus::WAIT:
-            m_channelState->recStatus.store(ChannelStatus::PLAY);
-                       m_channelState->readActions = true;
-                       break;
+               /* Record a stop event only if channel is SINGLE_PRESS. For any other 
+               mode the key release event is meaningless. */
 
-               default: break;
-       }       
-}
+       case eventDispatcher::EventType::KEY_RELEASE:
+               if (canRecord_(ch) && ch.samplePlayer->mode == SamplePlayerMode::SINGLE_PRESS)
+                       record_(ch, MidiEvent::NOTE_OFF);
+               break;
 
+       case eventDispatcher::EventType::KEY_KILL:
+               if (canRecord_(ch))
+                       record_(ch, MidiEvent::NOTE_KILL);
+               break;
 
-/* -------------------------------------------------------------------------- */
+       case eventDispatcher::EventType::CHANNEL_TOGGLE_READ_ACTIONS:
+               toggleReadActions_(ch);
+               break;
 
+       case eventDispatcher::EventType::CHANNEL_KILL_READ_ACTIONS:
+               killReadActions_(ch);
+               break;
 
-bool SampleActionRecorder::canRecord() const
-{
-       return recManager::isRecordingAction() && 
-              clock::isRunning()              && 
-              !recManager::isRecordingInput() &&
-                  !m_samplePlayerState->isAnyLoopMode();
+       default:
+               break;
+       }
 }
-}} // giada::m::
-
+} // namespace giada::m::sampleActionRecorder
\ No newline at end of file
index b6bf451655ea8cd719ee613d603a59b513a30a96..4ecac81eff03ea7078618e41fa0476b0f6bfc0f2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_SAMPLE_ACTION_RECORDER_H
 #define G_CHANNEL_SAMPLE_ACTION_RECORDER_H
 
-
-#include "core/types.h"
-
-
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-namespace mixer
+struct Data;
+}
+namespace giada::m::eventDispatcher
 {
 struct Event;
 }
-struct ChannelState;
-
-/* SampleActionRecorder
-Records actions for channels and optionally manages the 'read action' state ('R' 
-button on Sample Channels). */
-
-class SampleActionRecorder
+namespace giada::m::sampleActionRecorder
+{
+struct Data
 {
-public:
-
-    SampleActionRecorder(ChannelState*, SamplePlayerState*);
-    SampleActionRecorder(const SampleActionRecorder&, ChannelState* c=nullptr, 
-        SamplePlayerState* sc=nullptr);
-
-    void parse(const mixer::Event& e) const;
-
-private:
-    void record(int note) const;
-    void onKeyPress() const;
-    void onKeyRelease() const;
-    void onFirstBeat() const;
-
-    void toggleReadActions() const;
-    void startReadActions() const;
-    void stopReadActions(ChannelStatus curRecStatus) const;
-    void killReadActions() const;
-
-    bool canRecord() const;
-
-    ChannelState*      m_channelState;
-    SamplePlayerState* m_samplePlayerState;
 };
-}} // giada::m::
 
+void react(channel::Data& ch, const eventDispatcher::Event& e);
+} // namespace giada::m::sampleActionRecorder
 
 #endif
diff --git a/src/core/channels/sampleAdvancer.cpp b/src/core/channels/sampleAdvancer.cpp
new file mode 100644 (file)
index 0000000..d60df06
--- /dev/null
@@ -0,0 +1,253 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "sampleAdvancer.h"
+#include "core/channels/channel.h"
+#include "core/clock.h"
+#include <cassert>
+
+namespace giada::m::sampleAdvancer
+{
+namespace
+{
+void rewind_(const channel::Data& ch, Frame localFrame)
+{
+       ch.state->rewinding = true;
+       ch.state->offset    = localFrame;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void stop_(const channel::Data& ch, Frame localFrame)
+{
+       ch.state->playStatus.store(ChannelStatus::OFF);
+       ch.state->tracker.store(ch.samplePlayer->begin);
+
+       /*  Clear data in range [localFrame, (buffer.size)) if the event occurs in
+    the middle of the buffer. TODO - samplePlayer should be responsible for this*/
+
+       if (localFrame != 0)
+               ch.buffer->audio.clear(localFrame);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void play_(const channel::Data& ch, Frame localFrame)
+{
+       ch.state->playStatus.store(ChannelStatus::PLAY);
+       ch.state->offset = localFrame;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void onFirstBeat_(const channel::Data& ch, Frame localFrame)
+{
+       G_DEBUG("onFirstBeat ch=" << ch.id << ", localFrame=" << localFrame);
+
+       ChannelStatus playStatus = ch.state->playStatus.load();
+       ChannelStatus recStatus  = ch.state->recStatus.load();
+       bool          isLoop     = ch.samplePlayer->isAnyLoopMode();
+
+       switch (playStatus)
+       {
+       case ChannelStatus::PLAY:
+               if (isLoop)
+                       rewind_(ch, localFrame);
+               break;
+
+       case ChannelStatus::WAIT:
+               play_(ch, localFrame);
+               break;
+
+       case ChannelStatus::ENDING:
+               if (isLoop)
+                       stop_(ch, localFrame);
+               break;
+
+       default:
+               break;
+       }
+
+       switch (recStatus)
+       {
+       case ChannelStatus::WAIT:
+               ch.state->recStatus.store(ChannelStatus::PLAY);
+               ch.state->readActions.store(true);
+               break;
+
+       case ChannelStatus::ENDING:
+               ch.state->recStatus.store(ChannelStatus::OFF);
+               ch.state->readActions.store(false);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void onBar_(const channel::Data& ch, Frame localFrame)
+{
+       G_DEBUG("onBar ch=" << ch.id << ", localFrame=" << localFrame);
+
+       ChannelStatus    playStatus = ch.state->playStatus.load();
+       SamplePlayerMode mode       = ch.samplePlayer->mode;
+
+       if (playStatus == ChannelStatus::PLAY && (mode == SamplePlayerMode::LOOP_REPEAT ||
+                                                    mode == SamplePlayerMode::LOOP_ONCE_BAR))
+               rewind_(ch, localFrame);
+       else if (playStatus == ChannelStatus::WAIT && mode == SamplePlayerMode::LOOP_ONCE_BAR)
+               ch.state->playStatus.store(ChannelStatus::PLAY);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void onNoteOn_(const channel::Data& ch, Frame localFrame)
+{
+       ChannelStatus playStatus = ch.state->playStatus.load();
+
+       if (playStatus == ChannelStatus::OFF)
+       {
+               playStatus = ChannelStatus::PLAY;
+       }
+       else if (playStatus == ChannelStatus::PLAY)
+       {
+               if (ch.samplePlayer->mode == SamplePlayerMode::SINGLE_RETRIG)
+                       rewind_(ch, localFrame);
+               else
+                       playStatus = ChannelStatus::OFF;
+       }
+
+       ch.state->playStatus.store(playStatus);
+       ch.state->offset = localFrame;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void onNoteOff_(const channel::Data& ch, Frame localFrame)
+{
+       ch.state->playStatus.store(ChannelStatus::OFF);
+       ch.state->tracker.store(ch.samplePlayer->begin);
+
+       /*  Clear data in range [localFrame, (buffer.size)) if the kill event occurs
+    in the middle of the buffer. */
+
+       if (localFrame != 0)
+               ch.buffer->audio.clear(localFrame);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void parseActions_(const channel::Data& ch, const std::vector<Action>& as, Frame localFrame)
+{
+       if (ch.samplePlayer->isAnyLoopMode() || !ch.isReadingActions())
+               return;
+
+       for (const Action& a : as)
+       {
+               if (a.channelId != ch.id)
+                       continue;
+
+               switch (a.event.getStatus())
+               {
+               case MidiEvent::NOTE_ON:
+                       onNoteOn_(ch, localFrame);
+                       break;
+
+               case MidiEvent::NOTE_OFF:
+                       onNoteOff_(ch, localFrame);
+                       break;
+
+               case MidiEvent::NOTE_KILL:
+                       onNoteOff_(ch, localFrame);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+void onLastFrame(const channel::Data& ch)
+{
+       ChannelStatus    playStatus = ch.state->playStatus.load();
+       SamplePlayerMode mode       = ch.samplePlayer->mode;
+       bool             isLoop     = ch.samplePlayer->isAnyLoopMode();
+       bool             running    = clock::isRunning();
+
+       if (playStatus == ChannelStatus::PLAY)
+       {
+               /* Stop LOOP_* when the sequencer is off, or SINGLE_* except for
+               SINGLE_ENDLESS, which runs forever unless it's in ENDING mode. 
+               Other loop once modes are put in wait mode. */
+               if ((mode == SamplePlayerMode::SINGLE_BASIC ||
+                       mode == SamplePlayerMode::SINGLE_PRESS ||
+                       mode == SamplePlayerMode::SINGLE_RETRIG) ||
+                   (isLoop && !running))
+                       playStatus = ChannelStatus::OFF;
+               else if (mode == SamplePlayerMode::LOOP_ONCE || mode == SamplePlayerMode::LOOP_ONCE_BAR)
+                       playStatus = ChannelStatus::WAIT;
+       }
+       else if (playStatus == ChannelStatus::ENDING)
+               playStatus = ChannelStatus::OFF;
+
+       ch.state->playStatus.store(playStatus);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void advance(const channel::Data& ch, const sequencer::Event& e)
+{
+       switch (e.type)
+       {
+       case sequencer::EventType::FIRST_BEAT:
+               onFirstBeat_(ch, e.delta);
+               break;
+
+       case sequencer::EventType::BAR:
+               onBar_(ch, e.delta);
+               break;
+
+       case sequencer::EventType::REWIND:
+               rewind_(ch, e.delta);
+               break;
+
+       case sequencer::EventType::ACTIONS:
+               if (ch.state->readActions.load() == true)
+                       parseActions_(ch, *e.actions, e.delta);
+               break;
+
+       default:
+               break;
+       }
+}
+} // namespace giada::m::sampleAdvancer
\ No newline at end of file
diff --git a/src/core/channels/sampleAdvancer.h b/src/core/channels/sampleAdvancer.h
new file mode 100644 (file)
index 0000000..c19b97e
--- /dev/null
@@ -0,0 +1,42 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_CHANNEL_SAMPLE_ADVANCER_H
+#define G_CHANNEL_SAMPLE_ADVANCER_H
+
+#include "core/sequencer.h"
+
+namespace giada::m::channel
+{
+struct Data;
+}
+namespace giada::m::sampleAdvancer
+{
+void onLastFrame(const channel::Data& ch);
+void advance(const channel::Data& ch, const sequencer::Event& e);
+} // namespace giada::m::sampleAdvancer
+
+#endif
diff --git a/src/core/channels/sampleController.cpp b/src/core/channels/sampleController.cpp
deleted file mode 100644 (file)
index d6055b2..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <cassert>
-#include "core/conf.h"
-#include "core/clock.h"
-#include "core/action.h"
-#include "core/mixer.h"
-#include "core/channels/state.h"
-#include "utils/math.h"
-#include "sampleController.h"
-
-
-namespace giada {
-namespace m 
-{
-namespace
-{
-constexpr int Q_ACTION_PLAY   = 0;
-constexpr int Q_ACTION_REWIND = 1;
-} // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-SampleController::SampleController(ChannelState* c, SamplePlayerState* s)
-: m_channelState     (c)
-, m_samplePlayerState(s) 
-{
-       m_samplePlayerState->quantizer.schedule(Q_ACTION_PLAY, 
-               [&status = m_channelState->playStatus, &offset = m_samplePlayerState->offset]
-               (Frame delta)
-       {
-               offset = delta;
-               status = ChannelStatus::PLAY;
-       });
-
-       m_samplePlayerState->quantizer.schedule(Q_ACTION_REWIND, [this] (Frame delta)
-       {
-               rewind(delta);
-       });
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-SampleController::SampleController(const SampleController& /*o*/, ChannelState* c, SamplePlayerState* s)
-: SampleController(c, s)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::parse(const mixer::Event& e) const
-{
-       assert(m_channelState      != nullptr);
-       assert(m_samplePlayerState != nullptr);
-
-       switch (e.type) {
-               case mixer::EventType::KEY_PRESS:
-                       press(e.delta, e.action.event.getVelocity(), /*manual=*/true); break;
-
-               case mixer::EventType::KEY_RELEASE:
-                       release(e.delta); break;
-
-               case mixer::EventType::KEY_KILL:
-                       kill(e.delta); break;
-
-               case mixer::EventType::SEQUENCER_FIRST_BEAT:
-                       if (clock::isRunning())
-                               onFirstBeat(e.delta); 
-                       break;
-               
-               case mixer::EventType::SEQUENCER_BAR:
-                       onBar(e.delta);  break;
-               
-               case mixer::EventType::SEQUENCER_STOP:  
-                       onStopBySeq(); break;
-               
-               case mixer::EventType::ACTION:
-                       if (m_channelState->readActions.load() == true)
-                               parseAction(e.action, e.delta);
-                       break;
-                       
-               case mixer::EventType::CHANNEL_TOGGLE_READ_ACTIONS:     
-                       toggleReadActions(); break;   
-               
-               default: break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::onLastFrame() const
-{
-    ChannelStatus    playStatus = m_channelState->playStatus.load();
-    SamplePlayerMode mode       = m_samplePlayerState->mode.load();
-    bool             running    = clock::isRunning();
-       
-    if (playStatus == ChannelStatus::PLAY) {
-        /* Stop LOOP_* when the sequencer is off, or SINGLE_* except for
-        SINGLE_ENDLESS, which runs forever unless it's in ENDING mode. 
-        Other loop once modes are put in wait mode. */
-        if ((mode == SamplePlayerMode::SINGLE_BASIC   || 
-             mode == SamplePlayerMode::SINGLE_PRESS   ||
-             mode == SamplePlayerMode::SINGLE_RETRIG) || 
-            (m_samplePlayerState->isAnyLoopMode() && !running))
-            playStatus = ChannelStatus::OFF;
-        else
-        if (mode == SamplePlayerMode::LOOP_ONCE || mode == SamplePlayerMode::LOOP_ONCE_BAR)
-            playStatus = ChannelStatus::WAIT;
-    }
-    else
-    if (playStatus == ChannelStatus::ENDING)
-        playStatus = ChannelStatus::OFF;
-
-    m_channelState->playStatus.store(playStatus);      
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::advance(Frame bufferSize) const
-{
-       Range<Frame> block(clock::getCurrentFrame(), clock::getCurrentFrame() + bufferSize);
-       m_samplePlayerState->quantizer.advance(block, clock::getQuantizerStep());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::press(Frame localFrame, int velocity, bool manual) const
-{
-    ChannelStatus    playStatus = m_channelState->playStatus.load();
-    SamplePlayerMode mode       = m_samplePlayerState->mode.load();
-       bool             isLoop     = m_samplePlayerState->isAnyLoopMode();
-
-    switch (playStatus) {
-               case ChannelStatus::OFF:
-                       playStatus = pressWhileOff(localFrame, velocity, isLoop, manual); break;
-
-               case ChannelStatus::PLAY:
-                       playStatus = pressWhilePlay(localFrame, mode, isLoop, manual); break;
-
-               case ChannelStatus::WAIT:
-                       playStatus = ChannelStatus::OFF; break;
-
-               case ChannelStatus::ENDING:
-                       playStatus = ChannelStatus::PLAY; break;
-
-               default: break;
-       }
-
-    m_channelState->playStatus.store(playStatus); 
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::release(Frame localFrame) const
-{
-       /* Key release is meaningful only for SINGLE_PRESS modes. */
-       
-       if (m_samplePlayerState->mode.load() != SamplePlayerMode::SINGLE_PRESS)
-               return;
-
-       /* Kill it if it's SINGLE_PRESS is playing. Otherwise there might be a 
-       quantization step in progress that would play the channel later on: 
-       disable it. */
-
-       if (m_channelState->playStatus.load() == ChannelStatus::PLAY)
-               kill(localFrame);
-       else
-    if (m_samplePlayerState->quantizer.isTriggered())
-        m_samplePlayerState->quantizer.clear();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::kill(Frame localFrame) const
-{
-    m_channelState->playStatus.store(ChannelStatus::OFF);
-    m_samplePlayerState->tracker.store(m_samplePlayerState->begin.load());
-    m_samplePlayerState->quantizing = false; 
-
-    /*  Clear data in range [localFrame, (buffer.size)) if the kill event occurs
-    in the middle of the buffer. */
-
-    if (localFrame != 0)
-        m_channelState->buffer.clear(localFrame);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::rewind(Frame localFrame) const
-{
-       /* Quantization stops on rewind. */
-
-       m_samplePlayerState->quantizer.clear(); 
-
-       if (m_channelState->isPlaying()) { 
-               m_samplePlayerState->rewinding = true;
-               m_samplePlayerState->offset    = localFrame;
-       }
-       else
-               m_samplePlayerState->tracker.store(m_samplePlayerState->begin.load());
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-ChannelStatus SampleController::pressWhileOff(Frame localFrame, int velocity, bool isLoop, bool manual) const
-{
-       m_samplePlayerState->offset = localFrame;
-
-       if (isLoop)
-               return ChannelStatus::WAIT;
-
-       if (m_samplePlayerState->velocityAsVol.load() == true)  
-               m_channelState->volume_i = u::math::map(velocity, G_MAX_VELOCITY, G_MAX_VOLUME); 
-
-       if (clock::canQuantize() && manual) { // manual: don't quantize recorded actions
-               m_samplePlayerState->quantizer.trigger(Q_ACTION_PLAY);
-               return ChannelStatus::OFF;
-       }
-       else
-               return ChannelStatus::PLAY;
-}
-
-
-ChannelStatus SampleController::pressWhilePlay(Frame localFrame, SamplePlayerMode mode, bool isLoop, bool manual) const
-{
-       if (mode == SamplePlayerMode::SINGLE_RETRIG) {
-               if (clock::canQuantize() && manual)  // manual: don't quantize recorded actions 
-                       m_samplePlayerState->quantizer.trigger(Q_ACTION_REWIND);
-               else
-                       rewind(localFrame);
-               return ChannelStatus::PLAY;
-       }
-
-       if (isLoop || mode == SamplePlayerMode::SINGLE_ENDLESS)
-               return ChannelStatus::ENDING;
-
-       if (mode == SamplePlayerMode::SINGLE_BASIC) {
-               rewind(localFrame);
-               return ChannelStatus::OFF;
-       }
-
-       return ChannelStatus::OFF;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::onBar(Frame localFrame) const
-{
-       G_DEBUG("onBar ch=" << m_channelState->id);
-
-    ChannelStatus    playStatus = m_channelState->playStatus.load();
-    SamplePlayerMode mode       = m_samplePlayerState->mode.load();
-
-    if (playStatus == ChannelStatus::PLAY && (mode == SamplePlayerMode::LOOP_REPEAT || 
-                                                 mode == SamplePlayerMode::LOOP_ONCE_BAR))
-        rewind(localFrame);
-    else
-    if (playStatus == ChannelStatus::WAIT && mode == SamplePlayerMode::LOOP_ONCE_BAR) {
-               m_channelState->playStatus.store(ChannelStatus::PLAY);
-        m_samplePlayerState->offset = localFrame;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::onFirstBeat(Frame localFrame) const
-{
-G_DEBUG("onFirstBeat ch=" << m_channelState->id << ", localFrame=" << localFrame);
-
-    ChannelStatus playStatus = m_channelState->playStatus.load();
-       bool          isLoop     = m_samplePlayerState->isAnyLoopMode();
-
-       switch (playStatus) { 
-
-               case ChannelStatus::PLAY:
-                       if (isLoop) 
-                               rewind(localFrame); 
-                       break;
-               
-               case ChannelStatus::WAIT:
-               m_samplePlayerState->offset = localFrame;
-            m_channelState->playStatus.store(ChannelStatus::PLAY);
-                       break;
-
-               case ChannelStatus::ENDING:
-                       if (isLoop) 
-                               kill(localFrame);
-                       break;
-               
-               default: break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::onStopBySeq() const
-{
-       G_DEBUG("onStopBySeq ch=" << m_channelState->id);
-
-       ChannelStatus playStatus       = m_channelState->playStatus.load();
-       bool          isReadingActions = m_channelState->readActions.load() == true;
-       bool          isLoop           = m_samplePlayerState->isAnyLoopMode();
-
-       switch (playStatus) {
-
-               case ChannelStatus::WAIT:
-                       /* Loop-mode channels in wait status get stopped right away. */
-                       if (isLoop)
-                               m_channelState->playStatus.store(ChannelStatus::OFF);   
-                       break;
-
-               case ChannelStatus::PLAY:
-                       /* Kill samples if a) chansStopOnSeqHalt == true (run the sample to end 
-                       otherwise); b) when a channel is reading (and playing) actions. */
-                       if (conf::conf.chansStopOnSeqHalt)
-                               if (isLoop || isReadingActions)
-                                       kill(0);
-                       break;
-
-               default: break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::parseAction(const Action& a, Frame localFrame) const
-{
-       bool isLoop = m_samplePlayerState->isAnyLoopMode();
-
-       switch (a.event.getStatus()) {
-               case MidiEvent::NOTE_ON:
-                       if (!isLoop)
-                               press(localFrame, /*velocity=*/G_MAX_VELOCITY, /*manual=*/false);
-                       break;
-               case MidiEvent::NOTE_OFF:
-                       if (!isLoop)
-                               release(localFrame);
-                       break;
-               case MidiEvent::NOTE_KILL:
-                       if (!isLoop)
-                               kill(localFrame);
-                       break;
-               case MidiEvent::ENVELOPE:
-                       //calcVolumeEnv_(ch, a); TODO
-                       break;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void SampleController::toggleReadActions() const
-{
-       ChannelStatus recStatus = m_channelState->recStatus.load();
-       if (clock::isRunning() && recStatus == ChannelStatus::PLAY && !conf::conf.treatRecsAsLoops)
-               kill(0);
-}
-}} // giada::m::
diff --git a/src/core/channels/sampleController.h b/src/core/channels/sampleController.h
deleted file mode 100644 (file)
index 7a38dd2..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef G_CHANNEL_SAMPLE_CONTROLLER_H
-#define G_CHANNEL_SAMPLE_CONTROLLER_H
-
-
-#include "core/types.h"
-
-
-namespace giada {
-namespace m
-{
-namespace mixer
-{
-struct Event;
-}
-struct SamplePlayerState;
-class SampleController
-{
-public:
-
-    SampleController(ChannelState*, SamplePlayerState*);
-    SampleController(const SampleController&, ChannelState* c=nullptr, SamplePlayerState* s=nullptr);
-
-    void parse(const mixer::Event& e) const;
-    void onLastFrame() const;
-    void advance(Frame bufferSize) const;
-
-private:
-
-    void press(Frame localFrame, int velocity, bool manual) const;
-    void release(Frame localFrame) const;
-    void kill(Frame localFrame) const;
-    void rewind(Frame localFrame) const;
-
-    ChannelStatus pressWhileOff(Frame localFrame, int velocity, bool isLoop, bool manual) const;
-    ChannelStatus pressWhilePlay(Frame localFrame, SamplePlayerMode mode, bool isLoop, bool manual) const;
-    void toggleReadActions() const;
-
-    void onBar(Frame localFrame) const;
-    void onFirstBeat(Frame localFrame) const;
-    void onStopBySeq() const;
-    void parseAction(const Action& a, Frame localFrame) const;
-    
-    ChannelState*      m_channelState;
-    SamplePlayerState* m_samplePlayerState;
-};
-}} // giada::m::
-
-
-#endif
index 1fc5723d0f3f6814be369c0804c5be7e908660a4..78c67474eae06148795ba0424cee0a9ce8af2509 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <algorithm>
-#include <cassert>
+#include "samplePlayer.h"
 #include "core/channels/channel.h"
-#include "core/channels/state.h"
-#include "core/wave.h"
 #include "core/clock.h"
-#include "samplePlayer.h"
-
+#include "core/wave.h"
+#include "core/waveManager.h"
+#include <algorithm>
+#include <cassert>
 
-namespace giada {
-namespace m 
+namespace giada::m::samplePlayer
 {
-SamplePlayer::SamplePlayer(ChannelState* c)
-: state             (std::make_unique<SamplePlayerState>())
-, m_waveId          (0)
-, m_sampleController(c, state.get())
-, m_channelState    (c)
+namespace
 {
-}
+bool shouldLoop_(const channel::Data& ch)
+{
+       ChannelStatus    playStatus = ch.state->playStatus.load();
+       SamplePlayerMode mode       = ch.samplePlayer->mode;
 
+       return (mode == SamplePlayerMode::LOOP_BASIC ||
+                  mode == SamplePlayerMode::LOOP_REPEAT ||
+                  mode == SamplePlayerMode::SINGLE_ENDLESS) &&
+              playStatus == ChannelStatus::PLAY;
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-SamplePlayer::SamplePlayer(const SamplePlayer& o, ChannelState* c)
-: state             (std::make_unique<SamplePlayerState>(*o.state))
-, m_waveId          (o.m_waveId)
-, m_waveReader      (o.m_waveReader)
-, m_sampleController(o.m_sampleController, c, state.get())
-, m_channelState    (c)
+WaveReader::Result fillBuffer_(const channel::Data& ch, Frame start, Frame offset)
 {
-}
+       AudioBuffer&      buffer     = ch.buffer->audio;
+       const WaveReader& waveReader = ch.samplePlayer->waveReader;
 
+       return waveReader.fill(buffer, start, ch.samplePlayer->end, offset, ch.samplePlayer->pitch);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-SamplePlayer::SamplePlayer(const patch::Channel& p, ChannelState* c)
-: state             (std::make_unique<SamplePlayerState>(p))
-, m_waveId          (p.waveId)
-, m_sampleController(c, state.get())
-, m_channelState    (c)
+bool isPlaying_(const channel::Data& ch)
 {
+       return ch.samplePlayer->waveReader.wave != nullptr && ch.isPlaying();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SamplePlayer::parse(const mixer::Event& e) const
+void setWave_(samplePlayer::Data& sp, Wave* w, float samplerateRatio)
 {
-    if (e.type == mixer::EventType::CHANNEL_PITCH)
-        state->pitch.store(e.action.event.getVelocityFloat());
-
-    if (hasWave())
-        m_sampleController.parse(e);
+       if (w == nullptr)
+       {
+               sp.waveReader.wave = nullptr;
+               return;
+       }
+
+       sp.waveReader.wave = w;
+
+       if (samplerateRatio != 1.0f)
+       {
+               sp.begin *= samplerateRatio;
+               sp.end *= samplerateRatio;
+               sp.shift *= samplerateRatio;
+       }
 }
-
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void SamplePlayer::advance(Frame bufferSize) const
+Data::Data(Resampler* r)
+: pitch(G_DEFAULT_PITCH)
+, mode(SamplePlayerMode::SINGLE_BASIC)
+, velocityAsVol(false)
+, waveReader(r)
 {
-    m_sampleController.advance(bufferSize);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SamplePlayer::render(AudioBuffer& /*out*/) const
+Data::Data(const patch::Channel& p, float samplerateRatio, Resampler* r)
+: pitch(p.pitch)
+, mode(p.mode)
+, shift(p.shift)
+, begin(p.begin)
+, end(p.end)
+, velocityAsVol(p.midiInVeloAsVol)
+, waveReader(r)
 {
-    assert(m_channelState != nullptr);
-
-    if (m_waveReader.wave == nullptr || !m_channelState->isPlaying())
-        return;
-
-    Frame begin   = state->begin.load();
-    Frame end     = state->end.load();
-    Frame tracker = state->tracker.load();
-    float pitch   = state->pitch.load();
-    Frame used    = 0;
-
-    /* Audio data is temporarily stored to the working audio buffer. */
+       setWave_(*this, waveManager::hydrateWave(p.waveId), samplerateRatio);
+}
 
-    AudioBuffer& buffer = m_channelState->buffer;
+/* -------------------------------------------------------------------------- */
 
-    /* Adjust tracker in case someone has changed the begin/end points in the
-    meantime. */
-    
-    if (tracker < begin || tracker >= end)
-        tracker = begin;
+bool Data::hasWave() const { return waveReader.wave != nullptr; }
+bool Data::hasLogicalWave() const { return hasWave() && waveReader.wave->isLogical(); }
+bool Data::hasEditedWave() const { return hasWave() && waveReader.wave->isEdited(); }
 
-    /* If rewinding, fill the tail first, then reset the tracker to the begin
-    point. The rest is performed as usual. */
+/* -------------------------------------------------------------------------- */
 
-    if (state->rewinding) {
-               if (tracker < end)
-            m_waveReader.fill(buffer, tracker, 0, pitch);
-        state->rewinding = false;
-               tracker = begin;
-    }
-
-    used     = m_waveReader.fill(buffer, tracker, state->offset, pitch);
-    tracker += used;
-
-G_DEBUG ("block=[" << tracker - used << ", " << tracker << ")" << 
-         ", used=" << used << ", range=[" << begin << ", " << end << ")" <<
-         ", tracker=" << tracker << 
-         ", offset=" << state->offset << ", globalFrame=" << clock::getCurrentFrame());
-
-    if (tracker >= end) {
-G_DEBUG ("last frame tracker=" << tracker);
-        tracker = begin;
-        m_sampleController.onLastFrame();
-        if (shouldLoop()) {
-            Frame offset = std::min(static_cast<Frame>(used / pitch), buffer.countFrames() - 1);
-            tracker += m_waveReader.fill(buffer, tracker, offset, pitch);
-        }
-    }
-
-    state->offset = 0;
-    state->tracker.store(tracker);
+bool Data::isAnyLoopMode() const
+{
+       return mode == SamplePlayerMode::LOOP_BASIC ||
+              mode == SamplePlayerMode::LOOP_ONCE ||
+              mode == SamplePlayerMode::LOOP_REPEAT ||
+              mode == SamplePlayerMode::LOOP_ONCE_BAR;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SamplePlayer::loadWave(const Wave* w)
+Wave* Data::getWave() const
 {
-    m_waveReader.wave = w;
-
-    state->tracker.store(0);
-    state->shift.store(0);
-    state->begin.store(0);
-
-    if (w != nullptr) {
-        m_waveId = w->id;
-        m_channelState->playStatus.store(ChannelStatus::OFF);
-        m_channelState->name = w->getBasename(/*ext=*/false);
-        state->end.store(w->getSize() - 1);
-    }
-    else {
-        m_waveId = 0;
-        m_channelState->playStatus.store(ChannelStatus::EMPTY);
-        m_channelState->name = "";
-        state->end.store(0);
-    }
+       return waveReader.wave;
 }
 
+ID Data::getWaveId() const
+{
+       if (hasWave())
+               return waveReader.wave->id;
+       return 0;
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void SamplePlayer::setWave(const Wave& w, float samplerateRatio)
+Frame Data::getWaveSize() const
 {
-    m_waveReader.wave = &w;
-    m_waveId = w.id;
-
-    if (samplerateRatio != 1.0f) {
-        Frame begin = state->begin.load();
-        Frame end   = state->end.load();
-        Frame shift = state->shift.load();
-        state->begin.store(begin * samplerateRatio);
-        state->end.store(end * samplerateRatio);
-        state->shift.store(shift * samplerateRatio);
-    }
+       return hasWave() ? waveReader.wave->getBuffer().countFrames() : 0;
 }
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
-void SamplePlayer::setInvalidWave()
+void react(channel::Data& ch, const eventDispatcher::Event& e)
 {
-    m_waveReader.wave = nullptr;
-    m_waveId = 0;
+       if (e.type == eventDispatcher::EventType::CHANNEL_PITCH)
+               ch.samplePlayer->pitch = std::get<float>(e.data);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void SamplePlayer::kickIn(Frame f)
+void advance(const channel::Data& ch, const sequencer::Event& e)
 {
-    assert(hasWave());
-    
-       state->tracker.store(f);
-       m_channelState->playStatus.store(ChannelStatus::PLAY);    
+       sampleAdvancer::advance(ch, e);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool SamplePlayer::shouldLoop() const
+void render(const channel::Data& ch)
 {
-    ChannelStatus    playStatus = m_channelState->playStatus.load();
-    SamplePlayerMode mode       = state->mode.load();
-    
-    return (mode == SamplePlayerMode::LOOP_BASIC  || 
-            mode == SamplePlayerMode::LOOP_REPEAT || 
-            mode == SamplePlayerMode::SINGLE_ENDLESS) && playStatus == ChannelStatus::PLAY;
-}
+       if (!isPlaying_(ch))
+               return;
 
+       const Frame begin = ch.samplePlayer->begin;
+       const Frame end   = ch.samplePlayer->end;
 
-/* -------------------------------------------------------------------------- */
+       /* Make sure tracker stays within begin-end range. */
 
+       Frame tracker = std::clamp(ch.state->tracker.load(), begin, end);
 
-bool SamplePlayer::hasWave() const        { return m_waveReader.wave != nullptr; }
-bool SamplePlayer::hasLogicalWave() const { return hasWave() && m_waveReader.wave->isLogical(); }
-bool SamplePlayer::hasEditedWave() const  { return hasWave() && m_waveReader.wave->isEdited(); }
+       /* If rewinding, fill the tail first, then reset the tracker to the begin
+    point. The rest is performed as usual. */
 
+       if (ch.state->rewinding)
+       {
+               if (tracker < end)
+               {
+                       fillBuffer_(ch, tracker, 0);
+                       ch.samplePlayer->waveReader.last();
+               }
+               ch.state->rewinding = false;
+               tracker             = begin;
+       }
+
+       WaveReader::Result res = fillBuffer_(ch, tracker, ch.state->offset);
+       tracker += res.used;
+
+       /* If tracker has looped, special care is needed for the rendering. If the
+    channel is in loop mode, fill the second part of the buffer with data
+    coming from the sample's head. */
+
+       if (tracker >= end)
+       {
+               ch.samplePlayer->waveReader.last();
+               tracker = begin;
+               sampleAdvancer::onLastFrame(ch); // TODO - better moving this to samplerAdvancer::advance
+               if (shouldLoop_(ch) && res.generated < ch.buffer->audio.countFrames())
+                       tracker += fillBuffer_(ch, tracker, res.generated).used;
+       }
 
-/* -------------------------------------------------------------------------- */
+       ch.state->offset = 0;
+       ch.state->tracker.store(tracker);
+}
 
+/* -------------------------------------------------------------------------- */
 
-ID SamplePlayer::getWaveId() const
+void loadWave(channel::Data& ch, Wave* w)
 {
-    return m_waveId;
+       ch.samplePlayer->waveReader.wave = w;
+
+       ch.state->tracker.store(0);
+       ch.samplePlayer->shift = 0;
+       ch.samplePlayer->begin = 0;
+
+       if (w != nullptr)
+       {
+               ch.state->playStatus.store(ChannelStatus::OFF);
+               ch.name              = w->getBasename(/*ext=*/false);
+               ch.samplePlayer->end = w->getBuffer().countFrames() - 1;
+       }
+       else
+       {
+               ch.state->playStatus.store(ChannelStatus::EMPTY);
+               ch.name              = "";
+               ch.samplePlayer->end = 0;
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+void setWave(channel::Data& ch, Wave* w, float samplerateRatio)
+{
+       setWave_(ch.samplePlayer.value(), w, samplerateRatio);
+}
+
+/* -------------------------------------------------------------------------- */
 
-Frame SamplePlayer::getWaveSize() const
+void kickIn(channel::Data& ch, Frame f)
 {
-    return hasWave() ? m_waveReader.wave->getSize() : 0;
+       ch.state->tracker.store(f);
+       ch.state->playStatus.store(ChannelStatus::PLAY);
 }
-}} // giada::m::
+} // namespace giada::m::samplePlayer
\ No newline at end of file
index 2ddfbc5e18424f270653d9347981dcee5e41b68f..e8dff83ffd060790e9afdb369b555abb2f55162b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_SAMPLE_PLAYER_H
 #define G_CHANNEL_SAMPLE_PLAYER_H
 
-
-#include "core/types.h"
-#include "core/const.h"
-#include "core/mixer.h" // TODO - forward declare
-#include "core/audioBuffer.h" // TODO - forward declare
+#include "core/channels/sampleAdvancer.h"
+#include "core/channels/sampleReactor.h"
 #include "core/channels/waveReader.h"
-#include "core/channels/sampleController.h"
-
+#include "core/const.h"
+#include "core/types.h"
 
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-class  Wave;
-struct SamplePlayerState;
-class SamplePlayer
+struct Data;
+}
+namespace giada::m::patch
 {
-public:
-
-    SamplePlayer(ChannelState*);
-    SamplePlayer(const patch::Channel& p, ChannelState*);
-    SamplePlayer(const SamplePlayer&, ChannelState* c=nullptr);
-
-    void parse(const mixer::Event& e) const;
-    void advance(Frame bufferSize) const;
-    void render(AudioBuffer& out) const;
-
-    bool hasWave() const;
-    bool hasLogicalWave() const;
-    bool hasEditedWave() const;
-    ID getWaveId() const;
-    Frame getWaveSize() const;
-
-    /* loadWave
-    Loads Wave 'w' into this channel and sets it up (name, markers, ...). */
-
-    void loadWave(const Wave* w);
-    
-    /* setWave
-    Just sets the pointer to a Wave object. Used during de-serialization. The
-    ratio is used to adjust begin/end points in case of patch vs. conf sample
-    rate mismatch. */
-
-    void setWave(const Wave& w, float samplerateRatio);
-
-    /* setInvalidWave
-    Same as setWave(nullptr) plus the invalid ID (i.e. 0). */
-    
-    void setInvalidWave(); 
-
-    /* kickIn
-    Starts the player right away at frame 'f'. Used when launching a loop after
-    being live recorded. */
-    
-    void kickIn(Frame f);
-
-
-    /* state
-    Pointer to mutable SamplePlayerState state. */
-
-    std::unique_ptr<SamplePlayerState> state;
-
-private:
-
-    bool shouldLoop() const;
-
-    ID m_waveId;
+struct Channel;
+}
+namespace giada::m::samplePlayer
+{
+struct Data
+{
+       Data(Resampler* r);
+       Data(const patch::Channel& p, float samplerateRatio, Resampler* r);
+       Data(const Data& o) = default;
+       Data(Data&& o)      = default;
+       Data& operator=(const Data&) = default;
+       Data& operator=(Data&&) = default;
+
+       bool  hasWave() const;
+       bool  hasLogicalWave() const;
+       bool  hasEditedWave() const;
+       bool  isAnyLoopMode() const;
+       ID    getWaveId() const;
+       Frame getWaveSize() const;
+       Wave* getWave() const;
+
+       float            pitch;
+       SamplePlayerMode mode;
+       Frame            shift;
+       Frame            begin;
+       Frame            end;
+       bool             velocityAsVol; // Velocity drives volume
+       WaveReader       waveReader;
+};
 
-    /* m_waveReader
-    Used to read data from Wave and fill incoming buffer. */
+void react(channel::Data& ch, const eventDispatcher::Event& e);
+void advance(const channel::Data& ch, const sequencer::Event& e);
+void render(const channel::Data& ch);
 
-    WaveReader m_waveReader;
+/* loadWave
+Loads Wave 'w' into channel ch and sets it up (name, markers, ...). */
 
-    /* m_sampleController
-    Managers events for this Sample Player. */
+void loadWave(channel::Data& ch, Wave* w);
 
-    SampleController m_sampleController;
+/* setWave
+Just sets the pointer to a Wave object. Used during de-serialization. The
+ratio is used to adjust begin/end points in case of patch vs. conf sample
+rate mismatch. If nullptr, set the wave to invalid. */
 
-    /* m_channelState
-    Pointer to Channel state. Needed to alter the playStatus status when the
-    sample is over. */
+void setWave(channel::Data& ch, Wave* w, float samplerateRatio);
 
-    ChannelState* m_channelState;
-};
-}} // giada::m::
+/* kickIn
+Starts the player right away at frame 'f'. Used when launching a loop after
+being live recorded. */
 
+void kickIn(channel::Data& ch, Frame f);
+} // namespace giada::m::samplePlayer
 
 #endif
diff --git a/src/core/channels/sampleReactor.cpp b/src/core/channels/sampleReactor.cpp
new file mode 100644 (file)
index 0000000..378cb58
--- /dev/null
@@ -0,0 +1,260 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "sampleReactor.h"
+#include "core/channels/channel.h"
+#include "core/clock.h"
+#include "core/conf.h"
+#include "src/core/model/model.h"
+#include "utils/math.h"
+#include <cassert>
+
+namespace giada::m::sampleReactor
+{
+namespace
+{
+constexpr int Q_ACTION_PLAY   = 0;
+constexpr int Q_ACTION_REWIND = 1;
+
+void          press_(channel::Data& ch, int velocity);
+void          release_(channel::Data& ch);
+void          kill_(channel::Data& ch);
+void          onStopBySeq_(channel::Data& ch);
+void          toggleReadActions_(channel::Data& ch);
+ChannelStatus pressWhileOff_(channel::Data& ch, int velocity, bool isLoop);
+ChannelStatus pressWhilePlay_(channel::Data& ch, SamplePlayerMode mode, bool isLoop);
+void          rewind_(channel::Data& ch, Frame localFrame = 0);
+
+/* -------------------------------------------------------------------------- */
+
+void press_(channel::Data& ch, int velocity)
+{
+       ChannelStatus    playStatus = ch.state->playStatus.load();
+       SamplePlayerMode mode       = ch.samplePlayer->mode;
+       bool             isLoop     = ch.samplePlayer->isAnyLoopMode();
+
+       switch (playStatus)
+       {
+       case ChannelStatus::OFF:
+               playStatus = pressWhileOff_(ch, velocity, isLoop);
+               break;
+
+       case ChannelStatus::PLAY:
+               playStatus = pressWhilePlay_(ch, mode, isLoop);
+               break;
+
+       case ChannelStatus::WAIT:
+               playStatus = ChannelStatus::OFF;
+               break;
+
+       case ChannelStatus::ENDING:
+               playStatus = ChannelStatus::PLAY;
+               break;
+
+       default:
+               break;
+       }
+
+       ch.state->playStatus.store(playStatus);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void release_(channel::Data& ch)
+{
+       /* Key release is meaningful only for SINGLE_PRESS modes. */
+
+       if (ch.samplePlayer->mode != SamplePlayerMode::SINGLE_PRESS)
+               return;
+
+       /* Kill it if it's SINGLE_PRESS is playing. Otherwise there might be a 
+       quantization step in progress that would play the channel later on: 
+       disable it. */
+
+       if (ch.state->playStatus.load() == ChannelStatus::PLAY)
+               kill_(ch);
+       else if (sequencer::quantizer.hasBeenTriggered())
+               sequencer::quantizer.clear();
+}
+
+/* -------------------------------------------------------------------------- */
+
+void kill_(channel::Data& ch)
+{
+       ch.state->playStatus.store(ChannelStatus::OFF);
+       ch.state->tracker.store(ch.samplePlayer->begin);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void onStopBySeq_(channel::Data& ch)
+{
+       G_DEBUG("onStopBySeq ch=" << ch.id);
+
+       ChannelStatus playStatus       = ch.state->playStatus.load();
+       bool          isReadingActions = ch.state->readActions.load();
+       bool          isLoop           = ch.samplePlayer->isAnyLoopMode();
+
+       switch (playStatus)
+       {
+
+       case ChannelStatus::WAIT:
+               /* Loop-mode channels in wait status get stopped right away. */
+               if (isLoop)
+                       ch.state->playStatus.store(ChannelStatus::OFF);
+               break;
+
+       case ChannelStatus::PLAY:
+               if (conf::conf.chansStopOnSeqHalt && (isLoop || isReadingActions))
+                       kill_(ch);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+ChannelStatus pressWhileOff_(channel::Data& ch, int velocity, bool isLoop)
+{
+       if (isLoop)
+               return ChannelStatus::WAIT;
+
+       if (ch.samplePlayer->velocityAsVol)
+               ch.volume_i = u::math::map(velocity, G_MAX_VELOCITY, G_MAX_VOLUME);
+
+       if (clock::canQuantize())
+       {
+               sequencer::quantizer.trigger(Q_ACTION_PLAY + ch.id);
+               return ChannelStatus::OFF;
+       }
+       else
+               return ChannelStatus::PLAY;
+}
+
+/* -------------------------------------------------------------------------- */
+
+ChannelStatus pressWhilePlay_(channel::Data& ch, SamplePlayerMode mode, bool isLoop)
+{
+       if (mode == SamplePlayerMode::SINGLE_RETRIG)
+       {
+               if (clock::canQuantize())
+                       sequencer::quantizer.trigger(Q_ACTION_REWIND + ch.id);
+               else
+                       rewind_(ch);
+               return ChannelStatus::PLAY;
+       }
+
+       if (isLoop || mode == SamplePlayerMode::SINGLE_ENDLESS)
+               return ChannelStatus::ENDING;
+
+       if (mode == SamplePlayerMode::SINGLE_BASIC)
+       {
+               rewind_(ch);
+               return ChannelStatus::OFF;
+       }
+
+       return ChannelStatus::OFF;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void toggleReadActions_(channel::Data& ch)
+{
+       if (clock::isRunning() && ch.state->recStatus.load() == ChannelStatus::PLAY && !conf::conf.treatRecsAsLoops)
+               kill_(ch);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void rewind_(channel::Data& ch, Frame localFrame)
+{
+       if (ch.isPlaying())
+       {
+               ch.state->rewinding = true;
+               ch.state->offset    = localFrame;
+       }
+       else
+               ch.state->tracker.store(ch.samplePlayer->begin);
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+Data::Data(ID channelId)
+{
+       sequencer::quantizer.schedule(Q_ACTION_PLAY + channelId, [channelId](Frame delta) {
+               channel::Data& ch = model::get().getChannel(channelId);
+               ch.state->offset  = delta;
+               ch.state->playStatus.store(ChannelStatus::PLAY);
+       });
+
+       sequencer::quantizer.schedule(Q_ACTION_REWIND + channelId, [channelId](Frame delta) {
+               channel::Data& ch = model::get().getChannel(channelId);
+               rewind_(ch, delta);
+       });
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+void react(channel::Data& ch, const eventDispatcher::Event& e)
+{
+       if (!ch.hasWave())
+               return;
+
+       switch (e.type)
+       {
+
+       case eventDispatcher::EventType::KEY_PRESS:
+               press_(ch, std::get<int>(e.data));
+               break;
+
+       case eventDispatcher::EventType::KEY_RELEASE:
+               release_(ch);
+               break;
+
+       case eventDispatcher::EventType::KEY_KILL:
+               kill_(ch);
+               break;
+
+       case eventDispatcher::EventType::SEQUENCER_STOP:
+               onStopBySeq_(ch);
+               break;
+
+       case eventDispatcher::EventType::CHANNEL_TOGGLE_READ_ACTIONS:
+               toggleReadActions_(ch);
+               break;
+
+       default:
+               break;
+       }
+}
+} // namespace giada::m::sampleReactor
\ No newline at end of file
diff --git a/src/core/channels/sampleReactor.h b/src/core/channels/sampleReactor.h
new file mode 100644 (file)
index 0000000..a82b1c7
--- /dev/null
@@ -0,0 +1,56 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_CHANNEL_SAMPLE_REACTOR_H
+#define G_CHANNEL_SAMPLE_REACTOR_H
+
+#include "core/eventDispatcher.h"
+#include "core/quantizer.h"
+
+namespace giada::m::channel
+{
+struct Data;
+}
+
+/* sampleReactor
+Reacts to manual events sent to Sample Channels: key press, key release, 
+sequencer stop, ... . */
+
+namespace giada::m::sampleReactor
+{
+struct Data
+{
+       Data(ID channelId);
+       Data(const Data&) = default;
+       Data(Data&&)      = default;
+       Data& operator=(const Data&) = default;
+       Data& operator=(Data&&) = default;
+};
+
+void react(channel::Data& ch, const eventDispatcher::Event& e);
+} // namespace giada::m::sampleReactor
+
+#endif
diff --git a/src/core/channels/state.cpp b/src/core/channels/state.cpp
deleted file mode 100644 (file)
index b3dbd0e..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include "core/conf.h"
-#include "core/patch.h"
-#include "state.h"
-
-
-namespace giada {
-namespace m 
-{
-MidiLearnerState::MidiLearnerState()
-: enabled      (true)
-, filter       (0)
-{
-}
-
-
-MidiLearnerState::MidiLearnerState(const patch::Channel& p)
-: enabled      (p.midiIn)
-, filter       (p.midiInFilter)
-, keyPress     (p.midiInKeyPress)
-, keyRelease   (p.midiInKeyRel)
-, kill         (p.midiInKill)
-, arm          (p.midiInArm)
-, volume       (p.midiInVolume)
-, mute         (p.midiInMute)
-, solo         (p.midiInSolo)
-, readActions  (p.midiInReadActions)
-, pitch        (p.midiInPitch)
-{
-}
-
-
-MidiLearnerState::MidiLearnerState(const MidiLearnerState& o)
-: enabled      (o.enabled.load())
-, filter       (o.filter.load())
-, keyPress     (o.keyPress)
-, keyRelease   (o.keyRelease)
-, kill         (o.kill)
-, arm          (o.arm)
-, volume       (o.volume)
-, mute         (o.mute)
-, solo         (o.solo)
-, readActions  (o.readActions)
-, pitch        (o.pitch)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool MidiLearnerState::isAllowed(int c) const
-{
-    int filter_   = filter.load();
-    bool enabled_ = enabled.load();
-
-       return enabled_ && (filter_ == -1 || filter_ == c);
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-MidiLighterState::MidiLighterState()
-: enabled(false)
-, playing(0x0)
-{
-}
-
-
-MidiLighterState::MidiLighterState(const patch::Channel& p)
-: enabled(p.midiOutL)
-, playing(p.midiOutLplaying)
-, mute   (p.midiOutLmute)
-, solo   (p.midiOutLsolo)
-{
-}
-
-
-MidiLighterState::MidiLighterState(const MidiLighterState& o)
-: enabled(o.enabled.load())
-, playing(o.playing)
-, mute   (o.mute)
-, solo   (o.solo)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-MidiSenderState::MidiSenderState()
-: enabled(false)
-, filter (0)
-{
-}
-
-
-MidiSenderState::MidiSenderState(const patch::Channel& p)
-: enabled(p.midiOut)
-, filter (p.midiOutChan)
-{
-}
-
-
-MidiSenderState::MidiSenderState(const MidiSenderState& o)
-: enabled(o.enabled.load())
-, filter (o.filter.load())
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-MidiReceiverState::MidiReceiverState()
-{
-    midiBuffer.ensureSize(G_DEFAULT_VST_MIDIBUFFER_SIZE);
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-SamplePlayerState::SamplePlayerState()
-: tracker      (0)
-, pitch        (G_DEFAULT_PITCH)
-, mode         (SamplePlayerMode::SINGLE_BASIC)
-, velocityAsVol(false)
-, rewinding    (false)
-, quantizing   (false)
-, offset       (0)
-{
-}
-
-
-SamplePlayerState::SamplePlayerState(const SamplePlayerState& o)
-: tracker      (o.tracker.load())
-, pitch        (o.pitch.load())
-, mode         (o.mode.load())
-, shift        (o.shift.load())
-, begin        (o.begin.load())
-, end          (o.end.load())
-, velocityAsVol(o.velocityAsVol.load())
-, rewinding    (o.rewinding)
-, quantizing   (o.quantizing)
-, offset       (o.offset)
-, quantizer    (o.quantizer)
-{
-}
-
-
-SamplePlayerState::SamplePlayerState(const patch::Channel& p)
-: tracker      (0)
-, pitch        (p.pitch)
-, mode         (p.mode)
-, shift        (p.shift)
-, begin        (p.begin)
-, end          (p.end)
-, velocityAsVol(p.midiInVeloAsVol)
-, rewinding    (false)
-, quantizing   (false)
-, offset       (0)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool SamplePlayerState::isAnyLoopMode() const
-{
-    SamplePlayerMode m = mode.load();
-
-       return m == SamplePlayerMode::LOOP_BASIC  || 
-              m == SamplePlayerMode::LOOP_ONCE   || 
-              m == SamplePlayerMode::LOOP_REPEAT || 
-              m == SamplePlayerMode::LOOP_ONCE_BAR;
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-AudioReceiverState::AudioReceiverState(const conf::Conf& c)
-: inputMonitor     (c.inputMonitorDefaultOn)
-, overdubProtection(c.overdubProtectionDefaultOn)
-{
-}
-
-
-AudioReceiverState::AudioReceiverState(const patch::Channel& p)
-: inputMonitor     (p.inputMonitor)
-, overdubProtection(p.overdubProtection)
-{
-}
-
-
-AudioReceiverState::AudioReceiverState(const AudioReceiverState& o)
-: inputMonitor     (o.inputMonitor.load())
-, overdubProtection(o.overdubProtection.load())
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-ChannelState::ChannelState(ID id, Frame bufferSize)
-: id         (id)
-, playStatus (ChannelStatus::OFF)
-, recStatus  (ChannelStatus::OFF)
-, volume     (G_DEFAULT_VOL)
-, pan        (G_DEFAULT_PAN)
-, mute       (false)
-, solo       (false)
-, armed      (false)
-, key        (0)
-, readActions(true)
-, buffer     (bufferSize, G_MAX_IO_CHANS)
-, hasActions (false)
-, height     (G_GUI_UNIT)
-, volume_i   (1.0f)
-{
-}
-    
-
-ChannelState::ChannelState(const ChannelState& o)
-: id         (o.id)
-, playStatus (o.playStatus.load())
-, recStatus  (o.recStatus.load())
-, volume     (o.volume.load())
-, pan        (o.pan.load())
-, mute       (o.mute.load())
-, solo       (o.solo.load())
-, armed      (o.armed.load())
-, key        (o.key.load())
-, readActions(o.readActions.load())
-, buffer     (o.buffer)
-, hasActions (o.hasActions)
-, name       (o.name)
-, height     (o.height)
-, volume_i   (o.volume_i)
-{
-}
-
-
-ChannelState::ChannelState(const patch::Channel& p, Frame bufferSize)
-: id         (p.id)
-, playStatus (ChannelStatus::OFF)
-, recStatus  (ChannelStatus::OFF)
-, volume     (p.volume)
-, pan        (p.pan)
-, mute       (p.mute)
-, solo       (p.solo)
-, armed      (p.armed)
-, key        (p.key)
-, readActions(p.readActions)
-, buffer     (bufferSize, G_MAX_IO_CHANS)
-, hasActions (p.hasActions)
-, name       (p.name)
-, height     (p.height)
-, volume_i   (1.0f)
-{
-}
-    
-
-/* -------------------------------------------------------------------------- */
-
-
-bool ChannelState::isPlaying() const
-{
-    ChannelStatus s = playStatus.load();
-       return s == ChannelStatus::PLAY || s == ChannelStatus::ENDING;
-}
-}} // giada::m::
diff --git a/src/core/channels/state.h b/src/core/channels/state.h
deleted file mode 100644 (file)
index 9e69e2c..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef G_CHANNEL_STATE_H
-#define G_CHANNEL_STATE_H
-
-
-#include <string>
-#include <atomic>
-#include "core/const.h"
-#include "core/types.h"
-#include "core/quantizer.h"
-#include "core/audioBuffer.h"
-#include "core/midiLearnParam.h"
-#ifdef WITH_VST
-#include "deps/juce-config.h"
-#endif
-
-
-namespace giada {
-namespace m {
-namespace conf
-{
-struct Conf;
-}
-namespace patch
-{
-struct Channel;
-}
-struct MidiLearnerState
-{
-    MidiLearnerState();
-    MidiLearnerState(const patch::Channel& p);
-    MidiLearnerState(const MidiLearnerState& o);
-
-    /* isAllowed
-    Tells whether the current MIDI channel 'channel' is enabled to receive MIDI
-    data. */
-
-    bool isAllowed(int channel) const;
-
-    /* enabled
-    Tells whether MIDI learning is enabled for the current channel. */
-    
-       std::atomic<bool> enabled;
-
-    /* filter
-    Which MIDI channel should be filtered out when receiving MIDI messages. 
-    If -1 means 'all'. */
-    
-    std::atomic<int> filter;
-
-    /* MIDI learning fields. */
-
-       MidiLearnParam keyPress;
-       MidiLearnParam keyRelease;
-       MidiLearnParam kill;
-       MidiLearnParam arm;
-       MidiLearnParam volume;
-       MidiLearnParam mute;
-       MidiLearnParam solo;
-       MidiLearnParam readActions; // Sample Channels only
-       MidiLearnParam pitch;       // Sample Channels only
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-struct MidiLighterState
-{
-    MidiLighterState();
-    MidiLighterState(const patch::Channel& p);
-    MidiLighterState(const MidiLighterState& o);
-
-    /* enabled
-    Tells whether MIDI ligthing is enabled or not. */
-    
-       std::atomic<bool> enabled;
-
-    /* MIDI learning fields for MIDI ligthing. */
-
-       MidiLearnParam playing;
-       MidiLearnParam mute;
-       MidiLearnParam solo;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-struct MidiSenderState
-{
-    MidiSenderState();
-    MidiSenderState(const patch::Channel& p);
-    MidiSenderState(const MidiSenderState& o);
-
-    /* enabled
-    Tells whether MIDI output is enabled or not. */
-    
-       std::atomic<bool> enabled;
-
-    /* filter
-    Which MIDI channel data should be sent to. */
-    
-    std::atomic<int> filter;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-struct MidiReceiverState
-{
-    MidiReceiverState();
-
-       /* midiBuffer 
-       Contains MIDI events to be sent to plug-ins. */
-
-       juce::MidiBuffer midiBuffer;
-};
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-struct SamplePlayerState
-{
-    SamplePlayerState();
-    SamplePlayerState(const patch::Channel& p);
-    SamplePlayerState(const SamplePlayerState& o);
-
-    bool isAnyLoopMode() const;
-
-    std::atomic<Frame>            tracker;
-    std::atomic<float>            pitch;
-    std::atomic<SamplePlayerMode> mode;
-    std::atomic<Frame>            shift;
-    std::atomic<Frame>            begin;
-    std::atomic<Frame>            end;
-
-    /* velocityAsVol
-    Velocity drives volume. */
-
-       std::atomic<bool> velocityAsVol;
-
-    bool      rewinding;
-    bool      quantizing;
-    Frame     offset;
-    Quantizer quantizer;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-struct AudioReceiverState
-{
-    AudioReceiverState(const conf::Conf& c);
-    AudioReceiverState(const patch::Channel& p);
-    AudioReceiverState(const AudioReceiverState& o);
-
-    std::atomic<bool> inputMonitor;
-    std::atomic<bool> overdubProtection;
-};
-
-
-/* -------------------------------------------------------------------------- */
-
-
-struct ChannelState
-{
-    ChannelState(ID id, Frame bufferSize);
-    ChannelState(const patch::Channel& p, Frame bufferSize);
-    ChannelState(const ChannelState& o);
-
-    bool isPlaying() const;
-
-    ID id;
-
-    std::atomic<ChannelStatus> playStatus;
-       std::atomic<ChannelStatus> recStatus;
-    std::atomic<float>         volume;
-    std::atomic<float>         pan;
-    std::atomic<bool>          mute;
-    std::atomic<bool>          solo;
-    std::atomic<bool>          armed;
-    std::atomic<int>           key;
-       std::atomic<bool>          readActions;
-       
-       /* buffer (internal)
-       Working buffer for internal processing. */
-
-    AudioBuffer buffer;
-
-    bool        hasActions;
-    std::string name;
-    Pixel       height;
-
-       /* volume_i (internal)
-       Internal volume used for volume automation and velocity-drives-volume mode
-    on Sample Channels. */
-
-    float volume_i;
-};
-}} // giada::m::
-
-
-#endif
index 9f5717401d4660092d7b0e1c0dc22978d24885fb..fd190ca1bd2e8e083403c6313b105f62bf6bfc17 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <memory>
-#include <cassert>
-#include <algorithm>
+#include "waveReader.h"
+#include "core/audioBuffer.h"
 #include "core/const.h"
 #include "core/model/model.h"
-#include "core/audioBuffer.h"
 #include "core/wave.h"
 #include "utils/log.h"
-#include "waveReader.h"
-
-
-namespace giada {
-namespace m 
-{
-WaveReader::WaveReader()
-: wave      (nullptr),
-  m_srcState(nullptr)
-{
-       allocateSrc();
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-WaveReader::WaveReader(const WaveReader& o)
-: wave      (o.wave),
-  m_srcState(nullptr)
-{
-       allocateSrc();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-WaveReader::WaveReader(WaveReader&& o)
-: wave      (o.wave),
-  m_srcState(nullptr)
-{
-       moveSrc(&o.m_srcState);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-WaveReader& WaveReader::operator=(const WaveReader& o)
-{
-       if (this == &o) return *this;
-       wave = o.wave;
-       allocateSrc();
-       return *this;
-}
-
+#include <algorithm>
+#include <cassert>
+#include <memory>
 
-WaveReader& WaveReader::operator=(WaveReader&& o)
+namespace giada::m
 {
-       if (this == &o) return *this;
-       wave = o.wave;
-       moveSrc(&o.m_srcState);
-       return *this;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-WaveReader::~WaveReader()
+WaveReader::WaveReader(Resampler* r)
+: wave(nullptr)
+, m_resampler(r)
 {
-       if (m_srcState != nullptr)
-               src_delete(m_srcState);    
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Frame WaveReader::fill(AudioBuffer& out, Frame start, Frame offset, float pitch) const
+WaveReader::Result WaveReader::fill(AudioBuffer& out, Frame start, Frame max,
+    Frame offset, float pitch) const
 {
        assert(wave != nullptr);
        assert(start >= 0);
+       assert(max <= wave->getBuffer().countFrames());
        assert(offset < out.countFrames());
 
-       model::WavesLock l(model::waves); // TODO dependency
-       
-       if (pitch == 1.0) return fillCopy(out, start, offset);
-       else              return fillResampled(out, start, offset, pitch);
+       if (pitch == 1.0f)
+               return fillCopy(out, start, max, offset);
+       else
+               return fillResampled(out, start, max, offset, pitch);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Frame WaveReader::fillResampled(AudioBuffer& dest, Frame start, Frame offset, float pitch) const
+WaveReader::Result WaveReader::fillResampled(AudioBuffer& dest, Frame start,
+    Frame max, Frame offset, float pitch) const
 {
-    SRC_DATA srcData;
-       
-       srcData.data_in       = wave->getFrame(start);        // Source data
-       srcData.input_frames  = wave->getSize() - start;      // How many readable frames
-       srcData.data_out      = dest[offset];                 // Destination (processed data)
-       srcData.output_frames = dest.countFrames() - offset;  // How many frames to process
-       srcData.end_of_input  = false;
-       srcData.src_ratio     = 1 / pitch;
-
-       src_process(m_srcState, &srcData);
-
-       return srcData.input_frames_used;
+       Resampler::Result res = m_resampler->process(
+           /*input=*/wave->getBuffer()[0],
+           /*inputPos=*/start,
+           /*inputLen=*/max,
+           /*output=*/dest[offset],
+           /*outputLen=*/dest.countFrames() - offset,
+           /*pitch=*/pitch);
+
+       return {
+           static_cast<int>(res.used),
+           static_cast<int>(res.generated)};
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Frame WaveReader::fillCopy(AudioBuffer& dest, Frame start, Frame offset) const
+WaveReader::Result WaveReader::fillCopy(AudioBuffer& dest, Frame start, Frame max, Frame offset) const
 {
        Frame used = dest.countFrames() - offset;
-       if (used > wave->getSize() - start)
-               used = wave->getSize() - start;
+       if (used > max - start)
+               used = max - start;
 
-       dest.copyData(wave->getFrame(start), used, G_MAX_IO_CHANS, offset);
+       dest.set(wave->getBuffer(), used, start, offset);
 
-       return used;
+       return {used, used};
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void WaveReader::allocateSrc()
-{
-       m_srcState = src_new(SRC_LINEAR, G_MAX_IO_CHANS, nullptr);
-       if (m_srcState == nullptr) {
-               u::log::print("[WaveReader] unable to allocate memory for SRC_STATE!\n");
-               throw std::bad_alloc();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void WaveReader::moveSrc(SRC_STATE** other)
+void WaveReader::last() const
 {
-       if (m_srcState != nullptr)
-               src_delete(m_srcState);
-       m_srcState = *other;
-       *other = nullptr;
+       if (m_resampler != nullptr)
+               m_resampler->last();
 }
-}} // giada::m::
+} // namespace giada::m
index 1d6bc445069fa242b1cd68cb093c4c9a49d12217..ee0ab6d28cdd6ee9649ecd1946036dc1c044c09b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CHANNEL_WAVE_READER_H
 #define G_CHANNEL_WAVE_READER_H
 
-
-#include <samplerate.h>
 #include "core/types.h"
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 class Wave;
+class AudioBuffer;
+class Resampler;
 class WaveReader final
 {
 public:
+       /* Result
+       A Result object is returned by the fill() function below, containing the 
+       number of frames used and generated from a buffer filling operation. The
+       two values are different only when pitch is != 1.0, where a chunk of audio
+       in input (used) might result in a longer or shorter portion of audio in 
+       output (generated). */
 
-    WaveReader();
-    WaveReader(const WaveReader&);
-    WaveReader(WaveReader&&);
-    WaveReader& operator=(const WaveReader&);
-    WaveReader& operator=(WaveReader&&);
-    ~WaveReader();
+       struct Result
+       {
+               Frame used, generated;
+       };
 
-    Frame fill(AudioBuffer& out, Frame start, Frame offset, float pitch) const;
+       WaveReader() = delete;
+       WaveReader(Resampler* r);
 
-       /* wave
-       Wave object. Might be null if the channel has no sample. */
+       /* fill
+       Fills audio buffer 'out' with data coming from Wave, copying it from 'start'
+       frame up to 'max'. The buffer is filled starting at 'offset'. */
 
-       const Wave* wave;
+       Result fill(AudioBuffer& out, Frame start, Frame max, Frame offset,
+           float pitch) const;
 
-private:
+       /* last
+       Call this when you are about to process the last chunk of pitched data. 
+       Ignored if pitch == 1.0. */
 
-       Frame fillResampled(AudioBuffer& out, Frame start, Frame offset, float pitch) const;
-       Frame fillCopy     (AudioBuffer& out, Frame start, Frame offset) const;
+       void last() const;
 
-       void allocateSrc();
-       void moveSrc(SRC_STATE** o);
+       /* wave
+       Wave object. Might be null if the channel has no sample. */
 
-       /* srcState
-       Struct from libsamplerate. */
+       Wave* wave;
 
-       SRC_STATE* m_srcState;
-};
-}} // giada::m::
+private:
+       Result fillResampled(AudioBuffer& out, Frame start, Frame max, Frame offset,
+           float pitch) const;
+       Result fillCopy(AudioBuffer& out, Frame start, Frame max, Frame offset) const;
 
+       Resampler* m_resampler;
+};
+} // namespace giada::m
 
 #endif
index 2dd28ef105ab35fc1dd4bc391d7a98233b1434e6..da98093977d29180549d8fc607c4c1d8ea23cbf2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <atomic>
-#include <cassert>
-#include "glue/main.h"
-#include "glue/events.h"
-#include "core/model/model.h"
+#include "clock.h"
 #include "core/conf.h"
-#include "core/sequencer.h"
 #include "core/const.h"
 #include "core/kernelAudio.h"
-#include "core/mixerHandler.h"
 #include "core/kernelMidi.h"
+#include "core/mixerHandler.h"
+#include "core/model/model.h"
+#include "core/recorderHandler.h"
+#include "core/sequencer.h"
+#include "glue/events.h"
+#include "utils/log.h"
 #include "utils/math.h"
-#include "clock.h"
-
+#include <atomic>
+#include <cassert>
 
 namespace giada::m::clock
 {
 namespace
 {
-std::atomic<int> currentFrameWait_(0);
-std::atomic<int> currentFrame_(0);
-std::atomic<int> currentBeat_(0);
-
 /* quantizerStep_
 Tells how many frames to wait to perform a quantized action. */
 
@@ -56,7 +51,7 @@ int quantizerStep_ = 1;
 /* midiTC*
 MIDI timecode variables. */
 
-int midiTCrate_    = 0;      // Send MTC data every midiTCrate_ frames
+int midiTCrate_    = 0; // Send MTC data every midiTCrate_ frames
 int midiTCframes_  = 0;
 int midiTCseconds_ = 0;
 int midiTCminutes_ = 0;
@@ -66,7 +61,6 @@ int midiTChours_   = 0;
 kernelAudio::JackState jackStatePrev_;
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
 /* recomputeFrames_
@@ -75,232 +69,223 @@ Updates bpm, frames, beats and so on. Private version. */
 void recomputeFrames_(model::Clock& c)
 {
        c.framesInLoop = static_cast<int>((conf::conf.samplerate * (60.0f / c.bpm)) * c.beats);
-       c.framesInBar  = static_cast<int>(c.framesInLoop / (float) c.bars);
-       c.framesInBeat = static_cast<int>(c.framesInLoop / (float) c.beats);
+       c.framesInBar  = static_cast<int>(c.framesInLoop / (float)c.bars);
+       c.framesInBeat = static_cast<int>(c.framesInLoop / (float)c.beats);
        c.framesInSeq  = c.framesInBeat * G_MAX_BEATS;
 
        if (c.quantize != 0)
                quantizerStep_ = c.framesInBeat / c.quantize;
 }
-} // {anonymous}
 
+/* -------------------------------------------------------------------------- */
+
+void setBpm_(float current)
+{
+       float ratio = model::get().clock.bpm / current;
+
+       model::get().clock.bpm = current;
+       recomputeFrames_(model::get().clock);
+
+       m::recorderHandler::updateBpm(ratio, quantizerStep_);
+
+       model::swap(model::SwapType::HARD);
+
+       u::log::print("[clock::setBpm_] Bpm changed to %f\n", current);
+}
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void init(int sampleRate, float midiTCfps)
 {
-       midiTCrate_ = static_cast<int>((sampleRate / midiTCfps) * G_MAX_IO_CHANS);  // stereo values
+       midiTCrate_ = static_cast<int>((sampleRate / midiTCfps) * G_MAX_IO_CHANS); // stereo values
 
-       model::onSwap(model::clock, [&](model::Clock& c)
-       {
-               c.bars     = G_DEFAULT_BARS;
-               c.beats    = G_DEFAULT_BEATS;
-               c.bpm      = G_DEFAULT_BPM;
-               c.quantize = G_DEFAULT_QUANTIZE;
-               recomputeFrames_(c);
-       });
-}
+       model::get().clock.bars     = G_DEFAULT_BARS;
+       model::get().clock.beats    = G_DEFAULT_BEATS;
+       model::get().clock.bpm      = G_DEFAULT_BPM;
+       model::get().clock.quantize = G_DEFAULT_QUANTIZE;
+       recomputeFrames_(model::get().clock);
 
+       model::swap(model::SwapType::NONE);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void recomputeFrames()
 {
-       model::onSwap(model::clock, [&](model::Clock& c) { recomputeFrames_(c); });
+       recomputeFrames_(model::get().clock);
+       model::swap(model::SwapType::NONE);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isRunning()
 {
-       model::ClockLock lock(model::clock);
-
-       return model::clock.get()->status == ClockStatus::RUNNING;
+       return model::get().clock.status == ClockStatus::RUNNING;
 }
 
-
 bool isActive()
 {
-       model::ClockLock lock(model::clock);
-       
-       ClockStatus status = model::clock.get()->status;
-       return status == ClockStatus::RUNNING || status == ClockStatus::WAITING;
+       const model::Clock& c = model::get().clock;
+       return c.status == ClockStatus::RUNNING || c.status == ClockStatus::WAITING;
 }
 
-
 bool quantoHasPassed()
 {
-       return clock::getQuantizerValue() != 0 && currentFrame_.load() % quantizerStep_ == 0;
+       const model::Clock& c = model::get().clock;
+       return clock::getQuantizerValue() != 0 && c.state->currentFrame.load() % quantizerStep_ == 0;
 }
 
-
 bool isOnBar()
 {
-       model::ClockLock lock(model::clock);
+       const model::Clock& c = model::get().clock;
 
-       const model::Clock* c = model::clock.get();
-       
-       int currentFrame = currentFrame_.load();
+       int currentFrame = c.state->currentFrame.load();
 
-       if (c->status == ClockStatus::WAITING || currentFrame == 0)
+       if (c.status == ClockStatus::WAITING || currentFrame == 0)
                return false;
-       return currentFrame % c->framesInBar == 0;
+       return currentFrame % c.framesInBar == 0;
 }
 
-
 bool isOnBeat()
 {
-       model::ClockLock lock(model::clock);
-       
-       const model::Clock* c = model::clock.get();
-       
-       if (c->status == ClockStatus::WAITING)
-               return currentFrameWait_.load() % c->framesInBeat == 0;
-       return currentFrame_.load() % c->framesInBeat == 0;
-}
+       const model::Clock& c = model::get().clock;
 
+       if (c.status == ClockStatus::WAITING)
+               return c.state->currentFrameWait.load() % c.framesInBeat == 0;
+       return c.state->currentFrame.load() % c.framesInBeat == 0;
+}
 
 bool isOnFirstBeat()
 {
-       return currentFrame_.load() == 0;
+       return model::get().clock.state->currentFrame.load() == 0;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setBpm(float b)
-{      
+{
        b = std::clamp(b, G_MIN_BPM, G_MAX_BPM);
 
-       model::onSwap(model::clock, [&](model::Clock& c)
+       /* If JACK is being used, let it handle the bpm change. */
+
+#ifdef WITH_AUDIO_JACK
+       if (kernelAudio::getAPI() == G_SYS_API_JACK)
        {
-               c.bpm = b;
-               recomputeFrames_(c);
-       });
-}
+               kernelAudio::jackSetBpm(b);
+               return;
+       }
+#endif
 
+       setBpm_(b);
+}
 
 void setBeats(int newBeats, int newBars)
 {
        newBeats = std::clamp(newBeats, 1, G_MAX_BEATS);
        newBars  = std::clamp(newBars, 1, newBeats); // Bars cannot be greater than beats
 
-       model::onSwap(model::clock, [&](model::Clock& c)
-       {
-               c.beats = newBeats;
-               c.bars  = newBars;
-               recomputeFrames_(c);
-       });
-}
+       model::get().clock.beats = newBeats;
+       model::get().clock.bars  = newBars;
+       recomputeFrames_(model::get().clock);
 
+       model::swap(model::SwapType::HARD);
+}
 
 void setQuantize(int q)
 {
-       model::onSwap(model::clock, [&](model::Clock& c)
-       {
-               c.quantize = q; 
-               recomputeFrames_(c);
-       });
-}
+       model::get().clock.quantize = q;
+       recomputeFrames_(model::get().clock);
 
+       model::swap(model::SwapType::HARD);
+}
 
 void setStatus(ClockStatus s)
 {
-       model::onSwap(model::clock, [&](model::Clock& c)
+       model::get().clock.status = s;
+       model::swap(model::SwapType::SOFT);
+
+       if (s == ClockStatus::RUNNING)
        {
-               c.status = s;
-       });
-       
-       if (s == ClockStatus::RUNNING) {
-               if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M) {
+               if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M)
+               {
                        kernelMidi::send(MIDI_START, -1, -1);
                        kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
                }
        }
-       else
-       if (s == ClockStatus::STOPPED) {
+       else if (s == ClockStatus::STOPPED)
+       {
                if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M)
                        kernelMidi::send(MIDI_STOP, -1, -1);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void incrCurrentFrame() 
+void advance(Frame amount)
 {
-       model::ClockLock lock(model::clock);
-       
-       const model::Clock* c = model::clock.get();
-
-       if (c->status == ClockStatus::WAITING) {
-               int f = currentFrameWait_.load() + 1;
-               f %= c->framesInLoop;
-               currentFrameWait_.store(f);
+       const model::Clock& c = model::get().clock;
+
+       if (c.status == ClockStatus::WAITING)
+       {
+               int f = (c.state->currentFrameWait.load() + amount) % c.framesInLoop;
+               c.state->currentFrameWait.store(f);
                return;
        }
 
-       int f = currentFrame_.load() + 1;
-       int b = currentBeat_.load();
+       int f = (c.state->currentFrame.load() + amount) % c.framesInLoop;
+       int b = f / c.framesInBeat;
 
-       f %= c->framesInLoop;
-       b = f / c->framesInBeat;
-       
-       currentFrame_.store(f);
-       currentBeat_.store(b);
+       c.state->currentFrame.store(f);
+       c.state->currentBeat.store(b);
 }
 
+/* -------------------------------------------------------------------------- */
 
 void rewind()
 {
-       currentFrame_.store(0);
-       currentBeat_.store(0);
-       currentFrameWait_.store(0);
-       
+       const model::Clock& c = model::get().clock;
+
+       c.state->currentFrame.store(0);
+       c.state->currentBeat.store(0);
+       c.state->currentFrameWait.store(0);
+
        sendMIDIrewind();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sendMIDIsync()
 {
-       model::ClockLock lock(model::clock);
-       
-       const model::Clock* c = model::clock.get();
-       
+       const model::Clock& c = model::get().clock;
+
        /* Sending MIDI sync while waiting is meaningless. */
 
-       if (c->status == ClockStatus::WAITING)
+       if (c.status == ClockStatus::WAITING)
                return;
 
-       int currentFrame = currentFrame_.load();
+       int currentFrame = c.state->currentFrame.load();
 
        /* TODO - only Master (_M) is implemented so far. */
 
-       if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M) {
-               if (currentFrame % (c->framesInBeat / 24) == 0)
+       if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M)
+       {
+               if (currentFrame % (c.framesInBeat / 24) == 0)
                        kernelMidi::send(MIDI_CLOCK, -1, -1);
                return;
        }
 
-       if (conf::conf.midiSync == MIDI_SYNC_MTC_M) {
+       if (conf::conf.midiSync == MIDI_SYNC_MTC_M)
+       {
 
                /* check if a new timecode frame has passed. If so, send MIDI TC
                 * quarter frames. 8 quarter frames, divided in two branches:
                 * 1-4 and 5-8. We check timecode frame's parity: if even, send
                 * range 1-4, if odd send 5-8. */
 
-               if (currentFrame % midiTCrate_ != 0)  // no timecode frame passed
+               if (currentFrame % midiTCrate_ != 0) // no timecode frame passed
                        return;
 
                /* frame low nibble
@@ -308,11 +293,12 @@ void sendMIDIsync()
                 * seconds low nibble
                 * seconds high nibble */
 
-               if (midiTCframes_ % 2 == 0) {
-                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes_ & 0x0F)  | 0x00, -1);
-                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes_ >> 4)    | 0x10, -1);
+               if (midiTCframes_ % 2 == 0)
+               {
+                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes_ & 0x0F) | 0x00, -1);
+                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes_ >> 4) | 0x10, -1);
                        kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds_ & 0x0F) | 0x20, -1);
-                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds_ >> 4)   | 0x30, -1);
+                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds_ >> 4) | 0x30, -1);
                }
 
                /* minutes low nibble
@@ -320,11 +306,12 @@ void sendMIDIsync()
                 * hours low nibble
                 * hours high nibble SMPTE frame rate */
 
-               else {
+               else
+               {
                        kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes_ & 0x0F) | 0x40, -1);
-                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes_ >> 4)   | 0x50, -1);
-                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours_ & 0x0F)   | 0x60, -1);
-                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours_ >> 4)     | 0x70, -1);
+                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes_ >> 4) | 0x50, -1);
+                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours_ & 0x0F) | 0x60, -1);
+                       kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours_ >> 4) | 0x70, -1);
                }
 
                midiTCframes_++;
@@ -332,13 +319,16 @@ void sendMIDIsync()
                /* check if total timecode frames are greater than timecode fps:
                 * if so, a second has passed */
 
-               if (midiTCframes_ > conf::conf.midiTCfps) {
+               if (midiTCframes_ > conf::conf.midiTCfps)
+               {
                        midiTCframes_ = 0;
                        midiTCseconds_++;
-                       if (midiTCseconds_ >= 60) {
+                       if (midiTCseconds_ >= 60)
+                       {
                                midiTCminutes_++;
                                midiTCseconds_ = 0;
-                               if (midiTCminutes_ >= 60) {
+                               if (midiTCminutes_ >= 60)
+                               {
                                        midiTChours_++;
                                        midiTCminutes_ = 0;
                                }
@@ -348,10 +338,8 @@ void sendMIDIsync()
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sendMIDIrewind()
 {
        midiTCframes_  = 0;
@@ -364,21 +352,19 @@ void sendMIDIrewind()
         * be sent. The Full Frame is a SysEx message that encodes the entire
         * SMPTE time in one message */
 
-       if (conf::conf.midiSync == MIDI_SYNC_MTC_M) {
-               kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00);  // send msg on channel 0
-               kernelMidi::send(0x01, 0x01, 0x00);        // hours 0
-               kernelMidi::send(0x00, 0x00, 0x00);        // mins, secs, frames 0
-               kernelMidi::send(MIDI_EOX, -1, -1);        // end of sysex
+       if (conf::conf.midiSync == MIDI_SYNC_MTC_M)
+       {
+               kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00); // send msg on channel 0
+               kernelMidi::send(0x01, 0x01, 0x00);       // hours 0
+               kernelMidi::send(0x00, 0x00, 0x00);       // mins, secs, frames 0
+               kernelMidi::send(MIDI_EOX, -1, -1);       // end of sysex
        }
-       else
-       if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M)
+       else if (conf::conf.midiSync == MIDI_SYNC_CLOCK_M)
                kernelMidi::send(MIDI_POSITION_PTR, 0, 0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_AUDIO_JACK
 
 void recvJackSync()
@@ -388,21 +374,25 @@ void recvJackSync()
 
        kernelAudio::JackState jackStateCurr = kernelAudio::jackTransportQuery();
 
-       if (jackStateCurr != jackStatePrev_) {  
-
-               if (jackStateCurr.frame != jackStatePrev_.frame && jackStateCurr.frame == 0) {
-G_DEBUG("JackState received - rewind to frame 0");
-                       sequencer::rewind();
+       if (jackStateCurr != jackStatePrev_)
+       {
+               if (jackStateCurr.frame != jackStatePrev_.frame && jackStateCurr.frame == 0)
+               {
+                       G_DEBUG("JackState received - rewind to frame 0");
+                       sequencer::rawRewind();
                }
 
-               if (jackStateCurr.bpm != jackStatePrev_.bpm && jackStateCurr.bpm > 1.0f) {  // 0 bpm if Jack does not send that info
-G_DEBUG("JackState received - bpm=" << jackStateCurr.bpm);
-                       c::main::setBpm(jackStateCurr.bpm);
+               // jackStateCurr.bpm == 0 if JACK doesn't send that info
+               if (jackStateCurr.bpm != jackStatePrev_.bpm && jackStateCurr.bpm > 1.0f)
+               {
+                       G_DEBUG("JackState received - bpm=" << jackStateCurr.bpm);
+                       setBpm_(jackStateCurr.bpm);
                }
 
-               if (jackStateCurr.running != jackStatePrev_.running) {
-G_DEBUG("JackState received - running=" << jackStateCurr.running);                     
-                       jackStateCurr.running ? sequencer::start() : sequencer::stop();
+               if (jackStateCurr.running != jackStatePrev_.running)
+               {
+                       G_DEBUG("JackState received - running=" << jackStateCurr.running);
+                       jackStateCurr.running ? sequencer::rawStart() : sequencer::rawStop();
                }
        }
 
@@ -411,42 +401,57 @@ G_DEBUG("JackState received - running=" << jackStateCurr.running);
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool canQuantize()
 {
-       model::ClockLock lock(model::clock);
-       
-       const model::Clock* c = model::clock.get();
-       return c->quantize > 0 && c->status == ClockStatus::RUNNING;
-}
+       const model::Clock& c = model::get().clock;
 
+       return c.quantize > 0 && c.status == ClockStatus::RUNNING;
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 Frame quantize(Frame f)
 {
-       if (!canQuantize()) return f;
+       if (!canQuantize())
+               return f;
        return u::math::quantize(f, quantizerStep_) % getFramesInLoop(); // No overflow
 }
 
+/* -------------------------------------------------------------------------- */
+
+int         getCurrentFrame() { return model::get().clock.state->currentFrame.load(); }
+int         getCurrentBeat() { return model::get().clock.state->currentBeat.load(); }
+int         getQuantizerStep() { return quantizerStep_; }
+ClockStatus getStatus() { return model::get().clock.status; }
+int         getFramesInLoop() { return model::get().clock.framesInLoop; }
+int         getFramesInBar() { return model::get().clock.framesInBar; }
+int         getFramesInBeat() { return model::get().clock.framesInBeat; }
+int         getFramesInSeq() { return model::get().clock.framesInSeq; }
+int         getQuantizerValue() { return model::get().clock.quantize; }
+float       getBpm() { return model::get().clock.bpm; }
+int         getBeats() { return model::get().clock.beats; }
+int         getBars() { return model::get().clock.bars; }
+
+/* -------------------------------------------------------------------------- */
+
+float getCurrentSecond()
+{
+       return getCurrentFrame() / static_cast<float>(conf::conf.samplerate);
+}
 
 /* -------------------------------------------------------------------------- */
 
+Frame getMaxFramesInLoop()
+{
+       return (conf::conf.samplerate * (60.0f / G_MIN_BPM)) * getBeats();
+}
+
+/* -------------------------------------------------------------------------- */
 
-int         getCurrentFrame()   { return currentFrame_.load(); }
-int         getCurrentBeat()    { return currentBeat_.load(); }
-int         getQuantizerStep()  { return quantizerStep_; }
-ClockStatus getStatus()         { model::ClockLock lock(model::clock); return model::clock.get()->status; }
-int         getFramesInLoop()   { model::ClockLock lock(model::clock); return model::clock.get()->framesInLoop; }
-int         getFramesInBar()    { model::ClockLock lock(model::clock); return model::clock.get()->framesInBar; }
-int         getFramesInBeat()   { model::ClockLock lock(model::clock); return model::clock.get()->framesInBeat; }
-int         getFramesInSeq()    { model::ClockLock lock(model::clock); return model::clock.get()->framesInSeq; }
-int         getQuantizerValue() { model::ClockLock lock(model::clock); return model::clock.get()->quantize; }
-float       getBpm()            { model::ClockLock lock(model::clock); return model::clock.get()->bpm; }
-int         getBeats()          { model::ClockLock lock(model::clock); return model::clock.get()->beats; }
-int         getBars()           { model::ClockLock lock(model::clock); return model::clock.get()->bars; }
-} // giada::m::clock::
+float calcBpmFromRec(Frame recordedFrames)
+{
+       return (60.0f * getBeats()) / (recordedFrames / static_cast<float>(conf::conf.samplerate));
+}
+} // namespace giada::m::clock
index 92d1d1beb3bb5262d3567ed2c28e193c44c82bfa..716ec9f3cb24ad314176ac7c29be86f3ea3d954c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CLOCK_H
 #define G_CLOCK_H
 
-
 #include "types.h"
 
-
 namespace giada::m::clock
 {
 void init(int sampleRate, float midiTCfps);
@@ -43,35 +40,43 @@ void recomputeFrames();
 
 /* sendMIDIsync
 Generates MIDI sync output data. */
-
+/*TODO - move this to giada::m::sync*/
 void sendMIDIsync();
 
 /* sendMIDIrewind
 Rewinds timecode to beat 0 and also send a MTC full frame to cue the slave. */
-
+/*TODO - move this to giada::m::sync*/
 void sendMIDIrewind();
 
 #if defined(G_OS_LINUX) || defined(G_OS_FREEBSD) || defined(G_OS_MAC)
+/*TODO - move this to giada::m::sync*/
 void recvJackSync();
 #endif
 
-float getBpm();
-int getBeats();
-int getBars();
-int getCurrentBeat();
-int getCurrentFrame();
-int getFramesInBar();
-int getFramesInBeat();
-int getFramesInLoop();
-int getFramesInSeq();
-int getQuantizerValue();
-int getQuantizerStep();
+float       getBpm();
+int         getBeats();
+int         getBars();
+int         getCurrentBeat();
+int         getCurrentFrame();
+float       getCurrentSecond();
+int         getFramesInBar();
+int         getFramesInBeat();
+int         getFramesInLoop();
+int         getFramesInSeq();
+int         getQuantizerValue();
+int         getQuantizerStep();
 ClockStatus getStatus();
 
-/* incrCurrentFrame
-Increases current frame by a single step (+1). */
+/* getMaxFramesInLoop
+Returns how many frames the current loop length might contain at the slowest
+speed possible (G_MIN_BPM). Call this whenever you change the number or beats. */
+
+Frame getMaxFramesInLoop();
 
-void incrCurrentFrame();
+/* advance
+Increases current frame by a specific amount. */
+
+void advance(Frame amount);
 
 /* quantoHasPassed
 Tells whether a quantizer unit has passed yet. */
@@ -109,7 +114,12 @@ bool isOnFirstBeat();
 
 void rewind();
 void setStatus(ClockStatus s);
-} // giada::m::clock::
 
+/* calcBpmFromRec
+Given the amount of recorded frames, returns the speed of the current 
+performance. Used while input recording in FREE mode. */
+
+float calcBpmFromRec(Frame recordedFrames);
+} // namespace giada::m::clock
 
 #endif
index 769c9362e563b2835aae78dbb0e845685620844f..02c9f15a3833596ee5a32e523ee557c80a5afb59 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <fstream>
-#include <cassert>
-#include <string>
-#include <FL/Fl.H>
+#include "conf.h"
+#include "core/const.h"
+#include "core/types.h"
 #include "deps/json/single_include/nlohmann/json.hpp"
 #include "utils/fs.h"
 #include "utils/log.h"
-#include "core/const.h"
-#include "core/types.h"
-#include "conf.h"
-
+#include <FL/Fl.H>
+#include <cassert>
+#include <fstream>
+#include <string>
 
 namespace nl = nlohmann;
 
-
-namespace giada {
-namespace m {
-namespace conf
+namespace giada::m::conf
 {
 namespace
 {
 std::string confFilePath_ = "";
 std::string confDirPath_  = "";
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sanitize_()
 {
-       conf.soundDeviceOut = std::max(0, conf.soundDeviceOut);
-       conf.channelsOut    = std::max(0, conf.channelsOut);
+       conf.soundDeviceOut   = std::max(0, conf.soundDeviceOut);
+       conf.channelsOutCount = G_MAX_IO_CHANS;
+       conf.channelsOutStart = std::max(0, conf.channelsOutStart);
+       conf.channelsInCount  = std::max(1, conf.channelsInCount);
+       conf.channelsInStart  = std::max(0, conf.channelsInStart);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* createConfigFolder
 Creates local folder where to put the configuration file. Path differs from OS
 to OS. */
@@ -76,11 +70,13 @@ int createConfigFolder_()
 
        u::log::print("[conf::createConfigFolder] .giada folder not present. Updating...\n");
 
-       if (u::fs::mkdir(confDirPath_)) {
+       if (u::fs::mkdir(confDirPath_))
+       {
                u::log::print("[conf::createConfigFolder] status: ok\n");
                return 1;
        }
-       else {
+       else
+       {
                u::log::print("[conf::createConfigFolder] status: error!\n");
                return 0;
        }
@@ -91,20 +87,16 @@ int createConfigFolder_()
 
 #endif
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Conf conf;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
        conf = Conf();
@@ -125,10 +117,8 @@ void init()
 #endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool read()
 {
        init();
@@ -139,85 +129,88 @@ bool read()
 
        nl::json j = nl::json::parse(ifs);
 
-       conf.logMode                    =  j.value(CONF_KEY_LOG_MODE, conf.logMode);
-       conf.soundSystem                =  j.value(CONF_KEY_SOUND_SYSTEM, conf.soundSystem);
-       conf.soundDeviceOut             =  j.value(CONF_KEY_SOUND_DEVICE_OUT, conf.soundDeviceOut);
-       conf.soundDeviceIn              =  j.value(CONF_KEY_SOUND_DEVICE_IN, conf.soundDeviceIn);
-       conf.channelsOut                =  j.value(CONF_KEY_CHANNELS_OUT, conf.channelsOut);
-       conf.channelsInCount            =  j.value(CONF_KEY_CHANNELS_IN_COUNT, conf.channelsInCount);
-       conf.channelsInStart            =  j.value(CONF_KEY_CHANNELS_IN_START, conf.channelsInStart);
-       conf.samplerate                 =  j.value(CONF_KEY_SAMPLERATE, conf.samplerate);
-       conf.buffersize                 =  j.value(CONF_KEY_BUFFER_SIZE, conf.buffersize);
-       conf.limitOutput                =  j.value(CONF_KEY_LIMIT_OUTPUT, conf.limitOutput);
-       conf.rsmpQuality                =  j.value(CONF_KEY_RESAMPLE_QUALITY, conf.rsmpQuality);
-       conf.midiSystem                 =  j.value(CONF_KEY_MIDI_SYSTEM, conf.midiSystem);
-       conf.midiPortOut                =  j.value(CONF_KEY_MIDI_PORT_OUT, conf.midiPortOut);
-       conf.midiPortIn                 =  j.value(CONF_KEY_MIDI_PORT_IN, conf.midiPortIn);
-       conf.midiMapPath                =  j.value(CONF_KEY_MIDIMAP_PATH, conf.midiMapPath);
-       conf.lastFileMap                =  j.value(CONF_KEY_LAST_MIDIMAP, conf.lastFileMap);
-       conf.midiSync                   =  j.value(CONF_KEY_MIDI_SYNC, conf.midiSync);
-       conf.midiTCfps                  =  j.value(CONF_KEY_MIDI_TC_FPS, conf.midiTCfps);
-       conf.chansStopOnSeqHalt         =  j.value(CONF_KEY_CHANS_STOP_ON_SEQ_HALT, conf.chansStopOnSeqHalt);
-       conf.treatRecsAsLoops           =  j.value(CONF_KEY_TREAT_RECS_AS_LOOPS, conf.treatRecsAsLoops);
-       conf.inputMonitorDefaultOn      =  j.value(CONF_KEY_INPUT_MONITOR_DEFAULT_ON, conf.inputMonitorDefaultOn);
-       conf.overdubProtectionDefaultOn =  j.value(CONF_KEY_OVERDUB_PROTECTION_DEFAULT_ON, conf.overdubProtectionDefaultOn);
-       conf.pluginPath                 =  j.value(CONF_KEY_PLUGINS_PATH, conf.pluginPath);
-       conf.patchPath                  =  j.value(CONF_KEY_PATCHES_PATH, conf.patchPath);
-       conf.samplePath                 =  j.value(CONF_KEY_SAMPLES_PATH, conf.samplePath);
-       conf.mainWindowX                =  j.value(CONF_KEY_MAIN_WINDOW_X, conf.mainWindowX);
-       conf.mainWindowY                =  j.value(CONF_KEY_MAIN_WINDOW_Y, conf.mainWindowY);
-       conf.mainWindowW                =  j.value(CONF_KEY_MAIN_WINDOW_W, conf.mainWindowW);
-       conf.mainWindowH                =  j.value(CONF_KEY_MAIN_WINDOW_H, conf.mainWindowH);
-       conf.browserX                   =  j.value(CONF_KEY_BROWSER_X, conf.browserX);
-       conf.browserY                   =  j.value(CONF_KEY_BROWSER_Y, conf.browserY);
-       conf.browserW                   =  j.value(CONF_KEY_BROWSER_W, conf.browserW);
-       conf.browserH                   =  j.value(CONF_KEY_BROWSER_H, conf.browserH);
-       conf.browserPosition            =  j.value(CONF_KEY_BROWSER_POSITION, conf.browserPosition);
-       conf.browserLastPath            =  j.value(CONF_KEY_BROWSER_LAST_PATH, conf.browserLastPath);
-       conf.browserLastValue           =  j.value(CONF_KEY_BROWSER_LAST_VALUE, conf.browserLastValue);
-       conf.actionEditorX              =  j.value(CONF_KEY_ACTION_EDITOR_X, conf.actionEditorX);
-       conf.actionEditorY              =  j.value(CONF_KEY_ACTION_EDITOR_Y, conf.actionEditorY);
-       conf.actionEditorW              =  j.value(CONF_KEY_ACTION_EDITOR_W, conf.actionEditorW);
-       conf.actionEditorH              =  j.value(CONF_KEY_ACTION_EDITOR_H, conf.actionEditorH);
-       conf.actionEditorZoom           =  j.value(CONF_KEY_ACTION_EDITOR_ZOOM, conf.actionEditorZoom);
-       conf.actionEditorGridVal        =  j.value(CONF_KEY_ACTION_EDITOR_GRID_VAL, conf.actionEditorGridVal);
-       conf.actionEditorGridOn         =  j.value(CONF_KEY_ACTION_EDITOR_GRID_ON, conf.actionEditorGridOn);
-       conf.sampleEditorX              =  j.value(CONF_KEY_SAMPLE_EDITOR_X, conf.sampleEditorX);
-       conf.sampleEditorY              =  j.value(CONF_KEY_SAMPLE_EDITOR_Y, conf.sampleEditorY);
-       conf.sampleEditorW              =  j.value(CONF_KEY_SAMPLE_EDITOR_W, conf.sampleEditorW);
-       conf.sampleEditorH              =  j.value(CONF_KEY_SAMPLE_EDITOR_H, conf.sampleEditorH);
-       conf.sampleEditorGridVal        =  j.value(CONF_KEY_SAMPLE_EDITOR_GRID_VAL, conf.sampleEditorGridVal);
-       conf.sampleEditorGridOn         =  j.value(CONF_KEY_SAMPLE_EDITOR_GRID_ON, conf.sampleEditorGridOn);
-       conf.pianoRollY                 =  j.value(CONF_KEY_PIANO_ROLL_Y, conf.pianoRollY);
-       conf.pianoRollH                 =  j.value(CONF_KEY_PIANO_ROLL_H, conf.pianoRollH);
-       conf.sampleActionEditorH        =  j.value(CONF_KEY_SAMPLE_ACTION_EDITOR_H, conf.sampleActionEditorH);
-       conf.velocityEditorH            =  j.value(CONF_KEY_VELOCITY_EDITOR_H, conf.velocityEditorH);
-       conf.envelopeEditorH            =  j.value(CONF_KEY_ENVELOPE_EDITOR_H, conf.envelopeEditorH);
-       conf.pluginListX                =  j.value(CONF_KEY_PLUGIN_LIST_X, conf.pluginListX);
-       conf.pluginListY                =  j.value(CONF_KEY_PLUGIN_LIST_Y, conf.pluginListY);
-       conf.midiInputX                 =  j.value(CONF_KEY_MIDI_INPUT_X, conf.midiInputX);
-       conf.midiInputY                 =  j.value(CONF_KEY_MIDI_INPUT_Y, conf.midiInputY);
-       conf.midiInputW                 =  j.value(CONF_KEY_MIDI_INPUT_W, conf.midiInputW);
-       conf.midiInputH                 =  j.value(CONF_KEY_MIDI_INPUT_H, conf.midiInputH);
-       conf.recTriggerMode             =  j.value(CONF_KEY_REC_TRIGGER_MODE, conf.recTriggerMode);
-       conf.recTriggerLevel            =  j.value(CONF_KEY_REC_TRIGGER_LEVEL, conf.recTriggerLevel);
-       conf.midiInEnabled              =  j.value(CONF_KEY_MIDI_IN, conf.midiInEnabled);
-       conf.midiInFilter               =  j.value(CONF_KEY_MIDI_IN_FILTER, conf.midiInFilter);
-       conf.midiInRewind               =  j.value(CONF_KEY_MIDI_IN_REWIND, conf.midiInRewind);
-       conf.midiInStartStop            =  j.value(CONF_KEY_MIDI_IN_START_STOP, conf.midiInStartStop);
-       conf.midiInActionRec            =  j.value(CONF_KEY_MIDI_IN_ACTION_REC, conf.midiInActionRec);
-       conf.midiInInputRec             =  j.value(CONF_KEY_MIDI_IN_INPUT_REC, conf.midiInInputRec);
-       conf.midiInMetronome            =  j.value(CONF_KEY_MIDI_IN_METRONOME, conf.midiInMetronome);
-       conf.midiInVolumeIn             =  j.value(CONF_KEY_MIDI_IN_VOLUME_IN, conf.midiInVolumeIn);
-       conf.midiInVolumeOut            =  j.value(CONF_KEY_MIDI_IN_VOLUME_OUT, conf.midiInVolumeOut);
-       conf.midiInBeatDouble           =  j.value(CONF_KEY_MIDI_IN_BEAT_DOUBLE, conf.midiInBeatDouble);
-       conf.midiInBeatHalf             =  j.value(CONF_KEY_MIDI_IN_BEAT_HALF, conf.midiInBeatHalf);
+       conf.logMode                    = j.value(CONF_KEY_LOG_MODE, conf.logMode);
+       conf.showTooltips               = j.value(CONF_KEY_SHOW_TOOLTIPS, conf.showTooltips);
+       conf.soundSystem                = j.value(CONF_KEY_SOUND_SYSTEM, conf.soundSystem);
+       conf.soundDeviceOut             = j.value(CONF_KEY_SOUND_DEVICE_OUT, conf.soundDeviceOut);
+       conf.soundDeviceIn              = j.value(CONF_KEY_SOUND_DEVICE_IN, conf.soundDeviceIn);
+       conf.channelsOutCount           = j.value(CONF_KEY_CHANNELS_OUT_COUNT, conf.channelsOutCount);
+       conf.channelsOutStart           = j.value(CONF_KEY_CHANNELS_OUT_START, conf.channelsOutStart);
+       conf.channelsInCount            = j.value(CONF_KEY_CHANNELS_IN_COUNT, conf.channelsInCount);
+       conf.channelsInStart            = j.value(CONF_KEY_CHANNELS_IN_START, conf.channelsInStart);
+       conf.samplerate                 = j.value(CONF_KEY_SAMPLERATE, conf.samplerate);
+       conf.buffersize                 = j.value(CONF_KEY_BUFFER_SIZE, conf.buffersize);
+       conf.limitOutput                = j.value(CONF_KEY_LIMIT_OUTPUT, conf.limitOutput);
+       conf.rsmpQuality                = j.value(CONF_KEY_RESAMPLE_QUALITY, conf.rsmpQuality);
+       conf.midiSystem                 = j.value(CONF_KEY_MIDI_SYSTEM, conf.midiSystem);
+       conf.midiPortOut                = j.value(CONF_KEY_MIDI_PORT_OUT, conf.midiPortOut);
+       conf.midiPortIn                 = j.value(CONF_KEY_MIDI_PORT_IN, conf.midiPortIn);
+       conf.midiMapPath                = j.value(CONF_KEY_MIDIMAP_PATH, conf.midiMapPath);
+       conf.lastFileMap                = j.value(CONF_KEY_LAST_MIDIMAP, conf.lastFileMap);
+       conf.midiSync                   = j.value(CONF_KEY_MIDI_SYNC, conf.midiSync);
+       conf.midiTCfps                  = j.value(CONF_KEY_MIDI_TC_FPS, conf.midiTCfps);
+       conf.chansStopOnSeqHalt         = j.value(CONF_KEY_CHANS_STOP_ON_SEQ_HALT, conf.chansStopOnSeqHalt);
+       conf.treatRecsAsLoops           = j.value(CONF_KEY_TREAT_RECS_AS_LOOPS, conf.treatRecsAsLoops);
+       conf.inputMonitorDefaultOn      = j.value(CONF_KEY_INPUT_MONITOR_DEFAULT_ON, conf.inputMonitorDefaultOn);
+       conf.overdubProtectionDefaultOn = j.value(CONF_KEY_OVERDUB_PROTECTION_DEFAULT_ON, conf.overdubProtectionDefaultOn);
+       conf.pluginPath                 = j.value(CONF_KEY_PLUGINS_PATH, conf.pluginPath);
+       conf.patchPath                  = j.value(CONF_KEY_PATCHES_PATH, conf.patchPath);
+       conf.samplePath                 = j.value(CONF_KEY_SAMPLES_PATH, conf.samplePath);
+       conf.mainWindowX                = j.value(CONF_KEY_MAIN_WINDOW_X, conf.mainWindowX);
+       conf.mainWindowY                = j.value(CONF_KEY_MAIN_WINDOW_Y, conf.mainWindowY);
+       conf.mainWindowW                = j.value(CONF_KEY_MAIN_WINDOW_W, conf.mainWindowW);
+       conf.mainWindowH                = j.value(CONF_KEY_MAIN_WINDOW_H, conf.mainWindowH);
+       conf.browserX                   = j.value(CONF_KEY_BROWSER_X, conf.browserX);
+       conf.browserY                   = j.value(CONF_KEY_BROWSER_Y, conf.browserY);
+       conf.browserW                   = j.value(CONF_KEY_BROWSER_W, conf.browserW);
+       conf.browserH                   = j.value(CONF_KEY_BROWSER_H, conf.browserH);
+       conf.browserPosition            = j.value(CONF_KEY_BROWSER_POSITION, conf.browserPosition);
+       conf.browserLastPath            = j.value(CONF_KEY_BROWSER_LAST_PATH, conf.browserLastPath);
+       conf.browserLastValue           = j.value(CONF_KEY_BROWSER_LAST_VALUE, conf.browserLastValue);
+       conf.actionEditorX              = j.value(CONF_KEY_ACTION_EDITOR_X, conf.actionEditorX);
+       conf.actionEditorY              = j.value(CONF_KEY_ACTION_EDITOR_Y, conf.actionEditorY);
+       conf.actionEditorW              = j.value(CONF_KEY_ACTION_EDITOR_W, conf.actionEditorW);
+       conf.actionEditorH              = j.value(CONF_KEY_ACTION_EDITOR_H, conf.actionEditorH);
+       conf.actionEditorZoom           = j.value(CONF_KEY_ACTION_EDITOR_ZOOM, conf.actionEditorZoom);
+       conf.actionEditorGridVal        = j.value(CONF_KEY_ACTION_EDITOR_GRID_VAL, conf.actionEditorGridVal);
+       conf.actionEditorGridOn         = j.value(CONF_KEY_ACTION_EDITOR_GRID_ON, conf.actionEditorGridOn);
+       conf.sampleEditorX              = j.value(CONF_KEY_SAMPLE_EDITOR_X, conf.sampleEditorX);
+       conf.sampleEditorY              = j.value(CONF_KEY_SAMPLE_EDITOR_Y, conf.sampleEditorY);
+       conf.sampleEditorW              = j.value(CONF_KEY_SAMPLE_EDITOR_W, conf.sampleEditorW);
+       conf.sampleEditorH              = j.value(CONF_KEY_SAMPLE_EDITOR_H, conf.sampleEditorH);
+       conf.sampleEditorGridVal        = j.value(CONF_KEY_SAMPLE_EDITOR_GRID_VAL, conf.sampleEditorGridVal);
+       conf.sampleEditorGridOn         = j.value(CONF_KEY_SAMPLE_EDITOR_GRID_ON, conf.sampleEditorGridOn);
+       conf.pianoRollY                 = j.value(CONF_KEY_PIANO_ROLL_Y, conf.pianoRollY);
+       conf.pianoRollH                 = j.value(CONF_KEY_PIANO_ROLL_H, conf.pianoRollH);
+       conf.sampleActionEditorH        = j.value(CONF_KEY_SAMPLE_ACTION_EDITOR_H, conf.sampleActionEditorH);
+       conf.velocityEditorH            = j.value(CONF_KEY_VELOCITY_EDITOR_H, conf.velocityEditorH);
+       conf.envelopeEditorH            = j.value(CONF_KEY_ENVELOPE_EDITOR_H, conf.envelopeEditorH);
+       conf.pluginListX                = j.value(CONF_KEY_PLUGIN_LIST_X, conf.pluginListX);
+       conf.pluginListY                = j.value(CONF_KEY_PLUGIN_LIST_Y, conf.pluginListY);
+       conf.midiInputX                 = j.value(CONF_KEY_MIDI_INPUT_X, conf.midiInputX);
+       conf.midiInputY                 = j.value(CONF_KEY_MIDI_INPUT_Y, conf.midiInputY);
+       conf.midiInputW                 = j.value(CONF_KEY_MIDI_INPUT_W, conf.midiInputW);
+       conf.midiInputH                 = j.value(CONF_KEY_MIDI_INPUT_H, conf.midiInputH);
+       conf.recTriggerMode             = j.value(CONF_KEY_REC_TRIGGER_MODE, conf.recTriggerMode);
+       conf.recTriggerLevel            = j.value(CONF_KEY_REC_TRIGGER_LEVEL, conf.recTriggerLevel);
+       conf.inputRecMode               = j.value(CONF_KEY_INPUT_REC_MODE, conf.inputRecMode);
+       conf.midiInEnabled              = j.value(CONF_KEY_MIDI_IN, conf.midiInEnabled);
+       conf.midiInFilter               = j.value(CONF_KEY_MIDI_IN_FILTER, conf.midiInFilter);
+       conf.midiInRewind               = j.value(CONF_KEY_MIDI_IN_REWIND, conf.midiInRewind);
+       conf.midiInStartStop            = j.value(CONF_KEY_MIDI_IN_START_STOP, conf.midiInStartStop);
+       conf.midiInActionRec            = j.value(CONF_KEY_MIDI_IN_ACTION_REC, conf.midiInActionRec);
+       conf.midiInInputRec             = j.value(CONF_KEY_MIDI_IN_INPUT_REC, conf.midiInInputRec);
+       conf.midiInMetronome            = j.value(CONF_KEY_MIDI_IN_METRONOME, conf.midiInMetronome);
+       conf.midiInVolumeIn             = j.value(CONF_KEY_MIDI_IN_VOLUME_IN, conf.midiInVolumeIn);
+       conf.midiInVolumeOut            = j.value(CONF_KEY_MIDI_IN_VOLUME_OUT, conf.midiInVolumeOut);
+       conf.midiInBeatDouble           = j.value(CONF_KEY_MIDI_IN_BEAT_DOUBLE, conf.midiInBeatDouble);
+       conf.midiInBeatHalf             = j.value(CONF_KEY_MIDI_IN_BEAT_HALF, conf.midiInBeatHalf);
 #ifdef WITH_VST
-       conf.pluginChooserX             = j.value(CONF_KEY_PLUGIN_CHOOSER_X, conf.pluginChooserX);
-       conf.pluginChooserY             = j.value(CONF_KEY_PLUGIN_CHOOSER_Y, conf.pluginChooserY);
-       conf.pluginChooserW             = j.value(CONF_KEY_PLUGIN_CHOOSER_W, conf.pluginChooserW);
-       conf.pluginChooserH             = j.value(CONF_KEY_PLUGIN_CHOOSER_H, conf.pluginChooserH);
-       conf.pluginSortMethod           = j.value(CONF_KEY_PLUGIN_SORT_METHOD, conf.pluginSortMethod);
+       conf.pluginChooserX   = j.value(CONF_KEY_PLUGIN_CHOOSER_X, conf.pluginChooserX);
+       conf.pluginChooserY   = j.value(CONF_KEY_PLUGIN_CHOOSER_Y, conf.pluginChooserY);
+       conf.pluginChooserW   = j.value(CONF_KEY_PLUGIN_CHOOSER_W, conf.pluginChooserW);
+       conf.pluginChooserH   = j.value(CONF_KEY_PLUGIN_CHOOSER_H, conf.pluginChooserH);
+       conf.pluginSortMethod = j.value(CONF_KEY_PLUGIN_SORT_METHOD, conf.pluginSortMethod);
 #endif
 
        sanitize_();
@@ -225,10 +218,8 @@ bool read()
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool write()
 {
        if (!createConfigFolder_())
@@ -238,10 +229,12 @@ bool write()
 
        j[CONF_KEY_HEADER]                        = "GIADACFG";
        j[CONF_KEY_LOG_MODE]                      = conf.logMode;
+       j[CONF_KEY_SHOW_TOOLTIPS]                 = conf.showTooltips;
        j[CONF_KEY_SOUND_SYSTEM]                  = conf.soundSystem;
        j[CONF_KEY_SOUND_DEVICE_OUT]              = conf.soundDeviceOut;
        j[CONF_KEY_SOUND_DEVICE_IN]               = conf.soundDeviceIn;
-       j[CONF_KEY_CHANNELS_OUT]                  = conf.channelsOut;
+       j[CONF_KEY_CHANNELS_OUT_COUNT]            = conf.channelsOutCount;
+       j[CONF_KEY_CHANNELS_OUT_START]            = conf.channelsOutStart;
        j[CONF_KEY_CHANNELS_IN_COUNT]             = conf.channelsInCount;
        j[CONF_KEY_CHANNELS_IN_START]             = conf.channelsInStart;
        j[CONF_KEY_SAMPLERATE]                    = conf.samplerate;
@@ -310,21 +303,23 @@ bool write()
        j[CONF_KEY_MIDI_INPUT_H]                  = conf.midiInputH;
        j[CONF_KEY_REC_TRIGGER_MODE]              = static_cast<int>(conf.recTriggerMode);
        j[CONF_KEY_REC_TRIGGER_LEVEL]             = conf.recTriggerLevel;
+       j[CONF_KEY_INPUT_REC_MODE]                = static_cast<int>(conf.inputRecMode);
 #ifdef WITH_VST
-       j[CONF_KEY_PLUGIN_CHOOSER_X]              = conf.pluginChooserX;
-       j[CONF_KEY_PLUGIN_CHOOSER_Y]              = conf.pluginChooserY;
-       j[CONF_KEY_PLUGIN_CHOOSER_W]              = conf.pluginChooserW;
-       j[CONF_KEY_PLUGIN_CHOOSER_H]              = conf.pluginChooserH;
-       j[CONF_KEY_PLUGIN_SORT_METHOD]            = conf.pluginSortMethod;
+       j[CONF_KEY_PLUGIN_CHOOSER_X]   = conf.pluginChooserX;
+       j[CONF_KEY_PLUGIN_CHOOSER_Y]   = conf.pluginChooserY;
+       j[CONF_KEY_PLUGIN_CHOOSER_W]   = conf.pluginChooserW;
+       j[CONF_KEY_PLUGIN_CHOOSER_H]   = conf.pluginChooserH;
+       j[CONF_KEY_PLUGIN_SORT_METHOD] = conf.pluginSortMethod;
 #endif
 
-    std::ofstream ofs(confFilePath_);
-       if (!ofs.good()) {
+       std::ofstream ofs(confFilePath_);
+       if (!ofs.good())
+       {
                u::log::print("[conf::write] unable to write configuration file!\n");
                return false;
        }
 
-    ofs << j;
+       ofs << j;
        return true;
 }
-}}} // giada::m::conf::
\ No newline at end of file
+} // namespace giada::m::conf
\ No newline at end of file
index 91ca9d3a2db51ab46a65bca8dd9fb59155d3ca44..4d1a2dbb7065c35d6fd0b81fef338cfc2fb3dcd3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CONF_H
 #define G_CONF_H
 
-
-#include <string>
-#include "utils/gui.h"
 #include "core/const.h"
 #include "core/types.h"
+#include "utils/gui.h"
+#include <string>
 
-
-namespace giada {
-namespace m {
-namespace conf
+namespace giada::m::conf
 {
 struct Conf
 {
-       int  logMode         = LOG_MODE_MUTE;
-       int  soundSystem     = G_DEFAULT_SOUNDSYS;
-       int  soundDeviceOut  = G_DEFAULT_SOUNDDEV_OUT;
-       int  soundDeviceIn   = G_DEFAULT_SOUNDDEV_IN;
-       int  channelsOut     = 0;
-       int  channelsInCount = 0;
-       int  channelsInStart = 0;
-       int  samplerate      = G_DEFAULT_SAMPLERATE;
-       int  buffersize      = G_DEFAULT_BUFSIZE;
-       bool limitOutput     = false;
-       int  rsmpQuality     = 0;
+       int  logMode          = LOG_MODE_MUTE;
+       bool showTooltips     = true;
+       int  soundSystem      = G_DEFAULT_SOUNDSYS;
+       int  soundDeviceOut   = G_DEFAULT_SOUNDDEV_OUT;
+       int  soundDeviceIn    = G_DEFAULT_SOUNDDEV_IN;
+       int  channelsOutCount = G_MAX_IO_CHANS;
+       int  channelsOutStart = 0;
+       int  channelsInCount  = 1;
+       int  channelsInStart  = 0;
+       int  samplerate       = G_DEFAULT_SAMPLERATE;
+       int  buffersize       = G_DEFAULT_BUFSIZE;
+       bool limitOutput      = false;
+       int  rsmpQuality      = 0;
 
        int         midiSystem  = 0;
        int         midiPortOut = G_DEFAULT_MIDI_PORT_OUT;
@@ -76,8 +73,8 @@ struct Conf
        int mainWindowH = G_MIN_GUI_HEIGHT;
 
        int         browserX = u::gui::centerWindowX(G_DEFAULT_SUBWINDOW_W);
-       int         browserY = u::gui::centerWindowY(G_DEFAULT_SUBWINDOW_H); 
-       int         browserW = G_DEFAULT_SUBWINDOW_W; 
+       int         browserY = u::gui::centerWindowY(G_DEFAULT_SUBWINDOW_H);
+       int         browserW = G_DEFAULT_SUBWINDOW_W;
        int         browserH = G_DEFAULT_SUBWINDOW_H;
        int         browserPosition;
        int         browserLastValue;
@@ -85,36 +82,37 @@ struct Conf
 
        int actionEditorY       = u::gui::centerWindowY(G_DEFAULT_SUBWINDOW_H);
        int actionEditorX       = u::gui::centerWindowX(G_DEFAULT_SUBWINDOW_W);
-       int actionEditorW       = G_DEFAULT_SUBWINDOW_W; 
-       int actionEditorH       = G_DEFAULT_SUBWINDOW_H; 
+       int actionEditorW       = G_DEFAULT_SUBWINDOW_W;
+       int actionEditorH       = G_DEFAULT_SUBWINDOW_H;
        int actionEditorZoom    = 100;
        int actionEditorGridVal = 0;
        int actionEditorGridOn  = false;
 
        int sampleEditorX;
        int sampleEditorY;
-       int sampleEditorW = G_DEFAULT_SUBWINDOW_W;
-       int sampleEditorH = G_DEFAULT_SUBWINDOW_H;
+       int sampleEditorW       = G_DEFAULT_SUBWINDOW_W;
+       int sampleEditorH       = G_DEFAULT_SUBWINDOW_H;
        int sampleEditorGridVal = 0;
        int sampleEditorGridOn  = false;
 
-       int midiInputX; 
-       int midiInputY; 
-       int midiInputW = G_DEFAULT_SUBWINDOW_W; 
+       int midiInputX;
+       int midiInputY;
+       int midiInputW = G_DEFAULT_SUBWINDOW_W;
        int midiInputH = G_DEFAULT_SUBWINDOW_H;
 
        int pianoRollY = -1;
        int pianoRollH = 422;
 
-       int sampleActionEditorH = 40; 
-       int velocityEditorH     = 40; 
-       int envelopeEditorH     = 40; 
+       int sampleActionEditorH = 40;
+       int velocityEditorH     = 40;
+       int envelopeEditorH     = 40;
 
        int pluginListX;
        int pluginListY;
 
        RecTriggerMode recTriggerMode  = RecTriggerMode::NORMAL;
        float          recTriggerLevel = G_DEFAULT_REC_TRIGGER_LEVEL;
+       InputRecMode   inputRecMode    = InputRecMode::FREE;
 
        bool     midiInEnabled    = false;
        int      midiInFilter     = -1;
@@ -130,28 +128,24 @@ struct Conf
 
 #ifdef WITH_VST
 
-       int pluginChooserX; 
+       int pluginChooserX;
        int pluginChooserY;
-       int pluginChooserW   = G_DEFAULT_SUBWINDOW_W; 
+       int pluginChooserW   = G_DEFAULT_SUBWINDOW_W;
        int pluginChooserH   = G_DEFAULT_SUBWINDOW_H;
        int pluginSortMethod = 0;
 
 #endif
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 extern Conf conf;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void init();
 bool read();
 bool write();
-}}} // giada::m::conf::
+} // namespace giada::m::conf
 
 #endif
index 0e3ede2d4c830883d81ceb8da161bf99494d7f6a..8da87cbbc422db3ae675c40fb034ac1432e11d09 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_CONST_H
 #define G_CONST_H
 
-
 #include <cstdint>
-
+#include <iostream>
 
 /* -- debug ----------------------------------------------------------------- */
 #ifndef NDEBUG
-    #define G_DEBUG_MODE
-    #define G_DEBUG(x) std::cerr << __FILE__ << "::" << __func__  << "() - " << x << "\n";
+#define G_DEBUG_MODE
+// TODO - move G_DEBUG macro definition to u::log
+#define G_DEBUG(x) std::cerr << __FILE__ << "::" << __func__ << "() - " << x << "\n";
 #else
-    #define G_DEBUG(x) do {} while (0)
+#define G_DEBUG(x) \
+       do             \
+       {              \
+       } while (0)
 #endif
 
-
 /* -- environment ----------------------------------------------------------- */
 #if defined(_WIN32)
-       #define G_OS_WINDOWS
+#define G_OS_WINDOWS
 #elif defined(__APPLE__)
-       #define G_OS_MAC
+#define G_OS_MAC
 #elif defined(__linux__)
-       #define G_OS_LINUX
+#define G_OS_LINUX
 #elif defined(__FreeBSD__)
-       #define G_OS_FREEBSD
+#define G_OS_FREEBSD
 #endif
 
 #ifndef BUILD_DATE
-       #define BUILD_DATE __DATE__
+#define BUILD_DATE __DATE__
 #endif
 
-
-
 /* -- version --------------------------------------------------------------- */
 constexpr auto G_APP_NAME      = "Giada";
-constexpr auto G_VERSION_STR   = "0.17.1";
+constexpr auto G_VERSION_STR   = "0.18.1";
 constexpr int  G_VERSION_MAJOR = 0;
-constexpr int  G_VERSION_MINOR = 17;
+constexpr int  G_VERSION_MINOR = 18;
 constexpr int  G_VERSION_PATCH = 1;
 
 constexpr auto CONF_FILENAME = "giada.conf";
 
 #ifdef G_OS_WINDOWS
-       #define G_SLASH '\\'
-       #define G_SLASH_STR "\\"
+#define G_SLASH '\\'
+#define G_SLASH_STR "\\"
 #else
-       #define G_SLASH '/'
-       #define G_SLASH_STR "/"
+#define G_SLASH '/'
+#define G_SLASH_STR "/"
 #endif
 
+/* -- Engine ---------------------------------------------------------------- */
+/* G_EVENT_DISPATCHER_RATE_MS
+The amount of sleep between each Event Dispatcher cycle. It should be lower
+than the audio thread sleep time. Note: this value will obviously increase the 
+live input latency, keep it small! */
+constexpr int G_EVENT_DISPATCHER_RATE_MS = 5;
 
 /* -- GUI ------------------------------------------------------------------- */
 constexpr float G_GUI_REFRESH_RATE   = 1 / 30.0f; // 30 fps
@@ -82,108 +87,98 @@ constexpr float G_GUI_PLUGIN_RATE    = 1 / 30.0f; // 30 fps
 constexpr int   G_GUI_FONT_SIZE_BASE = 12;
 constexpr int   G_GUI_INNER_MARGIN   = 4;
 constexpr int   G_GUI_OUTER_MARGIN   = 8;
-constexpr int   G_GUI_UNIT           = 20;    // base unit for elements 
+constexpr int   G_GUI_UNIT           = 20; // base unit for elements
 constexpr int   G_GUI_ZOOM_FACTOR    = 2;
 
-#define G_COLOR_RED       fl_rgb_color(28,  32,  80)
-#define G_COLOR_BLUE      fl_rgb_color(113, 31,  31)
-#define G_COLOR_RED_ALERT fl_rgb_color(239, 75,  53)
-#define G_COLOR_LIGHT_2   fl_rgb_color(200, 200, 200)
-#define G_COLOR_LIGHT_1   fl_rgb_color(170, 170, 170)
-#define G_COLOR_GREY_4    fl_rgb_color(78,  78,  78)
-#define G_COLOR_GREY_3    fl_rgb_color(54,  54,  54)
-#define G_COLOR_GREY_2    fl_rgb_color(37,  37,  37)
-#define G_COLOR_GREY_1_5  fl_rgb_color(28,  28,  28)
-#define G_COLOR_GREY_1    fl_rgb_color(25,  25,  25)
-#define G_COLOR_BLACK     fl_rgb_color(0,   0,   0)
-
-
+#define G_COLOR_RED fl_rgb_color(28, 32, 80)
+#define G_COLOR_BLUE fl_rgb_color(113, 31, 31)
+#define G_COLOR_RED_ALERT fl_rgb_color(239, 75, 53)
+#define G_COLOR_LIGHT_2 fl_rgb_color(200, 200, 200)
+#define G_COLOR_LIGHT_1 fl_rgb_color(170, 170, 170)
+#define G_COLOR_GREY_4 fl_rgb_color(78, 78, 78)
+#define G_COLOR_GREY_3 fl_rgb_color(54, 54, 54)
+#define G_COLOR_GREY_2 fl_rgb_color(37, 37, 37)
+#define G_COLOR_GREY_1_5 fl_rgb_color(28, 28, 28)
+#define G_COLOR_GREY_1 fl_rgb_color(25, 25, 25)
+#define G_COLOR_BLACK fl_rgb_color(0, 0, 0)
 
 /* -- MIN/MAX values -------------------------------------------------------- */
-constexpr float  G_MIN_BPM            = 20.0f;
-constexpr auto   G_MIN_BPM_STR        = "20.0";
-constexpr float  G_MAX_BPM            = 999.0f;
-constexpr auto   G_MAX_BPM_STR        = "999.0";
-constexpr int    G_MAX_BEATS          = 32;
-constexpr int    G_MAX_BARS           = 32;
-constexpr int    G_MAX_QUANTIZE       = 8;
-constexpr float  G_MIN_DB_SCALE       = 60.0f;
-constexpr int    G_MIN_COLUMN_WIDTH   = 140;
-constexpr float  G_MAX_BOOST_DB       = 20.0f;
-constexpr float  G_MIN_PITCH          = 0.1f;
-constexpr float  G_MAX_PITCH          = 4.0f;
-constexpr float  G_MAX_PAN            = 1.0f;
-constexpr float  G_MAX_VOLUME         = 1.0f;
-constexpr int    G_MAX_GRID_VAL       = 64;
-constexpr int    G_MIN_BUF_SIZE       = 8;
-constexpr int    G_MAX_BUF_SIZE       = 4096;
-constexpr int    G_MIN_GUI_WIDTH      = 816;
-constexpr int    G_MIN_GUI_HEIGHT     = 510;
-constexpr int    G_MAX_IO_CHANS       = 2;
-constexpr int    G_MAX_VELOCITY       = 0x7F;
-constexpr int    G_MAX_MIDI_CHANS     = 16;
-constexpr int    G_MAX_POLYPHONY      = 32;
-constexpr int    G_MAX_QUEUE_EVENTS   = 32;
-constexpr int    G_MAX_QUANTIZER_SIZE = 8;
-
-
+constexpr float G_MIN_BPM               = 20.0f;
+constexpr auto  G_MIN_BPM_STR           = "20.0";
+constexpr float G_MAX_BPM               = 999.0f;
+constexpr auto  G_MAX_BPM_STR           = "999.0";
+constexpr int   G_MAX_BEATS             = 32;
+constexpr int   G_MAX_BARS              = 32;
+constexpr int   G_MAX_QUANTIZE          = 8;
+constexpr float G_MIN_DB_SCALE          = 60.0f;
+constexpr int   G_MIN_COLUMN_WIDTH      = 140;
+constexpr float G_MAX_BOOST_DB          = 20.0f;
+constexpr float G_MIN_PITCH             = 0.1f;
+constexpr float G_MAX_PITCH             = 4.0f;
+constexpr float G_MAX_PAN               = 1.0f;
+constexpr float G_MAX_VOLUME            = 1.0f;
+constexpr int   G_MAX_GRID_VAL          = 64;
+constexpr int   G_MIN_BUF_SIZE          = 8;
+constexpr int   G_MAX_BUF_SIZE          = 4096;
+constexpr int   G_MIN_GUI_WIDTH         = 816;
+constexpr int   G_MIN_GUI_HEIGHT        = 510;
+constexpr int   G_MAX_IO_CHANS          = 2;
+constexpr int   G_MAX_VELOCITY          = 0x7F;
+constexpr int   G_MAX_MIDI_CHANS        = 16;
+constexpr int   G_MAX_POLYPHONY         = 32;
+constexpr int   G_MAX_DISPATCHER_EVENTS = 32;
+constexpr int   G_MAX_SEQUENCER_EVENTS  = 128; // Per block
+constexpr int   G_MAX_QUANTIZER_SIZE    = 32;
 
 /* -- kernel audio ---------------------------------------------------------- */
-constexpr int G_SYS_API_NONE   = 0x00;  // 0000 0000
-constexpr int G_SYS_API_JACK   = 0x01;  // 0000 0001
-constexpr int G_SYS_API_ALSA   = 0x02;  // 0000 0010
-constexpr int G_SYS_API_DS     = 0x04;  // 0000 0100
-constexpr int G_SYS_API_ASIO   = 0x08;  // 0000 1000
-constexpr int G_SYS_API_CORE   = 0x10;  // 0001 0000
-constexpr int G_SYS_API_PULSE  = 0x20;  // 0010 0000
-constexpr int G_SYS_API_WASAPI = 0x40;  // 0100 0000
-constexpr int G_SYS_API_ANY    = 0x7F;  // 0111 1111
-
-
+constexpr int G_SYS_API_NONE   = 0;
+constexpr int G_SYS_API_JACK   = 1;
+constexpr int G_SYS_API_ALSA   = 2;
+constexpr int G_SYS_API_DS     = 3;
+constexpr int G_SYS_API_ASIO   = 4;
+constexpr int G_SYS_API_CORE   = 5;
+constexpr int G_SYS_API_PULSE  = 6;
+constexpr int G_SYS_API_WASAPI = 7;
 
 /* -- kernel midi ----------------------------------------------------------- */
-constexpr int G_MIDI_API_JACK = 0x01;  // 0000 0001
-constexpr int G_MIDI_API_ALSA = 0x02;  // 0000 0010
-
-
+constexpr int G_MIDI_API_JACK = 0x01; // 0000 0001
+constexpr int G_MIDI_API_ALSA = 0x02; // 0000 0010
 
 /* -- default system -------------------------------------------------------- */
 #if defined(G_OS_LINUX)
-       #define G_DEFAULT_SOUNDSYS      G_SYS_API_NONE
+#define G_DEFAULT_SOUNDSYS G_SYS_API_NONE
 #elif defined(G_OS_FREEBSD)
-       #define G_DEFAULT_SOUNDSYS      G_SYS_API_PULSE
+#define G_DEFAULT_SOUNDSYS G_SYS_API_PULSE
 #elif defined(G_OS_WINDOWS)
-       #define G_DEFAULT_SOUNDSYS      G_SYS_API_DS
+#define G_DEFAULT_SOUNDSYS G_SYS_API_DS
 #elif defined(G_OS_MAC)
-       #define G_DEFAULT_SOUNDSYS      G_SYS_API_CORE
+#define G_DEFAULT_SOUNDSYS G_SYS_API_CORE
 #endif
 
-constexpr int   G_DEFAULT_SOUNDDEV_OUT        = 0;      // FIXME - please override with rtAudio::getDefaultDevice (or similar)
-constexpr int   G_DEFAULT_SOUNDDEV_IN         = -1;     // no recording by default: input disabled
+constexpr int   G_DEFAULT_SOUNDDEV_OUT        = -1; // disabled by default
+constexpr int   G_DEFAULT_SOUNDDEV_IN         = -1; // disabled by default
 constexpr int   G_DEFAULT_MIDI_SYSTEM         = 0;
 constexpr int   G_DEFAULT_MIDI_PORT_IN        = -1;
 constexpr int   G_DEFAULT_MIDI_PORT_OUT       = -1;
 constexpr int   G_DEFAULT_SAMPLERATE          = 44100;
 constexpr int   G_DEFAULT_BUFSIZE             = 1024;
-constexpr int   G_DEFAULT_BIT_DEPTH           = 32;     // float
+constexpr int   G_DEFAULT_BIT_DEPTH           = 32;
 constexpr float G_DEFAULT_VOL                 = 1.0f;
 constexpr float G_DEFAULT_PAN                 = 0.5f;
 constexpr float G_DEFAULT_PITCH               = 1.0f;
 constexpr float G_DEFAULT_BPM                 = 120.0f;
 constexpr int   G_DEFAULT_BEATS               = 4;
 constexpr int   G_DEFAULT_BARS                = 1;
-constexpr int   G_DEFAULT_QUANTIZE            = 0;      // quantizer off
-constexpr float G_DEFAULT_FADEOUT_STEP        = 0.01f;  // micro-fadeout speed
+constexpr int   G_DEFAULT_QUANTIZE            = 0;     // quantizer off
+constexpr float G_DEFAULT_FADEOUT_STEP        = 0.01f; // micro-fadeout speed
 constexpr int   G_DEFAULT_COLUMN_WIDTH        = 380;
 constexpr auto  G_DEFAULT_PATCH_NAME          = "(default patch)";
-constexpr int   G_DEFAULT_ACTION_SIZE         = 8192;  // frames
+constexpr int   G_DEFAULT_ACTION_SIZE         = 8192; // frames
 constexpr int   G_DEFAULT_ZOOM_RATIO          = 128;
 constexpr float G_DEFAULT_REC_TRIGGER_LEVEL   = -10.0f;
 constexpr int   G_DEFAULT_SUBWINDOW_W         = 640;
 constexpr int   G_DEFAULT_SUBWINDOW_H         = 480;
-constexpr int   G_DEFAULT_VST_MIDIBUFFER_SIZE = 1024;  // TODO - not 100% sure about this size
-
-
+constexpr int   G_DEFAULT_VST_MIDIBUFFER_SIZE = 1024; // TODO - not 100% sure about this size
 
 /* -- responses and return codes -------------------------------------------- */
 constexpr int G_RES_ERR_PROCESSING    = -6;
@@ -192,18 +187,14 @@ constexpr int G_RES_ERR_NO_DATA       = -4;
 constexpr int G_RES_ERR_PATH_TOO_LONG = -3;
 constexpr int G_RES_ERR_IO            = -2;
 constexpr int G_RES_ERR_MEMORY        = -1;
-constexpr int G_RES_ERR               =  0;
-constexpr int G_RES_OK                =  1;
-
-
+constexpr int G_RES_ERR               = 0;
+constexpr int G_RES_OK                = 1;
 
 /* -- log modes ------------------------------------------------------------- */
 constexpr int LOG_MODE_STDOUT = 0x01;
 constexpr int LOG_MODE_FILE   = 0x02;
 constexpr int LOG_MODE_MUTE   = 0x04;
 
-
-
 /* -- unique IDs of mainWin's subwindows ------------------------------------ */
 /* -- wid > 0 are reserved by gg_keyboard ----------------------------------- */
 constexpr int WID_BEATS         = -1;
@@ -221,15 +212,11 @@ constexpr int WID_FX_CHOOSER    = -12;
 constexpr int WID_MIDI_INPUT    = -13;
 constexpr int WID_MIDI_OUTPUT   = -14;
 
-
-
 /* -- patch signals --------------------------------------------------------- */
 constexpr int G_PATCH_UNSUPPORTED = -2;
 constexpr int G_PATCH_UNREADABLE  = -1;
-constexpr int G_PATCH_INVALID     =  0;
-constexpr int G_PATCH_OK          =  1;
-
-
+constexpr int G_PATCH_INVALID     = 0;
+constexpr int G_PATCH_OK          = 1;
 
 /* -- midimap signals ------------------------------------------------------- */
 constexpr int MIDIMAP_NOT_SPECIFIED = 0x00;
@@ -237,8 +224,6 @@ constexpr int MIDIMAP_UNREADABLE    = 0x01;
 constexpr int MIDIMAP_INVALID       = 0x02;
 constexpr int MIDIMAP_READ_OK       = 0x04;
 
-
-
 /* -- MIDI in parameters (for MIDI learning) -------------------------------- */
 constexpr int G_MIDI_IN_ENABLED      = 1;
 constexpr int G_MIDI_IN_FILTER       = 2;
@@ -261,16 +246,12 @@ constexpr int G_MIDI_IN_VOLUME       = 18;
 constexpr int G_MIDI_IN_PITCH        = 19;
 constexpr int G_MIDI_IN_READ_ACTIONS = 20;
 
-
-
 /* -- MIDI out parameters (for MIDI output and lightning) ------------------- */
-constexpr int G_MIDI_OUT_ENABLED    = 1;
-constexpr int G_MIDI_OUT_L_ENABLED  = 2;
-constexpr int G_MIDI_OUT_L_PLAYING  = 3;
-constexpr int G_MIDI_OUT_L_MUTE     = 4;
-constexpr int G_MIDI_OUT_L_SOLO     = 5;
-
-
+constexpr int G_MIDI_OUT_ENABLED   = 1;
+constexpr int G_MIDI_OUT_L_ENABLED = 2;
+constexpr int G_MIDI_OUT_L_PLAYING = 3;
+constexpr int G_MIDI_OUT_L_MUTE    = 4;
+constexpr int G_MIDI_OUT_L_SOLO    = 5;
 
 /* -- MIDI signals -------------------------------------------------------------
 Channel voices messages - controller (0xB0) is a special subset of this family:
@@ -288,15 +269,15 @@ constexpr int MIDI_CLOCK        = 0xF8;
 constexpr int MIDI_START        = 0xFA;
 constexpr int MIDI_CONTINUE     = 0xFB;
 constexpr int MIDI_STOP         = 0xFC;
-constexpr int MIDI_EOX          = 0xF7;  // end of sysex
+constexpr int MIDI_EOX          = 0xF7; // end of sysex
 
 /* midi sync constants */
 
 constexpr int MIDI_SYNC_NONE    = 0x00;
-constexpr int MIDI_SYNC_CLOCK_M = 0x01;  // master
-constexpr int MIDI_SYNC_CLOCK_S = 0x02;  // slave
-constexpr int MIDI_SYNC_MTC_M   = 0x04;  // master
-constexpr int MIDI_SYNC_MTC_S   = 0x08;  // slave
+constexpr int MIDI_SYNC_CLOCK_M = 0x01; // master
+constexpr int MIDI_SYNC_CLOCK_S = 0x02; // slave
+constexpr int MIDI_SYNC_MTC_M   = 0x04; // master
+constexpr int MIDI_SYNC_MTC_S   = 0x08; // slave
 
 /* JSON patch keys */
 
@@ -378,20 +359,22 @@ constexpr auto PATCH_KEY_COLUMN_ID                    = "id";
 constexpr auto PATCH_KEY_COLUMN_WIDTH                 = "width";
 constexpr auto PATCH_KEY_COLUMN_CHANNELS              = "channels";
 constexpr auto G_PATCH_KEY_ACTION_ID                  = "id";
-constexpr auto G_PATCH_KEY_ACTION_CHANNEL             = "channel";     
-constexpr auto G_PATCH_KEY_ACTION_FRAME               = "frame";   
-constexpr auto G_PATCH_KEY_ACTION_EVENT               = "event";   
-constexpr auto G_PATCH_KEY_ACTION_PREV                = "prev";  
+constexpr auto G_PATCH_KEY_ACTION_CHANNEL             = "channel";
+constexpr auto G_PATCH_KEY_ACTION_FRAME               = "frame";
+constexpr auto G_PATCH_KEY_ACTION_EVENT               = "event";
+constexpr auto G_PATCH_KEY_ACTION_PREV                = "prev";
 constexpr auto G_PATCH_KEY_ACTION_NEXT                = "next";
 
 /* JSON config keys */
 
 constexpr auto CONF_KEY_HEADER                        = "header";
 constexpr auto CONF_KEY_LOG_MODE                      = "log_mode";
+constexpr auto CONF_KEY_SHOW_TOOLTIPS                 = "show_tooltips";
 constexpr auto CONF_KEY_SOUND_SYSTEM                  = "sound_system";
 constexpr auto CONF_KEY_SOUND_DEVICE_IN               = "sound_device_in";
 constexpr auto CONF_KEY_SOUND_DEVICE_OUT              = "sound_device_out";
-constexpr auto CONF_KEY_CHANNELS_OUT                  = "channels_out";
+constexpr auto CONF_KEY_CHANNELS_OUT_COUNT            = "channels_out_count";
+constexpr auto CONF_KEY_CHANNELS_OUT_START            = "channels_out_start";
 constexpr auto CONF_KEY_CHANNELS_IN_COUNT             = "channels_in_count";
 constexpr auto CONF_KEY_CHANNELS_IN_START             = "channels_in_start";
 constexpr auto CONF_KEY_SAMPLERATE                    = "samplerate";
@@ -466,6 +449,7 @@ constexpr auto CONF_KEY_MIDI_INPUT_H                  = "midi_input_h";
 constexpr auto CONF_KEY_PLUGIN_SORT_METHOD            = "plugin_sort_method";
 constexpr auto CONF_KEY_REC_TRIGGER_MODE              = "rec_trigger_mode";
 constexpr auto CONF_KEY_REC_TRIGGER_LEVEL             = "rec_trigger_level";
+constexpr auto CONF_KEY_INPUT_REC_MODE                = "input_rec_mode";
 
 /* JSON midimaps keys */
 
diff --git a/src/core/eventDispatcher.cpp b/src/core/eventDispatcher.cpp
new file mode 100644 (file)
index 0000000..6027fe4
--- /dev/null
@@ -0,0 +1,115 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "eventDispatcher.h"
+#include "core/clock.h"
+#include "core/const.h"
+#include "core/model/model.h"
+#include "core/sequencer.h"
+#include "core/worker.h"
+#include "utils/log.h"
+#include <functional>
+
+namespace giada::m::eventDispatcher
+{
+namespace
+{
+Worker worker_;
+
+/* eventBuffer_
+Buffer of events sent to channels for event parsing. This is filled with Events
+coming from the two event queues.*/
+
+EventBuffer eventBuffer_;
+
+/* -------------------------------------------------------------------------- */
+
+void processFuntions_()
+{
+       for (const Event& e : eventBuffer_)
+       {
+               if (e.type == EventType::FUNCTION)
+                       std::get<std::function<void()>>(e.data)();
+               G_DEBUG("Event type=" << (int)e.type << ", delta=" << e.delta << ", frame=" << clock::getCurrentFrame());
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void processChannels_()
+{
+       for (channel::Data& ch : model::get().channels)
+               channel::react(ch, eventBuffer_, mixer::isChannelAudible(ch));
+       model::swap(model::SwapType::SOFT);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void processSequencer_()
+{
+       sequencer::react(eventBuffer_);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void process_()
+{
+       eventBuffer_.clear();
+
+       Event e;
+       while (UIevents.pop(e))
+               eventBuffer_.push_back(e);
+       while (MidiEvents.pop(e))
+               eventBuffer_.push_back(e);
+
+       if (eventBuffer_.size() == 0)
+               return;
+
+       processFuntions_();
+       processChannels_();
+       processSequencer_();
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+Queue<Event, G_MAX_DISPATCHER_EVENTS> UIevents;
+Queue<Event, G_MAX_DISPATCHER_EVENTS> MidiEvents;
+
+/* -------------------------------------------------------------------------- */
+
+void init()
+{
+       worker_.start(process_, /*sleep=*/G_EVENT_DISPATCHER_RATE_MS);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void pumpUIevent(Event e) { UIevents.push(e); }
+void pumpMidiEvent(Event e) { MidiEvents.push(e); }
+} // namespace giada::m::eventDispatcher
\ No newline at end of file
diff --git a/src/core/eventDispatcher.h b/src/core/eventDispatcher.h
new file mode 100644 (file)
index 0000000..094c39c
--- /dev/null
@@ -0,0 +1,98 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_EVENT_DISPATCHER_H
+#define G_EVENT_DISPATCHER_H
+
+#include "core/action.h"
+#include "core/const.h"
+#include "core/queue.h"
+#include "core/ringBuffer.h"
+#include "core/types.h"
+#include <atomic>
+#include <functional>
+#include <thread>
+#include <variant>
+
+/* giada::m::eventDispatcher
+Takes events from the two queues (MIDI and UI) filled by c::events and turns 
+them into actual changes in the data model. The EventDispatcher runs in a
+separate worker thread. */
+
+namespace giada::m::eventDispatcher
+{
+enum class EventType
+{
+       KEY_PRESS,
+       KEY_RELEASE,
+       KEY_KILL,
+       SEQUENCER_START,
+       SEQUENCER_STOP,
+       SEQUENCER_REWIND,
+       MIDI,
+       CHANNEL_TOGGLE_READ_ACTIONS,
+       CHANNEL_KILL_READ_ACTIONS,
+       CHANNEL_TOGGLE_ARM,
+       CHANNEL_MUTE,
+       CHANNEL_SOLO,
+       CHANNEL_VOLUME,
+       CHANNEL_PITCH,
+       CHANNEL_PAN,
+       FUNCTION
+};
+
+using EventData = std::variant<int, float, Action, std::function<void()>>;
+
+struct Event
+{
+       EventType type;
+       Frame     delta     = 0;
+       ID        channelId = 0;
+       EventData data;
+};
+
+/* EventBuffer
+Alias for a RingBuffer containing events to be sent to engine. The double size
+is due to the presence of two distinct Queues for collecting events coming from
+other threads. See below. */
+
+using EventBuffer = RingBuffer<Event, G_MAX_DISPATCHER_EVENTS * 2>;
+
+/* Event queues
+Collect events coming from the UI or MIDI devices. Our poor's man Queue is a 
+single-producer/single-consumer one, so we need two queues for two writers. 
+TODO - let's add a multi-producer queue sooner or later! */
+
+extern Queue<Event, G_MAX_DISPATCHER_EVENTS> UIevents;
+extern Queue<Event, G_MAX_DISPATCHER_EVENTS> MidiEvents;
+
+void init();
+
+void pumpUIevent(Event e);
+void pumpMidiEvent(Event e);
+} // namespace giada::m::eventDispatcher
+
+#endif
index 3a9e83a0d48e13ff88d3cedb054c843f2f29b8d9..2715433473154b98eb25cae65da41309cb76384c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #include "graphics.h"
 
-
 const char* giada_logo_xpm[] = {
-"245 86 12 1",
-"      c #191919",
-".     c #303030",
-"+     c #404040",
-"@     c #454545",
-"#     c #5A5A5A",
-"$     c #686868",
-"%     c #818181",
-"&     c #9C9C9C",
-"*     c #B8B8B8",
-"=     c #CDCDCD",
-"-     c #DDDDDD",
-";     c #FEFEFE",
-"                                   ...+++@@@@++...                                                                                                                                                                                                   ",
-"                               .+@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                               ",
-"                            .+@@@@@@@@@@@@@@@@@@@@@@@@@@+.                                                                                                                                                                                           ",
-"                         .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                         ",
-"                       .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                       ",
-"                      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                     ",
-"                    +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                   ",
-"                  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                                                                                                                                                                                  ",
-"                 .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                ",
-"                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                               ",
-"               @@@@@@@@@@@@@@@@@@++$*--;;;;;;;;-=&@+@@@@@@@@@@@@@@@@@@+                                                                                                                                                                              ",
-"             .@@@@@@@@@@@@@@@@+#&=;;;;;;;;;;;;;;;;;-*%++@@@@@@@@@@@@@@@+                                                                                                                                                                             ",
-"            .@@@@@@@@@@@@@@@@$=;;;;;;;;;;;;;;;;;;;;;;;;&#+@@@@@@@@@@@@@@@                                                                                                                                                                            ",
-"           .@@@@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@                                                                                                                                                                           ",
-"           @@@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@@@@@@@@@+                                                                                                                                                                          ",
-"          @@@@@@@@@@@@@+*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$+@@@@@@@@@@@@+                                                                                                                                                                         ",
-"         @@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&@@@@@@@@@@@@@.                                                                                                                                                                        ",
-"        .@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@@@@@                                                                                                                                                                        ",
-"       .@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-@@@@@@@@@@@@@                                                                                                                                                                       ",
-"       @@@@@@@@@@@+&;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@@@@@@@@.                                                                                                                                                                      ",
-"      +@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@@@@@@@@@                                                                                                                                                                      ",
-"      @@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@@@+                                                                                                                                                                     ",
-"     @@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;=@@@@@@@@@@@.                                                                                                                                                                    ",
-"    .@@@@@@@@@@+-;;;;;;;;;;;;;;;;;;;;;=*&%%%%&*-;;;;;;;;;;;;;;;;;;;;;%+@@@@@@@@@@                                                                                                                                                                    ",
-"    +@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;-%++@@@@@@@++@*-;;;;;;;;;;;;;;;;;;;#@@@@@@@@@@.                                                                                                                                                                   ",
-"   .@@@@@@@@@@#;;;;;;;;;;;;;;;;;;=@@@@@@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;=+@@@@@@@@@@                                                                                                                                                                   ",
-"   +@@@@@@@@@@-;;;;;;;;;;;;;;;;-$+@@@@@@@@@@@@@@@@@@@&;;;;;;;;;;;;;;;;;%@@@@@@@@@@.                        %*------=*%.              $%%%%%%%                $%%%%%%%%.               #%%%%%%%%%%%%%%$@                         %%%%%%%%%            ",
-"   @@@@@@@@@@%;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@@@@@@@+$;;;;;;;;;;;;;;;;-+@@@@@@@@@+                     #=;;;;;;;;;;;;;=$           .;;;;;;;;&              &;;;;;;;;;;               ;;;;;;;;;;;;;;;;;;-&#                    -;;;;;;;;;=           ",
-"  .@@@@@@@@@@;;;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@@@@@@@;;;;;;;;;;;;;;;;%@@@@@@@@@@                   .=;;;;;;;;;;;;;;;;;;#         +;;;;;;;;*              ;;;;;;;;;;;&             .;;;;;;;;;;;;;;;;;;;;;;@                 .;;;;;;;;;;;.          ",
-"  +@@@@@@@@@%;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@@@@@@@@@@@@@;;;;;;;;;;;;;;;;@@@@@@@@@@.                 @;;;;;;;;;;;;;;;;;;;;;*        +;;;;;;;;*             +;;;;;;;;;;;;             .;;;;;;;;;;;;;;;;;;;;;;;*                &;;;;;;;;;;;*          ",
-"  @@@@@@@@@+-;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;;;;;;;;;;;;;;$@@@@@@@@@+                @;;;;;;;;;;;;;;;;;;;;;;;=       +;;;;;;;;*             *;;;;;;;;;;;;.            .;;;;;;;;;;;;;;;;;;;;;;;;=               ;;;;;;;;;;;;;          ",
-" .@@@@@@@@@#;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;;;;;;;;;;;;;;=+@@@@@@@@@               .;;;;;;;;;;;;;;;;;;;;;;;;;&      +;;;;;;;;*            .;;;;;;;;;;;;;&            .;;;;;;;;;;;;;;;;;;;;;;;;;*             #;;;;;;;;;;;;;+         ",
-" +@@@@@@@@@&;;;;;;;;;;;;;;#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+*;;;;;;;;;;;;;;#@@@@@@@@@               *;;;;;;;;;;;;;;;;;;;;;;;;;;#     +;;;;;;;;*            $;;;;;;;;;;;;;;            .;;;;;;;;;;;;;;;;;;;;;;;;;;#            *;;;;;;;;;;;;;=         ",
-" @@@@@@@@@+-;;;;;;;;;;;;;*@@@@@@@@@@@@+#*;;;-&@@@@@@@@@@@@@@;;;;;;;;;;;;;;%@@@@@@@@@.             +;;;;;;;;;;-#   #-;;;;;;;;;;=     +;;;;;;;;*            =;;;;;;;;;;;;;;#           .;;;;;;;;-&&&&*-;;;;;;;;;;;;            ;;;;;;;;;;;;;;;.        ",
-" @@@@@@@@@+;;;;;;;;;;;;;;@@@@@@@@@@@+%-;;;;;;;;*+@@@@@@@@@@+&;;;;;;;;;;;;;*+@@@@@@@@+             &;;;;;;;;;%       %;;;;;;;;;;     +;;;;;;;;*           .;;;;;;;;;;;;;;;*           .;;;;;;;;=       #;;;;;;;;;;#          %;;;;;;;;;;;;;;;$        ",
-".@@@@@@@@@%;;;;;;;;;;;;;=@@@@@@@@@@+&;;;;;;;;;;;;#@@@@@@@@@@#;;;;;;;;;;;;;;+@@@@@@@@@             =;;;;;;;;=         =;;;;;;;;;@    +;;;;;;;;*           &;;;;;;;%;;;;;;;;           .;;;;;;;;=         ;;;;;;;;;&          -;;;;;;;%;;;;;;;=        ",
-".@@@@@@@@@=;;;;;;;;;;;;;$@@@@@@@@@+*;;;;;;;;;;;;;;#@@@@@@@@@@-;;;;;;;;;;;;;#@@@@@@@@@             ;;;;;;;;;@          -;;;;;;;;.    +;;;;;;;;*           -;;;;;;;+*;;;;;;;%          .;;;;;;;;=         %;;;;;;;;-          ;;;;;;;; ;;;;;;;;.       ",
-".@@@@@@@@@-;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;%@@@@@@@@@             ;;;;;;;;;                         +;;;;;;;;*          .;;;;;;;; #;;;;;;;=          .;;;;;;;;=          ;;;;;;;;;         &;;;;;;;& &;;;;;;;&       ",
-"+@@@@@@@@@;;;;;;;;;;;;;*+@@@@@@@@@;;;;;;;;;;;;;;;;;&@@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@            .;;;;;;;;-                         +;;;;;;;;*          *;;;;;;;%  ;;;;;;;;          .;;;;;;;;=          -;;;;;;;;         ;;;;;;;;. @;;;;;;;-       ",
-"+@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@%;;;;;;;;;;;;;;;;;-+@@@@@@@@+-;;;;;;;;;;;;*@@@@@@@@@.           .;;;;;;;;-                         +;;;;;;;;*          ;;;;;;;;.  *;;;;;;;&         .;;;;;;;;=          =;;;;;;;;.       .;;;;;;;;   ;;;;;;;;.      ",
-"+@@@@@@@@@;;;;;;;;;;;;;%@@@@@@@@+-;;;;;;;;;;;;;;;;;;$@@@@@@@@@-;;;;;;;;;;;;=@@@@@@@@@.           .;;;;;;;;-      .%%%%%%%%%%%%$     +;;;;;;;;*         +;;;;;;;-   .;;;;;;;;         .;;;;;;;;=          =;;;;;;;;.       &;;;;;;;*   %;;;;;;;*      ",
-"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@@;;;;;;;;;;;;;;;;;;;&@@@@@@@@@=;;;;;;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;%    +;;;;;;;;*         *;;;;;;;&    ;;;;;;;;.        .;;;;;;;;=          *;;;;;;;;.       ;;;;;;;;.   .;;;;;;;;      ",
-"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@#;;;;;;;;;;;;;;;;;;;*@@@@@@@@@=;;;;;;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        .;;;;;;;;     *;;;;;;;&        .;;;;;;;;=          *;;;;;;;;+      #;;;;;;;-     ;;;;;;;;+     ",
-"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@#;;;;;;;;;;;;;;;;;;;*@@@@@@@@@#$$&*-;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        $;;;;;;;=     .;;;;;;;;        .;;;;;;;;=          *;;;;;;;;+      *;;;;;;;&     %;;;;;;;*     ",
-"@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@@;;;;;;;;;;;;;;;;;;;&@@@@@@@@@@@@@@+@=;;;;;=@@@@@@@@@.           .;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        =;;;;;;;%      -;;;;;;;#       .;;;;;;;;=          *;;;;;;;;.      ;;;;;;;;+      ;;;;;;;;.    ",
-"+@@@@@@@@@;;;;;;;;;;;;;%@@@@@@@@+-;;;;;;;;;;;;;;;;;;$@@@@@@@@@@@@@@@@@#-;;;=@@@@@@@@@.           .;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*       .;;;;;;;;.      &;;;;;;;*       .;;;;;;;;=          =;;;;;;;;.     %;;;;;;;-       =;;;;;;;#    ",
-"+@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@%;;;;;;;;;;;;;;;;;;+@@@@@+++++++@@@@@@@&;;*@@@@@@@@@.           .;;;;;;;;-      @%%%%*;;;;;;;;&    +;;;;;;;;*       &;;;;;;;=.......#;;;;;;;;       .;;;;;;;;=          =;;;;;;;;.     -;;;;;;;%.......&;;;;;;;=    ",
-"+@@@@@@@@@;;;;;;;;;;;;;*+@@@@@@@@@;;;;;;;;;;;;;;;;;&@@@+#%*-;;-=&$@@@@@@@%;&@@@@@@@@@             ;;;;;;;;;           %;;;;;;;;%    +;;;;;;;;*       -;;;;;;;;;;;;;;;;;;;;;;;;%      .;;;;;;;;=          -;;;;;;;;      ;;;;;;;;;;;;;;;;;;;;;;;;;.   ",
-".@@@@@@@@@-;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;;;;+@@@*;;;;;;;;;;;%@@@@@@&%@@@@@@@@@             ;;;;;;;;;           &;;;;;;;;%    +;;;;;;;;*       ;;;;;;;;;;;;;;;;;;;;;;;;;=      .;;;;;;;;=          ;;;;;;;;;     %;;;;;;;;;;;;;;;;;;;;;;;;;&   ",
-".@@@@@@@@@=;;;;;;;;;;;;;$@@@@@@@@@+*;;;;;;;;;;;;;;#@+%;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@             -;;;;;;;;#          =;;;;;;;;@    +;;;;;;;;*      *;;;;;;;;;;;;;;;;;;;;;;;;;;      .;;;;;;;;=         $;;;;;;;;-     ;;;;;;;;;;;;;;;;;;;;;;;;;;-   ",
-".@@@@@@@@@%;;;;;;;;;;;;;=@@@@@@@@@@+*;;;;;;;;;;;;#@+*;;;;;;;;;;;;;;;;;$+@@@@@@@@@@@@@             =;;;;;;;;=         @;;;;;;;;;     +;;;;;;;;*      ;;;;;;;;;;;;;;;;;;;;;;;;;;;&     .;;;;;;;;=         -;;;;;;;;&    .;;;;;;;;;;;;;;;;;;;;;;;;;;;.  ",
-" @@@@@@@@@+;;;;;;;;;;;;;;@@@@@@@@@@@+%-;;;;;;;;*@@+*;;;;;;;;;;;;;;;;;;;$@@@@@@@@@@@@+             &;;;;;;;;;%       +;;;;;;;;;=     +;;;;;;;;*     +;;;;;;;;;;;;;;;;;;;;;;;;;;;;     .;;;;;;;;=       +-;;;;;;;;;$    &;;;;;;;;;;;;;;;;;;;;;;;;;;;*  ",
-" @@@@@@@@@+-;;;;;;;;;;;;;*@@@@@@@@@@@@+$=;;;-&@@@@&;;;;;;;;;;;;;;;;;;;;;@@@@@@@@@@@@.             .;;;;;;;;;;-@   .*;;;;;;;;;;%     +;;;;;;;;*     *;;;;;;;;;;;;;;;;;;;;;;;;;;;;.    .;;;;;;;;-&&&&&*;;;;;;;;;;;;     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ",
-" +@@@@@@@@@*;;;;;;;;;;;;;;#@@@@@@@@@@@@@@@@@+@@@@@;;;;;;;;;;;;;;;;;;;;;;-@@@@@@@@@@@               &;;;;;;;;;;;;;;;;;;;;;;;;;;      +;;;;;;;;*    .;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&    .;;;;;;;;;;;;;;;;;;;;;;;;;;$    #;;;;;;;;;;;;;;;;;;;;;;;;;;;;;. ",
-" .@@@@@@@@@#;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@@@@@@@-;;;;;;;;;;;;;;;;;;;;;;;$@@@@@@@@@@               .;;;;;;;;;;;;;;;;;;;;;;;;;@      +;;;;;;;;*    $;;;;;;;;%            ;;;;;;;;;    .;;;;;;;;;;;;;;;;;;;;;;;;;-     *;;;;;;;;            .;;;;;;;;* ",
-"  @@@@@@@@@+-;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@+                @;;;;;;;;;;;;;;;;;;;;;;;&       +;;;;;;;;*    *;;;;;;;;             &;;;;;;;;#   .;;;;;;;;;;;;;;;;;;;;;;;;;      ;;;;;;;;=             -;;;;;;;;.",
-"  +@@@@@@@@@%;;;;;;;;;;;;;;;&@@@@@@@@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@@@@@.                 #;;;;;;;;;;;;;;;;;;;;;%        +;;;;;;;;*    ;;;;;;;;*              ;;;;;;;;*   .;;;;;;;;;;;;;;;;;;;;;;;-      %;;;;;;;;%             %;;;;;;;;#",
-"  .@@@@@@@@@@;;;;;;;;;;;;;;;;&+@@@@@@@@@@@@@@@@+-;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@@@@                   .-;;;;;;;;;;;;;;;;;;+         +;;;;;;;;*   &;;;;;;;;$              =;;;;;;;;   .;;;;;;;;;;;;;;;;;;;;;;%       -;;;;;;;;               ;;;;;;;;*",
-"   @@@@@@@@@@%;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@+;;;;;;;;;;;;;;;;;;;;;;;;;;&+@@@@@@+                     $=;;;;;;;;;;;;;=$           .;;;;;;;;*   =;;;;;;;;               $;;;;;;;;#  .;;;;;;;;;;;;;;;;;;;=%.        ;;;;;;;;&               *;;;;;;;;",
-"   +@@@@@@@@@@-;;;;;;;;;;;;;;;;-#+@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@@.                       .%=---;---=%.              %&&&&&&&.   +&&&&&&&.                $&&&&&&%    #&&&&&&&&&&&&&&%$+            $&&&&&&%                 %&&&&&&#",
-"   .@@@@@@@@@@#;;;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;=+@@@@@@                                                                                                                                                                   ",
-"    +@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;=%++@@@@@@@+@;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@.                                                                                                                                                                   ",
-"    .@@@@@@@@@@@-;;;;;;;;;;;;;;;;;;;;;=&%%$%%&*-;;;;;;;;;;;;;;;;;;;;;;;;;;&+@@@@@                                                                                                                                                                    ",
-"     +@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@.                                                                                                                                                                    ",
-"      @@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@+                                                                                                                                                                     ",
-"      +@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@                                                                                                                                                                      ",
-"       @@@@@@@@@@@+&;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$@@@@.                                                                                                                                                                      ",
-"       .@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-@@@@@                                                                                                                                                                       ",
-"        .@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@@                                                                                                                                                                        ",
-"         +@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$@@@@.                                                                                                                                                                        ",
-"          @@@@@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%+@@@+                                                                                                                                                                         ",
-"           @@@@@@@@@@@@@+#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-#@@@@+                                                                                                                                                                          ",
-"           .@@@@@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@@                                                                                                                                                                           ",
-"            .@@@@@@@@@@@@@@@@$-;;;;;;;;;;;;;;;;;;;;;;;;*$%*-;;;-*$@@@@@@@                                                                                                                                                                            ",
-"             .@@@@@@@@@@@@@@@@+#&-;;;;;;;;;;;;;;;;;;=%@+@@+++.+++@@@@@@+                                                                                                                                                                             ",
-"               @@@@@@@@@@@@@@@@@@++%*--;;;;;;;;--&#++@@@@@@@@@@@@@@@@@+                                                                                                                                                                              ",
-"                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                               ",
-"                 .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                ",
-"                  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                                                                                                                                                                                  ",
-"                    +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                   ",
-"                      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                     ",
-"                       .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                       ",
-"                         .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                         ",
-"                            .+@@@@@@@@@@@@@@@@@@@@@@@@@@+.                                                                                                                                                                                           ",
-"                               .+@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                               ",
-"                                   ...+++@@@@++...                                                                                                                                                                                                   "};
-
+    "245 86 12 1",
+    "  c #191919",
+    ". c #303030",
+    "+ c #404040",
+    "@ c #454545",
+    "# c #5A5A5A",
+    "$ c #686868",
+    "% c #818181",
+    "& c #9C9C9C",
+    "* c #B8B8B8",
+    "= c #CDCDCD",
+    "- c #DDDDDD",
+    "; c #FEFEFE",
+    "                                   ...+++@@@@++...                                                                                                                                                                                                   ",
+    "                               .+@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                               ",
+    "                            .+@@@@@@@@@@@@@@@@@@@@@@@@@@+.                                                                                                                                                                                           ",
+    "                         .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                         ",
+    "                       .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                       ",
+    "                      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                     ",
+    "                    +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                   ",
+    "                  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                                                                                                                                                                                  ",
+    "                 .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                ",
+    "                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                               ",
+    "               @@@@@@@@@@@@@@@@@@++$*--;;;;;;;;-=&@+@@@@@@@@@@@@@@@@@@+                                                                                                                                                                              ",
+    "             .@@@@@@@@@@@@@@@@+#&=;;;;;;;;;;;;;;;;;-*%++@@@@@@@@@@@@@@@+                                                                                                                                                                             ",
+    "            .@@@@@@@@@@@@@@@@$=;;;;;;;;;;;;;;;;;;;;;;;;&#+@@@@@@@@@@@@@@@                                                                                                                                                                            ",
+    "           .@@@@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@                                                                                                                                                                           ",
+    "           @@@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@@@@@@@@@+                                                                                                                                                                          ",
+    "          @@@@@@@@@@@@@+*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$+@@@@@@@@@@@@+                                                                                                                                                                         ",
+    "         @@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&@@@@@@@@@@@@@.                                                                                                                                                                        ",
+    "        .@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@@@@@                                                                                                                                                                        ",
+    "       .@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-@@@@@@@@@@@@@                                                                                                                                                                       ",
+    "       @@@@@@@@@@@+&;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@@@@@@@@.                                                                                                                                                                      ",
+    "      +@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@@@@@@@@@                                                                                                                                                                      ",
+    "      @@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@@@+                                                                                                                                                                     ",
+    "     @@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;=@@@@@@@@@@@.                                                                                                                                                                    ",
+    "    .@@@@@@@@@@+-;;;;;;;;;;;;;;;;;;;;;=*&%%%%&*-;;;;;;;;;;;;;;;;;;;;;%+@@@@@@@@@@                                                                                                                                                                    ",
+    "    +@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;-%++@@@@@@@++@*-;;;;;;;;;;;;;;;;;;;#@@@@@@@@@@.                                                                                                                                                                   ",
+    "   .@@@@@@@@@@#;;;;;;;;;;;;;;;;;;=@@@@@@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;=+@@@@@@@@@@                                                                                                                                                                   ",
+    "   +@@@@@@@@@@-;;;;;;;;;;;;;;;;-$+@@@@@@@@@@@@@@@@@@@&;;;;;;;;;;;;;;;;;%@@@@@@@@@@.                        %*------=*%.              $%%%%%%%                $%%%%%%%%.               #%%%%%%%%%%%%%%$@                         %%%%%%%%%            ",
+    "   @@@@@@@@@@%;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@@@@@@@+$;;;;;;;;;;;;;;;;-+@@@@@@@@@+                     #=;;;;;;;;;;;;;=$           .;;;;;;;;&              &;;;;;;;;;;               ;;;;;;;;;;;;;;;;;;-&#                    -;;;;;;;;;=           ",
+    "  .@@@@@@@@@@;;;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@@@@@@@;;;;;;;;;;;;;;;;%@@@@@@@@@@                   .=;;;;;;;;;;;;;;;;;;#         +;;;;;;;;*              ;;;;;;;;;;;&             .;;;;;;;;;;;;;;;;;;;;;;@                 .;;;;;;;;;;;.          ",
+    "  +@@@@@@@@@%;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@@@@@@@@@@@@@;;;;;;;;;;;;;;;;@@@@@@@@@@.                 @;;;;;;;;;;;;;;;;;;;;;*        +;;;;;;;;*             +;;;;;;;;;;;;             .;;;;;;;;;;;;;;;;;;;;;;;*                &;;;;;;;;;;;*          ",
+    "  @@@@@@@@@+-;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;;;;;;;;;;;;;;$@@@@@@@@@+                @;;;;;;;;;;;;;;;;;;;;;;;=       +;;;;;;;;*             *;;;;;;;;;;;;.            .;;;;;;;;;;;;;;;;;;;;;;;;=               ;;;;;;;;;;;;;          ",
+    " .@@@@@@@@@#;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;;;;;;;;;;;;;;=+@@@@@@@@@               .;;;;;;;;;;;;;;;;;;;;;;;;;&      +;;;;;;;;*            .;;;;;;;;;;;;;&            .;;;;;;;;;;;;;;;;;;;;;;;;;*             #;;;;;;;;;;;;;+         ",
+    " +@@@@@@@@@&;;;;;;;;;;;;;;#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+*;;;;;;;;;;;;;;#@@@@@@@@@               *;;;;;;;;;;;;;;;;;;;;;;;;;;#     +;;;;;;;;*            $;;;;;;;;;;;;;;            .;;;;;;;;;;;;;;;;;;;;;;;;;;#            *;;;;;;;;;;;;;=         ",
+    " @@@@@@@@@+-;;;;;;;;;;;;;*@@@@@@@@@@@@+#*;;;-&@@@@@@@@@@@@@@;;;;;;;;;;;;;;%@@@@@@@@@.             +;;;;;;;;;;-#   #-;;;;;;;;;;=     +;;;;;;;;*            =;;;;;;;;;;;;;;#           .;;;;;;;;-&&&&*-;;;;;;;;;;;;            ;;;;;;;;;;;;;;;.        ",
+    " @@@@@@@@@+;;;;;;;;;;;;;;@@@@@@@@@@@+%-;;;;;;;;*+@@@@@@@@@@+&;;;;;;;;;;;;;*+@@@@@@@@+             &;;;;;;;;;%       %;;;;;;;;;;     +;;;;;;;;*           .;;;;;;;;;;;;;;;*           .;;;;;;;;=       #;;;;;;;;;;#          %;;;;;;;;;;;;;;;$        ",
+    ".@@@@@@@@@%;;;;;;;;;;;;;=@@@@@@@@@@+&;;;;;;;;;;;;#@@@@@@@@@@#;;;;;;;;;;;;;;+@@@@@@@@@             =;;;;;;;;=         =;;;;;;;;;@    +;;;;;;;;*           &;;;;;;;%;;;;;;;;           .;;;;;;;;=         ;;;;;;;;;&          -;;;;;;;%;;;;;;;=        ",
+    ".@@@@@@@@@=;;;;;;;;;;;;;$@@@@@@@@@+*;;;;;;;;;;;;;;#@@@@@@@@@@-;;;;;;;;;;;;;#@@@@@@@@@             ;;;;;;;;;@          -;;;;;;;;.    +;;;;;;;;*           -;;;;;;;+*;;;;;;;%          .;;;;;;;;=         %;;;;;;;;-          ;;;;;;;; ;;;;;;;;.       ",
+    ".@@@@@@@@@-;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;%@@@@@@@@@             ;;;;;;;;;                         +;;;;;;;;*          .;;;;;;;; #;;;;;;;=          .;;;;;;;;=          ;;;;;;;;;         &;;;;;;;& &;;;;;;;&       ",
+    "+@@@@@@@@@;;;;;;;;;;;;;*+@@@@@@@@@;;;;;;;;;;;;;;;;;&@@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@            .;;;;;;;;-                         +;;;;;;;;*          *;;;;;;;%  ;;;;;;;;          .;;;;;;;;=          -;;;;;;;;         ;;;;;;;;. @;;;;;;;-       ",
+    "+@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@%;;;;;;;;;;;;;;;;;-+@@@@@@@@+-;;;;;;;;;;;;*@@@@@@@@@.           .;;;;;;;;-                         +;;;;;;;;*          ;;;;;;;;.  *;;;;;;;&         .;;;;;;;;=          =;;;;;;;;.       .;;;;;;;;   ;;;;;;;;.      ",
+    "+@@@@@@@@@;;;;;;;;;;;;;%@@@@@@@@+-;;;;;;;;;;;;;;;;;;$@@@@@@@@@-;;;;;;;;;;;;=@@@@@@@@@.           .;;;;;;;;-      .%%%%%%%%%%%%$     +;;;;;;;;*         +;;;;;;;-   .;;;;;;;;         .;;;;;;;;=          =;;;;;;;;.       &;;;;;;;*   %;;;;;;;*      ",
+    "@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@@;;;;;;;;;;;;;;;;;;;&@@@@@@@@@=;;;;;;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;%    +;;;;;;;;*         *;;;;;;;&    ;;;;;;;;.        .;;;;;;;;=          *;;;;;;;;.       ;;;;;;;;.   .;;;;;;;;      ",
+    "@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@#;;;;;;;;;;;;;;;;;;;*@@@@@@@@@=;;;;;;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        .;;;;;;;;     *;;;;;;;&        .;;;;;;;;=          *;;;;;;;;+      #;;;;;;;-     ;;;;;;;;+     ",
+    "@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@#;;;;;;;;;;;;;;;;;;;*@@@@@@@@@#$$&*-;;;;;;;=+@@@@@@@@.           +;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        $;;;;;;;=     .;;;;;;;;        .;;;;;;;;=          *;;;;;;;;+      *;;;;;;;&     %;;;;;;;*     ",
+    "@@@@@@@@@@;;;;;;;;;;;;;$@@@@@@@@@;;;;;;;;;;;;;;;;;;;&@@@@@@@@@@@@@@+@=;;;;;=@@@@@@@@@.           .;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*        =;;;;;;;%      -;;;;;;;#       .;;;;;;;;=          *;;;;;;;;.      ;;;;;;;;+      ;;;;;;;;.    ",
+    "+@@@@@@@@@;;;;;;;;;;;;;%@@@@@@@@+-;;;;;;;;;;;;;;;;;;$@@@@@@@@@@@@@@@@@#-;;;=@@@@@@@@@.           .;;;;;;;;-      -;;;;;;;;;;;;;&    +;;;;;;;;*       .;;;;;;;;.      &;;;;;;;*       .;;;;;;;;=          =;;;;;;;;.     %;;;;;;;-       =;;;;;;;#    ",
+    "+@@@@@@@@@;;;;;;;;;;;;;&@@@@@@@@@%;;;;;;;;;;;;;;;;;;+@@@@@+++++++@@@@@@@&;;*@@@@@@@@@.           .;;;;;;;;-      @%%%%*;;;;;;;;&    +;;;;;;;;*       &;;;;;;;=.......#;;;;;;;;       .;;;;;;;;=          =;;;;;;;;.     -;;;;;;;%.......&;;;;;;;=    ",
+    "+@@@@@@@@@;;;;;;;;;;;;;*+@@@@@@@@@;;;;;;;;;;;;;;;;;&@@@+#%*-;;-=&$@@@@@@@%;&@@@@@@@@@             ;;;;;;;;;           %;;;;;;;;%    +;;;;;;;;*       -;;;;;;;;;;;;;;;;;;;;;;;;%      .;;;;;;;;=          -;;;;;;;;      ;;;;;;;;;;;;;;;;;;;;;;;;;.   ",
+    ".@@@@@@@@@-;;;;;;;;;;;;;+@@@@@@@@@%;;;;;;;;;;;;;;;;+@@@*;;;;;;;;;;;%@@@@@@&%@@@@@@@@@             ;;;;;;;;;           &;;;;;;;;%    +;;;;;;;;*       ;;;;;;;;;;;;;;;;;;;;;;;;;=      .;;;;;;;;=          ;;;;;;;;;     %;;;;;;;;;;;;;;;;;;;;;;;;;&   ",
+    ".@@@@@@@@@=;;;;;;;;;;;;;$@@@@@@@@@+*;;;;;;;;;;;;;;#@+%;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@             -;;;;;;;;#          =;;;;;;;;@    +;;;;;;;;*      *;;;;;;;;;;;;;;;;;;;;;;;;;;      .;;;;;;;;=         $;;;;;;;;-     ;;;;;;;;;;;;;;;;;;;;;;;;;;-   ",
+    ".@@@@@@@@@%;;;;;;;;;;;;;=@@@@@@@@@@+*;;;;;;;;;;;;#@+*;;;;;;;;;;;;;;;;;$+@@@@@@@@@@@@@             =;;;;;;;;=         @;;;;;;;;;     +;;;;;;;;*      ;;;;;;;;;;;;;;;;;;;;;;;;;;;&     .;;;;;;;;=         -;;;;;;;;&    .;;;;;;;;;;;;;;;;;;;;;;;;;;;.  ",
+    " @@@@@@@@@+;;;;;;;;;;;;;;@@@@@@@@@@@+%-;;;;;;;;*@@+*;;;;;;;;;;;;;;;;;;;$@@@@@@@@@@@@+             &;;;;;;;;;%       +;;;;;;;;;=     +;;;;;;;;*     +;;;;;;;;;;;;;;;;;;;;;;;;;;;;     .;;;;;;;;=       +-;;;;;;;;;$    &;;;;;;;;;;;;;;;;;;;;;;;;;;;*  ",
+    " @@@@@@@@@+-;;;;;;;;;;;;;*@@@@@@@@@@@@+$=;;;-&@@@@&;;;;;;;;;;;;;;;;;;;;;@@@@@@@@@@@@.             .;;;;;;;;;;-@   .*;;;;;;;;;;%     +;;;;;;;;*     *;;;;;;;;;;;;;;;;;;;;;;;;;;;;.    .;;;;;;;;-&&&&&*;;;;;;;;;;;;     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  ",
+    " +@@@@@@@@@*;;;;;;;;;;;;;;#@@@@@@@@@@@@@@@@@+@@@@@;;;;;;;;;;;;;;;;;;;;;;-@@@@@@@@@@@               &;;;;;;;;;;;;;;;;;;;;;;;;;;      +;;;;;;;;*    .;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&    .;;;;;;;;;;;;;;;;;;;;;;;;;;$    #;;;;;;;;;;;;;;;;;;;;;;;;;;;;;. ",
+    " .@@@@@@@@@#;;;;;;;;;;;;;;-@@@@@@@@@@@@@@@@@@@@@@-;;;;;;;;;;;;;;;;;;;;;;;$@@@@@@@@@@               .;;;;;;;;;;;;;;;;;;;;;;;;;@      +;;;;;;;;*    $;;;;;;;;%            ;;;;;;;;;    .;;;;;;;;;;;;;;;;;;;;;;;;;-     *;;;;;;;;            .;;;;;;;;* ",
+    "  @@@@@@@@@+-;;;;;;;;;;;;;;*+@@@@@@@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@@@@@+                @;;;;;;;;;;;;;;;;;;;;;;;&       +;;;;;;;;*    *;;;;;;;;             &;;;;;;;;#   .;;;;;;;;;;;;;;;;;;;;;;;;;      ;;;;;;;;=             -;;;;;;;;.",
+    "  +@@@@@@@@@%;;;;;;;;;;;;;;;&@@@@@@@@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@@@@@.                 #;;;;;;;;;;;;;;;;;;;;;%        +;;;;;;;;*    ;;;;;;;;*              ;;;;;;;;*   .;;;;;;;;;;;;;;;;;;;;;;;-      %;;;;;;;;%             %;;;;;;;;#",
+    "  .@@@@@@@@@@;;;;;;;;;;;;;;;;&+@@@@@@@@@@@@@@@@+-;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@@@@                   .-;;;;;;;;;;;;;;;;;;+         +;;;;;;;;*   &;;;;;;;;$              =;;;;;;;;   .;;;;;;;;;;;;;;;;;;;;;;%       -;;;;;;;;               ;;;;;;;;*",
+    "   @@@@@@@@@@%;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@@@@+;;;;;;;;;;;;;;;;;;;;;;;;;;&+@@@@@@+                     $=;;;;;;;;;;;;;=$           .;;;;;;;;*   =;;;;;;;;               $;;;;;;;;#  .;;;;;;;;;;;;;;;;;;;=%.        ;;;;;;;;&               *;;;;;;;;",
+    "   +@@@@@@@@@@-;;;;;;;;;;;;;;;;-#+@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@@.                       .%=---;---=%.              %&&&&&&&.   +&&&&&&&.                $&&&&&&%    #&&&&&&&&&&&&&&%$+            $&&&&&&%                 %&&&&&&#",
+    "   .@@@@@@@@@@#;;;;;;;;;;;;;;;;;;*@@@@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;=+@@@@@@                                                                                                                                                                   ",
+    "    +@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;=%++@@@@@@@+@;;;;;;;;;;;;;;;;;;;;;;;;;;*+@@@@@.                                                                                                                                                                   ",
+    "    .@@@@@@@@@@@-;;;;;;;;;;;;;;;;;;;;;=&%%$%%&*-;;;;;;;;;;;;;;;;;;;;;;;;;;&+@@@@@                                                                                                                                                                    ",
+    "     +@@@@@@@@@@#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@.                                                                                                                                                                    ",
+    "      @@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#@@@@+                                                                                                                                                                     ",
+    "      +@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-+@@@@                                                                                                                                                                      ",
+    "       @@@@@@@@@@@+&;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$@@@@.                                                                                                                                                                      ",
+    "       .@@@@@@@@@@@+%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-@@@@@                                                                                                                                                                       ",
+    "        .@@@@@@@@@@@@$;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@@@@@                                                                                                                                                                        ",
+    "         +@@@@@@@@@@@@#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$@@@@.                                                                                                                                                                        ",
+    "          @@@@@@@@@@@@@@*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%+@@@+                                                                                                                                                                         ",
+    "           @@@@@@@@@@@@@+#-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-#@@@@+                                                                                                                                                                          ",
+    "           .@@@@@@@@@@@@@@@%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%@@@@@@                                                                                                                                                                           ",
+    "            .@@@@@@@@@@@@@@@@$-;;;;;;;;;;;;;;;;;;;;;;;;*$%*-;;;-*$@@@@@@@                                                                                                                                                                            ",
+    "             .@@@@@@@@@@@@@@@@+#&-;;;;;;;;;;;;;;;;;;=%@+@@+++.+++@@@@@@+                                                                                                                                                                             ",
+    "               @@@@@@@@@@@@@@@@@@++%*--;;;;;;;;--&#++@@@@@@@@@@@@@@@@@+                                                                                                                                                                              ",
+    "                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                               ",
+    "                 .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                ",
+    "                  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+                                                                                                                                                                                  ",
+    "                    +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                   ",
+    "                      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                     ",
+    "                       .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                       ",
+    "                         .+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                         ",
+    "                            .+@@@@@@@@@@@@@@@@@@@@@@@@@@+.                                                                                                                                                                                           ",
+    "                               .+@@@@@@@@@@@@@@@@@@@@.                                                                                                                                                                                               ",
+    "                                   ...+++@@@@++...                                                                                                                                                                                                   "};
 
 const char* loopRepeat_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #323331",
-"@     c #4D4F4C",
-"#     c #646663",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BFC1BD",
-"..................",
-"..................",
-"..................",
-"...&%#......#%&...",
-"...&&&%+..+%&&&...",
-"...$%&&%..%&&%$...",
-".....$&&##&&$.....",
-"......%&%%&%......",
-"......$&&&&$......",
-"......$&&&&$......",
-"......%&%%&%......",
-".....$&&##&&$.....",
-"...$%&&%..%&&%$...",
-"...&&&%+..+%&&&...",
-"...&%#......#%&...",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #323331",
+    "@ c #4D4F4C",
+    "# c #646663",
+    "$ c #787A77",
+    "% c #919390",
+    "& c #BFC1BD",
+    "..................",
+    "..................",
+    "..................",
+    "...&%#......#%&...",
+    "...&&&%+..+%&&&...",
+    "...$%&&%..%&&%$...",
+    ".....$&&##&&$.....",
+    "......%&%%&%......",
+    "......$&&&&$......",
+    "......$&&&&$......",
+    "......%&%%&%......",
+    ".....$&&##&&$.....",
+    "...$%&&%..%&&%$...",
+    "...&&&%+..+%&&&...",
+    "...&%#......#%&...",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* loopBasic_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"......#%&&%#......",
-"....+%&&&&&&%+....",
-"....%&&&%%&&&%....",
-"...#&&%+..+%&&#...",
-"...%&&+....+&&%...",
-"...&&%......%&&...",
-"...&&%......%&&...",
-"...%&&+....+&&%...",
-"...#&&%+..+%&&#...",
-"....%&&&%%&&&%....",
-"....+%&&&&&&%+....",
-"......#%&&%#......",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #313230",
+    "@ c #4D4F4C",
+    "# c #666765",
+    "$ c #787A77",
+    "% c #919390",
+    "& c #BEC0BD",
+    "..................",
+    "..................",
+    "..................",
+    "......#%&&%#......",
+    "....+%&&&&&&%+....",
+    "....%&&&%%&&&%....",
+    "...#&&%+..+%&&#...",
+    "...%&&+....+&&%...",
+    "...&&%......%&&...",
+    "...&&%......%&&...",
+    "...%&&+....+&&%...",
+    "...#&&%+..+%&&#...",
+    "....%&&&%%&&&%....",
+    "....+%&&&&&&%+....",
+    "......#%&&%#......",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* loopOnce_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #323331",
-"@     c #4D4F4C",
-"#     c #646663",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BFC1BD",
-"..................",
-"..................",
-"..................",
-"......$%&&%#......",
-"....+&&&&&&&&+....",
-"...+&&&&$$&&&&+...",
-"...$&&$....$&&$...",
-"...%&&......%&%...",
-"..................",
-"..................",
-"...%&&+.....&&&...",
-"...#&&$....$&&#...",
-"....%&&&%$&&&%....",
-"....+%&&&&&&%+....",
-"......#%&&%#......",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #323331",
+    "@ c #4D4F4C",
+    "# c #646663",
+    "$ c #787A77",
+    "% c #919390",
+    "& c #BFC1BD",
+    "..................",
+    "..................",
+    "..................",
+    "......$%&&%#......",
+    "....+&&&&&&&&+....",
+    "...+&&&&$$&&&&+...",
+    "...$&&$....$&&$...",
+    "...%&&......%&%...",
+    "..................",
+    "..................",
+    "...%&&+.....&&&...",
+    "...#&&$....$&&#...",
+    "....%&&&%$&&&%....",
+    "....+%&&&&&&%+....",
+    "......#%&&%#......",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* loopOnceBar_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #393A38",
-"+     c #545553",
-"@     c #747673",
-"#     c #A3A5A2",
-"$     c #ADAFAC",
-"%     c #B5B7B4",
-"&     c #C7C9C6",
-"                  ",
-"                  ",
-"                  ",
-"      @$&%#@      ",
-"    .$&&&&&&$.    ",
-"    %&&#@@#&&$    ",
-"   @&&@    @&&@   ",
-"   %&# +%$+ #&$   ",
-"       %&&%       ",
-"       %&&%       ",
-"   $&# +%%+ #&$   ",
-"   @&&@    @&&@   ",
-"    $&&#@@#&&$    ",
-"    .$&&&&&&$.    ",
-"      @#&&#@      ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #393A38",
+    "+ c #545553",
+    "@ c #747673",
+    "# c #A3A5A2",
+    "$ c #ADAFAC",
+    "% c #B5B7B4",
+    "& c #C7C9C6",
+    "                  ",
+    "                  ",
+    "                  ",
+    "      @$&%#@      ",
+    "    .$&&&&&&$.    ",
+    "    %&&#@@#&&$    ",
+    "   @&&@    @&&@   ",
+    "   %&# +%$+ #&$   ",
+    "       %&&%       ",
+    "       %&&%       ",
+    "   $&# +%%+ #&$   ",
+    "   @&&@    @&&@   ",
+    "    $&&#@@#&&$    ",
+    "    .$&&&&&&$.    ",
+    "      @#&&#@      ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* oneshotBasic_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"...$$$$$$$$$$$$...",
-"...&&&&&&&&&&&&...",
-"...&&&&&&&&&&&&...",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #313230",
+    "@ c #4D4F4C",
+    "# c #666765",
+    "$ c #787A77",
+    "% c #919390",
+    "& c #BEC0BD",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "...$$$$$$$$$$$$...",
+    "...&&&&&&&&&&&&...",
+    "...&&&&&&&&&&&&...",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* oneshotRetrig_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"...$$$$$$$#@......",
-"...&&&&&&&&&&@....",
-"...&&&&&&&&&&&+...",
-"..........+$&&%...",
-"............%&&...",
-"............%&&...",
-"...........+&&%...",
-"...$$$$$$$%&&&#...",
-"...&&&&&&&&&&%....",
-"...&&&&&&&&%#.....",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #313230",
+    "@ c #4D4F4C",
+    "# c #666765",
+    "$ c #787A77",
+    "% c #919390",
+    "& c #BEC0BD",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "...$$$$$$$#@......",
+    "...&&&&&&&&&&@....",
+    "...&&&&&&&&&&&+...",
+    "..........+$&&%...",
+    "............%&&...",
+    "............%&&...",
+    "...........+&&%...",
+    "...$$$$$$$%&&&#...",
+    "...&&&&&&&&&&%....",
+    "...&&&&&&&&%#.....",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* oneshotPress_xpm[] = {
-"18 18 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #313230",
-"@     c #4D4F4C",
-"#     c #666765",
-"$     c #787A77",
-"%     c #919390",
-"&     c #BEC0BD",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"...+%&%+..........",
-"...%&&&%..........",
-"...&&&&&..........",
-"...$&&&$..........",
-"...+$&$+..........",
-"..................",
-"...$$$$$$$$$$$$...",
-"...&&&&&&&&&&&&...",
-"...&&&&&&&&&&&&...",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #313230",
+    "@ c #4D4F4C",
+    "# c #666765",
+    "$ c #787A77",
+    "% c #919390",
+    "& c #BEC0BD",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "...+%&%+..........",
+    "...%&&&%..........",
+    "...&&&&&..........",
+    "...$&&&$..........",
+    "...+$&$+..........",
+    "..................",
+    "...$$$$$$$$$$$$...",
+    "...&&&&&&&&&&&&...",
+    "...&&&&&&&&&&&&...",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* oneshotEndless_xpm[] = {
-"18 18 6 1",
-"      c #242523",
-".     c #464745",
-"+     c #6D6F6C",
-"@     c #888A87",
-"#     c #ADAFAC",
-"$     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        .++.      ",
-"       @$$$$#.    ",
-"      @$$$$$$$.   ",
-"     .$$#. +$$@   ",
-"     +$$.   @$#   ",
-"     +$$    @$$   ",
-"     .$$+   #$#   ",
-"   @@@$$$@@#$$+   ",
-"   $$$$$$$$$$@    ",
-"   $$$$$$$$#+     ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 6 1",
+    "  c #242523",
+    ". c #464745",
+    "+ c #6D6F6C",
+    "@ c #888A87",
+    "# c #ADAFAC",
+    "$ c #C6C8C5",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "        .++.      ",
+    "       @$$$$#.    ",
+    "      @$$$$$$$.   ",
+    "     .$$#. +$$@   ",
+    "     +$$.   @$#   ",
+    "     +$$    @$$   ",
+    "     .$$+   #$#   ",
+    "   @@@$$$@@#$$+   ",
+    "   $$$$$$$$$$@    ",
+    "   $$$$$$$$#+     ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* updirOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #332F2E",
-"+     c #54494A",
-"@     c #6B5A5C",
-"#     c #866C6B",
-"$     c #967B7A",
-"%     c #987D7C",
-"&     c #B18E8F",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        @@        ",
-"       #&&#       ",
-"     .#&&&&#.     ",
-"    .$&&&&&&$.    ",
-"    +@%&&&&%@+    ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"      #&&&&#      ",
-"       ....       ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #332F2E",
+    "+ c #54494A",
+    "@ c #6B5A5C",
+    "# c #866C6B",
+    "$ c #967B7A",
+    "% c #987D7C",
+    "& c #B18E8F",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "        @@        ",
+    "       #&&#       ",
+    "     .#&&&&#.     ",
+    "    .$&&&&&&$.    ",
+    "    +@%&&&&%@+    ",
+    "      #&&&&#      ",
+    "      #&&&&#      ",
+    "      #&&&&#      ",
+    "      #&&&&#      ",
+    "      #&&&&#      ",
+    "       ....       ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* updirOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #555150",
-"+     c #706465",
-"@     c #7D6B6E",
-"#     c #877373",
-"$     c #957978",
-"%     c #9F8382",
-"&     c #B18E8F",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        ##        ",
-"       #&&#       ",
-"     .$&&&&$.     ",
-"    .%&&&&&&%.    ",
-"    +@%&&&&%@+    ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"      $&&&&$      ",
-"       ....       ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #555150",
+    "+ c #706465",
+    "@ c #7D6B6E",
+    "# c #877373",
+    "$ c #957978",
+    "% c #9F8382",
+    "& c #B18E8F",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "        ##        ",
+    "       #&&#       ",
+    "     .$&&&&$.     ",
+    "    .%&&&&&&%.    ",
+    "    +@%&&&&%@+    ",
+    "      $&&&&$      ",
+    "      $&&&&$      ",
+    "      $&&&&$      ",
+    "      $&&&&$      ",
+    "      $&&&&$      ",
+    "       ....       ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* pause_xpm[] = {
-"23 23 8 1",
-"      c #4D4F4C",
-".     c #514E53",
-"+     c #5C4F61",
-"@     c #6F507E",
-"#     c #855098",
-"$     c #9551AE",
-"%     c #A652C5",
-"&     c #AE52D1",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"       #+              ",
-"       &%#.            ",
-"       &&&%@           ",
-"       &&&&&$+         ",
-"       &&&&&&&#.       ",
-"       &&&&&&&&%@      ",
-"       &&&&&&&&&&#     ",
-"       &&&&&&&&%@.     ",
-"       &&&&&&&#.       ",
-"       &&&&&$+         ",
-"       &&&%@           ",
-"       &&#.            ",
-"       $+              ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
+    "23 23 8 1",
+    "  c #4D4F4C",
+    ". c #514E53",
+    "+ c #5C4F61",
+    "@ c #6F507E",
+    "# c #855098",
+    "$ c #9551AE",
+    "% c #A652C5",
+    "& c #AE52D1",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "       #+              ",
+    "       &%#.            ",
+    "       &&&%@           ",
+    "       &&&&&$+         ",
+    "       &&&&&&&#.       ",
+    "       &&&&&&&&%@      ",
+    "       &&&&&&&&&&#     ",
+    "       &&&&&&&&%@.     ",
+    "       &&&&&&&#.       ",
+    "       &&&&&$+         ",
+    "       &&&%@           ",
+    "       &&#.            ",
+    "       $+              ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
 
 const char* play_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #393534",
-"+     c #574B4C",
-"@     c #6E5B5A",
-"#     c #7C6663",
-"$     c #8C7170",
-"%     c #A48384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"       $.              ",
-"       &&@             ",
-"       &&&%+           ",
-"       &&&&&$.         ",
-"       &&&&&&&@        ",
-"       &&&&&&&&%+      ",
-"       &&&&&&&&&&#     ",
-"       &&&&&&&&%+      ",
-"       &&&&&&&#.       ",
-"       &&&&&$.         ",
-"       &&&%+           ",
-"       &&@             ",
-"       $.              ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
+    "23 23 8 1",
+    "  c #242523",
+    ". c #393534",
+    "+ c #574B4C",
+    "@ c #6E5B5A",
+    "# c #7C6663",
+    "$ c #8C7170",
+    "% c #A48384",
+    "& c #B18E8F",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "       $.              ",
+    "       &&@             ",
+    "       &&&%+           ",
+    "       &&&&&$.         ",
+    "       &&&&&&&@        ",
+    "       &&&&&&&&%+      ",
+    "       &&&&&&&&&&#     ",
+    "       &&&&&&&&%+      ",
+    "       &&&&&&&#.       ",
+    "       &&&&&$.         ",
+    "       &&&%+           ",
+    "       &&@             ",
+    "       $.              ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
 
 const char* rewindOff_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #393534",
-"+     c #574B4C",
-"@     c #6E5B5A",
-"#     c #7C6663",
-"$     c #8C7170",
-"%     c #A48384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                .$     ",
-"               @&&     ",
-"             +%&&&     ",
-"           .$&&&&&     ",
-"          @&&&&&&&     ",
-"        +%&&&&&&&&     ",
-"       #&&&&&&&&&&     ",
-"        +%&&&&&&&&     ",
-"         .#&&&&&&&     ",
-"           .$&&&&&     ",
-"             +%&&&     ",
-"               @&&     ",
-"                .$     ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
+    "23 23 8 1",
+    "  c #242523",
+    ". c #393534",
+    "+ c #574B4C",
+    "@ c #6E5B5A",
+    "# c #7C6663",
+    "$ c #8C7170",
+    "% c #A48384",
+    "& c #B18E8F",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                .$     ",
+    "               @&&     ",
+    "             +%&&&     ",
+    "           .$&&&&&     ",
+    "          @&&&&&&&     ",
+    "        +%&&&&&&&&     ",
+    "       #&&&&&&&&&&     ",
+    "        +%&&&&&&&&     ",
+    "         .#&&&&&&&     ",
+    "           .$&&&&&     ",
+    "             +%&&&     ",
+    "               @&&     ",
+    "                .$     ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
 
 const char* rewindOn_xpm[] = {
-"23 23 8 1",
-"      c #4D4F4C",
-".     c #514E53",
-"+     c #5C4F61",
-"@     c #6F507E",
-"#     c #855098",
-"$     c #9551AE",
-"%     c #A652C5",
-"&     c #AE52D1",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                +#     ",
-"              .#%&     ",
-"             @%&&&     ",
-"           +$&&&&&     ",
-"         .#&&&&&&&     ",
-"        @%&&&&&&&&     ",
-"       #&&&&&&&&&&     ",
-"       .@%&&&&&&&&     ",
-"         .#&&&&&&&     ",
-"           +$&&&&&     ",
-"             @%&&&     ",
-"              .#&&     ",
-"                +$     ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
-
+    "23 23 8 1",
+    "  c #4D4F4C",
+    ". c #514E53",
+    "+ c #5C4F61",
+    "@ c #6F507E",
+    "# c #855098",
+    "$ c #9551AE",
+    "% c #A652C5",
+    "& c #AE52D1",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                +#     ",
+    "              .#%&     ",
+    "             @%&&&     ",
+    "           +$&&&&&     ",
+    "         .#&&&&&&&     ",
+    "        @%&&&&&&&&     ",
+    "       #&&&&&&&&&&     ",
+    "       .@%&&&&&&&&     ",
+    "         .#&&&&&&&     ",
+    "           +$&&&&&     ",
+    "             @%&&&     ",
+    "              .#&&     ",
+    "                +$     ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
 
 const char* giada_icon[] = {
-"65 65 8 1",
-"      c #444643",
-".     c #565755",
-"+     c #6C6E6B",
-"@     c #898B88",
-"#     c #A3A5A2",
-"$     c #BEC0BD",
-"%     c #D7DAD6",
-"&     c #FCFEFB",
-"                                                                 ",
-" &&&&&&&&&&&&&&&&&&&&%$@                .@$%&&&&&&&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&&&&%$@.                     .#%&&&&&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&&&#+                          .@$&&&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&$+                              .@%&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&@                                  .#&&&&&&&&&&&&& ",
-" &&&&&&&&&&&%.                                     @&&&&&&&&&&&& ",
-" &&&&&&&&&&$              ...+@@#@@+..              +%&&&&&&&&&& ",
-" &&&&&&&&&#            .+#$&&&&&&&&&&%$@+.           .%&&&&&&&&& ",
-" &&&&&&&&#           +#%&&&&&&&&&&&&&&&&&$@.          .%&&&&&&&& ",
-" &&&&&&&#          .#%&&&&&&&&&&&&&&&&&&&&&%@          .%&&&&&&& ",
-" &&&&&&$          @%&&&&&&&&&&&&&&&&&&&&&&&&&%+         .&&&&&&& ",
-" &&&&&%          $&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@         +&&&&&& ",
-" &&&&&.        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#         @&&&&& ",
-" &&&&@        +%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#         $&&&& ",
-" &&&$        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#        +&&&& ",
-" &&&+        %&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#        #&&& ",
-" &&#        $&&&&&&&&&&&&&&&&%$###$%&&&&&&&&&&&&&&&&@       +%&& ",
-" &%+       @&&&&&&&&&&&&&&%@..    ..+#&&&&&&&&&&&&&&%.       #&& ",
-" &$       .%&&&&&&&&&&&&%+             #&&&&&&&&&&&&&#       +&& ",
-" &@       $&&&&&&&&&&&&#                +%&&&&&&&&&&&%+       $& ",
-" %.      +%&&&&&&&&&&&@                  .$&&&&&&&&&&&#       @& ",
-" $       #&&&&&&&&&&&@                    .$&&&&&&&&&&&+       & ",
-" @      .%&&&&&&&&&&#                      .%&&&&&&&&&&@       $ ",
-" .      +&&&&&&&&&&%                        +&&&&&&&&&&%.      @ ",
-"        #&&&&&&&&&&+         @%&&%$+         #&&&&&&&&&&.      . ",
-"       .%&&&&&&&&&$        +%&&&&&&&#        .&&&&&&&&&&@        ",
-"       .&&&&&&&&&&+       +&&&&&&&&&&$        $&&&&&&&&&$        ",
-"       +&&&&&&&&&&       .%&&&&&&&&&&&#       @&&&&&&&&&%        ",
-"       @&&&&&&&&&$       @&&&&&&&&&&&&&.      +&&&&&&&&&&        ",
-"       @&&&&&&&&&#       %&&&&&&&&&&&&&#      .%&&&&&&&&&.       ",
-"       #&&&&&&&&&@      .&&&&&&&&&&&&&&$      .%&&&&&&&&&.       ",
-"       #&&&&&&&&&@      .&&&&&&&&&&&&&&%      .#$%&&&&&&&+       ",
-"       #&&&&&&&&&@      .&&&&&&&&&&&&&&$           @%&&&&.       ",
-"       @&&&&&&&&&#       %&&&&&&&&&&&&&#             @%&&.       ",
-"       @&&&&&&&&&$       #&&&&&&&&&&&&&.   +@@@@+.    .$&        ",
-"       +&&&&&&&&&&       .%&&&&&&&&&&&#  +$%&&&&&%#.   .$        ",
-"       .&&&&&&&&&&+       +&&&&&&&&&&$  $&&&&&&&&&&%@   .        ",
-"       .%&&&&&&&&&$        +%&&&&&&&#. %&&&&&&&&&&&&&#           ",
-"        #&&&&&&&&&&+         @%&&&$+  $&&&&&&&&&&&&&&&@        . ",
-" .      +&&&&&&&&&&%                 @&&&&&&&&&&&&&&&&%.       @ ",
-" @      .%&&&&&&&&&&#                %&&&&&&&&&&&&&&&&&@       $ ",
-" $       #&&&&&&&&&&&@              @&&&&&&&&&&&&&&&&&&%.      & ",
-" %.      +%&&&&&&&&&&&@             $&&&&&&&&&&&&&&&&&&&.     @& ",
-" &@       $&&&&&&&&&&&&#            %&&&&&&&&&&&&&&&&&&&+     $& ",
-" &$       .%&&&&&&&&&&&&%+          %&&&&&&&&&&&&&&&&&&&@    +&& ",
-" &%+       @&&&&&&&&&&&&&&%@..     .%&&&&&&&&&&&&&&&&&&&@    #&& ",
-" &&#        $&&&&&&&&&&&&&&&&%$###$%&&&&&&&&&&&&&&&&&&&&+   +%&& ",
-" &&&+       .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.   #&&& ",
-" &&&$        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#   +&&&& ",
-" &&&&@        +%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+   $&&&& ",
-" &&&&&.        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#   @&&&&& ",
-" &&&&&%         .$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%.  +&&&&&& ",
-" &&&&&&$          @%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%.  .&&&&&&& ",
-" &&&&&&&#          .$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&%#   .%&&&&&&& ",
-" &&&&&&&&#           +#%&&&&&&&&&&&&&&&&&$@#$%%$$@+   .%&&&&&&&& ",
-" &&&&&&&&&#            .+#%&&&&&&&&&&&$@+.  ....     .%&&&&&&&&& ",
-" &&&&&&&&&&$              ..+@@###@+...             +%&&&&&&&&&& ",
-" &&&&&&&&&&&%.                                     @&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&@                                  .#&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&$+                              .@%&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&&&#+                          .@$&&&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&&&&%$@.                     .#%&&&&&&&&&&&&&&&&&& ",
-" &&&&&&&&&&&&&&&&&&&&%$@                .@$%&&&&&&&&&&&&&&&&&&&& ",
-"                                                                 "};
-
+    "65 65 8 1",
+    "  c #444643",
+    ". c #565755",
+    "+ c #6C6E6B",
+    "@ c #898B88",
+    "# c #A3A5A2",
+    "$ c #BEC0BD",
+    "% c #D7DAD6",
+    "& c #FCFEFB",
+    "                                                                 ",
+    " &&&&&&&&&&&&&&&&&&&&%$@                .@$%&&&&&&&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&&&&%$@.                     .#%&&&&&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&&&#+                          .@$&&&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&$+                              .@%&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&@                                  .#&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&%.                                     @&&&&&&&&&&&& ",
+    " &&&&&&&&&&$              ...+@@#@@+..              +%&&&&&&&&&& ",
+    " &&&&&&&&&#            .+#$&&&&&&&&&&%$@+.           .%&&&&&&&&& ",
+    " &&&&&&&&#           +#%&&&&&&&&&&&&&&&&&$@.          .%&&&&&&&& ",
+    " &&&&&&&#          .#%&&&&&&&&&&&&&&&&&&&&&%@          .%&&&&&&& ",
+    " &&&&&&$          @%&&&&&&&&&&&&&&&&&&&&&&&&&%+         .&&&&&&& ",
+    " &&&&&%          $&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@         +&&&&&& ",
+    " &&&&&.        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#         @&&&&& ",
+    " &&&&@        +%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#         $&&&& ",
+    " &&&$        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#        +&&&& ",
+    " &&&+        %&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#        #&&& ",
+    " &&#        $&&&&&&&&&&&&&&&&%$###$%&&&&&&&&&&&&&&&&@       +%&& ",
+    " &%+       @&&&&&&&&&&&&&&%@..    ..+#&&&&&&&&&&&&&&%.       #&& ",
+    " &$       .%&&&&&&&&&&&&%+             #&&&&&&&&&&&&&#       +&& ",
+    " &@       $&&&&&&&&&&&&#                +%&&&&&&&&&&&%+       $& ",
+    " %.      +%&&&&&&&&&&&@                  .$&&&&&&&&&&&#       @& ",
+    " $       #&&&&&&&&&&&@                    .$&&&&&&&&&&&+       & ",
+    " @      .%&&&&&&&&&&#                      .%&&&&&&&&&&@       $ ",
+    " .      +&&&&&&&&&&%                        +&&&&&&&&&&%.      @ ",
+    "        #&&&&&&&&&&+         @%&&%$+         #&&&&&&&&&&.      . ",
+    "       .%&&&&&&&&&$        +%&&&&&&&#        .&&&&&&&&&&@        ",
+    "       .&&&&&&&&&&+       +&&&&&&&&&&$        $&&&&&&&&&$        ",
+    "       +&&&&&&&&&&       .%&&&&&&&&&&&#       @&&&&&&&&&%        ",
+    "       @&&&&&&&&&$       @&&&&&&&&&&&&&.      +&&&&&&&&&&        ",
+    "       @&&&&&&&&&#       %&&&&&&&&&&&&&#      .%&&&&&&&&&.       ",
+    "       #&&&&&&&&&@      .&&&&&&&&&&&&&&$      .%&&&&&&&&&.       ",
+    "       #&&&&&&&&&@      .&&&&&&&&&&&&&&%      .#$%&&&&&&&+       ",
+    "       #&&&&&&&&&@      .&&&&&&&&&&&&&&$           @%&&&&.       ",
+    "       @&&&&&&&&&#       %&&&&&&&&&&&&&#             @%&&.       ",
+    "       @&&&&&&&&&$       #&&&&&&&&&&&&&.   +@@@@+.    .$&        ",
+    "       +&&&&&&&&&&       .%&&&&&&&&&&&#  +$%&&&&&%#.   .$        ",
+    "       .&&&&&&&&&&+       +&&&&&&&&&&$  $&&&&&&&&&&%@   .        ",
+    "       .%&&&&&&&&&$        +%&&&&&&&#. %&&&&&&&&&&&&&#           ",
+    "        #&&&&&&&&&&+         @%&&&$+  $&&&&&&&&&&&&&&&@        . ",
+    " .      +&&&&&&&&&&%                 @&&&&&&&&&&&&&&&&%.       @ ",
+    " @      .%&&&&&&&&&&#                %&&&&&&&&&&&&&&&&&@       $ ",
+    " $       #&&&&&&&&&&&@              @&&&&&&&&&&&&&&&&&&%.      & ",
+    " %.      +%&&&&&&&&&&&@             $&&&&&&&&&&&&&&&&&&&.     @& ",
+    " &@       $&&&&&&&&&&&&#            %&&&&&&&&&&&&&&&&&&&+     $& ",
+    " &$       .%&&&&&&&&&&&&%+          %&&&&&&&&&&&&&&&&&&&@    +&& ",
+    " &%+       @&&&&&&&&&&&&&&%@..     .%&&&&&&&&&&&&&&&&&&&@    #&& ",
+    " &&#        $&&&&&&&&&&&&&&&&%$###$%&&&&&&&&&&&&&&&&&&&&+   +%&& ",
+    " &&&+       .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.   #&&& ",
+    " &&&$        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#   +&&&& ",
+    " &&&&@        +%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&+   $&&&& ",
+    " &&&&&.        .%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#   @&&&&& ",
+    " &&&&&%         .$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%.  +&&&&&& ",
+    " &&&&&&$          @%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%.  .&&&&&&& ",
+    " &&&&&&&#          .$%&&&&&&&&&&&&&&&&&&&&&&&&&&&&%#   .%&&&&&&& ",
+    " &&&&&&&&#           +#%&&&&&&&&&&&&&&&&&$@#$%%$$@+   .%&&&&&&&& ",
+    " &&&&&&&&&#            .+#%&&&&&&&&&&&$@+.  ....     .%&&&&&&&&& ",
+    " &&&&&&&&&&$              ..+@@###@+...             +%&&&&&&&&&& ",
+    " &&&&&&&&&&&%.                                     @&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&@                                  .#&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&$+                              .@%&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&&&#+                          .@$&&&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&&&&%$@.                     .#%&&&&&&&&&&&&&&&&&& ",
+    " &&&&&&&&&&&&&&&&&&&&%$@                .@$%&&&&&&&&&&&&&&&&&&&& ",
+    "                                                                 "};
 
 const char* recOff_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #342F2E",
-"+     c #3F3B3A",
-"@     c #594F4F",
-"#     c #7A6663",
-"$     c #8C7170",
-"%     c #A68384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"         @$%%$@        ",
-"       .$&&&&&&$.      ",
-"       $&&&&&&&&$      ",
-"      @&&&#++#&&&@     ",
-"      $&&#    #&&$     ",
-"      %&&+    +&&%     ",
-"      %&&+    +&&%     ",
-"      $&&#    #&&$     ",
-"      @&&&#++#&&&@     ",
-"       $&&&&&&&&$      ",
-"       .$&&&&&&$.      ",
-"         @$%%$@        ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
+    "23 23 8 1",
+    "  c #242523",
+    ". c #342F2E",
+    "+ c #3F3B3A",
+    "@ c #594F4F",
+    "# c #7A6663",
+    "$ c #8C7170",
+    "% c #A68384",
+    "& c #B18E8F",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "         @$%%$@        ",
+    "       .$&&&&&&$.      ",
+    "       $&&&&&&&&$      ",
+    "      @&&&#++#&&&@     ",
+    "      $&&#    #&&$     ",
+    "      %&&+    +&&%     ",
+    "      %&&+    +&&%     ",
+    "      $&&#    #&&$     ",
+    "      @&&&#++#&&&@     ",
+    "       $&&&&&&&&$      ",
+    "       .$&&&&&&$.      ",
+    "         @$%%$@        ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
 
 const char* recOn_xpm[] = {
-"23 23 8 1",
-"      c #4D4F4C",
-".     c #5F4E50",
-"+     c #6E4F50",
-"@     c #8C5050",
-"#     c #AE5454",
-"$     c #BB5253",
-"%     c #C55352",
-"&     c #E85557",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"         @$&&$@        ",
-"       .%&&&&&&%.      ",
-"       %&&&&&&&&%      ",
-"      @&&&#++#&&&@     ",
-"      $&&#    #&&$     ",
-"      &&&+    +&&&     ",
-"      &&&+    +&&&     ",
-"      $&&#    #&&$     ",
-"      @&&&#++#&&&@     ",
-"       %&&&&&&&&%      ",
-"       .%&&&&&&%.      ",
-"         @$&&$@        ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
+    "23 23 8 1",
+    "  c #4D4F4C",
+    ". c #5F4E50",
+    "+ c #6E4F50",
+    "@ c #8C5050",
+    "# c #AE5454",
+    "$ c #BB5253",
+    "% c #C55352",
+    "& c #E85557",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "         @$&&$@        ",
+    "       .%&&&&&&%.      ",
+    "       %&&&&&&&&%      ",
+    "      @&&&#++#&&&@     ",
+    "      $&&#    #&&$     ",
+    "      &&&+    +&&&     ",
+    "      &&&+    +&&&     ",
+    "      $&&#    #&&$     ",
+    "      @&&&#++#&&&@     ",
+    "       %&&&&&&&&%      ",
+    "       .%&&&&&&%.      ",
+    "         @$&&$@        ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
 
 const char* inputRecOn_xpm[] = {
-"23 23 8 1",
-"      c #524D4C",
-".     c #4D4F4C",
-"+     c #5D4F50",
-"@     c #8C5050",
-"#     c #BB5253",
-"$     c #C45251",
-"%     c #DD5256",
-"&     c #EA5657",
-".......................",
-".......................",
-".......................",
-".......................",
-".......................",
-"........ @#%%#@ .......",
-".......+$&&&&&&$+......",
-"...... $&&&&&&&&$ .....",
-"......@&&&&&&&&&&@.....",
-"......#&&&&&&&&&&#.....",
-"......%&&&&&&&&&&%.....",
-"......%&&&&&&&&&&%.....",
-"......#&&&&&&&&&&#.....",
-"......@&&&&&&&&&&@.....",
-".......$&&&&&&&&$......",
-".......+$&&&&&&$+......",
-"........ @#%%#@ .......",
-".......................",
-".......................",
-".......................",
-".......................",
-".......................",
-"......................."};
+    "23 23 8 1",
+    "  c #524D4C",
+    ". c #4D4F4C",
+    "+ c #5D4F50",
+    "@ c #8C5050",
+    "# c #BB5253",
+    "$ c #C45251",
+    "% c #DD5256",
+    "& c #EA5657",
+    ".......................",
+    ".......................",
+    ".......................",
+    ".......................",
+    ".......................",
+    "........ @#%%#@ .......",
+    ".......+$&&&&&&$+......",
+    "...... $&&&&&&&&$ .....",
+    "......@&&&&&&&&&&@.....",
+    "......#&&&&&&&&&&#.....",
+    "......%&&&&&&&&&&%.....",
+    "......%&&&&&&&&&&%.....",
+    "......#&&&&&&&&&&#.....",
+    "......@&&&&&&&&&&@.....",
+    ".......$&&&&&&&&$......",
+    ".......+$&&&&&&$+......",
+    "........ @#%%#@ .......",
+    ".......................",
+    ".......................",
+    ".......................",
+    ".......................",
+    ".......................",
+    "......................."};
 
 const char* inputRecOff_xpm[] = {
-"23 23 8 1",
-"      c #242523",
-".     c #252724",
-"+     c #332F2E",
-"@     c #594E4F",
-"#     c #896E6D",
-"$     c #8D7271",
-"%     c #A68384",
-"&     c #B18E8F",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"        .@#%%#@.       ",
-"       +$&&&&&&$+      ",
-"      .$&&&&&&&&$.     ",
-"      @&&&&&&&&&&@     ",
-"      #&&&&&&&&&&#     ",
-"      %&&&&&&&&&&%     ",
-"      %&&&&&&&&&&%     ",
-"      #&&&&&&&&&&#     ",
-"      @&&&&&&&&&&@     ",
-"       $&&&&&&&&$      ",
-"       +$&&&&&&$+      ",
-"        .@#%%#@.       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       ",
-"                       "};
+    "23 23 8 1",
+    "  c #242523",
+    ". c #252724",
+    "+ c #332F2E",
+    "@ c #594E4F",
+    "# c #896E6D",
+    "$ c #8D7271",
+    "% c #A68384",
+    "& c #B18E8F",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "        .@#%%#@.       ",
+    "       +$&&&&&&$+      ",
+    "      .$&&&&&&&&$.     ",
+    "      @&&&&&&&&&&@     ",
+    "      #&&&&&&&&&&#     ",
+    "      %&&&&&&&&&&%     ",
+    "      %&&&&&&&&&&%     ",
+    "      #&&&&&&&&&&#     ",
+    "      @&&&&&&&&&&@     ",
+    "       $&&&&&&&&$      ",
+    "       +$&&&&&&$+      ",
+    "        .@#%%#@.       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       ",
+    "                       "};
+
+const char* freeInputRecOff_xpm[] = {
+    "13 23 9 1",
+    "  c None",
+    ". c #232523",
+    "+ c #353130",
+    "@ c #483E3F",
+    "# c #4D4F4C",
+    "$ c #574D4D",
+    "% c #705D5C",
+    "& c #8C7271",
+    "* c #AF8D8E",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".....+%%.....",
+    ".....@*&.....",
+    ".....@*&.....",
+    ".....@*&.....",
+    "....$@$@.....",
+    "...+**&@.....",
+    "....+%**&@...",
+    "......+%*$...",
+    ".....@&%+....",
+    ".....@*&.....",
+    ".....@*&.....",
+    ".....@*&.....",
+    ".....+@@.....",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    "............."};
+
+const char* freeInputRecOn_xpm[] = {
+    "13 23 9 1",
+    "  c None",
+    ". c #4D4F4C",
+    "+ c #575352",
+    "@ c #5D5857",
+    "# c #6A5F5F",
+    "$ c #796A6B",
+    "% c #877472",
+    "& c #977C7C",
+    "* c #B08E8F",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".....@%$.....",
+    ".....#*&.....",
+    ".....#*&.....",
+    ".....#*&.....",
+    "....##$#.....",
+    "...+**&@.....",
+    "....@%**&@...",
+    "......@%*$...",
+    ".....@&%@....",
+    ".....#*&.....",
+    ".....#*&.....",
+    ".....#*&.....",
+    ".....+##.....",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    "............."};
 
 const char* muteOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #2E2F2D",
-"+     c #3B3C3A",
-"@     c #525451",
-"#     c #6F716E",
-"$     c #878986",
-"%     c #ADAFAC",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ++.  .++     ",
-"    +&&$  $&&+    ",
-"    +&&%  %&&+    ",
-"    +&%&++&%&+    ",
-"    +&$&##&$&+    ",
-"    +&#%$$%#&+    ",
-"    +&#$%%$#&+    ",
-"    +&#@&&@#&+    ",
-"    +&#+&&+#&+    ",
-"    .#@ ## @#.    ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
+    "18 18 8 1",
+    "  c #242523",
+    ". c #2E2F2D",
+    "+ c #3B3C3A",
+    "@ c #525451",
+    "# c #6F716E",
+    "$ c #878986",
+    "% c #ADAFAC",
+    "& c #C6C8C5",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     ++.  .++     ",
+    "    +&&$  $&&+    ",
+    "    +&&%  %&&+    ",
+    "    +&%&++&%&+    ",
+    "    +&$&##&$&+    ",
+    "    +&#%$$%#&+    ",
+    "    +&#$%%$#&+    ",
+    "    +&#@&&@#&+    ",
+    "    +&#+&&+#&+    ",
+    "    .#@ ## @#.    ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* muteOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #585A57",
-"+     c #616260",
-"@     c #7A7C79",
-"#     c #888A87",
-"$     c #989A97",
-"%     c #B2B4B1",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ..    ..     ",
-"    +&&$  $&&+    ",
-"    +&&%  %&&+    ",
-"    +&%&++&%&+    ",
-"    +&$&@@&$&+    ",
-"    +&#%$$%#&+    ",
-"    +&#$&&$#&+    ",
-"    +&#@&&@#&+    ",
-"    +&#.&&.#&+    ",
-"    .#+ ## +#.    ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #585A57",
+    "+ c #616260",
+    "@ c #7A7C79",
+    "# c #888A87",
+    "$ c #989A97",
+    "% c #B2B4B1",
+    "& c #C6C8C5",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     ..    ..     ",
+    "    +&&$  $&&+    ",
+    "    +&&%  %&&+    ",
+    "    +&%&++&%&+    ",
+    "    +&$&@@&$&+    ",
+    "    +&#%$$%#&+    ",
+    "    +&#$&&$#&+    ",
+    "    +&#@&&@#&+    ",
+    "    +&#.&&.#&+    ",
+    "    .#+ ## +#.    ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* readActionOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #393B38",
-"+     c #555754",
-"@     c #6B6D6A",
-"#     c #7F807E",
-"$     c #9C9E9B",
-"%     c #B1B3B0",
-"&     c #C3C5C2",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ....         ",
-"     %&&&&%+      ",
-"     %&@@@&&      ",
-"     %%   $&.     ",
-"     %&@@#&$      ",
-"     %&&&&@       ",
-"     %% +&$       ",
-"     %%  #&#      ",
-"     %%   %&+     ",
-"     @@   .#+     ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #393B38",
+    "+ c #555754",
+    "@ c #6B6D6A",
+    "# c #7F807E",
+    "$ c #9C9E9B",
+    "% c #B1B3B0",
+    "& c #C3C5C2",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     ....         ",
+    "     %&&&&%+      ",
+    "     %&@@@&&      ",
+    "     %%   $&.     ",
+    "     %&@@#&$      ",
+    "     %&&&&@       ",
+    "     %% +&$       ",
+    "     %%  #&#      ",
+    "     %%   %&+     ",
+    "     @@   .#+     ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* readActionOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #696B68",
-"+     c #7A7C79",
-"@     c #888A87",
-"#     c #939592",
-"$     c #A7A9A6",
-"%     c #B7B9B6",
-"&     c #C4C6C3",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     %&&&&%.      ",
-"     %&++@&&      ",
-"     %%   $&      ",
-"     %&@@#&$      ",
-"     %&&&&@       ",
-"     %% +&$       ",
-"     %%  #&#      ",
-"     %%   %&.     ",
-"     +@   .@+     ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #696B68",
+    "+ c #7A7C79",
+    "@ c #888A87",
+    "# c #939592",
+    "$ c #A7A9A6",
+    "% c #B7B9B6",
+    "& c #C4C6C3",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     %&&&&%.      ",
+    "     %&++@&&      ",
+    "     %%   $&      ",
+    "     %&@@#&$      ",
+    "     %&&&&@       ",
+    "     %% +&$       ",
+    "     %%  #&#      ",
+    "     %%   %&.     ",
+    "     +@   .@+     ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* readActionDisabled_xpm[] = {
-"18 18 7 1",
-"      c None",
-".     c #252525",
-"+     c #313131",
-"@     c #393939",
-"#     c #424242",
-"$     c #4A4A4A",
-"%     c #585858",
-"..................",
-"..................",
-"..................",
-"..................",
-".....@@@@+........",
-".....%%%%%%+......",
-".....%%#+$%$......",
-".....%%@.#%$......",
-".....%%##%%@......",
-".....%%%%%$.......",
-".....%%@+%%#......",
-".....%%@.@%%......",
-".....%%@..%%#.....",
-".....@@...+@@.....",
-"..................",
-"..................",
-"..................",
-".................."};
-
+    "18 18 7 1",
+    "  c None",
+    ". c #252525",
+    "+ c #313131",
+    "@ c #393939",
+    "# c #424242",
+    "$ c #4A4A4A",
+    "% c #585858",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".....@@@@+........",
+    ".....%%%%%%+......",
+    ".....%%#+$%$......",
+    ".....%%@.#%$......",
+    ".....%%##%%@......",
+    ".....%%%%%$.......",
+    ".....%%@+%%#......",
+    ".....%%@.@%%......",
+    ".....%%@..%%#.....",
+    ".....@@...+@@.....",
+    "..................",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* metronomeOff_xpm[] = {
-"13 23 3 1",
-"      c None",
-".     c #252525",
-"+     c #B18E8E",
-".............",
-".............",
-".............",
-".............",
-".............",
-".............",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-".............",
-".............",
-".............",
-".............",
-".............",
-".............",
-"............."};
-
+    "13 23 3 1",
+    "  c None",
+    ". c #252525",
+    "+ c #B18E8E",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    "............."};
 
 const char* metronomeOn_xpm[] = {
-"13 23 3 1",
-"      c None",
-".     c #4E4E4E",
-"+     c #B18E8E",
-".............",
-".............",
-".............",
-".............",
-".............",
-".............",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-"....+...+....",
-".............",
-".............",
-".............",
-".............",
-".............",
-".............",
-"............."};
-
+    "13 23 3 1",
+    "  c None",
+    ". c #4E4E4E",
+    "+ c #B18E8E",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    "....+...+....",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    ".............",
+    "............."};
 
 const char* recTriggerModeOff_xpm[] = {
-"13 23 8 1",
-"      c #232523",
-".     c #2A2625",
-"+     c #43393A",
-"@     c #514647",
-"#     c #6F5C59",
-"$     c #8B7170",
-"%     c #AA8889",
-"&     c #B08E8F",
-"             ",
-"             ",
-"             ",
-"             ",
-"             ",
-"     @$@     ",
-"     %&%     ",
-"     $&$     ",
-"     .+.     ",
-"             ",
-"     #%#     ",
-"     %&%     ",
-"     #%#     ",
-"             ",
-"     .+.     ",
-"     $&$     ",
-"     %&%     ",
-"     @$@     ",
-"             ",
-"             ",
-"             ",
-"             ",
-"             "};
-
+    "13 23 8 1",
+    "  c #232523",
+    ". c #2A2625",
+    "+ c #43393A",
+    "@ c #514647",
+    "# c #6F5C59",
+    "$ c #8B7170",
+    "% c #AA8889",
+    "& c #B08E8F",
+    "             ",
+    "             ",
+    "             ",
+    "             ",
+    "             ",
+    "     @$@     ",
+    "     %&%     ",
+    "     $&$     ",
+    "     .+.     ",
+    "             ",
+    "     #%#     ",
+    "     %&%     ",
+    "     #%#     ",
+    "             ",
+    "     .+.     ",
+    "     $&$     ",
+    "     %&%     ",
+    "     @$@     ",
+    "             ",
+    "             ",
+    "             ",
+    "             ",
+    "             "};
 
 const char* recTriggerModeOn_xpm[] = {
-"13 23 8 1",
-"      c #4D4F4C",
-".     c #534E4D",
-"+     c #605B5A",
-"@     c #6D6363",
-"#     c #817072",
-"$     c #967C7B",
-"%     c #AC8A8B",
-"&     c #B08E8F",
-"             ",
-"             ",
-"             ",
-"             ",
-"             ",
-"     @$@     ",
-"     %&%     ",
-"     $&$     ",
-"     .+.     ",
-"             ",
-"     #%#     ",
-"     %&%     ",
-"     #%#     ",
-"             ",
-"     .+.     ",
-"     $&$     ",
-"     %&%     ",
-"     @$@     ",
-"             ",
-"             ",
-"             ",
-"             ",
-"             "};    
-
+    "13 23 8 1",
+    "  c #4D4F4C",
+    ". c #534E4D",
+    "+ c #605B5A",
+    "@ c #6D6363",
+    "# c #817072",
+    "$ c #967C7B",
+    "% c #AC8A8B",
+    "& c #B08E8F",
+    "             ",
+    "             ",
+    "             ",
+    "             ",
+    "             ",
+    "     @$@     ",
+    "     %&%     ",
+    "     $&$     ",
+    "     .+.     ",
+    "             ",
+    "     #%#     ",
+    "     %&%     ",
+    "     #%#     ",
+    "             ",
+    "     .+.     ",
+    "     $&$     ",
+    "     %&%     ",
+    "     @$@     ",
+    "             ",
+    "             ",
+    "             ",
+    "             ",
+    "             "};
 
 const char* zoomInOff_xpm[] = {
-"18 18 8 1",
-"      c None",
-".     c #252525",
-"+     c #262626",
-"@     c #535353",
-"#     c #ACACAC",
-"$     c #AEAEAE",
-"%     c #B1B1B1",
-"&     c #C4C4C4",
-"++++++++++++++++++",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+.......@@.......+",
-"+.......#$.......+",
-"+.......#$.......+",
-"+....@%%&&%%@....+",
-"+....@%%&&%%@....+",
-"+.......#$.......+",
-"+.......#$.......+",
-"+.......@@.......+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"++++++++++++++++++"};
-
+    "18 18 8 1",
+    "  c None",
+    ". c #252525",
+    "+ c #262626",
+    "@ c #535353",
+    "# c #ACACAC",
+    "$ c #AEAEAE",
+    "% c #B1B1B1",
+    "& c #C4C4C4",
+    "++++++++++++++++++",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+.......@@.......+",
+    "+.......#$.......+",
+    "+.......#$.......+",
+    "+....@%%&&%%@....+",
+    "+....@%%&&%%@....+",
+    "+.......#$.......+",
+    "+.......#$.......+",
+    "+.......@@.......+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "++++++++++++++++++"};
 
 const char* zoomInOn_xpm[] = {
-"18 18 8 1",
-"      c None",
-".     c #4E4E4E",
-"+     c #707070",
-"@     c #717171",
-"#     c #B3B3B3",
-"$     c #B5B5B5",
-"%     c #B7B7B7",
-"&     c #C5C5C5",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"........++........",
-"........#$........",
-"........#$........",
-".....@%%&&%%@.....",
-".....@%%&&%%@.....",
-"........#$........",
-"........#$........",
-"........++........",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-
+    "18 18 8 1",
+    "  c None",
+    ". c #4E4E4E",
+    "+ c #707070",
+    "@ c #717171",
+    "# c #B3B3B3",
+    "$ c #B5B5B5",
+    "% c #B7B7B7",
+    "& c #C5C5C5",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "........++........",
+    "........#$........",
+    "........#$........",
+    ".....@%%&&%%@.....",
+    ".....@%%&&%%@.....",
+    "........#$........",
+    "........#$........",
+    "........++........",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* zoomOutOff_xpm[] = {
-"18 18 5 1",
-"      c None",
-".     c #252525",
-"+     c #262626",
-"@     c #9C9C9C",
-"#     c #BBBBBB",
-"++++++++++++++++++",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+......@##@......+",
-"+......@##@......+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"+................+",
-"++++++++++++++++++"};
-
+    "18 18 5 1",
+    "  c None",
+    ". c #252525",
+    "+ c #262626",
+    "@ c #9C9C9C",
+    "# c #BBBBBB",
+    "++++++++++++++++++",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+......@##@......+",
+    "+......@##@......+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "+................+",
+    "++++++++++++++++++"};
 
 const char* zoomOutOn_xpm[] = {
-"18 18 4 1",
-"      c None",
-".     c #4E4E4E",
-"+     c #A7A7A7",
-"@     c #BEBEBE",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-".......+@@+.......",
-".......+@@+.......",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-
-
+    "18 18 4 1",
+    "  c None",
+    ". c #4E4E4E",
+    "+ c #A7A7A7",
+    "@ c #BEBEBE",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".......+@@+.......",
+    ".......+@@+.......",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* scrollRightOff_xpm[] = {
-"12 12 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #2E2F2D",
-"@     c #4D4F4C",
-"#     c #5D5F5C",
-"$     c #828481",
-"%     c #9B9D9A",
-"&     c #BCBEBB",
-"............",
-"............",
-"...+........",
-"...&$@......",
-"...$&&%@....",
-"....+#%&%...",
-"....+#%&%...",
-"...$&&%#....",
-"...&$@......",
-"...+........",
-"............",
-"............"};
-
+    "12 12 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #2E2F2D",
+    "@ c #4D4F4C",
+    "# c #5D5F5C",
+    "$ c #828481",
+    "% c #9B9D9A",
+    "& c #BCBEBB",
+    "............",
+    "............",
+    "...+........",
+    "...&$@......",
+    "...$&&%@....",
+    "....+#%&%...",
+    "....+#%&%...",
+    "...$&&%#....",
+    "...&$@......",
+    "...+........",
+    "............",
+    "............"};
 
 const char* scrollLeftOff_xpm[] = {
-"12 12 8 1",
-"      c #181917",
-".     c #242523",
-"+     c #2E2F2D",
-"@     c #4D4F4C",
-"#     c #5D5F5C",
-"$     c #828481",
-"%     c #9B9D9A",
-"&     c #BCBEBB",
-"............",
-"............",
-"........+...",
-"......@$&...",
-"....@%&&$...",
-"...%&%#+....",
-"...%&%#+....",
-"....#%&&$...",
-"......@$&...",
-"........+...",
-"............",
-"............"};
-
+    "12 12 8 1",
+    "  c #181917",
+    ". c #242523",
+    "+ c #2E2F2D",
+    "@ c #4D4F4C",
+    "# c #5D5F5C",
+    "$ c #828481",
+    "% c #9B9D9A",
+    "& c #BCBEBB",
+    "............",
+    "............",
+    "........+...",
+    "......@$&...",
+    "....@%&&$...",
+    "...%&%#+....",
+    "...%&%#+....",
+    "....#%&&$...",
+    "......@$&...",
+    "........+...",
+    "............",
+    "............"};
 
 const char* scrollLeftOn_xpm[] = {
-"12 12 8 1",
-"      c #4D4F4C",
-".     c #6B6D6A",
-"+     c #7B7D7A",
-"@     c #969895",
-"#     c #A6A8A5",
-"$     c #B4B6B3",
-"%     c #C0C2BF",
-"&     c #FEFFFC",
-"            ",
-"            ",
-"            ",
-"      .@$   ",
-"    +#%%@   ",
-"   $%#+     ",
-"   %%#+     ",
-"    +$%%@   ",
-"      .#$   ",
-"            ",
-"            ",
-"            "};
-
+    "12 12 8 1",
+    "  c #4D4F4C",
+    ". c #6B6D6A",
+    "+ c #7B7D7A",
+    "@ c #969895",
+    "# c #A6A8A5",
+    "$ c #B4B6B3",
+    "% c #C0C2BF",
+    "& c #FEFFFC",
+    "            ",
+    "            ",
+    "            ",
+    "      .@$   ",
+    "    +#%%@   ",
+    "   $%#+     ",
+    "   %%#+     ",
+    "    +$%%@   ",
+    "      .#$   ",
+    "            ",
+    "            ",
+    "            "};
 
 const char* scrollRightOn_xpm[] = {
-"12 12 8 1",
-"      c #4D4F4C",
-".     c #6B6D6A",
-"+     c #7B7D7A",
-"@     c #969895",
-"#     c #A6A8A5",
-"$     c #B4B6B3",
-"%     c #C0C2BF",
-"&     c #FEFFFC",
-"            ",
-"            ",
-"            ",
-"   %@.      ",
-"   @%%#.    ",
-"     +#%#   ",
-"     +#%#   ",
-"   @%%#+    ",
-"   %@.      ",
-"            ",
-"            ",
-"            "};
-
+    "12 12 8 1",
+    "  c #4D4F4C",
+    ". c #6B6D6A",
+    "+ c #7B7D7A",
+    "@ c #969895",
+    "# c #A6A8A5",
+    "$ c #B4B6B3",
+    "% c #C0C2BF",
+    "& c #FEFFFC",
+    "            ",
+    "            ",
+    "            ",
+    "   %@.      ",
+    "   @%%#.    ",
+    "     +#%#   ",
+    "     +#%#   ",
+    "   @%%#+    ",
+    "   %@.      ",
+    "            ",
+    "            ",
+    "            "};
 
 const char* soloOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #616360",
-"+     c #737572",
-"@     c #838582",
-"#     c #929491",
-"$     c #A5A7A4",
-"%     c #B1B3B0",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .@+.       ",
-"      #&&&&#      ",
-"     .&$  %&.     ",
-"      &%+ ..      ",
-"      #&&&$.      ",
-"       .@$&&.     ",
-"     .#.  @&@     ",
-"     .&$. #&+     ",
-"      #&&&&$      ",
-"       .+@+       ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #616360",
+    "+ c #737572",
+    "@ c #838582",
+    "# c #929491",
+    "$ c #A5A7A4",
+    "% c #B1B3B0",
+    "& c #C6C8C5",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "       .@+.       ",
+    "      #&&&&#      ",
+    "     .&$  %&.     ",
+    "      &%+ ..      ",
+    "      #&&&$.      ",
+    "       .@$&&.     ",
+    "     .#.  @&@     ",
+    "     .&$. #&+     ",
+    "      #&&&&$      ",
+    "       .+@+       ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* soloOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #3D3F3D",
-"+     c #525451",
-"@     c #666865",
-"#     c #80827F",
-"$     c #979996",
-"%     c #A7A9A6",
-"&     c #C6C8C5",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .@@.       ",
-"      #&&&&#      ",
-"     .&$  %&.     ",
-"      &%+ ..      ",
-"      #&&&$+      ",
-"       .@%&&.     ",
-"     +#.  @&@     ",
-"     .&$..#&+     ",
-"      #&&&&$      ",
-"       .@@+       ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #3D3F3D",
+    "+ c #525451",
+    "@ c #666865",
+    "# c #80827F",
+    "$ c #979996",
+    "% c #A7A9A6",
+    "& c #C6C8C5",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "       .@@.       ",
+    "      #&&&&#      ",
+    "     .&$  %&.     ",
+    "      &%+ ..      ",
+    "      #&&&$+      ",
+    "       .@%&&.     ",
+    "     +#.  @&@     ",
+    "     .&$..#&+     ",
+    "      #&&&&$      ",
+    "       .@@+       ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 #ifdef WITH_VST
 
-
 const char* fxOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #40423F",
-"+     c #4D4E4C",
-"@     c #686A67",
-"#     c #7B7D7A",
-"$     c #919390",
-"%     c #AEB0AD",
-"&     c #C1C3C0",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"   ..... .   .    ",
-"   $&&&$ $% @&.   ",
-"   $$    .&#&@    ",
-"   $%##.  @&$     ",
-"   $%##.  #&%     ",
-"   $$    .&@&#    ",
-"   $$    %$ @&.   ",
-"   ..    +   +.   ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #40423F",
+    "+ c #4D4E4C",
+    "@ c #686A67",
+    "# c #7B7D7A",
+    "$ c #919390",
+    "% c #AEB0AD",
+    "& c #C1C3C0",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "   ..... .   .    ",
+    "   $&&&$ $% @&.   ",
+    "   $$    .&#&@    ",
+    "   $%##.  @&$     ",
+    "   $%##.  #&%     ",
+    "   $$    .&@&#    ",
+    "   $$    %$ @&.   ",
+    "   ..    +   +.   ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* fxOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #565855",
-"+     c #636562",
-"@     c #80827F",
-"#     c #8E908D",
-"$     c #9FA19E",
-"%     c #B1B3B0",
-"&     c #C1C3C0",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"   .++++ +.  +.   ",
-"   $&&&$ $% @&.   ",
-"   $$    .&#&@    ",
-"   $%##+  @&$     ",
-"   $%##+  #&%     ",
-"   $$    +&@&#    ",
-"   $$    %$ @&+   ",
-"   ++   .+.  ++   ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #565855",
+    "+ c #636562",
+    "@ c #80827F",
+    "# c #8E908D",
+    "$ c #9FA19E",
+    "% c #B1B3B0",
+    "& c #C1C3C0",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "   .++++ +.  +.   ",
+    "   $&&&$ $% @&.   ",
+    "   $$    .&#&@    ",
+    "   $%##+  @&$     ",
+    "   $%##+  #&%     ",
+    "   $$    +&@&#    ",
+    "   $$    %$ @&+   ",
+    "   ++   .+.  ++   ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* fxShiftUpOff_xpm[] = {
-"18 18 7 1",
-"      c #242523",
-".     c #4D4F4C",
-"+     c #A3A5A2",
-"@     c #868885",
-"#     c #C1C3C0",
-"$     c #313330",
-"%     c #626361",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .+@        ",
-"       @+#.       ",
-"      $#%+@       ",
-"      %# %#$      ",
-"      +@ $#%      ",
-"     $#.  @+      ",
-"     $.   $.      ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 7 1",
+    "  c #242523",
+    ". c #4D4F4C",
+    "+ c #A3A5A2",
+    "@ c #868885",
+    "# c #C1C3C0",
+    "$ c #313330",
+    "% c #626361",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "       .+@        ",
+    "       @+#.       ",
+    "      $#%+@       ",
+    "      %# %#$      ",
+    "      +@ $#%      ",
+    "     $#.  @+      ",
+    "     $.   $.      ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* fxShiftUpOn_xpm[] = {
-"18 18 5 1",
-"      c #4D4F4C",
-".     c #70726F",
-"+     c #A5A7A4",
-"@     c #C1C3BF",
-"#     c #8E908D",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"       .++        ",
-"       +@@.       ",
-"       @.+#       ",
-"      .@ .@       ",
-"      +#  @.      ",
-"     .@.  #+      ",
-"      .    .      ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 5 1",
+    "  c #4D4F4C",
+    ". c #70726F",
+    "+ c #A5A7A4",
+    "@ c #C1C3BF",
+    "# c #8E908D",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "       .++        ",
+    "       +@@.       ",
+    "       @.+#       ",
+    "      .@ .@       ",
+    "      +#  @.      ",
+    "     .@.  #+      ",
+    "      .    .      ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* fxShiftDownOff_xpm[] = {
-"18 18 7 1",
-"      c #242523",
-".     c #4D4F4C",
-"+     c #A3A5A2",
-"@     c #313330",
-"#     c #626361",
-"$     c #868885",
-"%     c #C1C3C0",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     .+@  #$      ",
-"     @%#  +$      ",
-"      $+ .%@      ",
-"      .%@$+       ",
-"       +$%#       ",
-"       #%%@       ",
-"       @..        ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 7 1",
+    "  c #242523",
+    ". c #4D4F4C",
+    "+ c #A3A5A2",
+    "@ c #313330",
+    "# c #626361",
+    "$ c #868885",
+    "% c #C1C3C0",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     .+@  #$      ",
+    "     @%#  +$      ",
+    "      $+ .%@      ",
+    "      .%@$+       ",
+    "       +$%#       ",
+    "       #%%@       ",
+    "       @..        ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* fxShiftDownOn_xpm[] = {
-"18 18 5 1",
-"      c #4D4F4C",
-".     c #70726F",
-"+     c #A5A7A4",
-"@     c #C1C3BF",
-"#     c #8E908D",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     .+   .+      ",
-"      @.  +#      ",
-"      #+ .@.      ",
-"      .@.#+       ",
-"       +#@.       ",
-"       #@@        ",
-"        ..        ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 5 1",
+    "  c #4D4F4C",
+    ". c #70726F",
+    "+ c #A5A7A4",
+    "@ c #C1C3BF",
+    "# c #8E908D",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     .+   .+      ",
+    "      @.  +#      ",
+    "      #+ .@.      ",
+    "      .@.#+       ",
+    "       +#@.       ",
+    "       #@@        ",
+    "        ..        ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* vstLogo_xpm[] = {
-"65 38 8 1",
-"      c #161715",
-".     c #2B2D2A",
-"+     c #474846",
-"@     c #6A6C69",
-"#     c #8C8E8B",
-"$     c #A8AAA7",
-"%     c #C7C9C6",
-"&     c #EEF0ED",
-" @#############################################################+ ",
-"@#.............................................................$+",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                             ......      ..                  .#",
-"#.                         .@$$$####$%$#@.+&$                  .#",
-"#.                       .#$$#+.     +#$%%%%$                  .#",
-"#.                      .$$#$          .#$$%$                  .#",
-"#. .............    ....$$$$$          ++$$%$+@@@@@@@@@@@@@@@  .#",
-"#. ##$$$$$$%%%%@    %%&&&&%%$@         %&@#$$@@$%%&&&%%%&&&&&  .#",
-"#.   +$$$$$%@         .&%####%$@       $&$.$#  #$%%%&    @&%&  .#",
-"#.    +$$$$$%         +&$###$%%&&$@.   $&.     #$%%%&.    .%&  .#",
-"#.     @$$$$%$        %##$##$%&&&&&&%#.%#      #$$%%&.     @&  .#",
-"#.      $$$$$%+      #&  #$$%%&&&&&&&%%$$@     #$$%%&.      +  .#",
-"#.      .$$$$$%     +&+   .#%&&&&&&&&%$$#$$#   #$$%%&.         .#",
-"#.       @$$$$%$    %$       @%&&&&&&%$$###$$  #$$%%&.         .#",
-"#.        #$$$%%@  #&  .        +$&&&%$####$%$ #$$%%&.         .#",
-"#.         $$$%%% .&@ +%#          .@$$$###$$% #$$$%&.         .#",
-"#.         +%$%%%$$%  +$$+             #$#$$$% @$$$%&.         .#",
-"#.          #%%%%%&.  +%$$              ##$$%$ @$$$%%.         .#",
-"#.           $$%%%@   +%$$$.            #$$$%. @$$$$%.         .#",
-"#.           +%%%$    +%$$#$@          +$$%$   @#$$$%+         .#",
-"#.            @%%.    +%%%$$$$#@++.++@#$$$@ @@##$$$%%%$$@      .#",
-"#.             #@     +&#  .@@###$$$###@.   @+++@@@@###$@      .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                                                             .#",
-"#.                   .@$$$$$$$$  .$%%%%%%#                     .#",
-"#.                  .......      .@@@@@@@@@.                   .#",
-"#.                 ........   @@@+@@@@@@@@@@+                  .#",
-"@#                .........  .####@@@@@@@@@@@+                 #@",
-" @$$$$$$$$$$$$$$$..........  .@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$@ ",
-"                  .........  .@@@@@@@@@@@@@@@.                   ",
-"                   ........       @@@@@@@@@@.                    ",
-"                    ...........  .@@@@@@@@@                      ",
-"                     ..........  .@@@@@@@@                       "};
-
+    "65 38 8 1",
+    "  c #161715",
+    ". c #2B2D2A",
+    "+ c #474846",
+    "@ c #6A6C69",
+    "# c #8C8E8B",
+    "$ c #A8AAA7",
+    "% c #C7C9C6",
+    "& c #EEF0ED",
+    " @#############################################################+ ",
+    "@#.............................................................$+",
+    "#.                                                             .#",
+    "#.                                                             .#",
+    "#.                             ......      ..                  .#",
+    "#.                         .@$$$####$%$#@.+&$                  .#",
+    "#.                       .#$$#+.     +#$%%%%$                  .#",
+    "#.                      .$$#$          .#$$%$                  .#",
+    "#. .............    ....$$$$$          ++$$%$+@@@@@@@@@@@@@@@  .#",
+    "#. ##$$$$$$%%%%@    %%&&&&%%$@         %&@#$$@@$%%&&&%%%&&&&&  .#",
+    "#.   +$$$$$%@         .&%####%$@       $&$.$#  #$%%%&    @&%&  .#",
+    "#.    +$$$$$%         +&$###$%%&&$@.   $&.     #$%%%&.    .%&  .#",
+    "#.     @$$$$%$        %##$##$%&&&&&&%#.%#      #$$%%&.     @&  .#",
+    "#.      $$$$$%+      #&  #$$%%&&&&&&&%%$$@     #$$%%&.      +  .#",
+    "#.      .$$$$$%     +&+   .#%&&&&&&&&%$$#$$#   #$$%%&.         .#",
+    "#.       @$$$$%$    %$       @%&&&&&&%$$###$$  #$$%%&.         .#",
+    "#.        #$$$%%@  #&  .        +$&&&%$####$%$ #$$%%&.         .#",
+    "#.         $$$%%% .&@ +%#          .@$$$###$$% #$$$%&.         .#",
+    "#.         +%$%%%$$%  +$$+             #$#$$$% @$$$%&.         .#",
+    "#.          #%%%%%&.  +%$$              ##$$%$ @$$$%%.         .#",
+    "#.           $$%%%@   +%$$$.            #$$$%. @$$$$%.         .#",
+    "#.           +%%%$    +%$$#$@          +$$%$   @#$$$%+         .#",
+    "#.            @%%.    +%%%$$$$#@++.++@#$$$@ @@##$$$%%%$$@      .#",
+    "#.             #@     +&#  .@@###$$$###@.   @+++@@@@###$@      .#",
+    "#.                                                             .#",
+    "#.                                                             .#",
+    "#.                                                             .#",
+    "#.                                                             .#",
+    "#.                                                             .#",
+    "#.                   .@$$$$$$$$  .$%%%%%%#                     .#",
+    "#.                  .......      .@@@@@@@@@.                   .#",
+    "#.                 ........   @@@+@@@@@@@@@@+                  .#",
+    "@#                .........  .####@@@@@@@@@@@+                 #@",
+    " @$$$$$$$$$$$$$$$..........  .@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$@ ",
+    "                  .........  .@@@@@@@@@@@@@@@.                   ",
+    "                   ........       @@@@@@@@@@.                    ",
+    "                    ...........  .@@@@@@@@@                      ",
+    "                     ..........  .@@@@@@@@                       "};
 
 const char* fxRemoveOff_xpm[] = {
-"18 18 9 1",
-"      c None",
-".     c #242623",
-"+     c #2F312E",
-"@     c #393A38",
-"#     c #484A47",
-"$     c #5D5F5C",
-"%     c #8E908D",
-"&     c #9B9D9A",
-"*     c #BDBFBC",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-".....+#@..@#+.....",
-"......&*++*&......",
-"......@*%%*@......",
-".......$**$.......",
-".......#**#.......",
-"......+*&&*+......",
-"......%*@@*%......",
-"......@@..@@......",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
-
+    "18 18 9 1",
+    "  c None",
+    ". c #242623",
+    "+ c #2F312E",
+    "@ c #393A38",
+    "# c #484A47",
+    "$ c #5D5F5C",
+    "% c #8E908D",
+    "& c #9B9D9A",
+    "* c #BDBFBC",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".....+#@..@#+.....",
+    "......&*++*&......",
+    "......@*%%*@......",
+    ".......$**$.......",
+    ".......#**#.......",
+    "......+*&&*+......",
+    "......%*@@*%......",
+    "......@@..@@......",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".................."};
 
 const char* fxRemoveOn_xpm[] = {
-"18 18 9 1",
-"      c None",
-".     c #4D4F4C",
-"+     c #575956",
-"@     c #5C5D5B",
-"#     c #666865",
-"$     c #787977",
-"%     c #9C9E9B",
-"&     c #A6A8A5",
-"*     c #BFC1BE",
-"..................",
-"..................",
-"..................",
-"..................",
-"..................",
-"......#@..@#......",
-"......&*++*&......",
-"......@*%%*@......",
-".......$**$.......",
-".......#**#.......",
-"......+*&&*+......",
-"......%*@+*%......",
-"......@+..+@......",
-"..................",
-"..................",
-"..................",
-"..................",
-".................."};
+    "18 18 9 1",
+    "  c None",
+    ". c #4D4F4C",
+    "+ c #575956",
+    "@ c #5C5D5B",
+    "# c #666865",
+    "$ c #787977",
+    "% c #9C9E9B",
+    "& c #A6A8A5",
+    "* c #BFC1BE",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "......#@..@#......",
+    "......&*++*&......",
+    "......@*%%*@......",
+    ".......$**$.......",
+    ".......#**#.......",
+    "......+*&&*+......",
+    "......%*@+*%......",
+    "......@+..+@......",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    ".................."};
 #endif // #ifdef WITH_VST
 
-
 const char* divideOn_xpm[] = {
-"18 18 7 1",
-"      c #5A5A5A",
-".     c #696969",
-"+     c #757575",
-"@     c #8B8B8B",
-"#     c #AAAAAA",
-"$     c #BBBBBB",
-"%     c #BDBDBD",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        @@        ",
-"        %$        ",
-"        ++        ",
-"    .########.    ",
-"    .########.    ",
-"        ++        ",
-"        %$        ",
-"        @@        ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 7 1",
+    "  c #5A5A5A",
+    ". c #696969",
+    "+ c #757575",
+    "@ c #8B8B8B",
+    "# c #AAAAAA",
+    "$ c #BBBBBB",
+    "% c #BDBDBD",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "        @@        ",
+    "        %$        ",
+    "        ++        ",
+    "    .########.    ",
+    "    .########.    ",
+    "        ++        ",
+    "        %$        ",
+    "        @@        ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* divideOff_xpm[] = {
-"18 18 8 1",
-"      c #252525",
-".     c #3B3B3B",
-"+     c #4D4D4D",
-"@     c #6D6D6D",
-"#     c #6E6E6E",
-"$     c #9C9C9C",
-"%     c #B5B5B5",
-"&     c #B7B7B7",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"        @#        ",
-"        &%        ",
-"        ++        ",
-"    .$$$$$$$$.    ",
-"    .$$$$$$$$.    ",
-"        ++        ",
-"        &%        ",
-"        @#        ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #252525",
+    ". c #3B3B3B",
+    "+ c #4D4D4D",
+    "@ c #6D6D6D",
+    "# c #6E6E6E",
+    "$ c #9C9C9C",
+    "% c #B5B5B5",
+    "& c #B7B7B7",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "        @#        ",
+    "        &%        ",
+    "        ++        ",
+    "    .$$$$$$$$.    ",
+    "    .$$$$$$$$.    ",
+    "        ++        ",
+    "        &%        ",
+    "        @#        ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* multiplyOn_xpm[] = {
-"18 18 8 1",
-"      c #595B58",
-".     c #737572",
-"+     c #747673",
-"@     c #8B8D8A",
-"#     c #8D8F8C",
-"$     c #8E908D",
-"%     c #8F918E",
-"&     c #C7C9C6",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"      +    .      ",
-"     +&$  #&.     ",
-"      #&$#&#      ",
-"       @&&#       ",
-"       @&&%       ",
-"      @&#@&%      ",
-"     +&#  #&+     ",
-"      +    .      ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #595B58",
+    ". c #737572",
+    "+ c #747673",
+    "@ c #8B8D8A",
+    "# c #8D8F8C",
+    "$ c #8E908D",
+    "% c #8F918E",
+    "& c #C7C9C6",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "      +    .      ",
+    "     +&$  #&.     ",
+    "      #&$#&#      ",
+    "       @&&#       ",
+    "       @&&%       ",
+    "      @&#@&%      ",
+    "     +&#  #&+     ",
+    "      +    .      ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* multiplyOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #4A4C49",
-"+     c #4D4E4C",
-"@     c #6D6F6C",
-"#     c #717370",
-"$     c #737572",
-"%     c #757774",
-"&     c #C7C9C6",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"      +    .      ",
-"     +&$  #&.     ",
-"      #&$#&#      ",
-"       @&&#       ",
-"       @&&%       ",
-"      @&$@&%      ",
-"     +&#  #&+     ",
-"      +    .      ",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #4A4C49",
+    "+ c #4D4E4C",
+    "@ c #6D6F6C",
+    "# c #717370",
+    "$ c #737572",
+    "% c #757774",
+    "& c #C7C9C6",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "      +    .      ",
+    "     +&$  #&.     ",
+    "      #&$#&#      ",
+    "       @&&#       ",
+    "       @&&%       ",
+    "      @&$@&%      ",
+    "     +&#  #&+     ",
+    "      +    .      ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* channelStop_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #312D2C",
-"+     c #413A3A",
-"@     c #615253",
-"#     c #73605F",
-"$     c #7A6663",
-"%     c #9C7E7D",
-"&     c #B08D8E",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"     ##.          ",
-"     $&%@         ",
-"     $&&&%+       ",
-"     $&&&&&$.     ",
-"     $&&&&&&&@    ",
-"     $&&&&&&&@.   ",
-"     $&&&&&$.     ",
-"     $&&&%+       ",
-"     $&&@         ",
-"     $#.          ",
-"     .            ",
-"                  ",
-"                  ",
-"                  "};
-
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #312D2C",
+    "+ c #413A3A",
+    "@ c #615253",
+    "# c #73605F",
+    "$ c #7A6663",
+    "% c #9C7E7D",
+    "& c #B08D8E",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     ##.          ",
+    "     $&%@         ",
+    "     $&&&%+       ",
+    "     $&&&&&$.     ",
+    "     $&&&&&&&@    ",
+    "     $&&&&&&&@.   ",
+    "     $&&&&&$.     ",
+    "     $&&&%+       ",
+    "     $&&@         ",
+    "     $#.          ",
+    "     .            ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* channelPlay_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #554E56",
-"+     c #5A4D59",
-"@     c #605068",
-"#     c #775086",
-"$     c #8A509C",
-"%     c #9E50B5",
-"&     c #AD52D0",
-"                  ",
-"                  ",
-"                  ",
-"     .            ",
-"     $$.          ",
-"     $&%#         ",
-"     $&&&%@       ",
-"     $&&&&&$.     ",
-"     $&&&&&&&#.   ",
-"     $&&&&&&&#.   ",
-"     $&&&&&$+     ",
-"     $&&&%@       ",
-"     $&&#         ",
-"     $$.          ",
-"     .            ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #554E56",
+    "+ c #5A4D59",
+    "@ c #605068",
+    "# c #775086",
+    "$ c #8A509C",
+    "% c #9E50B5",
+    "& c #AD52D0",
+    "                  ",
+    "                  ",
+    "                  ",
+    "     .            ",
+    "     $$.          ",
+    "     $&%#         ",
+    "     $&&&%@       ",
+    "     $&&&&&$.     ",
+    "     $&&&&&&&#.   ",
+    "     $&&&&&&&#.   ",
+    "     $&&&&&$+     ",
+    "     $&&&%@       ",
+    "     $&&#         ",
+    "     $$.          ",
+    "     .            ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* armOff_xpm[] = {
-"18 18 8 1",
-"      c #242523",
-".     c #4F4445",
-"+     c #514647",
-"@     c #6D5C5E",
-"#     c #8E7372",
-"$     c #AA8889",
-"%     c #AC898A",
-"&     c #B18E8F",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"      +#%%#.      ",
-"     @&&&&&&@     ",
-"    +&&&&&&&&.    ",
-"    #&&&&&&&&#    ",
-"    %&&&&&&&&%    ",
-"    %&&&&&&&&%    ",
-"    #&&&&&&&&#    ",
-"    .&&&&&&&&.    ",
-"     @&&&&&&@     ",
-"      .#%%#.      ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
-
+    "18 18 8 1",
+    "  c #242523",
+    ". c #4F4445",
+    "+ c #514647",
+    "@ c #6D5C5E",
+    "# c #8E7372",
+    "$ c #AA8889",
+    "% c #AC898A",
+    "& c #B18E8F",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "      +#%%#.      ",
+    "     @&&&&&&@     ",
+    "    +&&&&&&&&.    ",
+    "    #&&&&&&&&#    ",
+    "    %&&&&&&&&%    ",
+    "    %&&&&&&&&%    ",
+    "    #&&&&&&&&#    ",
+    "    .&&&&&&&&.    ",
+    "     @&&&&&&@     ",
+    "      .#%%#.      ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* armOn_xpm[] = {
-"18 18 8 1",
-"      c #4D4F4C",
-".     c #6B5077",
-"+     c #805191",
-"@     c #9950AD",
-"#     c #9751B3",
-"$     c #9553AD",
-"%     c #AA52C9",
-"&     c #AE52D1",
-"                  ",
-"                  ",
-"                  ",
-"                  ",
-"      .#%%#.      ",
-"     +&&&&&&+     ",
-"    .&&&&&&&&.    ",
-"    #&&&&&&&&@    ",
-"    %&&&&&&&&%    ",
-"    %&&&&&&&&%    ",
-"    #&&&&&&&&$    ",
-"    .&&&&&&&&.    ",
-"     +&&&&&&+     ",
-"      .@%%$.      ",
-"                  ",
-"                  ",
-"                  ",
-"                  "};
+    "18 18 8 1",
+    "  c #4D4F4C",
+    ". c #6B5077",
+    "+ c #805191",
+    "@ c #9950AD",
+    "# c #9751B3",
+    "$ c #9553AD",
+    "% c #AA52C9",
+    "& c #AE52D1",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "      .#%%#.      ",
+    "     +&&&&&&+     ",
+    "    .&&&&&&&&.    ",
+    "    #&&&&&&&&@    ",
+    "    %&&&&&&&&%    ",
+    "    %&&&&&&&&%    ",
+    "    #&&&&&&&&$    ",
+    "    .&&&&&&&&.    ",
+    "     +&&&&&&+     ",
+    "      .@%%$.      ",
+    "                  ",
+    "                  ",
+    "                  ",
+    "                  "};
 
 const char* armDisabled_xpm[] = {
-"18 18 7 1",
-"      c None",
-".     c #232523",
-"+     c #303230",
-"@     c #393B38",
-"#     c #424441",
-"$     c #4B4D4A",
-"%     c #4D4F4C",
-"..................",
-"..................",
-"..................",
-"..................",
-"......+#$$#+......",
-".....@%%%%%%@.....",
-"....+%%%%%%%%+....",
-"....#%%%%%%%%#....",
-"....$%%%%%%%%$....",
-"....$%%%%%%%%$....",
-"....#%%%%%%%%#....",
-"....+%%%%%%%%+....",
-".....@%%%%%%@.....",
-"......+#$$#+......",
-"..................",
-"..................",
-"..................",
-".................."};
\ No newline at end of file
+    "18 18 7 1",
+    "  c None",
+    ". c #232523",
+    "+ c #303230",
+    "@ c #393B38",
+    "# c #424441",
+    "$ c #4B4D4A",
+    "% c #4D4F4C",
+    "..................",
+    "..................",
+    "..................",
+    "..................",
+    "......+#$$#+......",
+    ".....@%%%%%%@.....",
+    "....+%%%%%%%%+....",
+    "....#%%%%%%%%#....",
+    "....$%%%%%%%%$....",
+    "....$%%%%%%%%$....",
+    "....#%%%%%%%%#....",
+    "....+%%%%%%%%+....",
+    ".....@%%%%%%@.....",
+    "......+#$$#+......",
+    "..................",
+    "..................",
+    "..................",
+    ".................."};
\ No newline at end of file
index 7db77c9976e23cb87dddd8be8a0336f11532fbc0..ce3082af0ba5291a4be094c1a15029f60904495a 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GRAPHICS_H
 #define G_GRAPHICS_H
 
-
 extern const char* giada_logo_xpm[];
 
 extern const char* loopRepeat_xpm[];
@@ -73,6 +71,9 @@ extern const char* recTriggerModeOn_xpm[];
 extern const char* inputRecOn_xpm[];
 extern const char* inputRecOff_xpm[];
 
+extern const char* freeInputRecOn_xpm[];
+extern const char* freeInputRecOff_xpm[];
+
 extern const char* divideOn_xpm[];
 extern const char* divideOff_xpm[];
 extern const char* multiplyOn_xpm[];
@@ -112,5 +113,4 @@ extern const char* vstLogo_xpm[];
 
 extern const char* giada_icon[];
 
-
 #endif
index 8e8fa657098ec988dec5e18f8aea941d77da1169..fc001420fec10e443cef5f6edf6ad6a44f022c0a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #include "idManager.h"
 
-
-namespace giada::m 
+namespace giada::m
 {
-IdManager::IdManager() : m_id(0)
+IdManager::IdManager()
+: m_id(0)
 {
 }
-       
 
 /* -------------------------------------------------------------------------- */
 
-
 void IdManager::set(ID id)
 {
        if (id != 0 && id > m_id)
                m_id = id;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+ID IdManager::generate(ID id)
+{
+       if (id != 0)
+       {
+               m_id = id;
+               return id;
+       }
+       return ++m_id;
+}
+
+/* -------------------------------------------------------------------------- */
 
-ID IdManager::get(ID id)
+ID IdManager::get()
 {
-       return id != 0 ? id : ++m_id;
+       return m_id;
 }
-} // giada::m::
+} // namespace giada::m
index 54042865c3584b29024ec987eacad6757f65d469..a25cccaa719d849c1d90d6f7a064adca1ef065e5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_ID_MANAGER_H
 #define G_ID_MANAGER_H
 
-
 #include "core/types.h"
 
-
-namespace giada::m 
+namespace giada::m
 {
 class IdManager
 {
 public:
-
        IdManager();
 
        /* set
@@ -45,18 +41,21 @@ public:
 
        void set(ID id);
 
-       /* get
+       /* generate
        Generates a new unique id. If 'id' parameter is passed in is valid, it just 
        returns it with no unique id generation. Useful when loading things from the 
        model that already have their own id. */
 
-       ID   get(ID id=0);
+       ID generate(ID id = 0);
+
+       /* get
+       Returns the current id, a.k.a. the last generated one. */
 
-private:
+       ID get();
 
+  private:
        ID m_id;
 };
-} // giada::m::
-
+} // namespace giada::m
 
 #endif
index 9c15aa8c1c7e946d041e5ea3c817a3ae8a97a350..1dee5aa7e925169385dffdfcf6f0f5c9e44bdf1f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <thread>
 #include <atomic>
 #include <ctime>
+#include <thread>
 #ifdef __APPLE__
-       #include <pwd.h>
+#include <pwd.h>
 #endif
 #if (defined(__linux__) || defined(__FreeBSD__)) && defined(WITH_VST)
-       #include <X11/Xlib.h> // For XInitThreads
+#include <X11/Xlib.h> // For XInitThreads
 #endif
-#include <FL/Fl.H>
-#include "deps/json/single_include/nlohmann/json.hpp"
-#include "gui/updater.h"
-#include "utils/log.h"
-#include "utils/fs.h"
-#include "utils/time.h"
-#include "utils/gui.h"
-#include "utils/ver.h"
-#include "gui/dialogs/mainWindow.h"
-#include "gui/dialogs/warnings.h"
-#include "glue/main.h"
-#include "core/model/storage.h"
 #include "core/channels/channelManager.h"
-#include "core/mixer.h"
-#include "core/wave.h"
-#include "core/const.h"
 #include "core/clock.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include "core/eventDispatcher.h"
+#include "core/kernelAudio.h"
+#include "core/kernelMidi.h"
+#include "core/midiMapConf.h"
+#include "core/mixer.h"
 #include "core/mixerHandler.h"
-#include "core/sequencer.h"
+#include "core/model/model.h"
+#include "core/model/storage.h"
 #include "core/patch.h"
-#include "core/conf.h"
-#include "core/waveManager.h"
-#include "core/plugins/pluginManager.h"
 #include "core/plugins/pluginHost.h"
+#include "core/plugins/pluginManager.h"
+#include "core/recManager.h"
 #include "core/recorder.h"
 #include "core/recorderHandler.h"
-#include "core/recManager.h"
-#include "core/midiMapConf.h"
-#include "core/kernelMidi.h"
-#include "core/kernelAudio.h"
+#include "core/sequencer.h"
+#include "core/wave.h"
+#include "core/waveManager.h"
+#include "deps/json/single_include/nlohmann/json.hpp"
+#include "glue/main.h"
+#include "gui/dialogs/mainWindow.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/updater.h"
 #include "init.h"
-
+#include "utils/fs.h"
+#include "utils/gui.h"
+#include "utils/log.h"
+#include "utils/time.h"
+#include "utils/ver.h"
+#include <FL/Fl.H>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace m {
-namespace init
+namespace giada::m::init
 {
 namespace
 {
@@ -80,13 +77,13 @@ void initConf_()
 {
        if (!conf::read())
                u::log::print("[init] Can't read configuration file! Using default values\n");
-       
+
        patch::init();
        midimap::init();
        midimap::setDefault();
 
        model::load(conf::conf);
-       
+
        if (!u::log::init(conf::conf.logMode))
                u::log::print("[init] log init failed! Using default stdout\n");
 
@@ -94,9 +91,15 @@ void initConf_()
                u::log::print("[init] MIDI map read failed!\n");
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+void initSystem_()
+{
+       model::init();
+       eventDispatcher::init();
+}
+
+/* -------------------------------------------------------------------------- */
 
 void initAudio_()
 {
@@ -121,53 +124,47 @@ void initAudio_()
        kernelAudio::startStream();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void initMIDI_()
 {
        kernelMidi::setApi(conf::conf.midiSystem);
        kernelMidi::openOutDevice(conf::conf.midiPortOut);
-       kernelMidi::openInDevice(conf::conf.midiPortIn);        
+       kernelMidi::openInDevice(conf::conf.midiPortIn);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void initGUI_(int argc, char** argv)
 {
        /* This is of paramount importance on Linux with VST enabled, otherwise many
        plug-ins go nuts and crash hard. It seems that some plug-ins or our Juce-based
        PluginHost use Xlib concurrently. */
-       
+
 #if (defined(__linux__) || defined(__FreeBSD__)) && defined(WITH_VST)
        XInitThreads();
 #endif
 
        G_MainWin = new v::gdMainWindow(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT, "", argc, argv);
        G_MainWin->resize(conf::conf.mainWindowX, conf::conf.mainWindowY, conf::conf.mainWindowW,
-               conf::conf.mainWindowH);
+           conf::conf.mainWindowH);
 
        u::gui::updateMainWinLabel(patch::patch.name == "" ? G_DEFAULT_PATCH_NAME : patch::patch.name);
-       
+
        if (!kernelAudio::isReady())
                v::gdAlert("Your soundcard isn't configured correctly.\n"
-                       "Check the configuration and restart Giada.");
+                          "Check the configuration and restart Giada.");
 
+       v::updater::init();
        u::gui::updateStaticWidgets();
-
-       Fl::add_timeout(G_GUI_REFRESH_RATE, v::updater::update, nullptr);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void shutdownAudio_()
 {
-       if (kernelAudio::isReady()) {
+       if (kernelAudio::isReady())
+       {
                kernelAudio::closeDevice();
                u::log::print("[init] KernelAudio closed\n");
                mh::close();
@@ -185,10 +182,8 @@ void shutdownAudio_()
 #endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void shutdownGUI_()
 {
        u::gui::closeAllSubwindows();
@@ -196,10 +191,8 @@ void shutdownGUI_()
        u::log::print("[init] All subwindows and UI thread closed\n");
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void printBuildInfo_()
 {
        u::log::print("[init] Giada %s\n", G_VERSION_STR);
@@ -216,56 +209,54 @@ void printBuildInfo_()
        u::log::print("[init]   Libsamplerate\n"); // TODO - print version
        u::log::print("[init]   Libsndfile - %s\n", u::ver::getLibsndfileVersion());
        u::log::print("[init]   JSON for modern C++ - %d.%d.%d\n",
-               NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH);
+           NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, NLOHMANN_JSON_VERSION_PATCH);
 #ifdef WITH_VST
        u::log::print("[init]   JUCE - %d.%d.%d\n", JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER);
 #endif
        kernelAudio::logCompiledAPIs();
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void startup(int argc, char** argv)
 {
        printBuildInfo_();
+
        initConf_();
+       initSystem_();
        initAudio_();
        initMIDI_();
        initGUI_(argc, argv);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void closeMainWindow()
 {
        if (!v::gdConfirmWin("Warning", "Quit Giada: are you sure?"))
                return;
 
+       v::updater::close();
        G_MainWin->hide();
        delete G_MainWin;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void reset()
-{      
+{
        u::gui::closeAllSubwindows();
-       G_MainWin->clearKeyboard(); 
+       G_MainWin->clearKeyboard();
 
        mh::close();
 #ifdef WITH_VST
        pluginHost::close();
 #endif
 
+       model::init();
        channelManager::init();
        waveManager::init();
        clock::init(conf::conf.samplerate, conf::conf.midiTCfps);
@@ -276,15 +267,12 @@ void reset()
        pluginManager::init(conf::conf.samplerate, kernelAudio::getRealBufSize());
 #endif
 
-       
        u::gui::updateMainWinLabel(G_DEFAULT_PATCH_NAME);
        u::gui::updateStaticWidgets();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void shutdown()
 {
        shutdownGUI_();
@@ -301,4 +289,4 @@ void shutdown()
        u::log::print("[init] Giada %s closed\n\n", G_VERSION_STR);
        u::log::close();
 }
-}}} // giada::m::init
+} // namespace giada::m::init
index 68fc14ff2d26ebb75b0f342393e4a6a7f16cdc18..5370f6c57cdcfb01d64456b59020ea36c76902a4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_INIT_H
 #define G_INIT_H
 
-
-namespace giada {
-namespace m {
-namespace init
+namespace giada::m::init
 {
 void startup(int argc, char** argv);
-void reset(); 
+void reset();
 void closeMainWindow();
 void shutdown();
-}}} // giada::m::init
+} // namespace giada::m::init
 
-#endif
+#endif
\ No newline at end of file
index aa1ed50cbb39599e16980d46d38e045104206977..2ac51ac29607424bf1ccdaf2025b032538f9dbd9 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "deps/rtaudio/RtAudio.h"
-#include "utils/log.h"
-#include "glue/main.h"
-#include "core/model/model.h"
+#include "kernelAudio.h"
 #include "conf.h"
 #include "const.h"
+#include "core/clock.h"
+#include "core/mixerHandler.h"
+#include "core/model/model.h"
+#include "core/recManager.h"
+#include "deps/rtaudio/RtAudio.h"
+#include "glue/main.h"
 #include "mixer.h"
-#include "const.h"
-#include "kernelAudio.h"
-
+#include "utils/log.h"
+#include "utils/vector.h"
 
 namespace giada::m::kernelAudio
 {
 namespace
 {
-RtAudio* rtSystem     = nullptr;
-unsigned numDevs      = 0;
-bool     inputEnabled = false;
-unsigned realBufsize  = 0;     // Real buffer size from the soundcard
-int      api          = 0;
+std::vector<Device> devices_;
+RtAudio*            rtSystem_     = nullptr;
+bool                inputEnabled_ = false;
+unsigned            realBufsize_  = 0; // Real buffer size from the soundcard
+int                 api_          = 0;
 
-#ifdef WITH_AUDIO_JACK
+/* -------------------------------------------------------------------------- */
 
-JackState jackState;
+#ifdef WITH_AUDIO_JACK
 
 jack_client_t* jackGetHandle_()
 {
-       return static_cast<jack_client_t*>(rtSystem->HACK__getJackClient());
+       return static_cast<jack_client_t*>(rtSystem_->HACK__getJackClient());
 }
 
 #endif
-}  // {anonymous}
 
+/* -------------------------------------------------------------------------- */
+
+Device fetchDevice_(size_t deviceIndex)
+{
+       try
+       {
+               RtAudio::DeviceInfo info = rtSystem_->getDeviceInfo(deviceIndex);
+
+               if (!info.probed)
+               {
+                       u::log::print("[KA] Can't probe device %d\n", deviceIndex);
+                       return {deviceIndex};
+               }
+
+               return {
+                   deviceIndex,
+                   true,
+                   info.name,
+                   static_cast<int>(info.outputChannels),
+                   static_cast<int>(info.inputChannels),
+                   static_cast<int>(info.duplexChannels),
+                   info.isDefaultOutput,
+                   info.isDefaultInput,
+                   u::vector::cast<int>(info.sampleRates)};
+       }
+       catch (RtAudioError& e)
+       {
+               u::log::print("[KA] Error fetching device %d: %s\n", deviceIndex, e.getMessage());
+               return {0};
+       }
+}
 
 /* -------------------------------------------------------------------------- */
+
+std::vector<Device> fetchDevices_()
+{
+       std::vector<Device> out;
+       for (unsigned i = 0; i < rtSystem_->getDeviceCount(); i++)
+               out.push_back(fetchDevice_(i));
+       return out;
+}
+
 /* -------------------------------------------------------------------------- */
+
+void printDevices_(const std::vector<Device>& devices)
+{
+       u::log::print("[KA] %d device(s) found\n", devices.size());
+       for (const Device& d : devices)
+       {
+               u::log::print("  %d) %s\n", d.index, d.name);
+               u::log::print("      ins=%d outs=%d duplex=%d\n", d.maxInputChannels, d.maxOutputChannels, d.maxDuplexChannels);
+               u::log::print("      isDefaultOut=%d isDefaultIn=%d\n", d.isDefaultOut, d.isDefaultIn);
+               u::log::print("      sampleRates:\n\t");
+               for (int s : d.sampleRates)
+                       u::log::print("%d ", s);
+               u::log::print("\n");
+       }
+}
+
 /* -------------------------------------------------------------------------- */
 
+bool canRender_()
+{
+       return model::get().kernel.audioReady && model::get().mixer.state->active.load() == true;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int callback_(void* outBuf, void* inBuf, unsigned bufferSize, double /*streamTime*/,
+    RtAudioStreamStatus /*status*/, void* /*userData*/)
+{
+       AudioBuffer out(static_cast<float*>(outBuf), bufferSize, G_MAX_IO_CHANS);
+       AudioBuffer in;
+       if (isInputEnabled())
+               in = AudioBuffer(static_cast<float*>(inBuf), bufferSize, conf::conf.channelsInCount);
+
+       /* Clean up output buffer before any rendering. Do this even if mixer is
+       disabled to avoid audio leftovers during a temporary suspension (e.g. when
+       loading a new patch). */
+
+       out.clear();
+
+       if (!canRender_())
+               return 0;
+
+#ifdef WITH_AUDIO_JACK
+       if (getAPI() == G_SYS_API_JACK)
+               clock::recvJackSync();
+#endif
+
+       mixer::RenderInfo info;
+       info.isAudioReady    = model::get().kernel.audioReady;
+       info.hasInput        = isInputEnabled();
+       info.isClockActive   = clock::isActive();
+       info.isClockRunning  = clock::isRunning();
+       info.canLineInRec    = recManager::isRecordingInput() && isInputEnabled();
+       info.limitOutput     = conf::conf.limitOutput;
+       info.inToOut         = mh::getInToOut();
+       info.maxFramesToRec  = conf::conf.inputRecMode == InputRecMode::FREE ? clock::getMaxFramesInLoop() : clock::getFramesInLoop();
+       info.outVol          = mh::getOutVol();
+       info.inVol           = mh::getInVol();
+       info.recTriggerLevel = conf::conf.recTriggerLevel;
+
+       return mixer::render(out, in, info);
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
 #ifdef WITH_AUDIO_JACK
 
@@ -75,375 +180,218 @@ bool JackState::operator!=(const JackState& o) const
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isReady()
 {
-       model::KernelLock lock(model::kernel);
-       return model::kernel.get()->audioReady;
+       return model::get().kernel.audioReady;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int openDevice()
 {
-       api = conf::conf.soundSystem;
-       u::log::print("[KA] using system 0x%x\n", api);
+       api_ = conf::conf.soundSystem;
+       u::log::print("[KA] using system 0x%x\n", api_);
 
 #if defined(__linux__) || defined(__FreeBSD__)
 
-       if (api == G_SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK))
-               rtSystem = new RtAudio(RtAudio::UNIX_JACK);
-       else
-       if (api == G_SYS_API_ALSA && hasAPI(RtAudio::LINUX_ALSA))
-               rtSystem = new RtAudio(RtAudio::LINUX_ALSA);
-       else
-       if (api == G_SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE))
-               rtSystem = new RtAudio(RtAudio::LINUX_PULSE);
+       if (api_ == G_SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK))
+               rtSystem_ = new RtAudio(RtAudio::UNIX_JACK);
+       else if (api_ == G_SYS_API_ALSA && hasAPI(RtAudio::LINUX_ALSA))
+               rtSystem_ = new RtAudio(RtAudio::LINUX_ALSA);
+       else if (api_ == G_SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE))
+               rtSystem_ = new RtAudio(RtAudio::LINUX_PULSE);
 
 #elif defined(__FreeBSD__)
 
-       if (api == G_SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK))
-               rtSystem = new RtAudio(RtAudio::UNIX_JACK);
-       else
-       if (api == G_SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE))
-               rtSystem = new RtAudio(RtAudio::LINUX_PULSE);
+       if (api_ == G_SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK))
+               rtSystem_ = new RtAudio(RtAudio::UNIX_JACK);
+       else if (api_ == G_SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE))
+               rtSystem_ = new RtAudio(RtAudio::LINUX_PULSE);
 
 #elif defined(_WIN32)
 
-       if (api == G_SYS_API_DS && hasAPI(RtAudio::WINDOWS_DS))
-               rtSystem = new RtAudio(RtAudio::WINDOWS_DS);
-       else
-       if (api == G_SYS_API_ASIO && hasAPI(RtAudio::WINDOWS_ASIO))
-               rtSystem = new RtAudio(RtAudio::WINDOWS_ASIO);
-       else
-       if (api == G_SYS_API_WASAPI && hasAPI(RtAudio::WINDOWS_WASAPI))
-               rtSystem = new RtAudio(RtAudio::WINDOWS_WASAPI);
+       if (api_ == G_SYS_API_DS && hasAPI(RtAudio::WINDOWS_DS))
+               rtSystem_ = new RtAudio(RtAudio::WINDOWS_DS);
+       else if (api_ == G_SYS_API_ASIO && hasAPI(RtAudio::WINDOWS_ASIO))
+               rtSystem_ = new RtAudio(RtAudio::WINDOWS_ASIO);
+       else if (api_ == G_SYS_API_WASAPI && hasAPI(RtAudio::WINDOWS_WASAPI))
+               rtSystem_ = new RtAudio(RtAudio::WINDOWS_WASAPI);
 
 #elif defined(__APPLE__)
 
-       if (api == G_SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE))
-               rtSystem = new RtAudio(RtAudio::MACOSX_CORE);
+       if (api_ == G_SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE))
+               rtSystem_ = new RtAudio(RtAudio::MACOSX_CORE);
 
 #endif
 
-       else {
+       else
+       {
                u::log::print("[KA] No API available, nothing to do!\n");
                return 0;
        }
 
        u::log::print("[KA] Opening device out=%d, in=%d, samplerate=%d\n",
-    conf::conf.soundDeviceOut, conf::conf.soundDeviceIn, conf::conf.samplerate);
+           conf::conf.soundDeviceOut, conf::conf.soundDeviceIn, conf::conf.samplerate);
 
-       numDevs = rtSystem->getDeviceCount();
+       devices_ = fetchDevices_();
+       printDevices_(devices_);
 
-       if (numDevs < 1) {
-               u::log::print("[KA] no devices found with this API\n");
+       /* Abort here if devices found are zero. */
+
+       if (devices_.size() == 0)
+       {
                closeDevice();
                return 0;
        }
-       else {
-               u::log::print("[KA] %d device(s) found\n", numDevs);
-               for (unsigned i=0; i<numDevs; i++)
-                       u::log::print("  %d) %s\n", i, getDeviceName(i));
-       }
 
        RtAudio::StreamParameters outParams;
        RtAudio::StreamParameters inParams;
 
-       outParams.deviceId     = conf::conf.soundDeviceOut == G_DEFAULT_SOUNDDEV_OUT ? getDefaultOut() : conf::conf.soundDeviceOut;
-       outParams.nChannels    = G_MAX_IO_CHANS;
-       outParams.firstChannel = conf::conf.channelsOut * G_MAX_IO_CHANS; // chan 0=0, 1=2, 2=4, ...
+       outParams.deviceId     = conf::conf.soundDeviceOut == G_DEFAULT_SOUNDDEV_OUT ? rtSystem_->getDefaultOutputDevice() : conf::conf.soundDeviceOut;
+       outParams.nChannels    = conf::conf.channelsOutCount;
+       outParams.firstChannel = conf::conf.channelsOutStart;
 
        /* Input device can be disabled. Unlike the output, here we are using all
        channels and let the user choose which one to record from in the configuration
        panel. */
 
-       if (conf::conf.soundDeviceIn != -1) {
+       if (conf::conf.soundDeviceIn != -1)
+       {
                inParams.deviceId     = conf::conf.soundDeviceIn;
                inParams.nChannels    = conf::conf.channelsInCount;
                inParams.firstChannel = conf::conf.channelsInStart;
-               inputEnabled = true;
+               inputEnabled_         = true;
        }
        else
-               inputEnabled = false;
+               inputEnabled_ = false;
 
        RtAudio::StreamOptions options;
-       options.streamName = G_APP_NAME;
-       options.numberOfBuffers = 4;
+       options.streamName      = G_APP_NAME;
+       options.numberOfBuffers = 4; // TODO - wtf?
 
-       realBufsize = conf::conf.buffersize;
+       realBufsize_ = conf::conf.buffersize;
 
 #ifdef WITH_AUDIO_JACK
 
-       if (api == G_SYS_API_JACK) {
-               conf::conf.samplerate = getFreq(conf::conf.soundDeviceOut, 0);
+       if (api_ == G_SYS_API_JACK)
+       {
+               conf::conf.samplerate = devices_[conf::conf.soundDeviceOut].sampleRates[0];
                u::log::print("[KA] JACK in use, samplerate=%d\n", conf::conf.samplerate);
        }
 
 #endif
 
-       try {
-               rtSystem->openStream(
-                       &outParams,                                            // output params
-                       conf::conf.soundDeviceIn != -1 ? &inParams : nullptr,  // input params if inDevice is selected
-                       RTAUDIO_FLOAT32,                                       // audio format
-                       conf::conf.samplerate,                                 // sample rate
-                       &realBufsize,                                          // buffer size in byte
-                       &mixer::masterPlay,                                    // audio callback
-                       nullptr,                                               // user data (unused)
-                       &options);
-               
-               model::onSwap(model::kernel, [](model::Kernel& k) {
-                       k.audioReady = true;
-               });
+       try
+       {
+               rtSystem_->openStream(
+                   &outParams,                                           // output params
+                   conf::conf.soundDeviceIn != -1 ? &inParams : nullptr, // input params if inDevice is selected
+                   RTAUDIO_FLOAT32,                                      // audio format
+                   conf::conf.samplerate,                                // sample rate
+                   &realBufsize_,                                        // buffer size in byte
+                   &callback_,                                           // audio callback
+                   nullptr,                                              // user data (unused)
+                   &options);
+
+               model::get().kernel.audioReady = true;
+               model::swap(model::SwapType::NONE);
                return 1;
        }
-       catch (RtAudioError &e) {
-               u::log::print("[KA] rtSystem init error: %s\n", e.getMessage());
+       catch (RtAudioError& e)
+       {
+               u::log::print("[KA] rtSystem_ init error: %s\n", e.getMessage());
                closeDevice();
                return 0;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int startStream()
 {
-       try {
-               rtSystem->startStream();
-               u::log::print("[KA] latency = %lu\n", rtSystem->getStreamLatency());
+       try
+       {
+               rtSystem_->startStream();
+               u::log::print("[KA] latency = %lu\n", rtSystem_->getStreamLatency());
                return 1;
        }
-       catch (RtAudioError &e) {
+       catch (RtAudioError& e)
+       {
                u::log::print("[KA] Start stream error: %s\n", e.getMessage());
                return 0;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int stopStream()
 {
-       try {
-               rtSystem->stopStream();
+       try
+       {
+               rtSystem_->stopStream();
                return 1;
        }
-       catch (RtAudioError& /*e*/) {
+       catch (RtAudioError& /*e*/)
+       {
                u::log::print("[KA] Stop stream error\n");
                return 0;
        }
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-std::string getDeviceName(unsigned dev)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).name;
-       }
-       catch (RtAudioError& /*e*/) {
-               u::log::print("[KA] invalid device ID = %d\n", dev);
-               return "";
-       }
-}
-
-
 /* -------------------------------------------------------------------------- */
 
-
 int closeDevice()
 {
-       if (rtSystem->isStreamOpen()) {
-               rtSystem->stopStream();
-               rtSystem->closeStream();
-               delete rtSystem;
-               rtSystem = nullptr;
+       if (rtSystem_->isStreamOpen())
+       {
+               rtSystem_->stopStream();
+               rtSystem_->closeStream();
+               delete rtSystem_;
+               rtSystem_ = nullptr;
        }
        return 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-unsigned getMaxInChans(int dev)
-{
-       if (dev == -1) return 0;
-
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).inputChannels;
-       }
-       catch (RtAudioError& /*e*/) {
-               u::log::print("[KA] Unable to get input channels\n");
-               return 0;
-       }
-}
-
+unsigned getRealBufSize() { return realBufsize_; }
+bool     isInputEnabled() { return inputEnabled_; }
 
 /* -------------------------------------------------------------------------- */
 
-
-unsigned getMaxOutChans(unsigned dev)
+Device getDevice(const char* name)
 {
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).outputChannels;
-       }
-       catch (RtAudioError& /*e*/) {
-               u::log::print("[KA] Unable to get output channels\n");
-               return 0;
-       }
+       for (Device device : devices_)
+               if (name == device.name)
+                       return device;
+       return {0, false};
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool isProbed(unsigned dev)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).probed;
-       }
-       catch (RtAudioError& /*e*/) {
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-unsigned getDuplexChans(unsigned dev)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).duplexChannels;
-       }
-       catch (RtAudioError& /*e*/) {
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool isDefaultIn(unsigned dev)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).isDefaultInput;
-       }
-       catch (RtAudioError& /*e*/) {
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-bool isDefaultOut(unsigned dev)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).isDefaultOutput;
-       }
-       catch (RtAudioError& /*e*/) {
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int getTotalFreqs(unsigned dev)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).sampleRates.size();
-       }
-       catch (RtAudioError& /*e*/) {
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int    getFreq(unsigned dev, int i)
-{
-       try {
-               return static_cast<RtAudio::DeviceInfo>(rtSystem->getDeviceInfo(dev)).sampleRates.at(i);
-       }
-       catch (RtAudioError& /*e*/) {
-               return 0;
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-unsigned getRealBufSize() { return realBufsize; }
-bool isInputEnabled() { return inputEnabled; }
-unsigned countDevices() { return numDevs; }
-
-
-/* -------------------------------------------------------------------------- */
-
-
-int getDefaultIn()
-{
-       return rtSystem->getDefaultInputDevice();
-}
-
-int getDefaultOut()
+const std::vector<Device>& getDevices()
 {
-       return rtSystem->getDefaultOutputDevice();
+       return devices_;
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-int    getDeviceByName(const char* name)
-{
-       for (unsigned i=0; i<numDevs; i++)
-               if (name == getDeviceName(i))
-                       return i;
-       return -1;
-}
-
-
 /* -------------------------------------------------------------------------- */
 
-
 bool hasAPI(int API)
 {
        std::vector<RtAudio::Api> APIs;
        RtAudio::getCompiledApi(APIs);
-       for (unsigned i=0; i<APIs.size(); i++)
+       for (unsigned i = 0; i < APIs.size(); i++)
                if (APIs.at(i) == API)
                        return true;
        return false;
 }
 
-
-int getAPI() { return api; }
-
+int getAPI() { return api_; }
 
 /* -------------------------------------------------------------------------- */
 
-
 void logCompiledAPIs()
 {
        std::vector<RtAudio::Api> APIs;
@@ -451,102 +399,102 @@ void logCompiledAPIs()
 
        u::log::print("[KA] Compiled RtAudio APIs: %d\n", APIs.size());
 
-       for (const RtAudio::Api& api : APIs) {
-               switch (api) {
-                       case RtAudio::Api::LINUX_ALSA:
-                               u::log::print("  ALSA\n"); break;
-                       case RtAudio::Api::LINUX_PULSE:
-                               u::log::print("  PulseAudio\n"); break;
-                       case RtAudio::Api::UNIX_JACK:
-                               u::log::print("  JACK\n"); break;
-                       case RtAudio::Api::MACOSX_CORE:
-                               u::log::print("  CoreAudio\n"); break;
-                       case RtAudio::Api::WINDOWS_WASAPI:
-                               u::log::print("  WASAPI\n"); break;
-                       case RtAudio::Api::WINDOWS_ASIO:
-                               u::log::print("  ASIO\n"); break;
-                       case RtAudio::Api::WINDOWS_DS:
-                               u::log::print("  DirectSound\n"); break;
-                       case RtAudio::Api::RTAUDIO_DUMMY:
-                               u::log::print("  Dummy\n"); break;
-                       default:
-                               u::log::print("  (unknown)\n"); break;
+       for (const RtAudio::Api& api_ : APIs)
+       {
+               switch (api_)
+               {
+               case RtAudio::Api::LINUX_ALSA:
+                       u::log::print("  ALSA\n");
+                       break;
+               case RtAudio::Api::LINUX_PULSE:
+                       u::log::print("  PulseAudio\n");
+                       break;
+               case RtAudio::Api::UNIX_JACK:
+                       u::log::print("  JACK\n");
+                       break;
+               case RtAudio::Api::MACOSX_CORE:
+                       u::log::print("  CoreAudio\n");
+                       break;
+               case RtAudio::Api::WINDOWS_WASAPI:
+                       u::log::print("  WASAPI\n");
+                       break;
+               case RtAudio::Api::WINDOWS_ASIO:
+                       u::log::print("  ASIO\n");
+                       break;
+               case RtAudio::Api::WINDOWS_DS:
+                       u::log::print("  DirectSound\n");
+                       break;
+               case RtAudio::Api::RTAUDIO_DUMMY:
+                       u::log::print("  Dummy\n");
+                       break;
+               default:
+                       u::log::print("  (unknown)\n");
+                       break;
                }
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_AUDIO_JACK
 
 JackState jackTransportQuery()
 {
-       if (api != G_SYS_API_JACK)
-               return jackState;
+       if (api_ != G_SYS_API_JACK)
+               return {};
 
        jack_position_t        position;
        jack_transport_state_t ts = jack_transport_query(jackGetHandle_(), &position);
 
        return {
-               ts != JackTransportStopped,
-               position.beats_per_minute,
-               position.frame
-       };
+           ts != JackTransportStopped,
+           position.beats_per_minute,
+           position.frame};
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void jackStart()
 {
-       if (api == G_SYS_API_JACK)
+       if (api_ == G_SYS_API_JACK)
                jack_transport_start(jackGetHandle_());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void jackSetPosition(uint32_t frame)
 {
-       if (api != G_SYS_API_JACK)
-       return;
+       if (api_ != G_SYS_API_JACK)
+               return;
        jack_position_t position;
        jack_transport_query(jackGetHandle_(), &position);
        position.frame = frame;
        jack_transport_reposition(jackGetHandle_(), &position);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void jackSetBpm(double bpm)
 {
-       if (api != G_SYS_API_JACK)
+       if (api_ != G_SYS_API_JACK)
                return;
        jack_position_t position;
        jack_transport_query(jackGetHandle_(), &position);
-       position.valid = jack_position_bits_t::JackPositionBBT;
-       position.bar  = 0;  // no such info from Giada
-       position.beat = 0;  // no such info from Giada
-       position.tick = 0;  // no such info from Giada
+       position.valid            = jack_position_bits_t::JackPositionBBT;
+       position.bar              = 0; // no such info from Giada
+       position.beat             = 0; // no such info from Giada
+       position.tick             = 0; // no such info from Giada
        position.beats_per_minute = bpm;
        jack_transport_reposition(jackGetHandle_(), &position);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void jackStop()
 {
-       if (api == G_SYS_API_JACK)
+       if (api_ == G_SYS_API_JACK)
                jack_transport_stop(jackGetHandle_());
 }
 
-#endif  // WITH_AUDIO_JACK
-} // giada::m::kernelAudio
+#endif // WITH_AUDIO_JACK
+} // namespace giada::m::kernelAudio
index 8e3ed7ea1e0b04b323ee7a62c8f5ddec26e66a13..498eebab7df42552e98c82e3e2711783c7ddfa8b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_KERNELAUDIO_H
 #define G_KERNELAUDIO_H
 
-
+#include <optional>
 #include <string>
+#include <vector>
 #ifdef WITH_AUDIO_JACK
-       #include <jack/jack.h>
-       #include <jack/intclient.h>
-       #include <jack/transport.h>
+#include <jack/intclient.h>
+#include <jack/jack.h>
+#include <jack/transport.h>
 #endif
 
-
 namespace giada::m::kernelAudio
 {
 #ifdef WITH_AUDIO_JACK
@@ -52,41 +51,42 @@ struct JackState
 
 #endif
 
+struct Device
+{
+       size_t           index             = 0;
+       bool             probed            = false;
+       std::string      name              = "";
+       int              maxOutputChannels = 0;
+       int              maxInputChannels  = 0;
+       int              maxDuplexChannels = 0;
+       bool             isDefaultOut      = false;
+       bool             isDefaultIn       = false;
+       std::vector<int> sampleRates       = {};
+};
+
 int openDevice();
 int closeDevice();
 int startStream();
 int stopStream();
 
-bool isReady();
-bool isProbed(unsigned dev);
-bool isDefaultIn(unsigned dev);
-bool isDefaultOut(unsigned dev);
-bool isInputEnabled();
-std::string getDeviceName(unsigned dev);
-unsigned getMaxInChans(int dev);
-unsigned getMaxOutChans(unsigned dev);
-unsigned getDuplexChans(unsigned dev);
-unsigned getRealBufSize();
-unsigned countDevices();
-int getTotalFreqs(unsigned dev);
-int getFreq(unsigned dev, int i);
-int getDeviceByName(const char* name);
-int getDefaultOut();
-int getDefaultIn();
-bool hasAPI(int API);
-int getAPI();
-void logCompiledAPIs();
+bool                       isReady();
+bool                       isInputEnabled();
+unsigned                   getRealBufSize();
+bool                       hasAPI(int API);
+int                        getAPI();
+void                       logCompiledAPIs();
+Device                     getDevice(const char* name);
+const std::vector<Device>& getDevices();
 
 #ifdef WITH_AUDIO_JACK
 
-void jackStart();
-void jackStop();
-void jackSetPosition(uint32_t frame);
-void jackSetBpm(double bpm);
+void      jackStart();
+void      jackStop();
+void      jackSetPosition(uint32_t frame);
+void      jackSetBpm(double bpm);
 JackState jackTransportQuery();
 
 #endif
-} // giada::m::kernelAudio::
-
+} // namespace giada::m::kernelAudio
 
 #endif
index 4e0f62b1958597204a967678c99cee43dd60987a..93306b0d38de43bd899fcca800304fee284548e5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <RtMidi.h>
+#include "kernelMidi.h"
 #include "const.h"
-#include "utils/log.h"
 #include "midiDispatcher.h"
 #include "midiMapConf.h"
-#include "kernelMidi.h"
-
+#include "utils/log.h"
+#include <RtMidi.h>
 
-namespace giada {
-namespace m {
+namespace giada
+{
+namespace m
+{
 namespace kernelMidi
 {
 namespace
 {
-bool status_ = false;
-int api_ = 0;
-RtMidiOut* midiOut_ = nullptr;
-RtMidiIn*  midiIn_  = nullptr;
-unsigned numOutPorts_ = 0;
-unsigned numInPorts_  = 0;
-
+bool       status_      = false;
+int        api_         = 0;
+RtMidiOut* midiOut_     = nullptr;
+RtMidiIn*  midiIn_      = nullptr;
+unsigned   numOutPorts_ = 0;
+unsigned   numInPorts_  = 0;
 
 static void callback_(double /*t*/, std::vector<unsigned char>* msg, void* /*data*/)
 {
-       if (msg->size() < 3) {
+       if (msg->size() < 3)
+       {
                //u::log::print("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
                //for (unsigned i=0; i<msg->size(); i++)
                //      u::log::print("%X", (int) msg->at(i));
@@ -59,14 +59,14 @@ static void callback_(double /*t*/, std::vector<unsigned char>* msg, void* /*dat
        midiDispatcher::dispatch(msg->at(0), msg->at(1), msg->at(2));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sendMidiLightningInitMsgs_()
 {
-       for (const midimap::Message& m : midimap::midimap.initCommands) {
-               if (m.value != 0x0 && m.channel != -1) {
+       for (const midimap::Message& m : midimap::midimap.initCommands)
+       {
+               if (m.value != 0x0 && m.channel != -1)
+               {
                        u::log::print("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", m.channel, m.value);
                        MidiEvent e(m.value);
                        e.setChannel(m.channel);
@@ -74,31 +74,29 @@ void sendMidiLightningInitMsgs_()
                }
        }
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void setApi(int api)
 {
        api_ = api;
        u::log::print("[KM] using system 0x%x\n", api_);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int openOutDevice(int port)
 {
-       try {
-               midiOut_ = new RtMidiOut((RtMidi::Api) api_, "Giada MIDI Output");
+       try
+       {
+               midiOut_ = new RtMidiOut((RtMidi::Api)api_, "Giada MIDI Output");
                status_  = true;
        }
-       catch (RtMidiError &error) {
+       catch (RtMidiError& error)
+       {
                u::log::print("[KM] MIDI out device error: %s\n", error.getMessage());
                status_ = false;
                return 0;
@@ -108,13 +106,15 @@ int openOutDevice(int port)
 
        numOutPorts_ = midiOut_->getPortCount();
        u::log::print("[KM] %d output MIDI ports found\n", numOutPorts_);
-       for (unsigned i=0; i<numOutPorts_; i++)
+       for (unsigned i = 0; i < numOutPorts_; i++)
                u::log::print("  %d) %s\n", i, getOutPortName(i));
 
        /* try to open a port, if enabled */
 
-       if (port != -1 && numOutPorts_ > 0) {
-               try {
+       if (port != -1 && numOutPorts_ > 0)
+       {
+               try
+               {
                        midiOut_->openPort(port, getOutPortName(port));
                        u::log::print("[KM] MIDI out port %d open\n", port);
 
@@ -124,7 +124,8 @@ int openOutDevice(int port)
                        sendMidiLightningInitMsgs_();
                        return 1;
                }
-               catch (RtMidiError& error) {
+               catch (RtMidiError& error)
+               {
                        u::log::print("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage());
                        status_ = false;
                        return 0;
@@ -134,17 +135,17 @@ int openOutDevice(int port)
                return 2;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int openInDevice(int port)
 {
-       try {
-               midiIn_ = new RtMidiIn((RtMidi::Api) api_, "Giada MIDI input");
+       try
+       {
+               midiIn_ = new RtMidiIn((RtMidi::Api)api_, "Giada MIDI input");
                status_ = true;
        }
-       catch (RtMidiError &error) {
+       catch (RtMidiError& error)
+       {
                u::log::print("[KM] MIDI in device error: %s\n", error.getMessage());
                status_ = false;
                return 0;
@@ -154,20 +155,23 @@ int openInDevice(int port)
 
        numInPorts_ = midiIn_->getPortCount();
        u::log::print("[KM] %d input MIDI ports found\n", numInPorts_);
-       for (unsigned i=0; i<numInPorts_; i++)
+       for (unsigned i = 0; i < numInPorts_; i++)
                u::log::print("  %d) %s\n", i, getInPortName(i));
 
        /* try to open a port, if enabled */
 
-       if (port != -1 && numInPorts_ > 0) {
-               try {
+       if (port != -1 && numInPorts_ > 0)
+       {
+               try
+               {
                        midiIn_->openPort(port, getInPortName(port));
                        midiIn_->ignoreTypes(true, false, true); // ignore all system/time msgs, for now
                        u::log::print("[KM] MIDI in port %d open\n", port);
                        midiIn_->setCallback(&callback_);
                        return 1;
                }
-               catch (RtMidiError& error) {
+               catch (RtMidiError& error)
+               {
                        u::log::print("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage());
                        status_ = false;
                        return 0;
@@ -177,40 +181,46 @@ int openInDevice(int port)
                return 2;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool hasAPI(int API)
 {
        std::vector<RtMidi::Api> APIs;
        RtMidi::getCompiledApi(APIs);
-       for (unsigned i=0; i<APIs.size(); i++)
+       for (unsigned i = 0; i < APIs.size(); i++)
                if (APIs.at(i) == API)
                        return true;
        return false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getOutPortName(unsigned p)
 {
-       try { return midiOut_->getPortName(p); }
-       catch (RtMidiError& /*error*/) { return ""; }
+       try
+       {
+               return midiOut_->getPortName(p);
+       }
+       catch (RtMidiError& /*error*/)
+       {
+               return "";
+       }
 }
 
 std::string getInPortName(unsigned p)
 {
-       try { return midiIn_->getPortName(p); }
-       catch (RtMidiError& /*error*/) { return ""; }
+       try
+       {
+               return midiIn_->getPortName(p);
+       }
+       catch (RtMidiError& /*error*/)
+       {
+               return "";
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void send(uint32_t data)
 {
        if (!status_)
@@ -224,10 +234,8 @@ void send(uint32_t data)
        u::log::print("[KM::send] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void send(int b1, int b2, int b3)
 {
        if (!status_)
@@ -244,10 +252,8 @@ void send(int b1, int b2, int b3)
        u::log::print("[KM::send] send msg=(%X %X %X)\n", b1, b2, b3);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sendMidiLightning(uint32_t learnt, const midimap::Message& m)
 {
        // Skip lightning message if not defined in midi map
@@ -258,8 +264,8 @@ void sendMidiLightning(uint32_t learnt, const midimap::Message& m)
                return;
        }
 
-       u::log::print("[KM::sendMidiLightning] learnt=0x%X, chan=%d, msg=0x%X, offset=%d\n", 
-               learnt, m.channel, m.value, m.offset);
+       u::log::print("[KM::sendMidiLightning] learnt=0x%X, chan=%d, msg=0x%X, offset=%d\n",
+           learnt, m.channel, m.value, m.offset);
 
        /* Isolate 'channel' from learnt message and offset it as requested by 'nn' in 
        the midimap configuration file. */
@@ -273,25 +279,22 @@ void sendMidiLightning(uint32_t learnt, const midimap::Message& m)
        send(out);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-unsigned countInPorts()  { return numInPorts_; }
+unsigned countInPorts() { return numInPorts_; }
 unsigned countOutPorts() { return numOutPorts_; }
-bool getStatus()         { return status_; }
-
+bool     getStatus() { return status_; }
 
 /* -------------------------------------------------------------------------- */
 
-
 int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; }
 int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; }
-int getB3(uint32_t iValue) { return (iValue >> 8)  & 0xFF; }
-
+int getB3(uint32_t iValue) { return (iValue >> 8) & 0xFF; }
 
 uint32_t getIValue(int b1, int b2, int b3)
 {
        return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00);
 }
-}}} // giada::m::kernelMidi::
+} // namespace kernelMidi
+} // namespace m
+} // namespace giada
index 7e1c90a6e75821c170191435fa5d36ddcc819108..e3f2dfd81d6d0fa3be5ef741b003c5bcb7636a70 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_KERNELMIDI_H
 #define G_KERNELMIDI_H
 
-
+#include "midiMapConf.h"
 #include <cstdint>
 #include <string>
-#include "midiMapConf.h"
 
-
-namespace giada {
-namespace m {
+namespace giada
+{
+namespace m
+{
 namespace kernelMidi
 {
 int getB1(uint32_t iValue);
@@ -48,7 +47,7 @@ uint32_t getIValue(int b1, int b2, int b3);
 Sends a MIDI message 's' as uint32_t or as separate bytes. */
 
 void send(uint32_t s);
-void send(int b1, int b2=-1, int b3=-1);
+void send(int b1, int b2 = -1, int b3 = -1);
 
 /* sendMidiLightning
 Sends a MIDI lightning message defined by 'msg'. */
@@ -83,7 +82,8 @@ unsigned countOutPorts();
 
 bool hasAPI(int API);
 
-}}} // giada::m::kernelMidi::
-
+} // namespace kernelMidi
+} // namespace m
+} // namespace giada
 
 #endif
diff --git a/src/core/metronome.cpp b/src/core/metronome.cpp
new file mode 100644 (file)
index 0000000..4220777
--- /dev/null
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "metronome.h"
+#include "core/audioBuffer.h"
+
+namespace giada::m
+{
+void Metronome::trigger(Click c, Frame o)
+{
+       m_rendering = true;
+       m_click     = c;
+       m_offset    = o;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void Metronome::render(AudioBuffer& outBuf)
+{
+       const float* data = m_click == Click::BEAT ? beat : bar;
+       for (Frame f = m_offset; f < outBuf.countFrames() && m_rendering; f++)
+       {
+               for (int c = 0; c < outBuf.countChannels(); c++)
+                       outBuf[f][c] += data[m_tracker];
+               m_tracker = (m_tracker + 1) % CLICK_SIZE;
+               if (m_tracker == 0)
+                       m_rendering = false;
+       }
+       m_offset = 0;
+}
+} // namespace giada::m
\ No newline at end of file
diff --git a/src/core/metronome.h b/src/core/metronome.h
new file mode 100644 (file)
index 0000000..9a6986d
--- /dev/null
@@ -0,0 +1,77 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_METRONOME_H
+#define G_METRONOME_H
+
+#include "core/types.h"
+
+namespace giada::m
+{
+class AudioBuffer;
+class Metronome
+{
+public:
+       enum class Click
+       {
+               BEAT,
+               BAR
+       };
+
+       void render(AudioBuffer& outBuf);
+       void trigger(Click c, Frame o);
+
+       bool running = false;
+
+  private:
+       static constexpr Frame CLICK_SIZE = 38;
+
+       static constexpr float beat[CLICK_SIZE] = {
+           0.059033f, 0.117240f, 0.173807f, 0.227943f, 0.278890f, 0.325936f,
+           0.368423f, 0.405755f, 0.437413f, 0.462951f, 0.482013f, 0.494333f,
+           0.499738f, 0.498153f, 0.489598f, 0.474195f, 0.452159f, 0.423798f,
+           0.389509f, 0.349771f, 0.289883f, 0.230617f, 0.173194f, 0.118739f,
+           0.068260f, 0.022631f, -0.017423f, -0.051339f, -0.078721f, -0.099345f,
+           -0.113163f, -0.120295f, -0.121028f, -0.115804f, -0.105209f, -0.089954f,
+           -0.070862f, -0.048844f};
+
+       static constexpr float bar[CLICK_SIZE] = {
+           0.175860f, 0.341914f, 0.488904f, 0.608633f, 0.694426f, 0.741500f,
+           0.747229f, 0.711293f, 0.635697f, 0.524656f, 0.384362f, 0.222636f,
+           0.048496f, -0.128348f, -0.298035f, -0.451105f, -0.579021f, -0.674653f,
+           -0.732667f, -0.749830f, -0.688924f, -0.594091f, -0.474481f, -0.340160f,
+           -0.201360f, -0.067752f, 0.052194f, 0.151746f, 0.226280f, 0.273493f,
+           0.293425f, 0.288307f, 0.262252f, 0.220811f, 0.170435f, 0.117887f,
+           0.069639f, 0.031320f};
+
+       Frame m_tracker   = 0;
+       Frame m_offset    = 0;
+       bool  m_rendering = false;
+       Click m_click     = Click::BEAT;
+};
+} // namespace giada::m
+
+#endif
index eb2bd2066def6108d5a63d1d1b38d368636a2911..559894abc8f7244f1656f11f39b76df574e5230e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <vector>
-#include "glue/plugin.h"
-#include "glue/events.h"
-#include "utils/log.h"
-#include "utils/math.h"
-#include "core/model/model.h"
+#include "core/midiDispatcher.h"
 #include "core/conf.h"
 #include "core/mixer.h"
 #include "core/mixerHandler.h"
-#include "core/plugins/pluginHost.h"
+#include "core/model/model.h"
 #include "core/plugins/plugin.h"
+#include "core/plugins/pluginHost.h"
 #include "core/recManager.h"
 #include "core/types.h"
-#include "core/midiDispatcher.h"
-
+#include "glue/events.h"
+#include "glue/plugin.h"
+#include "utils/log.h"
+#include "utils/math.h"
+#include <cassert>
+#include <vector>
 
-namespace giada {
-namespace m {
-namespace midiDispatcher
+namespace giada::m::midiDispatcher
 {
 namespace
 {
@@ -55,35 +51,27 @@ contains things to do once the midi message has been stored. */
 std::function<void()>          signalCb_ = nullptr;
 std::function<void(MidiEvent)> learnCb_  = nullptr;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isMasterMidiInAllowed_(int c)
 {
-       model::MidiInLock l(model::midiIn);
-       int filter   = model::midiIn.get()->filter;
-       bool enabled = model::midiIn.get()->enabled;
+       int  filter  = model::get().midiIn.filter;
+       bool enabled = model::get().midiIn.enabled;
        return enabled && (filter == -1 || filter == c);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isChannelMidiInAllowed_(ID channelId, int c)
 {
-       model::ChannelsLock l(model::channels);
-       return model::get(model::channels, channelId).midiLearner.state->isAllowed(c);
+       return model::get().getChannel(channelId).midiLearner.isAllowed(c);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-void processPlugins_(const std::vector<ID>& ids, const MidiEvent& midiEvent)
+void processPlugins_(const std::vector<Plugin*>& plugins, const MidiEvent& midiEvent)
 {
        uint32_t pure = midiEvent.getRawNoVelocity();
        float    vf   = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, 1.0f);
@@ -93,180 +81,212 @@ void processPlugins_(const std::vector<ID>& ids, const MidiEvent& midiEvent)
        parameter indexes match both the structure of Channel::midiInPlugins and the 
        vector of plugins. */
 
-       m::model::PluginsLock l(m::model::plugins);
-       for (ID id : ids) {
-               const m::Plugin& p = m::model::get(m::model::plugins, id);
-               for (const MidiLearnParam& param : p.midiInParams) {
+       for (Plugin* p : plugins)
+       {
+               for (const MidiLearnParam& param : p->midiInParams)
+               {
                        if (pure != param.getValue())
                                continue;
-                       c::events::setPluginParameter(id, param.getIndex(), vf, /*gui=*/false);
+                       c::events::setPluginParameter(p->id, param.getIndex(), vf, /*gui=*/false);
                        u::log::print("  >>> [pluginId=%d paramIndex=%d] (pure=0x%X, value=%d, float=%f)\n",
-                               p.id, param.getIndex(), pure, midiEvent.getVelocity(), vf);
+                           p->id, param.getIndex(), pure, midiEvent.getVelocity(), vf);
                }
        }
 }
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void processChannels_(const MidiEvent& midiEvent)
 {
        uint32_t pure = midiEvent.getRawNoVelocity();
 
-       model::ChannelsLock lock(model::channels);
-
-       for (const Channel* c : model::channels) {
+       for (const channel::Data& c : model::get().channels)
+       {
 
                /* Do nothing on this channel if MIDI in is disabled or filtered out for
                the current MIDI channel. */
-
-               if (!c->midiLearner.state->isAllowed(midiEvent.getChannel()))
+               if (!c.midiLearner.isAllowed(midiEvent.getChannel()))
                        continue;
 
-               if (pure == c->midiLearner.state->keyPress.getValue()) {
-                       u::log::print("  >>> keyPress, ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::pressChannel(c->id, midiEvent.getVelocity(), Thread::MIDI);
+               if (pure == c.midiLearner.keyPress.getValue())
+               {
+                       u::log::print("  >>> keyPress, ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::pressChannel(c.id, midiEvent.getVelocity(), Thread::MIDI);
+               }
+               else if (pure == c.midiLearner.keyRelease.getValue())
+               {
+                       u::log::print("  >>> keyRel ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::releaseChannel(c.id, Thread::MIDI);
                }
-               else if (pure == c->midiLearner.state->keyRelease.getValue()) {
-                       u::log::print("  >>> keyRel ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::releaseChannel(c->id, Thread::MIDI);
+               else if (pure == c.midiLearner.mute.getValue())
+               {
+                       u::log::print("  >>> mute ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::toggleMuteChannel(c.id, Thread::MIDI);
                }
-               else if (pure == c->midiLearner.state->mute.getValue()) {
-                       u::log::print("  >>> mute ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::toggleMuteChannel(c->id, Thread::MIDI);
-               }               
-               else if (pure == c->midiLearner.state->kill.getValue()) {
-                       u::log::print("  >>> kill ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::killChannel(c->id, Thread::MIDI);
-               }               
-               else if (pure == c->midiLearner.state->arm.getValue()) {
-                       u::log::print("  >>> arm ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::toggleArmChannel(c->id, Thread::MIDI);
+               else if (pure == c.midiLearner.kill.getValue())
+               {
+                       u::log::print("  >>> kill ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::killChannel(c.id, Thread::MIDI);
                }
-               else if (pure == c->midiLearner.state->solo.getValue()) {
-                       u::log::print("  >>> solo ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::toggleSoloChannel(c->id, Thread::MIDI);
+               else if (pure == c.midiLearner.arm.getValue())
+               {
+                       u::log::print("  >>> arm ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::toggleArmChannel(c.id, Thread::MIDI);
                }
-               else if (pure == c->midiLearner.state->volume.getValue()) {
-                       float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_VOLUME); 
-                       u::log::print("  >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n", 
-                               c->id, pure, midiEvent.getVelocity(), vf);
-                       c::events::setChannelVolume(c->id, vf, Thread::MIDI);
+               else if (pure == c.midiLearner.solo.getValue())
+               {
+                       u::log::print("  >>> solo ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::toggleSoloChannel(c.id, Thread::MIDI);
                }
-               else if (pure == c->midiLearner.state->pitch.getValue()) {
-                       float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_PITCH); 
+               else if (pure == c.midiLearner.volume.getValue())
+               {
+                       float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_VOLUME);
+                       u::log::print("  >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n",
+                           c.id, pure, midiEvent.getVelocity(), vf);
+                       c::events::setChannelVolume(c.id, vf, Thread::MIDI);
+               }
+               else if (pure == c.midiLearner.pitch.getValue())
+               {
+                       float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_PITCH);
                        u::log::print("  >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n",
-                               c->id, pure, midiEvent.getVelocity(), vf);
-                       c::events::setChannelPitch(c->id, vf, Thread::MIDI);
+                           c.id, pure, midiEvent.getVelocity(), vf);
+                       c::events::setChannelPitch(c.id, vf, Thread::MIDI);
                }
-               else if (pure == c->midiLearner.state->readActions.getValue()) {
-                       u::log::print("  >>> toggle read actions ch=%d (pure=0x%X)\n", c->id, pure);
-                       c::events::toggleReadActionsChannel(c->id, Thread::MIDI);
+               else if (pure == c.midiLearner.readActions.getValue())
+               {
+                       u::log::print("  >>> toggle read actions ch=%d (pure=0x%X)\n", c.id, pure);
+                       c::events::toggleReadActionsChannel(c.id, Thread::MIDI);
                }
 
 #ifdef WITH_VST
                /* Process learned plugins parameters. */
-               processPlugins_(c->pluginIds, midiEvent); 
+               processPlugins_(c.plugins, midiEvent);
 #endif
 
                /* Redirect raw MIDI message (pure + velocity) to plug-ins in armed
                channels. */
-
-               if (c->state->armed.load() == true)
-                       c::events::sendMidiToChannel(c->id, midiEvent, Thread::MIDI);
+               if (c.armed)
+                       c::events::sendMidiToChannel(c.id, midiEvent, Thread::MIDI);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void processMaster_(const MidiEvent& midiEvent)
 {
-       m::model::MidiInLock l(m::model::midiIn);
-
        const uint32_t       pure   = midiEvent.getRawNoVelocity();
-       const model::MidiIn* midiIn = model::midiIn.get();
+       const model::MidiIn& midiIn = model::get().midiIn;
 
-       if      (pure == midiIn->rewind) {
+       if (pure == midiIn.rewind)
+       {
                c::events::rewindSequencer(Thread::MIDI);
                u::log::print("  >>> rewind (master) (pure=0x%X)\n", pure);
        }
-       else if (pure == midiIn->startStop) {
+       else if (pure == midiIn.startStop)
+       {
                c::events::toggleSequencer(Thread::MIDI);
                u::log::print("  >>> startStop (master) (pure=0x%X)\n", pure);
        }
-       else if (pure == midiIn->actionRec) {
+       else if (pure == midiIn.actionRec)
+       {
                c::events::toggleActionRecording();
                u::log::print("  >>> actionRec (master) (pure=0x%X)\n", pure);
        }
-       else if (pure == midiIn->inputRec) {
+       else if (pure == midiIn.inputRec)
+       {
                c::events::toggleInputRecording();
                u::log::print("  >>> inputRec (master) (pure=0x%X)\n", pure);
        }
-       else if (pure == midiIn->metronome) {
+       else if (pure == midiIn.metronome)
+       {
                c::events::toggleMetronome();
                u::log::print("  >>> metronome (master) (pure=0x%X)\n", pure);
        }
-       else if (pure == midiIn->volumeIn) {
-               float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_VOLUME); 
+       else if (pure == midiIn.volumeIn)
+       {
+               float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_VOLUME);
                c::events::setMasterInVolume(vf, Thread::MIDI);
                u::log::print("  >>> input volume (master) (pure=0x%X, value=%d, float=%f)\n",
-                       pure, midiEvent.getVelocity(), vf);
+                   pure, midiEvent.getVelocity(), vf);
        }
-       else if (pure == midiIn->volumeOut) {
-               float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_VOLUME); 
+       else if (pure == midiIn.volumeOut)
+       {
+               float vf = u::math::map(midiEvent.getVelocity(), G_MAX_VELOCITY, G_MAX_VOLUME);
                c::events::setMasterOutVolume(vf, Thread::MIDI);
                u::log::print("  >>> output volume (master) (pure=0x%X, value=%d, float=%f)\n",
-                       pure, midiEvent.getVelocity(), vf);
+                   pure, midiEvent.getVelocity(), vf);
        }
-       else if (pure == midiIn->beatDouble) {
+       else if (pure == midiIn.beatDouble)
+       {
                c::events::multiplyBeats();
                u::log::print("  >>> sequencer x2 (master) (pure=0x%X)\n", pure);
        }
-       else if (pure == midiIn->beatHalf) {
+       else if (pure == midiIn.beatHalf)
+       {
                c::events::divideBeats();
                u::log::print("  >>> sequencer /2 (master) (pure=0x%X)\n", pure);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void learnChannel_(MidiEvent e, int param, ID channelId, std::function<void()> doneCb)
 {
        if (!isChannelMidiInAllowed_(channelId, e.getChannel()))
-               return; 
+               return;
 
        uint32_t raw = e.getRawNoVelocity();
 
-       model::onGet(model::channels, channelId, [param, raw](Channel& c)
-       {       
-               switch (param) {
-                       case G_MIDI_IN_KEYPRESS:     c.midiLearner.state->keyPress.setValue(raw);    break;
-                       case G_MIDI_IN_KEYREL:       c.midiLearner.state->keyRelease.setValue(raw);  break;
-                       case G_MIDI_IN_KILL:         c.midiLearner.state->kill.setValue(raw);        break;
-                       case G_MIDI_IN_ARM:          c.midiLearner.state->arm.setValue(raw);         break;
-                       case G_MIDI_IN_MUTE:         c.midiLearner.state->mute.setValue(raw);        break;
-                       case G_MIDI_IN_SOLO:         c.midiLearner.state->solo.setValue(raw);        break;
-                       case G_MIDI_IN_VOLUME:       c.midiLearner.state->volume.setValue(raw);      break;
-                       case G_MIDI_IN_PITCH:        c.midiLearner.state->pitch.setValue(raw);       break;
-                       case G_MIDI_IN_READ_ACTIONS: c.midiLearner.state->readActions.setValue(raw); break;
-                       case G_MIDI_OUT_L_PLAYING:   c.midiLighter.state->playing.setValue(raw);     break;
-                       case G_MIDI_OUT_L_MUTE:      c.midiLighter.state->mute.setValue(raw);        break;
-                       case G_MIDI_OUT_L_SOLO:      c.midiLighter.state->solo.setValue(raw);        break;
-               }
-       });
+       channel::Data& ch = model::get().getChannel(channelId);
+
+       switch (param)
+       {
+       case G_MIDI_IN_KEYPRESS:
+               ch.midiLearner.keyPress.setValue(raw);
+               break;
+       case G_MIDI_IN_KEYREL:
+               ch.midiLearner.keyRelease.setValue(raw);
+               break;
+       case G_MIDI_IN_KILL:
+               ch.midiLearner.kill.setValue(raw);
+               break;
+       case G_MIDI_IN_ARM:
+               ch.midiLearner.arm.setValue(raw);
+               break;
+       case G_MIDI_IN_MUTE:
+               ch.midiLearner.mute.setValue(raw);
+               break;
+       case G_MIDI_IN_SOLO:
+               ch.midiLearner.solo.setValue(raw);
+               break;
+       case G_MIDI_IN_VOLUME:
+               ch.midiLearner.volume.setValue(raw);
+               break;
+       case G_MIDI_IN_PITCH:
+               ch.midiLearner.pitch.setValue(raw);
+               break;
+       case G_MIDI_IN_READ_ACTIONS:
+               ch.midiLearner.readActions.setValue(raw);
+               break;
+       case G_MIDI_OUT_L_PLAYING:
+               ch.midiLighter.playing.setValue(raw);
+               break;
+       case G_MIDI_OUT_L_MUTE:
+               ch.midiLighter.mute.setValue(raw);
+               break;
+       case G_MIDI_OUT_L_SOLO:
+               ch.midiLighter.solo.setValue(raw);
+               break;
+       }
+
+       model::swap(model::SwapType::SOFT);
 
        stopLearn();
        doneCb();
 }
 
-
 void learnMaster_(MidiEvent e, int param, std::function<void()> doneCb)
 {
        if (!isMasterMidiInAllowed_(e.getChannel()))
@@ -274,35 +294,55 @@ void learnMaster_(MidiEvent e, int param, std::function<void()> doneCb)
 
        uint32_t raw = e.getRawNoVelocity();
 
-       model::onSwap(model::midiIn, [param, raw](model::MidiIn& m)
+       switch (param)
        {
-               switch (param) {
-                       case G_MIDI_IN_REWIND:      m.rewind     = raw; break;
-                       case G_MIDI_IN_START_STOP:  m.startStop  = raw; break;
-                       case G_MIDI_IN_ACTION_REC:  m.actionRec  = raw; break;
-                       case G_MIDI_IN_INPUT_REC:   m.inputRec   = raw; break;
-                       case G_MIDI_IN_METRONOME:   m.metronome  = raw; break;
-                       case G_MIDI_IN_VOLUME_IN:   m.volumeIn   = raw; break;
-                       case G_MIDI_IN_VOLUME_OUT:  m.volumeOut  = raw; break;
-                       case G_MIDI_IN_BEAT_DOUBLE: m.beatDouble = raw; break;
-                       case G_MIDI_IN_BEAT_HALF:   m.beatHalf   = raw; break;
-               }
-       });
+       case G_MIDI_IN_REWIND:
+               model::get().midiIn.rewind = raw;
+               break;
+       case G_MIDI_IN_START_STOP:
+               model::get().midiIn.startStop = raw;
+               break;
+       case G_MIDI_IN_ACTION_REC:
+               model::get().midiIn.actionRec = raw;
+               break;
+       case G_MIDI_IN_INPUT_REC:
+               model::get().midiIn.inputRec = raw;
+               break;
+       case G_MIDI_IN_METRONOME:
+               model::get().midiIn.metronome = raw;
+               break;
+       case G_MIDI_IN_VOLUME_IN:
+               model::get().midiIn.volumeIn = raw;
+               break;
+       case G_MIDI_IN_VOLUME_OUT:
+               model::get().midiIn.volumeOut = raw;
+               break;
+       case G_MIDI_IN_BEAT_DOUBLE:
+               model::get().midiIn.beatDouble = raw;
+               break;
+       case G_MIDI_IN_BEAT_HALF:
+               model::get().midiIn.beatHalf = raw;
+               break;
+       }
+
+       model::swap(model::SwapType::SOFT);
 
        stopLearn();
        doneCb();
 }
 
-
 #ifdef WITH_VST
 
 void learnPlugin_(MidiEvent e, std::size_t paramIndex, ID pluginId, std::function<void()> doneCb)
 {
-       model::onGet(model::plugins, pluginId, [&](Plugin& p)
-       {
-               assert(paramIndex < p.midiInParams.size());
-               p.midiInParams[paramIndex].setValue(e.getRawNoVelocity());
-       });
+       model::DataLock lock(model::SwapType::NONE);
+
+       Plugin* plugin = model::find<Plugin>(pluginId);
+
+       assert(plugin != nullptr);
+       assert(paramIndex < plugin->midiInParams.size());
+
+       plugin->midiInParams[paramIndex].setValue(e.getRawNoVelocity());
 
        stopLearn();
        doneCb();
@@ -310,81 +350,68 @@ void learnPlugin_(MidiEvent e, std::size_t paramIndex, ID pluginId, std::functio
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void triggerSignalCb_()
 {
-       if (signalCb_ == nullptr) 
+       if (signalCb_ == nullptr)
                return;
        signalCb_();
        signalCb_ = nullptr;
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void startChannelLearn(int param, ID channelId, std::function<void()> f)
 {
        learnCb_ = [=](m::MidiEvent e) { learnChannel_(e, param, channelId, f); };
 }
 
-
-void startMasterLearn (int param, std::function<void()> f)
+void startMasterLearn(int param, std::function<void()> f)
 {
        learnCb_ = [=](m::MidiEvent e) { learnMaster_(e, param, f); };
 }
 
-
 #ifdef WITH_VST
 
-void startPluginLearn (std::size_t paramIndex, ID pluginId, std::function<void()> f)
+void startPluginLearn(std::size_t paramIndex, ID pluginId, std::function<void()> f)
 {
        learnCb_ = [=](m::MidiEvent e) { learnPlugin_(e, paramIndex, pluginId, f); };
 }
 
 #endif
 
-
 void stopLearn()
 {
        learnCb_ = nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearMasterLearn(int param, std::function<void()> f)
 {
        learnMaster_(MidiEvent(), param, f); // Empty event (0x0)
 }
 
-
 void clearChannelLearn(int param, ID channelId, std::function<void()> f)
 {
        learnChannel_(MidiEvent(), param, channelId, f); // Empty event (0x0)
 }
 
-
 #ifdef WITH_VST
 
-void clearPluginLearn (std::size_t paramIndex, ID pluginId, std::function<void()> f)
+void clearPluginLearn(std::size_t paramIndex, ID pluginId, std::function<void()> f)
 {
        learnPlugin_(MidiEvent(), paramIndex, pluginId, f); // Empty event (0x0)
 }
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void dispatch(int byte1, int byte2, int byte3)
 {
        /* Here we want to catch two things: a) note on/note off from a keyboard and 
@@ -395,8 +422,8 @@ void dispatch(int byte1, int byte2, int byte3)
        MidiEvent midiEvent(byte1, byte2, byte3);
        midiEvent.fixVelocityZero();
 
-       u::log::print("[midiDispatcher] MIDI received - 0x%X (chan %d)\n", midiEvent.getRaw(), 
-               midiEvent.getChannel());
+       u::log::print("[midiDispatcher] MIDI received - 0x%X (chan %d)\n", midiEvent.getRaw(),
+           midiEvent.getChannel());
 
        /* Start dispatcher. If midi learn is on don't parse channels, just learn 
        incoming MIDI signal. Learn callback wants 'pure' MIDI event, i.e. with
@@ -404,24 +431,26 @@ void dispatch(int byte1, int byte2, int byte3)
        then each channel in the stack. This way incoming signals don't get processed 
        by glue_* when MIDI learning is on. */
 
-       if (learnCb_ != nullptr) {
-               learnCb_(midiEvent);
-       }
-       else {
-               processMaster_(midiEvent);
-               processChannels_(midiEvent);
-               triggerSignalCb_();
-       }       
-}
+       std::function<void()> f = [midiEvent]() {
+               if (learnCb_ != nullptr)
+               {
+                       learnCb_(midiEvent);
+               }
+               else
+               {
+                       processMaster_(midiEvent);
+                       processChannels_(midiEvent);
+                       triggerSignalCb_();
+               }
+       };
 
+       eventDispatcher::pumpMidiEvent({eventDispatcher::EventType::FUNCTION, 0, 0, f});
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void setSignalCallback(std::function<void()> f)
 {
        signalCb_ = f;
 }
-
-}}} // giada::m::midiDispatcher::
-
+} // namespace giada::m::midiDispatcher
index 45f79e817b2e9baedfff771cc8a73e8ccead6946..531aef7371448dfd384335b9b7a9fa0412be561f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MIDI_DISPATCHER_H
 #define G_MIDI_DISPATCHER_H
 
-
-#include <functional>
-#include <cstdint>
-#include "core/model/model.h"
 #include "core/midiEvent.h"
+#include "core/model/model.h"
 #include "core/types.h"
+#include <cstdint>
+#include <functional>
 
-
-namespace giada {
-namespace m {
-namespace midiDispatcher
+namespace giada::m::midiDispatcher
 {
 void startChannelLearn(int param, ID channelId, std::function<void()> f);
-void startMasterLearn (int param, std::function<void()> f);
+void startMasterLearn(int param, std::function<void()> f);
 void stopLearn();
-void clearMasterLearn (int param, std::function<void()> f);
+void clearMasterLearn(int param, std::function<void()> f);
 void clearChannelLearn(int param, ID channelId, std::function<void()> f);
 #ifdef WITH_VST
-void startPluginLearn (std::size_t paramIndex, ID pluginId, std::function<void()> f);
-void clearPluginLearn (std::size_t paramIndex, ID pluginId, std::function<void()> f);
+void startPluginLearn(std::size_t paramIndex, ID pluginId, std::function<void()> f);
+void clearPluginLearn(std::size_t paramIndex, ID pluginId, std::function<void()> f);
 #endif
 
 void dispatch(int byte1, int byte2, int byte3);
 
 void setSignalCallback(std::function<void()> f);
-}}} // giada::m::midiDispatcher::
-
+} // namespace giada::m::midiDispatcher
 
 #endif
index a22d987f9c926ffd910e5b8e51e53e8fd4f3d398..4607111485a6ec700ae088d2674c47af77f74155 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
+#include "midiEvent.h"
 #include "const.h"
 #include "utils/math.h"
-#include "midiEvent.h"
-
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace m
 {
 namespace
 {
 constexpr int FLOAT_FACTOR = 10000;
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 MidiEvent::MidiEvent(uint32_t raw)
-: m_status  ((raw & 0xF0000000) >> 24)
-, m_channel ((raw & 0x0F000000) >> 24)
-, m_note    ((raw & 0x00FF0000) >> 16)
+: m_status((raw & 0xF0000000) >> 24)
+, m_channel((raw & 0x0F000000) >> 24)
+, m_note((raw & 0x00FF0000) >> 16)
 , m_velocity((raw & 0x0000FF00) >> 8)
-, m_delta   (0)  // not used
+, m_delta(0) // not used
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* static_cast to avoid ambiguity with MidiEvent(float). */
 MidiEvent::MidiEvent(int byte1, int byte2, int byte3)
 : MidiEvent(static_cast<uint32_t>((byte1 << 24) | (byte2 << 16) | (byte3 << 8) | (0x00)))
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-MidiEvent::MidiEvent(float v) 
+MidiEvent::MidiEvent(float v)
 : MidiEvent(ENVELOPE, 0, 0)
 {
        m_velocity = static_cast<int>(v * FLOAT_FACTOR);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void MidiEvent::setDelta(int d)
 {
        m_delta = d;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void MidiEvent::setChannel(int c)
 {
        assert(c >= 0 && c < G_MAX_MIDI_CHANS);
        m_channel = c;
 }
 
-
 void MidiEvent::setVelocity(int v)
 {
        assert(v >= 0 && v <= G_MAX_VELOCITY);
        m_velocity = v;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void MidiEvent::fixVelocityZero()
 {
        if (m_status == NOTE_ON && m_velocity == 0)
                m_status = NOTE_OFF;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int MidiEvent::getStatus() const
 {
        return m_status;
-}      
-
+}
 
 int MidiEvent::getChannel() const
 {
        return m_channel;
 }
 
-
 int MidiEvent::getNote() const
 {
        return m_note;
-}      
-
+}
 
 int MidiEvent::getVelocity() const
 {
        return m_velocity;
-}      
-
+}
 
 float MidiEvent::getVelocityFloat() const
 {
        return m_velocity / static_cast<float>(FLOAT_FACTOR);
 }
 
-
 bool MidiEvent::isNoteOnOff() const
 {
        return m_status == NOTE_ON || m_status == NOTE_OFF;
 }
 
-
 int MidiEvent::getDelta() const
 {
        return m_delta;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 uint32_t MidiEvent::getRaw() const
 {
        return (m_status << 24) | (m_channel << 24) | (m_note << 16) | (m_velocity << 8) | (0x00);
 }
 
-
 uint32_t MidiEvent::getRawNoVelocity() const
 {
        return (m_status << 24) | (m_channel << 24) | (m_note << 16) | (0x00 << 8) | (0x00);
 }
 
-
-}} // giada::m::
+} // namespace m
+} // namespace giada
index eefeb6c8ffe36c6cf6afb8de9ea97090fd8c1c8f..dfdede8044c7d0369259850896b5df4364486fa6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MIDI_EVENT_H
 #define G_MIDI_EVENT_H
 
-
 #include <cstdint>
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 class MidiEvent
 {
 public:
-
        static const int NOTE_ON   = 0x90;
        static const int NOTE_OFF  = 0x80;
        static const int NOTE_KILL = 0x70;
@@ -58,13 +55,13 @@ public:
 
        MidiEvent(float v);
 
-       int getStatus() const;  
-       int getChannel() const; 
-       int getNote() const;    
-       int getVelocity() const;
+       int   getStatus() const;
+       int   getChannel() const;
+       int   getNote() const;
+       int   getVelocity() const;
        float getVelocityFloat() const;
-       bool isNoteOnOff() const;       
-       int getDelta() const;
+       bool  isNoteOnOff() const;
+       int   getDelta() const;
 
        /* getRaw(), getRawNoVelocity()
        Returns the raw MIDI message. If getRawNoVelocity(), the velocity value is
@@ -86,15 +83,14 @@ public:
 
        void fixVelocityZero();
 
-private:
-
+  private:
        int m_status;
        int m_channel;
        int m_note;
        int m_velocity;
        int m_delta;
 };
-}} // giada::m::
-
+} // namespace m
+} // namespace giada
 
 #endif
index 6fd9d4721ff9887f91b51b42f44ca1bd931ca042..54dfcbf527d6cf0aeefa5fbdf730111340849592 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #include "midiLearnParam.h"
 
-
 namespace giada::m
 {
 MidiLearnParam::MidiLearnParam()
-: m_param(0x0)
-, m_index(0) 
+: m_param(0)
+, m_index(0)
 {
 }
 
-
 MidiLearnParam::MidiLearnParam(uint32_t v, std::size_t index)
 : m_param(v)
-, m_index(index) 
+, m_index(index)
 {
 }
 
-
-MidiLearnParam::MidiLearnParam(const MidiLearnParam& o)
-: m_param(o.m_param.load(std::memory_order_relaxed))
-, m_index(o.m_index) 
-{
-}
-
-
 /* -------------------------------------------------------------------------- */
 
-
 uint32_t MidiLearnParam::getValue() const
 {
-    return m_param.load(std::memory_order_relaxed);
+       return m_param.load();
 }
 
-
 void MidiLearnParam::setValue(uint32_t v)
 {
-    m_param.store(v, std::memory_order_relaxed);
+       m_param.store(v);
 }
 
-
 std::size_t MidiLearnParam::getIndex() const
 {
-    return m_index;
+       return m_index;
 }
-} // giada::m::
\ No newline at end of file
+} // namespace giada::m
\ No newline at end of file
index c5a86a04fa14156a0b7a648e6a7833e3f406c13f..b6f04304df071e3e688827790fbe9ef0ea2eadc7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MIDI_LEARN_PARAM_H
 #define G_MIDI_LEARN_PARAM_H
 
-
+#include "core/weakAtomic.h"
 #include <atomic>
 
-
 namespace giada::m
 {
 class MidiLearnParam
 {
 public:
-
        MidiLearnParam();
-       MidiLearnParam(uint32_t v, std::size_t index=0);
-       MidiLearnParam(const MidiLearnParam& o);
-
-    uint32_t getValue() const;
-    std::size_t getIndex() const;
-    void setValue(uint32_t v);
+       MidiLearnParam(uint32_t v, std::size_t index = 0);
+       MidiLearnParam(const MidiLearnParam& o) = default;
 
-private:
+       uint32_t    getValue() const;
+       std::size_t getIndex() const;
+       void        setValue(uint32_t v);
 
-    std::atomic<uint32_t> m_param;
-    std::size_t           m_index;
+  private:
+       WeakAtomic<uint32_t> m_param;
+       std::size_t          m_index;
 };
-} // giada::m::
-
+} // namespace giada::m
 
 #endif
index 0a481728caabdae8b8fc1abc352833f1e7abb953..240a8de4adcb11b3446e12a427cc4057e3b96707 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <fstream>
-#include <vector>
-#include <string>
-#include <cstring>
-#include <filesystem>
+#include "midiMapConf.h"
+#include "const.h"
 #include "deps/json/single_include/nlohmann/json.hpp"
-#include "utils/string.h"
-#include "utils/log.h"
 #include "utils/fs.h"
-#include "const.h"
-#include "midiMapConf.h"
-
+#include "utils/log.h"
+#include "utils/string.h"
+#include <cstring>
+#include <filesystem>
+#include <fstream>
+#include <string>
+#include <vector>
 
 namespace nl = nlohmann;
 
-
-namespace giada {
-namespace m {
+namespace giada
+{
+namespace m
+{
 namespace midimap
 {
 namespace
@@ -65,10 +64,8 @@ bool readInitCommands_(const nl::json& j)
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool readCommand_(const nl::json& j, Message& m, const std::string& key)
 {
        if (j.find(key) == j.end())
@@ -82,10 +79,8 @@ bool readCommand_(const nl::json& j, Message& m, const std::string& key)
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void parse_(Message& message)
 {
        /* Remove '0x' part from the original string. */
@@ -101,8 +96,10 @@ void parse_(Message& message)
        zeros. */
 
        std::string output;
-       for (unsigned i=0, p=24; i<input.length(); i++, p-=4) {
-               if (input[i] == 'n') {
+       for (unsigned i = 0, p = 24; i < input.length(); i++, p -= 4)
+       {
+               if (input[i] == 'n')
+               {
                        output += '0';
                        if (message.offset == -1) // do it once
                                message.offset = p;
@@ -116,24 +113,20 @@ void parse_(Message& message)
        message.value = strtoul(output.c_str(), nullptr, 16);
 
        u::log::print("[parse] parsed chan=%d valueStr=%s value=%#x, offset=%d\n",
-                       message.channel, message.valueStr, message.value, message.offset);
+           message.channel, message.valueStr, message.value, message.offset);
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 MidiMap                  midimap;
 std::string              midimapsPath;
 std::vector<std::string> maps;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
        midimapsPath = u::fs::getHomePath() + G_SLASH + "midimaps" + G_SLASH;
@@ -141,14 +134,16 @@ void init()
        /* scan dir of midi maps and load the filenames into <>maps. */
 
        u::log::print("[midiMapConf::init] scanning midimaps directory '%s'...\n",
-               midimapsPath);
+           midimapsPath);
 
-       if (!std::filesystem::exists(midimapsPath)) {
+       if (!std::filesystem::exists(midimapsPath))
+       {
                u::log::print("[midiMapConf::init] unable to scan midimaps directory!\n");
                return;
        }
 
-       for (const auto& d : std::filesystem::directory_iterator(midimapsPath)) {
+       for (const auto& d : std::filesystem::directory_iterator(midimapsPath))
+       {
                // TODO - check if is a valid midimap file (verify headers)
                if (!d.is_regular_file())
                        continue;
@@ -159,31 +154,26 @@ void init()
        u::log::print("[midiMapConf::init] total midimaps found: %d\n", maps.size());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setDefault()
 {
        midimap = MidiMap();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isDefined(const Message& m)
 {
        return m.offset != -1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int read(const std::string& file)
 {
-       if (file.empty()) {
+       if (file.empty())
+       {
                u::log::print("[midiMapConf::read] midimap not specified, nothing to do\n");
                return MIDIMAP_NOT_SPECIFIED;
        }
@@ -198,18 +188,30 @@ int read(const std::string& file)
 
        midimap.brand  = j[MIDIMAP_KEY_BRAND];
        midimap.device = j[MIDIMAP_KEY_DEVICE];
-       
-       if (!readInitCommands_(j)) return MIDIMAP_UNREADABLE;
-       if (readCommand_(j, midimap.muteOn,           MIDIMAP_KEY_MUTE_ON))  parse_(midimap.muteOn);
-       if (readCommand_(j, midimap.muteOff,          MIDIMAP_KEY_MUTE_OFF)) parse_(midimap.muteOff);
-       if (readCommand_(j, midimap.soloOn,           MIDIMAP_KEY_SOLO_ON))  parse_(midimap.soloOn);
-       if (readCommand_(j, midimap.soloOff,          MIDIMAP_KEY_SOLO_OFF)) parse_(midimap.soloOff);
-       if (readCommand_(j, midimap.waiting,          MIDIMAP_KEY_WAITING))  parse_(midimap.waiting);
-       if (readCommand_(j, midimap.playing,          MIDIMAP_KEY_PLAYING))  parse_(midimap.playing);
-       if (readCommand_(j, midimap.stopping,         MIDIMAP_KEY_STOPPING)) parse_(midimap.stopping);
-       if (readCommand_(j, midimap.stopped,          MIDIMAP_KEY_STOPPED))  parse_(midimap.stopped);
-       if (readCommand_(j, midimap.playingInaudible, MIDIMAP_KEY_PLAYING_INAUDIBLE))  parse_(midimap.playingInaudible);
+
+       if (!readInitCommands_(j))
+               return MIDIMAP_UNREADABLE;
+       if (readCommand_(j, midimap.muteOn, MIDIMAP_KEY_MUTE_ON))
+               parse_(midimap.muteOn);
+       if (readCommand_(j, midimap.muteOff, MIDIMAP_KEY_MUTE_OFF))
+               parse_(midimap.muteOff);
+       if (readCommand_(j, midimap.soloOn, MIDIMAP_KEY_SOLO_ON))
+               parse_(midimap.soloOn);
+       if (readCommand_(j, midimap.soloOff, MIDIMAP_KEY_SOLO_OFF))
+               parse_(midimap.soloOff);
+       if (readCommand_(j, midimap.waiting, MIDIMAP_KEY_WAITING))
+               parse_(midimap.waiting);
+       if (readCommand_(j, midimap.playing, MIDIMAP_KEY_PLAYING))
+               parse_(midimap.playing);
+       if (readCommand_(j, midimap.stopping, MIDIMAP_KEY_STOPPING))
+               parse_(midimap.stopping);
+       if (readCommand_(j, midimap.stopped, MIDIMAP_KEY_STOPPED))
+               parse_(midimap.stopped);
+       if (readCommand_(j, midimap.playingInaudible, MIDIMAP_KEY_PLAYING_INAUDIBLE))
+               parse_(midimap.playingInaudible);
 
        return MIDIMAP_READ_OK;
 }
-}}} // giada::m::midimap::
+} // namespace midimap
+} // namespace m
+} // namespace giada
index 4d348bdf996bd8051625125fe279baf910246dfe..546d2a0fd7bcf02f31bda53e0bfa296bf825cf7d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MIDIMAPCONF_H
 #define G_MIDIMAPCONF_H
 
-
-#include <vector>
 #include <string>
+#include <vector>
 
-
-namespace giada {
-namespace m {
+namespace giada
+{
+namespace m
+{
 namespace midimap
 {
 struct Message
 {
-    int         channel  = 0;
-    std::string valueStr = "";
+       int         channel  = 0;
+       std::string valueStr = "";
        int         offset   = -1;
        uint32_t    value    = 0;
 };
 
-
 struct MidiMap
 {
-    std::string brand;
-    std::string device;
-    std::vector<Message> initCommands;
-    Message muteOn;
-    Message muteOff;
-    Message soloOn;
-    Message soloOff;
-    Message waiting;
-    Message playing;
-    Message stopping;
-    Message stopped;
-    Message playingInaudible;
+       std::string          brand;
+       std::string          device;
+       std::vector<Message> initCommands;
+       Message              muteOn;
+       Message              muteOff;
+       Message              soloOn;
+       Message              soloOff;
+       Message              waiting;
+       Message              playing;
+       Message              stopping;
+       Message              stopped;
+       Message              playingInaudible;
 };
 
-
 /* -------------------------------------------------------------------------- */
 
 /* midimap
@@ -81,7 +78,6 @@ represents a .giadamap filename. */
 
 extern std::vector<std::string> maps;
 
-
 /* -------------------------------------------------------------------------- */
 
 /* init
@@ -103,6 +99,8 @@ bool isDefined(const Message& msg);
 Reads a midi map from file 'file'. */
 
 int read(const std::string& file);
-}}} // giada::m::midimap::
+} // namespace midimap
+} // namespace m
+} // namespace giada
 
 #endif
index 181b4527a7d5fa9886c3e660d3ea3781b08d00d0..6e292eef22340431ae61ab794721dc5370ab7603 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <cstring>
-#include "deps/rtaudio/RtAudio.h"
-#include "utils/log.h"
-#include "utils/math.h"
-#include "core/model/model.h"
-#include "core/wave.h"
-#include "core/kernelAudio.h"
-#include "core/recorder.h"
-#include "core/recManager.h"
-#include "core/plugins/pluginHost.h"
-#include "core/conf.h"
-#include "core/mixerHandler.h"
-#include "core/clock.h"
-#include "core/const.h"
+#include "core/mixer.h"
 #include "core/audioBuffer.h"
-#include "core/action.h"
+#include "core/const.h"
+#include "core/model/model.h"
 #include "core/sequencer.h"
-#include "core/mixer.h"
-
+#include "utils/log.h"
+#include "utils/math.h"
 
-namespace giada {
-namespace m {
-namespace mixer
+namespace giada::m::mixer
 {
 namespace
 {
@@ -72,49 +56,74 @@ Callback triggered when the input signal level reaches a threshold. */
 
 std::function<void()> signalCb_ = nullptr;
 
-std::atomic<bool> processing_(false);
-std::atomic<bool> active_(false);
+/* endOfRecCb_
+Callback triggered when the end of the internal recording buffer has been 
+reached.*/
 
-/* eventBuffer_
-Buffer of events sent to channels for event parsing. This is filled with Events
-coming from the two event queues.*/
+std::function<void()> endOfRecCb_ = nullptr;
 
-EventBuffer eventBuffer_;
+/* signalCbFired_
+Boolean guard to determine whether the signal callback has been fired or not.
+Checking if signalCb_ != null (i.e. a callback is still present, so not fired
+yet) is not enough, as the actual firing takes place on a different thread in
+a slightly different moment (see fireSignalCb_() below). */
 
+bool signalCbFired_ = false;
 
 /* -------------------------------------------------------------------------- */
 
+/* fireSignalCb_
+Invokes the signal callback. This is done by pumping a FUNCTION event to the
+event dispatcher, rather than invoking the callback directly. This is done on
+purpose: the callback might (and surely will) contain blocking stuff from 
+model:: that the realtime thread cannot perform directly. */
 
-bool isChannelAudible_(const Channel& c)
+void fireSignalCb_()
 {
-    if (c.getType() == ChannelType::MASTER || c.getType() == ChannelType::PREVIEW)
-        return true;
-    if (c.state->mute.load() == true)
-        return false;
-    model::MixerLock ml(model::mixer);
-    bool hasSolos = model::mixer.get()->hasSolos;
-    return !hasSolos || (hasSolos && c.state->solo.load() == true);
+       eventDispatcher::pumpUIevent({eventDispatcher::EventType::FUNCTION, 0, 0, []() {
+                                             signalCb_();
+                                             signalCb_ = nullptr;
+                                     }});
 }
 
+/* -------------------------------------------------------------------------- */
+
+/* fireEndOfRecCb_
+Same rationale of fireSignalCb_, for the endOfRecCb_ callback. */
+
+void fireEndOfRecCb_()
+{
+       eventDispatcher::pumpUIevent({eventDispatcher::EventType::FUNCTION, 0, 0, []() {
+                                             endOfRecCb_();
+                                             endOfRecCb_ = nullptr;
+                                     }});
+}
 
 /* -------------------------------------------------------------------------- */
 
 /* lineInRec
-Records from line in. */
+Records from line in. 'maxFrames' determines how many frames to record before
+the internal tracker loops over. The value changes whether you are recording
+in RIGID or FREE mode. */
 
-void lineInRec_(const AudioBuffer& inBuf)
+void lineInRec_(const AudioBuffer& inBuf, Frame maxFrames, float inVol)
 {
-       if (!recManager::isRecordingInput() || !kernelAudio::isInputEnabled())
+       assert(maxFrames <= recBuffer_.countFrames());
+
+       if (inputTracker_ >= maxFrames && endOfRecCb_ != nullptr)
+       {
+               fireEndOfRecCb_();
                return;
-       
-       float inVol        = mh::getInVol();
-       int   framesInLoop = clock::getFramesInLoop();
+       }
 
-       for (int i = 0; i < inBuf.countFrames(); i++, inputTracker_++)
-               for (int j = 0; j < inBuf.countChannels(); j++)
-                       recBuffer_[inputTracker_ % framesInLoop][j] += inBuf[i][j] * inVol;  // adding: overdub!
-}
+       const Frame framesToCopy = -1; // copy everything
+       const Frame srcOffset    = 0;
+       const Frame destOffset   = inputTracker_ % maxFrames; // loop over at maxFrames
 
+       recBuffer_.sum(inBuf, framesToCopy, srcOffset, destOffset, inVol);
+
+       inputTracker_ += inBuf.countFrames();
+}
 
 /* -------------------------------------------------------------------------- */
 
@@ -122,108 +131,76 @@ void lineInRec_(const AudioBuffer& inBuf)
 Computes line in peaks and prepares the internal working buffer for input
 recording. */
 
-void processLineIn_(const AudioBuffer& inBuf)
+void processLineIn_(const model::Mixer& mixer, const AudioBuffer& inBuf,
+    float inVol, float recTriggerLevel)
 {
-       if (!kernelAudio::isInputEnabled())
-               return;
+       float peak = inBuf.getPeak();
 
-       peakIn.store(inBuf.getPeak());
-
-       if (signalCb_ != nullptr && u::math::linearToDB(peakIn) > conf::conf.recTriggerLevel) {
-G_DEBUG("Signal > threshold!");
-               signalCb_();
-               signalCb_ = nullptr;
+       if (signalCb_ != nullptr && u::math::linearToDB(peak) > recTriggerLevel && !signalCbFired_)
+       {
+               G_DEBUG("Signal > threshold!");
+               fireSignalCb_();
+               signalCbFired_ = true;
        }
 
+       mixer.state->peakIn.store(peak);
+
        /* Prepare the working buffer for input stream, which will be processed 
        later on by the Master Input Channel with plug-ins. */
-       
+
        assert(inBuf.countChannels() <= inBuffer_.countChannels());
 
-       model::MixerLock lock(model::mixer);
-       inBuffer_.copyData(inBuf, mh::getInVol());
+       inBuffer_.set(inBuf, inVol);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void fillEventBuffer_()
+void processChannels_(const model::Layout& layout, AudioBuffer& out, AudioBuffer& in)
 {
-       eventBuffer_.clear();
-
-       Event e;
-       while (UIevents.pop(e))   eventBuffer_.push_back(e);
-       while (MidiEvents.pop(e)) eventBuffer_.push_back(e);
-
-#ifdef G_DEBUG_MODE
-       for (const Event& e : eventBuffer_)
-               G_DEBUG("Event type=" << (int) e.type << ", channel=" << e.action.channelId 
-                       << ", delta=" << e.delta << ", globalFrame=" << clock::getCurrentFrame());
-#endif
+       for (const channel::Data& c : layout.channels)
+               if (!c.isInternal())
+                       channel::render(c, &out, &in, isChannelAudible(c));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void processChannels_(AudioBuffer& out, AudioBuffer& in)
+void processSequencer_(const model::Layout& layout, AudioBuffer& out, const AudioBuffer& in)
 {
-       model::ChannelsLock lock(model::channels);
-
-       for (const Channel* c : model::channels) {
-               bool audible = isChannelAudible_(*c);   
-               c->parse(eventBuffer_, audible); 
-               if (c->getType() != ChannelType::MASTER) {
-                       c->advance(out.countFrames());
-                       c->render(&out, &in, audible);
-               }
-       }
-}
+       /* Advance sequencer first, then render it (rendering is just about
+       generating metronome audio). This way the metronome is aligned with 
+       everything else. */
 
+       const sequencer::EventBuffer& events = sequencer::advance(in.countFrames());
+       sequencer::render(out);
 
-/* -------------------------------------------------------------------------- */
+       /* No channel processing if layout is locked: another thread is changing
+    data (e.g. Plugins or Waves). */
 
+       if (layout.locked)
+               return;
 
-void processSequencer_(AudioBuffer& in)
-{
-       sequencer::parse(eventBuffer_);
-       if (clock::isActive()) {
-               if (clock::isRunning())
-                       sequencer::run(in.countFrames());
-               lineInRec_(in);
-       }
+       for (const channel::Data& c : layout.channels)
+               if (!c.isInternal())
+                       channel::advance(c, events);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void renderMasterIn_(AudioBuffer& in)
+void renderMasterIn_(const model::Layout& layout, AudioBuffer& in)
 {
-       model::ChannelsLock lock(model::channels);
-       model::get(model::channels, mixer::MASTER_IN_CHANNEL_ID).render(nullptr, &in, true);
+       channel::render(layout.getChannel(mixer::MASTER_IN_CHANNEL_ID), nullptr, &in, true);
 }
 
-void renderMasterOut_(AudioBuffer& out)
+void renderMasterOut_(const model::Layout& layout, AudioBuffer& out)
 {
-       model::ChannelsLock lock(model::channels);
-       model::get(model::channels, mixer::MASTER_OUT_CHANNEL_ID).render(&out, nullptr, true);
+       channel::render(layout.getChannel(mixer::MASTER_OUT_CHANNEL_ID), &out, nullptr, true);
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-/* prepareBuffers
-Cleans up every buffer. */
-
-void prepareBuffers_(AudioBuffer& outBuf)
+void renderPreview_(const model::Layout& layout, AudioBuffer& out)
 {
-       outBuf.clear();
-       inBuffer_.clear();
+       channel::render(layout.getChannel(mixer::PREVIEW_CHANNEL_ID), &out, nullptr, true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 /* limit_
@@ -231,203 +208,174 @@ Applies a very dumb hard limiter. */
 
 void limit_(AudioBuffer& outBuf)
 {
-       for (int i=0; i<outBuf.countFrames(); i++)
-               for (int j=0; j<outBuf.countChannels(); j++)
+       for (int i = 0; i < outBuf.countFrames(); i++)
+               for (int j = 0; j < outBuf.countChannels(); j++)
                        outBuf[i][j] = std::max(-1.0f, std::min(outBuf[i][j], 1.0f));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 /* finalizeOutput
 Last touches after the output has been rendered: apply inToOut if any, apply
 output volume, compute peak. */
 
-void finalizeOutput_(AudioBuffer& outBuf)
+void finalizeOutput_(const model::Mixer& mixer, AudioBuffer& outBuf,
+    const RenderInfo& info)
 {
-       bool  inToOut = mh::getInToOut();
-       float outVol  = mh::getOutVol();
-
-       if (inToOut)
-               outBuf.addData(inBuffer_, outVol);
+       if (info.inToOut)
+               outBuf.sum(inBuffer_, info.outVol);
        else
-               outBuf.applyGain(outVol);
+               outBuf.applyGain(info.outVol);
 
-       if (conf::conf.limitOutput)
+       if (info.limitOutput)
                limit_(outBuf);
-       
-       peakOut.store(outBuf.getPeak());
-}
-} // {anonymous}
 
+       mixer.state->peakOut.store(outBuf.getPeak());
+}
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-std::atomic<float> peakOut(0.0);
-std::atomic<float> peakIn(0.0);
-
-Queue<Event, G_MAX_QUEUE_EVENTS> UIevents;
-Queue<Event, G_MAX_QUEUE_EVENTS> MidiEvents;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void init(Frame framesInSeq, Frame framesInBuffer)
+void init(Frame maxFramesInLoop, Frame framesInBuffer)
 {
-       /* Allocate virtual inputs. recBuffer_ has variable size: it depends
-       on how many frames there are in sequencer. */
-       
-       recBuffer_.alloc(framesInSeq, G_MAX_IO_CHANS);
+       /* Allocate working buffers. recBuffer_ has variable size: it depends on how
+       many frames there are in the current loop. */
+
+       recBuffer_.alloc(maxFramesInLoop, G_MAX_IO_CHANS);
        inBuffer_.alloc(framesInBuffer, G_MAX_IO_CHANS);
 
-       u::log::print("[mixer::init] buffers ready - framesInSeq=%d, framesInBuffer=%d\n", 
-               framesInSeq, framesInBuffer);
+       u::log::print("[mixer::init] buffers ready - maxFramesInLoop=%d, framesInBuffer=%d\n",
+           maxFramesInLoop, framesInBuffer);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void enable()
-{ 
-       active_.store(true); 
+{
+       model::get().mixer.state->active.store(true);
        u::log::print("[mixer::enable] enabled\n");
 }
 
-
-void disable() 
-{ 
-       active_.store(false);
-       while (processing_.load() == true) 
-               std::this_thread::sleep_for(std::chrono::milliseconds(50));
+void disable()
+{
+       model::get().mixer.state->active.store(false);
+       while (model::isLocked())
+               ;
        u::log::print("[mixer::disable] disabled\n");
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void allocRecBuffer(Frame frames)
 {
        recBuffer_.alloc(frames, G_MAX_IO_CHANS);
 }
 
-
 void clearRecBuffer()
 {
        recBuffer_.clear();
 }
 
-
 const AudioBuffer& getRecBuffer()
 {
        return recBuffer_;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize, 
-       double /*streamTime*/, RtAudioStreamStatus /*status*/, void* /*userData*/)
+int render(AudioBuffer& out, const AudioBuffer& in, const RenderInfo& info)
 {
-       if (!kernelAudio::isReady() || active_.load() == false)
-               return 0;
+       const model::Lock   rtLock = model::get_RT();
+       const model::Mixer& mixer  = rtLock.get().mixer;
 
-       processing_.store(true);
-
-#ifdef WITH_AUDIO_JACK
-       if (kernelAudio::getAPI() == G_SYS_API_JACK)
-               clock::recvJackSync();
-#endif
-
-       AudioBuffer out, in;
-       out.setData(static_cast<float*>(outBuf), bufferSize, G_MAX_IO_CHANS);
-       if (kernelAudio::isInputEnabled())
-               in.setData(static_cast<float*>(inBuf), bufferSize, conf::conf.channelsInCount);
+       inBuffer_.clear();
 
        /* Reset peak computation. */
 
-       peakOut = 0.0;
-       peakIn  = 0.0;
+       mixer.state->peakOut.store(0.0);
+       mixer.state->peakIn.store(0.0);
 
-       prepareBuffers_(out);
-       processLineIn_(in);
+       /* Process line IN if input has been enabled in KernelAudio. */
 
-//out[0][0] = 3.0f;
-
-       renderMasterIn_(inBuffer_);
-
-       fillEventBuffer_();
-       processSequencer_(inBuffer_);
-       processChannels_(out, inBuffer_);
+       if (info.hasInput)
+       {
+               processLineIn_(mixer, in, info.inVol, info.recTriggerLevel);
+               renderMasterIn_(rtLock.get(), inBuffer_);
+       }
 
-       renderMasterOut_(out);
+       /* Record input audio and advance the sequencer only if clock is active:
+       can't record stuff with the sequencer off. */
 
-       /* Advance sequencer only when rendering is done. */
+       if (info.isClockActive)
+       {
+               if (info.canLineInRec)
+                       lineInRec_(in, info.maxFramesToRec, info.inVol);
+               if (info.isClockRunning)
+                       processSequencer_(rtLock.get(), out, inBuffer_);
+       }
 
-       if (clock::isActive())
-               sequencer::advance(out);
+       /* Channel processing. Don't do it if layout is locked: another thread is 
+       changing data (e.g. Plugins or Waves). */
 
-       /* Post processing. */
+       if (!rtLock.get().locked)
+               processChannels_(rtLock.get(), out, inBuffer_);
 
-       finalizeOutput_(out);
+       /* Render remaining internal channels. */
 
-       /* Unset data in buffers. If you don't do this, buffers go out of scope and
-       destroy memory allocated by RtAudio ---> havoc. */
+       renderMasterOut_(rtLock.get(), out);
+       renderPreview_(rtLock.get(), out);
 
-       out.setData(nullptr, 0, 0);
-       in.setData (nullptr, 0, 0);
+       /* Post processing. */
 
-       processing_.store(false);
+       finalizeOutput_(mixer, out, info);
 
        return 0;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void close()
+void startInputRec(Frame from)
 {
-       clock::setStatus(ClockStatus::STOPPED);
+       inputTracker_  = from;
+       signalCbFired_ = false;
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void startInputRec()
+Frame stopInputRec()
 {
-       /* Start inputTracker_ from the current frame, not the beginning. */
-       inputTracker_ = clock::getCurrentFrame();
+       Frame ret      = inputTracker_;
+       inputTracker_  = 0;
+       signalCbFired_ = false;
+       return ret;
 }
 
+/* -------------------------------------------------------------------------- */
 
-void stopInputRec()
-{
-       inputTracker_ = 0;
-}
-
+void setSignalCallback(std::function<void()> f) { signalCb_ = f; }
+void setEndOfRecCallback(std::function<void()> f) { endOfRecCb_ = f; }
 
 /* -------------------------------------------------------------------------- */
 
-
-void setSignalCallback(std::function<void()> f)
+bool isChannelAudible(const channel::Data& c)
 {
-       signalCb_ = f;
+       if (c.isInternal())
+               return true;
+       if (c.mute)
+               return false;
+       bool hasSolos = model::get().mixer.hasSolos;
+       return !hasSolos || (hasSolos && c.solo);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+float getPeakOut() { return m::model::get().mixer.state->peakOut.load(); }
+float getPeakIn() { return m::model::get().mixer.state->peakIn.load(); }
+
+/* -------------------------------------------------------------------------- */
 
-void pumpEvent(Event e)
+RecordInfo getRecordInfo()
 {
-       eventBuffer_.push_back(e);
+       return {inputTracker_, recBuffer_.countFrames()};
 }
-}}} // giada::m::mixer::
+} // namespace giada::m::mixer
index 3651af19af156f8ec61f727929a711afb6c8888d..b143274b7a1d752eb5783c13df485cdcd95426da 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MIXER_H
 #define G_MIXER_H
 
-
-#include <atomic>
-#include <functional>
-#include <vector>
-#include "deps/rtaudio/RtAudio.h"
-#include "core/ringBuffer.h"
+#include "core/midiEvent.h"
+#include "core/queue.h"
 #include "core/recorder.h"
+#include "core/ringBuffer.h"
 #include "core/types.h"
-#include "core/queue.h"
-#include "core/midiEvent.h"
-
+#include "deps/rtaudio/RtAudio.h"
+#include <functional>
 
-namespace giada {
-namespace m
+namespace giada::m
 {
 struct Action;
-class Channel;
 class AudioBuffer;
-
-namespace mixer
+} // namespace giada::m
+namespace giada::m::channel
 {
-enum class EventType 
+struct Data;
+}
+namespace giada::m::mixer
 {
-       KEY_PRESS, 
-       KEY_RELEASE, 
-       KEY_KILL,
-       SEQUENCER_FIRST_BEAT, // 3
-       SEQUENCER_BAR,        // 4
-       SEQUENCER_START,      // 5
-       SEQUENCER_STOP,       // 6
-       SEQUENCER_REWIND,     // 7
-       SEQUENCER_REWIND_REQ, // 8
-       MIDI, 
-       ACTION, 
-       CHANNEL_TOGGLE_READ_ACTIONS,
-       CHANNEL_KILL_READ_ACTIONS,
-       CHANNEL_TOGGLE_ARM,
-       CHANNEL_MUTE,
-       CHANNEL_SOLO,
-       CHANNEL_VOLUME,
-       CHANNEL_PITCH,
-       CHANNEL_PAN
-};
-
-struct Event
-{
-       EventType type;
-       Frame     delta;
-       Action    action;
-};
-
-/* EventBuffer
-Alias for a RingBuffer containing events to be sent to engine. The double size
-is due to the presence of two distinct Queues for collecting events coming from
-other threads. See below. */
-
-using EventBuffer = RingBuffer<Event, G_MAX_QUEUE_EVENTS * 2>;
-
 constexpr int MASTER_OUT_CHANNEL_ID = 1;
 constexpr int MASTER_IN_CHANNEL_ID  = 2;
 constexpr int PREVIEW_CHANNEL_ID    = 3;
 
-extern std::atomic<float> peakOut; // TODO - move to model::
-extern std::atomic<float> peakIn;  // TODO - move to model::
+/* RenderInfo
+Struct of parameters passed to Mixer for rendering. */
 
-/* Channel Event queues
-Collect events coming from the UI or MIDI devices to be sent to channels. Our 
-poor's man Queue is a single-producer/single-consumer one, so we need two queues 
-for two writers. TODO - let's add a multi-producer queue sooner or later! */
+struct RenderInfo
+{
+       bool  isAudioReady;
+       bool  hasInput;
+       bool  isClockActive;
+       bool  isClockRunning;
+       bool  canLineInRec;
+       bool  limitOutput;
+       bool  inToOut;
+       Frame maxFramesToRec;
+       float outVol;
+       float inVol;
+       float recTriggerLevel;
+};
 
-extern Queue<Event, G_MAX_QUEUE_EVENTS> UIevents;
-extern Queue<Event, G_MAX_QUEUE_EVENTS> MidiEvents;
+/* RecordInfo
+Information regarding the input recording progress. */
 
-void init(Frame framesInSeq, Frame framesInBuffer);
+struct RecordInfo
+{
+       Frame position;
+       Frame maxLength;
+};
+
+void init(Frame framesInLoop, Frame framesInBuffer);
 
 /* enable, disable
-Toggles master callback processing. Useful when loading a new patch. Mixer
-will flush itself to wait for a processing cycle to finish when disable() is
-called. */
+Toggles master callback processing. Useful to suspend the rendering. */
 
 void enable();
 void disable();
 
 /* allocRecBuffer
-Allocates new memory for the virtual input channel. Call this whenever you 
-shrink or resize the sequencer. */
+Allocates new memory for the virtual input channel. */
 
 void allocRecBuffer(Frame frames);
 
@@ -126,32 +99,42 @@ void clearRecBuffer();
 Returns a read-only reference to the internal virtual channel. Use this to
 merge data into channel after an input recording session. */
 
-const AudioBuffer& getRecBuffer(); 
+const AudioBuffer& getRecBuffer();
 
-void close();
+/* render
+Core rendering function. */
 
-/* masterPlay
-Core method (callback) */
-
-int masterPlay(void* outBuf, void* inBuf, unsigned bufferSize, double streamTime,
-       RtAudioStreamStatus status, void* userData);
+int render(AudioBuffer& out, const AudioBuffer& in, const RenderInfo& info);
 
 /* startInputRec, stopInputRec
-Starts/stops input recording on frame clock::getCurrentFrame(). */
+Starts/stops input recording on frame 'from'. The latter returns the number of
+recorded frames. */
+
+void  startInputRec(Frame from);
+Frame stopInputRec();
 
-void startInputRec();
-void stopInputRec();
+/* setSignalCallback
+Registers the function to be called when the audio signal reaches a certain
+threshold (record-on-signal mode). */
 
 void setSignalCallback(std::function<void()> f);
 
-/* pumpEvent
-Pumps a new mixer::Event into the event vector. Use this function when you want
-to inject a new event for the **current** block. Push the event in the two 
-queues UIevents and MIDIevents above if the event can be processed in the next 
-block instead. */
+/* setEndOfRecCallback
+Registers the function to be called when the end of the internal recording 
+buffer has been reached. */
+
+void setEndOfRecCallback(std::function<void()> f);
+
+/* isChannelAudible
+True if the channel 'c' is currently audible: not muted or not included in a 
+solo session. */
+
+bool isChannelAudible(const channel::Data& c);
 
-void pumpEvent(Event e);
-}}} // giada::m::mixer::;
+float getPeakOut();
+float getPeakIn();
 
+RecordInfo getRecordInfo();
+} // namespace giada::m::mixer
 
 #endif
index a247020dd0edd142b69a3a1fe1e53494d9e70121..057e70068b29fc75c98310b7a6417ad31e0fe06f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <vector>
-#include <algorithm>
-#include "utils/fs.h"
-#include "utils/string.h"
-#include "utils/log.h"
-#include "utils/vector.h"
-#include "glue/main.h"
-#include "glue/channel.h"
-#include "core/model/model.h"
+#include "core/mixerHandler.h"
 #include "core/channels/channelManager.h"
-#include "core/kernelMidi.h"
-#include "core/mixer.h"
+#include "core/clock.h"
+#include "core/conf.h"
 #include "core/const.h"
 #include "core/init.h"
+#include "core/kernelAudio.h"
+#include "core/kernelMidi.h"
+#include "core/midiMapConf.h"
+#include "core/mixer.h"
+#include "core/model/model.h"
+#include "core/patch.h"
+#include "core/plugins/plugin.h"
 #include "core/plugins/pluginHost.h"
 #include "core/plugins/pluginManager.h"
-#include "core/plugins/plugin.h"
-#include "core/waveFx.h"
-#include "core/conf.h"
-#include "core/patch.h"
+#include "core/recManager.h"
 #include "core/recorder.h"
 #include "core/recorderHandler.h"
-#include "core/recManager.h"
-#include "core/clock.h"
-#include "core/kernelAudio.h"
-#include "core/midiMapConf.h"
 #include "core/wave.h"
+#include "core/waveFx.h"
 #include "core/waveManager.h"
-#include "core/mixerHandler.h"
-
+#include "glue/channel.h"
+#include "glue/main.h"
+#include "utils/fs.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include "utils/vector.h"
+#include <algorithm>
+#include <cassert>
+#include <vector>
 
-namespace giada {
-namespace m {
-namespace mh
+namespace giada::m::mh
 {
 namespace
 {
-std::unique_ptr<Channel> createChannel_(ChannelType type, ID columnId, ID channelId=0)
+channel::Data& addChannel_(ChannelType type, ID columnId)
 {
-       std::unique_ptr<Channel> ch = channelManager::create(type, columnId, conf::conf);
+       model::get().channels.push_back(channelManager::create(/*id=*/0, type, columnId));
+       model::swap(model::SwapType::HARD);
 
-       if (type == ChannelType::MASTER) {
-               assert(channelId != 0);
-               ch->id = channelId;
-       }
-       
-       return ch;
+       return model::get().channels.back();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 waveManager::Result createWave_(const std::string& fname)
 {
-       return waveManager::createFromFile(fname, /*ID=*/0, conf::conf.samplerate, 
-               conf::conf.rsmpQuality); 
+       return waveManager::createFromFile(fname, /*id=*/0, conf::conf.samplerate,
+           conf::conf.rsmpQuality);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool anyChannel_(std::function<bool(const Channel*)> f)
+bool anyChannel_(std::function<bool(const channel::Data&)> f)
 {
-       model::ChannelsLock lock(model::channels);
-       return std::any_of(model::channels.begin(), model::channels.end(), f);
+       return std::any_of(model::get().channels.begin(), model::get().channels.end(), f);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 template <typename F>
-std::vector<ID> getChannelsIf_(F f)
-{
-       model::ChannelsLock l(model::channels);
-
-       std::vector<ID> ids;
-       for (const Channel* c : model::channels)
-               if (f(c)) ids.push_back(c->id);
-       
-       return ids;     
-}
-
-
-std::vector<ID> getChannelsWithWave_()
-{
-       return getChannelsIf_([] (const Channel* c)
-       {
-               return c->samplePlayer && c->samplePlayer->hasWave();
-       });
-}
-
-
-std::vector<ID> getRecordableChannels_()
+std::vector<channel::Data*> getChannelsIf_(F f)
 {
-       return getChannelsIf_([] (const Channel* c) { return c->canInputRec() && !c->hasWave(); });
+       std::vector<channel::Data*> out;
+       for (channel::Data& ch : model::get().channels)
+               if (f(ch))
+                       out.push_back(&ch);
+       return out;
 }
 
-
-std::vector<ID> getOverdubbableChannels_()
+std::vector<channel::Data*> getRecordableChannels_()
 {
-       return getChannelsIf_([] (const Channel* c) { return c->canInputRec() && c->hasWave(); });
+       return getChannelsIf_([](const channel::Data& c) { return c.canInputRec() && !c.hasWave(); });
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-/* pushWave_
-Pushes a new wave into Channel 'ch' and into the corresponding Wave list.
-Use this when modifying a local model, before swapping it. */
-
-void pushWave_(Channel& ch, std::unique_ptr<Wave>&& w)
+std::vector<channel::Data*> getOverdubbableChannels_()
 {
-       assert(ch.getType() == ChannelType::SAMPLE);
-
-       model::waves.push(std::move(w));
-
-       model::WavesLock l(model::waves);
-       ch.samplePlayer->loadWave(model::waves.back());
+       return getChannelsIf_([](const channel::Data& c) { return c.canInputRec() && c.hasWave(); });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void setupChannelPostRecording_(Channel& c)
+void setupChannelPostRecording_(channel::Data& ch)
 {
        /* Start sample channels in loop mode right away. */
-       if (c.samplePlayer->state->isAnyLoopMode())
-               c.samplePlayer->kickIn(clock::getCurrentFrame());
+       if (ch.samplePlayer->isAnyLoopMode())
+               samplePlayer::kickIn(ch, clock::getCurrentFrame());
        /* Disable 'arm' button if overdub protection is on. */
-       if (c.audioReceiver->state->overdubProtection.load() == true)
-               c.state->armed.store(false);
+       if (ch.audioReceiver->overdubProtection == true)
+               ch.armed = false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* recordChannel_
 Records the current Mixer audio input data into an empty channel. */
 
-void recordChannel_(ID channelId)
+void recordChannel_(channel::Data& ch, Frame recordedFrames)
 {
-       /* Create a new Wave with audio coming from Mixer's virtual input. */
+       /* Create a new Wave with audio coming from Mixer's input buffer. */
 
-       std::string filename = "TAKE-" + std::to_string(patch::patch.lastTakeId++) + ".wav";
+       std::string           filename = "TAKE-" + std::to_string(patch::patch.lastTakeId++) + ".wav";
+       std::unique_ptr<Wave> wave     = waveManager::createEmpty(recordedFrames, G_MAX_IO_CHANS,
+        conf::conf.samplerate, filename);
 
-       std::unique_ptr<Wave> wave = waveManager::createEmpty(clock::getFramesInLoop(), 
-               G_MAX_IO_CHANS, conf::conf.samplerate, filename);
+       G_DEBUG("Created new Wave, size=" << wave->getBuffer().countFrames());
 
-       wave->copyData(mixer::getRecBuffer());
+       /* Copy up to wave.getSize() from the mixer's input buffer into wave's. */
 
-       /* Update Channel with the new Wave. The function pushWave_ will take
-       care of pushing it into the Wave stack first. */
+       wave->getBuffer().set(mixer::getRecBuffer(), wave->getBuffer().countFrames());
 
-       model::onSwap(model::channels, channelId, [&](Channel& c)
-       {
-               pushWave_(c, std::move(wave));
-               setupChannelPostRecording_(c);
-       });
-}
+       /* Update channel with the new Wave. */
 
+       model::add(std::move(wave));
+       samplePlayer::loadWave(ch, &model::back<Wave>());
+       setupChannelPostRecording_(ch);
 
-/* -------------------------------------------------------------------------- */
+       model::swap(model::SwapType::HARD);
+}
 
+/* -------------------------------------------------------------------------- */
 
 /* overdubChannel_
 Records the current Mixer audio input data into a channel with an existing
 Wave, overdub mode. */
 
-void overdubChannel_(ID channelId)
+void overdubChannel_(channel::Data& ch)
 {
-       ID waveId;
-       model::onGet(model::channels, channelId, [&](Channel& c)
-       {
-               waveId = c.samplePlayer->getWaveId();
-       });
+       Wave* wave = ch.samplePlayer->getWave();
 
-       model::onGet(m::model::waves, waveId, [&](Wave& w)
-       {
-               w.addData(mixer::getRecBuffer());
-               w.setLogical(true);
-       });
+       /* Need model::DataLock here, as data might be being read by the audio
+       thread at the same time. */
 
-       model::onGet(model::channels, channelId, [&](Channel& c)
-       {
-               setupChannelPostRecording_(c);
-       });
-}
-} // {anonymous}
+       model::DataLock lock;
+       wave->getBuffer().sum(mixer::getRecBuffer(), /*gain=*/1.0f);
+       wave->setLogical(true);
 
+       setupChannelPostRecording_(ch);
+}
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
-       mixer::init(clock::getFramesInLoop(), kernelAudio::getRealBufSize());
-       
-       model::channels.push(createChannel_(ChannelType::MASTER, /*column=*/0, 
-               mixer::MASTER_OUT_CHANNEL_ID));
-       model::channels.push(createChannel_(ChannelType::MASTER, /*column=*/0, 
-               mixer::MASTER_IN_CHANNEL_ID));
-       model::channels.push(createChannel_(ChannelType::PREVIEW, /*column=*/0, 
-               mixer::PREVIEW_CHANNEL_ID));
-}
+       mixer::init(clock::getMaxFramesInLoop(), kernelAudio::getRealBufSize());
 
+       model::get().channels.clear();
 
-/* -------------------------------------------------------------------------- */
+       model::get().channels.push_back(channelManager::create(
+           mixer::MASTER_OUT_CHANNEL_ID, ChannelType::MASTER, /*columnId=*/0));
+       model::get().channels.push_back(channelManager::create(
+           mixer::MASTER_IN_CHANNEL_ID, ChannelType::MASTER, /*columnId=*/0));
+       model::get().channels.push_back(channelManager::create(
+           mixer::PREVIEW_CHANNEL_ID, ChannelType::PREVIEW, /*columnId=*/0));
 
+       model::swap(model::SwapType::NONE);
+}
+
+/* -------------------------------------------------------------------------- */
 
 void close()
 {
        mixer::disable();
-       model::channels.clear();
-       model::waves.clear();
-       mixer::close();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void addChannel(ChannelType type, ID columnId)
 {
-       model::channels.push(createChannel_(type, columnId));
+       addChannel_(type, columnId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int loadChannel(ID channelId, const std::string& fname)
 {
-       waveManager::Result res = createWave_(fname); 
+       waveManager::Result res = createWave_(fname);
 
-       if (res.status != G_RES_OK) 
+       if (res.status != G_RES_OK)
                return res.status;
 
-       ID oldWaveId;
+       model::add(std::move(res.wave));
 
-       model::onSwap(model::channels, channelId, [&](Channel& c)
-       {
-               oldWaveId = c.samplePlayer->getWaveId();
-               pushWave_(c, std::move(res.wave));
-       });
+       Wave& wave = model::back<Wave>();
+       Wave* old  = model::get().getChannel(channelId).samplePlayer->getWave();
 
-       /* Remove old wave, if any. It is safe to do it now: the channel already
-       points to the new one. */
+       samplePlayer::loadWave(model::get().getChannel(channelId), &wave);
+       model::swap(model::SwapType::HARD);
 
-       if (oldWaveId != 0)
-               model::waves.pop(model::getIndex(model::waves, oldWaveId));
+       /* Remove old wave, if any. It is safe to do it now: the audio thread is
+       already processing the new layout. */
+
+       if (old != nullptr)
+               model::remove<Wave>(*old);
+
+       recManager::refreshInputRecMode();
 
        return res.status;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int addAndLoadChannel(ID columnId, const std::string& fname)
 {
        waveManager::Result res = createWave_(fname);
@@ -299,238 +237,193 @@ int addAndLoadChannel(ID columnId, const std::string& fname)
        return res.status;
 }
 
-
 void addAndLoadChannel(ID columnId, std::unique_ptr<Wave>&& w)
 {
-       std::unique_ptr<Channel> ch = createChannel_(ChannelType::SAMPLE, columnId);
+       model::add(std::move(w));
 
-       pushWave_(*ch.get(), std::move(w));
+       Wave&          wave    = model::back<Wave>();
+       channel::Data& channel = addChannel_(ChannelType::SAMPLE, columnId);
 
-       /* Then add new channel to Channel list. */
+       samplePlayer::loadWave(channel, &wave);
+       model::swap(model::SwapType::HARD);
 
-       model::channels.push(std::move(ch));
+       recManager::refreshInputRecMode();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void cloneChannel(ID channelId)
 {
-       model::ChannelsLock cl(model::channels);
-       model::WavesLock    wl(model::waves);
-
-       const Channel&           oldChannel = model::get(model::channels, channelId);
-       std::unique_ptr<Channel> newChannel = channelManager::create(oldChannel);
+       channel::Data& oldChannel = model::get().getChannel(channelId);
+       channel::Data  newChannel = channelManager::create(oldChannel);
 
        /* Clone plugins, actions and wave first in their own lists. */
-       
+
 #ifdef WITH_VST
-       newChannel->pluginIds = pluginHost::clonePlugins(oldChannel.pluginIds);
+       newChannel.plugins = pluginHost::clonePlugins(oldChannel.plugins);
 #endif
-       recorderHandler::cloneActions(channelId, newChannel->id);
-       
-       if (newChannel->samplePlayer && newChannel->samplePlayer->hasWave()) 
+       recorderHandler::cloneActions(channelId, newChannel.id);
+
+       if (newChannel.samplePlayer && newChannel.samplePlayer->hasWave())
        {
-               Wave& wave = model::get(model::waves, newChannel->samplePlayer->getWaveId());
-               pushWave_(*newChannel, waveManager::createFromWave(wave, 0, wave.getSize()));
+               Wave* wave = newChannel.samplePlayer->getWave();
+               model::add(waveManager::createFromWave(*wave, 0, wave->getBuffer().countFrames()));
        }
 
-       /* Then push the new channel in the channels list. */
+       /* Then push the new channel in the channels vector. */
 
-       model::channels.push(std::move(newChannel));
+       model::get().channels.push_back(newChannel);
+       model::swap(model::SwapType::HARD);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void freeChannel(ID channelId)
 {
-       ID waveId;
-       
-       /* Remove Wave reference from Channel. */
-       
-       model::onSwap(model::channels, channelId, [&](Channel& c)
-       {
-               waveId = c.samplePlayer->getWaveId();
-               c.samplePlayer->loadWave(nullptr);
-       });
+       channel::Data& ch = model::get().getChannel(channelId);
 
-       /* Then remove the actual Wave, if any. */
-       
-       if (waveId != 0)
-               model::waves.pop(model::getIndex(model::waves, waveId)); 
-}
+       assert(ch.samplePlayer);
 
+       const Wave* wave = ch.samplePlayer->getWave();
 
-/* -------------------------------------------------------------------------- */
+       samplePlayer::loadWave(ch, nullptr);
+       model::swap(model::SwapType::HARD);
+
+       if (wave != nullptr)
+               model::remove<Wave>(*wave);
+
+       recManager::refreshInputRecMode();
+}
 
+/* -------------------------------------------------------------------------- */
 
 void freeAllChannels()
 {
-       for (ID id : getChannelsWithWave_()) {
-               model::onSwap(model::channels, id, [](Channel& c) 
-               { 
-                       c.samplePlayer->loadWave(nullptr);
-               });
-       }
+       for (channel::Data& ch : model::get().channels)
+               if (ch.samplePlayer)
+                       samplePlayer::loadWave(ch, nullptr);
 
-       model::waves.clear();
-}
+       model::swap(model::SwapType::HARD);
+       model::clear<model::WavePtrs>();
 
+       recManager::refreshInputRecMode();
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void deleteChannel(ID channelId)
 {
-       ID              waveId;
+       const channel::Data& ch   = model::get().getChannel(channelId);
+       const Wave*          wave = ch.samplePlayer ? ch.samplePlayer->getWave() : nullptr;
 #ifdef WITH_VST
-       std::vector<ID> pluginIds;
+       const std::vector<Plugin*> plugins = ch.plugins;
 #endif
 
-       model::onGet(model::channels, channelId, [&](const Channel& c)
-       {
-#ifdef WITH_VST
-               pluginIds = c.pluginIds;
-#endif
-               waveId    = c.samplePlayer ? c.samplePlayer->getWaveId() : 0;
+       u::vector::removeIf(model::get().channels, [channelId](const channel::Data& c) {
+               return c.id == channelId;
        });
-       
-       model::channels.pop(model::getIndex(model::channels, channelId));
+       model::swap(model::SwapType::HARD);
 
-       if (waveId != 0)
-               model::waves.pop(model::getIndex(model::waves, waveId)); 
+       if (wave != nullptr)
+               model::remove<Wave>(*wave);
 
 #ifdef WITH_VST
-       pluginHost::freePlugins(pluginIds);
+       pluginHost::freePlugins(plugins);
 #endif
-}
 
+       recManager::refreshInputRecMode();
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void renameChannel(ID channelId, const std::string& name)
 {
-       model::onGet(model::channels, channelId, [&](Channel& c) 
-       { 
-               c.state->name = name; 
-       }, /*rebuild=*/true);
+       model::get().getChannel(channelId).name = name;
+       model::swap(model::SwapType::HARD);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateSoloCount()
 {
-       model::onSwap(model::mixer, [](model::Mixer& m)
-       {
-               m.hasSolos = anyChannel_([](const Channel* ch) {
-                   return !ch->isInternal() && ch->state->solo.load() == true;
-               });
+       bool hasSolos = anyChannel_([](const channel::Data& ch) {
+               return !ch.isInternal() && ch.solo;
        });
-}
 
+       model::get().mixer.hasSolos = hasSolos;
+       model::swap(model::SwapType::NONE);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void setInToOut(bool v)
 {
-       model::onSwap(model::mixer, [&](model::Mixer& m)
-       {
-               m.inToOut = v;
-       });
+       model::get().mixer.inToOut = v;
+       model::swap(model::SwapType::NONE);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 float getInVol()
 {
-       model::ChannelsLock l(model::channels); 
-       return model::get(model::channels, mixer::MASTER_IN_CHANNEL_ID).state->volume.load();
+       return model::get().getChannel(mixer::MASTER_IN_CHANNEL_ID).volume;
 }
 
-
 float getOutVol()
 {
-       model::ChannelsLock l(model::channels); 
-       return model::get(model::channels, mixer::MASTER_OUT_CHANNEL_ID).state->volume.load();
+       return model::get().getChannel(mixer::MASTER_OUT_CHANNEL_ID).volume;
 }
 
-
 bool getInToOut()
 {
-       model::MixerLock lock(model::mixer); return model::mixer.get()->inToOut;
+       return model::get().mixer.inToOut;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-/* Push a new Wave into each recordable channel. Warning: this algorithm will 
-require some changes when we will allow overdubbing (the previous existing Wave
-has to be overwritten somehow). */
-
-void finalizeInputRec()
+void finalizeInputRec(Frame recordedFrames)
 {
-       for (ID id : getRecordableChannels_())
-               recordChannel_(id);
-       for (ID id : getOverdubbableChannels_())
-               overdubChannel_(id);
+       for (channel::Data* ch : getRecordableChannels_())
+               recordChannel_(*ch, recordedFrames);
+       for (channel::Data* ch : getOverdubbableChannels_())
+               overdubChannel_(*ch);
 
        mixer::clearRecBuffer();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool hasInputRecordableChannels()
 {
-       return anyChannel_([](const Channel* ch) { return ch->canInputRec(); });
+       return anyChannel_([](const channel::Data& ch) { return ch.canInputRec(); });
 }
 
-
 bool hasActionRecordableChannels()
 {
-       return anyChannel_([](const Channel* ch) { return ch->canActionRec(); });
+       return anyChannel_([](const channel::Data& ch) { return ch.canActionRec(); });
 }
 
-
 bool hasLogicalSamples()
 {
-       return anyChannel_([](const Channel* ch) 
-       { 
-               return ch->samplePlayer && ch->samplePlayer->hasLogicalWave(); }
-       );
+       return anyChannel_([](const channel::Data& ch) { return ch.samplePlayer && ch.samplePlayer->hasLogicalWave(); });
 }
 
-
 bool hasEditedSamples()
 {
-       return anyChannel_([](const Channel* ch) 
-       { 
-               return ch->samplePlayer && ch->samplePlayer->hasEditedWave(); 
+       return anyChannel_([](const channel::Data& ch) {
+               return ch.samplePlayer && ch.samplePlayer->hasEditedWave();
        });
 }
 
-
 bool hasActions()
 {
-       return anyChannel_([](const Channel* ch) { return ch->state->hasActions; });
+       return anyChannel_([](const channel::Data& ch) { return ch.hasActions; });
 }
 
-
 bool hasAudioData()
 {
-       return anyChannel_([](const Channel* ch)
-       { 
-               return ch->samplePlayer && ch->samplePlayer->hasWave(); 
+       return anyChannel_([](const channel::Data& ch) {
+               return ch.samplePlayer && ch.samplePlayer->hasWave();
        });
 }
-}}} // giada::m::mh::
+} // namespace giada::m::mh
index 4e1cf0536fae0d4d23e5dbd8ab00665db21f4ec5..4da3053a19cb1849ddc740ea2b909f0c6304ff6b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MIXER_HANDLER_H
 #define G_MIXER_HANDLER_H
 
-
+#include "types.h"
 #include <memory>
 #include <string>
-#include "types.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class Wave;
 class Channel;
 class SampleChannel;
-
-namespace mh
+} // namespace giada::m
+namespace giada::m::mh
 {
 /* init
 Initializes mixer. */
@@ -67,12 +63,12 @@ int loadChannel(ID channelId, const std::string& fname);
 /* addAndLoadChannel (1)
 Creates a new channels, fills it with a Wave and then add it to the stack. */
 
-int addAndLoadChannel(ID columnId, const std::string& fname); 
+int addAndLoadChannel(ID columnId, const std::string& fname);
 
 /* addAndLoadChannel (2)
 Same as (1), but Wave is already provided. */
 
-void addAndLoadChannel(ID columnId, std::unique_ptr<Wave>&& w); 
+void addAndLoadChannel(ID columnId, std::unique_ptr<Wave>&& w);
 
 /* freeChannel
 Unloads existing Wave from a Sample Channel. */
@@ -99,7 +95,7 @@ void updateSoloCount();
 Fills armed Sample Channels with audio data coming from an input recording
 session. */
 
-void finalizeInputRec();
+void finalizeInputRec(Frame recordedFrames);
 
 /* hasLogicalSamples
 True if 1 or more samples are logical (memory only, such as takes) */
@@ -129,8 +125,7 @@ bool hasAudioData();
 
 float getInVol();
 float getOutVol();
-bool getInToOut();
-}}}  // giada::m::mh::
-
+bool  getInToOut();
+} // namespace giada::m::mh
 
 #endif
index 3de8e8c82a2383c7374a3bb1e9d52980cc1f3696..5a69aece2aee89e5fc9f3122ed18728a706d47ee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
 #include "core/model/model.h"
+#include <cassert>
 #ifdef G_DEBUG_MODE
 #include "core/channels/channelManager.h"
 #endif
 
+namespace giada::m::model
+{
+namespace
+{
+struct State
+{
+       Clock::State                                 clock;
+       Mixer::State                                 mixer;
+       std::vector<std::unique_ptr<channel::State>> channels;
+};
 
-namespace giada {
-namespace m {
-namespace model
+struct Data
 {
-RCUList<Clock>    clock(std::make_unique<Clock>());
-RCUList<Mixer>    mixer(std::make_unique<Mixer>());
-RCUList<Kernel>   kernel(std::make_unique<Kernel>());
-RCUList<Recorder> recorder(std::make_unique<Recorder>());
-RCUList<MidiIn>   midiIn(std::make_unique<MidiIn>());
-RCUList<Actions>  actions(std::make_unique<Actions>());
-RCUList<Channel> channels;
-RCUList<Wave>     waves;
+       std::vector<std::unique_ptr<channel::Buffer>> channels;
+       std::vector<std::unique_ptr<Wave>>            waves;
+       recorder::ActionMap                           actions;
 #ifdef WITH_VST
-RCUList<Plugin>   plugins;
+       std::vector<std::unique_ptr<Plugin>> plugins;
 #endif
+};
 
+/* -------------------------------------------------------------------------- */
 
-Actions::Actions(const Actions& o) : map(o.map)
+template <typename T>
+auto getIter_(const std::vector<std::unique_ptr<T>>& source, ID id)
 {
-       /* Needs to update all pointers of prev and next actions with addresses 
-       coming from the new 'actions' map.  */
+       return u::vector::findIf(source, [id](const std::unique_ptr<T>& p) { return p->id == id; });
+}
+
+/* -------------------------------------------------------------------------- */
 
-       recorder::updateMapPointers(map);
+template <typename S>
+auto* get_(S& source, ID id)
+{
+       auto it = getIter_(source, id);
+       return it == source.end() ? nullptr : it->get();
 }
 
+/* -------------------------------------------------------------------------- */
 
-#ifdef G_DEBUG_MODE
+template <typename D, typename T>
+void remove_(D& dest, T& ref)
+{
+       u::vector::removeIf(dest, [&ref](const auto& other) { return other.get() == &ref; });
+}
+} // namespace
 
-void debug()
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+std::function<void(SwapType)> onSwap_ = nullptr;
+
+Swapper<Layout> layout;
+State           state;
+Data            data;
+
+/* -------------------------------------------------------------------------- */
+
+DataLock::DataLock(SwapType t)
+: m_swapType(t)
+{
+       get().locked = true;
+       swap(SwapType::NONE);
+}
+
+DataLock::~DataLock()
+{
+       get().locked = false;
+       swap(m_swapType);
+}
+
+/* -------------------------------------------------------------------------- */
+
+channel::Data& Layout::getChannel(ID id)
+{
+       return const_cast<channel::Data&>(const_cast<const Layout*>(this)->getChannel(id));
+}
+
+const channel::Data& Layout::getChannel(ID id) const
+{
+       auto it = std::find_if(channels.begin(), channels.end(), [id](const channel::Data& c) {
+               return c.id == id;
+       });
+       assert(it != channels.end());
+       return *it;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void init()
+{
+       get().clock.state = &state.clock;
+       get().mixer.state = &state.mixer;
+       swap(SwapType::NONE);
+}
+
+/* -------------------------------------------------------------------------- */
+
+Layout& get()
+{
+       return layout.get();
+}
+
+Lock get_RT()
+{
+       return Lock(layout);
+}
+
+void swap(SwapType t)
+{
+       layout.swap();
+       if (onSwap_)
+               onSwap_(t);
+}
+
+void onSwap(std::function<void(SwapType)> f)
+{
+       onSwap_ = f;
+}
+
+/* -------------------------------------------------------------------------- */
+
+bool isLocked()
+{
+       return layout.isLocked();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+T& getAll()
 {
-       ChannelsLock chl(channels);
-       ClockLock    cl(clock);
-       WavesLock    wl(waves);
-       ActionsLock  al(actions);
 #ifdef WITH_VST
-       PluginsLock  pl(plugins);
+       if constexpr (std::is_same_v<T, PluginPtrs>)
+               return data.plugins;
 #endif
+       if constexpr (std::is_same_v<T, WavePtrs>)
+               return data.waves;
+       if constexpr (std::is_same_v<T, Actions>)
+               return data.actions;
+       if constexpr (std::is_same_v<T, ChannelBufferPtrs>)
+               return data.channels;
+       if constexpr (std::is_same_v<T, ChannelStatePtrs>)
+               return state.channels;
 
+       assert(false);
+}
+
+#ifdef WITH_VST
+template PluginPtrs& getAll<PluginPtrs>();
+#endif
+template WavePtrs&          getAll<WavePtrs>();
+template Actions&           getAll<Actions>();
+template ChannelBufferPtrs& getAll<ChannelBufferPtrs>();
+template ChannelStatePtrs&  getAll<ChannelStatePtrs>();
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+T* find(ID id)
+{
+#ifdef WITH_VST
+       if constexpr (std::is_same_v<T, Plugin>)
+               return get_(data.plugins, id);
+#endif
+       if constexpr (std::is_same_v<T, Wave>)
+               return get_(data.waves, id);
+
+       assert(false);
+}
+
+#ifdef WITH_VST
+template Plugin* find<Plugin>(ID id);
+#endif
+template Wave* find<Wave>(ID id);
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+void add(T obj)
+{
+#ifdef WITH_VST
+       if constexpr (std::is_same_v<T, PluginPtr>)
+               data.plugins.push_back(std::move(obj));
+#endif
+       if constexpr (std::is_same_v<T, WavePtr>)
+               data.waves.push_back(std::move(obj));
+       if constexpr (std::is_same_v<T, ChannelBufferPtr>)
+               data.channels.push_back(std::move(obj));
+       if constexpr (std::is_same_v<T, ChannelStatePtr>)
+               state.channels.push_back(std::move(obj));
+}
+
+#ifdef WITH_VST
+template void add<PluginPtr>(PluginPtr p);
+#endif
+template void add<WavePtr>(WavePtr p);
+template void add<ChannelBufferPtr>(ChannelBufferPtr p);
+template void add<ChannelStatePtr>(ChannelStatePtr p);
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+void remove(const T& ref)
+{
+#ifdef WITH_VST
+       if constexpr (std::is_same_v<T, Plugin>)
+               remove_(data.plugins, ref);
+#endif
+       if constexpr (std::is_same_v<T, Wave>)
+               remove_(data.waves, ref);
+}
+
+#ifdef WITH_VST
+template void remove<Plugin>(const Plugin& t);
+#endif
+template void remove<Wave>(const Wave& t);
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+T& back()
+{
+#ifdef WITH_VST
+       if constexpr (std::is_same_v<T, Plugin>)
+               return *data.plugins.back().get();
+#endif
+       if constexpr (std::is_same_v<T, Wave>)
+               return *data.waves.back().get();
+       if constexpr (std::is_same_v<T, channel::State>)
+               return *state.channels.back().get();
+       if constexpr (std::is_same_v<T, channel::Buffer>)
+               return *data.channels.back().get();
+}
+
+#ifdef WITH_VST
+template Plugin& back<Plugin>();
+#endif
+template Wave&            back<Wave>();
+template channel::State&  back<channel::State>();
+template channel::Buffer& back<channel::Buffer>();
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+void clear()
+{
+#ifdef WITH_VST
+       if constexpr (std::is_same_v<T, PluginPtrs>)
+               data.plugins.clear();
+#endif
+       if constexpr (std::is_same_v<T, WavePtrs>)
+               data.waves.clear();
+}
+
+#ifdef WITH_VST
+template void clear<PluginPtrs>();
+#endif
+template void clear<WavePtrs>();
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef G_DEBUG_MODE
+
+void debug()
+{
        puts("======== SYSTEM STATUS ========");
-       
-       puts("model::channels");
+
+       puts("model::layout");
 
        int i = 0;
-       for (const Channel* c : channels) {
-               printf("\t%d) %p - ID=%d name='%s' type=%d columnID=%d\n",
-                       i++, (void*) c, c->state->id, c->state->name.c_str(), (int) c->getType(), c->getColumnId());
-/*
-               if (c->hasData())
-                       printf("\t\twave: ID=%d\n", static_cast<const SampleChannel*>(c)->waveId);
-*/
+       for (const channel::Data& c : get().channels)
+       {
+               printf("\t%d) - ID=%d name='%s' type=%d columnID=%d state=%p\n",
+                   i++, c.id, c.name.c_str(), (int)c.type, c.columnId, (void*)&c.state);
 #ifdef WITH_VST
-               if (c->pluginIds.size() > 0) {
+               if (c.plugins.size() > 0)
+               {
                        puts("\t\tplugins:");
-                       for (ID id : c->pluginIds)
-                               printf("\t\t\tID=%d\n", id);
+                       for (const auto& p : c.plugins)
+                               printf("\t\t\t%p - ID=%d\n", (void*)p, p->id);
                }
 #endif
        }
 
-       puts("model::waves");
+       puts("model::state.channels");
 
        i = 0;
-       for (const Wave* w : waves) 
-               printf("\t%d) %p - ID=%d name='%s'\n", i++, (void*)w, w->id, w->getPath().c_str());
-               
-#ifdef WITH_VST
-       puts("model::plugins");
+       for (const auto& c : state.channels)
+       {
+               printf("\t%d) - %p\n", i++, (void*)c.get());
+       }
+
+       puts("model::data.waves");
 
        i = 0;
-       for (const Plugin* p : plugins) {
-               if (p->valid)
-                       printf("\t%d) %p - ID=%d name='%s'\n", i++, (void*)p, p->id, p->getName().c_str());
-               else
-                       printf("\t%d) %p - ID=%d INVALID\n", i++, (void*)p, p->id); 
+       for (const auto& w : data.waves)
+               printf("\t%d) %p - ID=%d name='%s'\n", i++, (void*)w.get(), w->id, w->getPath().c_str());
+
+       puts("model::data.actions");
+
+       for (const auto& [frame, actions] : getAll<Actions>())
+       {
+               printf("\tframe: %d\n", frame);
+               for (const Action& a : actions)
+                       printf("\t\t(%p) - ID=%d, frame=%d, channel=%d, value=0x%X, prevId=%d, prev=%p, nextId=%d, next=%p\n",
+                           (void*)&a, a.id, a.frame, a.channelId, a.event.getRaw(), a.prevId, (void*)a.prev, a.nextId, (void*)a.next);
        }
-#endif
 
-       puts("model::clock");
+#ifdef WITH_VST
 
-       printf("\tclock.status   = %d\n", static_cast<int>(clock.get()->status));
-       printf("\tclock.bars     = %d\n", clock.get()->bars);
-       printf("\tclock.beats    = %d\n", clock.get()->beats);
-       printf("\tclock.bpm      = %f\n", clock.get()->bpm);
-       printf("\tclock.quantize = %d\n", clock.get()->quantize);
+       puts("model::data.plugins");
 
-       puts("model::actions");
+       i = 0;
+       for (const auto& p : data.plugins)
+               printf("\t%d) %p - ID=%d\n", i++, (void*)p.get(), p->id);
 
-       for (auto& kv : actions.get()->map) {
-               printf("\tframe: %d\n", kv.first);
-               for (const Action& a : kv.second)
-                       printf("\t\t(%p) - ID=%d, frame=%d, channel=%d, value=0x%X, prevId=%d, prev=%p, nextId=%d, next=%p\n", 
-                               (void*) &a, a.id, a.frame, a.channelId, a.event.getRaw(), a.prevId, (void*) a.prev, a.nextId, (void*) a.next);  
-       }
-       
-       puts("===============================");
+#endif
 }
 
 #endif // G_DEBUG_MODE
-}}} // giada::m::model::
+} // namespace giada::m::model
index 58396dc49e950b33287ae51077847a6aa839ef88..d6dcfd090fd73252c78d08046edb72bac9cbf315 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_RENDER_MODEL_H
 #define G_RENDER_MODEL_H
 
-
-#include <algorithm>
-#include "core/model/traits.h"
 #include "core/channels/channel.h"
-#include "core/channels/state.h"
 #include "core/const.h"
-#include "core/wave.h"
 #include "core/plugins/plugin.h"
-#include "core/rcuList.h"
 #include "core/recorder.h"
+#include "core/swapper.h"
+#include "core/wave.h"
+#include "utils/vector.h"
+#include <algorithm>
 
-
-namespace giada {
-namespace m {
-namespace model
-{
-namespace
-{
-/* getIter_
-Returns an iterator of an element from list 'list' with given ID. */
-
-template<typename L>
-auto getIter_(L& list, ID id)
-{
-       static_assert(has_id<typename L::value_type>(), "This type has no ID");
-       auto it = std::find_if(list.begin(), list.end(), [&](auto* t)
-       {
-               return t->id == id;
-       });
-       assert(it != list.end());
-       return it;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-/* onSwapByIndex_
-Swaps i-th element from list with a new one and applies a function f to it. */
-
-template<typename L>
-void onSwapByIndex_(L& list, std::size_t i, std::function<void(typename L::value_type&)> f)
-{
-       std::unique_ptr<typename L::value_type> o = list.clone(i);
-       f(*o.get());
-       list.swap(std::move(o), i);
-}
-} // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
-struct Clock
-{      
-       ClockStatus status       = ClockStatus::STOPPED;
-       int         framesInLoop = 0;
-       int         framesInBar  = 0;
-       int         framesInBeat = 0;
-       int         framesInSeq  = 0;
-       int         bars         = G_DEFAULT_BARS;
-       int         beats        = G_DEFAULT_BEATS;
-       float       bpm          = G_DEFAULT_BPM;
-       int         quantize     = G_DEFAULT_QUANTIZE;
-};
-
-struct Mixer
+namespace giada::m::model
 {
-       bool hasSolos = false;    
-       bool inToOut  = false;
-};
-
-
 struct Kernel
 {
        bool audioReady = false;
        bool midiReady  = false;
 };
 
-
 struct Recorder
 {
        bool isRecordingAction = false;
        bool isRecordingInput  = false;
 };
 
-
 struct MidiIn
 {
        bool     enabled    = false;
@@ -128,165 +62,174 @@ struct MidiIn
        uint32_t volumeOut  = 0x0;
        uint32_t beatDouble = 0x0;
        uint32_t beatHalf   = 0x0;
-       uint32_t metronome  = 0x0;      
+       uint32_t metronome  = 0x0;
 };
 
-
-struct Actions
+struct Clock
 {
-       Actions() = default;
-       Actions(const Actions& o);
+       struct State
+       {
+               WeakAtomic<int> currentFrameWait = 0;
+               WeakAtomic<int> currentFrame     = 0;
+               WeakAtomic<int> currentBeat      = 0;
+       };
 
-       recorder::ActionMap map;
+       State*      state        = nullptr;
+       ClockStatus status       = ClockStatus::STOPPED;
+       int         framesInLoop = 0;
+       int         framesInBar  = 0;
+       int         framesInBeat = 0;
+       int         framesInSeq  = 0;
+       int         bars         = G_DEFAULT_BARS;
+       int         beats        = G_DEFAULT_BEATS;
+       float       bpm          = G_DEFAULT_BPM;
+       int         quantize     = G_DEFAULT_QUANTIZE;
 };
 
+struct Mixer
+{
+       struct State
+       {
+               std::atomic<bool> active  = false;
+               WeakAtomic<float> peakOut = 0.0f;
+               WeakAtomic<float> peakIn  = 0.0f;
+       };
+
+       State* state    = nullptr;
+       bool   hasSolos = false;
+       bool   inToOut  = false;
+};
 
-using ClockLock    = RCUList<Clock>::Lock;
-using MixerLock    = RCUList<Mixer>::Lock;
-using KernelLock   = RCUList<Kernel>::Lock;
-using RecorderLock = RCUList<Recorder>::Lock;
-using MidiInLock   = RCUList<MidiIn>::Lock;
-using ActionsLock  = RCUList<Actions>::Lock;
-using ChannelsLock = RCUList<Channel>::Lock;
-using WavesLock    = RCUList<Wave>::Lock;
-#ifdef WITH_VST
-using PluginsLock  = RCUList<Plugin>::Lock;
-#endif
-
-extern RCUList<Clock>    clock;
-extern RCUList<Mixer>    mixer;
-extern RCUList<Kernel>   kernel;
-extern RCUList<Recorder> recorder;
-extern RCUList<MidiIn>   midiIn;
-extern RCUList<Actions>  actions;
-extern RCUList<Channel>  channels;
-extern RCUList<Wave>     waves;
-#ifdef WITH_VST
-extern RCUList<Plugin>   plugins;
-#endif
-
+struct Layout
+{
+       channel::Data&       getChannel(ID id);
+       const channel::Data& getChannel(ID id) const;
 
-/* -------------------------------------------------------------------------- */
+       Clock    clock;
+       Mixer    mixer;
+       Kernel   kernel;
+       Recorder recorder;
+       MidiIn   midiIn;
 
+       std::vector<channel::Data> channels;
 
-template<typename L>
-bool exists(L& list, ID id)
-{
-       static_assert(has_id<typename L::value_type>(), "This type has no ID"); 
-       typename L::Lock l(list);
-       auto it = std::find_if(list.begin(), list.end(), [&](auto* t)
-       {
-               return t->id == id;
-       });
-       return it != list.end();
-}
+       /* locked
+       If locked, Mixer won't process channels. This is used to allow editing the 
+       data (e.g. Actions or Plugins) a channel points to without data races. */
 
+       bool locked = false;
+};
 
-/* -------------------------------------------------------------------------- */
+/* Lock
+Alias for a REALTIME scoped lock provided by the Swapper class. Use this in the
+real-time thread to lock the Layout. */
 
+using Lock = Swapper<Layout>::RtLock;
 
-/* getIndex (thread safe)
-Returns the index of element with ID from a list. */
+/* SwapType
+Type of Layout change. 
+       Hard: the structure has changed (e.g. add a new channel);
+       Soft: a property has changed (e.g. change volume);
+       None: something has changed but we don't care. 
+Used by model listeners to determine the type of change that occured in the 
+layout. */
 
-template<typename L>
-std::size_t getIndex(L& list, ID id)
+enum class SwapType
 {
-       static_assert(has_id<typename L::value_type>(), "This type has no ID");
-       typename L::Lock l(list);
-       return std::distance(list.begin(), getIter_(list, id));
-}
-
+       HARD,
+       SOFT,
+       NONE
+};
 
 /* -------------------------------------------------------------------------- */
 
-
-/* getIndex (thread safe)
-Returns the element ID of the i-th element of a list. */
-
-template<typename L>
-ID getId(L& list, std::size_t i)
+class DataLock
 {
-       static_assert(has_id<typename L::value_type>(), "This type has no ID");
-       typename L::Lock l(list);
-       return list.get(i)->id;
-}
+public:
+       DataLock(SwapType t = SwapType::HARD);
+       ~DataLock();
 
+private:
+       SwapType m_swapType;
+};
 
 /* -------------------------------------------------------------------------- */
 
+/* init
+Initializes the internal layout. */
 
-template<typename L>
-typename L::value_type& get(L& list, ID id)
-{
-       static_assert(has_id<typename L::value_type>(), "This type has no ID");
-       return **getIter_(list, id);
-}
+void init();
 
+/* get
+Returns a reference to the NON-REALTIME layout structure. */
 
-/* -------------------------------------------------------------------------- */
+Layout& get();
 
+/* get_RT
+Returns a Lock object for REALTIME processing. Access layout by calling 
+Lock::get() method (returns ready-only Layout). */
 
-/* onGet (1) (thread safe)
-Utility function for reading ID-based things from a RCUList. */
+Lock get_RT();
 
-template<typename L>
-void onGet(L& list, ID id, std::function<void(typename L::value_type&)> f, bool rebuild=false)
-{
-       static_assert(has_id<typename L::value_type>(), "This type has no ID");
-       typename L::Lock l(list);
-       f(**getIter_(list, id));
-       if (rebuild)
-               list.changed.store(true);
-}
+/* swap
+Swap non-rt layout with the rt one. See 'SwapType' notes above. */
 
+void swap(SwapType t);
 
-/* onGet (2) (thread safe)
-Same as (1), for non-ID-based things. */
+/* onSwap
+Registers an optional callback fired when the layout has been swapped. Useful 
+for listening to model changes. */
 
-template<typename L>
-void onGet(L& list, std::function<void(typename L::value_type&)> f)
-{
-       static_assert(!has_id<typename L::value_type>(), "This type has ID");
-       typename L::Lock l(list);
-       f(*list.get());
-}
+void onSwap(std::function<void(SwapType)> f);
 
+bool isLocked();
 
-/* ---------------------------------------------------------------------------*/ 
+/* -------------------------------------------------------------------------- */
 
+/* Model utilities */
 
-/* onSwap (1) (thread safe)
-Utility function for swapping ID-based things in a RCUList. */
+#ifdef WITH_VST
+using PluginPtr = std::unique_ptr<Plugin>;
+#endif
+using WavePtr          = std::unique_ptr<Wave>;
+using ChannelBufferPtr = std::unique_ptr<channel::Buffer>;
+using ChannelStatePtr  = std::unique_ptr<channel::State>;
 
-template<typename L>
-void onSwap(L& list, ID id, std::function<void(typename L::value_type&)> f)
-{
-       static_assert(has_id<typename L::value_type>(), "This type has no ID");
-       onSwapByIndex_(list, getIndex(list, id), f); 
-}
+#ifdef WITH_VST
+using PluginPtrs = std::vector<PluginPtr>;
+#endif
+using WavePtrs          = std::vector<WavePtr>;
+using Actions           = recorder::ActionMap;
+using ChannelBufferPtrs = std::vector<ChannelBufferPtr>;
+using ChannelStatePtrs  = std::vector<ChannelStatePtr>;
 
+// TODO - are ID-based objects still necessary?
 
-/* onSwap (2) (thread safe)
-Utility function for swapping things in a RCUList when the list contains only
-a single element (and so with no ID). */
+template <typename T>
+T& getAll();
 
-template<typename L>
-void onSwap(L& list, std::function<void(typename L::value_type&)> f)
-{
-       static_assert(!has_id<typename L::value_type>(), "This type has ID");
-       onSwapByIndex_(list, 0, f); 
-}
+/* find
+Finds something (Plugins or Waves) given an ID. Returns nullptr if the object is
+not found. */
 
+template <typename T>
+T* find(ID id);
 
-/* ---------------------------------------------------------------------------*/
+template <typename T>
+void add(T);
 
+template <typename T>
+void remove(const T&);
 
-#ifdef G_DEBUG_MODE
+template <typename T>
+T& back();
 
-void debug();
+template <typename T>
+void clear();
 
+#ifdef G_DEBUG_MODE
+void debug();
 #endif
-}}} // giada::m::model::
-
+} // namespace giada::m::model
 
 #endif
index c8f1a1929b1f37d438b32c75876c8179020c57e4..15eb15be8c784b3f95a95a2282f41e07206658e4 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/model/model.h"
+#include "core/model/storage.h"
 #include "core/channels/channelManager.h"
+#include "core/conf.h"
 #include "core/kernelAudio.h"
+#include "core/model/model.h"
 #include "core/patch.h"
-#include "core/conf.h"
 #include "core/plugins/pluginManager.h"
 #include "core/recorderHandler.h"
-#include "core/waveManager.h"
 #include "core/sequencer.h"
-#include "core/model/storage.h"
+#include "core/waveManager.h"
+#include <cassert>
 
+namespace giada::m::model
+{
+namespace
+{
+void loadChannels_(const std::vector<patch::Channel>& channels, int samplerate)
+{
+       float samplerateRatio = conf::conf.samplerate / static_cast<float>(samplerate);
 
-namespace giada {
-namespace m {
-namespace model
+       for (const patch::Channel& pchannel : channels)
+               get().channels.push_back(channelManager::deserializeChannel(pchannel, samplerateRatio));
+}
+
+/* -------------------------------------------------------------------------- */
+
+void loadActions_(const std::vector<patch::Action>& pactions)
 {
+       getAll<Actions>() = std::move(recorderHandler::deserializeActions(pactions));
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
 void store(patch::Patch& patch)
 {
-#ifdef WITH_VST
-       PluginsLock  pl (plugins);
-#endif
-       ActionsLock  al (actions);
-       WavesLock    wl (waves);
-       ClockLock    cl (clock);
-       ChannelsLock chl(channels);
-
-       patch.bars       = clock.get()->bars;
-       patch.beats      = clock.get()->beats;
-       patch.bpm        = clock.get()->bpm;
-       patch.quantize   = clock.get()->quantize;
-       patch.metronome  = sequencer::isMetronomeOn();
+       const Layout& layout = get();
+
+       patch.bars       = layout.clock.bars;
+       patch.beats      = layout.clock.beats;
+       patch.bpm        = layout.clock.bpm;
+       patch.quantize   = layout.clock.quantize;
+       patch.metronome  = sequencer::isMetronomeOn(); // TODO - add bool metronome to Layout
        patch.samplerate = conf::conf.samplerate;
 
 #ifdef WITH_VST
-       for (const Plugin* p : plugins) 
+       for (const auto& p : getAll<PluginPtrs>())
                patch.plugins.push_back(pluginManager::serializePlugin(*p));
 #endif
 
-       patch.actions = recorderHandler::serializeActions(actions.get()->map); 
+       patch.actions = recorderHandler::serializeActions(getAll<Actions>());
 
-       for (const Wave* w : waves)
+       for (const auto& w : getAll<WavePtrs>())
                patch.waves.push_back(waveManager::serializeWave(*w));
 
-       for (const Channel* c : channels)
-               patch.channels.push_back(channelManager::serializeChannel(*c));
+       for (const channel::Data& c : layout.channels)
+               patch.channels.push_back(channelManager::serializeChannel(c));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void store(conf::Conf& conf)
 {
-       MidiInLock l(midiIn);
-
-       conf.midiInEnabled    = midiIn.get()->enabled;
-       conf.midiInFilter     = midiIn.get()->filter;
-       conf.midiInRewind     = midiIn.get()->rewind;
-       conf.midiInStartStop  = midiIn.get()->startStop;
-       conf.midiInActionRec  = midiIn.get()->actionRec;
-       conf.midiInInputRec   = midiIn.get()->inputRec;
-       conf.midiInMetronome  = midiIn.get()->metronome;
-       conf.midiInVolumeIn   = midiIn.get()->volumeIn;
-       conf.midiInVolumeOut  = midiIn.get()->volumeOut;
-       conf.midiInBeatDouble = midiIn.get()->beatDouble;
-       conf.midiInBeatHalf   = midiIn.get()->beatHalf;
+       const Layout& layout = get();
+
+       conf.midiInEnabled    = layout.midiIn.enabled;
+       conf.midiInFilter     = layout.midiIn.filter;
+       conf.midiInRewind     = layout.midiIn.rewind;
+       conf.midiInStartStop  = layout.midiIn.startStop;
+       conf.midiInActionRec  = layout.midiIn.actionRec;
+       conf.midiInInputRec   = layout.midiIn.inputRec;
+       conf.midiInMetronome  = layout.midiIn.metronome;
+       conf.midiInVolumeIn   = layout.midiIn.volumeIn;
+       conf.midiInVolumeOut  = layout.midiIn.volumeOut;
+       conf.midiInBeatDouble = layout.midiIn.beatDouble;
+       conf.midiInBeatHalf   = layout.midiIn.beatHalf;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void load(const patch::Patch& patch)
 {
-       onSwap(clock, [&](Clock& c)
-       {
-           c.status       = ClockStatus::STOPPED;
-           c.bars         = patch.bars;
-           c.beats        = patch.beats;
-           c.bpm          = patch.bpm;
-           c.quantize     = patch.quantize;
-       });
-
-       onSwap(actions, [&](Actions& a)
-       {
-               a.map = recorderHandler::deserializeActions(patch.actions);
-       });
+       DataLock lock;
+
+       /* Clear and re-initialize channels first. */
+
+       get().channels = {};
+       getAll<ChannelBufferPtrs>().clear();
+       getAll<ChannelStatePtrs>().clear();
+
+       /* Load external data first: plug-ins and waves. */
 
 #ifdef WITH_VST
-    for (const patch::Plugin& pplugin : patch.plugins)
-        plugins.push(pluginManager::deserializePlugin(pplugin, patch.version));
+       getAll<PluginPtrs>().clear();
+       for (const patch::Plugin& pplugin : patch.plugins)
+               getAll<PluginPtrs>().push_back(pluginManager::deserializePlugin(pplugin, patch.version));
 #endif
-    
-       for (const patch::Wave& pwave : patch.waves) {
+
+       getAll<WavePtrs>().clear();
+       for (const patch::Wave& pwave : patch.waves)
+       {
                std::unique_ptr<Wave> w = waveManager::deserializeWave(pwave, conf::conf.samplerate,
-                       conf::conf.rsmpQuality);
+                   conf::conf.rsmpQuality);
                if (w != nullptr)
-                       waves.push(std::move(w));       
+                       getAll<WavePtrs>().push_back(std::move(w));
        }
 
-       channels.clear();
-    for (const patch::Channel& pchannel : patch.channels)
-               channels.push(channelManager::deserializeChannel(pchannel, kernelAudio::getRealBufSize()));
-       
-       /* Load Waves into Channels. */
-
-       ChannelsLock cl(channels);
-       WavesLock    wl(waves);
-
-       float samplerateRatio = conf::conf.samplerate / static_cast<float>(patch::patch.samplerate);
-       
-       for (Channel* c : channels) {
-               if (!c->samplePlayer)
-                       continue;
-               if (exists(waves, c->samplePlayer->getWaveId()))
-                       c->samplePlayer->setWave(get(waves, c->samplePlayer->getWaveId()), samplerateRatio);
-               else
-                       c->samplePlayer->setInvalidWave();
-       }
-}
+       /* Then load up channels, actions and global properties. */
 
+       loadChannels_(patch.channels, patch::patch.samplerate);
+       loadActions_(patch.actions);
 
-/* -------------------------------------------------------------------------- */
+       get().clock.status   = ClockStatus::STOPPED;
+       get().clock.bars     = patch.bars;
+       get().clock.beats    = patch.beats;
+       get().clock.bpm      = patch.bpm;
+       get().clock.quantize = patch.quantize;
+}
 
+/* -------------------------------------------------------------------------- */
 
 void load(const conf::Conf& c)
 {
-       onSwap(midiIn, [&](MidiIn& m)
-       {
-               m.enabled    = c.midiInEnabled;
-               m.filter      = c.midiInFilter;
-               m.rewind     = c.midiInRewind;
-               m.startStop  = c.midiInStartStop;
-               m.actionRec  = c.midiInActionRec;
-               m.inputRec   = c.midiInInputRec;
-               m.volumeIn   = c.midiInVolumeIn;
-               m.volumeOut  = c.midiInVolumeOut;
-               m.beatDouble = c.midiInBeatDouble;
-               m.beatHalf   = c.midiInBeatHalf;
-               m.metronome  = c.midiInMetronome;
-       });     
+       get().midiIn.enabled    = c.midiInEnabled;
+       get().midiIn.filter     = c.midiInFilter;
+       get().midiIn.rewind     = c.midiInRewind;
+       get().midiIn.startStop  = c.midiInStartStop;
+       get().midiIn.actionRec  = c.midiInActionRec;
+       get().midiIn.inputRec   = c.midiInInputRec;
+       get().midiIn.volumeIn   = c.midiInVolumeIn;
+       get().midiIn.volumeOut  = c.midiInVolumeOut;
+       get().midiIn.beatDouble = c.midiInBeatDouble;
+       get().midiIn.beatHalf   = c.midiInBeatHalf;
+       get().midiIn.metronome  = c.midiInMetronome;
+
+       swap(SwapType::NONE);
 }
-}}} // giada::m::model::
+} // namespace giada::m::model
index 75d129adea6894623ed65c4ab9859bbe7f4be1df..c163abed5f5186d5daf0135460c797e1a7772ba0 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MODEL_STORAGE_H
 #define G_MODEL_STORAGE_H
 
-
-namespace giada {
-namespace m {
-namespace patch
+namespace giada::m::patch
 {
 struct Patch;
 }
-namespace conf
+namespace giada::m::conf
 {
 struct Conf;
 }
-namespace model
+namespace giada::m::model
 {
 void store(conf::Conf& c);
 void store(patch::Patch& p);
 void load(const patch::Patch& p);
 void load(const conf::Conf& c);
-}}} // giada::m::model::
-
+} // namespace giada::m::model
 
 #endif
diff --git a/src/core/model/traits.h b/src/core/model/traits.h
deleted file mode 100644 (file)
index a371ae6..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef G_MODEL_TRAITS_H
-#define G_MODEL_TRAITS_H
-
-
-#include <type_traits>
-#include "core/wave.h"
-#include "core/plugins/plugin.h"
-#include "core/channels/channel.h"
-
-
-namespace giada {
-namespace m {
-namespace model
-{
-template <typename T> struct has_id : std::false_type {};
-template <> struct has_id<Channel>  : std::true_type {};
-template <> struct has_id<Wave>     : std::true_type {};
-#ifdef WITH_VST
-template <> struct has_id<Plugin>   : std::true_type {};
-#endif
-}}} // giada::m::model::
-
-
-#endif
index 14a688d4cf6b12876408a40cf5c31def74e7dbad..4ababcda88fee8a9f35e1bd0b88b197119ba5115 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <fstream>
+#include "patch.h"
+#include "core/mixer.h"
 #include "deps/json/single_include/nlohmann/json.hpp"
-#include "utils/math.h"
 #include "utils/log.h"
-#include "core/mixer.h"
-#include "patch.h"
-
+#include "utils/math.h"
+#include <fstream>
 
 namespace nl = nlohmann;
 
-
-namespace giada {
-namespace m {
+namespace giada
+{
+namespace m
+{
 namespace patch
 {
 namespace
@@ -54,34 +53,32 @@ void readCommons_(const nl::json& j)
        patch.metronome  = j.value(PATCH_KEY_METRONOME, false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void readColumns_(const nl::json& j)
 {
        ID id = 0;
-       for (const auto& jcol : j[PATCH_KEY_COLUMNS]) {
+       for (const auto& jcol : j[PATCH_KEY_COLUMNS])
+       {
                Column c;
                c.id    = jcol.value(PATCH_KEY_COLUMN_ID, ++id);
-               c.width = jcol.value(PATCH_KEY_COLUMN_WIDTH, G_DEFAULT_COLUMN_WIDTH);   
+               c.width = jcol.value(PATCH_KEY_COLUMN_WIDTH, G_DEFAULT_COLUMN_WIDTH);
                patch.columns.push_back(c);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 #ifdef WITH_VST
 
-
 void readPlugins_(const nl::json& j)
 {
-       if (!j.contains(PATCH_KEY_PLUGINS))     
+       if (!j.contains(PATCH_KEY_PLUGINS))
                return;
 
        ID id = 0;
-       for (const auto& jplugin : j[PATCH_KEY_PLUGINS]) {
+       for (const auto& jplugin : j[PATCH_KEY_PLUGINS])
+       {
                Plugin p;
                p.id     = jplugin.value(PATCH_KEY_PLUGIN_ID, ++id);
                p.path   = jplugin.value(PATCH_KEY_PLUGIN_PATH, "");
@@ -94,26 +91,24 @@ void readPlugins_(const nl::json& j)
                        p.state = jplugin.value(PATCH_KEY_PLUGIN_STATE, "");
 
                for (const auto& jmidiParam : jplugin[PATCH_KEY_PLUGIN_MIDI_IN_PARAMS])
-                       p.midiInParams.push_back(jmidiParam);                   
+                       p.midiInParams.push_back(jmidiParam);
 
                patch.plugins.push_back(p);
        }
 }
 
-
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void readWaves_(const nl::json& j, const std::string& basePath)
 {
-       if (!j.contains(PATCH_KEY_WAVES))       
+       if (!j.contains(PATCH_KEY_WAVES))
                return;
 
        ID id = 0;
-       for (const auto& jwave : j[PATCH_KEY_WAVES]) {
+       for (const auto& jwave : j[PATCH_KEY_WAVES])
+       {
                Wave w;
                w.id   = jwave.value(PATCH_KEY_WAVE_ID, ++id);
                w.path = basePath + jwave.value(PATCH_KEY_WAVE_PATH, "");
@@ -121,17 +116,16 @@ void readWaves_(const nl::json& j, const std::string& basePath)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void readActions_(const nl::json& j)
 {
-       if (!j.contains(PATCH_KEY_ACTIONS))     
+       if (!j.contains(PATCH_KEY_ACTIONS))
                return;
 
        ID id = 0;
-       for (const auto& jaction : j[PATCH_KEY_ACTIONS]) {
+       for (const auto& jaction : j[PATCH_KEY_ACTIONS])
+       {
                Action a;
                a.id        = jaction.value(G_PATCH_KEY_ACTION_ID, ++id);
                a.channelId = jaction.value(G_PATCH_KEY_ACTION_CHANNEL, 0);
@@ -143,22 +137,21 @@ void readActions_(const nl::json& j)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void readChannels_(const nl::json& j)
 {
-       if (!j.contains(PATCH_KEY_CHANNELS))    
+       if (!j.contains(PATCH_KEY_CHANNELS))
                return;
 
        ID defaultId = mixer::PREVIEW_CHANNEL_ID;
 
-       for (const auto& jchannel : j[PATCH_KEY_CHANNELS]) {
+       for (const auto& jchannel : j[PATCH_KEY_CHANNELS])
+       {
                Channel c;
                c.id                = jchannel.value(PATCH_KEY_CHANNEL_ID, ++defaultId);
                c.type              = static_cast<ChannelType>(jchannel.value(PATCH_KEY_CHANNEL_TYPE, 1));
-               c.volume            = jchannel.value(PATCH_KEY_CHANNEL_VOLUME, G_DEFAULT_VOL);          
+               c.volume            = jchannel.value(PATCH_KEY_CHANNEL_VOLUME, G_DEFAULT_VOL);
                c.height            = jchannel.value(PATCH_KEY_CHANNEL_SIZE, G_GUI_UNIT);
                c.name              = jchannel.value(PATCH_KEY_CHANNEL_NAME, "");
                c.columnId          = jchannel.value(PATCH_KEY_CHANNEL_COLUMN, 1);
@@ -197,8 +190,8 @@ void readChannels_(const nl::json& j)
                c.midiOutChan       = jchannel.value(PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, 0);
 
 #ifdef WITH_VST
-               if (jchannel.contains(PATCH_KEY_CHANNEL_PLUGINS))       
-                       for (const auto& jplugin : jchannel[PATCH_KEY_CHANNEL_PLUGINS]) 
+               if (jchannel.contains(PATCH_KEY_CHANNEL_PLUGINS))
+                       for (const auto& jplugin : jchannel[PATCH_KEY_CHANNEL_PLUGINS])
                                c.pluginIds.push_back(jplugin);
 #endif
 
@@ -206,17 +199,16 @@ void readChannels_(const nl::json& j)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 void writePlugins_(nl::json& j)
 {
        j[PATCH_KEY_PLUGINS] = nl::json::array();
 
-       for (const Plugin& p : patch.plugins) {
+       for (const Plugin& p : patch.plugins)
+       {
 
                nl::json jplugin;
 
@@ -228,22 +220,21 @@ void writePlugins_(nl::json& j)
                jplugin[PATCH_KEY_PLUGIN_MIDI_IN_PARAMS] = nl::json::array();
                for (uint32_t param : p.midiInParams)
                        jplugin[PATCH_KEY_PLUGIN_MIDI_IN_PARAMS].push_back(param);
-               
+
                j[PATCH_KEY_PLUGINS].push_back(jplugin);
        }
 }
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void writeColumns_(nl::json& j)
 {
        j[PATCH_KEY_COLUMNS] = nl::json::array();
 
-       for (const Column& column : patch.columns) {
+       for (const Column& column : patch.columns)
+       {
                nl::json jcolumn;
                jcolumn[PATCH_KEY_COLUMN_ID]    = column.id;
                jcolumn[PATCH_KEY_COLUMN_WIDTH] = column.width;
@@ -251,15 +242,14 @@ void writeColumns_(nl::json& j)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void writeActions_(nl::json& j)
 {
        j[PATCH_KEY_ACTIONS] = nl::json::array();
 
-       for (const Action& a : patch.actions) {
+       for (const Action& a : patch.actions)
+       {
                nl::json jaction;
                jaction[G_PATCH_KEY_ACTION_ID]      = a.id;
                jaction[G_PATCH_KEY_ACTION_CHANNEL] = a.channelId;
@@ -271,15 +261,14 @@ void writeActions_(nl::json& j)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void writeWaves_(nl::json& j)
 {
        j[PATCH_KEY_WAVES] = nl::json::array();
 
-       for (const Wave& w : patch.waves) {
+       for (const Wave& w : patch.waves)
+       {
                nl::json jwave;
                jwave[PATCH_KEY_WAVE_ID]   = w.id;
                jwave[PATCH_KEY_WAVE_PATH] = w.path;
@@ -290,7 +279,6 @@ void writeWaves_(nl::json& j)
 
 /* -------------------------------------------------------------------------- */
 
-
 void writeCommons_(nl::json& j)
 {
        j[PATCH_KEY_HEADER]        = "GIADAPTC";
@@ -307,15 +295,14 @@ void writeCommons_(nl::json& j)
        j[PATCH_KEY_METRONOME]     = patch.metronome;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void writeChannels_(nl::json& j)
 {
        j[PATCH_KEY_CHANNELS] = nl::json::array();
 
-       for (const Channel& c : patch.channels) {
+       for (const Channel& c : patch.channels)
+       {
 
                nl::json jchannel;
 
@@ -369,76 +356,69 @@ void writeChannels_(nl::json& j)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void modernize_()
 {
-       for (Channel& c : patch.channels) {
+       for (Channel& c : patch.channels)
+       {
                /* 0.16.3
                Make sure that ChannelType is correct: ID 1, 2 are MASTER channels, ID 3 
                is PREVIEW channel. */
                if (c.id == mixer::MASTER_OUT_CHANNEL_ID || c.id == mixer::MASTER_IN_CHANNEL_ID)
                        c.type = ChannelType::MASTER;
-               else
-               if (c.id == mixer::PREVIEW_CHANNEL_ID)
+               else if (c.id == mixer::PREVIEW_CHANNEL_ID)
                        c.type = ChannelType::PREVIEW;
-               
+
                /* 0.16.4
                Make sure internal channels are never armed. */
                if (c.type == ChannelType::PREVIEW || c.type == ChannelType::MASTER)
                        c.armed = false;
-               
+
                /* 0.16.3
                Set panning to default (0.5) and waveId to 0 for non-Sample Channels. */
-               if (c.type != ChannelType::SAMPLE) {
+               if (c.type != ChannelType::SAMPLE)
+               {
                        c.pan    = G_DEFAULT_PAN;
                        c.waveId = 0;
                }
-       }       
+       }
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Patch patch;
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool Version::operator ==(const Version& o) const
+bool Version::operator==(const Version& o) const
 {
-       return major == o.major && minor == o.minor && patch == o.patch;        
+       return major == o.major && minor == o.minor && patch == o.patch;
 }
 
-
-bool Version::operator <(const Version& o) const
+bool Version::operator<(const Version& o) const
 {
-       if (major < o.major) return true;
-       if (minor < o.minor) return true;
-       if (patch < o.patch) return true;
+       if (major < o.major)
+               return true;
+       if (minor < o.minor)
+               return true;
+       if (patch < o.patch)
+               return true;
        return false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
        patch = Patch();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool write(const std::string& file)
 {
        nl::json j;
@@ -452,38 +432,36 @@ bool write(const std::string& file)
        writePlugins_(j);
 #endif
 
-    std::ofstream ofs(file);
+       std::ofstream ofs(file);
        if (!ofs.good())
                return false;
 
-    ofs << j;
+       ofs << j;
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int read(const std::string& file, const std::string& basePath)
 {
        std::ifstream ifs(file);
        if (!ifs.good())
                return G_PATCH_UNREADABLE;
-       
+
        nl::json j = nl::json::parse(ifs);
 
        if (j[PATCH_KEY_HEADER] != "GIADAPTC")
                return G_PATCH_INVALID;
-       
+
        patch.version = {
-               static_cast<int>(j[PATCH_KEY_VERSION_MAJOR]),
-               static_cast<int>(j[PATCH_KEY_VERSION_MINOR]),
-               static_cast<int>(j[PATCH_KEY_VERSION_PATCH])
-       };
+           static_cast<int>(j[PATCH_KEY_VERSION_MAJOR]),
+           static_cast<int>(j[PATCH_KEY_VERSION_MINOR]),
+           static_cast<int>(j[PATCH_KEY_VERSION_PATCH])};
        if (patch.version < Version{0, 16, 0})
                return G_PATCH_UNSUPPORTED;
 
-       try {
+       try
+       {
                readCommons_(j);
                readColumns_(j);
 #ifdef WITH_VST
@@ -494,11 +472,14 @@ int read(const std::string& file, const std::string& basePath)
                readChannels_(j);
                modernize_();
        }
-       catch (nl::json::exception& e) {
+       catch (nl::json::exception& e)
+       {
                u::log::print("[patch::read] Exception thrown: %s\n", e.what());
                return G_PATCH_INVALID;
        }
 
        return G_PATCH_OK;
 }
-}}} // giada::m::patch::
+} // namespace patch
+} // namespace m
+} // namespace giada
index 0b4e32a802c07c6684670f8f7174cf36ddc1c69a..0a28cabf29cfa00106ce5186c022262d9de1e824 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_PATCH_H
 #define G_PATCH_H
 
-
+#include "core/const.h"
+#include "core/types.h"
+#include <cstdint>
 #include <string>
 #include <vector>
-#include <cstdint>
-#include "core/types.h"
-#include "core/const.h"
-
 
-namespace giada {
-namespace m {
+namespace giada
+{
+namespace m
+{
 namespace patch
 {
 struct Version
@@ -46,18 +45,16 @@ struct Version
        int minor = G_VERSION_MINOR;
        int patch = G_VERSION_PATCH;
 
-       bool operator ==(const Version& o) const;
-       bool operator < (const Version& o) const;
+       bool operator==(const Version& o) const;
+       bool operator<(const Version& o) const;
 };
 
-
 struct Column
 {
        ID  id;
        int width;
 };
 
-
 struct Channel
 {
        ID          id;
@@ -99,14 +96,13 @@ struct Channel
        uint32_t         midiInReadActions;
        uint32_t         midiInPitch;
        // midi channel
-       bool        midiOut;
-       int         midiOutChan;
+       bool midiOut;
+       int  midiOutChan;
 #ifdef WITH_VST
        std::vector<ID> pluginIds;
 #endif
 };
 
-
 struct Action
 {
        ID       id;
@@ -117,14 +113,12 @@ struct Action
        ID       nextId;
 };
 
-
 struct Wave
 {
        ID          id;
        std::string path;
 };
 
-
 #ifdef WITH_VST
 struct Plugin
 {
@@ -137,7 +131,6 @@ struct Plugin
 };
 #endif
 
-
 struct Patch
 {
        Version     version;
@@ -155,17 +148,14 @@ struct Patch
        std::vector<Action>  actions;
        std::vector<Wave>    waves;
 #ifdef WITH_VST
-       std::vector<Plugin>  plugins;
+       std::vector<Plugin> plugins;
 #endif
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 extern Patch patch;
 
-
 /* -------------------------------------------------------------------------- */
 
 /* init
@@ -182,7 +172,8 @@ int read(const std::string& file, const std::string& basePath);
 Writes patch to file. */
 
 bool write(const std::string& file);
-}}}  // giada::m::patch::
-
+} // namespace patch
+} // namespace m
+} // namespace giada
 
 #endif
index df5909d1f5b7314779f8761cfb52e008a1a850a2..5e7011261c03ae1090a6f8ce870f69d0a92a2066 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <cassert>
-#include <FL/Fl.H>
-#include "utils/log.h"
-#include "utils/time.h"
+#include "plugin.h"
 #include "core/const.h"
 #include "core/plugins/pluginManager.h"
-#include "plugin.h"
-
-
-using std::string;
-
+#include "utils/log.h"
+#include "utils/time.h"
+#include <FL/Fl.H>
+#include <cassert>
 
-namespace giada {
-namespace m 
+namespace giada::m
 {
 Plugin::Plugin(ID id, const std::string& UID)
-: id            (id)
-, valid         (false)
+: id(id)
+, valid(false)
 , onEditorResize(nullptr)
-, m_plugin      (nullptr)
-, m_UID         (UID)
+, m_plugin(nullptr)
+, m_UID(UID)
+, m_hasEditor(false)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Plugin::Plugin(ID id, std::unique_ptr<juce::AudioPluginInstance> plugin, double samplerate,
-       int buffersize)
-: id            (id)
-, valid         (true)
+    int buffersize)
+: id(id)
+, valid(true)
 , onEditorResize(nullptr)
-, m_plugin      (std::move(plugin))
-, m_bypass      (false)
+, m_plugin(std::move(plugin))
+, m_playHead(std::make_unique<pluginHost::Info>())
+, m_bypass(false)
+, m_hasEditor(m_plugin->hasEditor())
 {
        /* (1) Initialize midiInParams vector, where midiInParams.size == number of 
        plugin parameters. All values are initially empty (0x0): they will be filled
@@ -78,33 +72,36 @@ Plugin::Plugin(ID id, std::unique_ptr<juce::AudioPluginInstance> plugin, double
 
        juce::AudioProcessor::Bus* outBus = getMainBus(BusType::OUT);
        juce::AudioProcessor::Bus* inBus  = getMainBus(BusType::IN);
-       if (outBus != nullptr) outBus->setNumberOfChannels(G_MAX_IO_CHANS);
-       if (inBus != nullptr)  inBus->setNumberOfChannels(G_MAX_IO_CHANS);
+       if (outBus != nullptr)
+               outBus->setNumberOfChannels(G_MAX_IO_CHANS);
+       if (inBus != nullptr)
+               inBus->setNumberOfChannels(G_MAX_IO_CHANS);
+
+       /* Set pointer to PlayHead, used to pass Giada information (bpm, time, ...)
+       to the plug-in. */
+
+       m_plugin->setPlayHead(m_playHead.get());
 
        m_plugin->prepareToPlay(samplerate, buffersize);
 
-       u::log::print("[Plugin] plugin initialized and ready. MIDI input params: %lu\n", 
-               midiInParams.size());
+       u::log::print("[Plugin] plugin initialized and ready. MIDI input params: %lu\n",
+           midiInParams.size());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Plugin::Plugin(const Plugin& o)
-: id            (o.id)
-, midiInParams  (o.midiInParams)
-, valid         (o.valid)
+: id(o.id)
+, midiInParams(o.midiInParams)
+, valid(o.valid)
 , onEditorResize(o.onEditorResize)
-, m_plugin      (std::move(pluginManager::makePlugin(o)->m_plugin))
-, m_bypass      (o.m_bypass.load())
+, m_plugin(std::move(pluginManager::makePlugin(o)->m_plugin))
+, m_bypass(o.m_bypass.load())
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Plugin::~Plugin()
 {
        if (!valid)
@@ -118,11 +115,9 @@ Plugin::~Plugin()
        m_plugin->releaseResources();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void Plugin::componentMovedOrResized(juce::Component& c, bool moved, bool/* resized*/)
+void Plugin::componentMovedOrResized(juce::Component& c, bool moved, bool /* resized*/)
 {
        if (moved)
                return;
@@ -130,20 +125,17 @@ void Plugin::componentMovedOrResized(juce::Component& c, bool moved, bool/* resi
                onEditorResize(c.getWidth(), c.getHeight());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 juce::AudioProcessor::Bus* Plugin::getMainBus(BusType b) const
 {
        const bool isInput = static_cast<bool>(b);
-       for (int i=0; i<m_plugin->getBusCount(isInput); i++)
+       for (int i = 0; i < m_plugin->getBusCount(isInput); i++)
                if (m_plugin->getBus(isInput, i)->isMain())
-                       return m_plugin->getBus(isInput, i); 
+                       return m_plugin->getBus(isInput, i);
        return nullptr;
 }
 
-
 int Plugin::countMainOutChannels() const
 {
        juce::AudioProcessor::Bus* b = getMainBus(BusType::OUT);
@@ -151,10 +143,8 @@ int Plugin::countMainOutChannels() const
        return b->getNumberOfChannels();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 juce::AudioProcessorEditor* Plugin::createEditor() const
 {
        juce::AudioProcessorEditor* e = m_plugin->createEditorIfNeeded();
@@ -163,59 +153,47 @@ juce::AudioProcessorEditor* Plugin::createEditor() const
        return e;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-string Plugin::getUniqueId() const
+std::string Plugin::getUniqueId() const
 {
        if (!valid)
                return m_UID;
        return m_plugin->getPluginDescription().createIdentifierString().toStdString();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int Plugin::getNumParameters() const
 {
        return valid ? m_plugin->getParameters().size() : 0;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 float Plugin::getParameter(int paramIndex) const
 {
        return m_plugin->getParameters()[paramIndex]->getValue();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Plugin::setParameter(int paramIndex, float value) const
 {
        m_plugin->getParameters()[paramIndex]->setValue(value);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-string Plugin::getName() const
+std::string Plugin::getName() const
 {
        if (!valid)
                return "** invalid **";
        return m_plugin->getName().toStdString();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool Plugin::isSuspended() const
 {
        if (!valid)
@@ -223,10 +201,8 @@ bool Plugin::isSuspended() const
        return m_plugin->isSuspended();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool Plugin::acceptsMidi() const
 {
        if (!valid)
@@ -234,28 +210,24 @@ bool Plugin::acceptsMidi() const
        return m_plugin->acceptsMidi();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 PluginState Plugin::getState() const
 {
+       if (!valid)
+               return {};
        juce::MemoryBlock data;
        m_plugin->getStateInformation(data);
        return PluginState(std::move(data));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool Plugin::isBypassed() const { return m_bypass.load(); }
 void Plugin::setBypass(bool b) { m_bypass.store(b); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Plugin::process(juce::AudioBuffer<float>& out, juce::MidiBuffer m)
 {
        /* If this is not an instrument (i.e. doesn't accept MIDI), copy the 
@@ -278,7 +250,8 @@ void Plugin::process(juce::AudioBuffer<float>& out, juce::MidiBuffer m)
        by taking into account the bus layout - many plug-ins might have mono output
        and we have a stereo buffer to fill. */
 
-       for (int i=0, j=0; i<out.getNumChannels(); i++) {
+       for (int i = 0, j = 0; i < out.getNumChannels(); i++)
+       {
                if (isInstrument)
                        out.addFrom(i, 0, m_buffer, j, 0, m_buffer.getNumSamples());
                else
@@ -288,19 +261,15 @@ void Plugin::process(juce::AudioBuffer<float>& out, juce::MidiBuffer m)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Plugin::setState(PluginState state)
 {
        m_plugin->setStateInformation(state.getData(), state.getSize());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int Plugin::getNumPrograms() const
 {
        if (!valid)
@@ -308,10 +277,8 @@ int Plugin::getNumPrograms() const
        return m_plugin->getNumPrograms();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int Plugin::getCurrentProgram() const
 {
        if (!valid)
@@ -319,43 +286,33 @@ int Plugin::getCurrentProgram() const
        return m_plugin->getCurrentProgram();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Plugin::setCurrentProgram(int index) const
 {
        if (valid)
                m_plugin->setCurrentProgram(index);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool Plugin::hasEditor() const
 {
-       if (!valid)
-               return false;
-       return m_plugin->hasEditor();
+       return m_hasEditor;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-string Plugin::getProgramName(int index) const
+std::string Plugin::getProgramName(int index) const
 {
        if (!valid)
                return {};
        return m_plugin->getProgramName(index).toStdString();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-string Plugin::getParameterName(int index) const
+std::string Plugin::getParameterName(int index) const
 {
        if (!valid)
                return {};
@@ -363,25 +320,19 @@ string Plugin::getParameterName(int index) const
        return m_plugin->getParameters()[index]->getName(labelSize).toStdString();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-string Plugin::getParameterText(int index) const
+std::string Plugin::getParameterText(int index) const
 {
        return m_plugin->getParameters()[index]->getCurrentValueAsText().toStdString();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-string Plugin::getParameterLabel(int index) const
+std::string Plugin::getParameterLabel(int index) const
 {
        return m_plugin->getParameters()[index]->getLabel().toStdString();
 }
-
-}} // giada::m::
-
+} // namespace giada::m
 
 #endif
index 6ec9608732e46fe08fa5c8c0ade2f0c81c730e58..665d2bbbff046a1bfa36b26c97b669c6974a8302 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 #ifndef G_PLUGIN_H
 #define G_PLUGIN_H
 
-
-#include <vector>
-#include "deps/juce-config.h"
+#include "core/const.h"
+#include "core/midiLearnParam.h"
 #include "core/plugins/pluginHost.h"
 #include "core/plugins/pluginState.h"
-#include "core/midiLearnParam.h"
-#include "core/const.h"
-
+#include "deps/juce-config.h"
+#include <vector>
 
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class Plugin : private juce::ComponentListener
 {
 public:
-
        Plugin(ID id, const std::string& UID);
        Plugin(ID id, std::unique_ptr<juce::AudioPluginInstance> p, double samplerate, int buffersize);
        Plugin(const Plugin& o);
        ~Plugin();
+       /* TODO - mark is as non-copiable/movable*/
 
        /* getUniqueId
        Returns a string-based UID. */
 
-       std::string getUniqueId() const;
-       std::string getName() const;
-       bool hasEditor() const;
-       int getNumParameters() const;
-       float getParameter(int index) const;
-       std::string getParameterName(int index) const;
-       std::string getParameterText(int index) const;
-       std::string getParameterLabel(int index) const;
-       bool isSuspended() const;
-       bool isBypassed() const;
-       int getNumPrograms() const;
-       int getCurrentProgram() const;
-       std::string getProgramName(int index) const;
-       void setParameter(int index, float value) const;
-       void setCurrentProgram(int index) const;
-       bool acceptsMidi() const;
-       PluginState getState() const;
+       std::string                 getUniqueId() const;
+       std::string                 getName() const;
+       bool                        hasEditor() const;
+       int                         getNumParameters() const;
+       float                       getParameter(int index) const;
+       std::string                 getParameterName(int index) const;
+       std::string                 getParameterText(int index) const;
+       std::string                 getParameterLabel(int index) const;
+       bool                        isSuspended() const;
+       bool                        isBypassed() const;
+       int                         getNumPrograms() const;
+       int                         getCurrentProgram() const;
+       std::string                 getProgramName(int index) const;
+       void                        setParameter(int index, float value) const;
+       void                        setCurrentProgram(int index) const;
+       bool                        acceptsMidi() const;
+       PluginState                 getState() const;
        juce::AudioProcessorEditor* createEditor() const;
 
        /* process
@@ -81,7 +77,7 @@ public:
        copy. */
 
        void process(juce::AudioBuffer<float>& b, juce::MidiBuffer m);
-       
+
        void setState(PluginState p);
        void setBypass(bool b);
 
@@ -95,7 +91,7 @@ public:
        external hardware. */
 
        std::vector<MidiLearnParam> midiInParams;
-       
+
        /* valid
        A missing plug-in is loaded anyway, yet marked as 'invalid'. */
 
@@ -104,20 +100,20 @@ public:
        std::function<void(int w, int h)> onEditorResize;
 
 private:
-
 #ifdef G_OS_WINDOWS
-       /* Fuck... */
-       #undef IN
-       #undef OUT
+/* Fuck... */
+#undef IN
+#undef OUT
 #endif
 
-       enum class BusType 
-       { 
-               IN = true, OUT = false 
+       enum class BusType
+       {
+               IN  = true,
+               OUT = false
        };
 
        /* JUCE overrides. */
-       
+
        void componentMovedOrResized(juce::Component& c, bool moved, bool resized) override;
 
        juce::AudioProcessor::Bus* getMainBus(BusType b) const;
@@ -128,6 +124,7 @@ private:
        int countMainOutChannels() const;
 
        std::unique_ptr<juce::AudioPluginInstance> m_plugin;
+       std::unique_ptr<pluginHost::Info>          m_playHead;
        juce::AudioBuffer<float>                   m_buffer;
 
        std::atomic<bool> m_bypass;
@@ -136,8 +133,14 @@ private:
        The original UID, used for missing plugins. */
 
        std::string m_UID;
+
+       /* m_hasEditor
+       Cached boolean value that tells if the plug-in has editor. Some plug-ins
+       take ages to query it, better fetch the property during construction. */
+
+       bool m_hasEditor;
 };
-}} // giada::m::
+} // namespace giada::m
 
 #endif
 
index 62715353d443893a7d3047ab2333b3135a56ba61..4ffdbed37d33663b84c6819d938d14bce1710378 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-#include <cassert>
-#include "utils/log.h"
-#include "utils/vector.h"
-#include "core/model/model.h"
+#include "core/plugins/pluginHost.h"
 #include "core/channels/channel.h"
+#include "core/clock.h"
 #include "core/const.h"
+#include "core/model/model.h"
 #include "core/plugins/plugin.h"
 #include "core/plugins/pluginManager.h"
-#include "core/plugins/pluginHost.h"
-
+#include "utils/log.h"
+#include "utils/vector.h"
+#include <cassert>
 
-namespace giada {
-namespace m {
-namespace pluginHost
+namespace giada::m::pluginHost
 {
 namespace
 {
-juce::MessageManager* messageManager_;
+std::vector<Plugin*>     plugins_;
+juce::MessageManager*    messageManager_;
 juce::AudioBuffer<float> audioBuffer_;
-ID pluginId_;
-
+ID                       pluginId_;
 
 /* -------------------------------------------------------------------------- */
 
-
 void giadaToJuceTempBuf_(const AudioBuffer& outBuf)
 {
-       for (int i=0; i<outBuf.countFrames(); i++)
-               for (int j=0; j<outBuf.countChannels(); j++)
+       for (int i = 0; i < outBuf.countFrames(); i++)
+               for (int j = 0; j < outBuf.countChannels(); j++)
                        audioBuffer_.setSample(j, i, outBuf[i][j]);
 }
 
-
 /* juceToGiadaOutBuf_
 Converts buffer from Juce to Giada. A note for the future: if we overwrite (=) 
 (as we do now) it's SEND, if we add (+) it's INSERT. */
 
 void juceToGiadaOutBuf_(AudioBuffer& outBuf)
 {
-       for (int i=0; i<outBuf.countFrames(); i++)
-               for (int j=0; j<outBuf.countChannels(); j++)    
+       for (int i = 0; i < outBuf.countFrames(); i++)
+               for (int j = 0; j < outBuf.countChannels(); j++)
                        outBuf[i][j] = audioBuffer_.getSample(j, i);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void processPlugins_(const std::vector<ID>& pluginIds, juce::MidiBuffer& events)
+void processPlugins_(const std::vector<Plugin*>& plugins, juce::MidiBuffer& events)
 {
-       model::PluginsLock l(model::plugins);
-
-       for (ID id : pluginIds) {
-               Plugin& p = model::get(model::plugins, id);
-               if (!p.valid || p.isSuspended() || p.isBypassed())
+       for (Plugin* p : plugins)
+       {
+               if (!p->valid || p->isSuspended() || p->isBypassed())
                        continue;
-               p.process(audioBuffer_, events);
-               events.clear();
+               p->process(audioBuffer_, events);
        }
+       events.clear();
 }
+} // namespace
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 
-ID clonePlugin_(ID pluginId)
+bool Info::getCurrentPosition(CurrentPositionInfo& result)
 {
-       model::PluginsLock l(model::plugins);
+       result.bpm           = clock::getBpm();
+       result.timeInSamples = clock::getCurrentFrame();
+       result.timeInSeconds = clock::getCurrentSecond();
+       result.isPlaying     = clock::isRunning();
 
-       const Plugin&           original = model::get(model::plugins, pluginId);
-       std::unique_ptr<Plugin> clone    = pluginManager::makePlugin(original);
-       ID                      newId    = clone->id;
+       return true;
+}
 
-       model::plugins.push(std::move(clone));
+/* -------------------------------------------------------------------------- */
 
-       return newId;
+bool Info::canControlTransport()
+{
+       return false;
 }
-} // {anonymous}
-
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void close()
 {
        messageManager_->deleteInstance();
-       model::plugins.clear();
+       model::clear<model::PluginPtrs>();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void init(int buffersize)
 {
        messageManager_ = juce::MessageManager::getInstance();
@@ -126,12 +120,10 @@ void init(int buffersize)
        pluginId_ = 0;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void processStack(AudioBuffer& outBuf, const std::vector<ID>& pluginIds, 
-       juce::MidiBuffer* events)
+void processStack(AudioBuffer& outBuf, const std::vector<Plugin*>& plugins,
+    juce::MidiBuffer* events)
 {
        assert(outBuf.countFrames() == audioBuffer_.getNumSamples());
 
@@ -139,129 +131,105 @@ void processStack(AudioBuffer& outBuf, const std::vector<ID>& pluginIds,
        sample channels. No need for MIDI events. 
        If events are not null: MIDI stack (MIDI channels). MIDI channels must not 
        process the current buffer: give them an empty and clean one. */
-       
-       if (events == nullptr) {
+
+       if (events == nullptr)
+       {
                giadaToJuceTempBuf_(outBuf);
                juce::MidiBuffer dummyEvents; // empty
-               processPlugins_(pluginIds, dummyEvents);
+               processPlugins_(plugins, dummyEvents);
        }
-       else {
+       else
+       {
                audioBuffer_.clear();
-               processPlugins_(pluginIds, *events);
+               processPlugins_(plugins, *events);
        }
        juceToGiadaOutBuf_(outBuf);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void addPlugin(std::unique_ptr<Plugin> p, ID channelId)
 {
-       ID pluginId = p->id;
-       
-       model::plugins.push(std::move(p));
+       model::add(std::move(p));
 
-       model::onSwap(model::channels, channelId, [&](Channel& c)
-       {
-               c.pluginIds.push_back(pluginId);
-       });
-}
+       const Plugin& pluginRef = model::back<Plugin>();
 
+       /* TODO - unfortunately JUCE wants mutable plugin objects due to the
+       presence of the non-const processBlock() method. Why not const_casting
+       only in the Plugin class? */
+       model::get().getChannel(channelId).plugins.push_back(const_cast<Plugin*>(&pluginRef));
+       model::swap(model::SwapType::HARD);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void swapPlugin(ID pluginId1, ID pluginId2, ID channelId)
+void swapPlugin(const m::Plugin& p1, const m::Plugin& p2, ID channelId)
 {
-       model::onSwap(model::channels, channelId, [&](Channel& c)
-       {
-               auto a = u::vector::indexOf(c.pluginIds, pluginId1); 
-               auto b = u::vector::indexOf(c.pluginIds, pluginId2); 
-       
-               std::swap(c.pluginIds.at(a), c.pluginIds.at(b));
-       });
-}
+       std::vector<m::Plugin*>& pvec   = model::get().getChannel(channelId).plugins;
+       std::size_t              index1 = u::vector::indexOf(pvec, &p1);
+       std::size_t              index2 = u::vector::indexOf(pvec, &p2);
+       std::swap(pvec.at(index1), pvec.at(index2));
 
+       model::swap(model::SwapType::HARD);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void freePlugin(ID pluginId, ID channelId)
+void freePlugin(const m::Plugin& plugin, ID channelId)
 {
-       model::onSwap(model::channels, channelId, [&](Channel& c)
-       {
-               u::vector::remove(c.pluginIds, pluginId);
-       });
-
-       model::plugins.pop(model::getIndex(model::plugins, pluginId));
+       u::vector::remove(model::get().getChannel(channelId).plugins, &plugin);
+       model::swap(model::SwapType::HARD);
+       model::remove(plugin);
 }
 
-
-void freePlugins(const std::vector<ID>& pluginIds)
+void freePlugins(const std::vector<Plugin*>& plugins)
 {
-       for (ID id : pluginIds)
-               model::plugins.pop(model::getIndex(model::plugins, id));
+       // TODO - channels???
+       for (const Plugin* p : plugins)
+               model::remove(*p);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-std::vector<ID> clonePlugins(std::vector<ID> pluginIds)
+std::vector<Plugin*> clonePlugins(const std::vector<Plugin*>& plugins)
 {
-       std::vector<ID> out;
-       for (ID id : pluginIds)
-               out.push_back(clonePlugin_(id));
+       std::vector<Plugin*> out;
+       for (const Plugin* p : plugins)
+       {
+               model::add(pluginManager::makePlugin(*p));
+               out.push_back(&model::back<Plugin>());
+       }
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setPluginParameter(ID pluginId, int paramIndex, float value)
 {
-       model::onGet(model::plugins, pluginId, [&](Plugin& p)
-       {
-               p.setParameter(paramIndex, value);
-       });
+       model::find<Plugin>(pluginId)->setParameter(paramIndex, value);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setPluginProgram(ID pluginId, int programIndex)
 {
-       model::onGet(model::plugins, pluginId, [&](Plugin& p)
-       {
-               p.setCurrentProgram(programIndex);
-       });
+       model::find<Plugin>(pluginId)->setCurrentProgram(programIndex);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleBypass(ID pluginId)
 {
-       model::onGet(model::plugins, pluginId, [&](Plugin& p)
-       {
-               p.setBypass(!p.isBypassed());
-       });
+       Plugin& plugin = *model::find<Plugin>(pluginId);
+       plugin.setBypass(!plugin.isBypassed());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void runDispatchLoop()
 {
        messageManager_->runDispatchLoopUntil(10);
 }
-
-}}} // giada::m::pluginHost::
-
+} // namespace giada::m::pluginHost
 
 #endif // #ifdef WITH_VST
index d75d21cbbce88785f711f47f18b14e803c9a9405..cff690e1a3bd0c9988f03c21ad2409eff73dceb0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef G_PLUGIN_HOST_H
 #define G_PLUGIN_HOST_H
 
-
-#include <functional>
-#include "deps/juce-config.h"
 #include "core/types.h"
+#include "deps/juce-config.h"
+#include <functional>
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class Plugin;
 class AudioBuffer;
-namespace pluginHost
+} // namespace giada::m
+namespace giada::m::pluginHost
+{
+struct Info : public juce::AudioPlayHead
 {
-using Stack = std::vector<std::shared_ptr<Plugin>>;
+       bool getCurrentPosition(CurrentPositionInfo& result) override;
+       bool canControlTransport() override;
+};
+
+/* -------------------------------------------------------------------------- */
 
 void init(int buffersize);
 void close();
@@ -57,42 +59,38 @@ void addPlugin(std::unique_ptr<Plugin> p, ID channelId);
 /* processStack
 Applies the fx list to the buffer. */
 
-void processStack(AudioBuffer& outBuf, const std::vector<ID>& pluginIds, 
-       juce::MidiBuffer* events=nullptr);
+void processStack(AudioBuffer& outBuf, const std::vector<Plugin*>& plugins,
+    juce::MidiBuffer* events = nullptr);
 
 /* swapPlugin 
-Swaps plug-in with ID 1 with plug-in with ID 2 in Channel 'channelId'. */
+Swaps plug-in 1 with plug-in 2 in Channel 'channelId'. */
 
-void swapPlugin(ID pluginId1, ID pluginId2, ID channelId);
+void swapPlugin(const m::Plugin& p1, const m::Plugin& p2, ID channelId);
 
 /* freePlugin.
 Unloads plugin from channel 'channelId'. */
 
-void freePlugin(ID pluginId, ID channelId);
+void freePlugin(const m::Plugin& plugin, ID channelId);
 
 /* freePlugins
 Unloads multiple plugins. Useful when freeing or deleting a channel. */
 
-void freePlugins(const std::vector<ID>& pluginIds);
+void freePlugins(const std::vector<Plugin*>& plugins);
 
 /* clonePlugins
-Clones all the plug-ins from 'pluginIds' vector coming from the old channel
-and returns new IDs. */
+Clones all the plug-ins in the 'plugins' vector. */
 
-std::vector<ID> clonePlugins(std::vector<ID> pluginIds);
+std::vector<Plugin*> clonePlugins(const std::vector<Plugin*>& plugins);
 
 void setPluginParameter(ID pluginId, int paramIndex, float value);
-
-void setPluginProgram(ID pluginId, int programIndex); 
-
+void setPluginProgram(ID pluginId, int programIndex);
 void toggleBypass(ID pluginId);
 
 /* runDispatchLoop
 Wakes up plugins' GUI manager for N milliseconds. */
 
 void runDispatchLoop();
-}}} // giada::m::pluginHost::
-
+} // namespace giada::m::pluginHost
 
 #endif
 
index a1c607787693506b4262ae8e7bf40e9f630d4250..482c4be959e8074c0af464245ca7ce1ea9cd31fc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <cassert>
-#include "utils/log.h"
-#include "utils/fs.h"
-#include "utils/string.h"
+#include "pluginManager.h"
+#include "core/conf.h"
 #include "core/const.h"
 #include "core/idManager.h"
+#include "core/model/model.h"
 #include "core/patch.h"
-#include "core/conf.h"
 #include "core/plugins/plugin.h"
-#include "pluginManager.h"
-
+#include "utils/fs.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include <cassert>
 
-namespace giada {
-namespace m {
-namespace pluginManager
+namespace giada::m::pluginManager
 {
 namespace
 {
@@ -71,26 +67,23 @@ If some plugins from any stack are missing. */
 
 bool missingPlugins_;
 
-
 std::unique_ptr<Plugin> makeInvalidPlugin_(const std::string& pid, ID id)
 {
        missingPlugins_ = true;
        unknownPluginList_.push_back(pid);
-       return std::make_unique<Plugin>(pluginId_.get(id), pid); // Invalid plug-in     
+       return std::make_unique<Plugin>(pluginId_.generate(id), pid); // Invalid plug-in
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void init(int samplerate, int buffersize)
 {
        pluginId_       = IdManager();
        samplerate_     = samplerate;
-    buffersize_     = buffersize;
+       buffersize_     = buffersize;
        missingPlugins_ = false;
 
        formatManager_.addDefaultFormats();
@@ -100,16 +93,14 @@ void init(int samplerate, int buffersize)
        sortPlugins(static_cast<pluginManager::SortMethod>(conf::conf.pluginSortMethod));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int scanDirs(const std::string& dirs, const std::function<void(float)>& cb)
 {
        u::log::print("[pluginManager::scanDir] requested directories: '%s'\n", dirs);
        u::log::print("[pluginManager::scanDir] current plugins: %d\n", knownPluginList_.getNumTypes());
 
-       knownPluginList_.clear();   // clear up previous plugins
+       knownPluginList_.clear(); // clear up previous plugins
 
        std::vector<std::string> dirVec = u::string::split(dirs, ";");
 
@@ -117,13 +108,15 @@ int scanDirs(const std::string& dirs, const std::function<void(float)>& cb)
        for (const std::string& dir : dirVec)
                searchPath.add(juce::File(dir));
 
-       for (int i = 0; i < formatManager_.getNumFormats(); i++) {
+       for (int i = 0; i < formatManager_.getNumFormats(); i++)
+       {
 
-               juce::PluginDirectoryScanner scanner(knownPluginList_, *formatManager_.getFormat(i), searchPath, 
-                       /*recursive=*/true, juce::File());
+               juce::PluginDirectoryScanner scanner(knownPluginList_, *formatManager_.getFormat(i), searchPath,
+                   /*recursive=*/true, juce::File());
 
                juce::String name;
-               while (scanner.scanNextFile(false, name)) {
+               while (scanner.scanNextFile(false, name))
+               {
                        u::log::print("[pluginManager::scanDir]   scanning '%s'\n", name.toRawUTF8());
                        cb(scanner.getProgress());
                }
@@ -133,10 +126,8 @@ int scanDirs(const std::string& dirs, const std::function<void(float)>& cb)
        return knownPluginList_.getNumTypes();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool saveList(const std::string& filepath)
 {
        bool out = knownPluginList_.createXml()->writeTo(juce::File(filepath));
@@ -145,10 +136,8 @@ bool saveList(const std::string& filepath)
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool loadList(const std::string& filepath)
 {
        std::unique_ptr<juce::XmlElement> elem(juce::XmlDocument::parse(juce::File(filepath)));
@@ -158,72 +147,65 @@ bool loadList(const std::string& filepath)
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unique_ptr<Plugin> makePlugin(const std::string& pid, ID id)
 {
        /* Plug-in ID generator is updated anyway, as we store Plugin objects also
        if they are in an invalid state. */
-       
+
        pluginId_.set(id);
 
        const std::unique_ptr<juce::PluginDescription> pd = knownPluginList_.getTypeForIdentifierString(pid);
-       if (pd == nullptr) {
+       if (pd == nullptr)
+       {
                u::log::print("[pluginManager::makePlugin] no plugin found with pid=%s!\n", pid);
                return makeInvalidPlugin_(pid, id);
        }
 
-       juce::String error;
+       juce::String                               error;
        std::unique_ptr<juce::AudioPluginInstance> pi = formatManager_.createPluginInstance(*pd, samplerate_, buffersize_, error);
-       if (pi == nullptr) {
+       if (pi == nullptr)
+       {
                u::log::print("[pluginManager::makePlugin] unable to create instance with pid=%s! Error: %s\n",
-                       pid, error.toStdString());
+                   pid, error.toStdString());
                return makeInvalidPlugin_(pid, id);
        }
 
        u::log::print("[pluginManager::makePlugin] plugin instance with pid=%s created\n", pid);
 
-       return std::make_unique<Plugin>(pluginId_.get(id), std::move(pi), samplerate_, buffersize_);
+       return std::make_unique<Plugin>(pluginId_.generate(id), std::move(pi), samplerate_, buffersize_);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unique_ptr<Plugin> makePlugin(int index)
 {
        juce::PluginDescription pd = knownPluginList_.getTypes()[index];
-       
+
        if (pd.uid == 0) // Invalid
                return {};
-       
+
        u::log::print("[pluginManager::makePlugin] plugin found, uid=%s, name=%s...\n",
-               pd.createIdentifierString().toRawUTF8(), pd.name.toRawUTF8());
-       
-       return makePlugin(pd.createIdentifierString().toStdString());
+           pd.createIdentifierString().toRawUTF8(), pd.name.toRawUTF8());
 
+       return makePlugin(pd.createIdentifierString().toStdString());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unique_ptr<Plugin> makePlugin(const Plugin& src)
 {
        std::unique_ptr<Plugin> p = makePlugin(src.getUniqueId());
-       
-       for (int i=0; i<src.getNumParameters(); i++)
-               p->setParameter(i, src.getParameter(i));        
+
+       for (int i = 0; i < src.getNumParameters(); i++)
+               p->setParameter(i, src.getParameter(i));
 
        return p;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 const patch::Plugin serializePlugin(const Plugin& p)
 {
        patch::Plugin pp;
@@ -238,21 +220,19 @@ const patch::Plugin serializePlugin(const Plugin& p)
        return pp;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unique_ptr<Plugin> deserializePlugin(const patch::Plugin& p, patch::Version version)
 {
        std::unique_ptr<Plugin> plugin = makePlugin(p.path, p.id);
        if (!plugin->valid)
                return plugin; // Return invalid version
-       
+
        /* Fill plug-in parameters. */
        plugin->setBypass(p.bypass);
-       
+
        if (version < patch::Version{0, 17, 0}) // TODO - to be removed in 0.18.0
-               for (unsigned j=0; j<p.params.size(); j++)
+               for (unsigned j = 0; j < p.params.size(); j++)
                        plugin->setParameter(j, p.params.at(j));
        else
                plugin->setState(PluginState(p.state));
@@ -260,8 +240,9 @@ std::unique_ptr<Plugin> deserializePlugin(const patch::Plugin& p, patch::Version
        /* Fill plug-in MidiIn parameters. Don't fill Plugin::midiInParam if 
        Patch::midiInParams are zero: it would wipe out the current default 0x0
        values. */
-       
-       if (!p.midiInParams.empty()) {
+
+       if (!p.midiInParams.empty())
+       {
                plugin->midiInParams.clear();
                std::size_t paramIndex = 0;
                for (uint32_t midiInParam : p.midiInParams)
@@ -271,32 +252,40 @@ std::unique_ptr<Plugin> deserializePlugin(const patch::Plugin& p, patch::Version
        return plugin;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+std::vector<Plugin*> hydratePlugins(std::vector<ID> pluginIds)
+{
+       std::vector<Plugin*> out;
+       for (ID id : pluginIds)
+       {
+               Plugin* plugin = model::find<Plugin>(id);
+               if (plugin != nullptr)
+                       out.push_back(plugin);
+       }
+       return out;
+}
+
+/* -------------------------------------------------------------------------- */
 
 int countAvailablePlugins()
 {
        return knownPluginList_.getNumTypes();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int countUnknownPlugins()
 {
        return unknownPluginList_.size();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 PluginInfo getAvailablePluginInfo(int i)
 {
        juce::PluginDescription pd = knownPluginList_.getTypes()[i];
-       PluginInfo pi;
+       PluginInfo              pi;
        pi.uid              = pd.fileOrIdentifier.toStdString();
        pi.name             = pd.descriptiveName.toStdString();
        pi.category         = pd.category.toStdString();
@@ -306,55 +295,47 @@ PluginInfo getAvailablePluginInfo(int i)
        return pi;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool hasMissingPlugins()
 {
        return missingPlugins_;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getUnknownPluginInfo(int i)
 {
        return unknownPluginList_.at(i);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool doesPluginExist(const std::string& pid)
 {
        return formatManager_.doesPluginStillExist(*knownPluginList_.getTypeForFile(pid));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sortPlugins(SortMethod method)
 {
-       switch (method) {
-               case SortMethod::NAME:
-                       knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortAlphabetically, true);
-                       break;
-               case SortMethod::CATEGORY:
-                       knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByCategory, true);
-                       break;
-               case SortMethod::MANUFACTURER:
-                       knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByManufacturer, true);
-                       break;
-               case SortMethod::FORMAT:
-                       knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByFormat, true);
-                       break;
+       switch (method)
+       {
+       case SortMethod::NAME:
+               knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortAlphabetically, true);
+               break;
+       case SortMethod::CATEGORY:
+               knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByCategory, true);
+               break;
+       case SortMethod::MANUFACTURER:
+               knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByManufacturer, true);
+               break;
+       case SortMethod::FORMAT:
+               knownPluginList_.sort(juce::KnownPluginList::SortMethod::sortByFormat, true);
+               break;
        }
 }
-}}} // giada::m::pluginManager::
-
+} // namespace giada::m::pluginManager
 
 #endif // #ifdef WITH_VST
index 5bb19ac6dafd405951196f8b3a54b4802983ccd8..d44a02d374c5f315d324904e92856178915783ca 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 #ifndef G_PLUGIN_MANAGER_H
 #define G_PLUGIN_MANAGER_H
 
-
 #include "deps/juce-config.h"
 #include "plugin.h"
 
-
-namespace giada {
-namespace m
-{
-namespace patch
+namespace giada::m::patch
 {
 struct Plugin;
 struct Version;
-}
-namespace pluginManager
+} // namespace giada::m::patch
+namespace giada::m::pluginManager
 {
 enum class SortMethod : int
 {
-       NAME = 0, CATEGORY,     MANUFACTURER, FORMAT
+       NAME = 0,
+       CATEGORY,
+       MANUFACTURER,
+       FORMAT
 };
 
 struct PluginInfo
@@ -57,7 +54,7 @@ struct PluginInfo
        std::string category;
        std::string manufacturerName;
        std::string format;
-       bool isInstrument;
+       bool        isInstrument;
 };
 
 void init(int samplerate, int buffersize);
@@ -85,7 +82,7 @@ Returns how many plug-ins are in a unknown/not-found state. */
 
 int countUnknownPlugins();
 
-std::unique_ptr<Plugin> makePlugin(const std::string& pid, ID id=0);
+std::unique_ptr<Plugin> makePlugin(const std::string& pid, ID id = 0);
 std::unique_ptr<Plugin> makePlugin(int index);
 std::unique_ptr<Plugin> makePlugin(const Plugin& other);
 
@@ -94,6 +91,7 @@ Transforms patch data into a Plugin object and vice versa. */
 
 const patch::Plugin     serializePlugin(const Plugin& p);
 std::unique_ptr<Plugin> deserializePlugin(const patch::Plugin& p, patch::Version version);
+std::vector<Plugin*>    hydratePlugins(std::vector<ID> pluginIds);
 
 /* getAvailablePluginInfo
 Returns the available plugin information (name, type, ...) given a plug-in
@@ -109,8 +107,7 @@ bool hasMissingPlugins();
 
 void sortPlugins(SortMethod sortMethod);
 
-}}} // giada::m::pluginManager::
-
+} // namespace giada::m::pluginManager
 
 #endif
 
index 97a257ed52a88ee0799dc9040d0c3072e58502e9..0cad68817ac5bbf4454796024ae12b81e7451081 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 #ifdef WITH_VST
 
-#include <cassert>
 #include "pluginState.h"
+#include "core/const.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 PluginState::PluginState(juce::MemoryBlock&& data)
 : m_data(std::move(data))
@@ -40,35 +38,31 @@ PluginState::PluginState(juce::MemoryBlock&& data)
 
 /* -------------------------------------------------------------------------- */
 
-
 PluginState::PluginState(const std::string& base64)
 {
        bool res = m_data.fromBase64Encoding(base64);
-       assert(res);
+       if (!res)
+               G_DEBUG("Error while loading plug-in state!");
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string PluginState::asBase64() const
 {
        return m_data.toBase64Encoding().toStdString();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-const void* PluginState::getData() const 
+const void* PluginState::getData() const
 {
        return m_data.getData();
 }
 
-
 size_t PluginState::getSize() const
 {
        return m_data.getSize();
 }
-}}
+} // namespace giada::m
 
 #endif // #ifdef WITH_VST
index b30ddbadd7f7731a87dd75c0200b905ea18b2508..ecb4c7c232eeb7779c81d69faecca972461215d7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 #ifndef G_PLUGIN_STATE_H
 #define G_PLUGIN_STATE_H
 
-
-#include <string>
 #include "deps/juce-config.h"
+#include <string>
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class PluginState
 {
 public:
+       PluginState() = default; // Invalid state
+       PluginState(juce::MemoryBlock&& data);
+       PluginState(const std::string& base64);
 
-    PluginState(juce::MemoryBlock&& data);
-    PluginState(const std::string& base64);
-
-    std::string asBase64() const;
-    const void* getData() const;
-    size_t getSize() const;
+       std::string asBase64() const;
+       const void* getData() const;
+       size_t      getSize() const;
 
 private:
-
-    juce::MemoryBlock m_data;
+       juce::MemoryBlock m_data;
 };
-}}
+} // namespace giada::m
 
 #endif
 
index 7be2fa1aa4d07562f086399d682467d2a6451584..aa6cdd795fd07d955e95504b68a9d440783edbdc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/clock.h"
 #include "quantizer.h"
+#include "core/clock.h"
+#include <cassert>
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 void Quantizer::trigger(int id)
 {
-       assert(id >= 0);
-       assert(id < (int) m_callbacks.size());
+       assert(m_callbacks.count(id) > 0); // Make sure id exists
 
        m_performId = id;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Quantizer::schedule(int id, std::function<void(Frame delta)> f)
 {
-       assert(id >= 0);
-       assert(id < (int) m_callbacks.size());
-
        m_callbacks[id] = f;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Quantizer::advance(Range<Frame> block, Frame quantizerStep)
 {
        /* Nothing to do if there's no action to perform. */
@@ -64,34 +53,31 @@ void Quantizer::advance(Range<Frame> block, Frame quantizerStep)
        if (m_performId == -1)
                return;
 
-       assert(m_callbacks[m_performId] != nullptr);
+       assert(m_callbacks.count(m_performId) > 0);
 
-       for (Frame global = block.getBegin(), local = 0; global < block.getEnd(); global++, local++) {
+       for (Frame global = block.getBegin(), local = 0; global < block.getEnd(); global++, local++)
+       {
 
-               if (global % quantizerStep != 0) // Skip if it's not on a quantization unit. 
+               if (global % quantizerStep != 0) // Skip if it's not on a quantization unit.
                        continue;
 
-               m_callbacks[m_performId](local);
+               m_callbacks.at(m_performId)(local);
                m_performId = -1;
                return;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void Quantizer::clear()
 {
        m_performId = -1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool Quantizer::isTriggered() const
+bool Quantizer::hasBeenTriggered() const
 {
        return m_performId != -1;
 }
-}} // giada::m::
\ No newline at end of file
+} // namespace giada::m
\ No newline at end of file
index e9973b735f9a492d6ee9bfeeefed69737b9466fa..88760b81859f455e959988fed64a19cefd4237d7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_QUANTIZER_H
 #define G_QUANTIZER_H
 
-
-#include <array>
-#include <functional>
 #include "core/const.h"
 #include "core/range.h"
 #include "core/types.h"
+#include <functional>
+#include <map>
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 class Quantizer
 {
 public:
-
        /* schedule
        Schedules a function in slot 'id' to be called at the right time. The 
        function has a 'delta' parameter for the buffer offset. */
@@ -67,17 +62,15 @@ public:
 
        void clear();
 
-       /* isTriggered
+       /* hasBeenTriggered
        True if a quantizer function has been triggered(). */
-       
-       bool isTriggered() const;
 
-private:
+       bool hasBeenTriggered() const;
 
-       std::array<std::function<void(Frame)>, G_MAX_QUANTIZER_SIZE> m_callbacks;
-       int m_performId = -1;
+  private:
+       std::map<int, std::function<void(Frame)>> m_callbacks;
+       int                                       m_performId = -1;
 };
-}} // giada::m::
-
+} // namespace giada::m
 
 #endif
index 6edf1c55bc672fadd380657b924d04a24e7de3b5..0e95d6faab477883671c1c34f73cb9f17d40d626 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_QUEUE_H
 #define G_QUEUE_H
 
-
 #include <array>
 #include <atomic>
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 /* Queue
 Single producer, single consumer lock-free queue. */
 
-template<typename T, std::size_t size>
+template <typename T, std::size_t size>
 class Queue
 {
 public:
-
-    Queue() : m_head(0), m_tail(0)
-    {
-    }
-
-
-    Queue(const Queue&) = delete;
-
-
-    bool pop(T& item)
-    {
-        std::size_t curr = m_head.load();
-        if (curr == m_tail.load())  // Queue empty, nothing to do
-            return false;
-
-        item = m_data[curr];
-        m_head.store(increment(curr));
-        return true;
-    }
-
-
-    bool push(const T& item)
-    {
-        std::size_t curr = m_tail.load();
-        std::size_t next = increment(curr);
-
-        if (next == m_head.load()) // Queue full, nothing to do
-            return false;
-
-        m_data[curr] = item;
-        m_tail.store(next);
-        return true;
-    }
-
-private:
-
-    std::size_t increment(std::size_t i) const
-    {
-        return (i + 1) % size;
-    }
-
-
-    std::array<T, size> m_data;
-    std::atomic<std::size_t> m_head;
-    std::atomic<std::size_t> m_tail;
+       Queue()
+       : m_head(0)
+       , m_tail(0)
+       {
+       }
+
+       Queue(const Queue&) = delete;
+
+       bool pop(T& item)
+       {
+               std::size_t curr = m_head.load();
+               if (curr == m_tail.load()) // Queue empty, nothing to do
+                       return false;
+
+               item = m_data[curr];
+               m_head.store(increment(curr));
+               return true;
+       }
+
+       bool push(const T& item)
+       {
+               std::size_t curr = m_tail.load();
+               std::size_t next = increment(curr);
+
+               if (next == m_head.load()) // Queue full, nothing to do
+                       return false;
+
+               m_data[curr] = item;
+               m_tail.store(next);
+               return true;
+       }
+
+  private:
+       std::size_t increment(std::size_t i) const
+       {
+               return (i + 1) % size;
+       }
+
+       std::array<T, size>      m_data;
+       std::atomic<std::size_t> m_head;
+       std::atomic<std::size_t> m_tail;
 };
-}} // giada::m::
-
+} // namespace m
+} // namespace giada
 
 #endif
index 96e91066f4f560c253bca4199b7d547cc8f32f43..1a1b9177818a024009c9b12f45feda62575b09a1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_RANGE_H
 #define G_RANGE_H
 
-
 #include <cassert>
 
-
 namespace giada
 {
-template<typename T>
+template <typename T>
 class Range
 {
 public:
+       Range()
+       : m_a(0)
+       , m_b(0)
+       {
+       }
+       Range(T a, T b)
+       : m_a(a)
+       , m_b(b)
+       {
+               assert(a < b);
+       }
 
-       Range() : m_a(0), m_b(0) {}
-       Range(T a, T b) : m_a(a), m_b(b) { assert(a < b); }
-
-       T getBegin() const  { return m_a; }
-       T getEnd() const    { return m_b; }
+       T getBegin() const { return m_a; }
+       T getEnd() const { return m_b; }
        T getLength() const { return m_b - m_a; }
 
-private:
+       bool contains(T t) const
+       {
+               return t >= m_a && t < m_b;
+       }
 
+  private:
        T m_a;
        T m_b;
 };
-} // giada::
-
+} // namespace giada
 
 #endif
diff --git a/src/core/rcuList.h b/src/core/rcuList.h
deleted file mode 100644 (file)
index 0050489..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef G_RCU_LIST_H
-#define G_RCU_LIST_H
-
-
-#include <array>
-#include <cassert>
-#include <thread>
-#include <atomic>
-#include <iterator>
-
-
-namespace giada {
-namespace m
-{
-/* RCUList
-Single producer, multiple consumer (i.e. one writer, many readers) RCU-based 
-list. */
-template<typename T>
-class RCUList
-{
-public:
-
-       /* Lock
-       Scoped lock structure. Not copyable, not moveable, not copy-constructible. 
-       Same as std::scoped_lock: 
-       https://en.cppreference.com/w/cpp/thread/scoped_lock .*/
-
-       struct Lock
-       {
-               Lock(RCUList<T>& r) : rcu(r) { rcu.lock(); }
-               Lock(const Lock&) = delete;
-               Lock& operator=(const Lock&) = delete;
-               ~Lock() { rcu.unlock(); }
-
-               RCUList<T>& rcu;
-       };
-
-       /* Node
-       Element of the linked list. */
-       
-       struct Node
-       {
-               std::unique_ptr<T> data;
-               std::atomic<Node*> next;
-
-               Node(std::unique_ptr<T> data, Node* next=nullptr)
-               : data(std::move(data)), 
-                 next(next) 
-               {}
-       };
-
-       /* Iterator (const)
-       This is based on simple, non-atomic pointers: you must always lock the RCU
-       list before looping over it! */
-
-       class Iterator : public std::iterator<std::forward_iterator_tag, Node*>
-       {
-       public:
-
-               Iterator(Node* n) : m_curr(n) {}
-
-               bool operator!= (const Iterator& o) const
-               {
-                       return m_curr != o.m_curr;
-               }
-
-               bool operator== (const Iterator& o) const
-               {
-                       return m_curr == o.m_curr;
-               }
-
-               const T* operator* () const
-               {
-                       return m_curr->data.get();
-               }
-
-               // TODO - this non-const will go away with the non-virtual Channel
-               // refactoring. 
-               T* operator* ()
-               {
-                       return m_curr->data.get();
-               }
-
-               const Iterator& operator++ ()  // Prefix operator (++x)
-               {
-                       if (m_curr != nullptr)
-                               m_curr = m_curr->next;
-                       return *this;
-               }
-       
-       private:
-       
-               const Node* m_curr;
-       };
-
-       /* RCUList
-       Singly linked list protected by a Read-Copy-Update (RCU) mechanism. */
-
-       RCUList()
-               : changed  (false),
-                 m_grace  (0), 
-                 m_size   (0), 
-                 m_writing(false),
-                 m_head   (nullptr),
-                 m_tail   (nullptr)
-       {
-               m_readers[0].store(0);
-               m_readers[1].store(0);
-       }
-
-       RCUList(std::unique_ptr<T> data) : RCUList()
-       {
-               push(std::move(data));
-       }
-
-       RCUList(const RCUList&) = delete;
-       RCUList(RCUList&&)      = delete;
-
-       ~RCUList()
-       {
-               clear();
-       }
-
-       Iterator begin()
-       { 
-               assert(m_readers[t_grace].load() > 0 && "Forgot lock before reading");
-               return Iterator(m_head.load());
-       }
-
-       Iterator end()
-       { 
-               assert(m_readers[t_grace].load() > 0 && "Forgot lock before reading");
-               return Iterator(nullptr);
-       }
-
-       /* unlock
-       Increases current readers count. Always call lock()/unlock() when reading
-       data from the list. Or use the scoped version Lock above. */
-
-       void lock()
-       {
-               t_grace = m_grace.load();
-               m_readers[t_grace]++;
-       }
-
-       /* unlock
-       Releases current readers count. */
-
-       void unlock()
-       {
-               m_readers[t_grace]--;
-               assert(m_readers[t_grace] >= 0 && "Negative reader");
-       }
-
-       /* get
-       Returns a reference to the data held by node 'i'. */
-
-       T* get(std::size_t i=0) const
-       {
-               assert(i < size() && "Index overflow");
-               assert(m_readers[t_grace].load() > 0 && "Forgot lock before reading");
-               return getNode(i)->data.get();
-       }
-
-       /* Subscript operator []
-       Same as above for the [] syntax. */
-
-       T* operator[] (std::size_t i) const
-       {
-       return get(i);
-    }
-
-       /* back
-       Return data held by the last node. */
-
-       T* back() const
-       {
-               assert(m_readers[t_grace].load() > 0 && "Forgot lock before reading");
-               return m_tail.load()->data.get();
-       }
-
-       /* clone
-       Returns a new copy of the data held by node 'i'. */
-
-       std::unique_ptr<T> clone(std::size_t i=0) const
-    {
-               /* Make sure no one is writing (swapping, popping, pushing). */
-               assert(m_writing.load() == false);
-               return std::make_unique<T>(*getNode(i)->data.get());
-    }
-
-       /* swap
-       Exchanges data contained in node 'i' with new data 'data'. New data must
-       always come from a call to clone(). There is a natural protection against 
-       multiple calls to swap() made by the same thread: the caller is blocked by 
-       the spinlock below: no progress is made until m_readers[oldgrace] > 0. */
-
-       void swap(std::unique_ptr<T> data, std::size_t i=0)
-       {
-               /* Never start two overlapping writing sessions. */
-
-               if (m_writing.load() == true)
-                       return;
-               
-               /* Begin of writing session. */
-
-               m_writing.store(true);
-
-               /* Flip the current grace bit. Now we have entered a new grace period
-               with a different number from the previous one. */
-
-               std::int8_t oldgrace = m_grace.fetch_xor(1);
-
-               /* Prepare useful node pointers: current, next and previous. Fetching
-               from the current list with getNode() is safe here: we are just reading. */
-
-               Node* curr = getNode(i);
-               Node* prev = curr == m_head.load() ? nullptr : getNode(i - 1);
-               Node* next = curr == m_tail.load() ? nullptr : getNode(i + 1);
-               
-               /* Prepare a new node holding the new data in input. */
-
-               Node* n = new Node(std::move(data), next);
-       
-               /* Make the previous node point to the new one just created. New
-               readers will read the new one from now on. The only write operation 
-               performed here is the atomic store. */
-
-               if (prev != nullptr)
-                       prev->next.store(n);
-               else
-                       m_head.store(n);
-
-               if (next == nullptr)
-                       m_tail.store(n);
-
-               /* Wait until no readers from the previous grace period are reading the 
-               list. Avoid brutal spinlock with a tiny sleep. */
-
-               while (m_readers[oldgrace] > 0)
-                       std::this_thread::sleep_for(std::chrono::milliseconds(50));
-
-               /* Delete old node. Node destructor makes sure data is deleted. */
-
-               delete curr;
-
-               /* End of writing session. */
-
-               m_writing.store(false);
-               changed.store(true);
-       }
-
-       /* push
-       Adds a new element to the list containing 'data'. */
-
-       void push(std::unique_ptr<T> data)
-       {
-               /* Never start two overlapping writing sessions. */
-
-               if (m_writing.load() == true)
-                       return;
-
-               /* Begin of writing session. */
-
-               m_writing.store(true);  
-               
-               /* Create new node. */
-
-               Node* n = new Node(std::move(data));
-               
-               /* Update the current tail->next pointer to this node, if a tail exists.
-               I.e., grab the current last node and append it the new one. */
-
-               if (m_tail.load() != nullptr)
-                       m_tail.load()->next.store(n);
-               
-               /* Update tail pointer to point to the new node. */
-
-               m_tail.store(n);
-
-               /* Head is null when the list is empty. If so, set head to this new
-               node too. A list with only one node has both head and tail pointing
-               to the same node. */
-
-               if (m_head.load() == nullptr)
-                       m_head.store(n);
-
-               /* Upgrade static size. Last thing to do, so that other threads won't
-               read a false size. */
-
-               m_size++;
-
-               /* End of writing session. Data has changed, set the flag. */
-
-               m_writing.store(false);
-               changed.store(true);
-       }
-
-       /* pop
-       Removes the i-th element. There is a natural protection against multiple
-       calls to pop() made by the same thread: the caller is blocked by the
-       spinlock below: no progress is made while m_readers[oldgrace] > 0. */
-
-       void pop(std::size_t i)
-       {
-               /* Never start two overlapping writing sessions. */
-
-               if (m_writing.load() == true)
-                       return;
-
-               /* Begin of writing session. */
-
-               m_writing.store(true);
-
-               /* Flip the current grace bit. Now we have entered a new grace period
-               with a different number from the previous one. */
-
-               std::int8_t oldgrace = m_grace.fetch_xor(1);
-               
-               /* Prepare useful node pointers: current, next and previous. Fetching
-               from the current list with getNode() is safe here: we are just reading. */
-
-               Node* curr = getNode(i);
-               Node* prev = curr == m_head.load() ? nullptr : getNode(i - 1);
-               Node* next = curr == m_tail.load() ? nullptr : getNode(i + 1);
-               
-               /* Disconnect the previous node from the current one to be deleted:
-               prev->curr->next becomes prev->next, with (curr) pending in the void 
-               for the remaining readers. Special care is needed if we are removing an 
-               edge node. */
-
-               if (prev != nullptr)
-                       prev->next.store(next);
-               else 
-                       m_head.store(next);
-
-               if (next == nullptr)
-                       m_tail.store(prev);
-
-               /* Size can be updated at this point. */
-
-               m_size--;
-               
-               /* Wait until no readers from the previous grace period are reading the 
-               list. Avoid brutal spinlock with a tiny sleep. */
-
-               while (m_readers[oldgrace] > 0)
-                       std::this_thread::sleep_for(std::chrono::milliseconds(50));
-
-               /* Delete old node. Node destructor makes sure data is deleted. */
-
-               delete curr;
-               
-               /* End of writing session. Data has changed, set the flag. */
-
-               m_writing.store(false);
-               changed.store(true);
-       }
-
-       /* clear
-       Removes all nodes. */
-
-       void clear()
-       {
-               /* Never start two overlapping writing sessions. */
-
-               if (m_writing.load() == true)
-                       return;
-
-               /* Begin of writing session. */
-
-               m_writing.store(true);
-
-               /* Flip the current grace bit. Now we have entered a new grace period
-               with a different number from the previous one. */
-
-               std::int8_t oldgrace = m_grace.fetch_xor(1);
-       
-               /* Store the first node locally. We will need it later on. */
-
-               Node* current = m_head.load();
-
-               /* Block any other reader by setting the size to 0 in advance and
-               cleaning up head/tail pointers. */
-
-               m_size.store(0);
-               m_head.store(nullptr);
-               m_tail.store(nullptr);
-
-               while (current != nullptr) {
-
-                       /* Wait until no readers from the previous grace period are reading the 
-                       list. Avoid brutal spinlock with a tiny sleep. */
-
-                       while (m_readers[oldgrace] > 0)
-                               std::this_thread::sleep_for(std::chrono::milliseconds(50));
-
-                       /* Delete old node. Node destructor makes sure data is deleted. */
-
-               Node* next = current->next;
-               delete current;
-               current = next;
-               }
-
-               /* End of writing session. Data has changed, set the flag. */
-
-               m_writing.store(false);
-               changed.store(true);
-       }
-
-       /* size
-       Returns the number of nodes in the list. */
-
-       std::size_t size() const
-       {
-               return m_size.load();
-       }
-
-       /* changed
-       Tells whether the list has been altered with a swap, a push or a pop. */
-
-       std::atomic<bool> changed;
-       
-       /* value_type
-       A variable that holds the type of data contained in the list. Used for
-       metaprogramming stuff. */
-
-       using value_type = T;
-
-private:
-
-       Node* getNode(std::size_t i) const
-       {
-               std::size_t p    = 0;
-               Node*  curr = m_head.load();
-               
-               while (curr != nullptr && p < i) {
-                       p++;
-                       curr = curr->next.load();
-               }
-               assert(curr != nullptr);
-               return curr;
-       }
-
-       std::array<std::atomic<int>, 2> m_readers;
-       std::atomic<std::int8_t>        m_grace;
-       std::atomic<std::size_t>             m_size;
-       std::atomic<bool>               m_writing;
-
-       /* m_head
-       Pointer to the first node. Used when reading and writing: always update
-       this one first, as it is read by reader threads. */
-
-       std::atomic<Node*> m_head;
-
-       /* m_tail
-       Pointer to the last node. Used only when reading: unlike m_head, updating it
-       the right time is not that critical. */
-
-       std::atomic<Node*> m_tail;
-
-       /* t_grace
-       Current grace flag. Each thread has its own copy of it (thread_local). */
-
-       thread_local static int t_grace;
-};
-
-
-template<typename T>
-thread_local int RCUList<T>::t_grace = 0;
-}} // giada::m::
-
-
-#endif
index f03c50f1ff985e0fc7db75306564d8e209ce2ca1..f14e46d4f8bab7d1bedb4682dd6eebedf49d566b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "gui/dispatcher.h"
-#include "core/model/model.h"
-#include "core/types.h"
+#include "core/recManager.h"
 #include "core/clock.h"
-#include "core/kernelAudio.h"
 #include "core/conf.h"
+#include "core/kernelAudio.h"
+#include "core/midiDispatcher.h"
 #include "core/mixer.h"
-#include "core/sequencer.h"
 #include "core/mixerHandler.h"
-#include "core/midiDispatcher.h"
+#include "core/model/model.h"
 #include "core/recorder.h"
 #include "core/recorderHandler.h"
-#include "core/recManager.h"
-
+#include "core/sequencer.h"
+#include "core/types.h"
+#include "gui/dispatcher.h"
 
-namespace giada {
-namespace m {
-namespace recManager
+namespace giada::m::recManager
 {
 namespace
 {
-void setRecordingAction_(bool v)
+bool isKernelReady_()
 {
-       model::onSwap(model::recorder, [&](model::Recorder& r)
-       {
-               r.isRecordingAction = v;
-       });
+       return kernelAudio::isReady();
 }
 
+bool canRec_()
+{
+       return isKernelReady_() && kernelAudio::isInputEnabled();
+}
 
-void setRecordingInput_(bool v)
+/* -------------------------------------------------------------------------- */
+
+void setRecordingAction_(bool v)
 {
-       model::onSwap(model::recorder, [&](model::Recorder& r)
-       {
-               r.isRecordingInput = v;
-       });
+       model::get().recorder.isRecordingAction = v;
+       model::swap(model::SwapType::NONE);
 }
 
+void setRecordingInput_(bool v)
+{
+       model::get().recorder.isRecordingInput = v;
+       model::swap(model::SwapType::NONE);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 bool startActionRec_()
 {
-       if (!kernelAudio::isReady())
-               return false;
        clock::setStatus(ClockStatus::RUNNING);
        sequencer::start();
-       m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
+       conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool startInputRec_()
+void startInputRec_()
 {
-       if (!kernelAudio::isReady() || !mh::hasInputRecordableChannels())
-               return false;
-       mixer::startInputRec();
+       /* Start recording from the current frame, not the beginning. */
+       mixer::startInputRec(clock::getCurrentFrame());
        sequencer::start();
-       m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
-       return true;
+       conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 bool isRecording()
-{ 
+{
        return isRecordingAction() || isRecordingInput();
 }
 
-
 bool isRecordingAction()
-{ 
-       model::RecorderLock lock(model::recorder); 
-       return model::recorder.get()->isRecordingAction;
+{
+       return model::get().recorder.isRecordingAction;
 }
 
-
 bool isRecordingInput()
-{ 
-       model::RecorderLock lock(model::recorder); 
-       return model::recorder.get()->isRecordingInput; 
+{
+       return model::get().recorder.isRecordingInput;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void startActionRec(RecTriggerMode mode)
 {
-       if (mode == RecTriggerMode::NORMAL) {
-               if (startActionRec_())
-                       setRecordingAction_(true);
+       if (!isKernelReady_())
+               return;
+
+       if (mode == RecTriggerMode::NORMAL)
+       {
+               startActionRec_();
+               setRecordingAction_(true);
        }
-       else {   // RecTriggerMode::SIGNAL
+       else
+       { // RecTriggerMode::SIGNAL
                clock::setStatus(ClockStatus::WAITING);
                clock::rewind();
-               m::midiDispatcher::setSignalCallback(startActionRec_);
+               midiDispatcher::setSignalCallback(startActionRec_);
                v::dispatcher::setSignalCallback(startActionRec_);
                setRecordingAction_(true);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void stopActionRec()
 {
        setRecordingAction_(false);
@@ -147,7 +137,8 @@ void stopActionRec()
        /* If you stop the Action Recorder in SIGNAL mode before any actual 
        recording: just clean up everything and return. */
 
-       if (clock::getStatus() == ClockStatus::WAITING) {
+       if (clock::getStatus() == ClockStatus::WAITING)
+       {
                clock::setStatus(ClockStatus::STOPPED);
                midiDispatcher::setSignalCallback(nullptr);
                v::dispatcher::setSignalCallback(nullptr);
@@ -160,81 +151,114 @@ void stopActionRec()
        actions. Start reading right away, without checking whether 
        conf::treatRecsAsLoops is enabled or not. Same thing for MIDI channels.  */
 
-       for (ID id : channels) {
-               model::onGet(model::channels, id, [](Channel& c)
-               {
-                       c.state->readActions.store(true);
-                       if (c.getType() == ChannelType::MIDI)
-                               c.state->playStatus.store(ChannelStatus::PLAY);
-               });
+       for (ID id : channels)
+       {
+               channel::Data& ch = model::get().getChannel(id);
+               ch.state->readActions.store(true);
+               if (ch.type == ChannelType::MIDI)
+                       ch.state->playStatus.store(ChannelStatus::PLAY);
        }
+       model::swap(model::SwapType::HARD);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleActionRec(RecTriggerMode m)
 {
        isRecordingAction() ? stopActionRec() : startActionRec(m);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-bool startInputRec(RecTriggerMode mode)
+bool startInputRec(RecTriggerMode triggerMode, InputRecMode inputMode)
 {
-       if (mode == RecTriggerMode::NORMAL) {
-G_DEBUG("Start input rec, NORMAL mode");
-               if (!startInputRec_())
-                       return false;
+       if (!canRec_() || !mh::hasInputRecordableChannels())
+               return false;
+
+       if (triggerMode == RecTriggerMode::SIGNAL || inputMode == InputRecMode::FREE)
+               clock::rewind();
+
+       if (inputMode == InputRecMode::FREE)
+               mixer::setEndOfRecCallback([inputMode] { stopInputRec(inputMode); });
+
+       if (triggerMode == RecTriggerMode::NORMAL)
+       {
+               startInputRec_();
                setRecordingInput_(true);
-               return true;
+               G_DEBUG("Start input rec, NORMAL mode");
        }
-       else {
-G_DEBUG("Start input rec, SIGNAL mode");
-               if (!mh::hasInputRecordableChannels())
-                       return false;
+       else
+       {
                clock::setStatus(ClockStatus::WAITING);
-               clock::rewind();
-               mixer::setSignalCallback(startInputRec_);
-               setRecordingInput_(true);
-               return true;
+               mixer::setSignalCallback([] {
+                       startInputRec_();
+                       setRecordingInput_(true);
+               });
+               G_DEBUG("Start input rec, SIGNAL mode");
        }
-}
 
+       return true;
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void stopInputRec()
+void stopInputRec(InputRecMode recMode)
 {
        setRecordingInput_(false);
 
-       mixer::stopInputRec();
-       
+       Frame recordedFrames = mixer::stopInputRec();
+
+       /* When recording in RIGID mode, the amount of recorded frames is always 
+       equal to the current loop length. */
+
+       if (recMode == InputRecMode::RIGID)
+               recordedFrames = clock::getFramesInLoop();
+
+       G_DEBUG("Stop input rec, recordedFrames=" << recordedFrames);
+
        /* If you stop the Input Recorder in SIGNAL mode before any actual 
        recording: just clean up everything and return. */
 
-       if (clock::getStatus() == ClockStatus::WAITING) {
+       if (clock::getStatus() == ClockStatus::WAITING)
+       {
                clock::setStatus(ClockStatus::STOPPED);
                mixer::setSignalCallback(nullptr);
+               return;
        }
-       else
-               mh::finalizeInputRec();
-}
 
+       /* Finalize recordings. InputRecMode::FREE requires some adjustments. */
 
-/* -------------------------------------------------------------------------- */
+       mh::finalizeInputRec(recordedFrames);
+
+       if (recMode == InputRecMode::FREE)
+       {
+               clock::rewind();
+               clock::setBpm(clock::calcBpmFromRec(recordedFrames));
+               mixer::setEndOfRecCallback(nullptr);
+               refreshInputRecMode(); // Back to RIGID mode if necessary
+       }
+}
 
+/* -------------------------------------------------------------------------- */
 
-bool toggleInputRec(RecTriggerMode m)
+bool toggleInputRec(RecTriggerMode m, InputRecMode i)
 {
-       if (isRecordingInput()) {
-               stopInputRec();
+       if (isRecordingInput())
+       {
+               stopInputRec(i);
                return true;
        }
-       return startInputRec(m);
+       return startInputRec(m, i);
+}
+
+/* -------------------------------------------------------------------------- */
+
+bool canEnableRecOnSignal() { return !clock::isRunning(); }
+bool canEnableFreeInputRec() { return !mh::hasAudioData(); }
+
+void refreshInputRecMode()
+{
+       if (!canEnableFreeInputRec())
+               conf::conf.inputRecMode = InputRecMode::RIGID;
 }
-}}} // giada::m::recManager
+} // namespace giada::m::recManager
\ No newline at end of file
index ddda5c5b40e39d8b040175c97ab804f157a7395e..1dd497109c5f2a6437886577b2819e42b5fff464 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_REC_MANAGER_H
 #define G_REC_MANAGER_H
 
-
 #include "core/types.h"
 
-
-namespace giada {
-namespace m {
-namespace recManager
+namespace giada::m::recManager
 {
 bool isRecording();
 bool isRecordingAction();
 bool isRecordingInput();
 
-void startActionRec(RecTriggerMode m);
+void startActionRec(RecTriggerMode);
 void stopActionRec();
-void toggleActionRec(RecTriggerMode m);
+void toggleActionRec(RecTriggerMode);
+
+bool startInputRec(RecTriggerMode, InputRecMode);
+void stopInputRec(InputRecMode);
+bool toggleInputRec(RecTriggerMode, InputRecMode);
+
+/* canEnableRecOnSignal
+True if rec-on-signal can be enabled: can't set it while sequencer is running,
+in order to prevent mistakes while live recording. */
+
+bool canEnableRecOnSignal();
+
+/* canEnableFreeInputRec
+True if free loop-length can be enabled: Can't set it if there's already a 
+filled Sample Channel in the current project. */
+
+bool canEnableFreeInputRec();
+
+/* refreshInputRecMode
+Makes sure the input rec mode stays the right one when a new Sample Channel is
+filled with data. See canEnableFreeInputRec() rationale. */
 
-bool startInputRec(RecTriggerMode m);
-void stopInputRec();
-bool toggleInputRec(RecTriggerMode m);
-}}} // giada::m::recManager
+void refreshInputRecMode();
+} // namespace giada::m::recManager
 
 #endif
index ed55dae6fcbb48b54125ace4d973801ea99bdbf0..bfee13a8b36238fc5fe46ff7e0c2ab3d52aaf36b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <memory>
-#include <algorithm>
-#include <cassert>
-#include "utils/log.h"
-#include "core/model/model.h"
+#include "core/recorder.h"
 #include "core/action.h"
 #include "core/idManager.h"
-#include "core/recorder.h"
-
+#include "core/model/model.h"
+#include "utils/log.h"
+#include <algorithm>
+#include <cassert>
+#include <memory>
 
-namespace giada {
-namespace m {
-namespace recorder
+namespace giada::m::recorder
 {
 namespace
 {
 IdManager actionId_;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Action* findAction_(ActionMap& src, ID id)
 {
        for (auto& [frame, actions] : src)
@@ -54,9 +48,29 @@ Action* findAction_(ActionMap& src, ID id)
                        if (a.id == id)
                                return &a;
        assert(false);
-       return nullptr; 
+       return nullptr;
 }
 
+/* -------------------------------------------------------------------------- */
+
+/* updateMapPointers_
+Updates all prev/next actions pointers into the action map. This is required
+after an action has been recorded, since pushing back new actions in a Action 
+vector makes it reallocating the existing ones. */
+
+void updateMapPointers_(ActionMap& src)
+{
+       for (auto& kv : src)
+       {
+               for (Action& action : kv.second)
+               {
+                       if (action.nextId != 0)
+                               action.next = findAction_(src, action.nextId);
+                       if (action.prevId != 0)
+                               action.prev = findAction_(src, action.prevId);
+               }
+       }
+}
 
 /* -------------------------------------------------------------------------- */
 
@@ -69,214 +83,173 @@ void optimize_(ActionMap& map)
                it->second.size() == 0 ? it = map.erase(it) : ++it;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void removeIf_(std::function<bool(const Action&)> f)
 {
-       model::onSwap(model::actions, [&](model::Actions& a)
-       {
-               for (auto& [frame, actions] : a.map)
-                       actions.erase(std::remove_if(actions.begin(), actions.end(), f), actions.end());
-               optimize_(a.map);
-               updateMapPointers(a.map);
-       });
+       model::DataLock lock;
+
+       ActionMap& map = model::getAll<model::Actions>();
+       for (auto& [frame, actions] : map)
+               actions.erase(std::remove_if(actions.begin(), actions.end(), f), actions.end());
+       optimize_(map);
+       updateMapPointers_(map);
 }
 
 /* -------------------------------------------------------------------------- */
 
-
 bool exists_(ID channelId, Frame frame, const MidiEvent& event, const ActionMap& target)
 {
        for (const auto& [_, actions] : target)
-               for (const Action& a : actions) 
+               for (const Action& a : actions)
                        if (a.channelId == channelId && a.frame == frame && a.event.getRaw() == event.getRaw())
                                return true;
-       return false;   
+       return false;
 }
 
-
 bool exists_(ID channelId, Frame frame, const MidiEvent& event)
 {
-       model::ActionsLock lock(model::actions);
-       return exists_(channelId, frame, event, model::actions.get()->map);
+       return exists_(channelId, frame, event, model::getAll<model::Actions>());
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
        actionId_ = IdManager();
        clearAll();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearAll()
 {
-       model::onSwap(model::actions, [&](model::Actions& a)
-       {
-               a.map.clear();
-       });
+       model::DataLock lock;
+       model::getAll<model::Actions>().clear();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearChannel(ID channelId)
 {
        removeIf_([=](const Action& a) { return a.channelId == channelId; });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearActions(ID channelId, int type)
 {
-       removeIf_([=](const Action& a)
-       { 
+       removeIf_([=](const Action& a) {
                return a.channelId == channelId && a.event.getStatus() == type;
        });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void deleteAction(ID id)
 {
        removeIf_([=](const Action& a) { return a.id == id; });
 }
 
-
 void deleteAction(ID currId, ID nextId)
 {
        removeIf_([=](const Action& a) { return a.id == currId || a.id == nextId; });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateKeyFrames(std::function<Frame(Frame old)> f)
 {
-       std::unique_ptr<model::Actions> ma = model::actions.clone();
-       
-       /* Remove all existing actions: let's start from scratch. 
-       TODO - so why cloning it?! */
+       recorder::ActionMap temp;
 
-       ma->map.clear();
-
-       /* Copy all existing actions in local data by cloning them, with just a
+       /* Copy all existing actions in local map by cloning them, with just a
        difference: they have a new frame value. */
 
+       for (const auto& [oldFrame, actions] : model::getAll<model::Actions>())
        {
-               model::ActionsLock lock(model::actions);
-
-               for (const auto& [oldFrame, actions] : model::actions.get()->map) {
-                       Frame newFrame = f(oldFrame);
-                       for (const Action& a : actions) {
-                               Action copy = a;
-                               copy.frame = newFrame;
-                               ma->map[newFrame].push_back(copy);
-                       }
-G_DEBUG(oldFrame << " -> " << newFrame);
+               Frame newFrame = f(oldFrame);
+               for (const Action& a : actions)
+               {
+                       Action copy = a;
+                       copy.frame  = newFrame;
+                       temp[newFrame].push_back(copy);
                }
+               G_DEBUG(oldFrame << " -> " << newFrame);
        }
 
-       updateMapPointers(ma->map);
+       updateMapPointers_(temp);
 
-       model::actions.swap(std::move(ma));
+       model::DataLock lock;
+       model::getAll<model::Actions>() = std::move(temp);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateEvent(ID id, MidiEvent e)
 {
-       model::onSwap(model::actions, [&](model::Actions& a)
-       {
-               findAction_(a.map, id)->event = e;
-       });
+       model::DataLock lock;
+       findAction_(model::getAll<model::Actions>(), id)->event = e;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateSiblings(ID id, ID prevId, ID nextId)
 {
-       model::onSwap(model::actions, [&](model::Actions& a)
+       model::DataLock lock;
+
+       Action* pcurr = findAction_(model::getAll<model::Actions>(), id);
+       Action* pprev = findAction_(model::getAll<model::Actions>(), prevId);
+       Action* pnext = findAction_(model::getAll<model::Actions>(), nextId);
+
+       pcurr->prev   = pprev;
+       pcurr->prevId = pprev->id;
+       pcurr->next   = pnext;
+       pcurr->nextId = pnext->id;
+
+       if (pprev != nullptr)
        {
-               Action* pcurr = findAction_(a.map, id);
-               Action* pprev = findAction_(a.map, prevId);
-               Action* pnext = findAction_(a.map, nextId);
-
-               pcurr->prev   = pprev;
-               pcurr->prevId = pprev->id;
-               pcurr->next   = pnext;
-               pcurr->nextId = pnext->id;
-
-               if (pprev != nullptr) {
-                       pprev->next   = pcurr;
-                       pprev->nextId = pcurr->id;
-               }
-               if (pnext != nullptr) {
-                       pnext->prev   = pcurr;
-                       pnext->prevId = pcurr->id;
-               }
-       });
+               pprev->next   = pcurr;
+               pprev->nextId = pcurr->id;
+       }
+       if (pnext != nullptr)
+       {
+               pnext->prev   = pcurr;
+               pnext->prevId = pcurr->id;
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool hasActions(ID channelId, int type)
 {
-       model::ActionsLock lock(model::actions);
-       
-       for (const auto& [frame, actions] : model::actions.get()->map)
+       for (const auto& [frame, actions] : model::getAll<model::Actions>())
                for (const Action& a : actions)
                        if (a.channelId == channelId && (type == 0 || type == a.event.getStatus()))
                                return true;
        return false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Action makeAction(ID id, ID channelId, Frame frame, MidiEvent e)
 {
-       Action out {actionId_.get(id), channelId, frame, e, -1, -1};
+       Action out{actionId_.generate(id), channelId, frame, e, -1, -1};
        actionId_.set(id);
        return out;
 }
 
-
 Action makeAction(const patch::Action& a)
 {
        actionId_.set(a.id);
-       return Action {a.id, a.channelId, a.frame, a.event, -1, -1, a.prevId,
-               a.nextId};
+       return Action{a.id, a.channelId, a.frame, a.event, -1, -1, a.prevId,
+           a.nextId};
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Action rec(ID channelId, Frame frame, MidiEvent event)
 {
        /* Skip duplicates. */
@@ -285,79 +258,69 @@ Action rec(ID channelId, Frame frame, MidiEvent event)
                return {};
 
        Action a = makeAction(0, channelId, frame, event);
-       
+
        /* If key frame doesn't exist yet, the [] operator in std::map is smart 
        enough to insert a new item first. No plug-in data for now. */
 
-       model::onSwap(model::actions, [&](model::Actions& mas)
-       {
-               mas.map[frame].push_back(a);
-               updateMapPointers(mas.map);
-       });
+       model::DataLock lock;
+
+       model::getAll<model::Actions>()[frame].push_back(a);
+       updateMapPointers_(model::getAll<model::Actions>());
 
        return a;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void rec(std::vector<Action>& actions)
 {
        if (actions.size() == 0)
                return;
 
-       model::onSwap(model::actions, [&](model::Actions& mas)
-       {
-               for (const Action& a : actions)
-                       if (!exists_(a.channelId, a.frame, a.event, mas.map))
-                               mas.map[a.frame].push_back(a);
-               updateMapPointers(mas.map);
-       });
-}
+       model::DataLock lock;
 
+       ActionMap& map = model::getAll<model::Actions>();
 
-/* -------------------------------------------------------------------------- */
+       for (const Action& a : actions)
+               if (!exists_(a.channelId, a.frame, a.event, map))
+                       map[a.frame].push_back(a);
+       updateMapPointers_(map);
+}
 
+/* -------------------------------------------------------------------------- */
 
 void rec(ID channelId, Frame f1, Frame f2, MidiEvent e1, MidiEvent e2)
 {
-       model::onSwap(model::actions, [&](model::Actions& mas)
-       {
-               mas.map[f1].push_back(makeAction(0, channelId, f1, e1));
-               mas.map[f2].push_back(makeAction(0, channelId, f2, e2));
+       model::DataLock lock;
 
-               Action* a1 = findAction_(mas.map, mas.map[f1].back().id);
-               Action* a2 = findAction_(mas.map, mas.map[f2].back().id);
-               a1->nextId = a2->id;
-               a2->prevId = a1->id;
+       ActionMap& map = model::getAll<model::Actions>();
 
-               updateMapPointers(mas.map);
-       });
-}
+       map[f1].push_back(makeAction(0, channelId, f1, e1));
+       map[f2].push_back(makeAction(0, channelId, f2, e2));
 
+       Action* a1 = findAction_(map, map[f1].back().id);
+       Action* a2 = findAction_(map, map[f2].back().id);
+       a1->nextId = a2->id;
+       a2->prevId = a1->id;
 
-/* -------------------------------------------------------------------------- */
+       updateMapPointers_(map);
+}
 
+/* -------------------------------------------------------------------------- */
 
 const std::vector<Action>* getActionsOnFrame(Frame frame)
 {
-       model::ActionsLock lock(model::actions);
-       
-       if (model::actions.get()->map.count(frame) == 0)
+       if (model::getAll<model::Actions>().count(frame) == 0)
                return nullptr;
-       return &model::actions.get()->map.at(frame);
+       return &model::getAll<model::Actions>().at(frame);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Action getClosestAction(ID channelId, Frame f, int type)
 {
        Action out = {};
-       forEachAction([&](const Action& a)
-       {
+       forEachAction([&](const Action& a) {
                if (a.event.getStatus() != type || a.channelId != channelId)
                        return;
                if (!out.isValid() || (a.frame <= f && a.frame > out.frame))
@@ -366,56 +329,31 @@ Action getClosestAction(ID channelId, Frame f, int type)
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::vector<Action> getActionsOnChannel(ID channelId)
 {
        std::vector<Action> out;
-       forEachAction([&](const Action& a)
-       {
+       forEachAction([&](const Action& a) {
                if (a.channelId == channelId)
                        out.push_back(a);
        });
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void updateMapPointers(ActionMap& src)
-{
-       for (auto& kv : src) {
-               for (Action& action : kv.second) {
-                       if (action.nextId != 0)
-                               action.next = findAction_(src, action.nextId);
-                       if (action.prevId != 0)
-                               action.prev = findAction_(src, action.prevId);
-               }
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 void forEachAction(std::function<void(const Action&)> f)
 {
-       model::ActionsLock lock(model::actions);
-       
-       for (auto& [_, actions] : model::actions.get()->map)
+       for (auto& [_, actions] : model::getAll<model::Actions>())
                for (const Action& action : actions)
                        f(action);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 ID getNewActionId()
 {
-       return actionId_.get();
+       return actionId_.generate();
 }
-}}} // giada::m::recorder::
+} // namespace giada::m::recorder
index fc1e78802e55e08fba78a0301641b6cb5bb36071..d20b4ada433809e53bd5a7d6348897f7db0688f4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_RECORDER_H
 #define G_RECORDER_H
 
-
-#include <map>
-#include <vector>
-#include <functional>
-#include <memory>
-#include "core/types.h"
 #include "core/action.h"
-#include "core/patch.h"
 #include "core/midiEvent.h"
+#include "core/patch.h"
+#include "core/types.h"
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
 
-
-namespace giada {
-namespace m 
-{
-namespace recorder
+namespace giada::m::recorder
 {
 using ActionMap = std::map<Frame, std::vector<Action>>;
 
@@ -96,7 +90,7 @@ void updateSiblings(ID id, ID prevId, ID nextId);
 /* hasActions
 Checks if the channel has at least one action recorded. */
 
-bool hasActions(ID channelId, int type=0);
+bool hasActions(ID channelId, int type = 0);
 
 /* makeAction
 Makes a new action given some data. */
@@ -143,20 +137,10 @@ Given a frame 'f' returns the closest action. */
 
 Action getClosestAction(ID channelId, Frame f, int type);
 
-/* updateMapPointers
-Updates all prev/next actions pointers into the action map. This is required
-after an action has been recorded, since pushing back new actions in a Action 
-vector makes it reallocating the existing ones. Also needed in model::Data copy
-constructor. */
-
-void updateMapPointers(ActionMap& src); 
-
 /* getNewActionId
 Returns a new action ID, internally generated. */
 
 ID getNewActionId();
-
-}}} // giada::m::recorder::
-
+} // namespace giada::m::recorder
 
 #endif
index b35b922ad08e1d07f3c3665f031815f592db511d..60ab6dbd2343b3acd4c6c396eb371fc83d871e48 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <unordered_map>
-#include <algorithm>
-#include <cmath>
-#include <cassert>
-#include "utils/log.h"
-#include "utils/ver.h"
-#include "model/model.h"
-#include "recorder.h"
+#include "recorderHandler.h"
 #include "action.h"
 #include "clock.h"
 #include "const.h"
+#include "model/model.h"
 #include "patch.h"
-#include "recorderHandler.h"
-
+#include "recorder.h"
+#include "utils/log.h"
+#include "utils/ver.h"
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <unordered_map>
 
-namespace giada {
-namespace m {
-namespace recorderHandler
+namespace giada::m::recorderHandler
 {
 namespace
 {
 constexpr int MAX_LIVE_RECS_CHUNK = 128;
 
-std::vector<Action> recs_; 
-
+std::vector<Action> recs_;
 
 /* -------------------------------------------------------------------------- */
 
-
 const Action* getActionPtrById_(int id, const recorder::ActionMap& source)
 {
        for (const auto& [_, actions] : source)
@@ -63,25 +57,21 @@ const Action* getActionPtrById_(int id, const recorder::ActionMap& source)
        return nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* areComposite_
 Composite: NOTE_ON + NOTE_OFF on the same note. */
 
 bool areComposite_(const Action& a1, const Action& a2)
 {
-       return a1.event.getStatus() == MidiEvent::NOTE_ON  &&
+       return a1.event.getStatus() == MidiEvent::NOTE_ON &&
               a2.event.getStatus() == MidiEvent::NOTE_OFF &&
-              a1.event.getNote() == a2.event.getNote()    &&
+              a1.event.getNote() == a2.event.getNote() &&
               a1.channelId == a2.channelId;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* consolidate_
 Given an action 'a1' tries to find the matching NOTE_OFF. This algorithm must
 start searching from the element next to 'a1': since live actions are recorded
@@ -91,7 +81,8 @@ algorithm would end up matching wrong partners. */
 
 void consolidate_(const Action& a1, std::size_t i)
 {
-       for (auto it = recs_.begin() + i; it != recs_.end(); ++it) {
+       for (auto it = recs_.begin() + i; it != recs_.end(); ++it)
+       {
 
                const Action& a2 = *it;
 
@@ -105,32 +96,26 @@ void consolidate_(const Action& a1, std::size_t i)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void consolidate_()
 {
        for (auto it = recs_.begin(); it != recs_.end(); ++it)
-               consolidate_(*it, it - recs_.begin());  // Pass current index
+               consolidate_(*it, it - recs_.begin()); // Pass current index
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
        recs_.reserve(MAX_LIVE_RECS_CHUNK);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isBoundaryEnvelopeAction(const Action& a)
 {
        assert(a.prev != nullptr);
@@ -138,21 +123,22 @@ bool isBoundaryEnvelopeAction(const Action& a)
        return a.prev->frame > a.frame || a.next->frame < a.frame;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void updateBpm(float oldval, float newval, int oldquanto)
+void updateBpm(float ratio, int quantizerStep)
 {
-       recorder::updateKeyFrames([=](Frame old) 
-       {
+       if (ratio == 1.0f)
+               return;
+
+       recorder::updateKeyFrames([=](Frame old) {
                /* The division here cannot be precise. A new frame can be 44099 and the 
                quantizer set to 44100. That would mean two recs completely useless. So we 
-               compute a reject value ('scarto'): if it's lower than 6 frames the new frame 
+               compute a reject value ('delta'): if it's lower than 6 frames the new frame 
                is collapsed with a quantized frame. FIXME - maybe 6 frames are too low. */
-               Frame frame = static_cast<Frame>((old / newval) * oldval);
-               if (frame != 0) {
-                       Frame delta = oldquanto % frame;
+               Frame frame = static_cast<Frame>(old * ratio);
+               if (frame != 0)
+               {
+                       Frame delta = quantizerStep % frame;
                        if (delta > 0 && delta <= 6)
                                frame = frame + delta;
                }
@@ -160,35 +146,30 @@ void updateBpm(float oldval, float newval, int oldquanto)
        });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateSamplerate(int systemRate, int patchRate)
 {
        if (systemRate == patchRate)
                return;
 
-       float ratio = systemRate / (float) patchRate;
+       float ratio = systemRate / (float)patchRate;
 
        recorder::updateKeyFrames([=](Frame old) { return floorf(old * ratio); });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool cloneActions(ID channelId, ID newChannelId)
 {
-       bool cloned = false;
-       std::vector<Action> actions;
+       bool                       cloned = false;
+       std::vector<Action>        actions;
        std::unordered_map<ID, ID> map; // Action ID mapper, old -> new
 
-       recorder::forEachAction([&](const Action& a) 
-       {
+       recorder::forEachAction([&](const Action& a) {
                if (a.channelId != channelId)
                        return;
-               
+
                ID newActionId = recorder::getNewActionId();
 
                map.insert({a.id, newActionId});
@@ -203,9 +184,12 @@ bool cloneActions(ID channelId, ID newChannelId)
 
        /* Update nextId and prevId relationships given the new action ID. */
 
-       for (Action& a : actions) {
-               if (a.prevId != 0) a.prevId = map.at(a.prevId);
-               if (a.nextId != 0) a.nextId = map.at(a.nextId);
+       for (Action& a : actions)
+       {
+               if (a.prevId != 0)
+                       a.prevId = map.at(a.prevId);
+               if (a.nextId != 0)
+                       a.nextId = map.at(a.nextId);
        }
 
        recorder::rec(actions);
@@ -213,10 +197,8 @@ bool cloneActions(ID channelId, ID newChannelId)
        return cloned;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void liveRec(ID channelId, MidiEvent e, Frame globalFrame)
 {
        assert(e.isNoteOnOff()); // Can't record any other kind of events for now
@@ -224,14 +206,12 @@ void liveRec(ID channelId, MidiEvent e, Frame globalFrame)
        /* TODO - this might allocate on the MIDI thread */
        if (recs_.size() >= recs_.capacity())
                recs_.reserve(recs_.size() + MAX_LIVE_RECS_CHUNK);
-       
+
        recs_.push_back(recorder::makeAction(recorder::getNewActionId(), channelId, globalFrame, e));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unordered_set<ID> consolidate()
 {
        consolidate_();
@@ -245,26 +225,20 @@ std::unordered_set<ID> consolidate()
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearAllActions()
 {
-       /* TODO - disgusting */
-       for (std::size_t i = 0; i < model::channels.size(); i++) {
-               model::onSwap(model::channels, model::getId(model::channels, i), [](Channel& c) 
-               { 
-                       c.state->hasActions = false;
-               });
-       }
+       for (channel::Data& ch : model::get().channels)
+               ch.hasActions = false;
+
+       model::swap(model::SwapType::HARD);
+
        recorder::clearAll();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 recorder::ActionMap deserializeActions(const std::vector<patch::Action>& pactions)
 {
        recorder::ActionMap out;
@@ -278,16 +252,19 @@ recorder::ActionMap deserializeActions(const std::vector<patch::Action>& paction
        /* Second pass: fill in previous and next actions, if any. Is this the
        fastest/smartest way to do it? Maybe not. Optimizations are welcome. */
 
-       for (const patch::Action& paction : pactions) {
-               if (paction.nextId == 0 && paction.prevId == 0) 
+       for (const patch::Action& paction : pactions)
+       {
+               if (paction.nextId == 0 && paction.prevId == 0)
                        continue;
                Action* curr = const_cast<Action*>(getActionPtrById_(paction.id, out));
                assert(curr != nullptr);
-               if (paction.nextId != 0) {
+               if (paction.nextId != 0)
+               {
                        curr->next = getActionPtrById_(paction.nextId, out);
                        assert(curr->next != nullptr);
                }
-               if (paction.prevId != 0) {
+               if (paction.prevId != 0)
+               {
                        curr->prev = getActionPtrById_(paction.prevId, out);
                        assert(curr->prev != nullptr);
                }
@@ -296,28 +273,25 @@ recorder::ActionMap deserializeActions(const std::vector<patch::Action>& paction
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::vector<patch::Action> serializeActions(const recorder::ActionMap& actions)
 {
        std::vector<patch::Action> out;
-       for (const auto& kv : actions) {
-               for (const Action& a : kv.second) {
+       for (const auto& kv : actions)
+       {
+               for (const Action& a : kv.second)
+               {
                        out.push_back({
-                               a.id,
-                               a.channelId,
-                               a.frame,
-                               a.event.getRaw(),
-                               a.prevId,
-                               a.nextId,
+                           a.id,
+                           a.channelId,
+                           a.frame,
+                           a.event.getRaw(),
+                           a.prevId,
+                           a.nextId,
                        });
                }
        }
-       return out;     
+       return out;
 }
-
-}}} // giada::m::recorderHandler::
-
-
+} // namespace giada::m::recorderHandler
\ No newline at end of file
index 533346fd2c3d2e12a15ac04f4af74aeca293499e..90f7eee56fc15d8374862d878ce5b08a0ba5cf13 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_RECORDER_HANDLER_H
 #define G_RECORDER_HANDLER_H
 
-
+#include "core/midiEvent.h"
+#include "core/recorder.h"
+#include "core/types.h"
 #include <unordered_set>
-#include "midiEvent.h"
 
-
-namespace giada {
-namespace m 
-{
-namespace patch
+namespace giada::m::patch
 {
 struct Action;
 }
+namespace giada::m
+{
 struct Action;
-namespace recorderHandler
+}
+namespace giada::m::recorderHandler
 {
 void init();
 
@@ -50,7 +49,7 @@ bool isBoundaryEnvelopeAction(const Action& a);
 /* updateBpm
 Changes actions position by calculating the new bpm value. */
 
-void updateBpm(float oldval, float newval, int oldquanto);
+void updateBpm(float ratio, int quantizerStep);
 
 /* updateSamplerate
 Changes actions position by taking in account the new samplerate. If 
@@ -84,9 +83,8 @@ void clearAllActions();
 /* (de)serializeActions
 Creates new Actions given the patch raw data and vice versa. */
 
-recorder::ActionMap deserializeActions(const std::vector<patch::Action>& as);
+recorder::ActionMap        deserializeActions(const std::vector<patch::Action>& as);
 std::vector<patch::Action> serializeActions(const recorder::ActionMap& as);
-}}} // giada::m::recorderHandler::
-
+} // namespace giada::m::recorderHandler
 
 #endif
diff --git a/src/core/resampler.cpp b/src/core/resampler.cpp
new file mode 100644 (file)
index 0000000..596e83c
--- /dev/null
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "core/resampler.h"
+#include <algorithm>
+#include <cassert>
+#include <new>
+#include <utility>
+
+#include <cstdio>
+
+namespace giada::m
+{
+Resampler::Resampler()
+: m_state(nullptr)
+, m_input(nullptr)
+, m_inputPos(0)
+, m_inputLength(0)
+, m_channels(0)
+, m_usedFrames(0)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+Resampler::Resampler(Quality quality, int channels)
+: Resampler()
+{
+       alloc(quality, channels);
+}
+
+/* -------------------------------------------------------------------------- */
+
+Resampler::Resampler(const Resampler& o)
+: Resampler()
+{
+       *this = o;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* This is a fake move constructor that makes a copy instead. The SRC_STATE
+object has a callback that, if moved, would still point to the original object.
+TODO: maybe delete the move constructor? */
+
+Resampler::Resampler(Resampler&& o)
+: Resampler()
+{
+       *this = o;
+}
+
+/* -------------------------------------------------------------------------- */
+
+Resampler& Resampler::operator=(const Resampler& o)
+{
+       if (this == &o)
+               return *this;
+       alloc(o.m_quality, o.m_channels);
+       return *this;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* This is a fake move operator: see notes above. */
+
+Resampler& Resampler::operator=(Resampler&& o)
+{
+       if (this == &o)
+               return *this;
+       alloc(o.m_quality, o.m_channels);
+       return *this;
+}
+
+/* -------------------------------------------------------------------------- */
+
+Resampler::~Resampler()
+{
+       src_delete(m_state);
+}
+
+/* -------------------------------------------------------------------------- */
+
+long Resampler::callback(void* self, float** audio)
+{
+       return static_cast<Resampler*>(self)->callback(audio);
+}
+
+/* -------------------------------------------------------------------------- */
+
+long Resampler::callback(float** audio)
+{
+       assert(audio != nullptr);
+
+       /* Move pointer properly, taking into account read data and number of 
+       channels in input data. */
+
+       *audio = m_input + (m_inputPos * m_channels);
+
+       /* Returns how many frames have been read in this callback shot. */
+
+       long frames;
+
+       /* Read in CHUNK_LEN parts, checking if there is enough data left. */
+
+       if (m_inputPos + CHUNK_LEN < m_inputLength)
+               frames = CHUNK_LEN;
+       else
+               frames = m_inputLength - m_inputPos;
+
+       m_usedFrames += frames;
+       m_inputPos += frames;
+
+       return frames;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void Resampler::alloc(Quality quality, int channels)
+{
+       if (m_state != nullptr)
+               src_delete(m_state);
+       m_state    = src_callback_new(callback, static_cast<int>(quality), channels, nullptr, this);
+       m_quality  = quality;
+       m_channels = channels;
+       if (m_state == nullptr)
+               throw std::bad_alloc();
+       src_reset(m_state);
+}
+
+/* -------------------------------------------------------------------------- */
+
+Resampler::Result Resampler::process(float* input, long inputPos, long inputLength,
+    float* output, long outputLength, float ratio)
+{
+       assert(m_state != nullptr); // Must be initialized first!
+
+       m_input       = input;
+       m_inputPos    = inputPos;
+       m_inputLength = inputLength;
+       m_usedFrames  = 0;
+
+       long generated = src_callback_read(m_state, 1 / ratio, outputLength, output);
+
+       return {m_usedFrames, generated};
+}
+
+/* -------------------------------------------------------------------------- */
+
+void Resampler::last()
+{
+       src_reset(m_state);
+}
+} // namespace giada::m
diff --git a/src/core/resampler.h b/src/core/resampler.h
new file mode 100644 (file)
index 0000000..680a0d3
--- /dev/null
@@ -0,0 +1,97 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_RESAMPLER_H
+#define G_RESAMPLER_H
+
+#include <cstddef>
+#include <samplerate.h>
+
+namespace giada::m
+{
+class Resampler final
+{
+public:
+       enum class Quality
+       {
+               SINC_BEST       = 0,
+               SINC_MEDIUM     = 1,
+               SINC_FASTEST    = 2,
+               ZERO_ORDER_HOLD = 3,
+               LINEAR          = 4
+       };
+
+       /* Result
+       A Result object is returned by the process() function below, containing the 
+       number of frames used from input and generated to output. */
+
+       struct Result
+       {
+               long used, generated;
+       };
+
+       Resampler(); // Invalid
+       Resampler(Quality quality, int channels);
+       Resampler(const Resampler& o);
+       Resampler(Resampler&&);
+       Resampler& operator=(const Resampler&);
+       Resampler& operator=(Resampler&&);
+       ~Resampler();
+
+       /* process
+       Resamples a certain amount of frames from 'input' starting at 'inputPos' and
+       puts the result into 'output'. */
+
+       Result process(float* input, long inputPos, long inputLength, float* output,
+           long outputLength, float ratio);
+
+       /* last
+       Call this when you are about to process the last chunk of data. */
+
+       void last();
+
+private:
+       static long callback(void* self, float** audio);
+       long        callback(float** audio);
+
+       void alloc(Quality quality, int channels);
+
+       /* CHUNK_LEN
+       How many chunks of data to read from input in the callback. */
+
+       static constexpr int CHUNK_LEN = 256;
+
+       SRC_STATE* m_state;
+       Quality    m_quality;
+       float*     m_input;       // Pointer to input data
+       long       m_inputPos;    // Where to read from input
+       long       m_inputLength; // Total number of frames in input data
+       int        m_channels;    // Number of channels
+       long       m_usedFrames;  // How many frames have been read from input with a process() call
+};
+} // namespace giada::m
+
+#endif
\ No newline at end of file
index c2520c3eff175e8eb83448f5c90ac5f705f02e15..310d027cd9c3169316ab5b7820865fd7cce5737f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_RING_BUFFER_H
 #define G_RING_BUFFER_H
 
-
 #include <array>
 
-
 namespace giada
 {
 /* RingBuffer
@@ -45,12 +42,12 @@ public:
        using iterator       = typename std::array<T, S>::iterator;
        using const_iterator = typename std::array<T, S>::const_iterator;
 
-       iterator       begin()        { return m_data.begin(); }
-       iterator       end()          { return m_data.begin() + m_end; }
-       const_iterator begin()  const { return m_data.begin(); }
-       const_iterator end()    const { return m_data.begin() + m_end; }
+       iterator       begin() { return m_data.begin(); }
+       iterator       end() { return m_data.begin() + m_end; }
+       const_iterator begin() const { return m_data.begin(); }
+       const_iterator end() const { return m_data.begin() + m_end; }
        const_iterator cbegin() const { return m_data.begin(); }
-       const_iterator cend()   const { return m_data.begin() + m_end; }
+       const_iterator cend() const { return m_data.begin() + m_end; }
 
        void clear()
        {
@@ -62,25 +59,20 @@ public:
        void push_back(T t)
        {
                m_data[m_index] = t;
-               m_index = (m_index + 1) % m_data.size(); // Wraps around at m_data.size() 
-               m_end   = std::max(m_index, m_end);      // Points to the greater index
+               m_index         = (m_index + 1) % m_data.size(); // Wraps around at m_data.size()
+               m_end           = std::max(m_index, m_end);      // Points to the greater index
        }
 
-       constexpr std::size_t size() const noexcept
+       std::size_t size() const noexcept
        {
-               return m_data.size();
+               return m_end;
        }
 
-private:
-
+  private:
        std::array<T, S> m_data;
        std::size_t      m_index = 0;
        std::size_t      m_end   = 0;
 };
-} // giada::
-
+} // namespace giada
 
 #endif
-
-
-
index c7bc0315f89d3453898bbf8440598c759277ba7c..6425e7f37db745c01a5310b345f0846bdc50b086 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/model/model.h"
+#include "sequencer.h"
+#include "core/clock.h"
+#include "core/conf.h"
 #include "core/const.h"
+#include "core/kernelAudio.h"
+#include "core/metronome.h"
 #include "core/mixer.h"
+#include "core/model/model.h"
 #include "core/quantizer.h"
-#include "core/clock.h"
-#include "core/conf.h"
 #include "core/recManager.h"
-#include "core/kernelAudio.h"
-#include "sequencer.h"
-
 
-namespace giada {
-namespace m {
-namespace sequencer
+namespace giada::m::sequencer
 {
 namespace
 {
 constexpr int Q_ACTION_REWIND = 0;
 
+/* eventBuffer_
+Buffer of events found in each block sent to channels for event parsing. This is 
+filled during react(). */
 
-/* -------------------------------------------------------------------------- */
-
-
-struct Metronome
-{
-       static constexpr Frame CLICK_SIZE = 38;
-
-       float beat[CLICK_SIZE] = {
-                0.059033f,  0.117240f,  0.173807f,  0.227943f,  0.278890f,  0.325936f,
-                0.368423f,  0.405755f,  0.437413f,  0.462951f,  0.482013f,  0.494333f,
-                0.499738f,  0.498153f,  0.489598f,  0.474195f,  0.452159f,  0.423798f,
-                0.389509f,  0.349771f,  0.289883f,  0.230617f,  0.173194f,  0.118739f,
-                0.068260f,  0.022631f, -0.017423f, -0.051339f, -0.078721f, -0.099345f,
-               -0.113163f, -0.120295f, -0.121028f, -0.115804f, -0.105209f, -0.089954f,
-               -0.070862f, -0.048844f
-       };
-
-       float bar[CLICK_SIZE] = {
-                0.175860f,  0.341914f,  0.488904f,  0.608633f,  0.694426f,  0.741500f,
-                0.747229f,  0.711293f,  0.635697f,  0.524656f,  0.384362f,  0.222636f,
-                0.048496f, -0.128348f, -0.298035f, -0.451105f, -0.579021f, -0.674653f,
-               -0.732667f, -0.749830f, -0.688924f, -0.594091f, -0.474481f, -0.340160f,
-               -0.201360f, -0.067752f,  0.052194f,  0.151746f,  0.226280f,  0.273493f,
-                0.293425f,  0.288307f,  0.262252f,  0.220811f,  0.170435f,  0.117887f,
-                0.069639f,  0.031320f
-       };
-
-       Frame tracker  = 0;
-       bool  running  = false;
-       bool  playBar  = false;
-       bool  playBeat = false;
-
-       void render(AudioBuffer& outBuf, bool& process, float* data, Frame f)
-       {
-               process = true;
-               for (int i=0; i<outBuf.countChannels(); i++)
-                       outBuf[f][i] += data[tracker];
-               if (++tracker > Metronome::CLICK_SIZE) {
-                       process = false;
-                       tracker = 0;
-               }       
-       }
-} metronome_;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void renderMetronome_(AudioBuffer& outBuf, Frame f)
-{
-       if (!metronome_.running)
-               return;
-
-       if (clock::isOnBar() || metronome_.playBar)
-               metronome_.render(outBuf, metronome_.playBar, metronome_.bar, f);
-       else
-       if (clock::isOnBeat() || metronome_.playBeat)
-               metronome_.render(outBuf, metronome_.playBeat, metronome_.beat, f);
-}
+EventBuffer eventBuffer_;
 
+Metronome metronome_;
 
 /* -------------------------------------------------------------------------- */
 
-
 void rewindQ_(Frame delta)
 {
        clock::rewind();
-       mixer::pumpEvent({ mixer::EventType::SEQUENCER_REWIND, delta, {} });    
+       eventBuffer_.push_back({EventType::REWIND, 0, delta});
 }
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
-
-
-void start_()
-{
-#ifdef WITH_AUDIO_JACK
-       if (kernelAudio::getAPI() == G_SYS_API_JACK)
-               kernelAudio::jackStart();
-       else
-#endif
-       start(); 
-}
-
-
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void stop_()
-{
-#ifdef WITH_AUDIO_JACK
-       if (kernelAudio::getAPI() == G_SYS_API_JACK)
-               kernelAudio::jackStop();
-       else
-#endif
-       stop();
-}
-
+Quantizer quantizer;
 
 /* -------------------------------------------------------------------------- */
 
-
-void rewind_()
+void init()
 {
-#ifdef WITH_AUDIO_JACK
-       if (kernelAudio::getAPI() == G_SYS_API_JACK)
-               kernelAudio::jackSetPosition(0);
-       else
-#endif
-       rewind();       
+       quantizer.schedule(Q_ACTION_REWIND, rewindQ_);
+       clock::rewind();
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-Quantizer quantizer_;
-} // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void init()
+void react(const eventDispatcher::EventBuffer& events)
 {
-       quantizer_.schedule(Q_ACTION_REWIND, rewindQ_);
-       clock::rewind();
+       for (const eventDispatcher::Event& e : events)
+       {
+               if (e.type == eventDispatcher::EventType::SEQUENCER_START)
+               {
+                       start();
+                       break;
+               }
+               if (e.type == eventDispatcher::EventType::SEQUENCER_STOP)
+               {
+                       stop();
+                       break;
+               }
+               if (e.type == eventDispatcher::EventType::SEQUENCER_REWIND)
+               {
+                       rewind();
+                       break;
+               }
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void run(Frame bufferSize)
+const EventBuffer& advance(Frame bufferSize)
 {
-       Frame start = clock::getCurrentFrame();
-       Frame end   = start + bufferSize;
-       Frame total = clock::getFramesInLoop();
-       Frame bar   = clock::getFramesInBar();
+       eventBuffer_.clear();
 
-       for (Frame i = start, local = 0; i < end; i++, local++) {
+       const Frame start        = clock::getCurrentFrame();
+       const Frame end          = start + bufferSize;
+       const Frame framesInLoop = clock::getFramesInLoop();
+       const Frame framesInBar  = clock::getFramesInBar();
+       const Frame framesInBeat = clock::getFramesInBeat();
+
+       for (Frame i = start, local = 0; i < end; i++, local++)
+       {
 
-               Frame global = i % total; // wraps around 'total'
+               Frame global = i % framesInLoop; // wraps around 'framesInLoop'
 
                if (global == 0)
-                       mixer::pumpEvent({ mixer::EventType::SEQUENCER_FIRST_BEAT, local, { 0, 0, global, {} } });
-               else
-               if (global % bar == 0)
-                       mixer::pumpEvent({ mixer::EventType::SEQUENCER_BAR, local, { 0, 0, global, {} } });
+               {
+                       eventBuffer_.push_back({EventType::FIRST_BEAT, global, local});
+                       metronome_.trigger(Metronome::Click::BEAT, local);
+               }
+               else if (global % framesInBar == 0)
+               {
+                       eventBuffer_.push_back({EventType::BAR, global, local});
+                       metronome_.trigger(Metronome::Click::BAR, local);
+               }
+               else if (global % framesInBeat == 0)
+               {
+                       metronome_.trigger(Metronome::Click::BEAT, local);
+               }
 
                const std::vector<Action>* as = recorder::getActionsOnFrame(global);
                if (as != nullptr)
-                       for (const Action& a : *as)
-                               mixer::pumpEvent({ mixer::EventType::ACTION, local, a });
+                       eventBuffer_.push_back({EventType::ACTIONS, global, local, as});
        }
 
-       quantizer_.advance(Range<Frame>(start, end), clock::getQuantizerStep());
-}
-
+       /* Advance clock and quantizer after the event parsing. */
+       clock::advance(bufferSize);
+       quantizer.advance(Range<Frame>(start, end), clock::getQuantizerStep());
 
-/* -------------------------------------------------------------------------- */
-
-
-void parse(const mixer::EventBuffer& events)
-{
-       for (const mixer::Event& e : events) {
-               if (e.type == mixer::EventType::SEQUENCER_START) {
-                       start_(); break;
-               }
-               if (e.type == mixer::EventType::SEQUENCER_STOP) {
-                       stop_(); break;
-               }
-               if (e.type == mixer::EventType::SEQUENCER_REWIND_REQ) {
-                       rewind_(); break;
-               }
-       }
+       return eventBuffer_;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void advance(AudioBuffer& outBuf)
+void render(AudioBuffer& outBuf)
 {
-       for (Frame i = 0; i < outBuf.countFrames(); i++) {
-               clock::sendMIDIsync(); 
-               clock::incrCurrentFrame();
-               renderMetronome_(outBuf, i);
-       }
+       if (metronome_.running)
+               metronome_.render(outBuf);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void start()
+void rawStart()
 {
-       switch (clock::getStatus()) {
-               case ClockStatus::STOPPED:
-                       clock::setStatus(ClockStatus::RUNNING); 
-                       break;
-               case ClockStatus::WAITING:
-                       clock::setStatus(ClockStatus::RUNNING); 
-                       recManager::stopActionRec();
-                       break;
-               default: 
-                       break;
+       switch (clock::getStatus())
+       {
+       case ClockStatus::STOPPED:
+               clock::setStatus(ClockStatus::RUNNING);
+               break;
+       case ClockStatus::WAITING:
+               clock::setStatus(ClockStatus::RUNNING);
+               recManager::stopActionRec();
+               break;
+       default:
+               break;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void stop()
+void rawStop()
 {
        clock::setStatus(ClockStatus::STOPPED);
 
@@ -270,30 +177,59 @@ void stop()
 
        if (recManager::isRecordingAction())
                recManager::stopActionRec();
-       else
-       if (recManager::isRecordingInput())
-               recManager::stopInputRec();
+       else if (recManager::isRecordingInput())
+               recManager::stopInputRec(conf::conf.inputRecMode);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void rewind()
+void rawRewind()
 {
        if (clock::canQuantize())
-               quantizer_.trigger(Q_ACTION_REWIND);
+               quantizer.trigger(Q_ACTION_REWIND);
        else
                rewindQ_(/*delta=*/0);
 }
 
+/* -------------------------------------------------------------------------- */
+
+void start()
+{
+#ifdef WITH_AUDIO_JACK
+       if (kernelAudio::getAPI() == G_SYS_API_JACK)
+               kernelAudio::jackStart();
+       else
+#endif
+               rawStart();
+}
 
 /* -------------------------------------------------------------------------- */
 
+void stop()
+{
+#ifdef WITH_AUDIO_JACK
+       if (kernelAudio::getAPI() == G_SYS_API_JACK)
+               kernelAudio::jackStop();
+       else
+#endif
+               rawStop();
+}
 
-bool isMetronomeOn()      { return metronome_.running; }
-void toggleMetronome()    { metronome_.running = !metronome_.running; }
-void setMetronome(bool v) { metronome_.running = v; }
-}}} // giada::m::sequencer::
+/* -------------------------------------------------------------------------- */
 
+void rewind()
+{
+#ifdef WITH_AUDIO_JACK
+       if (kernelAudio::getAPI() == G_SYS_API_JACK)
+               kernelAudio::jackSetPosition(0);
+       else
+#endif
+               rawRewind();
+}
+
+/* -------------------------------------------------------------------------- */
 
+bool isMetronomeOn() { return metronome_.running; }
+void toggleMetronome() { metronome_.running = !metronome_.running; }
+void setMetronome(bool v) { metronome_.running = v; }
+} // namespace giada::m::sequencer
\ No newline at end of file
index 19c88983d4b6d9de670c4a8d70179902caf69f0b..50498c5953db54f262376061628b8c205a88f0ac 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_SEQUENCER_H
 #define G_SEQUENCER_H
 
+#include "core/eventDispatcher.h"
+#include "core/quantizer.h"
+#include <vector>
 
-#include "core/mixer.h"
-
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class AudioBuffer;
-namespace sequencer
+}
+namespace giada::m::sequencer
 {
+enum class EventType
+{
+       NONE,
+       FIRST_BEAT,
+       BAR,
+       REWIND,
+       ACTIONS
+};
+
+struct Event
+{
+       EventType                  type    = EventType::NONE;
+       Frame                      global  = 0;
+       Frame                      delta   = 0;
+       const std::vector<Action>* actions = nullptr;
+};
+
+using EventBuffer = RingBuffer<Event, G_MAX_SEQUENCER_EVENTS>;
+
+/* quantizer
+Used by the sequencer itself and each sample channel. */
+
+extern Quantizer quantizer;
+
 void init();
 
-/* parse
+/* react
+Reacts to live events coming from the EventDispatcher (human events). */
+
+void react(const eventDispatcher::EventBuffer& e);
+
+/* advance
 Parses sequencer events that might occur in a block and advances the internal 
-quantizer. */
+quantizer. Returns a reference to the internal EventBuffer filled with events
+(if any). Call this on each new audio block. */
+
+const EventBuffer& advance(Frame bufferSize);
 
-void run(Frame bufferSize);
-void parse(const mixer::EventBuffer& events); 
-void advance(AudioBuffer& outBuf);
+/* render
+Renders audio coming out from the sequencer: that is, the metronome! */
+
+void render(AudioBuffer& outBuf);
+
+/* raw[*]
+Raw functions to start, stop and rewind the sequencer. These functions must be
+called only by clock:: when the JACK signal is received. Other modules should
+use the non-raw versions below. */
+
+void rawStart();
+void rawStop();
+void rawRewind();
 
 void start();
 void stop();
@@ -55,7 +96,6 @@ void rewind();
 bool isMetronomeOn();
 void toggleMetronome();
 void setMetronome(bool v);
-}}}  // giada::m::sequencer::
-
+} // namespace giada::m::sequencer
 
 #endif
diff --git a/src/core/swapper.h b/src/core/swapper.h
new file mode 100644 (file)
index 0000000..e29faed
--- /dev/null
@@ -0,0 +1,141 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_SWAPPER_H
+#define G_SWAPPER_H
+
+#include <atomic>
+#include <functional>
+
+namespace giada
+{
+/* Swapper
+A template class that performs atomic double buffering on type T. */
+
+template <typename T>
+class Swapper
+{
+public:
+       class RtLock
+       {
+               friend Swapper;
+
+       public:
+               RtLock(Swapper& s)
+               : m_swapper(s)
+               {
+                       m_swapper.rt_lock();
+               }
+
+               ~RtLock()
+               {
+                       m_swapper.rt_unlock();
+               }
+
+               const T& get() const
+               {
+                       return m_swapper.rt_get();
+               }
+
+       private:
+               Swapper& m_swapper;
+       };
+
+       Swapper()
+       {
+               static_assert(std::is_assignable_v<T, T>);
+       }
+
+       /* get
+       Returns local data for non-realtime thread. */
+
+       T& get()
+       {
+               return m_data[(m_bits.load() & BIT_INDEX) ^ 1];
+       }
+
+       void swap()
+       {
+               int bits = m_bits.load();
+
+               /* Wait for the audio thread to finish, i.e. until the BUSY bit becomes
+        zero. Only then, swap indexes. This will let the audio thread to pick
+        the updated data on its next cycle. */
+               int desired;
+               do
+               {
+                       bits    = bits & ~BIT_BUSY;               // Expected: current value without busy bit set
+                       desired = (bits ^ BIT_INDEX) & BIT_INDEX; // Desired: flipped (xor) index
+               } while (!m_bits.compare_exchange_weak(bits, desired));
+
+               bits = desired;
+
+               /* After the swap above, m_data[(bits & BIT_INDEX) ^ 1] has become the 
+               non-realtime slot and it points to the data previously read by the
+               realtime thread. That data is old, so update it: overwrite it with the 
+               realtime data in the realtime slot (m_data[bits & BIT_INDEX]) that is 
+               currently being read by the realtime thread. */
+               m_data[(bits & BIT_INDEX) ^ 1] = m_data[bits & BIT_INDEX];
+       }
+
+       bool isLocked()
+       {
+               return m_bits.load() & BIT_BUSY;
+       }
+
+private:
+       static constexpr int BIT_INDEX = (1 << 0); // 0001
+       static constexpr int BIT_BUSY  = (1 << 1); // 0010
+
+       /* [realtime] lock. */
+
+       void rt_lock()
+       {
+               /* Set the busy bit and also get the current index. */
+               m_index = m_bits.fetch_or(BIT_BUSY) & BIT_INDEX;
+       }
+
+       /* [realtime] unlock. */
+
+       void rt_unlock()
+       {
+               m_bits.store(m_index & BIT_INDEX);
+       }
+
+       /* [realtime] Get data currently being ready by the rt thread. */
+
+       const T& rt_get() const
+       {
+               return m_data[m_bits.load() & BIT_INDEX];
+       }
+
+       std::array<T, 2> m_data;
+       std::atomic<int> m_bits{0};
+       int              m_index{0};
+};
+} // namespace giada
+
+#endif
\ No newline at end of file
index ac04502b496f658ee3e22ef6986ae827fc0b9a5d..ea8bab0c549bd895f12e5fadf296440dc04f4060 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_TYPES_H
 #define G_TYPES_H
 
-
 namespace giada
 {
 using ID    = int;
 using Pixel = int;
 using Frame = int;
 
-enum class Thread { MAIN, MIDI, AUDIO };
+enum class Thread
+{
+       MAIN,
+       MIDI,
+       AUDIO,
+       EVENTS
+};
 
 /* Windows fix */
 #ifdef _WIN32
 #undef VOID
 #endif
-enum class ClockStatus { STOPPED, WAITING, RUNNING, ON_BEAT, ON_BAR, ON_FIRST_BEAT, VOID };
+enum class ClockStatus
+{
+       STOPPED,
+       WAITING,
+       RUNNING,
+       ON_BEAT,
+       ON_BAR,
+       ON_FIRST_BEAT,
+       VOID
+};
 
-enum class ChannelType : int { SAMPLE = 1, MIDI, MASTER, PREVIEW };
+enum class ChannelType : int
+{
+       SAMPLE = 1,
+       MIDI,
+       MASTER,
+       PREVIEW
+};
 
 enum class ChannelStatus : int
 {
-       ENDING = 1, WAIT, PLAY, OFF, EMPTY, MISSING, WRONG  
+       ENDING = 1,
+       WAIT,
+       PLAY,
+       OFF,
+       EMPTY,
+       MISSING,
+       WRONG
 };
 
 enum class SamplePlayerMode : int
 {
-       LOOP_BASIC = 1, LOOP_ONCE, LOOP_REPEAT, LOOP_ONCE_BAR,
-       SINGLE_BASIC, SINGLE_PRESS, SINGLE_RETRIG, SINGLE_ENDLESS
+       LOOP_BASIC = 1,
+       LOOP_ONCE,
+       LOOP_REPEAT,
+       LOOP_ONCE_BAR,
+       SINGLE_BASIC,
+       SINGLE_PRESS,
+       SINGLE_RETRIG,
+       SINGLE_ENDLESS
 };
 
-enum class RecTriggerMode : int { NORMAL = 0, SIGNAL };
+enum class RecTriggerMode : int
+{
+       NORMAL = 0,
+       SIGNAL
+};
 
-enum class EventType : int { AUTO = 0, MANUAL };
-}
+enum class InputRecMode : int
+{
+       RIGID = 0,
+       FREE
+};
 
+enum class EventType : int
+{
+       AUTO = 0,
+       MANUAL
+};
+} // namespace giada
 
 #endif
index f30c14a5aaddfc4cd103ba1949fd3b6e4fed5fbb..38ae59ca3f0133669ee290d2aa30fe7fe48bb1b8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <cstring>  // memcpy
+#include "wave.h"
+#include "const.h"
 #include "utils/fs.h"
 #include "utils/log.h"
 #include "utils/string.h"
-#include "const.h"
-#include "wave.h"
-
+#include <cassert>
 
-namespace giada {
-namespace m 
+namespace giada::m
 {
 Wave::Wave(ID id)
-: id       (id),
-  m_rate   (0),
-  m_bits   (0),
-  m_logical(false),
-  m_edited (false) 
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-float* Wave::operator [](int offset) const
+: id(id)
+, m_rate(0)
+, m_bits(0)
+, m_logical(false)
+, m_edited(false)
 {
-       return buffer[offset];
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Wave::Wave(const Wave& other)
-: id        (other.id), 
-  m_rate    (other.m_rate),
-  m_bits    (other.m_bits),    
-  m_logical (false),
-  m_edited  (false),
-  m_path    (other.m_path)
+: id(other.id)
+, m_buffer(other.getBuffer())
+, m_rate(other.m_rate)
+, m_bits(other.m_bits)
+, m_logical(false)
+, m_edited(false)
+, m_path(other.m_path)
 {
-       buffer.alloc(other.getSize(), other.getChannels());
-       buffer.copyData(other.getFrame(0), other.getSize());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void Wave::alloc(int size, int channels, int rate, int bits, const std::string& path)
+void Wave::alloc(Frame size, int channels, int rate, int bits, const std::string& path)
 {
-       buffer.alloc(size, channels);
+       m_buffer.alloc(size, channels);
        m_rate = rate;
        m_bits = bits;
        m_path = path;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string Wave::getBasename(bool ext) const
 {
        return ext ? u::fs::basename(m_path) : u::fs::stripExt(u::fs::basename(m_path));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-int Wave::getRate() const { return m_rate; }
-int Wave::getChannels() const { return buffer.countChannels(); }
+int         Wave::getRate() const { return m_rate; }
 std::string Wave::getPath() const { return m_path; }
-int Wave::getSize() const { return buffer.countFrames(); }
-int Wave::getBits() const { return m_bits; }
-bool Wave::isLogical() const { return m_logical; }
-bool Wave::isEdited() const { return m_edited; }
-
+int         Wave::getBits() const { return m_bits; }
+bool        Wave::isLogical() const { return m_logical; }
+bool        Wave::isEdited() const { return m_edited; }
 
 /* -------------------------------------------------------------------------- */
 
+AudioBuffer&       Wave::getBuffer() { return m_buffer; }
+const AudioBuffer& Wave::getBuffer() const { return m_buffer; }
+
+/* -------------------------------------------------------------------------- */
 
 int Wave::getDuration() const
 {
-       return buffer.countFrames() / m_rate;
+       return m_buffer.countFrames() / m_rate;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string Wave::getExtension() const
 {
        return u::fs::getExt(m_path);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-float* Wave::getFrame(int f) const
-{
-       return buffer[f];
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void Wave::setRate(int v)     { m_rate = v; }
+void Wave::setRate(int v) { m_rate = v; }
 void Wave::setLogical(bool l) { m_logical = l; }
-void Wave::setEdited(bool e)  { m_edited = e; }
-
+void Wave::setEdited(bool e) { m_edited = e; }
 
 /* -------------------------------------------------------------------------- */
 
-
-void Wave::setPath(const std::string& p, int wid) 
-{ 
+void Wave::setPath(const std::string& p, int wid)
+{
        if (wid == -1)
-               m_path = p; 
-       else 
+               m_path = p;
+       else
                m_path = u::fs::stripExt(p) + "-" + std::to_string(wid) + u::fs::getExt(p);
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void Wave::copyData(const float* data, int frames, int channels, int offset)
-{
-       buffer.copyData(data, frames, channels, offset);
-}
-
-
-void Wave::copyData(const AudioBuffer& b) { buffer.copyData(b); }
-void Wave::addData(const AudioBuffer& b)  { buffer.addData(b); }
-
-
 /* -------------------------------------------------------------------------- */
 
-
-void Wave::moveData(AudioBuffer& b)
+void Wave::replaceData(AudioBuffer&& b)
 {
-       buffer.moveData(b);
+       m_buffer = std::move(b);
 }
-}} // giada::m::
+} // namespace giada::m
index d3697326b473b76f194be1914dfb316f05c17268..8f2f697692d1aa7aec424d034654d9bb89215cf2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_WAVE_H
 #define G_WAVE_H
 
-
-#include <string>
 #include "core/audioBuffer.h"
 #include "core/types.h"
+#include <string>
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class Wave
 {
 public:
-
        Wave(ID id);
-       Wave(const Wave& other);
+       Wave(const Wave& o);
+       Wave(Wave&& o) = default;
 
-       float* operator [](int offset) const;
+       Wave& operator=(Wave&& o) = default;
 
-       /* getFrame
-       Works like operator []. See AudioBuffer for reference. */
-       
-       float* getFrame(int f) const;
-       
-       std::string getBasename(bool ext=false) const;
+       std::string getBasename(bool ext = false) const;
        std::string getExtension() const;
-       int getRate() const;
-       int getChannels() const;
-       std::string getPath() const;    
-       int getBits() const;
-       int getSize() const;        // in frames
-       int getDuration() const;
-       bool isLogical() const;
-       bool isEdited() const;
+       int         getRate() const;
+       std::string getPath() const;
+       int         getBits() const;
+       int         getDuration() const;
+       bool        isLogical() const;
+       bool        isEdited() const;
+
+       /* getBuffer
+       Returns a (non-)const reference to the underlying audio buffer. */
+
+       AudioBuffer&       getBuffer();
+       const AudioBuffer& getBuffer() const;
 
        /* setPath
        Sets new path 'p'. If 'id' != -1 inserts a numeric id next to the file 
        extension, e.g. : /path/to/sample-[id].wav */
 
-       void setPath(const std::string& p, int id=-1);
+       void setPath(const std::string& p, int id = -1);
 
        void setRate(int v);
        void setLogical(bool l);
        void setEdited(bool e);
 
-       /* moveData
-       Moves data held by 'b' into this buffer. Then 'b' becomes an empty buffer. */
-
-       void moveData(AudioBuffer& b); 
-       
-       /* copyData
-       Copies 'frames' frames from the new 'data' into m_data, starting from frame 
-       'offset'. */
-
-       void copyData(const float* data, int frames, int channels, int offset=0);
-       void copyData(const AudioBuffer& b);
+       /* replaceData
+       Replaces internal audio buffer with 'b' by moving it. */
 
-       /* addData
-       Merges audio data from buffer 'b' onto this one. */
+       void replaceData(AudioBuffer&& b);
 
-       void addData(const AudioBuffer& b);
-
-       void alloc(int size, int channels, int rate, int bits, const std::string& path);
+       void alloc(Frame size, int channels, int rate, int bits, const std::string& path);
 
        ID id;
 
 private:
-
-       AudioBuffer buffer;
-       int m_rate;
-       int m_bits;
-       bool m_logical;     // memory only (a take)
-       bool m_edited;      // edited via editor
-       std::string m_path; // E.g. /path/to/my/sample.wav
+       AudioBuffer m_buffer;
+       int         m_rate;
+       int         m_bits;
+       bool        m_logical; // memory only (a take)
+       bool        m_edited;  // edited via editor
+       std::string m_path;    // E.g. /path/to/my/sample.wav
 };
-}} // giada::m::
-
+} // namespace giada::m
 
 #endif
index 0fc0531e9c77c62b838508938b4cd04ac94d790d..edaf4f4fe7edc057e33e41b3adce421ac69bb0b2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
-#include <cassert>
-#include <algorithm>
-#include "core/model/model.h"
-#include "utils/log.h"
+#include "waveFx.h"
 #include "const.h"
+#include "utils/log.h"
 #include "wave.h"
-#include "waveFx.h"
-
+#include <algorithm>
+#include <cassert>
+#include <cmath>
 
-namespace giada {
-namespace m {
-namespace wfx
+namespace giada::m::wfx
 {
 namespace
 {
 void fadeFrame_(Wave& w, int i, float val)
 {
-       for (int j=0; j<w.getChannels(); j++)
-               w[i][j] *= val;
+       for (int j = 0; j < w.getBuffer().countChannels(); j++)
+               w.getBuffer()[i][j] *= val;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 float getPeak_(const Wave& w, int a, int b)
 {
        float peak = 0.0f;
        float abs  = 0.0f;
-       for (int i=a; i<b; i++) {
-               for (int j=0; j<w.getChannels(); j++) // Find highest value in any channel
-                       abs = fabs(w[i][j]);
+       for (int i = a; i < b; i++)
+       {
+               for (int j = 0; j < w.getBuffer().countChannels(); j++) // Find highest value in any channel
+                       abs = fabs(w.getBuffer()[i][j]);
                if (abs > peak)
                        peak = abs;
        }
        return peak;
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 constexpr int SMOOTH_SIZE = 32;
 
-
-void normalize(ID waveId, int a, int b)
+void normalize(Wave& w, int a, int b)
 {
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               float peak = getPeak_(w, a, b);
-               if (peak == 0.0f || peak > 1.0f)
-                       return;
+       float peak = getPeak_(w, a, b);
+       if (peak == 0.0f || peak > 1.0f)
+               return;
 
-               for (int i=a; i<b; i++) {
-                       for (int j=0; j<w.getChannels(); j++)
-                               w[i][j] = w[i][j] * (1.0f / peak);
-               }
-               w.setEdited(true);
-       });
+       for (int i = a; i < b; i++)
+       {
+               for (int j = 0; j < w.getBuffer().countChannels(); j++)
+                       w.getBuffer()[i][j] = w.getBuffer()[i][j] * (1.0f / peak);
+       }
+       w.setEdited(true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int monoToStereo(Wave& w)
 {
-       if (w.getChannels() >= G_MAX_IO_CHANS)
+       if (w.getBuffer().countChannels() >= G_MAX_IO_CHANS)
                return G_RES_OK;
 
        AudioBuffer newData;
-       newData.alloc(w.getSize(), G_MAX_IO_CHANS);
+       newData.alloc(w.getBuffer().countFrames(), G_MAX_IO_CHANS);
 
-       for (int i=0; i<newData.countFrames(); i++)
-               for (int j=0; j<newData.countChannels(); j++)
-                       newData[i][j] = w[i][0];
+       for (int i = 0; i < newData.countFrames(); i++)
+               for (int j = 0; j < newData.countChannels(); j++)
+                       newData[i][j] = w.getBuffer()[i][0];
 
-       w.moveData(newData);
+       w.replaceData(std::move(newData));
 
        return G_RES_OK;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void silence(ID waveId, int a, int b)
+void silence(Wave& w, int a, int b)
 {
        u::log::print("[wfx::silence] silencing from %d to %d\n", a, b);
-       
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               for (int i=a; i<b; i++)
-                       for (int j=0; j<w.getChannels(); j++)   
-                               w[i][j] = 0.0f;
-               w.setEdited(true);
-       });
-}
 
+       for (int i = a; i < b; i++)
+               for (int j = 0; j < w.getBuffer().countChannels(); j++)
+                       w.getBuffer()[i][j] = 0.0f;
+       w.setEdited(true);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void cut(ID waveId, int a, int b)
+void cut(Wave& w, int a, int b)
 {
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               if (a < 0) a = 0;
-               if (b > w.getSize()) b = w.getSize();
+       if (a < 0)
+               a = 0;
+       if (b > w.getBuffer().countFrames())
+               b = w.getBuffer().countFrames();
 
-               /* Create a new temp wave and copy there the original one, skipping the a-b 
-               range. */
+       /* Create a new temp wave and copy there the original one, skipping the a-b
+    range. */
 
-               int newSize = w.getSize() - (b - a);
+       int newSize = w.getBuffer().countFrames() - (b - a);
 
-               AudioBuffer newData;
-               newData.alloc(newSize, w.getChannels());
+       AudioBuffer newData;
+       newData.alloc(newSize, w.getBuffer().countChannels());
 
-               u::log::print("[wfx::cut] cutting from %d to %d\n", a, b);
+       u::log::print("[wfx::cut] cutting from %d to %d\n", a, b);
 
-               for (int i=0, k=0; i<w.getSize(); i++) {
-                       if (i < a || i >= b) {
-                               for (int j=0; j<w.getChannels(); j++)   
-                                       newData[k][j] = w[i][j];
-                               k++;
-                       }
+       for (int i = 0, k = 0; i < w.getBuffer().countFrames(); i++)
+       {
+               if (i < a || i >= b)
+               {
+                       for (int j = 0; j < w.getBuffer().countChannels(); j++)
+                               newData[k][j] = w.getBuffer()[i][j];
+                       k++;
                }
+       }
 
-               w.moveData(newData);
-               w.setEdited(true);
-       });
+       w.replaceData(std::move(newData));
+       w.setEdited(true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void trim(ID waveId, int a, int b)
+void trim(Wave& w, Frame a, Frame b)
 {
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               if (a < 0) a = 0;
-               if (b > w.getSize()) b = w.getSize();
+       if (a < 0)
+               a = 0;
+       if (b > w.getBuffer().countFrames())
+               b = w.getBuffer().countFrames();
 
-               int newSize = b - a;
+       Frame newSize = b - a;
 
-               AudioBuffer newData;
-               newData.alloc(newSize, w.getChannels());
+       AudioBuffer newData;
+       newData.alloc(newSize, w.getBuffer().countChannels());
 
-               u::log::print("[wfx::trim] trimming from %d to %d (area = %d)\n", a, b, b-a);
+       u::log::print("[wfx::trim] trimming from %d to %d (area = %d)\n", a, b, b - a);
 
-               for (int i=0; i<newData.countFrames(); i++)
-                       for (int j=0; j<newData.countChannels(); j++)
-                               newData[i][j] = w[i+a][j];
+       for (int i = 0; i < newData.countFrames(); i++)
+               for (int j = 0; j < newData.countChannels(); j++)
+                       newData[i][j] = w.getBuffer()[i + a][j];
 
-               w.moveData(newData);
-               w.setEdited(true);
-       });
+       w.replaceData(std::move(newData));
+       w.setEdited(true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void paste(const Wave& src, ID waveId, int a)
+void paste(const Wave& src, Wave& des, Frame a)
 {
-       model::onSwap(m::model::waves, waveId, [&](Wave& des)
-       {
-               assert(src.getChannels() == des.getChannels());
+       assert(src.getBuffer().countChannels() == des.getBuffer().countChannels());
 
-               AudioBuffer newData;
-               newData.alloc(src.getSize() + des.getSize(), des.getChannels());
+       AudioBuffer newData;
+       newData.alloc(src.getBuffer().countFrames() + des.getBuffer().countFrames(), des.getBuffer().countChannels());
 
-               /* |---original data---|///paste data///|---original data---|
-                                des[0, a)      src[0, src.size)   des[a, des.size)     */
+       /* |---original data---|///paste data///|---original data---|
+                des[0, a)      src[0, src.size)   des[a, des.size)     */
 
-               newData.copyData(des[0], a, 0);
-               newData.copyData(src[0], src.getSize(), a);
-               newData.copyData(des[a], des.getSize() - a, src.getSize() + a);
+       newData.set(des.getBuffer(), a, 0);
+       newData.set(src.getBuffer(), src.getBuffer().countFrames(), a);
+       newData.set(des.getBuffer(), des.getBuffer().countFrames() - a, src.getBuffer().countFrames() + a);
 
-               des.moveData(newData);
-               des.setEdited(true);
-       });
+       des.replaceData(std::move(newData));
+       des.setEdited(true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void fade(ID waveId, int a, int b, Fade type)
+void fade(Wave& w, int a, int b, Fade type)
 {
-       u::log::print("[wfx::fade] fade from %d to %d (range = %d)\n", a, b, b-a);
+       u::log::print("[wfx::fade] fade from %d to %d (range = %d)\n", a, b, b - a);
 
        float m = 0.0f;
-       float d = 1.0f / (float) (b - a);
+       float d = 1.0f / (float)(b - a);
 
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               if (type == Fade::IN)
-                       for (int i=a; i<=b; i++, m+=d)
-                               fadeFrame_(w, i, m);
-               else
-                       for (int i=b; i>=a; i--, m+=d)
-                               fadeFrame_(w, i, m);            
-               
-               w.setEdited(true);
-       });
-}
+       if (type == Fade::IN)
+               for (int i = a; i <= b; i++, m += d)
+                       fadeFrame_(w, i, m);
+       else
+               for (int i = b; i >= a; i--, m += d)
+                       fadeFrame_(w, i, m);
 
+       w.setEdited(true);
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void smooth(ID waveId, int a, int b)
+void smooth(Wave& w, int a, int b)
 {
        /* Do nothing if fade edges (both of SMOOTH_SIZE samples) are > than selected 
        portion of wave. SMOOTH_SIZE*2 to count both edges. */
 
-       if (SMOOTH_SIZE*2 > (b-a)) {
+       if (SMOOTH_SIZE * 2 > (b - a))
+       {
                u::log::print("[wfx::smooth] selection is too small, nothing to do\n");
                return;
        }
 
-       fade(waveId, a, a+SMOOTH_SIZE, Fade::IN);
-       fade(waveId, b-SMOOTH_SIZE, b, Fade::OUT);
+       fade(w, a, a + SMOOTH_SIZE, Fade::IN);
+       fade(w, b - SMOOTH_SIZE, b, Fade::OUT);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void shift(ID waveId, int offset)
+void shift(Wave& w, Frame offset)
 {
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               if (offset < 0)
-                       offset = (w.getSize() + w.getChannels()) + offset;
+       if (offset < 0)
+               offset = (w.getBuffer().countFrames() + w.getBuffer().countChannels()) + offset;
 
-               float* begin = w.getFrame(0);
-               float* end   = w.getFrame(0) + (w.getSize() * w.getChannels());
+       float* begin = w.getBuffer()[0];
+       float* end   = w.getBuffer()[0] + (w.getBuffer().countFrames() * w.getBuffer().countChannels());
 
-               std::rotate(begin, end - (offset * w.getChannels()), end);
-               w.setEdited(true);
-       });
+       std::rotate(begin, end - (offset * w.getBuffer().countChannels()), end);
+       w.setEdited(true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void reverse(ID waveId, int a, int b)
+void reverse(Wave& w, Frame a, Frame b)
 {
        /* https://stackoverflow.com/questions/33201528/reversing-an-array-of-structures-in-c */
-       model::onSwap(m::model::waves, waveId, [&](Wave& w)
-       {
-               float* begin = w.getFrame(0) + (a * w.getChannels());
-               float* end   = w.getFrame(0) + (b * w.getChannels());
+       float* begin = w.getBuffer()[0] + (a * w.getBuffer().countChannels());
+       float* end   = w.getBuffer()[0] + (b * w.getBuffer().countChannels());
 
-               std::reverse(begin, end);
+       std::reverse(begin, end);
 
-               w.setEdited(true);
-       });
+       w.setEdited(true);
 }
-
-}}} // giada::m::wfx::
+} // namespace giada::m::wfx
index 3de9b45104655593a616f6631220f7ef4ca2ac96..9c2c1f0345752dc6b2bbeef30ad4006aa0c31301 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_WAVE_FX_H
 #define G_WAVE_FX_H
 
-
 #include "core/types.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class Wave;
-namespace wfx
+}
+namespace giada::m::wfx
 {
 /* Windows fix */
 #ifdef _WIN32
 #undef IN
 #undef OUT
 #endif
-enum class Fade { IN, OUT };
+enum class Fade
+{
+       IN,
+       OUT
+};
 
 /* monoToStereo
-Converts a 1-channel Wave to a 2-channels wave. It works on a free Wave object,
-not yet added to the RCUList. */
+Converts a 1-channel Wave to a 2-channels wave. */
 
 int monoToStereo(Wave& w);
 
 /* normalize
 Normalizes the wave in range a-b by altering values in memory. */
 
-void normalize(ID waveId, int a, int b);
+void normalize(Wave& w, int a, int b);
 
-void silence(ID waveId, int a, int b);
-void cut(ID waveId, int a, int b);
-void trim(ID waveId, int a, int b);
+void silence(Wave& w, int a, int b);
+void cut(Wave& w, int a, int b);
+void trim(Wave& w, int a, int b);
 
 /* paste
-Pastes Wave 'src' into Wave at 'waveIndex', starting from frame 'a'. */
+Pastes Wave 'src' into Wave 'dest', starting from frame 'a'. */
 
-void paste(const Wave& src, ID waveId, int a);
+void paste(const Wave& src, Wave& dest, Frame a);
 
 /* fade
 Fades in or fades out selection. Can be Fade::IN or Fade::OUT. */
 
-void fade(ID waveId, int a, int b, Fade type);
+void fade(Wave& w, int a, int b, Fade type);
 
 /* smooth
 Smooth edges of selection. */
 
-void smooth(ID waveId, int a, int b);
+void smooth(Wave& w, int a, int b);
 
 /* reverse
 Flips Wave's data. */
 
-void reverse(ID waveId, int a, int b);
-
-void shift(ID waveId, int offset);
-}}} // giada::m::wfx::
+void reverse(Wave& v, Frame a, Frame b);
 
+void shift(Wave& w, Frame offset);
+} // namespace giada::m::wfx
 
 #endif
index d0b2248c5768faa8cc6b4e9f288f94e3ee760612..eee58c70fa56817adbc598f4da450ad6501d284c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
-#include <sndfile.h>
-#include <samplerate.h>
-#include "utils/log.h"
-#include "utils/fs.h"
+#include "waveManager.h"
 #include "const.h"
 #include "idManager.h"
-#include "wave.h"
+#include "model/model.h"
 #include "patch.h"
+#include "utils/fs.h"
+#include "utils/log.h"
+#include "wave.h"
 #include "waveFx.h"
-#include "waveManager.h"
-
+#include <cmath>
+#include <samplerate.h>
+#include <sndfile.h>
 
-namespace giada {
-namespace m {
-namespace waveManager
+namespace giada::m::waveManager
 {
 namespace
 {
 IdManager waveId_;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int getBits_(const SF_INFO& header)
 {
-       if      (header.format & SF_FORMAT_PCM_S8)
+       if (header.format & SF_FORMAT_PCM_S8)
                return 8;
        else if (header.format & SF_FORMAT_PCM_16)
                return 16;
@@ -68,99 +63,96 @@ int getBits_(const SF_INFO& header)
                return 64;
        return 0;
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void init()
 {
        waveId_ = IdManager();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Result createFromFile(const std::string& path, ID id, int samplerate, int quality)
 {
-       if (path == "" || u::fs::isDir(path)) {
+       if (path == "" || u::fs::isDir(path))
+       {
                u::log::print("[waveManager::create] malformed path (was '%s')\n", path);
-               return { G_RES_ERR_NO_DATA };
+               return {G_RES_ERR_NO_DATA};
        }
 
        if (path.size() > FILENAME_MAX)
-               return { G_RES_ERR_PATH_TOO_LONG };
+               return {G_RES_ERR_PATH_TOO_LONG};
 
-       SF_INFO header;
+       SF_INFO  header;
        SNDFILE* fileIn = sf_open(path.c_str(), SFM_READ, &header);
 
-       if (fileIn == nullptr) {
+       if (fileIn == nullptr)
+       {
                u::log::print("[waveManager::create] unable to read %s. %s\n", path, sf_strerror(fileIn));
-               return { G_RES_ERR_IO };
+               return {G_RES_ERR_IO};
        }
 
-       if (header.channels > G_MAX_IO_CHANS) {
+       if (header.channels > G_MAX_IO_CHANS)
+       {
                u::log::print("[waveManager::create] unsupported multi-channel sample\n");
-               return { G_RES_ERR_WRONG_DATA };
+               return {G_RES_ERR_WRONG_DATA};
        }
 
        waveId_.set(id);
 
-       std::unique_ptr<Wave> wave = std::make_unique<Wave>(waveId_.get(id));
+       std::unique_ptr<Wave> wave = std::make_unique<Wave>(waveId_.generate(id));
        wave->alloc(header.frames, header.channels, header.samplerate, getBits_(header), path);
 
-       if (sf_readf_float(fileIn, wave->getFrame(0), header.frames) != header.frames)
+       if (sf_readf_float(fileIn, wave->getBuffer()[0], header.frames) != header.frames)
                u::log::print("[waveManager::create] warning: incomplete read!\n");
 
        sf_close(fileIn);
 
        if (header.channels == 1 && !wfx::monoToStereo(*wave))
-               return { G_RES_ERR_PROCESSING };
-       
-       if (wave->getRate() != samplerate) {
+               return {G_RES_ERR_PROCESSING};
+
+       if (wave->getRate() != samplerate)
+       {
                u::log::print("[waveManager::create] input rate (%d) != required rate (%d), conversion needed\n",
-                       wave->getRate(), samplerate);
+                   wave->getRate(), samplerate);
                if (resample(*wave.get(), quality, samplerate) != G_RES_OK)
-                       return  { G_RES_ERR_PROCESSING };
+                       return {G_RES_ERR_PROCESSING};
        }
 
-       u::log::print("[waveManager::create] new Wave created, %d frames\n", wave->getSize());
+       u::log::print("[waveManager::create] new Wave created, %d frames\n", wave->getBuffer().countFrames());
 
-       return { G_RES_OK, std::move(wave) };
+       return {G_RES_OK, std::move(wave)};
 }
 
 /* -------------------------------------------------------------------------- */
 
-
-std::unique_ptr<Wave> createEmpty(int frames, int channels, int samplerate, 
-       const std::string& name)
+std::unique_ptr<Wave> createEmpty(int frames, int channels, int samplerate,
+    const std::string& name)
 {
-       std::unique_ptr<Wave> wave = std::make_unique<Wave>(waveId_.get());
+       std::unique_ptr<Wave> wave = std::make_unique<Wave>(waveId_.generate());
        wave->alloc(frames, channels, samplerate, G_DEFAULT_BIT_DEPTH, name);
        wave->setLogical(true);
 
-       u::log::print("[waveManager::createEmpty] new empty Wave created, %d frames\n", 
-               wave->getSize());
+       u::log::print("[waveManager::createEmpty] new empty Wave created, %d frames\n",
+           wave->getBuffer().countFrames());
 
        return wave;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unique_ptr<Wave> createFromWave(const Wave& src, int a, int b)
 {
-       int channels = src.getChannels();
+       int channels = src.getBuffer().countChannels();
        int frames   = b - a;
 
-       std::unique_ptr<Wave> wave = std::make_unique<Wave>(waveId_.get());
+       std::unique_ptr<Wave> wave = std::make_unique<Wave>(waveId_.generate());
        wave->alloc(frames, channels, src.getRate(), src.getBits(), src.getPath());
-       wave->copyData(src.getFrame(a), frames, channels);
+       wave->getBuffer().set(src.getBuffer(), frames);
        wave->setLogical(true);
 
        u::log::print("[waveManager::createFromWave] new Wave created, %d frames\n", frames);
@@ -168,77 +160,79 @@ std::unique_ptr<Wave> createFromWave(const Wave& src, int a, int b)
        return wave;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::unique_ptr<Wave> deserializeWave(const patch::Wave& w, int samplerate, int quality)
 {
        return createFromFile(w.path, w.id, samplerate, quality).wave;
 }
 
-
 const patch::Wave serializeWave(const Wave& w)
 {
-       return { w.id, u::fs::basename(w.getPath()) };
+       return {w.id, u::fs::basename(w.getPath())};
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+Wave* hydrateWave(ID waveId)
+{
+       return model::find<Wave>(waveId);
+}
+
+/* -------------------------------------------------------------------------- */
 
 int resample(Wave& w, int quality, int samplerate)
 {
-       float ratio = samplerate / (float) w.getRate();
-       int newSizeFrames = static_cast<int>(ceil(w.getSize() * ratio));
+       float ratio         = samplerate / (float)w.getRate();
+       int   newSizeFrames = static_cast<int>(ceil(w.getBuffer().countFrames() * ratio));
 
        AudioBuffer newData;
-       newData.alloc(newSizeFrames, w.getChannels());
+       newData.alloc(newSizeFrames, w.getBuffer().countChannels());
 
        SRC_DATA src_data;
-       src_data.data_in       = w.getFrame(0);
-       src_data.input_frames  = w.getSize();
+       src_data.data_in       = w.getBuffer()[0];
+       src_data.input_frames  = w.getBuffer().countFrames();
        src_data.data_out      = newData[0];
        src_data.output_frames = newSizeFrames;
        src_data.src_ratio     = ratio;
 
        u::log::print("[waveManager::resample] resampling: new size=%d frames\n", newSizeFrames);
 
-       int ret = src_simple(&src_data, quality, w.getChannels());
-       if (ret != 0) {
+       int ret = src_simple(&src_data, quality, w.getBuffer().countChannels());
+       if (ret != 0)
+       {
                u::log::print("[waveManager::resample] resampling error: %s\n", src_strerror(ret));
                return G_RES_ERR_PROCESSING;
        }
 
-       w.moveData(newData);
+       w.replaceData(std::move(newData));
        w.setRate(samplerate);
 
        return G_RES_OK;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int save(const Wave& w, const std::string& path)
 {
        SF_INFO header;
        header.samplerate = w.getRate();
-       header.channels   = w.getChannels();
+       header.channels   = w.getBuffer().countChannels();
        header.format     = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
 
        SNDFILE* file = sf_open(path.c_str(), SFM_WRITE, &header);
-       if (file == nullptr) {
+       if (file == nullptr)
+       {
                u::log::print("[waveManager::save] unable to open %s for exporting: %s\n",
-                       path, sf_strerror(file));
+                   path, sf_strerror(file));
                return G_RES_ERR_IO;
        }
 
-       if (sf_writef_float(file, w.getFrame(0), w.getSize()) != w.getSize())
+       if (sf_writef_float(file, w.getBuffer()[0], w.getBuffer().countFrames()) != w.getBuffer().countFrames())
                u::log::print("[waveManager::save] warning: incomplete write!\n");
 
        sf_close(file);
 
        return G_RES_OK;
 }
-}}} // giada::m::waveManager
+} // namespace giada::m::waveManager
index 98d7afdc6178e0742d2af2a664e6b2bdfff6f4e1..36fdf20008c93370d86f25a47c2de9d31be0e550 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_WAVE_MANAGER_H
 #define G_WAVE_MANAGER_H
 
-
-#include <string>
-#include <memory>
 #include "core/types.h"
+#include <memory>
+#include <string>
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 class Wave;
-namespace patch
+}
+namespace giada::m::patch
 {
 struct Wave;
 }
-namespace waveManager
+namespace giada::m::waveManager
 {
 struct Result
 {
-    int status;
-    std::unique_ptr<Wave> wave = nullptr;
+       int                   status;
+       std::unique_ptr<Wave> wave = nullptr;
 };
 /* init
 Initializes internal data. */
-       
+
 void init();
 
 /* create
@@ -64,7 +61,7 @@ Result createFromFile(const std::string& path, ID id, int samplerate, int qualit
 /* createEmpty
 Creates a new silent Wave object. */
 
-std::unique_ptr<Wave> createEmpty(int frames, int channels, int samplerate, 
+std::unique_ptr<Wave> createEmpty(int frames, int channels, int samplerate,
     const std::string& name);
 
 /* createFromWave
@@ -77,19 +74,18 @@ Creates a new Wave given the patch raw data and vice versa. */
 
 std::unique_ptr<Wave> deserializeWave(const patch::Wave& w, int samplerate, int quality);
 const patch::Wave     serializeWave(const Wave& w);
+Wave*                 hydrateWave(ID waveId);
 
 /* resample
 Change sample rate of 'w' to the desider value. The 'quality' parameter sets the
 algorithm to use for the conversion. */
 
-int resample(Wave& w, int quality, int samplerate); 
+int resample(Wave& w, int quality, int samplerate);
 
 /* save
 Writes Wave data to file 'path'. Only 'wav' format is supported for now. */
 
 int save(const Wave& w, const std::string& path);
-
-}}} // giada::m::waveManager
-
+} // namespace giada::m::waveManager
 
 #endif
diff --git a/src/core/weakAtomic.h b/src/core/weakAtomic.h
new file mode 100644 (file)
index 0000000..d3ae7df
--- /dev/null
@@ -0,0 +1,80 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_WEAK_ATOMIC_H
+#define G_WEAK_ATOMIC_H
+
+#include <atomic>
+
+namespace giada
+{
+template <typename T>
+class WeakAtomic
+{
+public:
+       WeakAtomic() = default;
+
+       WeakAtomic(T t)
+       : m_value(t)
+       {
+       }
+
+       WeakAtomic(const WeakAtomic& o)
+       : m_value(o.m_value.load(std::memory_order_relaxed))
+       {
+       }
+
+       WeakAtomic(WeakAtomic&& o)
+       : m_value(o.m_value.load(std::memory_order_relaxed), std::memory_order_relaxed)
+       {
+       }
+
+       WeakAtomic& operator=(const WeakAtomic& o)
+       {
+               if (this == &o)
+                       return *this;
+               m_value.store(o.m_value.load(std::memory_order_relaxed), std::memory_order_relaxed);
+               return *this;
+       }
+
+       WeakAtomic& operator=(WeakAtomic&& o) = delete;
+
+       T load() const
+       {
+               return m_value.load(std::memory_order_relaxed);
+       }
+
+       void store(T t)
+       {
+               return m_value.store(t, std::memory_order_relaxed);
+       }
+
+  private:
+       std::atomic<T> m_value;
+};
+} // namespace giada
+
+#endif
\ No newline at end of file
diff --git a/src/core/worker.cpp b/src/core/worker.cpp
new file mode 100644 (file)
index 0000000..8fef05b
--- /dev/null
@@ -0,0 +1,66 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "worker.h"
+#include "utils/time.h"
+
+namespace giada
+{
+Worker::Worker()
+: m_running(false)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+Worker::~Worker()
+{
+       stop();
+}
+
+/* -------------------------------------------------------------------------- */
+
+void Worker::start(std::function<void()> f, int sleep)
+{
+       m_running.store(true);
+       m_thread = std::thread([this, f, sleep]() {
+               while (m_running.load() == true)
+               {
+                       f();
+                       u::time::sleep(sleep);
+               }
+       });
+}
+
+/* -------------------------------------------------------------------------- */
+
+void Worker::stop()
+{
+       m_running.store(false);
+       if (m_thread.joinable())
+               m_thread.join();
+}
+} // namespace giada
diff --git a/src/core/worker.h b/src/core/worker.h
new file mode 100644 (file)
index 0000000..aad217d
--- /dev/null
@@ -0,0 +1,51 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_WORKER_H
+#define G_WORKER_H
+
+#include <atomic>
+#include <functional>
+#include <thread>
+
+namespace giada
+{
+class Worker
+{
+public:
+       Worker();
+       ~Worker();
+
+       void start(std::function<void()> f, int sleep);
+       void stop();
+
+  private:
+       std::thread       m_thread;
+       std::atomic<bool> m_running;
+};
+} // namespace giada
+
+#endif
\ No newline at end of file
index 1af65a1cec5d8fa920fa55cd4bb72d7f74538dc7..86a498d5b7da30a0541e5f1b2853cad009cd2cd1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/model/model.h"
+#include "actionEditor.h"
+#include "core/action.h"
 #include "core/clock.h"
 #include "core/const.h"
-#include "core/recorderHandler.h"
+#include "core/model/model.h"
 #include "core/recorder.h"
-#include "core/action.h"
+#include "core/recorderHandler.h"
 #include "glue/events.h"
 #include "glue/recorder.h"
-#include "actionEditor.h"
-
+#include <cassert>
 
-namespace giada {
-namespace c {
-namespace actionEditor
+namespace giada::c::actionEditor
 {
 namespace
 {
 Frame fixVerticalEnvActions_(Frame f, const m::Action& a1, const m::Action& a2)
 {
-       if      (a1.frame == f) f += 1;
-       else if (a2.frame == f) f -= 1;
+       if (a1.frame == f)
+               f += 1;
+       else if (a2.frame == f)
+               f -= 1;
        if (a1.frame == f || a2.frame == f)
                return -1;
        return f;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 /* recordFirstEnvelopeAction_
@@ -63,10 +60,10 @@ void recordFirstEnvelopeAction_(ID channelId, Frame frame, int value)
        namespace mr = m::recorder;
 
        // TODO - use MidiEvent(float)
-       m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, G_MAX_VELOCITY);
-       m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value);
-       const m::Action a1 = mr::rec(channelId, 0, e1); 
-       const m::Action a2 = mr::rec(channelId, frame, e2); 
+       m::MidiEvent    e1 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, G_MAX_VELOCITY);
+       m::MidiEvent    e2 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value);
+       const m::Action a1 = mr::rec(channelId, 0, e1);
+       const m::Action a2 = mr::rec(channelId, frame, e2);
        const m::Action a3 = mr::rec(channelId, m::clock::getFramesInLoop() - 1, e1);
 
        mr::updateSiblings(a1.id, /*prev=*/a3.id, /*next=*/a2.id); // Circular loop (begin)
@@ -74,10 +71,8 @@ void recordFirstEnvelopeAction_(ID channelId, Frame frame, int value)
        mr::updateSiblings(a3.id, /*prev=*/a2.id, /*next=*/a1.id); // Circular loop (end)
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* recordNonFirstEnvelopeAction_
 Find action right before frame 'frame' and inject a new action in there. 
 Vertical envelope points are forbidden. */
@@ -97,70 +92,53 @@ void recordNonFirstEnvelopeAction_(ID channelId, Frame frame, int value)
                return;
 
        // TODO - use MidiEvent(float)
-       m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value);
+       m::MidiEvent    e2 = m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value);
        const m::Action a2 = mr::rec(channelId, frame, e2);
 
        mr::updateSiblings(a2.id, a1.id, a3.id);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isSinglePressMode_(ID channelId)
 {
-       bool b;
-       m::model::onGet(m::model::channels, channelId, [&](const m::Channel& c)
-       {
-               b = c.samplePlayer->state->mode == SamplePlayerMode::SINGLE_PRESS;
-       });
-       return b;
+       /* TODO - use m::model getChannel utils (to be added) */
+       return m::model::get().getChannel(channelId).samplePlayer->mode == SamplePlayerMode::SINGLE_PRESS;
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-SampleData::SampleData(const m::SamplePlayer& s)
-: channelMode(s.state->mode.load())
-, isLoopMode (s.state->isAnyLoopMode())
+SampleData::SampleData(const m::samplePlayer::Data& s)
+: channelMode(s.mode)
+, isLoopMode(s.isAnyLoopMode())
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Data::Data(const m::Channel& c)
-: channelId  (c.id)
-, channelName(c.state->name)
-, actions    (m::recorder::getActionsOnChannel(c.id))
+Data::Data(const m::channel::Data& c)
+: channelId(c.id)
+, channelName(c.name)
+, actions(m::recorder::getActionsOnChannel(c.id))
 {
-       if (c.getType() == ChannelType::SAMPLE)
-               sample = std::make_optional<SampleData>(*c.samplePlayer);
+       if (c.type == ChannelType::SAMPLE)
+               sample = std::make_optional<SampleData>(c.samplePlayer.value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Data getData(ID channelId)
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock cl(mm::channels);
-       return Data(mm::get(mm::channels, channelId));
+       return Data(m::model::get().getChannel(channelId));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void recordMidiAction(ID channelId, int note, int velocity, Frame f1, Frame f2)
 {
        namespace mr = m::recorder;
@@ -172,12 +150,13 @@ void recordMidiAction(ID channelId, int note, int velocity, Frame f1, Frame f2)
        /* Avoid frame overflow. */
 
        Frame overflow = f2 - (m::clock::getFramesInLoop());
-       if (overflow > 0) {
+       if (overflow > 0)
+       {
                f2 -= overflow;
                f1 -= overflow;
        }
 
-       m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::NOTE_ON,  note, velocity);
+       m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::NOTE_ON, note, velocity);
        m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::NOTE_OFF, note, velocity);
 
        mr::rec(channelId, f1, f2, e1, e2);
@@ -185,10 +164,8 @@ void recordMidiAction(ID channelId, int note, int velocity, Frame f1, Frame f2)
        recorder::updateChannel(channelId, /*updateActionEditor=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void deleteMidiAction(ID channelId, const m::Action& a)
 {
        namespace mr = m::recorder;
@@ -198,8 +175,9 @@ void deleteMidiAction(ID channelId, const m::Action& a)
 
        /* Send a note-off first in case we are deleting it in a middle of a 
        key_on/key_off sequence. Check if 'next' exist first: could be orphaned. */
-       
-       if (a.next != nullptr) {
+
+       if (a.next != nullptr)
+       {
                events::sendMidiToChannel(channelId, a.next->event, Thread::MAIN);
                mr::deleteAction(a.id, a.next->id);
        }
@@ -211,9 +189,8 @@ void deleteMidiAction(ID channelId, const m::Action& a)
 
 /* -------------------------------------------------------------------------- */
 
-
-void updateMidiAction(ID channelId, const m::Action& a, int note, int velocity, 
-       Frame f1, Frame f2)
+void updateMidiAction(ID channelId, const m::Action& a, int note, int velocity,
+    Frame f1, Frame f2)
 {
        namespace mr = m::recorder;
 
@@ -221,22 +198,22 @@ void updateMidiAction(ID channelId, const m::Action& a, int note, int velocity,
        recordMidiAction(channelId, note, velocity, f1, f2);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void recordSampleAction(ID channelId, int type, Frame f1, Frame f2)
 {
        namespace mr = m::recorder;
 
-       if (isSinglePressMode_(channelId)) {
+       if (isSinglePressMode_(channelId))
+       {
                if (f2 == 0)
                        f2 = f1 + G_DEFAULT_ACTION_SIZE;
                m::MidiEvent e1 = m::MidiEvent(m::MidiEvent::NOTE_ON, 0, 0);
                m::MidiEvent e2 = m::MidiEvent(m::MidiEvent::NOTE_OFF, 0, 0);
                mr::rec(channelId, f1, f2, e1, e2);
        }
-       else {
+       else
+       {
                m::MidiEvent e1 = m::MidiEvent(type, 0, 0);
                mr::rec(channelId, f1, e1);
        }
@@ -244,14 +221,12 @@ void recordSampleAction(ID channelId, int type, Frame f1, Frame f2)
        recorder::updateChannel(channelId, /*updateActionEditor=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void updateSampleAction(ID channelId, const m::Action& a, int type, 
-       Frame f1, Frame f2)
+void updateSampleAction(ID channelId, const m::Action& a, int type,
+    Frame f1, Frame f2)
 {
-       namespace mr = m::recorder;     
+       namespace mr = m::recorder;
 
        if (isSinglePressMode_(channelId))
                mr::deleteAction(a.id, a.next->id);
@@ -261,10 +236,8 @@ void updateSampleAction(ID channelId, const m::Action& a, int type,
        recordSampleAction(channelId, type, f1, f2);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void deleteSampleAction(ID channelId, const m::Action& a)
 {
        namespace mr = m::recorder;
@@ -278,34 +251,29 @@ void deleteSampleAction(ID channelId, const m::Action& a)
        recorder::updateChannel(channelId, /*updateActionEditor=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void recordEnvelopeAction(ID channelId, Frame f, int value)
 {
-       namespace mr = m::recorder;     
-       namespace cr = c::recorder;     
+       namespace mr = m::recorder;
+       namespace cr = c::recorder;
 
        assert(value >= 0 && value <= G_MAX_VELOCITY);
 
        /* First action ever? Add actions at boundaries. Else, find action right
        before frame 'f' and inject a new action in there. Vertical envelope points 
        are forbidden for now. */
-       
 
        if (!mr::hasActions(channelId, m::MidiEvent::ENVELOPE))
                recordFirstEnvelopeAction_(channelId, f, value);
-       else 
+       else
                recordNonFirstEnvelopeAction_(channelId, f, value);
 
        recorder::updateChannel(channelId, /*updateActionEditor=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void deleteEnvelopeAction(ID channelId, const m::Action& a)
 {
        namespace mr  = m::recorder;
@@ -316,8 +284,10 @@ void deleteEnvelopeAction(ID channelId, const m::Action& a)
        to restore _i and _d members in channel. */
        /* TODO - move this to c::*/
        /* TODO - FIX*/
-       if (mrh::isBoundaryEnvelopeAction(a)) {
-               if (a.isVolumeEnvelope()) {
+       if (mrh::isBoundaryEnvelopeAction(a))
+       {
+               if (a.isVolumeEnvelope())
+               {
                        /*
                        m::model::onSwap(m::model::channels, channelId, [&](m::Channel& c)
                        {
@@ -327,14 +297,15 @@ void deleteEnvelopeAction(ID channelId, const m::Action& a)
                }
                mr::clearActions(channelId, a.event.getStatus());
        }
-       else {
+       else
+       {
                assert(a.prev != nullptr);
                assert(a.next != nullptr);
-               
+
                const m::Action a1     = *a.prev;
                const m::Action a1prev = *a1.prev;
-               const m::Action a3     = *a.next; 
-               const m::Action a3next = *a3.next; 
+               const m::Action a3     = *a.next;
+               const m::Action a3next = *a3.next;
 
                /* Original status:   a1--->a--->a3
                   Modified status:   a1-------->a3 
@@ -350,10 +321,8 @@ void deleteEnvelopeAction(ID channelId, const m::Action& a)
        recorder::updateChannel(channelId, /*updateActionEditor=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateEnvelopeAction(ID channelId, const m::Action& a, Frame f, int value)
 {
        namespace mr  = m::recorder;
@@ -365,32 +334,29 @@ void updateEnvelopeAction(ID channelId, const m::Action& a, Frame f, int value)
 
        if (mrh::isBoundaryEnvelopeAction(a))
                mr::updateEvent(a.id, m::MidiEvent(m::MidiEvent::ENVELOPE, 0, value));
-       else {
+       else
+       {
                deleteEnvelopeAction(channelId, a);
                recordEnvelopeAction(channelId, f, value);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::vector<m::Action> getActions(ID channelId)
 {
        return m::recorder::getActionsOnChannel(channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateVelocity(const m::Action& a, int value)
 {
        namespace mr = m::recorder;
-       
+
        m::MidiEvent event(a.event);
        event.setVelocity(value);
 
        mr::updateEvent(a.id, event);
 }
-}}} // giada::c::actionEditor::
+} // namespace giada::c::actionEditor
index cf07002801b99466a21f408fa119a6102ee8fdb7..ab4fab75fc963f84bf267c903599462e82cff4d8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_ACTION_EDITOR_H
 #define G_GLUE_ACTION_EDITOR_H
 
-
+#include "core/types.h"
 #include <optional>
-#include <vector>
 #include <string>
-#include "core/types.h"
-
+#include <vector>
 
-namespace giada {
-namespace m
+namespace giada::m
 {
 struct Action;
-class  Channel;
-class  SamplePlayer;
 }
-namespace c {
-namespace actionEditor 
+namespace giada::m::channel
+{
+struct Data;
+}
+namespace giada::m::samplePlayer
+{
+struct Data;
+}
+namespace giada::c::actionEditor
 {
 struct SampleData
 {
-       SampleData(const m::SamplePlayer&); 
+       SampleData(const m::samplePlayer::Data&);
 
-    SamplePlayerMode channelMode;
+       SamplePlayerMode channelMode;
        bool             isLoopMode;
 };
 
 struct Data
 {
-    Data() = default;
-    Data(const m::Channel&);
+       Data() = default;
+       Data(const m::channel::Data&);
 
-    ID                     channelId; 
-    std::string            channelName;
+       ID                     channelId;
+       std::string            channelName;
        std::vector<m::Action> actions;
 
-    std::optional<SampleData> sample;
+       std::optional<SampleData> sample;
 };
 
 Data getData(ID channelId);
 
 /* MIDI actions.  */
 
-void recordMidiAction(ID channelId, int note, int velocity, Frame f1, 
-       Frame f2=0);
+void recordMidiAction(ID channelId, int note, int velocity, Frame f1,
+    Frame f2 = 0);
 void deleteMidiAction(ID channelId, const m::Action& a);
-void updateMidiAction(ID channelId, const m::Action& a, int note, int velocity, 
-       Frame f1, Frame f2);
+void updateMidiAction(ID channelId, const m::Action& a, int note, int velocity,
+    Frame f1, Frame f2);
 void updateVelocity(const m::Action& a, int value);
 
 /* Sample Actions. */
 
-void recordSampleAction(ID channelId, int type, Frame f1, Frame f2=0);
+void recordSampleAction(ID channelId, int type, Frame f1, Frame f2 = 0);
 void deleteSampleAction(ID channelId, const m::Action& a);
-void updateSampleAction(ID channelId, const m::Action& a, int type, 
-    Frame f1, Frame f2=0);
+void updateSampleAction(ID channelId, const m::Action& a, int type,
+    Frame f1, Frame f2 = 0);
 
 /* Envelope actions (only volume for now). */
 
 void recordEnvelopeAction(ID channelId, Frame f, int value);
 void deleteEnvelopeAction(ID channelId, const m::Action& a);
 void updateEnvelopeAction(ID channelId, const m::Action& a, Frame f, int value);
-}}} // giada::c::actionEditor::
-
+} // namespace giada::c::actionEditor
 
 #endif
index f781ac606a629e7cf285450ed4c030ca28c2ffe0..5e37292c9d597913e2da024998d07a4150fb29f3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <functional>
-#include <cmath>
-#include <cassert>
-#include <FL/Fl.H>
+#include "gui/elems/mainWindow/keyboard/channel.h"
+#include "channel.h"
+#include "core/clock.h"
+#include "core/conf.h"
+#include "core/kernelAudio.h"
+#include "core/mixer.h"
+#include "core/mixerHandler.h"
+#include "core/model/model.h"
+#include "core/plugins/plugin.h"
+#include "core/plugins/pluginHost.h"
+#include "core/recManager.h"
+#include "core/recorder.h"
+#include "core/wave.h"
+#include "core/waveManager.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/sampleEditor.h"
 #include "gui/dialogs/warnings.h"
-#include "gui/elems/basics/input.h"
 #include "gui/elems/basics/dial.h"
-#include "gui/elems/sampleEditor/waveTools.h"
-#include "gui/elems/sampleEditor/volumeTool.h"
+#include "gui/elems/basics/input.h"
+#include "gui/elems/mainWindow/keyboard/channelButton.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
+#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
 #include "gui/elems/sampleEditor/boostTool.h"
 #include "gui/elems/sampleEditor/panTool.h"
 #include "gui/elems/sampleEditor/pitchTool.h"
 #include "gui/elems/sampleEditor/rangeTool.h"
+#include "gui/elems/sampleEditor/volumeTool.h"
+#include "gui/elems/sampleEditor/waveTools.h"
 #include "gui/elems/sampleEditor/waveform.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/elems/mainWindow/keyboard/channel.h"
-#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
-#include "gui/elems/mainWindow/keyboard/channelButton.h"
-#include "utils/gui.h"
+#include "main.h"
 #include "utils/fs.h"
+#include "utils/gui.h"
 #include "utils/log.h"
-#include "core/model/model.h"
-#include "core/kernelAudio.h"
-#include "core/mixerHandler.h"
-#include "core/mixer.h"
-#include "core/clock.h"
-#include "core/plugins/pluginHost.h"
-#include "core/conf.h"
-#include "core/wave.h"
-#include "core/recorder.h"
-#include "core/recManager.h"
-#include "core/plugins/plugin.h"
-#include "core/waveManager.h"
-#include "main.h"
-#include "channel.h"
-
+#include <FL/Fl.H>
+#include <cassert>
+#include <cmath>
+#include <functional>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace c {
-namespace channel 
+namespace giada::c::channel
 {
 namespace
 {
 void printLoadError_(int res)
 {
-       if      (res == G_RES_ERR_WRONG_DATA)
+       if (res == G_RES_ERR_WRONG_DATA)
                v::gdAlert("Multichannel samples not supported.");
        else if (res == G_RES_ERR_IO)
                v::gdAlert("Unable to read this sample.");
@@ -84,111 +79,93 @@ void printLoadError_(int res)
        else if (res == G_RES_ERR_NO_DATA)
                v::gdAlert("No file specified.");
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-SampleData::SampleData(const m::SamplePlayer& s, const m::AudioReceiver& a)
-: waveId         (s.getWaveId())
-, mode           (s.state->mode.load())
-, isLoop         (s.state->isAnyLoopMode())
-, pitch          (s.state->pitch.load())
-, m_samplePlayer (&s)
-, m_audioReceiver(&a)
+// TODO - just pass const channel::Data&
+SampleData::SampleData(const m::channel::Data& ch)
+: waveId(ch.samplePlayer->getWaveId())
+, mode(ch.samplePlayer->mode)
+, isLoop(ch.samplePlayer->isAnyLoopMode())
+, pitch(ch.samplePlayer->pitch)
+, m_channel(&ch)
 {
 }
 
-
-Frame SampleData::a_getTracker() const           { return a_get(m_samplePlayer->state->tracker); }
-Frame SampleData::a_getBegin() const             { return a_get(m_samplePlayer->state->begin); }
-Frame SampleData::a_getEnd() const               { return a_get(m_samplePlayer->state->end); }
-bool  SampleData::a_getInputMonitor() const      { return a_get(m_audioReceiver->state->inputMonitor); }
-bool  SampleData::a_getOverdubProtection() const { return a_get(m_audioReceiver->state->overdubProtection); }
-
+Frame SampleData::getTracker() const { return m_channel->state->tracker.load(); }
+/* TODO - useless methods, turn them into member vars */
+Frame SampleData::getBegin() const { return m_channel->samplePlayer->begin; }
+Frame SampleData::getEnd() const { return m_channel->samplePlayer->end; }
+bool  SampleData::getInputMonitor() const { return m_channel->audioReceiver->inputMonitor; }
+bool  SampleData::getOverdubProtection() const { return m_channel->audioReceiver->overdubProtection; }
 
 /* -------------------------------------------------------------------------- */
 
-
-MidiData::MidiData(const m::MidiSender& m)
-: m_midiSender(&m)
+MidiData::MidiData(const m::channel::Data& m)
+: m_channel(&m)
 {
 }
 
-bool MidiData::a_isOutputEnabled() const { return a_get(m_midiSender->state->enabled); }
-int  MidiData::a_getFilter() const       { return a_get(m_midiSender->state->filter); }
-
+/* TODO - useless methods, turn them into member vars */
+bool MidiData::isOutputEnabled() const { return m_channel->midiSender->enabled; }
+int  MidiData::getFilter() const { return m_channel->midiSender->filter; }
 
 /* -------------------------------------------------------------------------- */
 
-
-Data::Data(const m::Channel& c)
-: id         (c.id)
-, columnId   (c.getColumnId())
+Data::Data(const m::channel::Data& c)
+: id(c.id)
+, columnId(c.columnId)
 #ifdef WITH_VST
-, pluginIds  (c.pluginIds)
+, plugins(c.plugins)
 #endif
-, type       (c.getType())
-, height     (c.state->height)
-, name       (c.state->name)
-, volume     (c.state->volume.load())
-, pan        (c.state->pan.load())
-, key        (c.state->key.load())
-, hasActions (c.state->hasActions)
-, m_channel  (c)
+, type(c.type)
+, height(c.height)
+, name(c.name)
+, volume(c.volume)
+, pan(c.pan)
+, key(c.key)
+, hasActions(c.hasActions)
+, m_channel(c)
 {
-       if (c.getType() == ChannelType::SAMPLE)
-               sample = std::make_optional<SampleData>(*c.samplePlayer, *c.audioReceiver);
-       else
-       if (c.getType() == ChannelType::MIDI)
-               midi   = std::make_optional<MidiData>(*c.midiSender);
+       if (c.type == ChannelType::SAMPLE)
+               sample = std::make_optional<SampleData>(c);
+       else if (c.type == ChannelType::MIDI)
+               midi = std::make_optional<MidiData>(c);
 }
 
-
-bool          Data::a_getSolo() const           { return a_get(m_channel.state->solo); }
-bool          Data::a_getMute() const           { return a_get(m_channel.state->mute); }
-ChannelStatus Data::a_getPlayStatus() const     { return a_get(m_channel.state->playStatus); }
-ChannelStatus Data::a_getRecStatus() const      { return a_get(m_channel.state->recStatus); }
-bool          Data::a_getReadActions() const    { return a_get(m_channel.state->readActions); }
-bool          Data::a_isArmed() const           { return a_get(m_channel.state->armed); }
-bool          Data::a_isRecordingInput() const  { return m::recManager::isRecordingInput(); }
-bool          Data::a_isRecordingAction() const { return m::recManager::isRecordingAction(); }
-
+ChannelStatus Data::getPlayStatus() const { return m_channel.state->playStatus.load(); }
+ChannelStatus Data::getRecStatus() const { return m_channel.state->recStatus.load(); }
+bool          Data::getReadActions() const { return m_channel.state->readActions.load(); }
+bool          Data::isRecordingInput() const { return m::recManager::isRecordingInput(); }
+bool          Data::isRecordingAction() const { return m::recManager::isRecordingAction(); }
+/* TODO - useless methods, turn them into member vars */
+bool Data::getSolo() const { return m_channel.solo; }
+bool Data::getMute() const { return m_channel.mute; }
+bool Data::isArmed() const { return m_channel.armed; }
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Data getData(ID channelId)
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock cl(mm::channels);
-       return Data(mm::get(mm::channels, channelId));
+       return Data(m::model::get().getChannel(channelId));
 }
 
-
 std::vector<Data> getChannels()
 {
-       namespace mm = m::model;
-       mm::ChannelsLock cl(mm::channels);
-
        std::vector<Data> out;
-       for (const m::Channel* ch : mm::channels)
-               if (!ch->isInternal()) 
-                       out.push_back(Data(*ch));
-       
+       for (const m::channel::Data& ch : m::model::get().channels)
+               if (!ch.isInternal())
+                       out.push_back(Data(ch));
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int loadChannel(ID channelId, const std::string& fname)
 {
        /* Save the patch and take the last browser's dir in order to re-use it the 
@@ -199,23 +176,19 @@ int loadChannel(ID channelId, const std::string& fname)
        int res = m::mh::loadChannel(channelId, fname);
        if (res != G_RES_OK)
                printLoadError_(res);
-       
+
        return res;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void addChannel(ID columnId, ChannelType type)
 {
        m::mh::addChannel(type, columnId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void addAndLoadChannel(ID columnId, const std::string& fpath)
 {
        int res = m::mh::addAndLoadChannel(columnId, fpath);
@@ -223,7 +196,6 @@ void addAndLoadChannel(ID columnId, const std::string& fpath)
                printLoadError_(res);
 }
 
-
 void addAndLoadChannels(ID columnId, const std::vector<std::string>& fpaths)
 {
        if (fpaths.size() == 1)
@@ -238,10 +210,8 @@ void addAndLoadChannels(ID columnId, const std::vector<std::string>& fpaths)
                v::gdAlert("Some files weren't loaded sucessfully.");
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void deleteChannel(ID channelId)
 {
        if (!v::gdConfirmWin("Warning", "Delete channel: are you sure?"))
@@ -251,10 +221,8 @@ void deleteChannel(ID channelId)
        m::mh::deleteChannel(channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void freeChannel(ID channelId)
 {
        if (!v::gdConfirmWin("Warning", "Free channel: are you sure?"))
@@ -264,76 +232,53 @@ void freeChannel(ID channelId)
        m::mh::freeChannel(channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setInputMonitor(ID channelId, bool value)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c) 
-       { 
-               c.audioReceiver->state->inputMonitor.store(value);
-       });
+       m::model::get().getChannel(channelId).audioReceiver->inputMonitor = value;
+       m::model::swap(m::model::SwapType::SOFT);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setOverdubProtection(ID channelId, bool value)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c) 
-       {
-               c.audioReceiver->state->overdubProtection.store(value);
-               if (value == true && c.state->armed.load() == true)
-                       c.state->armed.store(false);
-       });     
+       m::channel::Data& ch                = m::model::get().getChannel(channelId);
+       ch.audioReceiver->overdubProtection = value;
+       if (value == true && ch.armed)
+               ch.armed = false;
+       m::model::swap(m::model::SwapType::SOFT);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void cloneChannel(ID channelId)
 {
        m::mh::cloneChannel(channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void setSamplePlayerMode(ID channelId, SamplePlayerMode m)
+void setSamplePlayerMode(ID channelId, SamplePlayerMode mode)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.samplePlayer->state->mode.store(m);
-       });
-
-       /* TODO - brutal rebuild! Just rebuild the specific channel instead */
-       G_MainWin->keyboard->rebuild();
-
+       m::model::get().getChannel(channelId).samplePlayer->mode = mode;
+       m::model::swap(m::model::SwapType::HARD); // TODO - SOFT should be enough, fix geChannel refresh method
        u::gui::refreshActionEditor();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setHeight(ID channelId, Pixel p)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.state->height = p;
-       });     
+       m::model::get().getChannel(channelId).height = p;
+       m::model::swap(m::model::SwapType::SOFT);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setName(ID channelId, const std::string& name)
 {
        m::mh::renameChannel(channelId, name);
 }
-}}} // giada::c::channel::
+} // namespace giada::c::channel
index c82d7e84542cab345ee68e99e3cfb24f14667960..cddf96c288b5ff979e211e3d6eaa3b02b3709c91 100644 (file)
@@ -1,10 +1,10 @@
-       /* -----------------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_CHANNEL_H
 #define G_GLUE_CHANNEL_H
 
-
-#include <optional>
+#include "core/model/model.h"
+#include "core/types.h"
 #include <atomic>
+#include <optional>
 #include <string>
 #include <vector>
-#include "core/model/model.h"
-#include "core/types.h"
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
-class Channel;
-class SamplePlayer;
+class Plugin;
 }
-namespace c {
-namespace channel 
+namespace giada::c::channel
 {
 struct SampleData
 {
        SampleData() = delete;
-       SampleData(const m::SamplePlayer&, const m::AudioReceiver&);
+       SampleData(const m::channel::Data&);
 
-       Frame a_getTracker() const;
-       Frame a_getBegin() const;
-       Frame a_getEnd() const;
-       bool  a_getInputMonitor() const;
-       bool  a_getOverdubProtection() const;
+       Frame getTracker() const;
+       Frame getBegin() const;
+       Frame getEnd() const;
+       bool  getInputMonitor() const;
+       bool  getOverdubProtection() const;
 
        ID               waveId;
        SamplePlayerMode mode;
        bool             isLoop;
        float            pitch;
 
-private:
-
-       const m::SamplePlayer*  m_samplePlayer;
-       const m::AudioReceiver* m_audioReceiver;
+  private:
+       const m::channel::Data* m_channel;
 };
 
 struct MidiData
 {
        MidiData() = delete;
-       MidiData(const m::MidiSender&);
+       MidiData(const m::channel::Data&);
 
-       bool a_isOutputEnabled() const;
-       int  a_getFilter() const;
+       bool isOutputEnabled() const;
+       int  getFilter() const;
 
-private:
-
-       const m::MidiSender* m_midiSender;
+  private:
+       const m::channel::Data* m_channel;
 };
 
 struct Data
 {
-       Data(const m::Channel&);
-
-       bool a_getMute() const;
-       bool a_getSolo() const;
-       ChannelStatus a_getPlayStatus() const;
-       ChannelStatus a_getRecStatus() const;
-       bool a_getReadActions() const;
-       bool a_isArmed() const;
-       bool a_isRecordingInput() const;
-       bool a_isRecordingAction() const;
-
-       ID              id;
-       ID              columnId;
+       Data(const m::channel::Data&);
+
+       bool          getMute() const;
+       bool          getSolo() const;
+       ChannelStatus getPlayStatus() const;
+       ChannelStatus getRecStatus() const;
+       bool          getReadActions() const;
+       bool          isArmed() const;
+       bool          isRecordingInput() const;
+       bool          isRecordingAction() const;
+
+       ID id;
+       ID columnId;
 #ifdef WITH_VST
-       std::vector<ID> pluginIds;
+       std::vector<m::Plugin*> plugins;
 #endif
-       ChannelType     type;
-       Pixel           height;
-       std::string     name;
-       float           volume;
-       float           pan;
-       int             key;
-       bool            hasActions;
+       ChannelType type;
+       Pixel       height;
+       std::string name;
+       float       volume;
+       float       pan;
+       int         key;
+       bool        hasActions;
 
        std::optional<SampleData> sample;
        std::optional<MidiData>   midi;
 
-private:
-
-       const m::Channel& m_channel;
+  private:
+       const m::channel::Data& m_channel;
 };
 
 /* getChannels
@@ -125,16 +115,6 @@ Returns a vector of viewModel objects filled with data from channels. */
 
 std::vector<Data> getChannels();
 
-/* a_get
-Returns an atomic property from a Channel, by locking it first. */
-
-template <typename T>
-T a_get(const std::atomic<T>& a)
-{
-       m::model::ChannelsLock l(m::model::channels);
-       return a.load();
-}
-
 /* addChannel
 Adds an empty new channel to the stack. */
 
@@ -148,7 +128,7 @@ int loadChannel(ID columnId, const std::string& fname);
 /* addAndLoadChannel
 Adds a new Sample Channel and fills it with a wave right away. */
 
-void addAndLoadChannel(ID columnId, const std::string& fpath); 
+void addAndLoadChannel(ID columnId, const std::string& fpath);
 
 /* addAndLoadChannels
 As above, with multiple audio file paths in input. */
@@ -179,6 +159,6 @@ void setName(ID channelId, const std::string& name);
 void setHeight(ID channelId, Pixel p);
 
 void setSamplePlayerMode(ID channelId, SamplePlayerMode m);
-}}} // giada::c::channel::
+} // namespace giada::c::channel
 
 #endif
diff --git a/src/glue/config.cpp b/src/glue/config.cpp
new file mode 100644 (file)
index 0000000..9232c0f
--- /dev/null
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "config.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include "core/kernelAudio.h"
+#include "deps/rtaudio/RtAudio.h"
+
+namespace giada::c::config
+{
+namespace
+{
+AudioDeviceData getAudioDeviceData_(DeviceType type, size_t index, int channelsCount, int channelsStart)
+{
+       for (const m::kernelAudio::Device& device : m::kernelAudio::getDevices())
+               if (device.index == index)
+                       return AudioDeviceData(type, device, channelsCount, channelsStart);
+       return AudioDeviceData();
+}
+} // namespace
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+AudioDeviceData::AudioDeviceData(DeviceType type, const m::kernelAudio::Device& device,
+    int channelsCount, int channelsStart)
+: type(type)
+, index(device.index)
+, name(device.name)
+, channelsMax(type == DeviceType::OUTPUT ? device.maxOutputChannels : device.maxInputChannels)
+, sampleRates(device.sampleRates)
+, channelsCount(channelsCount)
+, channelsStart(channelsStart)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+void AudioData::setOutputDevice(int index)
+{
+       for (AudioDeviceData& d : outputDevices)
+       {
+               if (index != d.index)
+                       continue;
+               outputDevice = d;
+       }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioData::setInputDevice(int index)
+{
+       for (AudioDeviceData& d : inputDevices)
+       {
+               if (index == d.index)
+               {
+                       inputDevice = d;
+                       return;
+               }
+       }
+       inputDevice = {};
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+AudioData getAudioData()
+{
+       AudioData audioData;
+
+       audioData.apis[G_SYS_API_NONE] = "(none)";
+
+#if defined(G_OS_LINUX)
+
+       if (m::kernelAudio::hasAPI(RtAudio::LINUX_ALSA))
+               audioData.apis[G_SYS_API_ALSA] = "ALSA";
+       if (m::kernelAudio::hasAPI(RtAudio::UNIX_JACK))
+               audioData.apis[G_SYS_API_JACK] = "Jack";
+       if (m::kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
+               audioData.apis[G_SYS_API_PULSE] = "PulseAudio";
+
+#elif defined(G_OS_FREEBSD)
+
+       if (m::kernelAudio::hasAPI(RtAudio::UNIX_JACK))
+               audioData.apis[G_SYS_API_JACK] = "Jack";
+       if (m::kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
+               audioData.apis[G_SYS_API_PULSE] = "PulseAudio";
+
+#elif defined(G_OS_WINDOWS)
+
+       if (m::kernelAudio::hasAPI(RtAudio::WINDOWS_DS))
+               audioData.apis[G_SYS_API_DS] = "DirectSound";
+       if (m::kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO))
+               audioData.apis[G_SYS_API_ASIO] = "ASIO";
+       if (m::kernelAudio::hasAPI(RtAudio::WINDOWS_WASAPI))
+               audioData.apis[G_SYS_API_WASAPI] = "WASAPI";
+
+#elif defined(G_OS_MAC)
+
+       if (m::kernelAudio::hasAPI(RtAudio::MACOSX_CORE))
+               audioData.apis[G_SYS_API_CORE] = "CoreAudio";
+
+#endif
+
+       std::vector<m::kernelAudio::Device> devices = m::kernelAudio::getDevices();
+
+       for (const m::kernelAudio::Device& device : devices)
+       {
+               if (device.maxOutputChannels > 0)
+                       audioData.outputDevices.push_back(AudioDeviceData(DeviceType::OUTPUT, device, G_MAX_IO_CHANS, 0));
+               if (device.maxInputChannels > 0)
+                       audioData.inputDevices.push_back(AudioDeviceData(DeviceType::INPUT, device, 1, 0));
+       }
+
+       audioData.api             = m::conf::conf.soundSystem;
+       audioData.bufferSize      = m::conf::conf.buffersize;
+       audioData.sampleRate      = m::conf::conf.samplerate;
+       audioData.limitOutput     = m::conf::conf.limitOutput;
+       audioData.recTriggerLevel = m::conf::conf.recTriggerLevel;
+       audioData.resampleQuality = m::conf::conf.rsmpQuality;
+       audioData.outputDevice    = getAudioDeviceData_(DeviceType::OUTPUT,
+        m::conf::conf.soundDeviceOut, m::conf::conf.channelsOutCount,
+        m::conf::conf.channelsOutStart);
+       audioData.inputDevice     = getAudioDeviceData_(DeviceType::INPUT,
+        m::conf::conf.soundDeviceIn, m::conf::conf.channelsInCount,
+        m::conf::conf.channelsInStart);
+
+       return audioData;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void save(const AudioData& data)
+{
+       m::conf::conf.soundSystem      = data.api;
+       m::conf::conf.soundDeviceOut   = data.outputDevice.index;
+       m::conf::conf.soundDeviceIn    = data.inputDevice.index;
+       m::conf::conf.channelsOutCount = data.outputDevice.channelsCount;
+       m::conf::conf.channelsOutStart = data.outputDevice.channelsStart;
+       m::conf::conf.channelsInCount  = data.inputDevice.channelsCount;
+       m::conf::conf.channelsInStart  = data.inputDevice.channelsStart;
+       m::conf::conf.limitOutput      = data.limitOutput;
+       m::conf::conf.rsmpQuality      = data.resampleQuality;
+       m::conf::conf.buffersize       = data.bufferSize;
+       m::conf::conf.recTriggerLevel  = data.recTriggerLevel;
+       m::conf::conf.samplerate       = data.sampleRate;
+}
+} // namespace giada::c::config
\ No newline at end of file
diff --git a/src/glue/config.h b/src/glue/config.h
new file mode 100644 (file)
index 0000000..fb39817
--- /dev/null
@@ -0,0 +1,95 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_GLUE_CONFIG_H
+#define G_GLUE_CONFIG_H
+
+#include "core/types.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace giada::m::kernelAudio
+{
+struct Device;
+}
+namespace giada::c::config
+{
+enum class DeviceType
+{
+       INPUT,
+       OUTPUT
+};
+
+struct AudioDeviceData
+{
+       AudioDeviceData() = default;
+       AudioDeviceData(DeviceType t, const m::kernelAudio::Device&, int channelsCount, int channelsStart);
+
+       DeviceType       type        = DeviceType::OUTPUT;
+       int              index       = -1;
+       std::string      name        = "";
+       int              channelsMax = 0;
+       std::vector<int> sampleRates = {};
+
+       /* Selectable values. */
+
+       int channelsCount = 0;
+       int channelsStart = 0;
+};
+
+struct AudioData
+{
+       void setOutputDevice(int index);
+       void setInputDevice(int index);
+
+       std::map<int, std::string>   apis;
+       std::vector<AudioDeviceData> outputDevices;
+       std::vector<AudioDeviceData> inputDevices;
+
+       /* Selectable values. */
+
+       int             api;
+       AudioDeviceData outputDevice;
+       AudioDeviceData inputDevice;
+       int             bufferSize;
+       int             sampleRate;
+       bool            limitOutput;
+       float           recTriggerLevel;
+       int             resampleQuality;
+};
+
+/* getAudioData
+Returns viewModel object filled with data. */
+
+AudioData getAudioData();
+/*
+AudioDeviceData getAudioDeviceData(size_t index, int channelsCount, int channelsStart);
+*/
+void save(const AudioData&);
+} // namespace giada::c::config
+
+#endif
index 48e1321e164f01368271b8caa9f0834c077062ec..a6bd9097461793350040e5aed15a317827c58a72 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
-#include "core/model/model.h"
-#include "core/const.h"
+#include "events.h"
 #include "core/clock.h"
-#include "core/mixer.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include "core/eventDispatcher.h"
 #include "core/midiEvent.h"
-#include "core/plugins/pluginHost.h"
-#include "core/sequencer.h"
+#include "core/mixer.h"
 #include "core/mixerHandler.h"
-#include "core/conf.h"
+#include "core/model/model.h"
+#include "core/plugins/pluginHost.h"
 #include "core/recManager.h"
-#include "utils/log.h"
-#include "gui/dialogs/sampleEditor.h"
+#include "core/sequencer.h"
+#include "core/types.h"
+#include "glue/main.h"
+#include "glue/plugin.h"
+#include "glue/sampleEditor.h"
 #include "gui/dialogs/mainWindow.h"
+#include "gui/dialogs/sampleEditor.h"
 #include "gui/dialogs/warnings.h"
-#include "gui/elems/mainWindow/mainIO.h"
-#include "gui/elems/mainWindow/mainTimer.h"
 #include "gui/elems/basics/dial.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
-#include "gui/elems/sampleEditor/volumeTool.h"
-#include "gui/elems/sampleEditor/pitchTool.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
+#include "gui/elems/mainWindow/mainIO.h"
+#include "gui/elems/mainWindow/mainTimer.h"
 #include "gui/elems/sampleEditor/panTool.h"
-#include "glue/sampleEditor.h"
-#include "glue/plugin.h"
-#include "glue/main.h"
-#include "events.h"
-
+#include "gui/elems/sampleEditor/pitchTool.h"
+#include "gui/elems/sampleEditor/volumeTool.h"
+#include "utils/log.h"
+#include <FL/Fl.H>
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace c {
-namespace events 
+namespace giada::c::events
 {
 namespace
 {
-void pushEvent_(m::mixer::Event e, Thread t)
+void pushEvent_(m::eventDispatcher::Event e, Thread t)
 {
        bool res = true;
        if (t == Thread::MAIN)
-               res = m::mixer::UIevents.push(e);
-       else
-       if (t == Thread::MIDI)
-               res = m::mixer::MidiEvents.push(e);
+               res = m::eventDispatcher::UIevents.push(e);
+       else if (t == Thread::MIDI)
+               res = m::eventDispatcher::MidiEvents.push(e);
        else
                assert(false);
-       
+
        if (!res)
                G_DEBUG("[events] Queue full!\n");
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void pressChannel(ID channelId, int velocity, Thread t)
 {
        m::MidiEvent e;
        e.setVelocity(velocity);
-       pushEvent_({ m::mixer::EventType::KEY_PRESS, 0, {0, channelId, 0, e} }, t);
+       pushEvent_({m::eventDispatcher::EventType::KEY_PRESS, 0, channelId, velocity}, t);
 }
 
-
 void releaseChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::KEY_RELEASE, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::KEY_RELEASE, 0, channelId, {}}, t);
 }
 
-
 void killChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::KEY_KILL, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::KEY_KILL, 0, channelId, {}}, t);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setChannelVolume(ID channelId, float v, Thread t)
 {
        v = std::clamp(v, 0.0f, G_MAX_VOLUME);
 
-       pushEvent_({ m::mixer::EventType::CHANNEL_VOLUME, 0, { 0, channelId, 0, {v} } }, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_VOLUME, 0, channelId, v}, t);
 
        sampleEditor::onRefresh(t == Thread::MAIN, [v](v::gdSampleEditor& e) { e.volumeTool->update(v); });
 
-       if (t != Thread::MAIN) {
+       if (t != Thread::MAIN)
+       {
                Fl::lock();
                G_MainWin->keyboard->getChannel(channelId)->vol->value(v);
                Fl::unlock();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void setChannelPitch(ID channelId, float v,  Thread t)
-{      
+void setChannelPitch(ID channelId, float v, Thread t)
+{
        v = std::clamp(v, G_MIN_PITCH, G_MAX_PITCH);
 
-       pushEvent_({ m::mixer::EventType::CHANNEL_PITCH, 0, { 0, channelId, 0, {v} } }, t);
-       
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_PITCH, 0, channelId, v}, t);
+
        sampleEditor::onRefresh(t == Thread::MAIN, [v](v::gdSampleEditor& e) { e.pitchTool->update(v); });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sendChannelPan(ID channelId, float v)
 {
        v = std::clamp(v, 0.0f, G_MAX_PAN);
 
        /* Pan event is currently triggered only by the main thread. */
-       pushEvent_({ m::mixer::EventType::CHANNEL_PAN, 0, { 0, channelId, 0, {v} } }, Thread::MAIN);
-       
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_PAN, 0, channelId, v}, Thread::MAIN);
+
        sampleEditor::onRefresh(/*gui=*/true, [v](v::gdSampleEditor& e) { e.panTool->update(v); });
 }
 
 /* -------------------------------------------------------------------------- */
 
-
 void toggleMuteChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_MUTE, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_MUTE, 0, channelId, {}}, t);
 }
 
-
 void toggleSoloChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_SOLO, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_SOLO, 0, channelId, {}}, t);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleArmChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_TOGGLE_ARM, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_TOGGLE_ARM, 0, channelId, {}}, t);
 }
 
-
 void toggleReadActionsChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_TOGGLE_READ_ACTIONS, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_TOGGLE_READ_ACTIONS, 0, channelId, {}}, t);
 }
 
-
 void killReadActionsChannel(ID channelId, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_KILL_READ_ACTIONS, 0, {0, channelId} }, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_KILL_READ_ACTIONS, 0, channelId, {}}, t);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void sendMidiToChannel(ID channelId, m::MidiEvent e, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::MIDI, 0, {0, channelId, 0, e} }, t);
+       pushEvent_({m::eventDispatcher::EventType::MIDI, 0, channelId, m::Action{0, channelId, 0, e}}, t);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleMetronome()
 {
        m::sequencer::toggleMetronome();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setMasterInVolume(float v, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_VOLUME, 0, { 0, m::mixer::MASTER_IN_CHANNEL_ID, 0, {v} }}, t);
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_VOLUME, 0, m::mixer::MASTER_IN_CHANNEL_ID, v}, t);
 
-       if (t != Thread::MAIN) {
+       if (t != Thread::MAIN)
+       {
                Fl::lock();
                G_MainWin->mainIO->setInVol(v);
                Fl::unlock();
        }
 }
 
-
 void setMasterOutVolume(float v, Thread t)
 {
-       pushEvent_({ m::mixer::EventType::CHANNEL_VOLUME, 0, { 0, m::mixer::MASTER_OUT_CHANNEL_ID, 0, {v} }}, t);
-       
-       if (t != Thread::MAIN) {
+       pushEvent_({m::eventDispatcher::EventType::CHANNEL_VOLUME, 0, m::mixer::MASTER_OUT_CHANNEL_ID, v}, t);
+
+       if (t != Thread::MAIN)
+       {
                Fl::lock();
                G_MainWin->mainIO->setOutVol(v);
                Fl::unlock();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void multiplyBeats()
 {
        main::setBeats(m::clock::getBeats() * 2, m::clock::getBars());
 }
 
-
 void divideBeats()
 {
        main::setBeats(m::clock::getBeats() / 2, m::clock::getBars());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void startSequencer(Thread t)
-{ 
-       pushEvent_({ m::mixer::EventType::SEQUENCER_START, 0 }, t);
+{
+       pushEvent_({m::eventDispatcher::EventType::SEQUENCER_START, 0, 0, {}}, t);
        m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
 }
 
-
 void stopSequencer(Thread t)
-{ 
-       pushEvent_({ m::mixer::EventType::SEQUENCER_STOP, 0 }, t);
+{
+       pushEvent_({m::eventDispatcher::EventType::SEQUENCER_STOP, 0, 0, {}}, t);
 }
 
-
 void toggleSequencer(Thread t)
-{ 
+{
        m::clock::isRunning() ? stopSequencer(t) : startSequencer(t);
 }
 
-
 void rewindSequencer(Thread t)
-{ 
-       pushEvent_({ m::mixer::EventType::SEQUENCER_REWIND_REQ, 0 }, t);
+{
+       pushEvent_({m::eventDispatcher::EventType::SEQUENCER_REWIND, 0, 0, {}}, t);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleActionRecording()
 {
        m::recManager::toggleActionRec(m::conf::conf.recTriggerMode);
 }
 
-
 void toggleInputRecording()
 {
-       m::recManager::toggleInputRec(m::conf::conf.recTriggerMode);
+       m::recManager::toggleInputRec(m::conf::conf.recTriggerMode, m::conf::conf.inputRecMode);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 void setPluginParameter(ID pluginId, int paramIndex, float value, bool gui)
 {
@@ -300,4 +263,4 @@ void setPluginParameter(ID pluginId, int paramIndex, float value, bool gui)
        c::plugin::updateWindow(pluginId, gui);
 }
 #endif
-}}} // giada::c::events::
+} // namespace giada::c::events
index 7c8ab7b4f5a898369935dd906e1d7c8f9effc672..64a3f5b83d8b414c9014e6b617506ea93a2657a4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_EVENTS_H
 #define G_GLUE_EVENTS_H
 
-
 #include "core/types.h"
 
-
 /* giada::c::events
 Functions that take care of live event dispatching. Every live gesture that 
 comes from the UI, MIDI thread or keyboard interaction and wants to change the
 internal engine state must call these functions. */
 
-namespace giada {
-namespace m
+namespace giada::m
 {
 class MidiEvent;
 }
-namespace c {
-namespace events
+namespace giada::c::events
 {
 /* Channel*
 Channel-related events. */
 
-void pressChannel            (ID channelId, int velocity, Thread t);
-void releaseChannel          (ID channelId, Thread t);
-void killChannel             (ID channelId, Thread t);
-void setChannelVolume        (ID channelId, float v, Thread t);
-void setChannelPitch         (ID channelId, float v, Thread t);
-void sendChannelPan          (ID channelId, float v); // FIXME typo: should be setChannelPan
-void toggleMuteChannel       (ID channelId, Thread t);
-void toggleSoloChannel       (ID channelId, Thread t);
-void toggleArmChannel        (ID channelId, Thread t);
+void pressChannel(ID channelId, int velocity, Thread t);
+void releaseChannel(ID channelId, Thread t);
+void killChannel(ID channelId, Thread t);
+void setChannelVolume(ID channelId, float v, Thread t);
+void setChannelPitch(ID channelId, float v, Thread t);
+void sendChannelPan(ID channelId, float v); // FIXME typo: should be setChannelPan
+void toggleMuteChannel(ID channelId, Thread t);
+void toggleSoloChannel(ID channelId, Thread t);
+void toggleArmChannel(ID channelId, Thread t);
 void toggleReadActionsChannel(ID channelId, Thread t);
-void killReadActionsChannel  (ID channelId, Thread t);
-void sendMidiToChannel       (ID channelId, m::MidiEvent e, Thread t);
+void killReadActionsChannel(ID channelId, Thread t);
+void sendMidiToChannel(ID channelId, m::MidiEvent e, Thread t);
 
 /* Main*
 Master I/O, transport and other engine-related events. */
 
-void toggleMetronome      ();
-void setMasterInVolume    (float v, Thread t);
-void setMasterOutVolume   (float v, Thread t);
-void multiplyBeats        ();
-void divideBeats          ();
-void startSequencer       (Thread t);
-void stopSequencer        (Thread t);
-void toggleSequencer      (Thread t);
-void rewindSequencer      (Thread t);
+void toggleMetronome();
+void setMasterInVolume(float v, Thread t);
+void setMasterOutVolume(float v, Thread t);
+void multiplyBeats();
+void divideBeats();
+void startSequencer(Thread t);
+void stopSequencer(Thread t);
+void toggleSequencer(Thread t);
+void rewindSequencer(Thread t);
 void toggleActionRecording();
-void toggleInputRecording ();
+void toggleInputRecording();
 
 /* Plug-ins. */
 
 #ifdef WITH_VST
-void setPluginParameter(ID pluginId, int paramIndex, float value, bool gui); 
+void setPluginParameter(ID pluginId, int paramIndex, float value, bool gui);
 #endif
-}}} // giada::c::events::
-
+} // namespace giada::c::events
 
 #endif
index 518ca3f2f62a6eb72acac46e98536d5e4e5d41f5..aad617f489399cfa3b9adb274d7006848aac3510 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
+#include "io.h"
+#include "channel.h"
+#include "core/clock.h"
+#include "core/conf.h"
+#include "core/kernelAudio.h"
+#include "core/midiDispatcher.h"
+#include "core/mixer.h"
+#include "core/mixerHandler.h"
+#include "core/model/model.h"
+#include "core/recManager.h"
+#include "core/recorder.h"
+#include "core/recorderHandler.h"
+#include "core/wave.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/midiIO/midiInputBase.h"
 #include "gui/dialogs/warnings.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/mainWindow/mainTransport.h"
-#include "gui/elems/mainWindow/mainTimer.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/mainWindow/keyboard/channelButton.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/keyboard/sampleChannel.h"
+#include "gui/elems/mainWindow/mainTimer.h"
+#include "gui/elems/mainWindow/mainTransport.h"
+#include "main.h"
 #include "utils/gui.h"
 #include "utils/log.h"
 #include "utils/math.h"
-#include "core/model/model.h"
-#include "core/recorder.h"
-#include "core/conf.h"
-#include "core/recManager.h"
-#include "core/kernelAudio.h"
-#include "core/mixer.h"
-#include "core/mixerHandler.h"
-#include "core/wave.h"
-#include "core/midiDispatcher.h"
-#include "core/clock.h"
-#include "core/recorderHandler.h"
-#include "main.h"
-#include "channel.h"
-#include "io.h"
-
+#include <FL/Fl.H>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace c {
-namespace io 
+namespace giada::c::io
 {
 namespace
 {
@@ -69,230 +64,171 @@ void rebuildMidiWindows_()
        u::gui::rebuildSubWindow(WID_MIDI_INPUT);
        u::gui::rebuildSubWindow(WID_MIDI_OUTPUT);
 }
-} // {anonymous}
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-Channel_InputData::Channel_InputData(const m::Channel& c)
-: channelId    (c.id)
-, channelType  (c.getType())
-, enabled      (c.midiLearner.state->enabled.load())
-, velocityAsVol(c.samplePlayer ? c.samplePlayer->state->velocityAsVol.load() : 0)
-, filter       (c.midiLearner.state->filter.load())
-, keyPress     (c.midiLearner.state->keyPress.getValue())
-, keyRelease   (c.midiLearner.state->keyRelease.getValue())
-, kill         (c.midiLearner.state->kill.getValue())
-, arm          (c.midiLearner.state->arm.getValue())
-, volume       (c.midiLearner.state->volume.getValue())
-, mute         (c.midiLearner.state->mute.getValue())
-, solo         (c.midiLearner.state->solo.getValue())
-, pitch        (c.midiLearner.state->pitch.getValue())
-, readActions  (c.midiLearner.state->readActions.getValue()) 
+Channel_InputData::Channel_InputData(const m::channel::Data& c)
+: channelId(c.id)
+, channelType(c.type)
+, enabled(c.midiLearner.enabled)
+, velocityAsVol(c.samplePlayer ? c.samplePlayer->velocityAsVol : 0)
+, filter(c.midiLearner.filter)
+, keyPress(c.midiLearner.keyPress.getValue())
+, keyRelease(c.midiLearner.keyRelease.getValue())
+, kill(c.midiLearner.kill.getValue())
+, arm(c.midiLearner.arm.getValue())
+, volume(c.midiLearner.volume.getValue())
+, mute(c.midiLearner.mute.getValue())
+, solo(c.midiLearner.solo.getValue())
+, pitch(c.midiLearner.pitch.getValue())
+, readActions(c.midiLearner.readActions.getValue())
 {
 #ifdef WITH_VST
-       for (ID id : c.pluginIds) {
-               m::Plugin& p = m::model::get(m::model::plugins, id);
-               
+       for (const m::Plugin* p : c.plugins)
+       {
                PluginData pd;
-               pd.id = p.id;
-               pd.name = p.getName();
-               for (int i = 0; i < p.getNumParameters(); i++)
-                       pd.params.push_back({ i, p.getParameterName(i), p.midiInParams.at(i).getValue() });
-
+               pd.id   = p->id;
+               pd.name = p->getName();
+               for (int i = 0; i < p->getNumParameters(); i++)
+                       pd.params.push_back({i, p->getParameterName(i), p->midiInParams.at(i).getValue()});
                plugins.push_back(pd);
        }
 #endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-MidiChannel_OutputData::MidiChannel_OutputData(const m::MidiSender& s)
-: enabled(s.state->enabled.load())
-, filter (s.state->filter.load())
+MidiChannel_OutputData::MidiChannel_OutputData(const m::midiSender::Data& s)
+: enabled(s.enabled)
+, filter(s.filter)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-Channel_OutputData::Channel_OutputData(const m::Channel& c)
-: channelId       (c.id)
-, lightningEnabled(c.midiLighter.state->enabled.load())
-, lightningPlaying(c.midiLighter.state->playing.getValue())
-, lightningMute   (c.midiLighter.state->mute.getValue())
-, lightningSolo   (c.midiLighter.state->solo.getValue())
-{      
-       if (c.getType() == ChannelType::MIDI)
+Channel_OutputData::Channel_OutputData(const m::channel::Data& c)
+: channelId(c.id)
+, lightningEnabled(c.midiLighter.enabled)
+, lightningPlaying(c.midiLighter.playing.getValue())
+, lightningMute(c.midiLighter.mute.getValue())
+, lightningSolo(c.midiLighter.solo.getValue())
+{
+       if (c.type == ChannelType::MIDI)
                output = std::make_optional<MidiChannel_OutputData>(*c.midiSender);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Master_InputData::Master_InputData(const m::model::MidiIn& midiIn)
-: enabled   (midiIn.enabled)
-, filter    (midiIn.filter)
-, rewind    (midiIn.rewind)
-, startStop (midiIn.startStop)
-, actionRec (midiIn.actionRec)
-, inputRec  (midiIn.inputRec)
-, volumeIn  (midiIn.volumeIn)
-, volumeOut (midiIn.volumeOut)
+: enabled(midiIn.enabled)
+, filter(midiIn.filter)
+, rewind(midiIn.rewind)
+, startStop(midiIn.startStop)
+, actionRec(midiIn.actionRec)
+, inputRec(midiIn.inputRec)
+, volumeIn(midiIn.volumeIn)
+, volumeOut(midiIn.volumeOut)
 , beatDouble(midiIn.beatDouble)
-, beatHalf  (midiIn.beatHalf)
-, metronome (midiIn.metronome) 
+, beatHalf(midiIn.beatHalf)
+, metronome(midiIn.metronome)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Channel_InputData channel_getInputData(ID channelId)
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock cl(mm::channels);
-#ifdef WITH_VST
-       mm::PluginsLock  ml(mm::plugins);
-#endif
-
-       return Channel_InputData(mm::get(mm::channels, channelId));     
+       return Channel_InputData(m::model::get().getChannel(channelId));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Channel_OutputData channel_getOutputData(ID channelId)
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock cl(mm::channels);
-       return Channel_OutputData(mm::get(mm::channels, channelId));            
+       return Channel_OutputData(m::model::get().getChannel(channelId));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Master_InputData master_getInputData()
 {
-       namespace mm = m::model;
-
-       mm::MidiInLock l(mm::midiIn);
-       return Master_InputData(*mm::midiIn.get());
+       return Master_InputData(m::model::get().midiIn);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_enableMidiLearn(ID channelId, bool v)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.midiLearner.state->enabled.store(v);
-       });
+       m::model::get().getChannel(channelId).midiLearner.enabled = v;
+       m::model::swap(m::model::SwapType::NONE);
        rebuildMidiWindows_();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_enableMidiLightning(ID channelId, bool v)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.midiLighter.state->enabled.store(v);
-       });
+       m::model::get().getChannel(channelId).midiLighter.enabled = v;
+       m::model::swap(m::model::SwapType::NONE);
        rebuildMidiWindows_();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_enableMidiOutput(ID channelId, bool v)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.midiSender->state->enabled.store(v);
-       });     
+       m::model::get().getChannel(channelId).midiSender->enabled = v;
+       m::model::swap(m::model::SwapType::NONE);
        rebuildMidiWindows_();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_enableVelocityAsVol(ID channelId, bool v)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.samplePlayer->state->velocityAsVol.store(v);
-       });
+       m::model::get().getChannel(channelId).samplePlayer->velocityAsVol = v;
+       m::model::swap(m::model::SwapType::NONE);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_setMidiInputFilter(ID channelId, int ch)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.midiLearner.state->filter.store(ch);
-       });
+       m::model::get().getChannel(channelId).midiLearner.filter = ch;
+       m::model::swap(m::model::SwapType::NONE);
 }
 
-
 void channel_setMidiOutputFilter(ID channelId, int ch)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.midiSender->state->filter.store(ch);
-       });     
+       m::model::get().getChannel(channelId).midiSender->filter = ch;
+       m::model::swap(m::model::SwapType::NONE);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_setKey(ID channelId, int k)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.state->key.store(k);
-       }, /*rebuild=*/true);
+       m::model::get().getChannel(channelId).key = k;
+       m::model::swap(m::model::SwapType::HARD);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_startMidiLearn(int param, ID channelId)
 {
        m::midiDispatcher::startChannelLearn(param, channelId, rebuildMidiWindows_);
 }
 
-
 void master_startMidiLearn(int param)
 {
        m::midiDispatcher::startMasterLearn(param, rebuildMidiWindows_);
 }
 
-
 #ifdef WITH_VST
 
 void plugin_startMidiLearn(int paramIndex, ID pluginId)
@@ -302,63 +238,49 @@ void plugin_startMidiLearn(int paramIndex, ID pluginId)
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void stopMidiLearn()
 {
        m::midiDispatcher::stopLearn();
        rebuildMidiWindows_();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void channel_clearMidiLearn(int param, ID channelId)
 {
        m::midiDispatcher::clearChannelLearn(param, channelId, rebuildMidiWindows_);
 }
 
-
-void master_clearMidiLearn (int param)
+void master_clearMidiLearn(int param)
 {
        m::midiDispatcher::clearMasterLearn(param, rebuildMidiWindows_);
 }
 
-
 #ifdef WITH_VST
 
-void plugin_clearMidiLearn (int param, ID pluginId)
+void plugin_clearMidiLearn(int param, ID pluginId)
 {
        m::midiDispatcher::clearPluginLearn(param, pluginId, rebuildMidiWindows_);
 }
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void master_enableMidiLearn(bool v)
 {
-       m::model::onSwap(m::model::midiIn, [&](m::model::MidiIn& m)
-       {
-               m.enabled = v;
-       });     
+       m::model::get().midiIn.enabled = v;
+       m::model::swap(m::model::SwapType::NONE);
        rebuildMidiWindows_();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void master_setMidiFilter(int c)
 {
-       m::model::onSwap(m::model::midiIn, [&](m::model::MidiIn& m)
-       {
-               m.filter = c;
-       });
+       m::model::get().midiIn.filter = c;
+       m::model::swap(m::model::SwapType::NONE);
 }
-}}} // giada::c::io::
+} // namespace giada::c::io
index 46cbd8903d441f81bcb2ef55eedd418eda229183..69f24f9f5082de9cc0ee14612951d03fc9fe7ca8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_IO_H
 #define G_GLUE_IO_H
 
-
-#include <atomic>
-#include "core/types.h"
 #include "core/midiEvent.h"
 #include "core/model/model.h"
+#include "core/types.h"
 
-
-namespace giada {
-namespace m
+namespace giada::m::channel
 {
-class Channel;
+struct Data;
 }
-namespace c {
-namespace io 
+namespace giada::c::io
 {
 struct PluginParamData
 {
-    int         index;
-    std::string name;
-    uint32_t    value;
+       int         index;
+       std::string name;
+       uint32_t    value;
 };
 
 struct PluginData
 {
-    ID          id;
-    std::string name;
-    std::vector<PluginParamData> params;
+       ID                           id;
+       std::string                  name;
+       std::vector<PluginParamData> params;
 };
 
 struct Channel_InputData
 {
-    Channel_InputData() = default;
-    Channel_InputData(const m::Channel&);
-
-    ID          channelId;
-    ChannelType channelType;
-    bool        enabled;
-    bool        velocityAsVol;
-    int         filter;
-
-    uint32_t    keyPress;
-    uint32_t    keyRelease;
-    uint32_t    kill;
-    uint32_t    arm;
-    uint32_t    volume;
-    uint32_t    mute;
-    uint32_t    solo;
-    uint32_t    pitch;
-    uint32_t    readActions;   
-
-    std::vector<PluginData> plugins;
+       Channel_InputData() = default;
+       Channel_InputData(const m::channel::Data&);
+
+       ID          channelId;
+       ChannelType channelType;
+       bool        enabled;
+       bool        velocityAsVol;
+       int         filter;
+
+       uint32_t keyPress;
+       uint32_t keyRelease;
+       uint32_t kill;
+       uint32_t arm;
+       uint32_t volume;
+       uint32_t mute;
+       uint32_t solo;
+       uint32_t pitch;
+       uint32_t readActions;
+
+       std::vector<PluginData> plugins;
 };
 
 struct Master_InputData
 {
-    Master_InputData() = default;
-    Master_InputData(const m::model::MidiIn&);
+       Master_InputData() = default;
+       Master_InputData(const m::model::MidiIn&);
 
-    bool     enabled;
-    int      filter;
+       bool enabled;
+       int  filter;
 
        uint32_t rewind;
        uint32_t startStop;
@@ -97,29 +91,29 @@ struct Master_InputData
        uint32_t volumeOut;
        uint32_t beatDouble;
        uint32_t beatHalf;
-       uint32_t metronome;     
+       uint32_t metronome;
 };
 
 struct MidiChannel_OutputData
 {
-    MidiChannel_OutputData(const m::MidiSender&);
+       MidiChannel_OutputData(const m::midiSender::Data&);
 
-    bool enabled;
-    int  filter;
+       bool enabled;
+       int  filter;
 };
 
 struct Channel_OutputData
 {
-    Channel_OutputData() = default;
-    Channel_OutputData(const m::Channel&);
+       Channel_OutputData() = default;
+       Channel_OutputData(const m::channel::Data&);
 
-    ID       channelId;
-    bool     lightningEnabled;
-    uint32_t lightningPlaying;
-    uint32_t lightningMute;
-    uint32_t lightningSolo;
+       ID       channelId;
+       bool     lightningEnabled;
+       uint32_t lightningPlaying;
+       uint32_t lightningMute;
+       uint32_t lightningSolo;
 
-    std::optional<MidiChannel_OutputData> output;
+       std::optional<MidiChannel_OutputData> output;
 };
 
 Channel_InputData  channel_getInputData(ID channelId);
@@ -144,18 +138,18 @@ void channel_setKey(ID channelId, int k);
 
 void channel_startMidiLearn(int param, ID channelId);
 void channel_clearMidiLearn(int param, ID channelId);
-void master_clearMidiLearn (int param);
-void master_startMidiLearn (int param);
+void master_clearMidiLearn(int param);
+void master_startMidiLearn(int param);
 void stopMidiLearn();
 #ifdef WITH_VST
-void plugin_startMidiLearn (int paramIndex, ID pluginId);
-void plugin_clearMidiLearn (int param, ID pluginId);
+void plugin_startMidiLearn(int paramIndex, ID pluginId);
+void plugin_clearMidiLearn(int param, ID pluginId);
 #endif
 
 /* Master functions. */
 
 void master_enableMidiLearn(bool v);
 void master_setMidiFilter(int c);
-}}} // giada::c::io::
+} // namespace giada::c::io
 
 #endif
index 8fbf735283578c612240c0536852890909fc4ecb..761e94c0784154b98b9dabd30e6e195ce79400c8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
-#include <cassert>
-#include <FL/Fl.H>
-#include "gui/dialogs/warnings.h"
-#include "gui/elems/mainWindow/mainIO.h"
-#include "gui/elems/mainWindow/mainTimer.h"
-#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/dialogs/mainWindow.h"
-#include "utils/gui.h"
-#include "utils/string.h"
-#include "utils/log.h"
-#include "core/model/model.h"
-#include "core/mixerHandler.h"
-#include "core/mixer.h"
+#include "main.h"
 #include "core/clock.h"
+#include "core/conf.h"
+#include "core/const.h"
 #include "core/init.h"
-#include "core/kernelMidi.h"
 #include "core/kernelAudio.h"
+#include "core/kernelMidi.h"
+#include "core/mixer.h"
+#include "core/mixerHandler.h"
+#include "core/model/model.h"
+#include "core/plugins/pluginHost.h"
+#include "core/plugins/pluginManager.h"
+#include "core/recManager.h"
 #include "core/recorder.h"
 #include "core/recorderHandler.h"
-#include "core/recManager.h"
-#include "core/conf.h"
-#include "core/const.h"
-#include "core/plugins/pluginManager.h"
-#include "core/plugins/pluginHost.h"
-#include "main.h"
-
-
-extern giada::v::gdMainWindow *G_MainWin;
+#include "gui/dialogs/mainWindow.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
+#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
+#include "gui/elems/mainWindow/mainIO.h"
+#include "gui/elems/mainWindow/mainTimer.h"
+#include "utils/gui.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
+#include <cassert>
+#include <cmath>
 
+extern giada::v::gdMainWindow* G_MainWin;
 
-namespace giada {
-namespace c {
-namespace main
+namespace giada::c::main
 {
-namespace
-{
-void setBpm_(float current, std::string s)
-{
-       if (current < G_MIN_BPM) {
-               current = G_MIN_BPM;
-               s = G_MIN_BPM_STR;
-       }
-       else
-       if (current > G_MAX_BPM) {
-               current = G_MAX_BPM;
-               s = G_MAX_BPM_STR;              
-       }
-
-       float previous = m::clock::getBpm();
-       m::clock::setBpm(current);
-       m::recorderHandler::updateBpm(previous, current, m::clock::getQuantizerStep());
-       m::mixer::allocRecBuffer(m::clock::getFramesInLoop());
-
-       /* This function might get called by Jack callback BEFORE the UI is up
-       and running, that is when G_MainWin == nullptr. */
-       
-       if (G_MainWin != nullptr) {
-               u::gui::refreshActionEditor();
-               G_MainWin->mainTimer->setBpm(s.c_str());
-       }
-
-       u::log::print("[glue::setBpm_] Bpm changed to %s (real=%f)\n", s, m::clock::getBpm());
-}
-} // {anonymous}
-
-
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-/* -------------------------------------------------------------------------- */
-
-
 Timer::Timer(const m::model::Clock& c)
-: bpm             (c.bpm)
-, beats           (c.beats)
-, bars            (c.bars)
-, quantize        (c.quantize)
-, isUsingJack     (m::kernelAudio::getAPI() == G_SYS_API_JACK)
+: bpm(c.bpm)
+, beats(c.beats)
+, bars(c.bars)
+, quantize(c.quantize)
+, isUsingJack(m::kernelAudio::getAPI() == G_SYS_API_JACK)
 , isRecordingInput(m::recManager::isRecordingInput())
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-IO::IO(const m::Channel& out, const m::Channel& in, const m::model::Mixer& m)
-: masterOutVol       (out.state->volume.load())
-, masterInVol        (in.state->volume.load())
+IO::IO(const m::channel::Data& out, const m::channel::Data& in, const m::model::Mixer& m)
+: masterOutVol(out.volume)
+, masterInVol(in.volume)
 #ifdef WITH_VST
-, masterOutHasPlugins(out.pluginIds.size() > 0)
-, masterInHasPlugins (in.pluginIds.size() > 0)
+, masterOutHasPlugins(out.plugins.size() > 0)
+, masterInHasPlugins(in.plugins.size() > 0)
 #endif
-, inToOut            (m.inToOut)
+, inToOut(m.inToOut)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-float IO::a_getMasterOutPeak()
+float IO::getMasterOutPeak()
 {
-       return m::mixer::peakOut.load();
+       return m::mixer::getPeakOut();
 }
 
-
-float IO::a_getMasterInPeak()
+float IO::getMasterInPeak()
 {
-       return m::mixer::peakIn.load();
+       return m::mixer::getPeakIn();
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Timer getTimer()
 {
-       namespace mm = m::model;
-       
-       mm::ClockLock c(mm::clock);
-       return Timer(*mm::clock.get());
+       return Timer(m::model::get().clock);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 IO getIO()
 {
-       namespace mm = m::model;
+       return IO(m::model::get().getChannel(m::mixer::MASTER_OUT_CHANNEL_ID),
+           m::model::get().getChannel(m::mixer::MASTER_IN_CHANNEL_ID),
+           m::model::get().mixer);
+}
 
-       mm::ChannelsLock cl(mm::channels);
-       mm::MixerLock    ml(mm::mixer);
+/* -------------------------------------------------------------------------- */
 
-       return IO(mm::get(mm::channels, m::mixer::MASTER_OUT_CHANNEL_ID), 
-                 mm::get(mm::channels, m::mixer::MASTER_IN_CHANNEL_ID),
-                         *mm::mixer.get());
-}
+Sequencer getSequencer()
+{
+       Sequencer out;
 
+       m::mixer::RecordInfo recInfo = m::mixer::getRecordInfo();
 
-/* -------------------------------------------------------------------------- */
+       out.isFreeModeInputRec = m::recManager::isRecordingInput() && m::conf::conf.inputRecMode == InputRecMode::FREE;
+       out.shouldBlink        = u::gui::shouldBlink() && (m::clock::getStatus() == ClockStatus::WAITING || out.isFreeModeInputRec);
+       out.beats              = m::clock::getBeats();
+       out.bars               = m::clock::getBars();
+       out.currentBeat        = m::clock::getCurrentBeat();
+       out.recPosition        = recInfo.position;
+       out.recMaxLength       = recInfo.maxLength;
+
+       return out;
+}
 
+/* -------------------------------------------------------------------------- */
 
-void setBpm(const char* v1, const char* v2)
+void setBpm(const char* i, const char* f)
 {
        /* Never change this stuff while recording audio. */
 
        if (m::recManager::isRecordingInput())
                return;
 
-       /* A value such as atof("120.1") will never be 120.1 but 120.0999999, because 
-       of the rounding error. So we pass the actual "wrong" value to mixer and we show 
-       the nice looking (but fake) one to the GUI. 
-       On Linux, let Jack handle the bpm change if it's on. */
-
-       float       f = static_cast<float>(std::atof(v1) + (std::atof(v2)/10));
-       std::string s = std::string(v1) + "." + std::string(v2);
-
-#ifdef WITH_AUDIO_JACK
-       if (m::kernelAudio::getAPI() == G_SYS_API_JACK)
-               m::kernelAudio::jackSetBpm(f);
-       else
-#endif
-       setBpm_(f, s);
+       m::clock::setBpm(std::atof(i) + (std::atof(f) / 10.0f));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setBpm(float f)
 {
        /* Never change this stuff while recording audio. */
@@ -208,17 +151,11 @@ void setBpm(float f)
        if (m::recManager::isRecordingInput())
                return;
 
-       float intpart;
-       float fracpart = std::round(std::modf(f, &intpart) * 10);
-       std::string s = std::to_string((int) intpart) + "." + std::to_string((int)fracpart);
-
-       setBpm_(f, s);
+       m::clock::setBpm(f);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setBeats(int beats, int bars)
 {
        /* Never change this stuff while recording audio. */
@@ -227,25 +164,18 @@ void setBeats(int beats, int bars)
                return;
 
        m::clock::setBeats(beats, bars);
-       m::mixer::allocRecBuffer(m::clock::getFramesInLoop());
-
-       G_MainWin->mainTimer->setMeter(m::clock::getBeats(), m::clock::getBars());
-       u::gui::refreshActionEditor();  // in case the action editor is open
+       m::mixer::allocRecBuffer(m::clock::getMaxFramesInLoop());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void quantize(int val)
 {
        m::clock::setQuantize(val);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearAllSamples()
 {
        if (!v::gdConfirmWin("Warning", "Free all Sample channels: are you sure?"))
@@ -256,10 +186,8 @@ void clearAllSamples()
        m::recorderHandler::clearAllActions();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearAllActions()
 {
        if (!v::gdConfirmWin("Warning", "Clear all actions: are you sure?"))
@@ -268,32 +196,38 @@ void clearAllActions()
        m::recorderHandler::clearAllActions();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setInToOut(bool v)
 {
        m::mh::setInToOut(v);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleRecOnSignal()
 {
-       /* Can't set RecTriggerMode::SIGNAL while sequencer is running, in order
-       to prevent mistakes while live recording. */
-               
-       if (m::conf::conf.recTriggerMode == RecTriggerMode::NORMAL && m::clock::isRunning())
+       if (!m::recManager::canEnableRecOnSignal())
+       {
+               m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
                return;
+       }
        m::conf::conf.recTriggerMode = m::conf::conf.recTriggerMode == RecTriggerMode::NORMAL ? RecTriggerMode::SIGNAL : RecTriggerMode::NORMAL;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+void toggleFreeInputRec()
+{
+       if (!m::recManager::canEnableFreeInputRec())
+       {
+               m::conf::conf.inputRecMode = InputRecMode::RIGID;
+               return;
+       }
+       m::conf::conf.inputRecMode = m::conf::conf.inputRecMode == InputRecMode::FREE ? InputRecMode::RIGID : InputRecMode::FREE;
+}
+
+/* -------------------------------------------------------------------------- */
 
 void closeProject()
 {
@@ -302,4 +236,4 @@ void closeProject()
        m::init::reset();
        m::mixer::enable();
 }
-}}} // giada::c::main::
+} // namespace giada::c::main
index 98a72c3fb9b8a21cc273aa76d26febfafc5578f3..098fbfc7db3fb4ee24489e79878fa758cf9eb976 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_MAIN_H
 #define G_MAIN_H
 
-
 #include "core/types.h"
 
-
-namespace giada {
-namespace m 
+namespace giada::m::channel
 {
-class Channel;
-namespace model
-{ 
+struct Data;
+}
+namespace giada::m::model
+{
+struct Clock;
 struct Clock;
 struct Mixer;
-}}
-namespace c {
-namespace main
+struct Mixer;
+} // namespace giada::m::model
+namespace giada::c::main
 {
 struct Timer
 {
-    Timer() = default;
-    Timer(const m::model::Clock& c);
-
-    float bpm;
-    int   beats;
-    int   bars;
-    int   quantize;
-    bool  isUsingJack;
-    bool  isRecordingInput;
+       Timer() = default;
+       Timer(const m::model::Clock& c);
+
+       float bpm;
+       int   beats;
+       int   bars;
+       int   quantize;
+       bool  isUsingJack;
+       bool  isRecordingInput;
 };
 
 struct IO
 {
-    IO() = default;
-    IO(const m::Channel& out, const m::Channel& in, const m::model::Mixer& m);
+       IO() = default;
+       IO(const m::channel::Data& out, const m::channel::Data& in, const m::model::Mixer& m);
 
-    float masterOutVol;
-    float masterInVol;
+       float masterOutVol;
+       float masterInVol;
 #ifdef WITH_VST
-    bool  masterOutHasPlugins;
-    bool  masterInHasPlugins;
+       bool masterOutHasPlugins;
+       bool masterInHasPlugins;
 #endif
-    bool  inToOut;
+       bool inToOut;
+
+       float getMasterOutPeak();
+       float getMasterInPeak();
+};
 
-    float a_getMasterOutPeak();
-    float a_getMasterInPeak();
+struct Sequencer
+{
+       bool  isFreeModeInputRec;
+       bool  shouldBlink;
+       int   beats;
+       int   bars;
+       int   currentBeat;
+       Frame recPosition;
+       Frame recMaxLength;
 };
 
 /* get*
 Returns viewModel objects filled with data. */
 
-Timer getTimer();
-IO getIO();
+Timer     getTimer();
+IO        getIO();
+Sequencer getSequencer();
 
 /* setBpm (1)
 Sets bpm value from string to float. */
@@ -101,11 +111,12 @@ Enables the "hear what you playing" feature. */
 void setInToOut(bool v);
 
 void toggleRecOnSignal();
+void toggleFreeInputRec();
 
 /* closeProject
 Resets Giada to init state. If resetGui also refresh all widgets. */
 
 void closeProject();
-}}} // giada::c::main::
+} // namespace giada::c::main
 
 #endif
index 5c8860957430e6d3aad1f0daed4bc377cda6f509..7cc9934c73a053a2024993c6f023793c6a92912c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <cassert>
-#include <FL/Fl.H>
-#include "core/model/model.h"
-#include "core/plugins/pluginManager.h"
-#include "core/plugins/pluginHost.h"
-#include "core/mixer.h"
 #include "core/plugins/plugin.h"
-#include "core/const.h"
 #include "core/conf.h"
-#include "utils/gui.h"
+#include "core/const.h"
+#include "core/mixer.h"
+#include "core/model/model.h"
+#include "core/plugins/pluginHost.h"
+#include "core/plugins/pluginManager.h"
+#include "gui/dialogs/browser/browserDir.h"
+#include "gui/dialogs/config.h"
 #include "gui/dialogs/mainWindow.h"
-#include "gui/dialogs/pluginWindow.h"
 #include "gui/dialogs/pluginList.h"
+#include "gui/dialogs/pluginWindow.h"
 #include "gui/dialogs/warnings.h"
-#include "gui/dialogs/config.h"
-#include "gui/dialogs/browser/browserDir.h"
 #include "plugin.h"
-
+#include "utils/gui.h"
+#include <FL/Fl.H>
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace c {
-namespace plugin 
+namespace giada::c::plugin
 {
-Param::Param(const m::Plugin& p, int index)
-: index   (index)
+Param::Param(const m::Plugin& p, int index, ID channelId)
+: index(index)
 , pluginId(p.id)
-, name    (p.getParameterName(index))
-, text    (p.getParameterText(index))
-, label   (p.getParameterLabel(index))
-, value   (p.getParameter(index))
+, channelId(channelId)
+, name(p.getParameterName(index))
+, text(p.getParameterText(index))
+, label(p.getParameterLabel(index))
+, value(p.getParameter(index))
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Plugin::Plugin(m::Plugin& p, ID channelId)
-: id            (p.id)
-, channelId     (channelId)
-, valid         (p.valid)
-, hasEditor     (p.hasEditor())
-, isBypassed    (p.isBypassed())
-, name          (p.getName())
-, uniqueId      (p.getUniqueId())
+: id(p.id)
+, channelId(channelId)
+, valid(p.valid)
+, hasEditor(p.hasEditor())
+, isBypassed(p.isBypassed())
+, name(p.getName())
+, uniqueId(p.getUniqueId())
 , currentProgram(p.getCurrentProgram())
-, m_plugin      (p)
+, m_plugin(p)
 {
        for (int i = 0; i < p.getNumPrograms(); i++)
-               programs.push_back({ i, p.getProgramName(i) });
+               programs.push_back({i, p.getProgramName(i)});
        for (int i = 0; i < p.getNumParameters(); i++)
                paramIndexes.push_back(i);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 juce::AudioProcessorEditor* Plugin::createEditor() const
 {
-       m::model::PluginsLock l(m::model::plugins);
        return m_plugin.createEditor();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+const m::Plugin& Plugin::getPluginRef() const { return m_plugin; }
+
+/* -------------------------------------------------------------------------- */
 
 void Plugin::setResizeCallback(std::function<void(int, int)> f)
 {
        m_plugin.onEditorResize = f;
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-Plugins::Plugins(const m::Channel& c)
+Plugins::Plugins(const m::channel::Data& c)
 : channelId(c.id)
-, pluginIds(c.pluginIds) 
+, plugins(c.plugins)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Plugins getPlugins(ID channelId)
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock cl(mm::channels);
-       return Plugins(mm::get(mm::channels, channelId));
+       return Plugins(m::model::get().getChannel(channelId));
 }
 
-
-Plugin getPlugin(ID pluginId, ID channelId)
+Plugin getPlugin(m::Plugin& plugin, ID channelId)
 {
-       m::model::PluginsLock l(m::model::plugins);
-       return Plugin(m::model::get(m::model::plugins, pluginId), channelId);
+       return Plugin(plugin, channelId);
 }
 
-
-Param getParam (int index, ID pluginId)
+Param getParam(int index, const m::Plugin& plugin, ID channelId)
 {
-       m::model::PluginsLock l(m::model::plugins);
-       return Param(m::model::get(m::model::plugins, pluginId), index);
+       return Param(plugin, index, channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateWindow(ID pluginId, bool gui)
 {
-       m::model::PluginsLock l(m::model::plugins);
-       const m::Plugin& p = m::model::get(m::model::plugins, pluginId);
+       m::Plugin* p = m::model::find<m::Plugin>(pluginId);
+
+       assert(p != nullptr);
 
-       if (p.hasEditor())
+       if (p->hasEditor())
                return;
 
        /* Get the parent window first: the plug-in list. Then, if it exists, get
-       the child window - the actual pluginWindow. */
+    the child window - the actual pluginWindow. */
 
        v::gdPluginList* parent = static_cast<v::gdPluginList*>(u::gui::getSubwindow(G_MainWin, WID_FX_LIST));
        if (parent == nullptr)
                return;
        v::gdPluginWindow* child = static_cast<v::gdPluginWindow*>(u::gui::getSubwindow(parent, pluginId + 1));
-       if (child == nullptr) 
+       if (child == nullptr)
                return;
-       
-       if (!gui) Fl::lock();
+
+       if (!gui)
+               Fl::lock();
        child->updateParameters(!gui);
-       if (!gui) Fl::unlock();
+       if (!gui)
+               Fl::unlock();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void addPlugin(int pluginListIndex, ID channelId)
 {
        if (pluginListIndex >= m::pluginManager::countAvailablePlugins())
@@ -186,52 +166,43 @@ void addPlugin(int pluginListIndex, ID channelId)
                m::pluginHost::addPlugin(std::move(p), channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void swapPlugins(ID pluginId1, ID pluginId2, ID channelId)
+void swapPlugins(const m::Plugin& p1, const m::Plugin& p2, ID channelId)
 {
-       m::pluginHost::swapPlugin(pluginId1, pluginId2, channelId);
+       m::pluginHost::swapPlugin(p1, p2, channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void freePlugin(ID pluginId, ID channelId)
+void freePlugin(const m::Plugin& plugin, ID channelId)
 {
-       m::pluginHost::freePlugin(pluginId, channelId);
+       m::pluginHost::freePlugin(plugin, channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setProgram(ID pluginId, int programIndex)
 {
-       m::pluginHost::setPluginProgram(pluginId, programIndex); 
-       updateWindow(pluginId, /*gui=*/true); 
+       m::pluginHost::setPluginProgram(pluginId, programIndex);
+       updateWindow(pluginId, /*gui=*/true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void toggleBypass(ID pluginId)
 {
        m::pluginHost::toggleBypass(pluginId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setPluginPathCb(void* data)
 {
-       v::gdBrowserDir* browser = (v::gdBrowserDir*) data;
+       v::gdBrowserDir* browser = (v::gdBrowserDir*)data;
 
-       if (browser->getCurrentPath() == "") {
+       if (browser->getCurrentPath() == "")
+       {
                v::gdAlert("Invalid path.");
                return;
        }
@@ -245,8 +216,6 @@ void setPluginPathCb(void* data)
        v::gdConfig* configWin = static_cast<v::gdConfig*>(u::gui::getSubwindow(G_MainWin, WID_CONFIG));
        configWin->refreshVstPath();
 }
-
-}}} // giada::c::plugin::
-
+} // namespace giada::c::plugin
 
 #endif
index 0c2711941e7275003e1f9a55a5fddab7ab4e8c13..f091937ae693a2cd840db619718269a7cc59c51f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_PLUGIN_H
 #define G_GLUE_PLUGIN_H
 
-
 #ifdef WITH_VST
 
-
-#include <vector>
-#include <string>
 #include "core/plugins/pluginHost.h"
 #include "core/types.h"
+#include <string>
+#include <vector>
 
-
-namespace juce {
+namespace juce
+{
 class AudioProcessorEditor;
 }
-
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 class Plugin;
-class Channel;
 }
-namespace c {
-namespace plugin 
+namespace giada::m::channel
+{
+struct Data;
+}
+namespace giada::c::plugin
 {
 struct Program
 {
-    int         index;
-    std::string name;
+       int         index;
+       std::string name;
 };
 
 struct Param
 {
-    Param() = default;
-    Param(const m::Plugin&, int index);
-
-    int         index;
-    ID          pluginId;
-    std::string name;
-    std::string text;
-    std::string label;
-    float       value;
+       Param() = default;
+       Param(const m::Plugin&, int index, ID channelId);
+
+       int         index;
+       ID          pluginId;
+       ID          channelId;
+       std::string name;
+       std::string text;
+       std::string label;
+       float       value;
 };
 
 struct Plugin
 {
-    Plugin(m::Plugin&, ID channelId);
-
-    juce::AudioProcessorEditor* createEditor() const;
+       Plugin(m::Plugin&, ID channelId);
 
-    void setResizeCallback(std::function<void(int, int)> f);
+       juce::AudioProcessorEditor* createEditor() const;
+       const m::Plugin&            getPluginRef() const;
 
-    ID          id;
-    ID          channelId;
-    bool        valid;
-    bool        hasEditor;
-    bool        isBypassed;
-    std::string name;
-    std::string uniqueId;
-    int         currentProgram;
+       void setResizeCallback(std::function<void(int, int)> f);
 
-    std::vector<Program> programs;
-    std::vector<int>     paramIndexes;
+       ID          id;
+       ID          channelId;
+       bool        valid;
+       bool        hasEditor;
+       bool        isBypassed;
+       std::string name;
+       std::string uniqueId;
+       int         currentProgram;
 
-private:
+       std::vector<Program> programs;
+       std::vector<int>     paramIndexes;
 
-    m::Plugin& m_plugin;
+  private:
+       m::Plugin& m_plugin;
 };
 
 struct Plugins
 {
-    Plugins() = default;
-    Plugins(const m::Channel&);
+       Plugins() = default;
+       Plugins(const m::channel::Data&);
 
-    ID channelId;
-    std::vector<ID> pluginIds; 
+       ID                      channelId;
+       std::vector<m::Plugin*> plugins;
 };
 
 /* get*
 Returns ViewModel objects. */
 
 Plugins getPlugins(ID channelId);
-Plugin  getPlugin (ID pluginId, ID channelId);
-Param   getParam  (int index, ID pluginId);
+Plugin  getPlugin(m::Plugin& plugin, ID channelId);
+Param   getParam(int index, const m::Plugin& plugin, ID channelId);
 
 /* updateWindow
 Updates the editor-less plug-in window. This is useless if the plug-in has an
@@ -119,8 +116,8 @@ editor. */
 void updateWindow(ID pluginId, bool gui);
 
 void addPlugin(int pluginListIndex, ID channelId);
-void swapPlugins(ID pluginId1, ID pluginId2, ID channelId);
-void freePlugin(ID pluginId, ID channelId);
+void swapPlugins(const m::Plugin& p1, const m::Plugin& p2, ID channelId);
+void freePlugin(const m::Plugin& plugin, ID channelId);
 void setProgram(ID pluginId, int programIndex);
 void toggleBypass(ID pluginId);
 
@@ -129,10 +126,8 @@ Callback attached to the DirBrowser for adding new Plug-in search paths in the
 configuration window. */
 
 void setPluginPathCb(void* data);
-}}} // giada::c::plugin::
-
+} // namespace giada::c::plugin
 
 #endif
 
-
 #endif
index 4eab2b260ab6490514883178e5c61b97ec676abd..03e38ea4f3777067d5ae6c8b774219a2aa9d4621 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "gui/dialogs/warnings.h"
-#include "gui/elems/mainWindow/keyboard/channel.h"
-#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
+#include "core/recorder.h"
+#include "core/action.h"
 #include "core/channels/channel.h"
-#include "core/const.h"
 #include "core/clock.h"
-#include "core/model/model.h"
+#include "core/const.h"
 #include "core/kernelMidi.h"
-#include "core/recorderHandler.h"
-#include "core/recorder.h"
-#include "core/action.h"
 #include "core/mixer.h"
+#include "core/model/model.h"
+#include "core/recorderHandler.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/elems/mainWindow/keyboard/channel.h"
+#include "gui/elems/mainWindow/keyboard/sampleChannel.h"
+#include "recorder.h"
 #include "utils/gui.h"
 #include "utils/log.h"
-#include "recorder.h"
-
+#include <cassert>
 
-namespace giada {
-namespace c {
-namespace recorder 
+namespace giada::c::recorder
 {
 void clearAllActions(ID channelId)
 {
@@ -55,10 +51,8 @@ void clearAllActions(ID channelId)
        updateChannel(channelId, /*updateActionEditor=*/true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearVolumeActions(ID channelId)
 {
        if (!v::gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
@@ -67,10 +61,8 @@ void clearVolumeActions(ID channelId)
        updateChannel(channelId, /*updateActionEditor=*/true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void clearStartStopActions(ID channelId)
 {
        if (!v::gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
@@ -81,19 +73,15 @@ void clearStartStopActions(ID channelId)
        updateChannel(channelId, /*updateActionEditor=*/true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateChannel(ID channelId, bool updateActionEditor)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.state->hasActions = m::recorder::hasActions(channelId);
-       });
-                               
+       /* TODO - move somewhere else in the core area */
+       m::model::get().getChannel(channelId).hasActions = m::recorder::hasActions(channelId);
+       m::model::swap(m::model::SwapType::HARD);
+
        if (updateActionEditor)
                u::gui::refreshActionEditor();
 }
-
-}}} // giada::c::recorder::
+} // namespace giada::c::recorder
index 70bf565a07b5041c79fe73ec47d58ad70956441b..cb5bb74c8acb642c61be56e3494e570cafe3f4d8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_RECORDER_H
 #define G_GLUE_RECORDER_H
 
-
-namespace giada {
-namespace c {
-namespace recorder 
+namespace giada::c::recorder
 {
 void clearAllActions(ID channelId);
 void clearVolumeActions(ID channelId);
 void clearStartStopActions(ID channelId);
 void updateChannel(ID channelId, bool updateActionEditor);
-}}} // giada::c::recorder::
+} // namespace giada::c::recorder
 
 #endif
index 12535b53bcb801c04beb10974587f21cad5b94fd..5f5f4ea3da1b75eb25d946bea5c75873289b1a96 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
+#include "gui/dialogs/sampleEditor.h"
+#include "channel.h"
+#include "core/const.h"
+#include "core/mixerHandler.h"
+#include "core/model/model.h"
+#include "core/wave.h"
+#include "core/waveManager.h"
 #include "glue/events.h"
 #include "gui/dialogs/mainWindow.h"
-#include "gui/dialogs/sampleEditor.h"
 #include "gui/dialogs/warnings.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/sampleEditor/waveTools.h"
-#include "gui/elems/sampleEditor/volumeTool.h"
+#include "gui/elems/mainWindow/keyboard/channel.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/sampleEditor/boostTool.h"
 #include "gui/elems/sampleEditor/panTool.h"
 #include "gui/elems/sampleEditor/pitchTool.h"
 #include "gui/elems/sampleEditor/rangeTool.h"
 #include "gui/elems/sampleEditor/shiftTool.h"
+#include "gui/elems/sampleEditor/volumeTool.h"
+#include "gui/elems/sampleEditor/waveTools.h"
 #include "gui/elems/sampleEditor/waveform.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/elems/mainWindow/keyboard/channel.h"
-#include "core/model/model.h"
-#include "core/wave.h"
-#include "core/waveManager.h"
-#include "core/mixerHandler.h"
-#include "core/const.h"
+#include "sampleEditor.h"
 #include "utils/gui.h"
 #include "utils/log.h"
-#include "channel.h"
-#include "sampleEditor.h"
-
+#include <FL/Fl.H>
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace c {
-namespace sampleEditor
+namespace giada::c::sampleEditor
 {
 namespace
 {
+m::channel::Data& getChannel_(ID channelId)
+{
+       return m::model::get().getChannel(channelId);
+}
+
+m::samplePlayer::Data& getSamplePlayer_(ID channelId)
+{
+       return getChannel_(channelId).samplePlayer.value();
+}
+
+m::Wave& getWave_(ID channelId)
+{
+       return *const_cast<m::Wave*>(getSamplePlayer_(channelId).getWave());
+}
+
+/* -------------------------------------------------------------------------- */
+
 /* waveBuffer
 A Wave used during cut/copy/paste operations. */
 
@@ -69,125 +81,84 @@ std::unique_ptr<m::Wave> waveBuffer_;
 
 Frame previewTracker_ = 0;
 
-
 /* -------------------------------------------------------------------------- */
 
 /* resetBeginEnd_
-Resets begin/end points when model has changed and a new Channel pointer is
-needed for the operation. */
+Resets begin/end points to 0/max. */
 
 void resetBeginEnd_(ID channelId)
 {
-       m::model::onGet(m::model::channels, channelId, [&](const m::Channel& c)
-       {
-               Frame begin = c.samplePlayer->state->begin.load();
-               Frame end   = c.samplePlayer->state->end.load();
-               setBeginEnd(channelId, begin, end);
-       });
+       Frame begin = getSamplePlayer_(channelId).begin;
+       Frame end   = getSamplePlayer_(channelId).getWaveSize();
+       setBeginEnd(channelId, begin, end);
 }
-
-
-/* -------------------------------------------------------------------------- */
-
-/* updateWavePtr_
-Updates the Wave pointer in Channel::WaveReader. */
-
-void updateWavePtr_(ID channelId, ID waveId)
-{
-       namespace mm = m::model;
-
-       mm::WavesLock wl(mm::waves);
-       const m::Wave& wave = mm::get(mm::waves, waveId);
-
-       mm::onSwap(mm::channels, channelId, [&](m::Channel& c)
-       {
-               c.samplePlayer->loadWave(&wave);
-       });
-}
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-Data::Data(const m::Channel& c, const m::Wave& w)
-: channelId   (c.id)
-, waveId      (w.id)
-, name        (c.state->name)
-, volume      (c.state->volume.load())
-, pan         (c.state->pan.load())
-, pitch       (c.samplePlayer->state->pitch.load())
-, begin       (c.samplePlayer->state->begin.load())
-, end         (c.samplePlayer->state->end.load())
-, shift       (c.samplePlayer->state->shift.load())
-, waveSize    (w.getSize())
-, waveBits    (w.getBits())
-, waveDuration(w.getDuration())
-, waveRate    (w.getRate())
-, wavePath    (w.getPath())
-, isLogical   (w.isLogical())
+Data::Data(const m::channel::Data& c)
+: channelId(c.id)
+, name(c.name)
+, volume(c.volume)
+, pan(c.pan)
+, pitch(c.samplePlayer->pitch)
+, begin(c.samplePlayer->begin)
+, end(c.samplePlayer->end)
+, shift(c.samplePlayer->shift)
+, waveSize(c.samplePlayer->getWave()->getBuffer().countFrames())
+, waveBits(c.samplePlayer->getWave()->getBits())
+, waveDuration(c.samplePlayer->getWave()->getDuration())
+, waveRate(c.samplePlayer->getWave()->getRate())
+, wavePath(c.samplePlayer->getWave()->getPath())
+, isLogical(c.samplePlayer->getWave()->isLogical())
+, m_channel(&c)
 {
 }
 
-/* TODO - use c::channel::a_get() */
 ChannelStatus Data::a_getPreviewStatus() const
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock l(mm::channels);
-       return mm::get(mm::channels, m::mixer::PREVIEW_CHANNEL_ID).state->playStatus.load();
+       return getChannel_(m::mixer::PREVIEW_CHANNEL_ID).state->playStatus.load();
 }
 
-/* TODO - use c::channel::a_get() */
 Frame Data::a_getPreviewTracker() const
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock l(mm::channels);
-       return mm::get(mm::channels, m::mixer::PREVIEW_CHANNEL_ID).samplePlayer->state->tracker.load();
+       return getChannel_(m::mixer::PREVIEW_CHANNEL_ID).state->tracker.load();
 }
 
+const m::Wave& Data::getWaveRef() const
+{
+       return *m_channel->samplePlayer->getWave();
+}
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 Data getData(ID channelId)
 {
-       namespace mm = m::model;
-
-       mm::ChannelsLock cl(mm::channels);
-       mm::WavesLock        wl(mm::waves);
-
-       const m::Channel& channel = mm::get(mm::channels, channelId);
-       const m::Wave&        wave    = mm::get(mm::waves, channel.samplePlayer->getWaveId());
+       /* Prepare the preview channel first, then return Data object. */
+       m::samplePlayer::loadWave(getChannel_(m::mixer::PREVIEW_CHANNEL_ID), &getWave_(channelId));
+       m::model::swap(m::model::SwapType::SOFT);
 
-       /* Prepare the preview channel. */
-
-       m::Channel& preview = mm::get(mm::channels, m::mixer::PREVIEW_CHANNEL_ID);
-       preview.samplePlayer->loadWave(&wave);
-
-       return Data(channel, wave);
+       return Data(getChannel_(channelId));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void onRefresh(bool gui, std::function<void(v::gdSampleEditor&)> f)
 {
        v::gdSampleEditor* se = static_cast<v::gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
-       if (se == nullptr) 
+       if (se == nullptr)
                return;
-       if (!gui) Fl::lock();
+       if (!gui)
+               Fl::lock();
        f(*se);
-       if (!gui) Fl::unlock();
+       if (!gui)
+               Fl::unlock();
 }
 
-
 v::gdSampleEditor* getSampleEditorWindow()
 {
        v::gdSampleEditor* se = static_cast<v::gdSampleEditor*>(u::gui::getSubwindow(G_MainWin, WID_SAMPLE_EDITOR));
@@ -195,163 +166,150 @@ v::gdSampleEditor* getSampleEditorWindow()
        return se;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void setBeginEnd(ID channelId, int b, int e)
+void setBeginEnd(ID channelId, Frame b, Frame e)
 {
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               b = std::clamp(b, 0, c.samplePlayer->getWaveSize() - 1);
-               e = std::clamp(e, 1, c.samplePlayer->getWaveSize() - 1);
-               if      (b >= e) b = e - 1;
-               else if (e < b)  e = b + 1;
+       m::channel::Data& c = getChannel_(channelId);
 
-               c.samplePlayer->state->begin.store(b);
-               c.samplePlayer->state->end.store(e);
-               if (c.samplePlayer->state->tracker.load() < b)
-                       c.samplePlayer->state->tracker.store(b);
-       });
+       b = std::clamp(b, 0, c.samplePlayer->getWaveSize() - 1);
+       e = std::clamp(e, 1, c.samplePlayer->getWaveSize() - 1);
+       if (b >= e)
+               b = e - 1;
+       else if (e < b)
+               e = b + 1;
+
+       if (c.state->tracker.load() < b)
+               c.state->tracker.store(b);
+
+       getSamplePlayer_(channelId).begin = b;
+       getSamplePlayer_(channelId).end   = e;
+       m::model::swap(m::model::SwapType::SOFT);
 
        /* TODO waveform widget is dumb and wants a rebuild. Refactoring needed! */
        getSampleEditorWindow()->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void cut(ID channelId, ID waveId, int a, int b)
+void cut(ID channelId, Frame a, Frame b)
 {
-       copy(waveId, a, b);
-       m::wfx::cut(waveId, a, b);
-       updateWavePtr_(channelId, waveId);
+       copy(channelId, a, b);
+       m::model::DataLock lock;
+       m::wfx::cut(getWave_(channelId), a, b);
        resetBeginEnd_(channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void copy(ID waveId, int a, int b)
+void copy(ID channelId, Frame a, Frame b)
 {
-       m::model::WavesLock lock(m::model::waves);
-       waveBuffer_ = m::waveManager::createFromWave(m::model::get(m::model::waves, waveId), a, b);
+       waveBuffer_ = m::waveManager::createFromWave(getWave_(channelId), a, b);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void paste(ID channelId, ID waveId, int a)
+void paste(ID channelId, Frame a)
 {
-       if (!isWaveBufferFull()) {
+       if (!isWaveBufferFull())
+       {
                u::log::print("[sampleEditor::paste] Buffer is empty, nothing to paste\n");
                return;
        }
 
-       m::wfx::paste(*waveBuffer_, waveId, a);
-       updateWavePtr_(channelId, waveId);
+       /* Get the existing wave in channel. */
 
-       /* Shift begin/end points to keep the previous position. */
+       m::Wave& wave = getWave_(channelId);
 
-       int   delta = waveBuffer_->getSize();
-       Frame begin;
-       Frame end;
+       /* Temporary disable wave reading in channel. From now on, the audio thread
+       won't be reading any wave, so editing it is safe.  */
 
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               begin = c.samplePlayer->state->begin.load();
-               end   = c.samplePlayer->state->end.load();
-       });
+       m::model::DataLock lock;
+
+       /* Paste copied data to destination wave. */
+
+       m::wfx::paste(*waveBuffer_, wave, a);
+
+       /* Pass the old wave that contains the pasted data to channel. */
+
+       m::samplePlayer::setWave(getChannel_(channelId), &wave, 1.0f);
+
+       /* In the meantime, shift begin/end points to keep the previous position. */
+
+       int   delta = waveBuffer_->getBuffer().countFrames();
+       Frame begin = getSamplePlayer_(channelId).begin;
+       Frame end   = getSamplePlayer_(channelId).end;
 
        if (a < begin && a < end)
                setBeginEnd(channelId, begin + delta, end + delta);
-       else
-       if (a < end)
+       else if (a < end)
                setBeginEnd(channelId, begin, end + delta);
 
        getSampleEditorWindow()->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void silence(ID channelId, ID waveId, int a, int b)
+void silence(ID channelId, int a, int b)
 {
-       m::wfx::silence(waveId, a, b);
-       updateWavePtr_(channelId, waveId);
+       m::model::DataLock lock;
+       m::wfx::silence(getWave_(channelId), a, b);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void fade(ID channelId, ID waveId, int a, int b, m::wfx::Fade type)
+void fade(ID channelId, int a, int b, m::wfx::Fade type)
 {
-       m::wfx::fade(waveId, a, b, type);
-       updateWavePtr_(channelId, waveId);
+       m::model::DataLock lock;
+       m::wfx::fade(getWave_(channelId), a, b, type);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void smoothEdges(ID channelId, ID waveId, int a, int b)
+void smoothEdges(ID channelId, int a, int b)
 {
-       m::wfx::smooth(waveId, a, b);
-       updateWavePtr_(channelId, waveId);
+       m::model::DataLock lock;
+       m::wfx::smooth(getWave_(channelId), a, b);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void reverse(ID channelId, ID waveId, int a, int b)
+void reverse(ID channelId, Frame a, Frame b)
 {
-       m::wfx::reverse(waveId, a, b);
-       updateWavePtr_(channelId, waveId);
+       m::model::DataLock lock;
+       m::wfx::reverse(getWave_(channelId), a, b);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void normalize(ID channelId, ID waveId, int a, int b)
+void normalize(ID channelId, int a, int b)
 {
-       m::wfx::normalize(waveId, a, b);
-       updateWavePtr_(channelId, waveId);
+       m::model::DataLock lock;
+       m::wfx::normalize(getWave_(channelId), a, b);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void trim(ID channelId, ID waveId, int a, int b)
+void trim(ID channelId, int a, int b)
 {
-       m::wfx::trim(waveId, a, b);
-       updateWavePtr_(channelId, waveId);
+       m::model::DataLock lock;
+       m::wfx::trim(getWave_(channelId), a, b);
        resetBeginEnd_(channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* TODO - this arcane logic of keeping previewTracker_ will go away as soon as
 the One-shot pause mode is implemented: 
        https://github.com/monocasual/giada/issues/88 */
 
 void playPreview(bool loop)
-{      
+{
        setPreviewTracker(previewTracker_);
        channel::setSamplePlayerMode(m::mixer::PREVIEW_CHANNEL_ID, loop ? SamplePlayerMode::SINGLE_ENDLESS : SamplePlayerMode::SINGLE_BASIC);
        events::pressChannel(m::mixer::PREVIEW_CHANNEL_ID, G_MAX_VELOCITY, Thread::MAIN);
 }
 
-
 void stopPreview()
 {
        /* Let the Sample Editor show the initial tracker position, then kill the
@@ -361,69 +319,50 @@ void stopPreview()
        events::killChannel(m::mixer::PREVIEW_CHANNEL_ID, Thread::MAIN);
 }
 
-
 void setPreviewTracker(Frame f)
 {
        namespace mm = m::model;
 
-       mm::onGet(mm::channels, m::mixer::PREVIEW_CHANNEL_ID, [&](m::Channel& c)
-       {
-               c.samplePlayer->state->tracker.store(f);
-       });
+       mm::get().getChannel(m::mixer::PREVIEW_CHANNEL_ID).state->tracker.store(f);
+       mm::swap(mm::SwapType::SOFT);
 
        previewTracker_ = f;
 
        getSampleEditorWindow()->refresh();
 }
 
-
 void cleanupPreview()
 {
        namespace mm = m::model;
 
-       mm::ChannelsLock cl(mm::channels);
-       mm::get(mm::channels, m::mixer::PREVIEW_CHANNEL_ID).samplePlayer->loadWave(nullptr);
+       m::samplePlayer::loadWave(mm::get().getChannel(m::mixer::PREVIEW_CHANNEL_ID), nullptr);
+       mm::swap(mm::SwapType::SOFT);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void toNewChannel(ID channelId, ID waveId, int a, int b)
+void toNewChannel(ID channelId, Frame a, Frame b)
 {
        ID columnId = G_MainWin->keyboard->getChannel(channelId)->getColumnId();
-
-       m::model::onGet(m::model::waves, waveId, [&](m::Wave& w)
-       {
-               m::mh::addAndLoadChannel(columnId, m::waveManager::createFromWave(w, a, b));
-       });
+       m::mh::addAndLoadChannel(columnId, m::waveManager::createFromWave(getWave_(channelId), a, b));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isWaveBufferFull()
 {
        return waveBuffer_ != nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void reload(ID channelId, ID waveId)
+void reload(ID channelId)
 {
        if (!v::gdConfirmWin("Warning", "Reload sample: are you sure?"))
                return;
 
-       std::string wavePath;
-       m::model::onGet(m::model::waves, waveId, [&](const m::Wave& w)
+       if (channel::loadChannel(channelId, getWave_(channelId).getPath()) != G_RES_OK)
        {
-               wavePath = w.getPath();
-       });
-
-       if (channel::loadChannel(channelId, wavePath) != G_RES_OK) {
                v::gdAlert("Unable to reload sample!");
                return;
        }
@@ -431,26 +370,18 @@ void reload(ID channelId, ID waveId)
        getSampleEditorWindow()->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void shift(ID channelId, ID waveId, int offset)
+void shift(ID channelId, Frame offset)
 {
-       Frame shift;
-       m::model::onGet(m::model::channels, channelId, [&](const m::Channel& c)
-       {
-               shift = c.samplePlayer->state->shift.load();
-       });
-       
-       m::wfx::shift(waveId, offset - shift);
-       updateWavePtr_(channelId, waveId);
+       namespace mm = m::model;
 
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               c.samplePlayer->state->shift.store(offset);
-       });
+       Frame shift = getSamplePlayer_(channelId).shift;
+
+       mm::DataLock lock();
+       m::wfx::shift(getWave_(channelId), offset - shift);
+       getSamplePlayer_(channelId).shift = offset;
 
        getSampleEditorWindow()->shiftTool->update(offset);
 }
-}}} // giada::c::sampleEditor::
+} // namespace giada::c::sampleEditor
index d398e7e6e97161681990d81763373a15052b742e..4a1473b90940eb6d4d081818fb13d6b8e6f06960 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_SAMPLE_EDITOR_H
 #define G_GLUE_SAMPLE_EDITOR_H
 
-
-#include <functional>
-#include <string>
 #include "core/types.h"
 #include "core/waveFx.h"
+#include <functional>
+#include <string>
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
-class Channel;
 class Wave;
 }
-namespace v 
+namespace giada::m::channel
+{
+struct Data;
+}
+namespace giada::v
 {
 class gdSampleEditor;
 }
-namespace c {
-namespace sampleEditor 
+namespace giada::c::sampleEditor
 {
 struct Data
 {
-    Data() = default;
-    Data(const m::Channel&, const m::Wave&);
-
-    ChannelStatus a_getPreviewStatus() const;
-    Frame a_getPreviewTracker() const;
-
-    ID          channelId; 
-    ID          waveId; 
-    std::string name;
-    float       volume;
-    float       pan;
-    float       pitch;
-    Frame       begin;
-    Frame       end;
-    Frame       shift;
-    Frame       waveSize;
-    int         waveBits;
-    int         waveDuration;
-    int         waveRate;
-    std::string wavePath;
-    bool        isLogical;
+       Data() = default;
+       Data(const m::channel::Data&);
+
+       ChannelStatus  a_getPreviewStatus() const;
+       Frame          a_getPreviewTracker() const;
+       const m::Wave& getWaveRef() const; // TODO - getWaveData (or public ptr member to Wave::data)
+
+       ID          channelId;
+       std::string name;
+       float       volume;
+       float       pan;
+       float       pitch;
+       Frame       begin;
+       Frame       end;
+       Frame       shift;
+       Frame       waveSize;
+       int         waveBits;
+       int         waveDuration;
+       int         waveRate;
+       std::string wavePath;
+       bool        isLogical;
+
+  private:
+       const m::channel::Data* m_channel;
 };
 
 /* onRefresh --- TODO - wrong name */
@@ -85,20 +86,20 @@ Data getData(ID channelId);
 /* setBeginEnd
 Sets start/end points in the sample editor. */
 
-void setBeginEnd(ID channelId, int b, int e);
+void setBeginEnd(ID channelId, Frame b, Frame e);
 
-void cut(ID channelId, ID waveId, int a, int b);
-void copy(ID waveId, int a, int b);
-void paste(ID channelId, ID waveId, int a);
+void cut(ID channelId, Frame a, Frame b);
+void copy(ID channelId, Frame a, Frame b);
+void paste(ID channelId, Frame a);
 
-void trim(ID channelId, ID waveId, int a, int b);
-void reverse(ID channelId, ID waveId, int a, int b);
-void normalize(ID channelId, ID waveId, int a, int b);
-void silence(ID channelId, ID waveId, int a, int b);
-void fade(ID channelId, ID waveId, int a, int b, m::wfx::Fade type);
-void smoothEdges(ID channelId, ID waveId, int a, int b);
-void shift(ID channelId, ID waveId, int offset);
-void reload(ID channelId, ID waveId);
+void trim(ID channelId, Frame a, Frame b);
+void reverse(ID channelId, Frame a, Frame b);
+void normalize(ID channelId, Frame a, Frame b);
+void silence(ID channelId, Frame a, Frame b);
+void fade(ID channelId, Frame a, Frame b, m::wfx::Fade type);
+void smoothEdges(ID channelId, Frame a, Frame b);
+void shift(ID channelId, Frame offset);
+void reload(ID channelId);
 
 bool isWaveBufferFull();
 
@@ -110,7 +111,7 @@ void cleanupPreview();
 /* toNewChannel
 Copies the selected range into a new sample channel. */
 
-void toNewChannel(ID channelId, ID waveId, int a, int b);
-}}} // giada::c::sampleEditor::
+void toNewChannel(ID channelId, Frame a, Frame b);
+} // namespace giada::c::sampleEditor
 
 #endif
index 2005c57812157129f4ecda277d10955c47f79e2e..e468facf8a16c2df40089415d5b1e0894472283e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/model/model.h"
 #include "core/model/storage.h"
+#include "channel.h"
+#include "core/clock.h"
+#include "core/conf.h"
+#include "core/init.h"
 #include "core/mixer.h"
-#include "core/wave.h"
 #include "core/mixerHandler.h"
-#include "core/recorderHandler.h"
-#include "core/plugins/pluginManager.h"
-#include "core/plugins/pluginHost.h"
-#include "core/plugins/plugin.h"
-#include "core/conf.h"
+#include "core/model/model.h"
 #include "core/patch.h"
-#include "core/init.h"
-#include "core/waveManager.h"
-#include "core/clock.h"
+#include "core/plugins/plugin.h"
+#include "core/plugins/pluginHost.h"
+#include "core/plugins/pluginManager.h"
+#include "core/recorderHandler.h"
 #include "core/wave.h"
-#include "utils/gui.h"
-#include "utils/log.h"
-#include "utils/string.h"
-#include "utils/fs.h"
-#include "gui/model.h"
+#include "core/waveManager.h"
+#include "gui/dialogs/browser/browserLoad.h"
+#include "gui/dialogs/browser/browserSave.h"
+#include "gui/dialogs/mainWindow.h"
+#include "gui/dialogs/warnings.h"
 #include "gui/elems/basics/progress.h"
 #include "gui/elems/mainWindow/keyboard/column.h"
 #include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/dialogs/mainWindow.h"
-#include "gui/dialogs/warnings.h"
-#include "gui/dialogs/browser/browserSave.h"
-#include "gui/dialogs/browser/browserLoad.h"
+#include "gui/model.h"
 #include "main.h"
-#include "channel.h"
 #include "storage.h"
-
+#include "utils/fs.h"
+#include "utils/gui.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace c {
+namespace giada
+{
+namespace c
+{
 namespace storage
 {
 namespace
 {
 std::string makeWavePath_(const std::string& base, const m::Wave& w, int k)
 {
-       return base + G_SLASH + w.getBasename(/*ext=*/false) + "-" + std::to_string(k) + "." +  w.getExtension();
-} 
-
+       return base + G_SLASH + w.getBasename(/*ext=*/false) + "-" + std::to_string(k) + w.getExtension();
+}
 
 bool isWavePathUnique_(const m::Wave& skip, const std::string& path)
 {
-       m::model::WavesLock l(m::model::waves);
-
-       for (const m::Wave* w : m::model::waves)
+       for (const auto& w : m::model::getAll<m::model::WavePtrs>())
                if (w->id != skip.id && w->getPath() == path)
                        return false;
        return true;
@@ -91,17 +86,15 @@ std::string makeUniqueWavePath_(const std::string& base, const m::Wave& w)
 
        // TODO - just use a timestamp. e.g. makeWavePath_(..., ..., getTimeStamp())
        int k = 0;
-       path = makeWavePath_(base, w, k);
+       path  = makeWavePath_(base, w, k);
        while (!isWavePathUnique_(w, path))
                path = makeWavePath_(base, w, k++);
-       
+
        return path;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool savePatch_(const std::string& path, const std::string& name)
 {
        m::patch::init();
@@ -119,71 +112,55 @@ bool savePatch_(const std::string& path, const std::string& name)
        return true;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void saveWavesToProject_(const std::string& basePath)
 {
-       /* No need for a hard Wave swap here: nobody is reading the path data. */
-
-       m::model::WavesLock l(m::model::waves);
-
-       for (m::Wave* w : m::model::waves) {
+       for (const std::unique_ptr<m::Wave>& w : m::model::getAll<m::model::WavePtrs>())
+       {
                w->setPath(makeUniqueWavePath_(basePath, *w));
-               m::waveManager::save(*w, w->getPath()); // TODO - error checking                        
+               m::waveManager::save(*w, w->getPath()); // TODO - error checking
        }
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void loadProject(void* data)
 {
-       v::gdBrowserLoad* browser = static_cast<v::gdBrowserLoad*>(data);
-       std::string fullPath      = browser->getSelectedItem();
-       bool isProject            = u::fs::isProject(browser->getSelectedItem());
+       v::gdBrowserLoad* browser  = static_cast<v::gdBrowserLoad*>(data);
+       std::string       fullPath = browser->getSelectedItem();
 
        browser->showStatusBar();
 
        u::log::print("[loadProject] load from %s\n", fullPath);
 
-       std::string fileToLoad = fullPath;  // patch file to read from
-       std::string basePath   = "";        // base path, in case of reading from a project
-       if (isProject) {
-               fileToLoad = fullPath + G_SLASH + u::fs::stripExt(u::fs::basename(fullPath)) + ".gptc";
-               basePath   = fullPath + G_SLASH;
-       }
+       std::string fileToLoad = fullPath + G_SLASH + u::fs::stripExt(u::fs::basename(fullPath)) + ".gptc";
+       std::string basePath   = fullPath + G_SLASH;
 
        /* Read the patch from file. */
 
        m::patch::init();
        int res = m::patch::read(fileToLoad, basePath);
-       if (res != G_PATCH_OK) {
+       if (res != G_PATCH_OK)
+       {
                if (res == G_PATCH_UNREADABLE)
                        v::gdAlert("This patch is unreadable.");
-               else
-               if (res == G_PATCH_INVALID)
+               else if (res == G_PATCH_INVALID)
                        v::gdAlert("This patch is not valid.");
-               else
-               if (res == G_PATCH_UNSUPPORTED)
+               else if (res == G_PATCH_UNSUPPORTED)
                        v::gdAlert("This patch format is no longer supported.");
                browser->hideStatusBar();
                return;
-       }       
-
-       if (!isProject)
-               v::gdAlert("Support for raw patches is deprecated\nand will be removed soon!");
+       }
 
        /* Then reset the system (it disables mixer) and fill the model. */
 
        m::init::reset();
-       m::model::load(m::patch::patch);
        v::model::load(m::patch::patch);
+       m::model::load(m::patch::patch);
 
        /* Prepare the engine. Recorder has to recompute the actions positions if 
        the current samplerate != patch samplerate. Clock needs to update frames
@@ -192,7 +169,7 @@ void loadProject(void* data)
        m::mh::updateSoloCount();
        m::recorderHandler::updateSamplerate(m::conf::conf.samplerate, m::patch::patch.samplerate);
        m::clock::recomputeFrames();
-       m::mixer::allocRecBuffer(m::clock::getFramesInLoop());
+       m::mixer::allocRecBuffer(m::clock::getMaxFramesInLoop());
 
        /* Mixer is ready to go back online. */
 
@@ -214,19 +191,18 @@ void loadProject(void* data)
        browser->do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void saveProject(void* data)
 {
-       v::gdBrowserSave* browser = static_cast<v::gdBrowserSave*>(data);
-       std::string name          = u::fs::stripExt(browser->getName());
-       std::string folderPath    = browser->getCurrentPath();
-       std::string fullPath      = folderPath + G_SLASH + name + ".gprj";
-       std::string gptcPath      = fullPath + G_SLASH + name + ".gptc";
+       v::gdBrowserSave* browser    = static_cast<v::gdBrowserSave*>(data);
+       std::string       name       = u::fs::stripExt(browser->getName());
+       std::string       folderPath = browser->getCurrentPath();
+       std::string       fullPath   = folderPath + G_SLASH + name + ".gprj";
+       std::string       gptcPath   = fullPath + G_SLASH + name + ".gptc";
 
-       if (name == "") {
+       if (name == "")
+       {
                v::gdAlert("Please choose a project name.");
                return;
        }
@@ -234,7 +210,8 @@ void saveProject(void* data)
        if (u::fs::dirExists(fullPath) && !v::gdConfirmWin("Warning", "Project exists: overwrite?"))
                return;
 
-       if (!u::fs::mkdir(fullPath)) {
+       if (!u::fs::mkdir(fullPath))
+       {
                u::log::print("[saveProject] Unable to make project directory!\n");
                return;
        }
@@ -247,13 +224,10 @@ void saveProject(void* data)
                browser->do_callback();
        else
                v::gdAlert("Unable to save the project!");
-
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void loadSample(void* data)
 {
        v::gdBrowserLoad* browser  = static_cast<v::gdBrowserLoad*>(data);
@@ -264,25 +238,25 @@ void loadSample(void* data)
 
        int res = c::channel::loadChannel(browser->getChannelId(), fullPath);
 
-       if (res == G_RES_OK) {
+       if (res == G_RES_OK)
+       {
                m::conf::conf.samplePath = u::fs::dirname(fullPath);
                browser->do_callback();
                G_MainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void saveSample(void* data)
 {
-       v::gdBrowserSave* browser = static_cast<v::gdBrowserSave*>(data);
-       std::string name          = browser->getName();
-       std::string folderPath    = browser->getCurrentPath();
-       ID channelId              = browser->getChannelId();
+       v::gdBrowserSave* browser    = static_cast<v::gdBrowserSave*>(data);
+       std::string       name       = browser->getName();
+       std::string       folderPath = browser->getCurrentPath();
+       ID                channelId  = browser->getChannelId();
 
-       if (name == "") {
+       if (name == "")
+       {
                v::gdAlert("Please choose a file name.");
                return;
        }
@@ -292,17 +266,13 @@ void saveSample(void* data)
        if (u::fs::fileExists(filePath) && !v::gdConfirmWin("Warning", "File exists: overwrite?"))
                return;
 
-       ID waveId;
-       m::model::onGet(m::model::channels, channelId, [&](m::Channel& c)
-       {
-               waveId = c.samplePlayer->getWaveId();
-       });
-
-       std::size_t waveIndex = m::model::getIndex(m::model::waves, waveId);
+       ID       waveId = m::model::get().getChannel(channelId).samplePlayer->getWaveId();
+       m::Wave* wave   = m::model::find<m::Wave>(waveId);
 
-       std::unique_ptr<m::Wave> wave = m::model::waves.clone(waveIndex);
+       assert(wave != nullptr);
 
-       if (!m::waveManager::save(*wave.get(), filePath)) {
+       if (!m::waveManager::save(*wave, filePath))
+       {
                v::gdAlert("Unable to save this sample!");
                return;
        }
@@ -315,13 +285,14 @@ void saveSample(void* data)
 
        /* Update logical and edited states in Wave. */
 
+       m::model::DataLock lock;
        wave->setLogical(false);
        wave->setEdited(false);
 
-       m::model::waves.swap(std::move(wave), waveIndex);
-
        /* Finally close the browser. */
 
        browser->do_callback();
 }
-}}} // giada::c::storage::
+} // namespace storage
+} // namespace c
+} // namespace giada
index b9ada967c7e6cdccd45ed347d31131b493adbce2..75352f7029c635a8340dfdce488768fc283e73d8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_GLUE_STORAGE_H
 #define G_GLUE_STORAGE_H
 
-
-namespace giada {
-namespace c {
+namespace giada
+{
+namespace c
+{
 namespace storage
 {
 void loadProject(void* data);
 void saveProject(void* data);
-void saveSample (void* data);
-void loadSample (void* data);
-}}} // giada::c::storage::
+void saveSample(void* data);
+void loadSample(void* data);
+} // namespace storage
+} // namespace c
+} // namespace giada
 
 #endif
index 6423433280c555d16590d63afc8da4dfc827a643..18cd81f5405e809513740302c4b53365816f2234 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Pixmap.H>
-#include <FL/fl_draw.H>
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/graphics.h"
+#include <FL/Fl_Pixmap.H>
+#include <FL/fl_draw.H>
 #ifdef WITH_VST
 #include "deps/juce-config.h"
 #endif
+#include "about.h"
+#include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 #include "utils/gui.h"
 #include "utils/string.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/box.h"
-#include "about.h"
 
-
-namespace giada {
-namespace v 
+namespace giada::v
 {
 gdAbout::gdAbout()
 #ifdef WITH_VST
@@ -49,64 +46,58 @@ gdAbout::gdAbout()
 #else
 : gdWindow(340, 330, "About Giada")
 #endif
-{
-       set_modal();
-
-       logo  = new geBox(8, 20, 324, 86);
-       text  = new geBox(8, 120, 324, 140);
-       close = new geButton(252, h()-28, 80, 20, "Close");
+, logo(8, 20, 324, 86)
+, text(8, 120, 324, 140)
+, close(252, h() - 28, 80, 20, "Close")
 #ifdef WITH_VST
-       vstLogo = new geBox(8, 265, 324, 50);
-       vstText = new geBox(8, 315, 324, 46);
+, vstText(8, 315, 324, 46)
+, vstLogo(8, 265, 324, 50)
 #endif
+{
        end();
+       set_modal();
 
        std::string version = G_VERSION_STR;
 #ifdef G_DEBUG_MODE
        version += " (debug build)";
 #endif
 
-       logo->image(new Fl_Pixmap(giada_logo_xpm));
-       text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
-       text->copy_label(std::string(
-               "Version " + version + " (" BUILD_DATE ")\n\n"
-               "Developed by Monocasual Laboratories\n\n"
-               "Released under the terms of the GNU General\n"
-               "Public License (GPL v3)\n\n"
-               "News, infos, contacts and documentation:\n"
-               "www.giadamusic.com").c_str());
+       logo.image(new Fl_Pixmap(giada_logo_xpm));
+       text.align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
+       text.copy_label(std::string(
+           "Version " + version + " (" BUILD_DATE ")\n\n"
+                                  "Developed by Monocasual Laboratories\n\n"
+                                  "Released under the terms of the GNU General\n"
+                                  "Public License (GPL v3)\n\n"
+                                  "News, infos, contacts and documentation:\n"
+                                  "www.giadamusic.com")
+                           .c_str());
 
 #ifdef WITH_VST
 
-       vstLogo->image(new Fl_Pixmap(vstLogo_xpm));
-       vstLogo->position(vstLogo->x(), text->y() + text->h() + 8);
-       vstText->label(
-               "VST Plug-In Technology by Steinberg\n"
-               "VST is a trademark of Steinberg\nMedia Technologies GmbH"
-       );
-       vstText->position(vstText->x(), vstLogo->y()+vstLogo->h());
+       vstLogo.image(new Fl_Pixmap(vstLogo_xpm));
+       vstLogo.position(vstLogo.x(), text.y() + text.h() + 8);
+       vstText.label(
+           "VST Plug-In Technology by Steinberg\n"
+           "VST is a trademark of Steinberg\nMedia Technologies GmbH");
+       vstText.position(vstText.x(), vstLogo.y() + vstLogo.h());
 
 #endif
 
-       close->callback(cb_close, (void*)this);
+       close.callback(cb_close, (void*)this);
        u::gui::setFavicon(this);
        setId(WID_ABOUT);
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdAbout::cb_close(Fl_Widget* /*w*/, void* p) { ((gdAbout*)p)->cb_close(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdAbout::cb_close()
 {
        do_callback();
 }
-
-}} // giada::v::
\ No newline at end of file
+} // namespace giada::v
\ No newline at end of file
index 1d2c5810d3f91189f74ec2e920929bea86764912..a2cd3ba93af39bf1d192f70fb3c3bc3f60a9b6ea 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_ABOUT_H
 #define GD_ABOUT_H
 
+#include "gui/dialogs/window.h"
+#include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 
-#include "window.h"
-
-
-class geBox;
-class geButton;
-
-
-namespace giada {
-namespace v 
+namespace giada::v
 {
 class gdAbout : public gdWindow
 {
 public:
+       gdAbout();
 
-    gdAbout();
-
-    static void cb_close(Fl_Widget* /*w*/, void* p);
-    inline void cb_close();
+       static void cb_close(Fl_Widget* /*w*/, void* p);
+       inline void cb_close();
 
 private:
-
-       geBox*    logo;
-       geBox*    text;
-       geButton* close;
-
+       geBox    logo;
+       geBox    text;
+       geButton close;
 #ifdef WITH_VST
-       geBox* vstText;
-       geBox* vstLogo;
+       geBox vstText;
+       geBox vstLogo;
 #endif
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index c4f81a9861a1c3bec7857a65474cbd459dae1fec..9acb522097698bcbccbdab02847fced9adafef76 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <string>
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include "utils/gui.h"
-#include "utils/string.h"
-#include "core/conf.h"
+#include "baseActionEditor.h"
 #include "core/action.h"
-#include "core/const.h"
 #include "core/clock.h"
+#include "core/conf.h"
+#include "core/const.h"
 #include "core/midiEvent.h"
 #include "glue/channel.h"
 #include "gui/elems/actionEditor/gridTool.h"
-#include "gui/elems/basics/scrollPack.h"
 #include "gui/elems/basics/choice.h"
-#include "baseActionEditor.h"
-
+#include "gui/elems/basics/scrollPack.h"
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <cassert>
+#include <string>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gdBaseActionEditor::gdBaseActionEditor(ID channelId)
-: gdWindow (640, 284)
+: gdWindow(640, 284)
 , channelId(channelId)
-, ratio    (G_DEFAULT_ZOOM_RATIO)
+, ratio(G_DEFAULT_ZOOM_RATIO)
 {
        using namespace giada::m;
 
-       if (conf::conf.actionEditorW) {
-               resize(conf::conf.actionEditorX, conf::conf.actionEditorY, 
-                       conf::conf.actionEditorW, conf::conf.actionEditorH);
+       if (conf::conf.actionEditorW)
+       {
+               resize(conf::conf.actionEditorX, conf::conf.actionEditorY,
+                   conf::conf.actionEditorW, conf::conf.actionEditorH);
                ratio = conf::conf.actionEditorZoom;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdBaseActionEditor::~gdBaseActionEditor()
 {
        using namespace giada::m;
 
-       conf::conf.actionEditorX = x();
-       conf::conf.actionEditorY = y();
-       conf::conf.actionEditorW = w();
-       conf::conf.actionEditorH = h();
+       conf::conf.actionEditorX    = x();
+       conf::conf.actionEditorY    = y();
+       conf::conf.actionEditorW    = w();
+       conf::conf.actionEditorH    = h();
        conf::conf.actionEditorZoom = ratio;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gdBaseActionEditor::cb_zoomIn(Fl_Widget* /*w*/, void* p)  { ((gdBaseActionEditor*)p)->zoomIn(); }
+void gdBaseActionEditor::cb_zoomIn(Fl_Widget* /*w*/, void* p) { ((gdBaseActionEditor*)p)->zoomIn(); }
 void gdBaseActionEditor::cb_zoomOut(Fl_Widget* /*w*/, void* p) { ((gdBaseActionEditor*)p)->zoomOut(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBaseActionEditor::computeWidth()
 {
        fullWidth = frameToPixel(m::clock::getFramesInSeq());
        loopWidth = frameToPixel(m::clock::getFramesInLoop());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Pixel gdBaseActionEditor::frameToPixel(Frame f) const
 {
        return f / ratio;
 }
 
-
 Frame gdBaseActionEditor::pixelToFrame(Pixel p, bool snap) const
 {
        return snap ? gridTool->getSnapFrame(p * ratio) : p * ratio;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBaseActionEditor::zoomIn()
 {
        float ratioPrev = ratio;
@@ -119,79 +108,72 @@ void gdBaseActionEditor::zoomIn()
        if (ratio < MIN_RATIO)
                ratio = MIN_RATIO;
 
-       if (ratioPrev != ratio) {
+       if (ratioPrev != ratio)
+       {
                rebuild();
                centerViewportIn();
                redraw();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBaseActionEditor::zoomOut()
 {
        float ratioPrev = ratio;
-       
+
        ratio *= 2;
        if (ratio > MAX_RATIO)
                ratio = MAX_RATIO;
 
-       if (ratioPrev != ratio) {
+       if (ratioPrev != ratio)
+       {
                rebuild();
                centerViewportOut();
                redraw();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBaseActionEditor::centerViewportIn()
 {
        Pixel sx = Fl::event_x() + (viewport->xposition() * 2);
-       viewport->scroll_to(sx, viewport->yposition()); 
+       viewport->scroll_to(sx, viewport->yposition());
 }
 
-
 void gdBaseActionEditor::centerViewportOut()
 {
        Pixel sx = -((Fl::event_x() + viewport->xposition()) / 2) + viewport->xposition();
-       if (sx < 0) sx = 0;
+       if (sx < 0)
+               sx = 0;
        viewport->scroll_to(sx, viewport->yposition());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int gdBaseActionEditor::getActionType() const
 {
        if (actionType->value() == 0)
                return m::MidiEvent::NOTE_ON;
-       else
-       if (actionType->value() == 1)
+       else if (actionType->value() == 1)
                return m::MidiEvent::NOTE_OFF;
-       else
-       if (actionType->value() == 2)
+       else if (actionType->value() == 2)
                return m::MidiEvent::NOTE_KILL;
 
        assert(false);
        return -1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBaseActionEditor::prepareWindow()
 {
        u::gui::setFavicon(this);
 
        std::string l = "Action Editor";
-       if (m_data.channelName != "") l += " - " + m_data.channelName;
+       if (m_data.channelName != "")
+               l += " - " + m_data.channelName;
        copy_label(l.c_str());
 
        set_non_modal();
@@ -201,18 +183,18 @@ void gdBaseActionEditor::prepareWindow()
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int gdBaseActionEditor::handle(int e)
 {
-       switch (e) {
-               case FL_MOUSEWHEEL:
-                       Fl::event_dy() == -1 ? zoomIn() : zoomOut();
-                       return 1;
-               default:
-                       return Fl_Group::handle(e);
+       switch (e)
+       {
+       case FL_MOUSEWHEEL:
+               Fl::event_dy() == -1 ? zoomIn() : zoomOut();
+               return 1;
+       default:
+               return Fl_Group::handle(e);
        }
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index e92af912a31717cc5ae83a6239293fd87ebf4757..c76143d9425e41080429d78f74e21f6a4643c37f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BASE_ACTION_EDITOR_H
 #define GD_BASE_ACTION_EDITOR_H
 
-
 #include "core/types.h"
 #include "glue/actionEditor.h"
 #include "gui/dialogs/window.h"
 
-
 class geButton;
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 class Channel;
 struct Action;
-}
+} // namespace m
 namespace v
 {
 class geChoice;
@@ -51,14 +48,13 @@ class geScrollPack;
 class gdBaseActionEditor : public gdWindow
 {
 public:
-
        virtual ~gdBaseActionEditor();
 
        int handle(int e) override;
 
        Pixel frameToPixel(Frame f) const;
-       Frame pixelToFrame(Pixel p, bool snap=true) const;
-       int getActionType() const;
+       Frame pixelToFrame(Pixel p, bool snap = true) const;
+       int   getActionType() const;
 
        ID channelId;
 
@@ -66,14 +62,13 @@ public:
        geGridTool*   gridTool;
        geButton*     zoomInBtn;
        geButton*     zoomOutBtn;
-       geScrollPack* viewport;       // widget container
+       geScrollPack* viewport; // widget container
 
        float ratio;
-       Pixel fullWidth;     // Full widgets width, i.e. scaled-down full sequencer
-       Pixel loopWidth;         // Loop width, i.e. scaled-down sequencer range
-
-protected:
+       Pixel fullWidth; // Full widgets width, i.e. scaled-down full sequencer
+       Pixel loopWidth; // Loop width, i.e. scaled-down sequencer range
 
+  protected:
        static constexpr Pixel RESIZER_BAR_H = 20;
        static constexpr Pixel MIN_WIDGET_H  = 10;
        static constexpr float MIN_RATIO     = 25.0f;
@@ -81,11 +76,11 @@ protected:
 
        gdBaseActionEditor(ID channelId);
 
-       void zoomIn();
-       void zoomOut();
+       void        zoomIn();
+       void        zoomOut();
        static void cb_zoomIn(Fl_Widget* /*w*/, void* p);
        static void cb_zoomOut(Fl_Widget* /*w*/, void* p);
-       
+
        /* computeWidth
        Computes total width, in pixel. */
 
@@ -98,7 +93,7 @@ protected:
 
        c::actionEditor::Data m_data;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 6b5ec7f5b64001180211ac3c2f83dd94d7f37324..851e71639beba694e39de161d2ac05d2ea1624a9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <string>
+#include "midiActionEditor.h"
 #include "core/graphics.h"
 #include "glue/actionEditor.h"
 #include "glue/channel.h"
-#include "gui/elems/basics/scrollPack.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/resizerBar.h"
-#include "gui/elems/basics/box.h"
+#include "gui/elems/actionEditor/gridTool.h"
 #include "gui/elems/actionEditor/noteEditor.h"
-#include "gui/elems/actionEditor/velocityEditor.h"
 #include "gui/elems/actionEditor/pianoRoll.h"
-#include "gui/elems/actionEditor/gridTool.h"
-#include "midiActionEditor.h"
-
+#include "gui/elems/actionEditor/velocityEditor.h"
+#include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
+#include "gui/elems/basics/resizerBar.h"
+#include "gui/elems/basics/scrollPack.h"
+#include <string>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gdMidiActionEditor::gdMidiActionEditor(ID channelId)
@@ -51,31 +50,33 @@ gdMidiActionEditor::gdMidiActionEditor(ID channelId)
        computeWidth();
 
        gePack* upperArea = new gePack(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, Direction::HORIZONTAL);
-               gridTool   = new geGridTool(0, 0);
-               geBox* b1  = new geBox     (0, 0, w() - 150, G_GUI_UNIT);    // padding actionType - zoomButtons
-               zoomInBtn  = new geButton  (0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
-               zoomOutBtn = new geButton  (0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomOutOff_xpm, zoomOutOn_xpm);
-       upperArea->add(gridTool); 
-       upperArea->add(b1); 
-       upperArea->add(zoomInBtn); 
-       upperArea->add(zoomOutBtn); 
+       gridTool          = new geGridTool(0, 0);
+       geBox* b1         = new geBox(0, 0, w() - 150, G_GUI_UNIT); // padding actionType - zoomButtons
+       zoomInBtn         = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
+       zoomOutBtn        = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomOutOff_xpm, zoomOutOn_xpm);
+       upperArea->add(gridTool);
+       upperArea->add(b1);
+       upperArea->add(zoomInBtn);
+       upperArea->add(zoomOutBtn);
        upperArea->resizable(b1);
 
        /* Main viewport: contains all widgets. */
 
-       viewport = new geScrollPack(G_GUI_OUTER_MARGIN, upperArea->y() + upperArea->h() + G_GUI_OUTER_MARGIN, 
-               upperArea->w(), h()-44, Fl_Scroll::BOTH, Direction::VERTICAL, /*gutter=*/0);
-               m_ne  = new geNoteEditor    (0, 0, this);
-               m_ner = new geResizerBar    (0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
-               m_ve  = new geVelocityEditor(0, 0, this);
-               m_ver = new geResizerBar    (0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
+       viewport = new geScrollPack(G_GUI_OUTER_MARGIN, upperArea->y() + upperArea->h() + G_GUI_OUTER_MARGIN,
+           upperArea->w(), h() - 44, Fl_Scroll::BOTH, Direction::VERTICAL, /*gutter=*/0);
+       m_ne     = new geNoteEditor(0, 0, this);
+       m_ner    = new geResizerBar(0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
+       m_ve     = new geVelocityEditor(0, 0, this);
+       m_ver    = new geResizerBar(0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
        viewport->add(m_ne);
        viewport->add(m_ner);
        viewport->add(m_ve);
        viewport->add(m_ver);
 
        zoomInBtn->callback(cb_zoomIn, (void*)this);
+       zoomInBtn->copy_tooltip("Zoom in");
        zoomOutBtn->callback(cb_zoomOut, (void*)this);
+       zoomOutBtn->copy_tooltip("Zoom out");
 
        add(upperArea);
        add(viewport);
@@ -85,10 +86,8 @@ gdMidiActionEditor::gdMidiActionEditor(ID channelId)
        rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiActionEditor::rebuild()
 {
        m_data = c::actionEditor::getData(channelId);
@@ -99,4 +98,5 @@ void gdMidiActionEditor::rebuild()
        m_ve->rebuild(m_data);
        m_ver->size(m_ve->w(), m_ver->h());
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 47f3cf6b026d00e965d331476687773488db66c5..85390274d2a7c90b0ef974c2b68fbf428a10aa4c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_ACTION_EDITOR_H
 #define GD_MIDI_ACTION_EDITOR_H
 
-
 #include "baseActionEditor.h"
 
-
 class geResizerBar;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geNoteEditor;
@@ -44,20 +41,18 @@ class geVelocityEditor;
 class gdMidiActionEditor : public gdBaseActionEditor
 {
 public:
+       gdMidiActionEditor(ID channelId);
 
-    gdMidiActionEditor(ID channelId);
-
-    void rebuild() override;
+       void rebuild() override;
 
-private:
-
-    geNoteEditor*     m_ne;
-       geResizerBar*     m_ner;
+  private:
+       geNoteEditor* m_ne;
+       geResizerBar* m_ner;
 
        geVelocityEditor* m_ve;
-    geResizerBar*     m_ver;
+       geResizerBar*     m_ver;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 6b47af2389c4166a0fcd773ca7f7175753f385b0..a6aea68819a3de724ade8e3e454289dd49c85192 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <string>
-#include "core/model/model.h"
+#include "gui/elems/actionEditor/sampleActionEditor.h"
 #include "core/const.h"
-#include "core/midiEvent.h"
 #include "core/graphics.h"
+#include "core/midiEvent.h"
+#include "core/model/model.h"
 #include "glue/actionEditor.h"
 #include "glue/channel.h"
-#include "gui/elems/basics/pack.h"
-#include "gui/elems/basics/scrollPack.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/resizerBar.h"
-#include "gui/elems/basics/choice.h"
-#include "gui/elems/basics/box.h"
-#include "gui/elems/actionEditor/sampleActionEditor.h"
 #include "gui/elems/actionEditor/envelopeEditor.h"
 #include "gui/elems/actionEditor/gridTool.h"
+#include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
+#include "gui/elems/basics/choice.h"
+#include "gui/elems/basics/pack.h"
+#include "gui/elems/basics/resizerBar.h"
+#include "gui/elems/basics/scrollPack.h"
 #include "sampleActionEditor.h"
+#include <string>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gdSampleActionEditor::gdSampleActionEditor(ID channelId)
@@ -58,11 +57,11 @@ gdSampleActionEditor::gdSampleActionEditor(ID channelId)
        resizable boxes: |[--b1--][actionType][--b2--][+][-]| */
 
        gePack* upperArea = new gePack(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, Direction::HORIZONTAL);
-               actionType = new geChoice  (0, 0, 80, 20);
-               gridTool   = new geGridTool(0, 0);
-               geBox* b1  = new geBox     (0, 0, w() - 232, 20);    // padding actionType - zoomButtons
-               zoomInBtn  = new geButton  (0, 0, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
-               zoomOutBtn = new geButton  (0, 0, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
+       actionType        = new geChoice(0, 0, 80, 20);
+       gridTool          = new geGridTool(0, 0);
+       geBox* b1         = new geBox(0, 0, w() - 232, 20); // padding actionType - zoomButtons
+       zoomInBtn         = new geButton(0, 0, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm);
+       zoomOutBtn        = new geButton(0, 0, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm);
        upperArea->add(actionType);
        upperArea->add(gridTool);
        upperArea->add(b1);
@@ -74,20 +73,23 @@ gdSampleActionEditor::gdSampleActionEditor(ID channelId)
        actionType->add("Key release");
        actionType->add("Kill chan");
        actionType->value(0);
+       actionType->copy_tooltip("Action type to add");
        if (!canChangeActionType())
                actionType->deactivate();
 
        zoomInBtn->callback(cb_zoomIn, (void*)this);
+       zoomInBtn->copy_tooltip("Zoom in");
        zoomOutBtn->callback(cb_zoomOut, (void*)this);
+       zoomOutBtn->copy_tooltip("Zoom out");
 
        /* Main viewport: contains all widgets. */
 
-       viewport = new geScrollPack(G_GUI_OUTER_MARGIN, upperArea->y() + upperArea->h() + G_GUI_OUTER_MARGIN, 
-               upperArea->w(), h()-44, Fl_Scroll::BOTH, Direction::VERTICAL, /*gutter=*/0);
-               m_ae  = new geSampleActionEditor(0, 0, this);
-               m_aer = new geResizerBar        (0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);     
-               m_ee  = new geEnvelopeEditor    (0, 0, "volume", this);
-               m_eer = new geResizerBar        (0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
+       viewport = new geScrollPack(G_GUI_OUTER_MARGIN, upperArea->y() + upperArea->h() + G_GUI_OUTER_MARGIN,
+           upperArea->w(), h() - 44, Fl_Scroll::BOTH, Direction::VERTICAL, /*gutter=*/0);
+       m_ae     = new geSampleActionEditor(0, 0, this);
+       m_aer    = new geResizerBar(0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
+       m_ee     = new geEnvelopeEditor(0, 0, "volume", this);
+       m_eer    = new geResizerBar(0, 0, viewport->w(), RESIZER_BAR_H, MIN_WIDGET_H, geResizerBar::VERTICAL);
        viewport->add(m_ae);
        viewport->add(m_aer);
        viewport->add(m_ee);
@@ -101,30 +103,27 @@ gdSampleActionEditor::gdSampleActionEditor(ID channelId)
        rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool gdSampleActionEditor::canChangeActionType()
 {
-       return m_data.sample->channelMode != SamplePlayerMode::SINGLE_PRESS && 
+       return m_data.sample->channelMode != SamplePlayerMode::SINGLE_PRESS &&
               m_data.sample->isLoopMode == false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleActionEditor::rebuild()
 {
        m_data = c::actionEditor::getData(channelId);
 
-       canChangeActionType() ? actionType->activate() : actionType->deactivate(); 
+       canChangeActionType() ? actionType->activate() : actionType->deactivate();
        computeWidth();
-       
+
        m_ae->rebuild(m_data);
        m_aer->size(m_ae->w(), m_aer->h());
-       m_ee->rebuild(m_data);  
+       m_ee->rebuild(m_data);
        m_eer->size(m_ee->w(), m_eer->h());
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 6f47840bed10c5c097c64ec9779e65390cb15c79..03d167b4e5300495197116c04df48f78f5636154 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_SAMPLE_ACTION_EDITOR_H
 #define GD_SAMPLE_ACTION_EDITOR_H
 
-
 #include "baseActionEditor.h"
 
-
 class geResizerBar;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geSampleActionEditor;
 class geEnvelopeEditor;
 class gdSampleActionEditor : public gdBaseActionEditor
-{  
+{
 public:
+       gdSampleActionEditor(ID channelId);
 
-    gdSampleActionEditor(ID channelId);
-
-    void rebuild() override;
-
-private:
+       void rebuild() override;
 
+  private:
        bool canChangeActionType();
 
        geSampleActionEditor* m_ae;
-    geResizerBar*         m_aer;
+       geResizerBar*         m_aer;
 
-       geEnvelopeEditor*     m_ee;
-    geResizerBar*         m_eer;
+       geEnvelopeEditor* m_ee;
+       geResizerBar*     m_eer;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 19cf64f69894008e1afe6144337e6824b36c11e6..e022b89ca01b72e5ef3e1ab2f907ede15cb1d206 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cstring>
-#include "utils/gui.h"
-#include "utils/string.h"
-#include "core/mixer.h"
+#include "beatsInput.h"
 #include "core/clock.h"
 #include "core/conf.h"
 #include "core/const.h"
+#include "core/mixer.h"
 #include "glue/main.h"
-#include "gui/elems/basics/input.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
-#include "beatsInput.h"
+#include "gui/elems/basics/input.h"
 #include "mainWindow.h"
-
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <cstring>
 
 extern giada::v::gdMainWindow* mainWin;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdBeatsInput::gdBeatsInput()
 : gdWindow(u::gui::centerWindowX(180), u::gui::centerWindowY(36), 180, 36, "Beats")
 {
        set_modal();
 
-       beats = new geInput(8,  8,  43, G_GUI_UNIT);
-       bars  = new geInput(beats->x()+beats->w()+4, 8,  43, G_GUI_UNIT);
-       ok        = new geButton(bars->x()+bars->w()+4, 8,  70, G_GUI_UNIT, "Ok");
+       beats = new geInput(8, 8, 43, G_GUI_UNIT);
+       bars  = new geInput(beats->x() + beats->w() + 4, 8, 43, G_GUI_UNIT);
+       ok    = new geButton(bars->x() + bars->w() + 4, 8, 70, G_GUI_UNIT, "Ok");
        end();
 
        beats->maximum_size(2);
        beats->value(std::to_string(m::clock::getBeats()).c_str());
        beats->type(FL_INT_INPUT);
-       
+
        bars->maximum_size(2);
        bars->value(std::to_string(m::clock::getBars()).c_str());
        bars->type(FL_INT_INPUT);
-       
+
        ok->shortcut(FL_Enter);
        ok->callback(cb_update, (void*)this);
 
@@ -72,16 +70,12 @@ gdBeatsInput::gdBeatsInput()
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBeatsInput::cb_update(Fl_Widget* /*w*/, void* p) { ((gdBeatsInput*)p)->cb_update(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBeatsInput::cb_update()
 {
        if (!strcmp(beats->value(), "") || !strcmp(bars->value(), ""))
@@ -90,4 +84,5 @@ void gdBeatsInput::cb_update()
        do_callback();
 }
 
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 0126c79f753482cb6ab4ca2959051a6403ce38ce..5cae21cf94f0a3551f2a7446aefed66860781ca4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BEATSINPUT_H
 #define GD_BEATSINPUT_H
 
-
 #include "window.h"
 
-
 class geInput;
 class geButton;
 class geCheck;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class gdBeatsInput : public gdWindow
 {
 public:
+       gdBeatsInput();
 
-    gdBeatsInput();
-
-private:
-
+  private:
        static void cb_update(Fl_Widget* /*w*/, void* p);
-       void cb_update();
+       void        cb_update();
 
-       geInput* beats;
-       geInput* bars;
+       geInput*  beats;
+       geInput*  bars;
        geButton* ok;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index cede7f56c6e55e742e9b070c5ebca664b1acbcd8..5c076390fecf95edd74d989bd314ce5c546b3e94 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cstring>
+#include "bpmInput.h"
+#include "core/clock.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/mixer.h"
-#include "core/clock.h"
 #include "glue/main.h"
-#include "utils/gui.h"
-#include "utils/string.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
-#include "bpmInput.h"
 #include "mainWindow.h"
-
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <cstring>
 
 extern giada::v::gdMainWindow* mainWin;
 
-
-namespace giada {
-namespace v 
+namespace giada::v
 {
 gdBpmInput::gdBpmInput(const char* label)
 : gdWindow(u::gui::centerWindowX(144), u::gui::centerWindowY(36), 144, 36, "Bpm")
 {
        set_modal();
 
-       input_a = new geInput(8,  8, 30, G_GUI_UNIT);
+       input_a = new geInput(8, 8, 30, G_GUI_UNIT);
        input_b = new geInput(42, 8, 20, G_GUI_UNIT);
-       ok              = new geButton(66, 8, 70, G_GUI_UNIT, "Ok");
+       ok      = new geButton(66, 8, 70, G_GUI_UNIT, "Ok");
        end();
 
+       std::vector<std::string> parts = u::string::split(label, ".");
+
        input_a->maximum_size(3);
        input_a->type(FL_INT_INPUT);
-       input_a->value(u::string::fToString(m::clock::getBpm(), 0).c_str());
+       input_a->value(parts[0].c_str());
 
-       /* Use the decimal value from the string label. */
-
-       std::vector<std::string> tokens = u::string::split(label, ".");
-       
        input_b->maximum_size(1);
        input_b->type(FL_INT_INPUT);
-       input_b->value(tokens[1].c_str());
+       input_b->value(parts[1].c_str());
 
        ok->shortcut(FL_Enter);
        ok->callback(cb_update, (void*)this);
@@ -75,16 +69,12 @@ gdBpmInput::gdBpmInput(const char* label)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBpmInput::cb_update(Fl_Widget* /*w*/, void* p) { ((gdBpmInput*)p)->cb_update(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBpmInput::cb_update()
 {
        if (strcmp(input_a->value(), "") == 0)
@@ -92,6 +82,4 @@ void gdBpmInput::cb_update()
        c::main::setBpm(input_a->value(), input_b->value());
        do_callback();
 }
-
-
-}} // giada::v::
\ No newline at end of file
+} // namespace giada::v
\ No newline at end of file
index e9465d1f094050057dbfb34c9f0cb0e3b2724fbe..5dde87dac89a3eeedde0284cfb60747ee0ae8e67 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BPMINPUT_H
 #define GD_BPMINPUT_H
 
-
 #include "window.h"
 
-
 class geInput;
 class geButton;
 
-
-namespace giada {
-namespace v 
+namespace giada::v
 {
 class gdBpmInput : public gdWindow
 {
 public:
-
        gdBpmInput(const char* label); // pointer to mainWin->timing->bpm->label()
 
 private:
+       static void cb_update(Fl_Widget* /*w*/, void* p);
+       void        cb_update();
 
-    static void cb_update(Fl_Widget* /*w*/, void* p);
-    void cb_update();
-
-    geInput* input_a;
-    geInput* input_b;
-    geButton* ok;
+       geInput*  input_a;
+       geInput*  input_b;
+       geButton* ok;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 81928d029603b07c78f01b5de32b8ad41158bab9..90c4fa41419ef0451d884de81f115a5630ea0225 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/graphics.h"
+#include "browserBase.h"
 #include "core/conf.h"
 #include "core/const.h"
-#include "utils/gui.h"
-#include "utils/fs.h"
-#include "gui/elems/browser.h"
+#include "core/graphics.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/check.h"
 #include "gui/elems/basics/input.h"
 #include "gui/elems/basics/progress.h"
-#include "gui/elems/basics/check.h"
-#include "browserBase.h"
-
+#include "gui/elems/browser.h"
+#include "utils/fs.h"
+#include "utils/gui.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
-gdBrowserBase::gdBrowserBase(const std::string& title, const std::string& path, 
-       std::function<void(void*)> callback, ID channelId)
-: gdWindow   (m::conf::conf.browserX, m::conf::conf.browserY, m::conf::conf.browserW, 
-                 m::conf::conf.browserH, title.c_str()),
-  m_callback (callback),
-  m_channelId(channelId)
+gdBrowserBase::gdBrowserBase(const std::string& title, const std::string& path,
+    std::function<void(void*)> callback, ID channelId)
+: gdWindow(m::conf::conf.browserX, m::conf::conf.browserY, m::conf::conf.browserW,
+      m::conf::conf.browserH, title.c_str())
+, m_callback(callback)
+, m_channelId(channelId)
 {
        set_non_modal();
 
-       groupTop = new Fl_Group(8, 8, w()-16, 48);
-    hiddenFiles = new geCheck(groupTop->x(), groupTop->y(), 400, 20, "Show hidden files");
-               where   = new geInput(groupTop->x(), hiddenFiles->y()+hiddenFiles->h()+8, 20, 20);
-               updir   = new geButton(groupTop->x()+groupTop->w()-20, where->y(), 20, 20, "", updirOff_xpm, updirOn_xpm);
+       groupTop    = new Fl_Group(8, 8, w() - 16, 48);
+       hiddenFiles = new geCheck(groupTop->x(), groupTop->y(), 400, 20, "Show hidden files");
+       where       = new geInput(groupTop->x(), hiddenFiles->y() + hiddenFiles->h() + 8, 20, 20);
+       updir       = new geButton(groupTop->x() + groupTop->w() - 20, where->y(), 20, 20, "", updirOff_xpm, updirOn_xpm);
        groupTop->end();
        groupTop->resizable(where);
 
-       hiddenFiles->callback(cb_toggleHiddenFiles, (void*) this);
+       hiddenFiles->callback(cb_toggleHiddenFiles, (void*)this);
 
        where->readonly(true);
        where->cursor_color(G_COLOR_BLACK);
        where->value(path.c_str());
 
-       updir->callback(cb_up, (void*) this);
+       updir->callback(cb_up, (void*)this);
 
-       browser = new geBrowser(8, groupTop->y()+groupTop->h()+8, w()-16, h()-101);
+       browser = new geBrowser(8, groupTop->y() + groupTop->h() + 8, w() - 16, h() - 101);
        browser->loadDir(path);
        if (path == m::conf::conf.browserLastPath)
                browser->preselect(m::conf::conf.browserPosition, m::conf::conf.browserLastValue);
 
-       Fl_Group* groupButtons = new Fl_Group(8, browser->y()+browser->h()+8, w()-16, 20);
-               ok      = new geButton(w()-88, groupButtons->y(), 80, 20);
-               cancel  = new geButton(w()-ok->w()-96, groupButtons->y(), 80, 20, "Cancel");
-               status  = new geProgress(8, groupButtons->y(), cancel->x()-16, 20);
-               status->minimum(0);
-               status->maximum(1);
-               status->hide();   // show the bar only if necessary
+       Fl_Group* groupButtons = new Fl_Group(8, browser->y() + browser->h() + 8, w() - 16, 20);
+       ok                     = new geButton(w() - 88, groupButtons->y(), 80, 20);
+       cancel                 = new geButton(w() - ok->w() - 96, groupButtons->y(), 80, 20, "Cancel");
+       status                 = new geProgress(8, groupButtons->y(), cancel->x() - 16, 20);
+       status->minimum(0);
+       status->maximum(1);
+       status->hide(); // show the bar only if necessary
        groupButtons->resizable(status);
        groupButtons->end();
 
        end();
 
-       cancel->callback(cb_close, (void*) this);
+       cancel->callback(cb_close, (void*)this);
 
        resizable(browser);
        size_range(320, 200);
@@ -91,113 +90,92 @@ gdBrowserBase::gdBrowserBase(const std::string& title, const std::string& path,
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdBrowserBase::~gdBrowserBase()
 {
-       m::conf::conf.browserX = x();
-       m::conf::conf.browserY = y();
-       m::conf::conf.browserW = w();
-       m::conf::conf.browserH = h();
+       m::conf::conf.browserX         = x();
+       m::conf::conf.browserY         = y();
+       m::conf::conf.browserW         = w();
+       m::conf::conf.browserH         = h();
        m::conf::conf.browserPosition  = browser->position();
        m::conf::conf.browserLastPath  = browser->getCurrentDir();
        m::conf::conf.browserLastValue = browser->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::cb_up(Fl_Widget* /*v*/, void* p) { ((gdBrowserBase*)p)->cb_up(); }
 void gdBrowserBase::cb_close(Fl_Widget* /*v*/, void* p) { ((gdBrowserBase*)p)->cb_close(); }
 void gdBrowserBase::cb_toggleHiddenFiles(Fl_Widget* /*v*/, void* p) { ((gdBrowserBase*)p)->cb_toggleHiddenFiles(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::cb_up()
 {
        browser->loadDir(u::fs::getUpDir(browser->getCurrentDir()));
        where->value(browser->getCurrentDir().c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::cb_close()
 {
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::cb_toggleHiddenFiles()
 {
        browser->toggleHiddenFiles();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::setStatusBar(float v)
 {
        status->value(status->value() + v);
        Fl::wait(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::showStatusBar()
 {
        status->show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::hideStatusBar()
 {
        status->hide();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-std::string gdBrowserBase::getCurrentPath() const 
-{ 
-       return where->value(); 
+std::string gdBrowserBase::getCurrentPath() const
+{
+       return where->value();
 }
 
-
-ID gdBrowserBase::getChannelId() const 
-{ 
-       return m_channelId; 
+ID gdBrowserBase::getChannelId() const
+{
+       return m_channelId;
 }
 
-
-std::string gdBrowserBase::getSelectedItem() const 
+std::string gdBrowserBase::getSelectedItem() const
 {
        return browser->getSelectedItem();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserBase::fireCallback() const
-{ 
+{
        m_callback((void*)this);
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 83a1b275058cc1b86413d2fba8e1c3baaa3e20dd..4781d732275214f49fb5ac29eab548ad56eb29eb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BROWSER_BASE_H
 #define GD_BROWSER_BASE_H
 
-
-#include<functional>
-#include "gui/dialogs/window.h"
 #include "core/types.h"
-
+#include "gui/dialogs/window.h"
+#include <functional>
+#include <string>
 
 class Fl_Group;
 class geCheck;
-class geBrowser;
 class geButton;
 class geInput;
 class geProgress;
 
-
-namespace giada {
-namespace m 
-{ 
-class Channel; 
+namespace giada
+{
+namespace m
+{
+class Channel;
 }
 namespace v
 {
+class geBrowser;
 class gdBrowserBase : public gdWindow
 {
 public:
-
        ~gdBrowserBase();
 
        /* getSelectedItem
@@ -61,9 +58,9 @@ public:
        std::string getSelectedItem() const;
 
        std::string getCurrentPath() const;
-       ID getChannelId() const;
-       void fireCallback() const;
-       
+       ID          getChannelId() const;
+       void        fireCallback() const;
+
        /* setStatusBar
        Increments status bar for progress tracking. */
 
@@ -72,17 +69,16 @@ public:
        void showStatusBar();
        void hideStatusBar();
 
-protected:
-
-       gdBrowserBase(const std::string& title, const std::string& path, 
-               std::function<void(void*)> f, ID channelId);
+  protected:
+       gdBrowserBase(const std::string& title, const std::string& path,
+           std::function<void(void*)> f, ID channelId);
 
        static void cb_up(Fl_Widget* /*w*/, void* p);
        static void cb_close(Fl_Widget* /*w*/, void* p);
        static void cb_toggleHiddenFiles(Fl_Widget* /*w*/, void* p);
-       void cb_up();
-       void cb_close();
-       void cb_toggleHiddenFiles();
+       void        cb_up();
+       void        cb_close();
+       void        cb_toggleHiddenFiles();
 
        /* m_callback
        Fired when the save/load button is pressed. */
@@ -100,7 +96,7 @@ protected:
        geButton*   updir;
        geProgress* status;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 4ba2f455139d1e757d479b7e4a601798e8dc6c8f..6b2a1fb1136e2569c015a05211a19735013922e4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "utils/fs.h"
-#include "gui/elems/browser.h"
+#include "browserDir.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
-#include "browserDir.h"
-
+#include "gui/elems/browser.h"
+#include "utils/fs.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
-gdBrowserDir::gdBrowserDir(const std::string& title, const std::string& path, 
-       std::function<void(void*)> cb)
+gdBrowserDir::gdBrowserDir(const std::string& title, const std::string& path,
+    std::function<void(void*)> cb)
 : gdBrowserBase(title, path, cb, 0)
 {
-       where->size(groupTop->w()-updir->w()-8, 20);
+       where->size(groupTop->w() - updir->w() - 8, 20);
 
-       browser->callback(cb_down, (void*) this);
+       browser->callback(cb_down, (void*)this);
 
        ok->label("Select");
-       ok->callback(cb_load, (void*) this);
+       ok->callback(cb_load, (void*)this);
        ok->shortcut(FL_ENTER);
 
        /* On OS X the 'where' input doesn't get resized properly on startup. Let's 
        force it. */
-       
+
        where->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserDir::cb_load(Fl_Widget* /*v*/, void* p) { ((gdBrowserDir*)p)->cb_load(); }
 void gdBrowserDir::cb_down(Fl_Widget* /*v*/, void* p) { ((gdBrowserDir*)p)->cb_down(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserDir::cb_load()
 {
        fireCallback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserDir::cb_down()
 {
        std::string path = browser->getSelectedItem();
@@ -84,4 +77,5 @@ void gdBrowserDir::cb_down()
        where->value(browser->getCurrentDir().c_str());
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 77b9ecc97aee7806d5dd741cc87dcb8baa397613..cc140206d0ae694171ff8d7f01c69611dfafb273 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BROWSER_DIR_H
 #define GD_BROWSER_DIR_H
 
-
 #include "browserBase.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class gdBrowserDir : public gdBrowserBase
 {
 public:
-
-       gdBrowserDir(const std::string& title, const std::string& path, 
-        std::function<void(void*)> cb);
-
-private:
-
-    static void cb_load(Fl_Widget* /*w*/, void* p);
-    static void cb_down(Fl_Widget* /*w*/, void* p);
-    void cb_load();
-    void cb_down();
+       gdBrowserDir(const std::string& title, const std::string& path,
+           std::function<void(void*)> cb);
+
+  private:
+       static void cb_load(Fl_Widget* /*w*/, void* p);
+       static void cb_down(Fl_Widget* /*w*/, void* p);
+       void        cb_load();
+       void        cb_down();
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 211d3f2bfe119e359fe1b6069174b5c7b111c895..edaa07d0cd14db5346f8dc8ff6fe396798b00b5d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "utils/fs.h"
-#include "gui/elems/browser.h"
+#include "browserLoad.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
-#include "browserLoad.h"
-
+#include "gui/elems/browser.h"
+#include "utils/fs.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
-gdBrowserLoad::gdBrowserLoad(const std::string& title, const std::string& path, 
-       std::function<void(void*)> cb, ID channelId)
+gdBrowserLoad::gdBrowserLoad(const std::string& title, const std::string& path,
+    std::function<void(void*)> cb, ID channelId)
 : gdBrowserBase(title, path, cb, channelId)
 {
-       where->size(groupTop->w()-updir->w()-8, 20);
+       where->size(groupTop->w() - updir->w() - 8, 20);
 
-       browser->callback(cb_down, (void*) this);
+       browser->callback(cb_down, (void*)this);
 
        ok->label("Load");
-       ok->callback(cb_load, (void*) this);
+       ok->callback(cb_load, (void*)this);
        ok->shortcut(FL_ENTER);
 
        /* On OS X the 'where' input doesn't get resized properly on startup. Let's 
        force it. */
-       
+
        where->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserLoad::cb_load(Fl_Widget* /*v*/, void* p) { ((gdBrowserLoad*)p)->cb_load(); }
 void gdBrowserLoad::cb_down(Fl_Widget* /*v*/, void* p) { ((gdBrowserLoad*)p)->cb_down(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserLoad::cb_load()
 {
        fireCallback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserLoad::cb_down()
 {
        std::string path = browser->getSelectedItem();
@@ -84,4 +77,5 @@ void gdBrowserLoad::cb_down()
        where->value(browser->getCurrentDir().c_str());
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 39dfef57495bc3f176def60468a9750054f5d7e5..3c6070a29f68d89191d30e0fa9e8aa62c262582a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BROWSER_LOAD_H
 #define GD_BROWSER_LOAD_H
 
-
 #include "browserBase.h"
 
-
-namespace giada {
-namespace m 
-{ 
-class Channel; 
+namespace giada
+{
+namespace m
+{
+class Channel;
 }
 namespace v
 {
 class gdBrowserLoad : public gdBrowserBase
 {
 public:
+       gdBrowserLoad(const std::string& title, const std::string& path,
+           std::function<void(void*)> cb, ID channelId);
 
-    gdBrowserLoad(const std::string& title, const std::string& path, 
-        std::function<void(void*)> cb, ID channelId);
-
-private:
-
+  private:
        static void cb_load(Fl_Widget* /*w*/, void* p);
        static void cb_down(Fl_Widget* /*w*/, void* p);
-       void cb_load();
-       void cb_down();
+       void        cb_load();
+       void        cb_down();
 };
-}} // giada::v::
+} // namespace v
+} // namespace giada
 
 #endif
index 2462672e870b712d76a629c8b080c2293632aa1b..bfcf3fe875467598a69eace082bb37675e083192 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "utils/fs.h"
-#include "gui/elems/browser.h"
+#include "browserSave.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
-#include "browserSave.h"
-
+#include "gui/elems/browser.h"
+#include "utils/fs.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
-gdBrowserSave::gdBrowserSave(const std::string& title, const std::string& path, 
-       const std::string& name_, std::function<void(void*)> cb, ID channelId)
+gdBrowserSave::gdBrowserSave(const std::string& title, const std::string& path,
+    const std::string& name_, std::function<void(void*)> cb, ID channelId)
 : gdBrowserBase(title, path, cb, channelId)
 {
-       where->size(groupTop->w()-236, 20);
+       where->size(groupTop->w() - 236, 20);
 
-       name = new geInput(where->x()+where->w()+8, where->y(), 200, 20);
+       name = new geInput(where->x() + where->w() + 8, where->y(), 200, 20);
        name->value(name_.c_str());
        groupTop->add(name);
 
-       browser->callback(cb_down, (void*) this);
+       browser->callback(cb_down, (void*)this);
 
        ok->label("Save");
-       ok->callback(cb_save, (void*) this);
+       ok->callback(cb_save, (void*)this);
        ok->shortcut(FL_ENTER);
 
        /* On OS X the 'where' and 'name' inputs don't get resized properly on startup. 
@@ -58,28 +57,25 @@ gdBrowserSave::gdBrowserSave(const std::string& title, const std::string& path,
        name->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserSave::cb_save(Fl_Widget* /*v*/, void* p) { ((gdBrowserSave*)p)->cb_save(); }
 void gdBrowserSave::cb_down(Fl_Widget* /*v*/, void* p) { ((gdBrowserSave*)p)->cb_down(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserSave::cb_down()
 {
        std::string path = browser->getSelectedItem();
 
-       if (path.empty())  // when click on an empty area
+       if (path.empty()) // when click on an empty area
                return;
 
        /* if the selected item is a directory just load its content. If it's a file
         * use it as the file name (i.e. fill name->value()). */
 
-       if (u::fs::isDir(path)) {
+       if (u::fs::isDir(path))
+       {
                browser->loadDir(path);
                where->value(browser->getCurrentDir().c_str());
        }
@@ -87,22 +83,19 @@ void gdBrowserSave::cb_down()
                name->value(browser->getSelectedItem(false).c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string gdBrowserSave::getName() const
 {
-  return name->value();
+       return name->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdBrowserSave::cb_save()
 {
        fireCallback();
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index f6a88420e33103f0facdea945f922c64d52ab180..92f334240c86177562b31dacd8ecbb307eb3c848 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_BROWSER_SAVE_H
 #define GD_BROWSER_SAVE_H
 
-
 #include "browserBase.h"
 
-
 class geInput;
 
-
-namespace giada {
-namespace m 
-{ 
-class Channel; 
+namespace giada
+{
+namespace m
+{
+class Channel;
 }
 namespace v
 {
 class gdBrowserSave : public gdBrowserBase
 {
 public:
-
-       gdBrowserSave(const std::string& title, const std::string& path, 
-        const std::string& name, std::function<void(void*)> cb, 
-        ID channelId);
+       gdBrowserSave(const std::string& title, const std::string& path,
+           const std::string& name, std::function<void(void*)> cb,
+           ID channelId);
 
        std::string getName() const;
 
-private:
+  private:
+       geInput* name;
 
-    geInput* name;
-
-    static void cb_down(Fl_Widget* /*w*/, void* p);
-    static void cb_save(Fl_Widget* /*w*/, void* p);
-    void cb_down();
-    void cb_save();
+       static void cb_down(Fl_Widget* /*w*/, void* p);
+       static void cb_save(Fl_Widget* /*w*/, void* p);
+       void        cb_down();
+       void        cb_save();
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 5bad36660173f33f0f9b03e48f92036a848baaf3..f5f2d07313ad0357a5db5d371d37d111a65ffe0b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "glue/channel.h"
-#include "utils/gui.h"
-#include "core/model/model.h"
-#include "core/const.h"
+#include "channelNameInput.h"
 #include "core/conf.h"
+#include "core/const.h"
+#include "core/model/model.h"
+#include "glue/channel.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/input.h"
-#include "channelNameInput.h"
-
-
+#include "utils/gui.h"
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdChannelNameInput::gdChannelNameInput(const c::channel::Data& d)
-: gdWindow(u::gui::centerWindowX(400), u::gui::centerWindowY(64), 400, 64, "New channel name"),
-  m_data  (d)
+: gdWindow(u::gui::centerWindowX(400), u::gui::centerWindowY(64), 400, 64, "New channel name")
+, m_data(d)
 {
        set_modal();
 
        m_name   = new geInput(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w() - (G_GUI_OUTER_MARGIN * 2), G_GUI_UNIT);
-       m_ok     = new geButton(w() - 70 - G_GUI_OUTER_MARGIN, m_name->y()+m_name->h() + G_GUI_OUTER_MARGIN, 70, G_GUI_UNIT, "Ok");
+       m_ok     = new geButton(w() - 70 - G_GUI_OUTER_MARGIN, m_name->y() + m_name->h() + G_GUI_OUTER_MARGIN, 70, G_GUI_UNIT, "Ok");
        m_cancel = new geButton(m_ok->x() - 70 - G_GUI_OUTER_MARGIN, m_ok->y(), 70, G_GUI_UNIT, "Cancel");
        end();
 
@@ -62,30 +60,25 @@ gdChannelNameInput::gdChannelNameInput(const c::channel::Data& d)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdChannelNameInput::cb_update(Fl_Widget* /*w*/, void* p) { ((gdChannelNameInput*)p)->cb_update(); }
 void gdChannelNameInput::cb_cancel(Fl_Widget* /*w*/, void* p) { ((gdChannelNameInput*)p)->cb_cancel(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdChannelNameInput::cb_cancel()
 {
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdChannelNameInput::cb_update()
 {
        c::channel::setName(m_data.id, m_name->value());
        do_callback();
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 7f3616720dc35c97be64d56826a6a981cb6a3e15..6325c9e72603be2c8a0c8634f4fde0a502d4b536 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_CHANNEL_NAME_INPUT_H
 #define GD_CHANNEL_NAME_INPUT_H
 
-
 #include "window.h"
 
-
 class geInput;
 class geButton;
 
-
-namespace giada {
-namespace v 
+namespace giada::c::channel
+{
+struct Data;
+}
+namespace giada::v
 {
 class gdChannelNameInput : public gdWindow
 {
 public:
-
        gdChannelNameInput(const c::channel::Data& d);
 
-private:
-
+  private:
        static void cb_update(Fl_Widget* /*w*/, void* p);
        static void cb_cancel(Fl_Widget* /*w*/, void* p);
-       void cb_update();
-       void cb_cancel();
+       void        cb_update();
+       void        cb_cancel();
 
        const c::channel::Data& m_data;
 
@@ -58,7 +55,6 @@ private:
        geButton* m_ok;
        geButton* m_cancel;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 8ade6b2423e133689a9dbc80887fb572fa303f07..f1933f1dc1e6f907181b56edc643e25d1ca3266d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Tabs.H>
+#include "config.h"
 #include "core/conf.h"
 #include "core/const.h"
-#include "utils/gui.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/config/tabMisc.h"
-#include "gui/elems/config/tabMidi.h"
 #include "gui/elems/config/tabAudio.h"
 #include "gui/elems/config/tabBehaviors.h"
+#include "gui/elems/config/tabMidi.h"
+#include "gui/elems/config/tabMisc.h"
 #include "gui/elems/config/tabPlugins.h"
-#include "config.h"
-
+#include "utils/gui.h"
+#include <FL/Fl_Tabs.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdConfig::gdConfig(int w, int h)
 : gdWindow(u::gui::centerWindowX(w), u::gui::centerWindowY(h), w, h, "Configuration")
 {
-       Fl_Tabs* tabs = new Fl_Tabs(8, 8, w-16, h-44);
+       Fl_Tabs* tabs = new Fl_Tabs(8, 8, w - 16, h - 44);
        tabs->box(G_CUSTOM_BORDER_BOX);
        tabs->labelcolor(G_COLOR_LIGHT_2);
        tabs->begin();
 
-               tabAudio     = new geTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-               tabMidi      = new geTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-               tabBehaviors = new geTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
-               tabMisc      = new geTabMisc(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+       tabAudio     = new geTabAudio(tabs->x() + 10, tabs->y() + 20, tabs->w() - 20, tabs->h() - 40);
+       tabMidi      = new geTabMidi(tabs->x() + 10, tabs->y() + 20, tabs->w() - 20, tabs->h() - 40);
+       tabBehaviors = new geTabBehaviors(tabs->x() + 10, tabs->y() + 20, tabs->w() - 20, tabs->h() - 40);
+       tabMisc      = new geTabMisc(tabs->x() + 10, tabs->y() + 20, tabs->w() - 20, tabs->h() - 40);
 #ifdef WITH_VST
-               tabPlugins   = new geTabPlugins(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40);
+       tabPlugins = new geTabPlugins(tabs->x() + 10, tabs->y() + 20, tabs->w() - 20, tabs->h() - 40);
 #endif
 
        tabs->end();
 
-       save   = new geButton (w-88, h-28, 80, 20, "Save");
-       cancel = new geButton (w-176, h-28, 80, 20, "Cancel");
+       save   = new geButton(w - 88, h - 28, 80, 20, "Save");
+       cancel = new geButton(w - 176, h - 28, 80, 20, "Cancel");
 
        end();
 
@@ -73,17 +72,13 @@ gdConfig::gdConfig(int w, int h)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdConfig::cb_save_config(Fl_Widget* /*w*/, void* p) { ((gdConfig*)p)->cb_save_config(); }
-void gdConfig::cb_cancel     (Fl_Widget* /*w*/, void* p) { ((gdConfig*)p)->cb_cancel(); }
-
+void gdConfig::cb_cancel(Fl_Widget* /*w*/, void* p) { ((gdConfig*)p)->cb_cancel(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void gdConfig::cb_save_config()
 {
        tabAudio->save();
@@ -96,16 +91,13 @@ void gdConfig::cb_save_config()
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdConfig::cb_cancel()
 {
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 #ifdef WITH_VST
@@ -117,4 +109,5 @@ void gdConfig::refreshVstPath()
 
 #endif
 
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 003b3d26ca8ffd39c1f2f4c23629c7034107252c..041016245bea99e918d027c735d232bf178cd9e2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_CONFIG_H
 #define GD_CONFIG_H
 
-
 #include "window.h"
 
+class geButton;
+class geCheck;
+class geInput;
+class geBox;
 
+namespace giada
+{
+namespace v
+{
+class geChoice;
 class geTabAudio;
 class geTabBehaviors;
 class geTabMidi;
@@ -39,21 +46,9 @@ class geTabMisc;
 #ifdef WITH_VST
 class geTabPlugins;
 #endif
-class geButton;
-class geCheck;
-class geInput;
-class geRadio;
-class geBox;
-
-
-namespace giada {
-namespace v 
-{
-class geChoice;
 class gdConfig : public gdWindow
 {
 public:
-
        gdConfig(int w, int h);
 
 #ifdef WITH_VST
@@ -65,18 +60,18 @@ public:
        geTabMidi*      tabMidi;
        geTabMisc*      tabMisc;
 #ifdef WITH_VST
-       geTabPlugins*   tabPlugins;
+       geTabPlugins* tabPlugins;
 #endif
-       geButton*       save;
-       geButton*       cancel;
-
-private:
+       geButton* save;
+       geButton* cancel;
 
+  private:
        static void cb_save_config(Fl_Widget* /*w*/, void* p);
        static void cb_cancel(Fl_Widget* /*w*/, void* p);
-       void cb_save_config();
-       void cb_cancel();
+       void        cb_save_config();
+       void        cb_cancel();
 };
-}} // giada::v::
+} // namespace v
+} // namespace giada
 
 #endif
diff --git a/src/gui/dialogs/devInfo.cpp b/src/gui/dialogs/devInfo.cpp
deleted file mode 100644 (file)
index c3e78ae..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "core/kernelAudio.h"
-#include "utils/gui.h"
-#include "utils/string.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/box.h"
-#include "window.h"
-#include "devInfo.h"
-
-
-namespace giada {
-namespace v 
-{
-gdDevInfo::gdDevInfo(unsigned dev)
-: gdWindow(340, 300, "Device information")
-{
-       set_modal();
-
-       text  = new geBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-       close = new geButton(252, h()-28, 80, 20, "Close");
-       end();
-
-       std::string body  = "";
-       int         lines = 7;
-
-       body  = "Device name: " + m::kernelAudio::getDeviceName(dev) + "\n";
-       body += "Total output(s): " + std::to_string(m::kernelAudio::getMaxOutChans(dev)) + "\n";
-       body += "Total input(s): " + std::to_string(m::kernelAudio::getMaxInChans(dev)) + "\n";
-       body += "Duplex channel(s): " + std::to_string(m::kernelAudio::getDuplexChans(dev)) + "\n";
-       body += "Default output: " + std::string(m::kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n";
-       body += "Default input: " + std::string(m::kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n";
-
-       int totalFreq = m::kernelAudio::getTotalFreqs(dev);
-       body += "Supported frequencies: " + std::to_string(totalFreq);
-
-       for (int i=0; i<totalFreq; i++) {
-               if (i % 6 == 0) {
-                       body += "\n    ";  // add new line each 6 printed freqs AND on the first line (i % 0 != 0)
-                       lines++;
-               }
-               body += std::to_string(m::kernelAudio::getFreq(dev, i)) + "  ";
-       }
-
-       text->copy_label(body.c_str());
-
-       /* Resize the window to fit the content. fl_height() returns the height of a 
-       line. fl_height() * total lines + margins + button size */
-
-       resize(x(), y(), w(), (lines * fl_height()) + 8 + 8 + 8 + 20);
-       close->position(close->x(), (lines * fl_height()) + 8 + 8);
-
-       close->callback(cb_window_closer, (void*)this);
-       u::gui::setFavicon(this);
-       show();
-}
-}} // giada::v::
diff --git a/src/gui/dialogs/devInfo.h b/src/gui/dialogs/devInfo.h
deleted file mode 100644 (file)
index a16543a..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GD_DEV_INFO_H
-#define GD_DEV_INFO_H
-
-
-#include "window.h"
-
-
-class geBox;
-class geButton;
-
-
-namespace giada {
-namespace v 
-{
-class gdDevInfo : public gdWindow
-{
-public:
-
-    gdDevInfo(unsigned dev);
-
-private:
-
-       geBox*    text;
-       geButton* close;
-};
-}} // giada::v::
-
-#endif
index 8d693a76450df9adebd56dc3e310629da5284c56..1ee505b8ad0cfc0600342ea939a224937a6960e7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "utils/gui.h"
-#include "utils/string.h"
-#include "glue/io.h"
-#include "core/model/model.h"
+#include "keyGrabber.h"
+#include "config.h"
 #include "core/conf.h"
-#include "utils/log.h"
+#include "core/model/model.h"
+#include "glue/io.h"
 #include "gui/elems/basics/box.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/mainWindow/keyboard/channelButton.h"
-#include "keyGrabber.h"
-#include "config.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "mainWindow.h"
-
+#include "utils/gui.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include <cassert>
 
 extern giada::v::gdMainWindow* mainWin;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdKeyGrabber::gdKeyGrabber(const c::channel::Data& d)
 : gdWindow(300, 126, "Key configuration")
-, m_data  (d)
+, m_data(d)
 {
        begin();
        m_text   = new geBox(8, 8, 284, 80, "");
-       m_clear  = new geButton(w()-88, m_text->y()+m_text->h()+8, 80, 20, "Clear");
-       m_cancel = new geButton(m_clear->x()-88, m_clear->y(), 80, 20, "Close");
+       m_clear  = new geButton(w() - 88, m_text->y() + m_text->h() + 8, 80, 20, "Clear");
+       m_cancel = new geButton(m_clear->x() - 88, m_clear->y(), 80, 20, "Close");
        end();
 
        m_clear->callback(cb_clear, (void*)this);
@@ -67,45 +65,35 @@ gdKeyGrabber::gdKeyGrabber(const c::channel::Data& d)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdKeyGrabber::rebuild()
 {
        updateText(m_data.key);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gdKeyGrabber::cb_clear (Fl_Widget* /*w*/, void* p) { ((gdKeyGrabber*)p)->cb_clear(); }
+void gdKeyGrabber::cb_clear(Fl_Widget* /*w*/, void* p) { ((gdKeyGrabber*)p)->cb_clear(); }
 void gdKeyGrabber::cb_cancel(Fl_Widget* /*w*/, void* p) { ((gdKeyGrabber*)p)->cb_cancel(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdKeyGrabber::cb_cancel()
 {
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdKeyGrabber::cb_clear()
 {
        updateText(0);
        setButtonLabel(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdKeyGrabber::setButtonLabel(int key)
 {
        c::io::channel_setKey(m_data.id, key);
@@ -113,7 +101,6 @@ void gdKeyGrabber::setButtonLabel(int key)
 
 /* -------------------------------------------------------------------------- */
 
-
 void gdKeyGrabber::updateText(int key)
 {
        std::string tmp = "Press a key.\n\nCurrent binding: ";
@@ -124,34 +111,29 @@ void gdKeyGrabber::updateText(int key)
        m_text->copy_label(tmp.c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int gdKeyGrabber::handle(int e)
 {
        int ret = Fl_Group::handle(e);
-       switch(e) {
-               case FL_KEYUP: {
-                       int x = Fl::event_key();
-                       if (strlen(Fl::event_text()) != 0
-                           && x != FL_BackSpace
-                           && x != FL_Enter
-                           && x != FL_Delete
-                           && x != FL_Tab
-                           && x != FL_End
-                           && x != ' ')
-                       {
-                               u::log::print("set key '%c' (%d) for channel ID=%d\n", x, x, m_data.id);
-                               setButtonLabel(x);
-                               updateText(x);
-                               break;
-                       }
-                       else
-                               u::log::print("invalid key\n");
+       switch (e)
+       {
+       case FL_KEYUP:
+       {
+               int x = Fl::event_key();
+               if (strlen(Fl::event_text()) != 0 && x != FL_BackSpace && x != FL_Enter && x != FL_Delete && x != FL_Tab && x != FL_End && x != ' ')
+               {
+                       u::log::print("set key '%c' (%d) for channel ID=%d\n", x, x, m_data.id);
+                       setButtonLabel(x);
+                       updateText(x);
+                       break;
                }
+               else
+                       u::log::print("invalid key\n");
+       }
        }
-       return(ret);
+       return (ret);
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index edb7d6934963839a177927a7cbefb15336a3409e..a4c5feb956e6490cee21faee52c3b68492047522 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_KEYGRABBER_H
 #define GD_KEYGRABBER_H
 
-
-#include <FL/Fl.H>
 #include "window.h"
-
+#include <FL/Fl.H>
 
 class geBox;
 class geButton;
 
-
-namespace giada {
-namespace c {
+namespace giada
+{
+namespace c
+{
 namespace channel
 {
 struct Data;
-}}
-namespace v 
+}
+} // namespace c
+namespace v
 {
 class gdKeyGrabber : public gdWindow
 {
 public:
-
        gdKeyGrabber(const c::channel::Data& d);
 
-       int handle(int e) override;
+       int  handle(int e) override;
        void rebuild() override;
 
-private:
-
-       static void cb_clear (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_clear(Fl_Widget* /*w*/, void* p);
        static void cb_cancel(Fl_Widget* /*w*/, void* p);
-       void cb_clear ();
-       void cb_cancel();
+       void        cb_clear();
+       void        cb_cancel();
 
        void setButtonLabel(int key);
        void updateText(int key);
-       
+
        const c::channel::Data& m_data;
 
        geBox*    m_text;
        geButton* m_clear;
        geButton* m_cancel;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index fb1884d32541fabf493020b734dcca28cd944a98..f27d2ca0c062be06255cd30662b79db540bdddf3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include "core/const.h"
+#include "mainWindow.h"
+#include "core/clock.h"
 #include "core/conf.h"
+#include "core/const.h"
 #include "core/init.h"
-#include "utils/gui.h"
 #include "gui/elems/basics/boxtypes.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/mainIO.h"
 #include "gui/elems/mainWindow/mainMenu.h"
 #include "gui/elems/mainWindow/mainTimer.h"
 #include "gui/elems/mainWindow/mainTransport.h"
-#include "gui/elems/mainWindow/beatMeter.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
+#include "gui/elems/mainWindow/sequencer.h"
+#include "utils/gui.h"
 #include "warnings.h"
-#include "mainWindow.h"
-
+#include <FL/Fl.H>
+#include <FL/Fl_Tooltip.H>
 
-namespace giada {
-namespace v 
+namespace giada::v
 {
 gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** argv)
-       : gdWindow(W, H, title)
+: gdWindow(W, H, title)
 {
        Fl::visible_focus(0);
 
        Fl::background(25, 25, 25); // TODO use G_COLOR_GREY_1
 
        Fl::set_boxtype(G_CUSTOM_BORDER_BOX, g_customBorderBox, 1, 1, 2, 2);
-       Fl::set_boxtype(G_CUSTOM_UP_BOX,     g_customUpBox,     1, 1, 2, 2);
-       Fl::set_boxtype(G_CUSTOM_DOWN_BOX,   g_customDownBox,   1, 1, 2, 2);
+       Fl::set_boxtype(G_CUSTOM_UP_BOX, g_customUpBox, 1, 1, 2, 2);
+       Fl::set_boxtype(G_CUSTOM_DOWN_BOX, g_customDownBox, 1, 1, 2, 2);
 
        Fl::set_boxtype(FL_BORDER_BOX, G_CUSTOM_BORDER_BOX);
-       Fl::set_boxtype(FL_UP_BOX,     G_CUSTOM_UP_BOX);
-       Fl::set_boxtype(FL_DOWN_BOX,   G_CUSTOM_DOWN_BOX);
+       Fl::set_boxtype(FL_UP_BOX, G_CUSTOM_UP_BOX);
+       Fl::set_boxtype(FL_DOWN_BOX, G_CUSTOM_DOWN_BOX);
+
+       Fl_Tooltip::color(G_COLOR_GREY_1);
+       Fl_Tooltip::textcolor(G_COLOR_LIGHT_2);
+       Fl_Tooltip::size(G_GUI_FONT_SIZE_BASE);
+       Fl_Tooltip::enable(m::conf::conf.showTooltips);
 
        size_range(G_MIN_GUI_WIDTH, G_MIN_GUI_HEIGHT);
 
-       mainMenu      = new v::geMainMenu(8, 0);
+       mainMenu = new v::geMainMenu(8, 0);
 #if defined(WITH_VST)
-       mainIO        = new v::geMainIO(412, 8);
+       mainIO = new v::geMainIO(412, 8);
 #else
-       mainIO        = new v::geMainIO(460, 8);
+       mainIO = new v::geMainIO(460, 8);
 #endif
        mainTransport = new v::geMainTransport(8, 39);
        mainTimer     = new v::geMainTimer(571, 44);
-       beatMeter     = new v::geBeatMeter(100, 83, 609, 20);
-       keyboard      = new v::geKeyboard(8, 122, w()-16, 380);
+       sequencer     = new v::geSequencer(100, 78, 609, 30);
+       keyboard      = new v::geKeyboard(8, 122, w() - 16, 380);
 
        /* zone 1 - menus, and I/O tools */
 
-       Fl_Group* zone1 = new Fl_Group(8, 0, W-16, 28);
+       Fl_Group* zone1 = new Fl_Group(8, 0, W - 16, 28);
        zone1->add(mainMenu);
        zone1->resizable(new Fl_Box(300, 8, 80, 20));
        zone1->add(mainIO);
 
        /* zone 2 - mainTransport and timing tools */
 
-       Fl_Group* zone2 = new Fl_Group(8, mainTransport->y(), W-16, mainTransport->h());
+       Fl_Group* zone2 = new Fl_Group(8, mainTransport->y(), W - 16, mainTransport->h());
        zone2->add(mainTransport);
-       zone2->resizable(new Fl_Box(mainTransport->x()+mainTransport->w()+4, zone2->y(), 80, 20));
+       zone2->resizable(new Fl_Box(mainTransport->x() + mainTransport->w() + 4, zone2->y(), 80, 20));
        zone2->add(mainTimer);
 
        /* zone 3 - beat meter */
 
-       Fl_Group* zone3 = new Fl_Group(8, beatMeter->y(), W-16, beatMeter->h());
-       zone3->add(beatMeter);
+       Fl_Group* zone3 = new Fl_Group(8, sequencer->y(), W - 16, sequencer->h());
+       zone3->add(sequencer);
 
        /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is
         * a group by itself) */
@@ -105,13 +109,13 @@ gdMainWindow::gdMainWindow(int W, int H, const char* title, int argc, char** arg
        });
        u::gui::setFavicon(this);
 
+       refresh();
+
        show(argc, argv);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdMainWindow::~gdMainWindow()
 {
        m::conf::conf.mainWindowX = x();
@@ -120,23 +124,19 @@ gdMainWindow::~gdMainWindow()
        m::conf::conf.mainWindowH = h();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMainWindow::refresh()
 {
        mainIO->refresh();
        mainTimer->refresh();
        mainTransport->refresh();
-       beatMeter->refresh();
+       sequencer->refresh();
        keyboard->refresh();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMainWindow::rebuild()
 {
        keyboard->rebuild();
@@ -144,12 +144,10 @@ void gdMainWindow::rebuild()
        mainTimer->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMainWindow::clearKeyboard()
 {
        keyboard->init();
 }
-}} // giada::v::
+} // namespace giada::v
\ No newline at end of file
index d439e01a05d1f66eeeeb2d7b7f5c5d918164f7e5..a99689eacb7d28f63ee1d2a3225c657ceba733a4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MAINWINDOW_H
 #define GD_MAINWINDOW_H
 
-
 #include "window.h"
 
-
-namespace giada {
-namespace v 
+namespace giada::v
 {
 class geKeyboard;
 class geMainIO;
 class geMainMenu;
-class geBeatMeter;
+class geSequencer;
 class geMainTransport;
 class geMainTimer;
 class gdMainWindow : public gdWindow
 {
 public:
-
-    gdMainWindow(int w, int h, const char* title, int argc, char** argv);
+       gdMainWindow(int w, int h, const char* title, int argc, char** argv);
        ~gdMainWindow();
 
        void refresh() override;
-    void rebuild() override;
+       void rebuild() override;
 
        /* clearKeyboard
        Resets Keyboard to initial state, with no columns. */
@@ -57,13 +52,12 @@ public:
        void clearKeyboard();
 
        geKeyboard*      keyboard;
-       geBeatMeter*     beatMeter;
+       geSequencer*     sequencer;
        geMainMenu*      mainMenu;
        geMainIO*        mainIO;
        geMainTimer*     mainTimer;
        geMainTransport* mainTransport;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 7817d5279e1986da635c548fbcba5e54a8f45aec..f5cce51608db171616c40d027db42ec75d8e0641 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "glue/io.h"
-#include "core/conf.h"
 #include "midiInputBase.h"
+#include "core/conf.h"
+#include "glue/io.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdMidiInputBase::gdMidiInputBase(int x, int y, int w, int h, const char* title)
 : gdWindow(x, y, w, h, title)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdMidiInputBase::~gdMidiInputBase()
 {
        c::io::stopMidiLearn();
-       
+
        m::conf::conf.midiInputX = x();
        m::conf::conf.midiInputY = y();
        m::conf::conf.midiInputW = w();
        m::conf::conf.midiInputH = h();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputBase::cb_close(Fl_Widget* /*w*/, void* p) { ((gdMidiInputBase*)p)->cb_close(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputBase::cb_close()
 {
        do_callback();
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 8264fb18e646004547abb18d7253d3a52fac3fd0..78dd91fb0b3f8b56dca2ada3dec11cdd8099d859 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_INPUT_BASE_H
 #define GD_MIDI_INPUT_BASE_H
 
-
 #include "gui/dialogs/window.h"
 #include "gui/elems/midiIO/midiLearner.h"
 
-
 class geButton;
 class geCheck;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geChoice;
 class gdMidiInputBase : public gdWindow
 {
 public:
-
        virtual ~gdMidiInputBase();
 
-protected:
-
-       gdMidiInputBase(int x, int y, int w, int h, const char* title="");
+  protected:
+       gdMidiInputBase(int x, int y, int w, int h, const char* title = "");
 
        static void cb_close(Fl_Widget* /*w*/, void* p);
-       void cb_close();
+       void        cb_close();
 
        geButton* m_ok;
        geCheck*  m_enable;
        geChoice* m_channel;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index f19bae4f9d64bec3f2b3d9503c7c826bb4992a84..713070562dbb0a5930a6526dbc1265697736e916 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl_Pack.H>
+#include "core/conf.h"
+#include "core/const.h"
 #include "utils/gui.h"
 #include "utils/log.h"
-#include "core/const.h"
-#include "core/conf.h"
+#include <FL/Fl_Pack.H>
+#include <cassert>
 #ifdef WITH_VST
 #include "core/plugins/plugin.h"
 #endif
-#include "utils/string.h"
-#include "gui/elems/midiIO/midiLearner.h"
-#include "gui/elems/midiIO/midiLearnerPack.h"
-#include "gui/elems/basics/scrollPack.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/check.h"
+#include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/group.h"
+#include "gui/elems/basics/scrollPack.h"
+#include "gui/elems/midiIO/midiLearner.h"
+#include "gui/elems/midiIO/midiLearnerPack.h"
 #include "midiInputChannel.h"
+#include "utils/string.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geChannelLearnerPack::geChannelLearnerPack(int x, int y, const c::io::Channel_InputData& channel)
 : geMidiLearnerPack(x, y, "Channel")
 {
        setCallbacks(
-               [channelId=channel.channelId] (int param) { c::io::channel_startMidiLearn(param, channelId); },
-               [channelId=channel.channelId] (int param) { c::io::channel_clearMidiLearn(param, channelId); }
-       );
-       addMidiLearner("keyPress",     G_MIDI_IN_KEYPRESS);
-       addMidiLearner("key release",  G_MIDI_IN_KEYREL);
-       addMidiLearner("key kill",     G_MIDI_IN_KILL);
-       addMidiLearner("arm",          G_MIDI_IN_ARM);
-       addMidiLearner("mute",         G_MIDI_IN_MUTE);
-       addMidiLearner("solo",         G_MIDI_IN_SOLO);
-       addMidiLearner("volume",       G_MIDI_IN_VOLUME);
-       addMidiLearner("pitch",        G_MIDI_IN_PITCH,        /*visible=*/channel.channelType == ChannelType::SAMPLE);
+           [channelId = channel.channelId](int param) { c::io::channel_startMidiLearn(param, channelId); },
+           [channelId = channel.channelId](int param) { c::io::channel_clearMidiLearn(param, channelId); });
+       addMidiLearner("keyPress", G_MIDI_IN_KEYPRESS);
+       addMidiLearner("key release", G_MIDI_IN_KEYREL);
+       addMidiLearner("key kill", G_MIDI_IN_KILL);
+       addMidiLearner("arm", G_MIDI_IN_ARM);
+       addMidiLearner("mute", G_MIDI_IN_MUTE);
+       addMidiLearner("solo", G_MIDI_IN_SOLO);
+       addMidiLearner("volume", G_MIDI_IN_VOLUME);
+       addMidiLearner("pitch", G_MIDI_IN_PITCH, /*visible=*/channel.channelType == ChannelType::SAMPLE);
        addMidiLearner("read actions", G_MIDI_IN_READ_ACTIONS, /*visible=*/channel.channelType == ChannelType::SAMPLE);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelLearnerPack::update(const c::io::Channel_InputData& d)
 {
        learners[0]->update(d.keyPress);
@@ -85,30 +81,25 @@ void geChannelLearnerPack::update(const c::io::Channel_InputData& d)
        setEnabled(d.enabled);
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 gePluginLearnerPack::gePluginLearnerPack(int x, int y, const c::io::PluginData& plugin)
 : geMidiLearnerPack(x, y, plugin.name)
 {
        setCallbacks(
-               [pluginId=plugin.id] (int param) { c::io::plugin_startMidiLearn(param, pluginId); },
-               [pluginId=plugin.id] (int param) { c::io::plugin_clearMidiLearn(param, pluginId); }
-       );
+           [pluginId = plugin.id](int param) { c::io::plugin_startMidiLearn(param, pluginId); },
+           [pluginId = plugin.id](int param) { c::io::plugin_clearMidiLearn(param, pluginId); });
 
        for (const c::io::PluginParamData& param : plugin.params)
                addMidiLearner(param.name, param.index);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginLearnerPack::update(const c::io::PluginData& d, bool enabled)
 {
        std::size_t i = 0;
@@ -119,19 +110,17 @@ void gePluginLearnerPack::update(const c::io::PluginData& d, bool enabled)
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 gdMidiInputChannel::gdMidiInputChannel(ID channelId)
-: gdMidiInputBase(m::conf::conf.midiInputX, 
-                  m::conf::conf.midiInputY, 
-                                 m::conf::conf.midiInputW, 
-                     m::conf::conf.midiInputH)
-, m_channelId    (channelId)
-, m_data         (c::io::channel_getInputData(channelId))
+: gdMidiInputBase(m::conf::conf.midiInputX,
+      m::conf::conf.midiInputY,
+      m::conf::conf.midiInputW,
+      m::conf::conf.midiInputH)
+, m_channelId(channelId)
+, m_data(c::io::channel_getInputData(channelId))
 {
        end();
 
@@ -140,10 +129,10 @@ gdMidiInputChannel::gdMidiInputChannel(ID channelId)
        /* Header */
 
        geGroup* groupHeader = new geGroup(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN);
-               m_enable    = new geCheck(0, 0, 120, G_GUI_UNIT, "Enable MIDI input");
-               m_channel   = new geChoice(m_enable->x() + m_enable->w() + 44, 0, 120, G_GUI_UNIT);
-               m_veloAsVol = new geCheck(0, m_enable->y() + m_enable->h() + G_GUI_OUTER_MARGIN, w() - 16, G_GUI_UNIT, 
-                       "Velocity drives volume (Sample Channels)");
+       m_enable             = new geCheck(0, 0, 120, G_GUI_UNIT, "Enable MIDI input");
+       m_channel            = new geChoice(m_enable->x() + m_enable->w() + 44, 0, 120, G_GUI_UNIT);
+       m_veloAsVol          = new geCheck(0, m_enable->y() + m_enable->h() + G_GUI_OUTER_MARGIN, w() - 16, G_GUI_UNIT,
+        "Velocity drives volume (Sample Channels)");
        groupHeader->add(m_enable);
        groupHeader->add(m_channel);
        groupHeader->add(m_veloAsVol);
@@ -151,8 +140,8 @@ gdMidiInputChannel::gdMidiInputChannel(ID channelId)
 
        /* Main scrollable content. */
 
-       m_container = new geScrollPack(G_GUI_OUTER_MARGIN, groupHeader->y() + groupHeader->h() + G_GUI_OUTER_MARGIN, 
-               w() - 16, h() - groupHeader->h() - 52);
+       m_container = new geScrollPack(G_GUI_OUTER_MARGIN, groupHeader->y() + groupHeader->h() + G_GUI_OUTER_MARGIN,
+           w() - 16, h() - groupHeader->h() - 52);
        m_container->add(new geChannelLearnerPack(0, 0, m_data));
 #ifdef WITH_VST
        for (c::io::PluginData& plugin : m_data.plugins)
@@ -162,8 +151,8 @@ gdMidiInputChannel::gdMidiInputChannel(ID channelId)
        /* Footer buttons. */
 
        geGroup* groupButtons = new geGroup(G_GUI_OUTER_MARGIN, m_container->y() + m_container->h() + G_GUI_OUTER_MARGIN);
-               geBox* spacer = new geBox(0, 0, w() - 80, G_GUI_UNIT); // spacer window border <-> buttons
-               m_ok = new geButton(w() - 96, 0, 80, G_GUI_UNIT, "Close");
+       geBox*   spacer       = new geBox(0, 0, w() - 80, G_GUI_UNIT); // spacer window border <-> buttons
+       m_ok                  = new geButton(w() - 96, 0, 80, G_GUI_UNIT, "Close");
        groupButtons->add(spacer);
        groupButtons->add(m_ok);
        groupButtons->resizable(spacer);
@@ -190,7 +179,7 @@ gdMidiInputChannel::gdMidiInputChannel(ID channelId)
        m_channel->add("Channel 16");
        m_channel->callback(cb_setChannel, (void*)this);
 
-       m_veloAsVol->callback(cb_veloAsVol, (void*)this);       
+       m_veloAsVol->callback(cb_veloAsVol, (void*)this);
 
        add(groupHeader);
        add(m_container);
@@ -203,17 +192,16 @@ gdMidiInputChannel::gdMidiInputChannel(ID channelId)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputChannel::rebuild()
 {
        m_data = c::io::channel_getInputData(m_channelId);
 
        m_enable->value(m_data.enabled);
 
-       if (m_data.channelType == ChannelType::SAMPLE) {
+       if (m_data.channelType == ChannelType::SAMPLE)
+       {
                m_veloAsVol->activate();
                m_veloAsVol->value(m_data.velocityAsVol);
        }
@@ -229,50 +217,45 @@ void gdMidiInputChannel::rebuild()
 
        m_channel->value(m_data.filter == -1 ? 0 : m_data.filter + 1);
 
-       if (m_data.enabled) {
+       if (m_data.enabled)
+       {
                m_channel->activate();
                if (m_data.channelType == ChannelType::SAMPLE)
                        m_veloAsVol->activate();
        }
-       else {
+       else
+       {
                m_channel->deactivate();
                m_veloAsVol->deactivate();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputChannel::cb_enable(Fl_Widget* /*w*/, void* p) { ((gdMidiInputChannel*)p)->cb_enable(); }
 void gdMidiInputChannel::cb_setChannel(Fl_Widget* /*w*/, void* p) { ((gdMidiInputChannel*)p)->cb_setChannel(); }
 void gdMidiInputChannel::cb_veloAsVol(Fl_Widget* /*w*/, void* p) { ((gdMidiInputChannel*)p)->cb_veloAsVol(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputChannel::cb_enable()
 {
        c::io::channel_enableMidiLearn(m_data.channelId, m_enable->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputChannel::cb_veloAsVol()
 {
        c::io::channel_enableVelocityAsVol(m_data.channelId, m_veloAsVol->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputChannel::cb_setChannel()
 {
-       c::io::channel_setMidiInputFilter(m_data.channelId, 
-               m_channel->value() == 0 ? -1 : m_channel->value() - 1);
+       c::io::channel_setMidiInputFilter(m_data.channelId,
+           m_channel->value() == 0 ? -1 : m_channel->value() - 1);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 65eb3d3f32478f9e68ddc62dc4a725e23ad3ec69..88c883299bf2bb25902a0177fd82016e6efe370c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_INPUT_CHANNEL_H
 #define GD_MIDI_INPUT_CHANNEL_H
 
-
 #include "glue/io.h"
 #include "gui/elems/midiIO/midiLearnerPack.h"
 #include "midiInputBase.h"
 
-
 class geCheck;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geChoice;
 class geScrollPack;
 class geChannelLearnerPack : public geMidiLearnerPack
 {
 public:
-
        geChannelLearnerPack(int x, int y, const c::io::Channel_InputData& d);
 
        void update(const c::io::Channel_InputData&);
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 class gePluginLearnerPack : public geMidiLearnerPack
 {
 public:
-
        gePluginLearnerPack(int x, int y, const c::io::PluginData&);
 
        void update(const c::io::PluginData&, bool enabled);
@@ -70,36 +63,31 @@ public:
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
-
 class gdMidiInputChannel : public gdMidiInputBase
 {
 public:
-
        gdMidiInputChannel(ID channelId);
 
        void rebuild() override;
 
-private:
-
+  private:
        static void cb_enable(Fl_Widget* /*w*/, void* p);
        static void cb_setChannel(Fl_Widget* /*w*/, void* p);
        static void cb_veloAsVol(Fl_Widget* /*w*/, void* p);
-       void cb_enable();
-       void cb_setChannel();
-       void cb_veloAsVol();
+       void        cb_enable();
+       void        cb_setChannel();
+       void        cb_veloAsVol();
 
        ID m_channelId;
-       
+
        c::io::Channel_InputData m_data;
 
        geScrollPack* m_container;
        geCheck*      m_veloAsVol;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 23e682dc0948913a71696c74e76129edb2ecef9d..33802931308a09610c7861d7c123323136d2fca3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Pack.H>
-#include "utils/gui.h"
+#include "midiInputMaster.h"
 #include "core/conf.h"
 #include "core/const.h"
-#include "gui/elems/midiIO/midiLearner.h"
-#include "gui/elems/basics/scrollPack.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/group.h"
-#include "midiInputMaster.h"
-
+#include "gui/elems/basics/scrollPack.h"
+#include "gui/elems/midiIO/midiLearner.h"
+#include "utils/gui.h"
+#include <FL/Fl_Pack.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geMasterLearnerPack::geMasterLearnerPack(int x, int y)
 : geMidiLearnerPack(x, y)
 {
        setCallbacks(
-               [] (int param) { c::io::master_startMidiLearn(param); },
-               [] (int param) { c::io::master_clearMidiLearn(param); }
-       );
-       addMidiLearner("rewind",           G_MIDI_IN_REWIND);
-       addMidiLearner("play/stop",        G_MIDI_IN_START_STOP);
+           [](int param) { c::io::master_startMidiLearn(param); },
+           [](int param) { c::io::master_clearMidiLearn(param); });
+       addMidiLearner("rewind", G_MIDI_IN_REWIND);
+       addMidiLearner("play/stop", G_MIDI_IN_START_STOP);
        addMidiLearner("action recording", G_MIDI_IN_ACTION_REC);
-       addMidiLearner("input recording",  G_MIDI_IN_INPUT_REC);
-       addMidiLearner("metronome",        G_MIDI_IN_METRONOME);
-       addMidiLearner("input volume",     G_MIDI_IN_VOLUME_IN);
-       addMidiLearner("output volume",    G_MIDI_IN_VOLUME_OUT);
-       addMidiLearner("sequencer ×2",     G_MIDI_IN_BEAT_DOUBLE);
-       addMidiLearner("sequencer ÷2",     G_MIDI_IN_BEAT_HALF);
+       addMidiLearner("input recording", G_MIDI_IN_INPUT_REC);
+       addMidiLearner("metronome", G_MIDI_IN_METRONOME);
+       addMidiLearner("input volume", G_MIDI_IN_VOLUME_IN);
+       addMidiLearner("output volume", G_MIDI_IN_VOLUME_OUT);
+       addMidiLearner("sequencer ×2", G_MIDI_IN_BEAT_DOUBLE);
+       addMidiLearner("sequencer ÷2", G_MIDI_IN_BEAT_HALF);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMasterLearnerPack::update(const c::io::Master_InputData& d)
 {
        learners[0]->update(d.rewind);
        learners[1]->update(d.startStop);
        learners[2]->update(d.actionRec);
        learners[3]->update(d.inputRec);
-       learners[4]->update(d.metronome);       
+       learners[4]->update(d.metronome);
        learners[5]->update(d.volumeIn);
        learners[6]->update(d.volumeOut);
        learners[7]->update(d.beatDouble);
@@ -77,20 +73,18 @@ void geMasterLearnerPack::update(const c::io::Master_InputData& d)
        setEnabled(d.enabled);
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 gdMidiInputMaster::gdMidiInputMaster()
 : gdMidiInputBase(m::conf::conf.midiInputX, m::conf::conf.midiInputY, 300, 284, "MIDI Input Setup (global)")
 {
        end();
 
        geGroup* groupHeader = new geGroup(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN);
-               m_enable  = new geCheck(0, 0, 120, G_GUI_UNIT, "Enable MIDI input");
-               m_channel = new geChoice(m_enable->x() + m_enable->w() + 44, 0, 120, G_GUI_UNIT);
+       m_enable             = new geCheck(0, 0, 120, G_GUI_UNIT, "Enable MIDI input");
+       m_channel            = new geChoice(m_enable->x() + m_enable->w() + 44, 0, 120, G_GUI_UNIT);
        groupHeader->resizable(nullptr);
        groupHeader->add(m_enable);
        groupHeader->add(m_channel);
@@ -131,10 +125,8 @@ gdMidiInputMaster::gdMidiInputMaster()
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputMaster::rebuild()
 {
        m_data = c::io::master_getInputData();
@@ -146,28 +138,23 @@ void gdMidiInputMaster::rebuild()
        m_data.enabled ? m_channel->activate() : m_channel->deactivate();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputMaster::cb_enable(Fl_Widget* /*w*/, void* p) { ((gdMidiInputMaster*)p)->cb_enable(); }
 void gdMidiInputMaster::cb_setChannel(Fl_Widget* /*w*/, void* p) { ((gdMidiInputMaster*)p)->cb_setChannel(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputMaster::cb_enable()
 {
        c::io::master_enableMidiLearn(m_enable->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiInputMaster::cb_setChannel()
 {
        c::io::master_setMidiFilter(m_channel->value() == 0 ? -1 : m_channel->value() - 1);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 216d4549a79a3cc109d3f16789a46c4d6a7550f3..d3031898796203078c528b91d894cde4b9c474cd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_INPUT_MASTER_H
 #define GD_MIDI_INPUT_MASTER_H
 
-
 #include "glue/io.h"
 #include "gui/elems/midiIO/midiLearnerPack.h"
 #include "midiInputBase.h"
 
-
 class geCheck;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geChoice;
 class geMasterLearnerPack : public geMidiLearnerPack
 {
 public:
-
        geMasterLearnerPack(int x, int y);
 
        void update(const c::io::Master_InputData&);
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 class gdMidiInputMaster : public gdMidiInputBase
 {
 public:
-
-    gdMidiInputMaster();
+       gdMidiInputMaster();
 
        void rebuild() override;
 
-private:
-
+  private:
        static void cb_enable(Fl_Widget* /*w*/, void* p);
        static void cb_setChannel(Fl_Widget* /*w*/, void* p);
-       void cb_enable();
-       void cb_setChannel();
+       void        cb_enable();
+       void        cb_setChannel();
 
        c::io::Master_InputData m_data;
 
        geMasterLearnerPack* m_learners;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index d5f750c144ae61f86ce879d9dfd914c9d60ff138..fd75e243b95b274e364f6dcabb56ce729722a80f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "midiOutputBase.h"
 #include "glue/io.h"
-#include "gui/elems/midiIO/midiLearner.h"
 #include "gui/elems/basics/check.h"
-#include "midiOutputBase.h"
-
+#include "gui/elems/midiIO/midiLearner.h"
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geLightningLearnerPack::geLightningLearnerPack(int x, int y, ID channelId)
 : geMidiLearnerPack(x, y)
 {
        setCallbacks(
-               [channelId] (int param) { c::io::channel_startMidiLearn(param, channelId); },
-               [channelId] (int param) { c::io::channel_clearMidiLearn(param, channelId); }
-       );
+           [channelId](int param) { c::io::channel_startMidiLearn(param, channelId); },
+           [channelId](int param) { c::io::channel_clearMidiLearn(param, channelId); });
        addMidiLearner("playing", G_MIDI_OUT_L_PLAYING);
-       addMidiLearner("mute",    G_MIDI_OUT_L_MUTE);
-       addMidiLearner("solo",    G_MIDI_OUT_L_SOLO);   
+       addMidiLearner("mute", G_MIDI_OUT_L_MUTE);
+       addMidiLearner("solo", G_MIDI_OUT_L_SOLO);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geLightningLearnerPack::update(const c::io::Channel_OutputData& d)
 {
        learners[0]->update(d.lightningPlaying);
@@ -58,59 +54,48 @@ void geLightningLearnerPack::update(const c::io::Channel_OutputData& d)
        setEnabled(d.lightningEnabled);
 }
 
-
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 gdMidiOutputBase::gdMidiOutputBase(int w, int h, ID channelId)
-: gdWindow   (w, h, "Midi Output Setup")
+: gdWindow(w, h, "Midi Output Setup")
 , m_channelId(channelId)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdMidiOutputBase::~gdMidiOutputBase()
 {
        c::io::stopMidiLearn();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gdMidiOutputBase::cb_close          (Fl_Widget* /*w*/, void* p) { ((gdMidiOutputBase*)p)->cb_close(); }
+void gdMidiOutputBase::cb_close(Fl_Widget* /*w*/, void* p) { ((gdMidiOutputBase*)p)->cb_close(); }
 void gdMidiOutputBase::cb_enableLightning(Fl_Widget* /*w*/, void* p) { ((gdMidiOutputBase*)p)->cb_enableLightning(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputBase::cb_close()
 {
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputBase::cb_enableLightning()
 {
        c::io::channel_enableMidiLightning(m_channelId, m_enableLightning->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputBase::setTitle(ID channelId)
 {
-       std::string tmp = "MIDI Output Setup (channel " + std::to_string(channelId) + ")"; 
+       std::string tmp = "MIDI Output Setup (channel " + std::to_string(channelId) + ")";
        copy_label(tmp.c_str());
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 884709941394d49605ec2f41dccf24000297be56..df9de01e192c5178d2a76c31d1e1d3b95a712472 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_OUTPUT_BASE_H
 #define GD_MIDI_OUTPUT_BASE_H
 
-
 #include "core/types.h"
 #include "glue/io.h"
-#include "gui/elems/midiIO/midiLearnerPack.h"
-#include "gui/elems/midiIO/midiLearner.h"
 #include "gui/dialogs/window.h"
-
+#include "gui/elems/midiIO/midiLearner.h"
+#include "gui/elems/midiIO/midiLearnerPack.h"
 
 class geButton;
 class geCheck;
 
-
 /* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI
 output master is managed by the configuration window, hence gdMidiOutput deals
 only with channels.
@@ -47,39 +43,35 @@ only with channels.
 Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set.
 In addition MidiOutputMidiCh has the MIDI message output box. */
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geLightningLearnerPack : public geMidiLearnerPack
 {
 public:
-
        geLightningLearnerPack(int x, int y, ID channelId);
 
        void update(const c::io::Channel_OutputData&);
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 class gdMidiOutputBase : public gdWindow
 {
 public:
-
        gdMidiOutputBase(int w, int h, ID channelId);
        ~gdMidiOutputBase();
 
-protected:
-
+  protected:
        /* cb_close
        close current window. */
 
        static void cb_close(Fl_Widget* /*w*/, void* p);
-       void cb_close();
+       void        cb_close();
 
        static void cb_enableLightning(Fl_Widget* /*w*/, void* p);
-       void cb_enableLightning();
+       void        cb_enableLightning();
 
        /* setTitle
         * set window title. */
@@ -87,14 +79,14 @@ protected:
        void setTitle(ID channelId);
 
        ID m_channelId;
-       
+
        c::io::Channel_OutputData m_data;
-       
+
        geLightningLearnerPack* m_learners;
        geButton*               m_close;
        geCheck*                m_enableLightning;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index a4c7715269c39be2804fa38b610082e2bc0e223a..801ea4e79eb29a5cdae8dbd589e2da7bfc1847e0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Pack.H>
+#include "midiOutputMidiCh.h"
 #include "glue/io.h"
-#include "gui/elems/midiIO/midiLearner.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/choice.h"
+#include "gui/elems/midiIO/midiLearner.h"
 #include "utils/gui.h"
-#include "midiOutputMidiCh.h"
-
+#include <FL/Fl_Pack.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdMidiOutputMidiCh::gdMidiOutputMidiCh(ID channelId)
 : gdMidiOutputBase(300, 168, channelId)
@@ -45,14 +44,14 @@ gdMidiOutputMidiCh::gdMidiOutputMidiCh(ID channelId)
        setTitle(m_channelId + 1);
 
        m_enableOut   = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 150, G_GUI_UNIT, "Enable MIDI output");
-       m_chanListOut = new geChoice(w()-108, G_GUI_OUTER_MARGIN, 100, G_GUI_UNIT);
-
-       m_enableLightning = new geCheck(G_GUI_OUTER_MARGIN, m_chanListOut->y() + m_chanListOut->h() + G_GUI_OUTER_MARGIN, 
-               120, G_GUI_UNIT, "Enable MIDI lightning output");
-       
-       m_learners = new geLightningLearnerPack(G_GUI_OUTER_MARGIN, 
-               m_enableLightning->y() + m_enableLightning->h() + G_GUI_OUTER_MARGIN, channelId);
-       
+       m_chanListOut = new geChoice(w() - 108, G_GUI_OUTER_MARGIN, 100, G_GUI_UNIT);
+
+       m_enableLightning = new geCheck(G_GUI_OUTER_MARGIN, m_chanListOut->y() + m_chanListOut->h() + G_GUI_OUTER_MARGIN,
+           120, G_GUI_UNIT, "Enable MIDI lightning output");
+
+       m_learners = new geLightningLearnerPack(G_GUI_OUTER_MARGIN,
+           m_enableLightning->y() + m_enableLightning->h() + G_GUI_OUTER_MARGIN, channelId);
+
        m_close = new geButton(w() - 88, m_learners->y() + m_learners->h() + G_GUI_OUTER_MARGIN, 80, G_GUI_UNIT, "Close");
 
        add(m_enableOut);
@@ -78,7 +77,7 @@ gdMidiOutputMidiCh::gdMidiOutputMidiCh(ID channelId)
        m_chanListOut->add("Channel 15");
        m_chanListOut->add("Channel 16");
        m_chanListOut->value(0);
-               
+
        m_chanListOut->callback(cb_setChannel, (void*)this);
        m_enableOut->callback(cb_enableOut, (void*)this);
        m_enableLightning->callback(cb_enableLightning, (void*)this);
@@ -91,16 +90,14 @@ gdMidiOutputMidiCh::gdMidiOutputMidiCh(ID channelId)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputMidiCh::rebuild()
 {
        m_data = c::io::channel_getOutputData(m_channelId);
 
        assert(m_data.output.has_value());
-       
+
        m_learners->update(m_data);
        m_chanListOut->value(m_data.output->filter);
        m_enableOut->value(m_data.output->enabled);
@@ -108,28 +105,23 @@ void gdMidiOutputMidiCh::rebuild()
        m_data.output->enabled ? m_chanListOut->activate() : m_chanListOut->deactivate();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gdMidiOutputMidiCh::cb_enableOut (Fl_Widget* /*w*/, void* p) { ((gdMidiOutputMidiCh*)p)->cb_enableOut(); }
+void gdMidiOutputMidiCh::cb_enableOut(Fl_Widget* /*w*/, void* p) { ((gdMidiOutputMidiCh*)p)->cb_enableOut(); }
 void gdMidiOutputMidiCh::cb_setChannel(Fl_Widget* /*w*/, void* p) { ((gdMidiOutputMidiCh*)p)->cb_setChannel(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputMidiCh::cb_enableOut()
 {
        c::io::channel_enableMidiOutput(m_channelId, m_enableOut->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputMidiCh::cb_setChannel()
 {
        c::io::channel_setMidiOutputFilter(m_channelId, m_chanListOut->value());
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 0d6b6993055e410b232b8fa15d1ae9ed938194a0..61bc1702e15c22622c4ecdef3d2a00c51eca69ec 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_OUTPUT_MIDI_CH_H
 #define GD_MIDI_OUTPUT_MIDI_CH_H
 
-
 #include "midiOutputBase.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
+class geChoice;
 class gdMidiOutputMidiCh : public gdMidiOutputBase
 {
 public:
-
        gdMidiOutputMidiCh(ID channelId);
 
        void rebuild() override;
 
-private:
-
-       static void cb_enableOut (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_enableOut(Fl_Widget* /*w*/, void* p);
        static void cb_setChannel(Fl_Widget* /*w*/, void* p);
-       void cb_enableOut();
-       void cb_setChannel();
+       void        cb_enableOut();
+       void        cb_setChannel();
 
        geCheck*  m_enableOut;
        geChoice* m_chanListOut;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 257d46ac35c5d6b8f1ec6da1e4ddea29a204d9d6..43ad49b939fcd9477435b8cc64aa3664cdefdc84 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Pack.H>
+#include "midiOutputSampleCh.h"
 #include "core/model/model.h"
-#include "utils/gui.h"
-#include "gui/elems/midiIO/midiLearner.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
-#include "midiOutputSampleCh.h"
-
+#include "gui/elems/midiIO/midiLearner.h"
+#include "utils/gui.h"
+#include <FL/Fl_Pack.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gdMidiOutputSampleCh::gdMidiOutputSampleCh(ID channelId)
 : gdMidiOutputBase(300, 140, channelId)
@@ -45,8 +44,8 @@ gdMidiOutputSampleCh::gdMidiOutputSampleCh(ID channelId)
 
        m_enableLightning = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 120, 20, "Enable MIDI lightning output");
 
-       m_learners = new geLightningLearnerPack(G_GUI_OUTER_MARGIN, 
-               m_enableLightning->y() + m_enableLightning->h() + 8, channelId);
+       m_learners = new geLightningLearnerPack(G_GUI_OUTER_MARGIN,
+           m_enableLightning->y() + m_enableLightning->h() + 8, channelId);
 
        m_close = new geButton(w() - 88, m_learners->y() + m_learners->h() + 8, 80, 20, "Close");
 
@@ -56,7 +55,7 @@ gdMidiOutputSampleCh::gdMidiOutputSampleCh(ID channelId)
 
        m_close->callback(cb_close, (void*)this);
        m_enableLightning->callback(cb_enableLightning, (void*)this);
-       
+
        u::gui::setFavicon(this);
 
        set_modal();
@@ -64,10 +63,8 @@ gdMidiOutputSampleCh::gdMidiOutputSampleCh(ID channelId)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdMidiOutputSampleCh::rebuild()
 {
        m_data = c::io::channel_getOutputData(m_channelId);
@@ -75,4 +72,5 @@ void gdMidiOutputSampleCh::rebuild()
        m_enableLightning->value(m_data.lightningEnabled);
        m_learners->update(m_data);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 10f403310ba6406cc56c40c047505adbf81cca44..68a433a7c9cf09ceea5507916f734604e1757b0d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_MIDI_OUTPUT_SAMPLE_CH_H
 #define GD_MIDI_OUTPUT_SAMPLE_CH_H
 
-
 #include "midiOutputBase.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class gdMidiOutputSampleCh : public gdMidiOutputBase
 {
 public:
-
-    gdMidiOutputSampleCh(ID channelId);
+       gdMidiOutputSampleCh(ID channelId);
 
        void rebuild() override;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index d3a209d41b3de0fc66214d869bc94585f38fca94..e557b77ffb9af5ad1e40bc3ad624dd25547098b9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include "glue/plugin.h"
-#include "utils/gui.h"
+#include "pluginChooser.h"
 #include "core/conf.h"
-#include "core/plugins/pluginManager.h"
 #include "core/plugins/pluginHost.h"
-#include "gui/elems/plugin/pluginBrowser.h"
+#include "core/plugins/pluginManager.h"
+#include "glue/plugin.h"
+#include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
-#include "gui/elems/basics/box.h"
-#include "pluginChooser.h"
-
+#include "gui/elems/plugin/pluginBrowser.h"
+#include "utils/gui.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, ID channelId)
-: gdWindow   (X, Y, W, H, "Available plugins")
+: gdWindow(X, Y, W, H, "Available plugins")
 , m_channelId(channelId)
 {
        /* top area */
-       Fl_Group *group_top = new Fl_Group(8, 8, w()-16, 20);
-       sortMethod  = new geChoice(group_top->x() + 45, group_top->y(), 100, 20, "Sort by");
-               geBox *b1 = new geBox(sortMethod->x()+sortMethod->w(), group_top->y(), 100, 20);        // spacer window border <-> menu
+       Fl_Group* group_top = new Fl_Group(8, 8, w() - 16, 20);
+       sortMethod          = new geChoice(group_top->x() + 45, group_top->y(), 100, 20, "Sort by");
+       geBox* b1           = new geBox(sortMethod->x() + sortMethod->w(), group_top->y(), 100, 20); // spacer window border <-> menu
        group_top->resizable(b1);
        group_top->end();
 
        /* center browser */
-       browser = new v::gePluginBrowser(8, 36, w()-16, h()-70);
+       browser = new v::gePluginBrowser(8, 36, w() - 16, h() - 70);
 
        /* ok/cancel buttons */
-       Fl_Group *group_btn = new Fl_Group(8, browser->y()+browser->h()+8, w()-16, h()-browser->h()-16);
-               geBox *b2 = new geBox(8, browser->y()+browser->h(), 100, 20);   // spacer window border <-> buttons
-               addBtn = new geButton(w()-88, group_btn->y(), 80, 20, "Add");
-               cancelBtn = new geButton(addBtn->x()-88, group_btn->y(), 80, 20, "Cancel");
+       Fl_Group* group_btn = new Fl_Group(8, browser->y() + browser->h() + 8, w() - 16, h() - browser->h() - 16);
+       geBox*    b2        = new geBox(8, browser->y() + browser->h(), 100, 20); // spacer window border <-> buttons
+       addBtn              = new geButton(w() - 88, group_btn->y(), 80, 20, "Add");
+       cancelBtn           = new geButton(addBtn->x() - 88, group_btn->y(), 80, 20, "Cancel");
        group_btn->resizable(b2);
        group_btn->end();
 
@@ -70,62 +68,52 @@ gdPluginChooser::gdPluginChooser(int X, int Y, int W, int H, ID channelId)
        sortMethod->add("Name");
        sortMethod->add("Category");
        sortMethod->add("Manufacturer");
-       sortMethod->callback(cb_sort, (void*) this);
+       sortMethod->callback(cb_sort, (void*)this);
        sortMethod->value(m::conf::conf.pluginSortMethod);
 
-       addBtn->callback(cb_add, (void*) this);
+       addBtn->callback(cb_add, (void*)this);
        addBtn->shortcut(FL_Enter);
-       cancelBtn->callback(cb_close, (void*) this);
+       cancelBtn->callback(cb_close, (void*)this);
 
        resizable(browser);
        u::gui::setFavicon(this);
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdPluginChooser::~gdPluginChooser()
 {
-       m::conf::conf.pluginChooserX = x();
-       m::conf::conf.pluginChooserY = y();
-       m::conf::conf.pluginChooserW = w();
-       m::conf::conf.pluginChooserH = h();
+       m::conf::conf.pluginChooserX   = x();
+       m::conf::conf.pluginChooserY   = y();
+       m::conf::conf.pluginChooserW   = w();
+       m::conf::conf.pluginChooserH   = h();
        m::conf::conf.pluginSortMethod = sortMethod->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginChooser::cb_close(Fl_Widget* /*w*/, void* p) { ((gdPluginChooser*)p)->cb_close(); }
-void gdPluginChooser::cb_add  (Fl_Widget* /*w*/, void* p) { ((gdPluginChooser*)p)->cb_add(); }
-void gdPluginChooser::cb_sort (Fl_Widget* /*w*/, void* p) { ((gdPluginChooser*)p)->cb_sort(); }
-
+void gdPluginChooser::cb_add(Fl_Widget* /*w*/, void* p) { ((gdPluginChooser*)p)->cb_add(); }
+void gdPluginChooser::cb_sort(Fl_Widget* /*w*/, void* p) { ((gdPluginChooser*)p)->cb_sort(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginChooser::cb_close()
 {
        do_callback();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginChooser::cb_sort()
 {
        m::pluginManager::sortPlugins(static_cast<m::pluginManager::SortMethod>(sortMethod->value()));
        browser->refresh();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginChooser::cb_add()
 {
        int pluginIndex = browser->value() - 3; // subtract header lines
@@ -134,7 +122,7 @@ void gdPluginChooser::cb_add()
        c::plugin::addPlugin(pluginIndex, m_channelId);
        do_callback();
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // #ifdef WITH_VST
index bdbb2b82345748a4dcb58c596a42f68da52c33e5..201035e2481ffbe38e4889ddbbec5aeb8bbc5ef3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 #ifndef GD_PLUGIN_CHOOSER_H
 #define GD_PLUGIN_CHOOSER_H
 
-
+#include "core/types.h"
+#include "window.h"
 #include <FL/Fl.H>
 #include <FL/Fl_Scroll.H>
-#include "window.h"
-
 
 class geButton;
 class geButton;
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geChoice;
@@ -48,18 +47,16 @@ class gePluginBrowser;
 class gdPluginChooser : public gdWindow
 {
 public:
-
        gdPluginChooser(int x, int y, int w, int h, ID channelId);
        ~gdPluginChooser();
 
-private:
-
+  private:
        static void cb_close(Fl_Widget* /*w*/, void* p);
-       static void cb_add  (Fl_Widget* /*w*/, void* p);
-       static void cb_sort (Fl_Widget* /*w*/, void* p);
-       void cb_close();
-       void cb_add  ();
-       void cb_sort ();
+       static void cb_add(Fl_Widget* /*w*/, void* p);
+       static void cb_sort(Fl_Widget* /*w*/, void* p);
+       void        cb_close();
+       void        cb_add();
+       void        cb_sort();
 
        geChoice*        sortMethod;
        geButton*        addBtn;
@@ -68,8 +65,8 @@ private:
 
        ID m_channelId;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
 
index 7e9115bbbf76e5fb72b3566f4a03771ea1cfdd88..514d9e18cc689957215535d691d13ed3914fae4e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <cassert>
-#include <string>
+#include "pluginList.h"
 #include "core/conf.h"
 #include "core/const.h"
-#include "utils/string.h"
-#include "utils/gui.h"
-#include "gui/elems/basics/liquidScroll.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/liquidScroll.h"
 #include "gui/elems/basics/statusButton.h"
-#include "gui/elems/mainWindow/mainIO.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
+#include "gui/elems/mainWindow/mainIO.h"
 #include "gui/elems/plugin/pluginElement.h"
-#include "pluginChooser.h"
 #include "mainWindow.h"
-#include "pluginList.h"
-
+#include "pluginChooser.h"
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <cassert>
+#include <string>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gdPluginList::gdPluginList(ID channelId)
-: gdWindow   (m::conf::conf.pluginListX, m::conf::conf.pluginListY, 468, 204)
+: gdWindow(m::conf::conf.pluginListX, m::conf::conf.pluginListY, 468, 204)
 , m_channelId(channelId)
 {
        end();
 
-       list = new geLiquidScroll(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 
-               w() - (G_GUI_OUTER_MARGIN*2), h() - (G_GUI_OUTER_MARGIN*2));
+       list = new geLiquidScroll(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN,
+           w() - (G_GUI_OUTER_MARGIN * 2), h() - (G_GUI_OUTER_MARGIN * 2));
        list->end();
        add(list);
        resizable(list);
@@ -70,36 +67,30 @@ gdPluginList::gdPluginList(ID channelId)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdPluginList::~gdPluginList()
 {
        m::conf::conf.pluginListX = x();
        m::conf::conf.pluginListY = y();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginList::cb_addPlugin(Fl_Widget* /*v*/, void* p) { ((gdPluginList*)p)->cb_addPlugin(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginList::rebuild()
 {
        m_plugins = c::plugin::getPlugins(m_channelId);
 
        if (m_plugins.channelId == m::mixer::MASTER_OUT_CHANNEL_ID)
                label("Master Out Plug-ins");
-       else
-       if (m_plugins.channelId == m::mixer::MASTER_IN_CHANNEL_ID)
+       else if (m_plugins.channelId == m::mixer::MASTER_IN_CHANNEL_ID)
                label("Master In Plug-ins");
-       else {
+       else
+       {
                std::string l = "Channel " + u::string::iToString(m_plugins.channelId) + " Plug-ins";
                copy_label(l.c_str());
        }
@@ -109,32 +100,27 @@ void gdPluginList::rebuild()
        list->clear();
        list->scroll_to(0, 0);
 
-       for (ID pluginId : m_plugins.pluginIds)
-               list->addWidget(new gePluginElement(0, 0, c::plugin::getPlugin(pluginId, m_plugins.channelId)));
-       
+       for (m::Plugin* plugin : m_plugins.plugins)
+               list->addWidget(new gePluginElement(0, 0, c::plugin::getPlugin(*plugin, m_plugins.channelId)));
+
        addPlugin = list->addWidget(new geButton(0, 0, 0, G_GUI_UNIT, "-- add new plugin --"));
-       
+
        addPlugin->callback(cb_addPlugin, (void*)this);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginList::cb_addPlugin()
 {
        int wx = m::conf::conf.pluginChooserX;
        int wy = m::conf::conf.pluginChooserY;
        int ww = m::conf::conf.pluginChooserW;
        int wh = m::conf::conf.pluginChooserH;
-       u::gui::openSubWindow(G_MainWin, new v::gdPluginChooser(wx, wy, ww, wh, 
-               m_plugins.channelId), WID_FX_CHOOSER);
+       u::gui::openSubWindow(G_MainWin, new v::gdPluginChooser(wx, wy, ww, wh, m_plugins.channelId), WID_FX_CHOOSER);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 const gePluginElement& gdPluginList::getNextElement(const gePluginElement& currEl) const
 {
        int curr = list->find(currEl);
@@ -144,7 +130,6 @@ const gePluginElement& gdPluginList::getNextElement(const gePluginElement& currE
        return *static_cast<gePluginElement*>(list->child(next));
 }
 
-
 const gePluginElement& gdPluginList::getPrevElement(const gePluginElement& currEl) const
 {
        int curr = list->find(currEl);
@@ -153,7 +138,7 @@ const gePluginElement& gdPluginList::getPrevElement(const gePluginElement& currE
                prev = 0;
        return *static_cast<gePluginElement*>(list->child(prev));
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // #ifdef WITH_VST
index d0e027189028ea4439b8d25d59614af97b32f759..0e2d224d5f81936ef9cba06be09ac7aba60cf6ce 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef GD_PLUGINLIST_H
 #define GD_PLUGINLIST_H
 
-
 #include "glue/plugin.h"
 #include "window.h"
 
-
 class geLiquidScroll;
 class geButton;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class gePluginElement;
 class gdPluginList : public gdWindow
 {
 public:
-
        gdPluginList(ID channelId);
        ~gdPluginList();
 
@@ -56,19 +51,18 @@ public:
        const gePluginElement& getNextElement(const gePluginElement& curr) const;
        const gePluginElement& getPrevElement(const gePluginElement& curr) const;
 
-private:
-
+  private:
        static void cb_addPlugin(Fl_Widget* /*w*/, void* p);
-       void cb_addPlugin();
+       void        cb_addPlugin();
 
        geButton*       addPlugin;
-       geLiquidScroll* list;   
+       geLiquidScroll* list;
 
-       ID m_channelId;
+       ID                 m_channelId;
        c::plugin::Plugins m_plugins;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
 
index f21017331d93d8d1068b9f7a9533d1f3e44f34c3..31ea919c5713ed78c11ae7940e5a8aadcd0cf78d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <FL/fl_draw.H>
-#include "glue/plugin.h"
-#include "utils/gui.h"
+#include "pluginWindow.h"
 #include "core/const.h"
+#include "glue/plugin.h"
 #include "gui/elems/basics/liquidScroll.h"
 #include "gui/elems/plugin/pluginParameter.h"
-#include "pluginWindow.h"
-
+#include "utils/gui.h"
+#include <FL/fl_draw.H>
 
-namespace giada {
-namespace v
+namespace giada::v
 {
 gdPluginWindow::gdPluginWindow(const c::plugin::Plugin& plugin)
 : gdWindow(450, 156)
@@ -46,40 +42,38 @@ gdPluginWindow::gdPluginWindow(const c::plugin::Plugin& plugin)
 {
        set_non_modal();
 
-       m_list = new geLiquidScroll(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 
-               w()-(G_GUI_OUTER_MARGIN*2), h()-(G_GUI_OUTER_MARGIN*2));
-       
+       m_list = new geLiquidScroll(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN,
+           w() - (G_GUI_OUTER_MARGIN * 2), h() - (G_GUI_OUTER_MARGIN * 2));
+
        m_list->type(Fl_Scroll::VERTICAL_ALWAYS);
        m_list->begin();
-               int labelWidth = 100; // TODO
-               for (int index : m_plugin.paramIndexes) {
-                       int py = m_list->y() + (index * (G_GUI_UNIT + G_GUI_INNER_MARGIN));
-                       int pw = m_list->w() - m_list->scrollbar_size() - (G_GUI_OUTER_MARGIN*3);
-                       new v::gePluginParameter(m_list->x(), py, pw, labelWidth, c::plugin::getParam(index, m_plugin.id));
-               }
+       int labelWidth = 100; // TODO
+       for (int index : m_plugin.paramIndexes)
+       {
+               int py = m_list->y() + (index * (G_GUI_UNIT + G_GUI_INNER_MARGIN));
+               int pw = m_list->w() - m_list->scrollbar_size() - (G_GUI_OUTER_MARGIN * 3);
+               new v::gePluginParameter(m_list->x(), py, pw, labelWidth, c::plugin::getParam(index, m_plugin.getPluginRef(), m_plugin.channelId));
+       }
        m_list->end();
 
        end();
 
        label(m_plugin.name.c_str());
 
-       size_range(450, (G_GUI_UNIT + (G_GUI_OUTER_MARGIN*2)));
+       size_range(450, (G_GUI_UNIT + (G_GUI_OUTER_MARGIN * 2)));
        resizable(m_list);
 
        u::gui::setFavicon(this);
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginWindow::updateParameters(bool changeSlider)
 {
        for (int index : m_plugin.paramIndexes)
-               static_cast<v::gePluginParameter*>(m_list->child(index))->update(c::plugin::getParam(index, m_plugin.id), changeSlider);
+               static_cast<v::gePluginParameter*>(m_list->child(index))->update(c::plugin::getParam(index, m_plugin.getPluginRef(), m_plugin.channelId), changeSlider);
 }
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif // #ifdef WITH_VST
index a0c106f071f03b03e5f1ed641f2428ec3cb1acf0..babe30e0cf531c8d0c34f8c9659c22bd6abab21c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef GD_PLUGIN_WINDOW_H
 #define GD_PLUGIN_WINDOW_H
 
-
 #include "window.h"
 
-
 class geBox;
 class geSlider;
 class geLiquidScroll;
 
-
-namespace giada {
-namespace c {
-namespace plugin
+namespace giada::c::plugin
 {
-class Plugin;
-}}
-namespace m
+struct Plugin;
+}
+namespace giada::m
 {
 class Plugin;
 }
-namespace v
+namespace giada::v
 {
 class gdPluginWindow : public gdWindow
 {
 public:
-
        gdPluginWindow(const c::plugin::Plugin&);
 
-       void updateParameters(bool changeSlider=false);
+       void updateParameters(bool changeSlider = false);
 
-private:
-       
+  private:
        const c::plugin::Plugin& m_plugin;
-               
+
        geLiquidScroll* m_list;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
 
index bd9091132cc3a575feb74986a53571a5870598cd..03e417006c9000732a9d2cdbc339721996f27e11 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <FL/x.H>
-#include "utils/log.h"
-#include "utils/gui.h"
-#include "glue/plugin.h"
-#include "core/const.h"
 #include "pluginWindowGUI.h"
+#include "core/const.h"
+#include "glue/plugin.h"
+#include "utils/gui.h"
+#include "utils/log.h"
+#include <FL/x.H>
 #ifdef G_OS_MAC
 #import "utils/cocoa.h" // objective-c
 #endif
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gdPluginWindowGUI::gdPluginWindowGUI(c::plugin::Plugin& p)
@@ -49,7 +47,7 @@ gdPluginWindowGUI::gdPluginWindowGUI(c::plugin::Plugin& p)
 : gdWindow(320, 200)
 #endif
 , m_plugin(p)
-, m_ui    (nullptr)
+, m_ui(nullptr)
 {
        show();
 
@@ -70,100 +68,88 @@ gdPluginWindowGUI::gdPluginWindowGUI(c::plugin::Plugin& p)
 #endif
 
        u::log::print("[gdPluginWindowGUI] opening GUI, this=%p, xid=%p\n",
-               (void*) this, (void*) fl_xid(this));
+           (void*)this, (void*)fl_xid(this));
 
 #ifdef G_OS_MAC
 
-       void* cocoaWindow = (void*) fl_xid(this);
+       void* cocoaWindow = (void*)fl_xid(this);
        openEditor(cocoa_getViewFromWindow(cocoaWindow));
 
 #else
 
-       openEditor((void*) fl_xid(this));
+       openEditor((void*)fl_xid(this));
 
        int pluginW = m_ui->getWidth();
        int pluginH = m_ui->getHeight();
 
        resize((Fl::w() - pluginW) / 2, (Fl::h() - pluginH) / 2, pluginW, pluginH);
 
-       m_plugin.setResizeCallback([this] (int w, int h)
-       {
+       m_plugin.setResizeCallback([this](int w, int h) {
                resize(x(), y(), w, h);
        });
 
 #endif
 
 #ifdef G_OS_LINUX
-       Fl::add_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
+       Fl::add_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*)this);
 #endif
 
        copy_label(m_plugin.name.c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdPluginWindowGUI::~gdPluginWindowGUI()
 {
        cb_close();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginWindowGUI::cb_close(Fl_Widget* /*v*/, void* p) { ((gdPluginWindowGUI*)p)->cb_close(); }
 void gdPluginWindowGUI::cb_refresh(void* data) { ((gdPluginWindowGUI*)data)->cb_refresh(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginWindowGUI::cb_close()
 {
 #ifdef G_OS_LINUX
        Fl::remove_timeout(cb_refresh);
 #endif
        closeEditor();
-       u::log::print("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*) this);
+       u::log::print("[gdPluginWindowGUI::__cb_close] GUI closed, this=%p\n", (void*)this);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginWindowGUI::cb_refresh()
 {
        m::pluginHost::runDispatchLoop();
-       Fl::repeat_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*) this);
+       Fl::repeat_timeout(G_GUI_PLUGIN_RATE, cb_refresh, (void*)this);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginWindowGUI::openEditor(void* parent)
 {
        m_ui = m_plugin.createEditor();
-       if (m_ui == nullptr) {
+       if (m_ui == nullptr)
+       {
                u::log::print("[gdPluginWindowGUI::openEditor] unable to create editor!\n");
                return;
        }
        m_ui->setOpaque(true);
-       m_ui->addToDesktop(0, parent);  
+       m_ui->addToDesktop(0, parent);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdPluginWindowGUI::closeEditor()
 {
        delete m_ui;
        m_ui = nullptr;
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // #ifdef WITH_VST
index 211892abf9c909144f6cb362c39629f6dc421957..a907f282f9a1e93671210423cbcb795946b72736 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef GD_PLUGIN_WINDOW_GUI_H
 #define GD_PLUGIN_WINDOW_GUI_H
 
-
+#include "deps/juce-config.h"
+#include "window.h"
 #include <FL/Fl.H>
 #include <FL/Fl_Window.H>
-#include "window.h"
-
 
-namespace giada {
-namespace c {
+namespace giada
+{
+namespace c
+{
 namespace plugin
 {
 struct Plugin;
-}}
+}
+} // namespace c
 namespace v
 {
 class gdPluginWindowGUI : public gdWindow
 {
 public:
-
        gdPluginWindowGUI(c::plugin::Plugin&);
        ~gdPluginWindowGUI();
 
-private:
-
+  private:
        static void cb_close(Fl_Widget* /*w*/, void* p);
        static void cb_refresh(void* data);
-       void cb_close();
-       void cb_refresh();
+       void        cb_close();
+       void        cb_refresh();
 
-       void openEditor(void* parent); 
-       void closeEditor(); 
+       void openEditor(void* parent);
+       void closeEditor();
 
        c::plugin::Plugin& m_plugin;
 
        juce::AudioProcessorEditor* m_ui;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // include guard
 
-
 #endif // #ifdef WITH_VST
index a0362821dc634ea8ef25aac50e5c1bece5e6c8f9..a77994d3f5d666d4d9acde4201d2e5da8724e83f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
-#include <cassert>
-#include <FL/Fl.H>
-#include <FL/Fl_Group.H>
-#include "glue/channel.h"
 #include "glue/sampleEditor.h"
-#include "core/waveFx.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/graphics.h"
 #include "core/mixer.h"
 #include "core/wave.h"
-#include "utils/gui.h"
-#include "utils/string.h"
+#include "core/waveFx.h"
+#include "glue/channel.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/basics/statusButton.h"
-#include "gui/elems/basics/input.h"
+#include "gui/elems/basics/check.h"
 #include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/dial.h"
-#include "gui/elems/basics/box.h"
-#include "gui/elems/basics/check.h"
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/group.h"
-#include "gui/elems/sampleEditor/waveform.h"
-#include "gui/elems/sampleEditor/waveTools.h"
-#include "gui/elems/sampleEditor/volumeTool.h"
+#include "gui/elems/basics/input.h"
+#include "gui/elems/basics/pack.h"
+#include "gui/elems/basics/statusButton.h"
+#include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/sampleEditor/boostTool.h"
 #include "gui/elems/sampleEditor/panTool.h"
 #include "gui/elems/sampleEditor/pitchTool.h"
 #include "gui/elems/sampleEditor/rangeTool.h"
 #include "gui/elems/sampleEditor/shiftTool.h"
-#include "gui/elems/mainWindow/keyboard/channel.h"
-#include "gui/dialogs/warnings.h"
+#include "gui/elems/sampleEditor/volumeTool.h"
+#include "gui/elems/sampleEditor/waveTools.h"
+#include "gui/elems/sampleEditor/waveform.h"
 #include "sampleEditor.h"
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
+#include <FL/Fl_Group.H>
+#include <cassert>
+#include <cmath>
 
-
-namespace giada {
-namespace v 
+namespace giada::v
 {
 gdSampleEditor::gdSampleEditor(ID channelId)
-: gdWindow   (m::conf::conf.sampleEditorX, m::conf::conf.sampleEditorY, 
-              m::conf::conf.sampleEditorW, m::conf::conf.sampleEditorH)
+: gdWindow(m::conf::conf.sampleEditorX, m::conf::conf.sampleEditorY,
+      m::conf::conf.sampleEditorW, m::conf::conf.sampleEditorH)
 , m_channelId(channelId)
 {
        end();
 
        gePack* upperBar = createUpperBar();
-       
-       waveTools = new geWaveTools(G_GUI_OUTER_MARGIN, upperBar->y()+upperBar->h()+G_GUI_OUTER_MARGIN, 
-               w()-16, h()-168);
-       
-       gePack* bottomBar = createBottomBar(G_GUI_OUTER_MARGIN, waveTools->y()+waveTools->h()+G_GUI_OUTER_MARGIN, 
-               h()-waveTools->h()-upperBar->h()-32);
+
+       waveTools = new geWaveTools(G_GUI_OUTER_MARGIN, upperBar->y() + upperBar->h() + G_GUI_OUTER_MARGIN,
+           w() - 16, h() - 168);
+
+       gePack* bottomBar = createBottomBar(G_GUI_OUTER_MARGIN, waveTools->y() + waveTools->h() + G_GUI_OUTER_MARGIN,
+           h() - waveTools->h() - upperBar->h() - 32);
 
        add(upperBar);
        add(waveTools);
@@ -93,27 +90,23 @@ gdSampleEditor::gdSampleEditor(ID channelId)
        show();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdSampleEditor::~gdSampleEditor()
 {
-       m::conf::conf.sampleEditorX = x();
-       m::conf::conf.sampleEditorY = y();
-       m::conf::conf.sampleEditorW = w();
-       m::conf::conf.sampleEditorH = h();
+       m::conf::conf.sampleEditorX       = x();
+       m::conf::conf.sampleEditorY       = y();
+       m::conf::conf.sampleEditorW       = w();
+       m::conf::conf.sampleEditorH       = h();
        m::conf::conf.sampleEditorGridVal = atoi(grid->text());
        m::conf::conf.sampleEditorGridOn  = snap->value();
-       
+
        c::sampleEditor::stopPreview();
        c::sampleEditor::cleanupPreview();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::rebuild()
 {
        m_data = c::sampleEditor::getData(m_channelId);
@@ -130,29 +123,25 @@ void gdSampleEditor::rebuild()
        updateInfo();
 
        if (m_data.isLogical) // Logical samples (aka takes) cannot be reloaded.
-               reload->deactivate();   
+               reload->deactivate();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::refresh()
 {
        waveTools->refresh();
        play->setStatus(m_data.a_getPreviewStatus() == ChannelStatus::PLAY);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gePack* gdSampleEditor::createUpperBar()
 {
        reload  = new geButton(0, 0, 70, G_GUI_UNIT, "Reload");
        grid    = new geChoice(0, 0, 50, G_GUI_UNIT);
-       snap    = new geCheck (0, 0, 12, G_GUI_UNIT, "Snap");
-       sep1    = new geBox   (0, 0, w() - 208, G_GUI_UNIT);
+       snap    = new geCheck(0, 0, 12, G_GUI_UNIT, "Snap");
+       sep1    = new geBox(0, 0, w() - 208, G_GUI_UNIT);
        zoomOut = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomOutOff_xpm, zoomOutOn_xpm);
        zoomIn  = new geButton(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
 
@@ -167,19 +156,24 @@ gePack* gdSampleEditor::createUpperBar()
        grid->add("16");
        grid->add("32");
        grid->add("64");
+       grid->copy_tooltip("Grid frequency");
+
        if (m::conf::conf.sampleEditorGridVal == 0)
                grid->value(0);
-       else 
+       else
                grid->value(grid->find_item(u::string::iToString(m::conf::conf.sampleEditorGridVal).c_str()));
        grid->callback(cb_changeGrid, (void*)this);
 
        snap->value(m::conf::conf.sampleEditorGridOn);
+       snap->copy_tooltip("Snap to grid");
        snap->callback(cb_enableSnap, (void*)this);
 
        /* TODO - redraw grid if != (off) */
 
        zoomOut->callback(cb_zoomOut, (void*)this);
+       zoomOut->copy_tooltip("Zoom out");
        zoomIn->callback(cb_zoomIn, (void*)this);
+       zoomIn->copy_tooltip("Zoom in");
 
        gePack* g = new gePack(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, Direction::HORIZONTAL);
        g->add(reload);
@@ -187,24 +181,22 @@ gePack* gdSampleEditor::createUpperBar()
        g->add(snap);
        g->add(sep1);
        g->add(zoomOut);
-       g->add(zoomIn); 
+       g->add(zoomIn);
        g->resizable(sep1);
 
        return g;
 }
 
-\
 /* -------------------------------------------------------------------------- */
-\
 
 gePack* gdSampleEditor::createOpTools(int x, int y)
 {
        volumeTool = new geVolumeTool(m_data, 0, 0);
-       panTool    = new gePanTool   (m_data, 0, 0);
-       pitchTool  = new gePitchTool (m_data, 0, 0);
-       rangeTool  = new geRangeTool (m_data, 0, 0);
-       shiftTool  = new geShiftTool (m_data, 0, 0);
-       
+       panTool    = new gePanTool(m_data, 0, 0);
+       pitchTool  = new gePitchTool(m_data, 0, 0);
+       rangeTool  = new geRangeTool(m_data, 0, 0);
+       shiftTool  = new geShiftTool(m_data, 0, 0);
+
        gePack* g = new gePack(x, y, Direction::VERTICAL);
        g->add(volumeTool);
        g->add(panTool);
@@ -215,10 +207,8 @@ gePack* gdSampleEditor::createOpTools(int x, int y)
        return g;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geGroup* gdSampleEditor::createPreviewBox(int x, int y, int h)
 {
        rewind = new geButton(x, y + (h / 2) - 12, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
@@ -236,17 +226,15 @@ geGroup* gdSampleEditor::createPreviewBox(int x, int y, int h)
        return g;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gePack* gdSampleEditor::createBottomBar(int x, int y, int h)
 {
        geGroup*  previewBox = createPreviewBox(0, 0, h);
-       geBox*    divisor1   = new geBox       (0, 0, 1, h);
-       Fl_Group* opTools    = createOpTools   (0, 0);
-       geBox*    divisor2   = new geBox       (0, 0, 1, h);
-                 info       = new geBox       (0, 0, 400, h);
+       geBox*    divisor1   = new geBox(0, 0, 1, h);
+       Fl_Group* opTools    = createOpTools(0, 0);
+       geBox*    divisor2   = new geBox(0, 0, 1, h);
+       info                 = new geBox(0, 0, 400, h);
 
        divisor1->box(FL_BORDER_BOX);
        divisor2->box(FL_BORDER_BOX);
@@ -264,31 +252,25 @@ gePack* gdSampleEditor::createBottomBar(int x, int y, int h)
        return g;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gdSampleEditor::cb_reload       (Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_reload(); }
-void gdSampleEditor::cb_zoomIn       (Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_zoomIn(); }
-void gdSampleEditor::cb_zoomOut      (Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_zoomOut(); }
-void gdSampleEditor::cb_changeGrid   (Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_changeGrid(); }
-void gdSampleEditor::cb_enableSnap   (Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_enableSnap(); }
+void gdSampleEditor::cb_reload(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_reload(); }
+void gdSampleEditor::cb_zoomIn(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_zoomIn(); }
+void gdSampleEditor::cb_zoomOut(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_zoomOut(); }
+void gdSampleEditor::cb_changeGrid(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_changeGrid(); }
+void gdSampleEditor::cb_enableSnap(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_enableSnap(); }
 void gdSampleEditor::cb_togglePreview(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_togglePreview(); }
 void gdSampleEditor::cb_rewindPreview(Fl_Widget* /*w*/, void* p) { ((gdSampleEditor*)p)->cb_rewindPreview(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::cb_enableSnap()
 {
        waveTools->waveform->setSnap(!waveTools->waveform->getSnap());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::cb_togglePreview()
 {
        if (!play->getStatus())
@@ -297,65 +279,58 @@ void gdSampleEditor::cb_togglePreview()
                c::sampleEditor::stopPreview();
 }
 
-
 void gdSampleEditor::cb_rewindPreview()
 {
        c::sampleEditor::setPreviewTracker(m_data.begin);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::cb_reload()
 {
-       c::sampleEditor::reload(m_data.channelId, m_data.waveId);
+       c::sampleEditor::reload(m_data.channelId);
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::cb_zoomIn()
 {
        waveTools->waveform->setZoom(geWaveform::Zoom::IN);
        waveTools->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::cb_zoomOut()
 {
        waveTools->waveform->setZoom(geWaveform::Zoom::OUT);
        waveTools->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::cb_changeGrid()
 {
        waveTools->waveform->setGridLevel(atoi(grid->text()));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdSampleEditor::updateInfo()
 {
        std::string bitDepth = m_data.waveBits != 0 ? u::string::iToString(m_data.waveBits) : "(unknown)";
-       std::string infoText = 
-               "File: "      + m_data.wavePath + "\n"
-               "Size: "      + u::string::iToString(m_data.waveSize) + " frames\n"
-               "Duration: "  + u::string::iToString(m_data.waveDuration) + " seconds\n"
-               "Bit depth: " + bitDepth + "\n"
-               "Frequency: " + u::string::iToString(m_data.waveRate) + " Hz\n";
+       std::string infoText =
+           "File: " + m_data.wavePath + "\n"
+                                        "Size: " +
+           u::string::iToString(m_data.waveSize) + " frames\n"
+                                                   "Duration: " +
+           u::string::iToString(m_data.waveDuration) + " seconds\n"
+                                                       "Bit depth: " +
+           bitDepth + "\n"
+                      "Frequency: " +
+           u::string::iToString(m_data.waveRate) + " Hz\n";
 
        info->copy_label(infoText.c_str());
 }
-}} // giada::v::
+} // namespace giada::v
index 02c25bec8755c9fc81b1739967b22f20fcb50c6d..65e78ce3df0f5d25a5e60c7b056e742f992a25a9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_EDITOR_H
 #define GD_EDITOR_H
 
-
 #include "core/types.h"
 #include "glue/sampleEditor.h"
 #include "window.h"
 
-
 class geButton;
 class geCheck;
 class geBox;
 class geButton;
 class geStatusButton;
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 class Wave;
 }
-namespace 
+namespace giada::v
 {
 class geChoice;
 class gePack;
@@ -60,10 +55,9 @@ class geRangeTool;
 class geShiftTool;
 class gdSampleEditor : public gdWindow
 {
-friend class geWaveform;
+       friend class geWaveform;
 
 public:
-
        gdSampleEditor(ID channelId);
        ~gdSampleEditor();
 
@@ -75,7 +69,7 @@ public:
        geBox*    sep1;
        geButton* zoomIn;
        geButton* zoomOut;
-       
+
        geWaveTools* waveTools;
 
        geVolumeTool* volumeTool;
@@ -92,28 +86,26 @@ public:
        geCheck*        loop;
        geBox*          info;
 
-
-private:
-
-       gePack* createUpperBar();
-       gePack* createBottomBar(int x, int y, int h);
+  private:
+       gePack*  createUpperBar();
+       gePack*  createBottomBar(int x, int y, int h);
        geGroup* createPreviewBox(int x, int y, int h);
-       gePack* createOpTools(int x, int y);
+       gePack*  createOpTools(int x, int y);
 
-       static void cb_reload    (Fl_Widget* /*w*/, void* p);
-       static void cb_zoomIn    (Fl_Widget* /*w*/, void* p);
-       static void cb_zoomOut   (Fl_Widget* /*w*/, void* p);
+       static void cb_reload(Fl_Widget* /*w*/, void* p);
+       static void cb_zoomIn(Fl_Widget* /*w*/, void* p);
+       static void cb_zoomOut(Fl_Widget* /*w*/, void* p);
        static void cb_changeGrid(Fl_Widget* /*w*/, void* p);
        static void cb_enableSnap(Fl_Widget* /*w*/, void* p);
        static void cb_togglePreview(Fl_Widget* /*w*/, void* p);
        static void cb_rewindPreview(Fl_Widget* /*w*/, void* p);
-       void cb_reload();
-       void cb_zoomIn();
-       void cb_zoomOut();
-       void cb_changeGrid();
-       void cb_enableSnap();
-       void cb_togglePreview();
-       void cb_rewindPreview();
+       void        cb_reload();
+       void        cb_zoomIn();
+       void        cb_zoomOut();
+       void        cb_changeGrid();
+       void        cb_enableSnap();
+       void        cb_togglePreview();
+       void        cb_rewindPreview();
 
        void updateInfo();
 
@@ -121,7 +113,6 @@ private:
 
        c::sampleEditor::Data m_data;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 5a5f4e1f917ef0bd85fa45940894214577180372..96230b7991461615c01a8a3237d2f2507906e7b5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include <FL/Fl_Window.H>
-#include "utils/gui.h"
+#include "warnings.h"
 #include "core/const.h"
-#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
+#include "utils/gui.h"
 #include "window.h"
-#include "warnings.h"
-
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 void gdAlert(const char* c)
 {
        gdWindow* modal = new gdWindow(
-               (Fl::w() / 2) - 150,
-               (Fl::h() / 2) - 47,
-               300, 90, "Alert");
+           (Fl::w() / 2) - 150,
+           (Fl::h() / 2) - 47,
+           300, 90, "Alert");
        modal->set_modal();
        modal->begin();
-               geBox*    box = new geBox(10, 10, 280, 40, c);
-               geButton* b   = new geButton(210, 60, 80, 20, "Close");
+       geBox*    box = new geBox(10, 10, 280, 40, c);
+       geButton* b   = new geButton(210, 60, 80, 20, "Close");
        modal->end();
        box->labelsize(G_GUI_FONT_SIZE_BASE);
-       b->callback(cb_window_closer, (void *)modal);
+       b->callback(cb_window_closer, (void*)modal);
        b->shortcut(FL_Enter);
        u::gui::setFavicon(modal);
        modal->show();
 }
 
-
 int gdConfirmWin(const char* title, const char* msg)
 {
        gdWindow* win = new gdWindow(
-                       (Fl::w() / 2) - 150,
-                       (Fl::h() / 2) - 47,
-                       300, 90, title);
+           (Fl::w() / 2) - 150,
+           (Fl::h() / 2) - 47,
+           300, 90, title);
        win->set_modal();
        win->begin();
-               new geBox(10, 10, 280, 40, msg);
-               geButton* ok = new geButton(212, 62, 80, 20, "Ok");
-               geButton* ko = new geButton(124, 62, 80, 20, "Cancel");
+       new geBox(10, 10, 280, 40, msg);
+       geButton* ok = new geButton(212, 62, 80, 20, "Ok");
+       geButton* ko = new geButton(124, 62, 80, 20, "Cancel");
        win->end();
        ok->shortcut(FL_Enter);
        u::gui::setFavicon(win);
@@ -76,14 +74,25 @@ int gdConfirmWin(const char* title, const char* msg)
        /* no callbacks here. readqueue() check the event stack. */
 
        int r = 0;
-       while (true) {
+       while (true)
+       {
                Fl_Widget* o = Fl::readqueue();
-               if (!o) Fl::wait();
-               else if (o == ok) {r = 1; break;}
-               else if (o == ko) {r = 0; break;}
+               if (!o)
+                       Fl::wait();
+               else if (o == ok)
+               {
+                       r = 1;
+                       break;
+               }
+               else if (o == ko)
+               {
+                       r = 0;
+                       break;
+               }
        }
        //delete win;
        win->hide();
        return r;
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 169a62e8b522a988aa91870bf417a42510d12480..1cbf284dfb3f12c62e74c555ef2fafacac0014d0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_WARNINGS_H
 #define GD_WARNINGS_H
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
-void gdAlert(const char *c);
-int  gdConfirmWin(const char *title, const char *msg);
-}} // giada::v::
+void gdAlert(const char* c);
+int  gdConfirmWin(const char* title, const char* msg);
+} // namespace v
+} // namespace giada
 
 #endif
index 7cc1d54fdf6a1396cffb18205d7e84f284c2bc8f..5159f57b06ba08ec4f7b855c90b0cd9588ac516e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "utils/log.h"
 #include "window.h"
+#include "utils/log.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 void cb_window_closer(Fl_Widget* /*v*/, void* p)
 {
-  delete (Fl_Window*) p;
+       delete (Fl_Window*)p;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdWindow::gdWindow(int x, int y, int w, int h, const char* title, int id)
-       : Fl_Double_Window(x, y, w, h, title), id(id), parent(nullptr)
+: Fl_Double_Window(x, y, w, h, title)
+, id(id)
+, parent(nullptr)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdWindow::gdWindow(int w, int h, const char* title, int id)
-       : Fl_Double_Window(w, h, title), id(id), parent(nullptr)
+: Fl_Double_Window(w, h, title)
+, id(id)
+, parent(nullptr)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdWindow::~gdWindow()
 {
        /* delete all subwindows in order to empty the stack */
@@ -68,7 +65,6 @@ gdWindow::~gdWindow()
        subWindows.clear();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 /* this is the default callback of each window, fired when the user closes
@@ -76,15 +72,13 @@ gdWindow::~gdWindow()
 
 void gdWindow::cb_closeChild(Fl_Widget* w, void* /*p*/)
 {
-       gdWindow* child = (gdWindow*) w;
+       gdWindow* child = (gdWindow*)w;
        if (child->getParent() != nullptr)
                (child->getParent())->delSubWindow(child);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdWindow::addSubWindow(gdWindow* w)
 {
        w->setParent(this);
@@ -93,53 +87,46 @@ void gdWindow::addSubWindow(gdWindow* w)
        //debug();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdWindow::delSubWindow(gdWindow* w)
 {
        for (unsigned j = 0; j < subWindows.size(); j++)
-               if (w->getId() == subWindows.at(j)->getId()) {
+               if (w->getId() == subWindows.at(j)->getId())
+               {
                        delete subWindows.at(j);
                        subWindows.erase(subWindows.begin() + j);
                        return;
                }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdWindow::delSubWindow(int wid)
 {
        for (unsigned j = 0; j < subWindows.size(); j++)
-               if (subWindows.at(j)->getId() == wid) {
+               if (subWindows.at(j)->getId() == wid)
+               {
                        delete subWindows.at(j);
                        subWindows.erase(subWindows.begin() + j);
                        return;
                }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int gdWindow::getId() const
 {
        return id;
 }
 
-
 void gdWindow::setId(int wid)
 {
        id = wid;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gdWindow::debug() const
 {
        /* TODO - use G_DEBUG
@@ -150,25 +137,20 @@ void gdWindow::debug() const
        */
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdWindow* gdWindow::getParent()
 {
        return parent;
 }
 
-
 void gdWindow::setParent(gdWindow* w)
 {
        parent = w;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool gdWindow::hasWindow(int wid) const
 {
        for (unsigned j = 0; j < subWindows.size(); j++)
@@ -177,10 +159,8 @@ bool gdWindow::hasWindow(int wid) const
        return false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 gdWindow* gdWindow::getChild(int wid)
 {
        for (unsigned j = 0; j < subWindows.size(); j++)
@@ -188,4 +168,5 @@ gdWindow* gdWindow::getChild(int wid)
                        return subWindows.at(j);
        return nullptr;
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 1923c91a1f5c4fc2efac61824e89a06c92795edb..ac22160f0348390c1966b9985803b5c81fcc304b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GD_WINDOW_H
 #define GD_WINDOW_H
 
-
-#include <vector>
 #include <FL/Fl_Double_Window.H>
+#include <vector>
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 /* cb_window_closer
 Callback for closing windows. Deletes the widget (delete). */
@@ -44,9 +42,8 @@ void cb_window_closer(Fl_Widget* /*w*/, void* p);
 class gdWindow : public Fl_Double_Window
 {
 public:
-
-       gdWindow(int x, int y, int w, int h, const char* title=0, int id=0);
-       gdWindow(int w, int h, const char* title=0, int id=0);
+       gdWindow(int x, int y, int w, int h, const char* title = 0, int id = 0);
+       gdWindow(int w, int h, const char* title = 0, int id = 0);
        ~gdWindow();
 
        static void cb_closeChild(Fl_Widget* /*w*/, void* p);
@@ -55,33 +52,32 @@ public:
        Rebuild() is called by the View Updater when something structural changes
        (e.g. a new channel added). Refresh() is called periodically by the View 
        Updater during the refresh loop. */
-       
-       virtual void rebuild() {};
-       virtual void refresh() {};
+
+       virtual void rebuild(){};
+       virtual void refresh(){};
 
        /* hasWindow
        True if the window with id 'id' exists in the stack. */
 
        bool hasWindow(int id) const;
-       
+
        int  getId() const;
        void debug() const;
 
-       void addSubWindow(gdWindow* w);
-       void delSubWindow(gdWindow* w);
-       void delSubWindow(int id);
-       void setId(int id);
-       void setParent(gdWindow* w);
+       void      addSubWindow(gdWindow* w);
+       void      delSubWindow(gdWindow* w);
+       void      delSubWindow(int id);
+       void      setId(int id);
+       void      setParent(gdWindow* w);
        gdWindow* getParent();
        gdWindow* getChild(int id);
 
-protected:
-
+  protected:
        std::vector<gdWindow*> subWindows;
-       int id;
-       gdWindow* parent;
+       int                    id;
+       gdWindow*              parent;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index c84dd8fac2d5c8b950ebed779349a7ed4693a49d..89df7e5c2eec7bc279be9718abceb9319df4b1e3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
+#include "dispatcher.h"
 #include "core/init.h"
 #include "glue/events.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "dispatcher.h"
-
+#include <FL/Fl.H>
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace v {
+namespace giada
+{
+namespace v
+{
 namespace dispatcher
 {
 namespace
@@ -51,97 +50,94 @@ bool space_     = false;
 bool esc_       = false;
 bool key_       = false;
 
-
 std::function<void()> signalCb_ = nullptr;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void perform_(ID channelId, int event)
 {
-       if (event == FL_KEYDOWN) {
+       if (event == FL_KEYDOWN)
+       {
                if (Fl::event_ctrl())
                        c::events::toggleMuteChannel(channelId, Thread::MAIN);
-               else
-               if (Fl::event_shift())
+               else if (Fl::event_shift())
                        c::events::killChannel(channelId, Thread::MAIN);
                else
                        c::events::pressChannel(channelId, G_MAX_VELOCITY, Thread::MAIN);
        }
-       else
-       if (event == FL_KEYUP)  
+       else if (event == FL_KEYUP)
                c::events::releaseChannel(channelId, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 /* Walk channels array, trying to match button's bound key with the event. If 
 found, trigger the key-press/key-release function. */
 
 void dispatchChannels_(int event)
 {
-       G_MainWin->keyboard->forEachChannel([=](geChannel& c)
-       {
+       G_MainWin->keyboard->forEachChannel([=](geChannel& c) {
                if (c.handleKey(event))
                        perform_(c.getData().id, event);
        });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void triggerSignalCb_()
 {
-       if (signalCb_ == nullptr) 
+       if (signalCb_ == nullptr)
                return;
        signalCb_();
        signalCb_ = nullptr;
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void dispatchKey(int event)
 {
        /* These events come from the keyboard, not from a direct interaction on the 
        UI with the mouse/touch. */
 
-       if (event == FL_KEYDOWN) {
-               if (Fl::event_key() == FL_BackSpace && !backspace_) {
+       if (event == FL_KEYDOWN)
+       {
+               if (Fl::event_key() == FL_BackSpace && !backspace_)
+               {
                        backspace_ = true;
                        c::events::rewindSequencer(Thread::MAIN);
                }
-               else if (Fl::event_key() == FL_End && !end_) {
+               else if (Fl::event_key() == FL_End && !end_)
+               {
                        end_ = true;
                        c::events::toggleInputRecording();
                }
-               else if (Fl::event_key() == FL_Enter && !enter_) {
+               else if (Fl::event_key() == FL_Enter && !enter_)
+               {
                        enter_ = true;
                        c::events::toggleActionRecording();
                }
-               else if (Fl::event_key() == ' ' && !space_) {
+               else if (Fl::event_key() == ' ' && !space_)
+               {
                        space_ = true;
                        c::events::toggleSequencer(Thread::MAIN);
                }
-               else if (Fl::event_key() == FL_Escape && !esc_) {
+               else if (Fl::event_key() == FL_Escape && !esc_)
+               {
                        esc_ = true;
                        m::init::closeMainWindow();
                }
-               else if (!key_) {
+               else if (!key_)
+               {
                        key_ = true;
                        triggerSignalCb_();
                        dispatchChannels_(event);
                }
        }
-       else if (event == FL_KEYUP) {
+       else if (event == FL_KEYUP)
+       {
                if (Fl::event_key() == FL_BackSpace)
                        backspace_ = false;
                else if (Fl::event_key() == FL_End)
@@ -152,30 +148,29 @@ void dispatchKey(int event)
                        enter_ = false;
                else if (Fl::event_key() == FL_Escape)
                        esc_ = false;
-               else {
+               else
+               {
                        key_ = false;
                        dispatchChannels_(event);
                }
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void dispatchTouch(const geChannel& gch, bool status)
 {
        triggerSignalCb_();
        perform_(gch.getData().id, status ? FL_KEYDOWN : FL_KEYUP);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setSignalCallback(std::function<void()> f)
 {
        signalCb_ = f;
 }
 
-}}} // giada::v::dispatcher
+} // namespace dispatcher
+} // namespace v
+} // namespace giada
index bb10117e3acfa1f3d46d4dbe5a58543a5282f408..2d4d7e19e4143ee5379f2dc055cb6fcec17aca9b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_V_DISPATCHER_H
 #define G_V_DISPATCHER_H
 
-
 #include <functional>
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geChannel;
 
@@ -50,7 +48,8 @@ Processes a mouse click/touch event. */
 void dispatchTouch(const geChannel& gch, bool status);
 
 void setSignalCallback(std::function<void()> f);
-}}} // giada::v::dispatcher
-
+} // namespace dispatcher
+} // namespace v
+} // namespace giada
 
 #endif
\ No newline at end of file
diff --git a/src/gui/drawing.cpp b/src/gui/drawing.cpp
new file mode 100644 (file)
index 0000000..b1b9cd6
--- /dev/null
@@ -0,0 +1,51 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "drawing.h"
+#include <FL/Fl.H>
+
+namespace giada::v
+{
+void drawRectf(geompp::Rect<int> r, Fl_Color c)
+{
+       fl_rectf(r.x, r.y, r.w, r.h, c);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void drawRect(geompp::Rect<int> r, Fl_Color c)
+{
+       fl_rect(r.x, r.y, r.w, r.h, c);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void drawLine(geompp::Line<int> l, Fl_Color c)
+{
+       fl_color(c);
+       fl_line(l.x1, l.y1, l.x2, l.y2);
+}
+} // namespace giada::v
diff --git a/src/gui/drawing.h b/src/gui/drawing.h
new file mode 100644 (file)
index 0000000..4ee7955
--- /dev/null
@@ -0,0 +1,40 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef G_V_DRAWING_H
+#define G_V_DRAWING_H
+
+#include "deps/geompp/src/rect.hpp"
+#include <FL/fl_draw.H>
+
+namespace giada::v
+{
+void drawRectf(geompp::Rect<int> r, Fl_Color c);
+void drawRect(geompp::Rect<int> r, Fl_Color c);
+void drawLine(geompp::Line<int> l, Fl_Color c);
+} // namespace giada::v
+
+#endif
\ No newline at end of file
index af71efc96240859f6e78f09d2ba9474281f13067..04cc65afcf671c5b4d8f95da7aba70baca83d03a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "baseAction.h"
 #include <FL/Fl.H>
 #include <FL/fl_draw.H>
-#include "baseAction.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geBaseAction::geBaseAction(Pixel X, Pixel Y, Pixel W, Pixel H, bool resizable,
-       m::Action a1, m::Action a2)
-: Fl_Box     (X, Y, W, H)
+    m::Action a1, m::Action a2)
+: Fl_Box(X, Y, W, H)
 , onRightEdge(false)
-, onLeftEdge (false)
-, hovered    (false)
-, altered    (false)
-, pick       (0)
-, a1         (a1)
-, a2         (a2)
+, onLeftEdge(false)
+, hovered(false)
+, altered(false)
+, pick(0)
+, a1(a1)
+, a2(a2)
 , m_resizable(resizable)
 {
        if (w() < MIN_WIDTH)
                size(MIN_WIDTH, h());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geBaseAction::handle(int e)
 {
-       switch (e) {
-               case FL_ENTER: {
-                       hovered = true;
-                       redraw();
-                       return 1;
-               }
-               case FL_LEAVE: {
-                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                       hovered = false;
-                       redraw();
-                       return 1;
-               }
-               case FL_MOVE: {
-                       if (m_resizable) {
-                               onLeftEdge  = false;
-                               onRightEdge = false;
-                               if (Fl::event_x() >= x() && Fl::event_x() < x() + HANDLE_WIDTH) {
-                                       onLeftEdge = true;
-                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                               }
-                               else
-                               if (Fl::event_x() >= x() + w() - HANDLE_WIDTH && 
-                                         Fl::event_x() <= x() + w()) {
-                                       onRightEdge = true;
-                                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                               }
-                               else
-                                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+       switch (e)
+       {
+       case FL_ENTER:
+       {
+               hovered = true;
+               redraw();
+               return 1;
+       }
+       case FL_LEAVE:
+       {
+               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+               hovered = false;
+               redraw();
+               return 1;
+       }
+       case FL_MOVE:
+       {
+               if (m_resizable)
+               {
+                       onLeftEdge  = false;
+                       onRightEdge = false;
+                       if (Fl::event_x() >= x() && Fl::event_x() < x() + HANDLE_WIDTH)
+                       {
+                               onLeftEdge = true;
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
                        }
-                       return 1;
+                       else if (Fl::event_x() >= x() + w() - HANDLE_WIDTH &&
+                                Fl::event_x() <= x() + w())
+                       {
+                               onRightEdge = true;
+                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+                       }
+                       else
+                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
                }
-               default:
-                       return Fl_Widget::handle(e);
+               return 1;
+       }
+       default:
+               return Fl_Widget::handle(e);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBaseAction::setLeftEdge(Pixel p)
 {
        resize(p, y(), x() - p + w(), h());
@@ -102,10 +103,8 @@ void geBaseAction::setLeftEdge(Pixel p)
                size(MIN_WIDTH, h());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBaseAction::setRightEdge(Pixel p)
 {
        size(p, h());
@@ -113,21 +112,18 @@ void geBaseAction::setRightEdge(Pixel p)
                size(MIN_WIDTH, h());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBaseAction::setPosition(Pixel p)
 {
        position(p, y());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geBaseAction::isOnEdges() const
 {
        return onLeftEdge || onRightEdge;
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index f01338341b706a569de964341b4efc5b2e18def4..664a7aa8e921558ff31021501051ead9f2fd5f7f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BASE_ACTION_H
 #define GE_BASE_ACTION_H
 
-
-#include <FL/Fl_Box.H>
 #include "core/recorder.h"
 #include "core/types.h"
+#include <FL/Fl_Box.H>
 
-
-namespace giada {
-namespace m 
+namespace giada::m
 {
 struct Action;
 }
-namespace v
+namespace giada::v
 {
 class geBaseAction : public Fl_Box
 {
 public:
-
        static const Pixel MIN_WIDTH    = 12;
        static const Pixel HANDLE_WIDTH = 6;
 
-       geBaseAction(Pixel x, Pixel y, Pixel w, Pixel h, bool resizable, 
-               m::Action a1, m::Action a2);
+       geBaseAction(Pixel x, Pixel y, Pixel w, Pixel h, bool resizable,
+           m::Action a1, m::Action a2);
 
        int handle(int e) override;
 
@@ -63,19 +58,18 @@ public:
 
        void setPosition(Pixel p);
 
-       bool onRightEdge;
-       bool onLeftEdge;
-       bool hovered;
-       bool altered;
+       bool  onRightEdge;
+       bool  onLeftEdge;
+       bool  hovered;
+       bool  altered;
        Pixel pick;
 
        m::Action a1;
        m::Action a2;
-       
-protected:
-       
+
+  protected:
        bool m_resizable;
 };
-}} // giada::v::
+} // namespace giada::v
 
 #endif
index ee5cf1b756e3f82e3247f1e4e1adffb467b1eac8..dc79fe5d0cc1101198643cbbcc0f70f9b10a33ab 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include "core/const.h"
-#include "core/clock.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
-#include "gridTool.h"
 #include "baseAction.h"
 #include "baseActionEditor.h"
+#include "core/clock.h"
+#include "core/const.h"
+#include "gridTool.h"
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geBaseActionEditor::geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h,
-       gdBaseActionEditor* base)
+    gdBaseActionEditor* base)
 : Fl_Group(x, y, w, h)
-, m_data  (nullptr)
-, m_base  (base)
+, m_data(nullptr)
+, m_base(base)
 , m_action(nullptr)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geBaseAction* geBaseActionEditor::getActionAtCursor() const
 {
-       for (int i = 0; i < children(); i++) {
+       for (int i = 0; i < children(); i++)
+       {
                geBaseAction* a = static_cast<geBaseAction*>(child(i));
                if (a->hovered)
                        return a;
@@ -61,10 +59,8 @@ geBaseAction* geBaseActionEditor::getActionAtCursor() const
        return nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBaseActionEditor::baseDraw(bool clear) const
 {
        /* Clear the screen. */
@@ -80,7 +76,8 @@ void geBaseActionEditor::baseDraw(bool clear) const
        /* Draw grid, beats and bars. A grid set to 1 has a cell size == beat, so
        painting it is useless. */
 
-       if (m_base->gridTool->getValue() > 1) {
+       if (m_base->gridTool->getValue() > 1)
+       {
                fl_color(G_COLOR_GREY_3);
                drawVerticals(m_base->gridTool->getCellSize());
        }
@@ -95,71 +92,69 @@ void geBaseActionEditor::baseDraw(bool clear) const
 
        Pixel coverWidth = m_base->fullWidth - m_base->loopWidth;
        if (coverWidth != 0)
-               fl_rectf(m_base->loopWidth+x(), y()+1, coverWidth, h()-2, G_COLOR_GREY_4);
+               fl_rectf(m_base->loopWidth + x(), y() + 1, coverWidth, h() - 2, G_COLOR_GREY_4);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBaseActionEditor::drawVerticals(int steps) const
 {
        /* Start drawing from steps, not from 0. The zero-th element is always 
        graphically useless. */
-       for (Frame i=steps; i<m::clock::getFramesInLoop(); i+=steps) {
+       for (Frame i = steps; i < m::clock::getFramesInLoop(); i += steps)
+       {
                Pixel p = m_base->frameToPixel(i) + x();
-               fl_line(p, y()+1, p, y()+h()-2);
-       }       
+               fl_line(p, y() + 1, p, y() + h() - 2);
+       }
 }
 
 /* -------------------------------------------------------------------------- */
 
-
 int geBaseActionEditor::handle(int e)
 {
-       switch (e) {
-               case FL_PUSH:
-                       return push();
-               case FL_DRAG:
-                       return drag();
-               case FL_RELEASE:
-                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); // Make sure cursor returns normal
-                       return release();
-               default:
-                       return Fl_Group::handle(e);
+       switch (e)
+       {
+       case FL_PUSH:
+               return push();
+       case FL_DRAG:
+               return drag();
+       case FL_RELEASE:
+               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); // Make sure cursor returns normal
+               return release();
+       default:
+               return Fl_Group::handle(e);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geBaseActionEditor::push()
 {
        m_action = getActionAtCursor();
 
-       if (Fl::event_button1()) {    // Left button
-               if (m_action == nullptr) {  // No action under cursor: add a new one
+       if (Fl::event_button1())
+       { // Left button
+               if (m_action == nullptr)
+               {                                          // No action under cursor: add a new one
                        if (Fl::event_x() < m_base->loopWidth) // Avoid click on grey area
                                onAddAction();
                }
-               else                        // Prepare for dragging
+               else // Prepare for dragging
                        m_action->pick = Fl::event_x() - m_action->x();
        }
-       else
-       if (Fl::event_button3()) {    // Right button
-               if (m_action != nullptr) {
+       else if (Fl::event_button3())
+       { // Right button
+               if (m_action != nullptr)
+               {
                        onDeleteAction();
                        m_action = nullptr;
                }
        }
-       return 1;       
+       return 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geBaseActionEditor::drag()
 {
        if (m_action == nullptr)
@@ -173,18 +168,18 @@ int geBaseActionEditor::drag()
        return 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geBaseActionEditor::release()
 {
        int ret = 0;
-       if (m_action != nullptr && m_action->altered) {
+       if (m_action != nullptr && m_action->altered)
+       {
                onRefreshAction();
                ret = 1;
        }
        m_action = nullptr;
        return ret;
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 74032d9734a3cd7dc0295dde9122c7532ae4440b..028a88ea1bc9fb8a68a858780b6aea84278fd4ea 100644 (file)
@@ -5,7 +5,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BASE_ACTION_EDITOR_H
 #define GE_BASE_ACTION_EDITOR_H
 
-
+#include "core/types.h"
 #include <FL/Fl_Group.H>
 
-
-namespace giada {
-namespace v
+namespace giada::c::actionEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class gdBaseActionEditor;
 class geBaseAction;
-
 class geBaseActionEditor : public Fl_Group
 {
 public:
-
        /* updateActions
        Rebuild the actions widgets from scratch. */
-  
+
        virtual void rebuild(c::actionEditor::Data& d) = 0;
 
        /* handle
        Override base FL_Group events. */
-       
+
        int handle(int e) override;
 
        /* getActionAtCursor
@@ -59,8 +58,7 @@ public:
 
        geBaseAction* getActionAtCursor() const;
 
-protected:
-
+  protected:
        geBaseActionEditor(Pixel x, Pixel y, Pixel w, Pixel h, gdBaseActionEditor*);
 
        c::actionEditor::Data* m_data;
@@ -78,7 +76,7 @@ protected:
        /* baseDraw
        Draws basic things like borders and grids. Optional background clear. */
 
-  void baseDraw(bool clear=true) const;
+       void baseDraw(bool clear = true) const;
 
        virtual void onAddAction()     = 0;
        virtual void onDeleteAction()  = 0;
@@ -86,18 +84,16 @@ protected:
        virtual void onResizeAction()  = 0;
        virtual void onRefreshAction() = 0;
 
-private:
-       
+  private:
        /* drawVerticals
        Draws generic vertical lines (beats, bars, grid lines...). */
-       
+
        void drawVerticals(int steps) const;
-       
+
        int push();
        int drag();
        int release();
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 83fe8ec0f9795a1ee9548551d814d82ee837fd1b..b8e6d7814feeb1341d256306e5e28540630613df 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include "utils/log.h"
-#include "utils/math.h"
-#include "core/const.h"
-#include "core/conf.h"
+#include "envelopeEditor.h"
 #include "core/action.h"
+#include "core/conf.h"
+#include "core/const.h"
 #include "core/recorder.h"
+#include "envelopePoint.h"
 #include "glue/actionEditor.h"
 #include "glue/channel.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
-#include "envelopePoint.h"
-#include "envelopeEditor.h"
-
+#include "utils/log.h"
+#include "utils/math.h"
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geEnvelopeEditor::geEnvelopeEditor(Pixel x, Pixel y, const char* l, gdBaseActionEditor* b)
@@ -50,20 +49,16 @@ geEnvelopeEditor::geEnvelopeEditor(Pixel x, Pixel y, const char* l, gdBaseAction
        copy_label(l);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geEnvelopeEditor::~geEnvelopeEditor()
 {
        m::conf::conf.envelopeEditorH = h();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geEnvelopeEditor::draw() 
+void geEnvelopeEditor::draw()
 {
        baseDraw();
 
@@ -71,7 +66,7 @@ void geEnvelopeEditor::draw()
 
        fl_color(G_COLOR_GREY_4);
        fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
-       fl_draw(label(), x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT));
+       fl_draw(label(), x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT));
 
        if (children() == 0)
                return;
@@ -88,11 +83,13 @@ void geEnvelopeEditor::draw()
                - reposition it on the y axis, only if there's no point selected (dragged
            around). */
 
-       for (int i=0; i<children(); i++) {
+       for (int i = 0; i < children(); i++)
+       {
                geEnvelopePoint* p = static_cast<geEnvelopePoint*>(child(i));
                if (m_action == nullptr)
                        p->position(p->x(), valueToY(p->a1.event.getVelocity()));
-               if (i > 0) {
+               if (i > 0)
+               {
                        x2 = p->x() + side;
                        y2 = p->y() + side;
                        fl_line(x1, y1, x2, y2);
@@ -104,10 +101,8 @@ void geEnvelopeEditor::draw()
        draw_children();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geEnvelopeEditor::rebuild(c::actionEditor::Data& d)
 {
        m_data = &d;
@@ -118,10 +113,11 @@ void geEnvelopeEditor::rebuild(c::actionEditor::Data& d)
        clear();
        size(m_base->fullWidth, h());
 
-       for (const m::Action& a : m_data->actions) {
+       for (const m::Action& a : m_data->actions)
+       {
                if (a.event.getStatus() != m::MidiEvent::ENVELOPE)
                        continue;
-               add(new geEnvelopePoint(frameToX(a.frame), valueToY(a.event.getVelocity()), a));                
+               add(new geEnvelopePoint(frameToX(a.frame), valueToY(a.event.getVelocity()), a));
        }
 
        resizable(nullptr);
@@ -129,72 +125,59 @@ void geEnvelopeEditor::rebuild(c::actionEditor::Data& d)
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geEnvelopeEditor::isFirstPoint() const
 {
        return find(m_action) == 0;
 }
 
-
 bool geEnvelopeEditor::isLastPoint() const
 {
        return find(m_action) == children() - 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Pixel geEnvelopeEditor::frameToX(Frame frame) const
 {
        return x() + m_base->frameToPixel(frame) - (geEnvelopePoint::SIDE / 2);
 }
 
-
 Pixel geEnvelopeEditor::valueToY(int value) const
 {
        return u::math::map<int, Pixel>(value, 0, G_MAX_VELOCITY, y() + (h() - geEnvelopePoint::SIDE), y());
 }
 
-
 int geEnvelopeEditor::yToValue(Pixel pixel, Pixel offset) const
 {
-       return u::math::map<Pixel, int>(pixel, h() - offset, 0, 0, G_MAX_VELOCITY);     
+       return u::math::map<Pixel, int>(pixel, h() - offset, 0, 0, G_MAX_VELOCITY);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geEnvelopeEditor::onAddAction()     
+void geEnvelopeEditor::onAddAction()
 {
        Frame f = m_base->pixelToFrame(Fl::event_x() - x());
        int   v = yToValue(Fl::event_y() - y());
-       
+
        c::actionEditor::recordEnvelopeAction(m_data->channelId, f, v);
-       
+
        m_base->rebuild(); // TODO - USELESS
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geEnvelopeEditor::onDeleteAction()  
+void geEnvelopeEditor::onDeleteAction()
 {
        c::actionEditor::deleteEnvelopeAction(m_data->channelId, m_action->a1);
-               
+
        m_base->rebuild(); // TODO - USELESS
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geEnvelopeEditor::onMoveAction()    
+void geEnvelopeEditor::onMoveAction()
 {
        Pixel side = geEnvelopePoint::SIDE / 2;
        Pixel ex   = Fl::event_x() - side;
@@ -206,21 +189,24 @@ void geEnvelopeEditor::onMoveAction()
        Pixel y2 = y() + h() - geEnvelopePoint::SIDE;
 
        /* x-axis constraints. */
-       if      (isFirstPoint() || ex < x1) ex = x1; 
-       else if (isLastPoint()  || ex > x2) ex = x2;
+       if (isFirstPoint() || ex < x1)
+               ex = x1;
+       else if (isLastPoint() || ex > x2)
+               ex = x2;
 
        /* y-axis constraints. */
-       if (ey < y1) ey = y1; else if (ey > y2) ey = y2;
+       if (ey < y1)
+               ey = y1;
+       else if (ey > y2)
+               ey = y2;
 
        m_action->position(ex, ey);
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geEnvelopeEditor::onRefreshAction() 
+void geEnvelopeEditor::onRefreshAction()
 {
        Frame f = m_base->pixelToFrame((m_action->x() - x()) + geEnvelopePoint::SIDE / 2);
        float v = yToValue(m_action->y() - y(), geEnvelopePoint::SIDE);
@@ -228,4 +214,5 @@ void geEnvelopeEditor::onRefreshAction()
 
        m_base->rebuild();
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 50def75e34f07dddd70f3d5f4a14f121d77bccba..f7663c7c0a86fc5552c8dc932b4bb7f15087b73e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_ENVELOPE_EDITOR_H
 #define GE_ENVELOPE_EDITOR_H
 
-
 #include "baseActionEditor.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 class SampleChannel;
@@ -43,7 +41,6 @@ class geEnvelopePoint;
 class geEnvelopeEditor : public geBaseActionEditor
 {
 public:
-
        geEnvelopeEditor(Pixel x, Pixel y, const char* l, gdBaseActionEditor*);
        ~geEnvelopeEditor();
 
@@ -51,21 +48,21 @@ public:
 
        void rebuild(c::actionEditor::Data& d) override;
 
-private:
-
-       void onAddAction()     override;
-       void onDeleteAction()  override;
-       void onMoveAction()    override;
-       void onResizeAction()  override{}; // Nothing to do here
+  private:
+       void onAddAction() override;
+       void onDeleteAction() override;
+       void onMoveAction() override;
+       void onResizeAction() override{}; // Nothing to do here
        void onRefreshAction() override;
 
        Pixel frameToX(Frame frame) const;
        Pixel valueToY(int value) const;
-       int   yToValue(Pixel pixel, Pixel offset=0) const;
+       int   yToValue(Pixel pixel, Pixel offset = 0) const;
 
        bool isFirstPoint() const;
-       bool isLastPoint()  const;
+       bool isLastPoint() const;
 };
-}} // giada::v::
+} // namespace v
+} // namespace giada
 
 #endif
index 67c90e1ce496b5e95ad4a82b6ff74bfc50ed6664..4215d3916750b734bc8b5659cae02263a5c804c7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
-#include "core/const.h"
 #include "envelopePoint.h"
+#include "core/const.h"
+#include <FL/fl_draw.H>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geEnvelopePoint::geEnvelopePoint(Pixel X, Pixel Y, m::Action a)
-       : geBaseAction(X, Y, SIDE, SIDE, /*resizable=*/false, a, {})
+: geBaseAction(X, Y, SIDE, SIDE, /*resizable=*/false, a, {})
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geEnvelopePoint::draw()
 {
        fl_rectf(x(), y(), w(), h(), hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1);
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index dde54caaa26b6348ca33fbc2404b1e44c1a16ce5..8f4d4f457fd6e62239a174f4736732fbb0c02af8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_ENVELOPE_POINT_H
 #define GE_ENVELOPE_POINT_H
 
-
-#include "core/recorder.h"
 #include "baseAction.h"
+#include "core/recorder.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geEnvelopePoint : public geBaseAction
 {
 public:
-
        static const Pixel SIDE = 12;
 
        geEnvelopePoint(Pixel x, Pixel y, m::Action a);
 
        void draw() override;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 95751a567f933006e1e1a19e6e84479d685b717b..622d46d72c3d7eb1d187e42f0197a5bd1bde5f83 100644 (file)
@@ -4,7 +4,7 @@
 *
 * ------------------------------------------------------------------------------
 *
-* Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+* Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
 *
 * This file is part of Giada - Your Hardcore Loopmachine.
 *
 *
 * --------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Double_Window.H>
-#include "core/conf.h"
+#include "gridTool.h"
 #include "core/clock.h"
-#include "utils/math.h"
-#include "gui/elems/basics/choice.h"
+#include "core/conf.h"
 #include "gui/elems/basics/check.h"
-#include "gridTool.h"
-
+#include "gui/elems/basics/choice.h"
+#include "utils/math.h"
+#include <FL/Fl_Double_Window.H>
 
-namespace giada {
-namespace v
+namespace giada::v
 {
 geGridTool::geGridTool(Pixel x, Pixel y)
-:      Fl_Group(x, y, 80, 20)
+: Fl_Group(x, y, 80, 20)
 {
        gridType = new geChoice(x, y, 40, 20);
        gridType->add("1");
@@ -58,65 +55,65 @@ geGridTool::geGridTool(Pixel x, Pixel y)
        active->value(m::conf::conf.actionEditorGridOn);
 
        end();
-}
 
+       gridType->copy_tooltip("Grid resolution");
+       active->copy_tooltip("Snap to grid");
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 geGridTool::~geGridTool()
 {
        m::conf::conf.actionEditorGridVal = gridType->value();
        m::conf::conf.actionEditorGridOn  = active->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geGridTool::cb_changeType(Fl_Widget* /*w*/, void* p) { ((geGridTool*)p)->cb_changeType(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geGridTool::cb_changeType()
 {
        window()->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geGridTool::isOn() const
 {
        return active->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geGridTool::getValue() const
 {
-       switch (gridType->value()) {
-               case 0: return 1;
-               case 1: return 2;
-               case 2: return 3;
-               case 3: return 4;
-               case 4: return 6;
-               case 5: return 8;
-               case 6: return 16;
-               case 7: return 32;
+       switch (gridType->value())
+       {
+       case 0:
+               return 1;
+       case 1:
+               return 2;
+       case 2:
+               return 3;
+       case 3:
+               return 4;
+       case 4:
+               return 6;
+       case 5:
+               return 8;
+       case 6:
+               return 16;
+       case 7:
+               return 32;
        }
        return 0;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Frame geGridTool::getSnapFrame(Frame v) const
 {
        if (!isOn())
@@ -124,12 +121,10 @@ Frame geGridTool::getSnapFrame(Frame v) const
        return u::math::quantize(v, getCellSize());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Frame geGridTool::getCellSize() const
 {
        return m::clock::getFramesInBeat() / getValue();
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace giada::v
\ No newline at end of file
index 0b61bfcbe238b766fb3b8db1cb8934e9d9d3573a..04b4cf1b577796d5fa4c95b2852c3573f96f916d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_GRID_TOOL_H
 #define GE_GRID_TOOL_H
 
-
-#include <FL/Fl_Group.H>
 #include "core/types.h"
-
+#include <FL/Fl_Group.H>
 
 class geCheck;
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 class geChoice;
 class geGridTool : public Fl_Group
 {
 public:
-
        geGridTool(Pixel x, Pixel y);
        ~geGridTool();
 
-       int getValue() const;
+       int  getValue() const;
        bool isOn() const;
 
        Frame getSnapFrame(Frame f) const;
@@ -57,15 +51,13 @@ public:
 
        Frame getCellSize() const;
 
-private:
-
-       geChoice* gridType;
+  private:
+       geChoice* gridType;
        geCheck*  active;
 
        static void cb_changeType(Fl_Widget* /*w*/, void* p);
-       void cb_changeType();
+       void        cb_changeType();
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 574280f4cf1f6e34c272df7884eea70dc0aefa34..42936fecbbc94091ba210c75ba3dc1bfbfd24fc4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include "core/const.h"
+#include "noteEditor.h"
 #include "core/conf.h"
+#include "core/const.h"
 #include "gui/dialogs/actionEditor/midiActionEditor.h"
 #include "pianoRoll.h"
-#include "noteEditor.h"
-
+#include <FL/Fl.H>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geNoteEditor::geNoteEditor(Pixel x, Pixel y, gdMidiActionEditor* base)
 : geScroll(x, y, 200, 422)
-, m_base  (base)
+, m_base(base)
 {
        end();
-       
+
        type(Fl_Scroll::VERTICAL_ALWAYS);
        size(m_base->fullWidth, m::conf::conf.pianoRollH);
 
@@ -49,20 +48,16 @@ geNoteEditor::geNoteEditor(Pixel x, Pixel y, gdMidiActionEditor* base)
        add(pianoRoll);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geNoteEditor::~geNoteEditor()
 {
        m::conf::conf.pianoRollH = h();
        m::conf::conf.pianoRollY = pianoRoll->y();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geNoteEditor::scroll()
 {
        Pixel ey = Fl::event_y() - pianoRoll->pick;
@@ -70,20 +65,22 @@ void geNoteEditor::scroll()
        Pixel y1 = y();
        Pixel y2 = (y() + h()) - pianoRoll->h();
 
-       if (ey > y1) ey = y1; else if (ey < y2) ey = y2;
+       if (ey > y1)
+               ey = y1;
+       else if (ey < y2)
+               ey = y2;
 
        pianoRoll->position(x(), ey);
 
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geNoteEditor::rebuild(c::actionEditor::Data& d)
 {
        size(m_base->fullWidth, h());
        pianoRoll->rebuild(d);
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 143dd835efecafe045a4c527308973ffe23b89b4..9c737d52726f23636b8a67b1eb6518496c6ce160 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_NOTE_EDITOR_H
 #define GE_NOTE_EDITOR_H
 
-
+#include "core/types.h"
 #include "gui/elems/basics/scroll.h"
 
-
-namespace giada {
-namespace v
+namespace giada::c::actionEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class gdMidiActionEditor;
 class gePianoRoll;
 class geNoteEditor : public geScroll
 {
 public:
-
        geNoteEditor(Pixel x, Pixel y, gdMidiActionEditor* base);
        ~geNoteEditor();
 
@@ -49,10 +49,9 @@ public:
 
        gePianoRoll* pianoRoll;
 
-private:
-
-    gdMidiActionEditor* m_base;
+  private:
+       gdMidiActionEditor* m_base;
 };
-}} // giada::v::
+} // namespace giada::v
 
 #endif
index 9581cc3573c221e12c38777ef14efee5bbdbba09..e44f9a69652a6cfc2cd7bd6ea1f642752a4764ee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
-#include "core/const.h"
+#include "pianoItem.h"
 #include "core/action.h"
+#include "core/const.h"
 #include "core/midiEvent.h"
 #include "utils/math.h"
-#include "pianoItem.h"
-
+#include <FL/fl_draw.H>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gePianoItem::gePianoItem(Pixel X, Pixel Y, Pixel W, Pixel H, m::Action a1,
-       m::Action a2)
-: geBaseAction(X, Y, W, H, /*resizable=*/true, a1, a2),
-  m_ringLoop  (a2.isValid() && a1.frame > a2.frame),
-  m_orphaned  (!a2.isValid())
+    m::Action a2)
+: geBaseAction(X, Y, W, H, /*resizable=*/true, a1, a2)
+, m_ringLoop(a2.isValid() && a1.frame > a2.frame)
+, m_orphaned(!a2.isValid())
 {
        m_resizable = isResizable();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool gePianoItem::isResizable() const
 {
        return !(m_ringLoop || m_orphaned);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoItem::draw()
 {
        Fl_Color color = hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1;
@@ -65,31 +60,34 @@ void gePianoItem::draw()
        Pixel by = y() + 2;
        Pixel bh = h() - 3;
 
-       if (m_orphaned) {
+       if (m_orphaned)
+       {
                fl_rect(x(), by, w(), bh, color);
                fl_line(x(), by, x() + w(), by + bh);
        }
-       else {
+       else
+       {
                Pixel vh = calcVelocityH();
-               if (m_ringLoop) {
+               if (m_ringLoop)
+               {
                        fl_rect(x(), by, MIN_WIDTH, bh, color);
-                       fl_line(x() + MIN_WIDTH, by + bh/2, x() + w(), by + bh/2);
+                       fl_line(x() + MIN_WIDTH, by + bh / 2, x() + w(), by + bh / 2);
                        fl_rectf(x(), by + (bh - vh), MIN_WIDTH, vh, color);
                }
-               else {
+               else
+               {
                        fl_rect(x(), by, w(), bh, color);
                        fl_rectf(x(), by + (bh - vh), w(), vh, color);
                }
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Pixel gePianoItem::calcVelocityH() const
 {
        int v = a1.event.getVelocity();
        return u::math::map<int, Pixel>(v, 0, G_MAX_VELOCITY, 0, h() - 3);
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 01ac51a6490711ba98b1db1a68567e942cd4e2d8..00c25f120d698badc7f97c7cfba951413e89521c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_PIANO_ITEM_H
 #define GE_PIANO_ITEM_H
 
-
 #include "baseAction.h"
 
-
-namespace giada {
-namespace m 
+namespace giada
+{
+namespace m
 {
 struct Action;
 }
@@ -44,21 +42,19 @@ class gdActionEditor;
 class gePianoItem : public geBaseAction
 {
 public:
-
        gePianoItem(int x, int y, int w, int h, m::Action a1, m::Action a2);
+
        void draw() override;
 
        bool isResizable() const;
 
-private:
+  private:
+       bool m_ringLoop;
+       bool m_orphaned;
 
-    bool m_ringLoop;
-    bool m_orphaned;
-
-    Pixel calcVelocityH() const;
+       Pixel calcVelocityH() const;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 08c4dbac29880f5bc62c5368eac7595f99b41f69..78c5ae3a03caba9e7a3bbca5e8627b2349c0ad6b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
+#include "pianoRoll.h"
+#include "core/action.h"
+#include "core/clock.h"
 #include "core/conf.h"
 #include "core/const.h"
-#include "core/clock.h"
-#include "core/action.h"
 #include "core/midiEvent.h"
-#include "utils/log.h"
-#include "utils/string.h"
-#include "utils/math.h"
-#include "glue/channel.h"
 #include "glue/actionEditor.h"
+#include "glue/channel.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
-#include "pianoItem.h"
 #include "noteEditor.h"
-#include "pianoRoll.h"
-
+#include "pianoItem.h"
+#include "utils/log.h"
+#include "utils/math.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gePianoRoll::gePianoRoll(Pixel X, Pixel Y, Pixel W, gdBaseActionEditor* b)
 : geBaseActionEditor(X, Y, W, 40, b)
-, pick              (0)
+, pick(0)
 {
-       position(x(), m::conf::conf.pianoRollY == -1 ? y()-(h()/2) : m::conf::conf.pianoRollY);
+       position(x(), m::conf::conf.pianoRollY == -1 ? y() - (h() / 2) : m::conf::conf.pianoRollY);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::drawSurface1()
 {
        surface1 = fl_create_offscreen(CELL_W, h());
@@ -72,76 +69,76 @@ void gePianoRoll::drawSurface1()
 
        int octave = MAX_OCTAVES;
 
-       for (int i = 1; i <= MAX_KEYS+1; i++) {
+       for (int i = 1; i <= MAX_KEYS + 1; i++)
+       {
 
                /* print key note label. C C# D D# E F F# G G# A A# B */
 
                std::string note = u::string::iToString(octave);
-               switch (i % KEYS) {
-                       case (int) Notes::G:
-                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               note += " G"; 
-                               break;
-                       case (int) Notes::FS:
-                               note += " F#";
-                               break;
-                       case (int) Notes::F:
-                               note += " F";
-                               break;
-                       case (int) Notes::E:
-                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               note += " E";
-                               break;
-                       case (int) Notes::DS:
-                               note += " D#";
-                               break;
-                       case (int) Notes::D:
-                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               note += " D";
-                               break;
-                       case (int) Notes::CS:
-                               note += " C#";
-                               break;
-                       case (int) Notes::C:
-                               note += " C";
-                               octave--;
-                               break;
-                       case (int) Notes::B:
-                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               note += " B";
-                               break;
-                       case (int) Notes::AS:
-                               note += " A#";
-                               break;
-                       case (int) Notes::A:
-                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               note += " A";
-                               break;
-                       case (int) Notes::GS:
-                               note += " G#";
-                               break;
+               switch (i % KEYS)
+               {
+               case (int)Notes::G:
+                       fl_rectf(0, i * CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
+                       note += " G";
+                       break;
+               case (int)Notes::FS:
+                       note += " F#";
+                       break;
+               case (int)Notes::F:
+                       note += " F";
+                       break;
+               case (int)Notes::E:
+                       fl_rectf(0, i * CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
+                       note += " E";
+                       break;
+               case (int)Notes::DS:
+                       note += " D#";
+                       break;
+               case (int)Notes::D:
+                       fl_rectf(0, i * CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
+                       note += " D";
+                       break;
+               case (int)Notes::CS:
+                       note += " C#";
+                       break;
+               case (int)Notes::C:
+                       note += " C";
+                       octave--;
+                       break;
+               case (int)Notes::B:
+                       fl_rectf(0, i * CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
+                       note += " B";
+                       break;
+               case (int)Notes::AS:
+                       note += " A#";
+                       break;
+               case (int)Notes::A:
+                       fl_rectf(0, i * CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
+                       note += " A";
+                       break;
+               case (int)Notes::GS:
+                       note += " G#";
+                       break;
                }
 
                /* Print note name */
 
                fl_color(G_COLOR_GREY_3);
-               fl_draw(note.c_str(), 4, ((i-1)*CELL_H)+1, CELL_W, CELL_H,
-                       (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+               fl_draw(note.c_str(), 4, ((i - 1) * CELL_H) + 1, CELL_W, CELL_H,
+                   (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
 
                /* Print horizontal line */
 
-               if (i < MAX_KEYS+1)
-                       fl_line(0, i*CELL_H, CELL_W, +i*CELL_H);
+               if (i < MAX_KEYS + 1)
+                       fl_line(0, i * CELL_H, CELL_W, +i * CELL_H);
        }
 
        fl_line_style(0);
        fl_end_offscreen();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::drawSurface2()
 {
        surface2 = fl_create_offscreen(CELL_W, h());
@@ -151,19 +148,22 @@ void gePianoRoll::drawSurface2()
        fl_color(G_COLOR_GREY_3);
        fl_line_style(FL_DASH, 0, nullptr);
 
-       for (int i=1; i<=MAX_KEYS+1; i++) {
-               switch (i % KEYS) {
-                       case (int) Notes::G:
-                       case (int) Notes::E:
-                       case (int) Notes::D:
-                       case (int) Notes::B:
-                       case (int) Notes::A:
-                               fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               break;
+       for (int i = 1; i <= MAX_KEYS + 1; i++)
+       {
+               switch (i % KEYS)
+               {
+               case (int)Notes::G:
+               case (int)Notes::E:
+               case (int)Notes::D:
+               case (int)Notes::B:
+               case (int)Notes::A:
+                       fl_rectf(0, i * CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
+                       break;
                }
-               if (i < MAX_KEYS+1) {
+               if (i < MAX_KEYS + 1)
+               {
                        fl_color(G_COLOR_GREY_3);
-                       fl_line(0, i*CELL_H, CELL_W, i*CELL_H);
+                       fl_line(0, i * CELL_H, CELL_W, i * CELL_H);
                }
        }
 
@@ -171,10 +171,8 @@ void gePianoRoll::drawSurface2()
        fl_end_offscreen();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::draw()
 {
        fl_copy_offscreen(x(), y(), CELL_W, h(), surface1, 0, 0);
@@ -182,85 +180,83 @@ void gePianoRoll::draw()
 // TODO - is this APPLE thing still useful?
 #if defined(__APPLE__)
        for (Pixel i = 36; i < m_base->fullWidth; i += 36) /// TODO: i < m_base->loopWidth is faster
-               fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 1, 0);
+               fl_copy_offscreen(x() + i, y(), CELL_W, h(), surface2, 1, 0);
 #else
        for (Pixel i = CELL_W; i < m_base->loopWidth; i += CELL_W)
-               fl_copy_offscreen(x()+i, y(), CELL_W, h(), surface2, 0, 0);
+               fl_copy_offscreen(x() + i, y(), CELL_W, h(), surface2, 0, 0);
 #endif
 
        baseDraw(false);
        draw_children();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int gePianoRoll::handle(int e)
 {
-       if (e == FL_PUSH && Fl::event_button3()) {
+       if (e == FL_PUSH && Fl::event_button3())
+       {
                pick = Fl::event_y() - y();
                return geBaseActionEditor::handle(e);
        }
-       if (e == FL_DRAG && Fl::event_button3()) {
+       if (e == FL_DRAG && Fl::event_button3())
+       {
                static_cast<geNoteEditor*>(parent())->scroll();
                return 1;
        }
        return geBaseActionEditor::handle(e);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::onAddAction()
 {
        Frame frame = m_base->pixelToFrame(Fl::event_x() - x());
        int   note  = yToNote(Fl::event_y() - y());
-       c::actionEditor::recordMidiAction(m_data->channelId, note, G_MAX_VELOCITY, 
-               frame);
+       c::actionEditor::recordMidiAction(m_data->channelId, note, G_MAX_VELOCITY,
+           frame);
 
-       m_base->rebuild();  // Rebuild velocityEditor as well
+       m_base->rebuild(); // Rebuild velocityEditor as well
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::onDeleteAction()
 {
-       c::actionEditor::deleteMidiAction(m_data->channelId, m_action->a1);     
-       
-       m_base->rebuild();  // Rebuild velocityEditor as well
-}
+       c::actionEditor::deleteMidiAction(m_data->channelId, m_action->a1);
 
+       m_base->rebuild(); // Rebuild velocityEditor as well
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::onMoveAction()
 {
        /* Y computation:  - (CELL_H/2) is wrong: we should need the y pick value as 
        done with x. Let's change this when vertical piano zoom will be available. */
 
        Pixel ex = Fl::event_x() - m_action->pick;
-       Pixel ey = snapToY(Fl::event_y() - y() - (CELL_H/2)) + y();
+       Pixel ey = snapToY(Fl::event_y() - y() - (CELL_H / 2)) + y();
 
        Pixel x1 = x();
        Pixel x2 = (m_base->loopWidth + x()) - m_action->w();
        Pixel y1 = y();
        Pixel y2 = y() + h();
 
-       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
-       if (ey < y1) ey = y1; else if (ey > y2) ey = y2;
+       if (ex < x1)
+               ex = x1;
+       else if (ex > x2)
+               ex = x2;
+       if (ey < y1)
+               ey = y1;
+       else if (ey > y2)
+               ey = y2;
 
        m_action->position(ex, ey);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::onResizeAction()
 {
        if (!static_cast<gePianoItem*>(m_action)->isResizable())
@@ -270,19 +266,20 @@ void gePianoRoll::onResizeAction()
 
        Pixel x1 = x();
        Pixel x2 = m_base->loopWidth + x();
-       
-       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
 
-       if (m_action->onRightEdge) 
+       if (ex < x1)
+               ex = x1;
+       else if (ex > x2)
+               ex = x2;
+
+       if (m_action->onRightEdge)
                m_action->setRightEdge(ex - m_action->x());
        else
                m_action->setLeftEdge(ex);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::onRefreshAction()
 {
        namespace ca = c::actionEditor;
@@ -293,17 +290,20 @@ void gePianoRoll::onRefreshAction()
        Frame f1 = 0;
        Frame f2 = 0;
 
-       if (!m_action->isOnEdges()) {
+       if (!m_action->isOnEdges())
+       {
                f1 = m_base->pixelToFrame(p1);
                f2 = m_base->pixelToFrame(p2, /*snap=*/false) - (m_base->pixelToFrame(p1, /*snap=*/false) - f1);
-       }       
-       else if (m_action->onLeftEdge) {
+       }
+       else if (m_action->onLeftEdge)
+       {
                f1 = m_base->pixelToFrame(p1);
                f2 = m_action->a2.frame;
                if (f1 == f2) // If snapping makes an action fall onto the other
                        f1 -= G_DEFAULT_ACTION_SIZE;
        }
-       else if (m_action->onRightEdge) {
+       else if (m_action->onRightEdge)
+       {
                f1 = m_action->a1.frame;
                f2 = m_base->pixelToFrame(p2);
                if (f1 == f2) // If snapping makes an action fall onto the other
@@ -317,45 +317,39 @@ void gePianoRoll::onRefreshAction()
 
        ca::updateMidiAction(m_data->channelId, m_action->a1, note, velocity, f1, f2);
 
-       m_base->rebuild();  // Rebuild velocityEditor as well
+       m_base->rebuild(); // Rebuild velocityEditor as well
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int gePianoRoll::yToNote(Pixel p) const
 {
        return gePianoRoll::MAX_KEYS - (p / gePianoRoll::CELL_H);
 }
 
-
 Pixel gePianoRoll::noteToY(int n) const
 {
        return (MAX_KEYS * CELL_H) - (n * gePianoRoll::CELL_H);
 }
 
-
 Pixel gePianoRoll::snapToY(Pixel p) const
 {
        return u::math::quantize(p, CELL_H);
 }
 
-
 Pixel gePianoRoll::getPianoItemW(Pixel px, const m::Action& a1, const m::Action& a2) const
 {
-       if (a2.isValid()) {             // Regular
-               if (a1.frame > a2.frame)    // Ring-loop
+       if (a2.isValid())
+       {                            // Regular
+               if (a1.frame > a2.frame) // Ring-loop
                        return m_base->loopWidth - (px - x());
                return m_base->frameToPixel(a2.frame - a1.frame);
        }
-       return geBaseAction::MIN_WIDTH; // Orphaned
+       return geBaseAction::MIN_WIDTH; // Orphaned
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePianoRoll::rebuild(c::actionEditor::Data& d)
 {
        m_data = &d;
@@ -371,7 +365,7 @@ void gePianoRoll::rebuild(c::actionEditor::Data& d)
                if (a1.event.getStatus() == m::MidiEvent::NOTE_OFF)
                        continue;
 
-               assert(a1.isValid());  // a2 might be null if orphaned
+               assert(a1.isValid()); // a2 might be null if orphaned
 
                const m::Action& a2 = a1.next != nullptr ? *a1.next : m::Action{};
 
@@ -388,4 +382,5 @@ void gePianoRoll::rebuild(c::actionEditor::Data& d)
 
        redraw();
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 3f49c2c69f2274fb38b57f0928d6f771aa697ecb..470359bc5c05d1430228cc205eef8c2721c8c01b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_PIANO_ROLL_H
 #define GE_PIANO_ROLL_H
 
-
-#include <FL/fl_draw.H>
 #include "baseActionEditor.h"
+#include <FL/fl_draw.H>
 
-
-namespace giada {
-namespace m
+namespace giada::m
 {
 class MidiChannel;
-}      
-namespace v
+class Action;
+} // namespace giada::m
+namespace giada::v
 {
 class gePianoRoll : public geBaseActionEditor
 {
 public:
-
-       static const int MAX_KEYS    = 127;
-       static const int MAX_OCTAVES = 9;
-       static const int KEYS        = 12;
-       static const Pixel CELL_H    = 20;
-       static const Pixel CELL_W    = 40;
+       static const int   MAX_KEYS    = 127;
+       static const int   MAX_OCTAVES = 9;
+       static const int   KEYS        = 12;
+       static const Pixel CELL_H      = 20;
+       static const Pixel CELL_W      = 40;
 
        gePianoRoll(Pixel x, Pixel y, Pixel w, gdBaseActionEditor*);
 
@@ -59,21 +55,30 @@ public:
 
        Pixel pick;
 
-private:
-
+  private:
        enum class Notes
        {
-               G = 1, FS = 2, F = 3, E = 4, DS = 5, D = 6, CS = 7, C = 8, B = 9, AS = 10,
-               A = 11, GS = 0
+               G  = 1,
+               FS = 2,
+               F  = 3,
+               E  = 4,
+               DS = 5,
+               D  = 6,
+               CS = 7,
+               C  = 8,
+               B  = 9,
+               AS = 10,
+               A  = 11,
+               GS = 0
        };
 
-       Fl_Offscreen surface1;  // notes, no repeat
-       Fl_Offscreen surface2;  // lines, x-repeat
+       Fl_Offscreen surface1; // notes, no repeat
+       Fl_Offscreen surface2; // lines, x-repeat
 
-       void onAddAction()     override;
-       void onDeleteAction()  override;
-       void onMoveAction()    override;
-       void onResizeAction()  override;
+       void onAddAction() override;
+       void onDeleteAction() override;
+       void onMoveAction() override;
+       void onResizeAction() override;
        void onRefreshAction() override;
 
        /* drawSurface*
@@ -92,7 +97,6 @@ private:
        Pixel noteToY(int n) const;
        Pixel getPianoItemW(Pixel x, const m::Action& a1, const m::Action& a2) const;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index ba42a88fab77e8ed9f48acfeed1fdd0aef4a9735..38f71d0c4b2f46e56c23d2014d458d7d01dc7fed 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
-#include "core/const.h"
-#include "core/action.h"
 #include "sampleAction.h"
+#include "core/action.h"
+#include "core/const.h"
+#include <FL/fl_draw.H>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
-geSampleAction::geSampleAction(Pixel X, Pixel Y, Pixel W, Pixel H, 
-       bool singlePress, m::Action a1, m::Action a2)
-: geBaseAction (X, Y, W, H, singlePress, a1, a2),
-  m_singlePress(singlePress)
+geSampleAction::geSampleAction(Pixel X, Pixel Y, Pixel W, Pixel H,
+    bool singlePress, m::Action a1, m::Action a2)
+: geBaseAction(X, Y, W, H, singlePress, a1, a2)
+, m_singlePress(singlePress)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleAction::draw()
 {
-       Fl_Color color = hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1; 
+       Fl_Color color = hovered ? G_COLOR_LIGHT_2 : G_COLOR_LIGHT_1;
 
-       if (m_singlePress) {
+       if (m_singlePress)
+       {
                fl_rectf(x(), y(), w(), h(), color);
        }
-       else {
+       else
+       {
                if (a1.event.getStatus() == m::MidiEvent::NOTE_KILL)
                        fl_rect(x(), y(), MIN_WIDTH, h(), color);
-               else {
+               else
+               {
                        fl_rectf(x(), y(), MIN_WIDTH, h(), color);
                        if (a1.event.getStatus() == m::MidiEvent::NOTE_ON)
-                               fl_rectf(x()+3, y()+h()-11, w()-6, 8, G_COLOR_GREY_4);
-                       else
-                       if (a1.event.getStatus() == m::MidiEvent::NOTE_OFF)
-                               fl_rectf(x()+3, y()+3, w()-6, 8, G_COLOR_GREY_4);
+                               fl_rectf(x() + 3, y() + h() - 11, w() - 6, 8, G_COLOR_GREY_4);
+                       else if (a1.event.getStatus() == m::MidiEvent::NOTE_OFF)
+                               fl_rectf(x() + 3, y() + 3, w() - 6, 8, G_COLOR_GREY_4);
                }
        }
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 0b47eb2f668924d80d5a6ea80618c1be22df7a74..0ec2eaf67e37bc30846a89cdead133c0f5cacc37 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SAMPLE_ACTION_H
 #define GE_SAMPLE_ACTION_H
 
-
-#include "core/recorder.h"
 #include "baseAction.h"
+#include "core/recorder.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 class SampleChannel;
@@ -43,17 +41,15 @@ namespace v
 class geSampleAction : public geBaseAction
 {
 public:
-
-       geSampleAction(Pixel x, Pixel y, Pixel w, Pixel h, bool singlePress, 
-               m::Action a1, m::Action a2);
+       geSampleAction(Pixel x, Pixel y, Pixel w, Pixel h, bool singlePress,
+           m::Action a1, m::Action a2);
 
        void draw() override;
 
-private:
-
+  private:
        bool m_singlePress;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 24bc9dfacac8bacad1dcc6efe284036efacf91a4..c290abf56bf474de61c86011bf8c131a19ee04d1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include "core/recorder.h"
-#include "core/const.h"
-#include "core/conf.h"
+#include "sampleActionEditor.h"
 #include "core/action.h"
-#include "utils/log.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include "core/recorder.h"
 #include "glue/actionEditor.h"
 #include "glue/channel.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
 #include "sampleAction.h"
-#include "sampleActionEditor.h"
-
+#include "utils/log.h"
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geSampleActionEditor::geSampleActionEditor(Pixel x, Pixel y, gdBaseActionEditor* b)
@@ -48,19 +47,15 @@ geSampleActionEditor::geSampleActionEditor(Pixel x, Pixel y, gdBaseActionEditor*
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geSampleActionEditor::~geSampleActionEditor()
 {
        m::conf::conf.sampleActionEditorH = h();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleActionEditor::rebuild(c::actionEditor::Data& d)
 {
        m_data = &d;
@@ -73,13 +68,14 @@ void geSampleActionEditor::rebuild(c::actionEditor::Data& d)
 
        clear();
        size(m_base->fullWidth, h());
-       
-       for (const m::Action& a1 : m_data->actions) {
+
+       for (const m::Action& a1 : m_data->actions)
+       {
 
                if (a1.event.getStatus() == m::MidiEvent::ENVELOPE || isNoteOffSinglePress(a1))
                        continue;
 
-        const m::Action& a2 = a1.next != nullptr ? *a1.next : m::Action{};
+               const m::Action& a2 = a1.next != nullptr ? *a1.next : m::Action{};
 
                Pixel px = x() + m_base->frameToPixel(a1.frame);
                Pixel py = y() + 4;
@@ -95,16 +91,14 @@ void geSampleActionEditor::rebuild(c::actionEditor::Data& d)
 
        /* If channel is LOOP_ANY, deactivate it: a loop mode channel cannot hold 
        keypress/keyrelease actions. */
-       
+
        isAnyLoopMode ? deactivate() : activate();
 
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleActionEditor::draw()
 {
        /* Draw basic boundaries (+ beat bars) and hide the unused area. Then draw 
@@ -117,72 +111,68 @@ void geSampleActionEditor::draw()
        fl_color(G_COLOR_GREY_4);
        fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
        if (active())
-               fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+               fl_draw("start/stop", x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
        else
-               fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER));
+               fl_draw("start/stop (disabled)", x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CENTER));
 
        draw_children();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleActionEditor::onAddAction()     
+void geSampleActionEditor::onAddAction()
 {
        Frame f = m_base->pixelToFrame(Fl::event_x() - x());
        c::actionEditor::recordSampleAction(m_data->channelId, m_base->getActionType(), f);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleActionEditor::onDeleteAction()  
+void geSampleActionEditor::onDeleteAction()
 {
        c::actionEditor::deleteSampleAction(m_data->channelId, m_action->a1);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleActionEditor::onMoveAction()    
+void geSampleActionEditor::onMoveAction()
 {
        Pixel ex = Fl::event_x() - m_action->pick;
 
        Pixel x1 = x();
        Pixel x2 = m_base->loopWidth + x() - m_action->w();
 
-       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
+       if (ex < x1)
+               ex = x1;
+       else if (ex > x2)
+               ex = x2;
 
        m_action->setPosition(ex);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleActionEditor::onResizeAction()  
+void geSampleActionEditor::onResizeAction()
 {
        Pixel ex = Fl::event_x();
 
        Pixel x1 = x();
        Pixel x2 = m_base->loopWidth + x();
 
-       if (ex < x1) ex = x1; else if (ex > x2) ex = x2;
+       if (ex < x1)
+               ex = x1;
+       else if (ex > x2)
+               ex = x2;
 
-       if (m_action->onRightEdge) 
+       if (m_action->onRightEdge)
                m_action->setRightEdge(ex - m_action->x());
        else
                m_action->setLeftEdge(ex);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleActionEditor::onRefreshAction() 
+void geSampleActionEditor::onRefreshAction()
 {
        namespace ca = c::actionEditor;
 
@@ -192,32 +182,33 @@ void geSampleActionEditor::onRefreshAction()
        Frame f2   = 0;
        int   type = m_action->a1.event.getStatus();
 
-       if (!m_action->isOnEdges()) {
+       if (!m_action->isOnEdges())
+       {
                f1 = m_base->pixelToFrame(p1);
                f2 = m_base->pixelToFrame(p2, /*snap=*/false) - (m_base->pixelToFrame(p1, /*snap=*/false) - f1);
-       }       
-       else if (m_action->onLeftEdge) {
+       }
+       else if (m_action->onLeftEdge)
+       {
                f1 = m_base->pixelToFrame(p1);
                f2 = m_action->a2.frame;
        }
-       else if (m_action->onRightEdge) {
+       else if (m_action->onRightEdge)
+       {
                f1 = m_action->a1.frame;
                f2 = m_base->pixelToFrame(p2);
        }
 
        ca::updateSampleAction(m_data->channelId, m_action->a1, type, f1, f2);
-                       
+
        m_base->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geSampleActionEditor::isNoteOffSinglePress(const m::Action& a)
 {
-       return m_data->sample->channelMode == SamplePlayerMode::SINGLE_PRESS && 
+       return m_data->sample->channelMode == SamplePlayerMode::SINGLE_PRESS &&
               a.event.getStatus() == m::MidiEvent::NOTE_OFF;
-
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 1d23d3d1edfbaeea677fc1c9b014c38d1023b2bb..c1bab27462be5a5309fcade5fda1c8fe1e069cad 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SAMPLE_ACTION_EDITOR_H
 #define GE_SAMPLE_ACTION_EDITOR_H
 
-
 #include "baseActionEditor.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 class SampleChannel;
 struct Action;
-}
+} // namespace m
 namespace v
 {
 class geSampleAction;
@@ -45,7 +43,6 @@ class geSampleAction;
 class geSampleActionEditor : public geBaseActionEditor
 {
 public:
-
        geSampleActionEditor(Pixel x, Pixel y, gdBaseActionEditor*);
        ~geSampleActionEditor();
 
@@ -53,16 +50,16 @@ public:
 
        void rebuild(c::actionEditor::Data& d) override;
 
-private:
-
-       void onAddAction()     override;
-       void onDeleteAction()  override;
-       void onMoveAction()    override;
-       void onResizeAction()  override;
+  private:
+       void onAddAction() override;
+       void onDeleteAction() override;
+       void onMoveAction() override;
+       void onResizeAction() override;
        void onRefreshAction() override;
 
-    bool isNoteOffSinglePress(const m::Action& a);
+       bool isNoteOffSinglePress(const m::Action& a);
 };
-}} // giada::v::
+} // namespace v
+} // namespace giada
 
 #endif
index 57918422778f7b0e5d4602f9067155c6404aa358..fe01bd454f2e1729fb42ad187eff3894a305eeaf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include "utils/log.h"
-#include "utils/math.h"
-#include "core/const.h"
-#include "core/conf.h"
+#include "velocityEditor.h"
 #include "core/action.h"
 #include "core/clock.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include "envelopePoint.h"
 #include "glue/actionEditor.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
-#include "envelopePoint.h"
-#include "velocityEditor.h"
-
+#include "utils/log.h"
+#include "utils/math.h"
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geVelocityEditor::geVelocityEditor(Pixel x, Pixel y, gdBaseActionEditor* b)
-:      geBaseActionEditor(x, y, 200, m::conf::conf.velocityEditorH, b)
+: geBaseActionEditor(x, y, 200, m::conf::conf.velocityEditorH, b)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geVelocityEditor::~geVelocityEditor()
 {
        m::conf::conf.velocityEditorH = h();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geVelocityEditor::draw() 
+void geVelocityEditor::draw()
 {
        baseDraw();
 
@@ -69,14 +64,15 @@ void geVelocityEditor::draw()
 
        fl_color(G_COLOR_GREY_4);
        fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
-       fl_draw("Velocity", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT));
+       fl_draw("Velocity", x() + 4, y(), w(), h(), (Fl_Align)(FL_ALIGN_LEFT));
 
        if (children() == 0)
                return;
 
        Pixel side = geEnvelopePoint::SIDE / 2;
 
-       for (int i=0; i<children(); i++) {
+       for (int i = 0; i < children(); i++)
+       {
                geEnvelopePoint* p = static_cast<geEnvelopePoint*>(child(i));
                if (m_action == nullptr)
                        p->position(p->x(), valueToY(p->a1.event.getVelocity()));
@@ -89,26 +85,21 @@ void geVelocityEditor::draw()
        draw_children();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Pixel geVelocityEditor::valueToY(int v) const
 {
        /* Cast the input type of 'v' to float, to make the mapping more precise. */
        return u::math::map<float, Pixel>(v, 0, G_MAX_VELOCITY, y() + (h() - geEnvelopePoint::SIDE), y());
 }
 
-
 int geVelocityEditor::yToValue(Pixel px) const
 {
-       return u::math::map<Pixel, int>(px, h() - geEnvelopePoint::SIDE, 0, 0, G_MAX_VELOCITY); 
+       return u::math::map<Pixel, int>(px, h() - geEnvelopePoint::SIDE, 0, 0, G_MAX_VELOCITY);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geVelocityEditor::rebuild(c::actionEditor::Data& d)
 {
        m_data = &d;
@@ -119,8 +110,9 @@ void geVelocityEditor::rebuild(c::actionEditor::Data& d)
        clear();
        size(m_base->fullWidth, h());
 
-       for (const m::Action& action : m_data->actions) {
-               
+       for (const m::Action& action : m_data->actions)
+       {
+
                if (action.event.getStatus() == m::MidiEvent::NOTE_OFF)
                        continue;
 
@@ -129,36 +121,36 @@ void geVelocityEditor::rebuild(c::actionEditor::Data& d)
 
                add(new geEnvelopePoint(px, py, action));
        }
-       
+
        resizable(nullptr);
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geVelocityEditor::onMoveAction()    
+void geVelocityEditor::onMoveAction()
 {
        Pixel ey = Fl::event_y() - (geEnvelopePoint::SIDE / 2);
 
        Pixel y1 = y();
        Pixel y2 = y() + h() - geEnvelopePoint::SIDE;
 
-       if (ey < y1) ey = y1; else if (ey > y2) ey = y2;
+       if (ey < y1)
+               ey = y1;
+       else if (ey > y2)
+               ey = y2;
 
        m_action->position(m_action->x(), ey);
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geVelocityEditor::onRefreshAction() 
+void geVelocityEditor::onRefreshAction()
 {
        c::actionEditor::updateVelocity(m_action->a1, yToValue(m_action->y() - y()));
 
-       m_base->rebuild();  // Rebuild pianoRoll as well
+       m_base->rebuild(); // Rebuild pianoRoll as well
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index be19b8ad924994afa2a448e26a6a41c0565cdeb6..7f83a87e0ee36dca9d84987bef6c20485a0c2d33 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_VELOCITY_EDITOR_H
 #define GE_VELOCITY_EDITOR_H
 
-
 #include "baseActionEditor.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace m
 {
 class MidiChannel;
@@ -41,11 +39,9 @@ namespace v
 {
 class geEnvelopePoint;
 
-
 class geVelocityEditor : public geBaseActionEditor
 {
 public:
-
        geVelocityEditor(Pixel x, Pixel y, gdBaseActionEditor*);
        ~geVelocityEditor();
 
@@ -53,18 +49,17 @@ public:
 
        void rebuild(c::actionEditor::Data& d) override;
 
-private:
-
-       void onMoveAction()    override;
+  private:
+       void onMoveAction() override;
        void onRefreshAction() override;
-       void onAddAction()     override {};
-       void onDeleteAction()  override {};
-       void onResizeAction()  override {};
+       void onAddAction() override{};
+       void onDeleteAction() override{};
+       void onResizeAction() override{};
 
-       Pixel valueToY(int v)   const;
+       Pixel valueToY(int v) const;
        int   yToValue(Pixel y) const;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 14e23150cc931bd9599aabaae5e89c1d6d4e6b63..c14cf957319275eaf03486829a7d1ea5503b488d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
+#include "box.h"
 #include "core/const.h"
 #include "utils/gui.h"
-#include "box.h"
-
+#include <FL/fl_draw.H>
 
 geBox::geBox(int x, int y, int w, int h, const char* l, Fl_Align al)
-: Fl_Box (x, y, w, h)
+: Fl_Box(x, y, w, h)
 {
        copy_label(l);
        box(FL_NO_BOX);
        align(al | FL_ALIGN_INSIDE);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBox::draw()
 {
        fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_1); // Clear background
@@ -51,11 +47,11 @@ void geBox::draw()
                fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // Border
 
        if (image() != nullptr)
-               draw_label(); // draw_label also paints image, if any
-       else
-       if (label() != nullptr) {
+               draw_label(); // draw_label also paints image, if any
+       else if (label() != nullptr)
+       {
                fl_color(G_COLOR_LIGHT_2);
                fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
-               fl_draw(giada::u::gui::truncate(label(), w()-8).c_str(), x()+4, y(), w()-4, h(), align());
+               fl_draw(giada::u::gui::truncate(label(), w() - 8).c_str(), x() + 4, y(), w() - 4, h(), align());
        }
 }
\ No newline at end of file
index bfd52763ef76dd21c4bdb57009031c4147f9f12f..2cc1ca92bd5ed823169baf69e914d8ddbbbed404 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BOX_H
 #define GE_BOX_H
 
-
 #include <FL/Fl_Box.H>
 
-
 class geBox : public Fl_Box
 {
 public:
-
-       geBox(int x, int y, int w, int h, const char* l=nullptr, Fl_Align al=FL_ALIGN_CENTER);
+       geBox(int x, int y, int w, int h, const char* l = nullptr, Fl_Align al = FL_ALIGN_CENTER);
 
        void draw() override;
 };
 
-
 #endif
index 57787ccfa4c101cafe1b5e20c932bd82a44ed68a..47e003af86c153b5b3c12ad0cfbd06495f9831e0 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
-#include "../../../core/const.h"
 #include "boxtypes.h"
-
+#include "../../../core/const.h"
+#include <FL/fl_draw.H>
 
 void g_customBorderBox(int x, int y, int w, int h, Fl_Color c)
 {
-  fl_color(c);
-  fl_rectf(x, y, w, h);
-  fl_color(G_COLOR_GREY_4);
-  fl_rect(x, y, w, h);
+       fl_color(c);
+       fl_rectf(x, y, w, h);
+       fl_color(G_COLOR_GREY_4);
+       fl_rect(x, y, w, h);
 }
 
-
 void g_customUpBox(int x, int y, int w, int h, Fl_Color /*c*/)
 {
-  fl_color(G_COLOR_GREY_2);
-  fl_rectf(x, y, w, h);
-  fl_color(G_COLOR_GREY_2);
-  fl_rect(x, y, w, h);
+       fl_color(G_COLOR_GREY_2);
+       fl_rectf(x, y, w, h);
+       fl_color(G_COLOR_GREY_2);
+       fl_rect(x, y, w, h);
 }
 
-
 void g_customDownBox(int x, int y, int w, int h, Fl_Color c)
 {
-  fl_color(c);
-  fl_rectf(x, y, w, h);
-  fl_color(G_COLOR_GREY_2);
-  fl_rect(x, y, w, h);
+       fl_color(c);
+       fl_rectf(x, y, w, h);
+       fl_color(G_COLOR_GREY_2);
+       fl_rect(x, y, w, h);
 }
index 9df68827e4412749dc36e71eb85f00f935095db8..f763f66c4641ddc1975f61d974050128a5c8f5cd 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BOXTYPES_H
 #define GE_BOXTYPES_H
 
-
 #include <FL/Fl.H>
 
-
 constexpr Fl_Boxtype G_CUSTOM_BORDER_BOX = FL_FREE_BOXTYPE;
 constexpr Fl_Boxtype G_CUSTOM_UP_BOX     = static_cast<Fl_Boxtype>(FL_FREE_BOXTYPE + 1);
 constexpr Fl_Boxtype G_CUSTOM_DOWN_BOX   = static_cast<Fl_Boxtype>(FL_FREE_BOXTYPE + 3);
 
-
 void g_customBorderBox(int x, int y, int w, int h, Fl_Color c);
-void g_customUpBox    (int x, int y, int w, int h, Fl_Color c);
-void g_customDownBox  (int x, int y, int w, int h, Fl_Color c);
-
+void g_customUpBox(int x, int y, int w, int h, Fl_Color c);
+void g_customDownBox(int x, int y, int w, int h, Fl_Color c);
 
 #endif
index 66b8539c5df776a952722d8c20a61ecd89a04952..a37591531ac329e0bf8128eb0776ddf4330c4595 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
+#include "button.h"
 #include "core/const.h"
 #include "utils/gui.h"
-#include "button.h"
-
+#include <FL/fl_draw.H>
 
-geButton::geButton(int x, int y, int w, int h, const char* l, 
-       const char** imgOff, const char** imgOn, const char** imgDisabled)
-: Fl_Button  (x, y, w, h, l),
-  imgOff     (imgOff),
-  imgOn      (imgOn),
-  imgDisabled(imgDisabled),
-  bgColor0   (G_COLOR_GREY_2),
-  bgColor1   (G_COLOR_GREY_4),
-  bdColor    (G_COLOR_GREY_4),
-  txtColor   (G_COLOR_LIGHT_2)
+geButton::geButton(int x, int y, int w, int h, const char* l,
+    const char** imgOff, const char** imgOn, const char** imgDisabled)
+: Fl_Button(x, y, w, h, l)
+, imgOff(imgOff)
+, imgOn(imgOn)
+, imgDisabled(imgDisabled)
+, bgColor0(G_COLOR_GREY_2)
+, bgColor1(G_COLOR_GREY_4)
+, bdColor(G_COLOR_GREY_4)
+, txtColor(G_COLOR_LIGHT_2)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geButton::draw()
 {
        //Fl_Button::draw();
 
        if (active())
-               if (value()) draw(imgOn,  bgColor1, txtColor);
-               else         draw(imgOff, bgColor0, txtColor);
+               if (value())
+                       draw(imgOn, bgColor1, txtColor);
+               else
+                       draw(imgOff, bgColor0, txtColor);
        else
                draw(imgDisabled, bgColor0, bdColor);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geButton::draw(const char** img, Fl_Color bgColor, Fl_Color textColor)
 {
-       fl_rect(x(), y(), w(), h(), bdColor);               // draw border
+       fl_rect(x(), y(), w(), h(), bdColor); // draw border
 
-       if (img != nullptr) {
-               fl_draw_pixmap(img, x()+1, y()+1);
+       if (img != nullptr)
+       {
+               fl_draw_pixmap(img, x() + 1, y() + 1);
                return;
        }
 
-       fl_rectf(x()+1, y()+1, w()-2, h()-2, bgColor); // draw background
+       fl_rectf(x() + 1, y() + 1, w() - 2, h() - 2, bgColor); // draw background
        fl_color(textColor);
 
-       if (label() != nullptr) {
+       if (label() != nullptr)
+       {
                fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
-               fl_draw(giada::u::gui::truncate(label(), w()-16).c_str(), x()+2, y(), w()-2, h(), FL_ALIGN_CENTER);
+               fl_draw(giada::u::gui::truncate(label(), w() - 16).c_str(), x() + 2, y(), w() - 2, h(), FL_ALIGN_CENTER);
        }
 }
\ No newline at end of file
index 81cc9d7355686604afb3bec44efdb1c4017b8ba5..ab5dfe6bb06a493c0acfed69129e53d7cfc69418 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BUTTON_H
 #define GE_BUTTON_H
 
-
 #include <FL/Fl_Button.H>
 
-
 class geButton : public Fl_Button
 {
 public:
-
-       geButton(int x, int y, int w, int h, const char* l=nullptr,
-               const char** imgOff=nullptr, const char** imgOn=nullptr, 
-               const char** imgDisabled=nullptr);
+       geButton(int x, int y, int w, int h, const char* l = nullptr,
+           const char** imgOff = nullptr, const char** imgOn = nullptr,
+           const char** imgDisabled = nullptr);
 
        void draw() override;
 
-protected:
-
+  protected:
        void draw(const char** img, Fl_Color bgColor, Fl_Color textColor);
 
        const char** imgOff;
        const char** imgOn;
        const char** imgDisabled;
 
-       Fl_Color bgColor0;   // background not clicked
-       Fl_Color bgColor1;   // background clicked
-       Fl_Color bdColor;    // border
-       Fl_Color txtColor;       // text
+       Fl_Color bgColor0; // background not clicked
+       Fl_Color bgColor1; // background clicked
+       Fl_Color bdColor;  // border
+       Fl_Color txtColor; // text
 };
 
-
 #endif
index 96c2cf578a6c24867281edff57c1edcf180204c8..4e7c6bc6fcfc121ee501633282e5848aaae4e93e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cstring>
-#include <FL/fl_draw.H>
-#include "core/const.h"
 #include "check.h"
-
+#include "core/const.h"
+#include <FL/fl_draw.H>
+#include <cstring>
 
 geCheck::geCheck(int x, int y, int w, int h, const char* l)
 : Fl_Check_Button(x, y, w, h, l)
 {
+       callback(cb_onChange, this);
 }
 
+/* -------------------------------------------------------------------------- */
+
+void geCheck::cb_onChange(Fl_Widget* /*w*/, void* p) { (static_cast<geCheck*>(p))->cb_onChange(); }
 
 /* -------------------------------------------------------------------------- */
 
+void geCheck::cb_onChange()
+{
+       if (onChange != nullptr)
+               onChange(value());
+}
+
+/* -------------------------------------------------------------------------- */
 
 void geCheck::draw()
 {
-       fl_rectf(x(), y(), w(), h(), FL_BACKGROUND_COLOR);  // clearer
+       fl_rectf(x(), y(), w(), h(), FL_BACKGROUND_COLOR); // clearer
 
-       const int boxColor  = !active() ? FL_INACTIVE_COLOR : G_COLOR_GREY_4;
-       const int textColor = !active() ? FL_INACTIVE_COLOR : G_COLOR_LIGHT_2;
-       const int textAlign = hasMultilineText() ? FL_ALIGN_LEFT | FL_ALIGN_TOP : FL_ALIGN_LEFT | FL_ALIGN_CENTER;
+       const Fl_Color boxColor  = !active() ? FL_INACTIVE_COLOR : G_COLOR_GREY_4;
+       const int      textColor = !active() ? FL_INACTIVE_COLOR : G_COLOR_LIGHT_2;
+       const Fl_Align textAlign = hasMultilineText() ? FL_ALIGN_LEFT | FL_ALIGN_TOP : FL_ALIGN_LEFT | FL_ALIGN_CENTER;
 
        if (value())
-               fl_rectf(x(), y(), 12, h(), (Fl_Color) boxColor);
+               fl_rectf(x(), y(), 12, h(), boxColor);
        else
-               fl_rect(x(), y(), 12, h(), (Fl_Color) boxColor);
+               fl_rect(x(), y(), 12, h(), boxColor);
 
        fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
        fl_color(textColor);
-       fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) textAlign);
+       fl_draw(label(), x() + 20, y(), w(), h(), textAlign);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geCheck::hasMultilineText() const
 {
        return label() == nullptr ? false : std::strchr(label(), '\n') != nullptr;
 }
-
index dbe53408aca244be6c75dfe5a8473e3039e07ea1..0a4a54c4c353ff12ffd49aa2383d95ffce05ac2c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_CHECK_H
 #define GE_CHECK_H
 
-
 #include <FL/Fl_Check_Button.H>
-
+#include <functional>
 
 class geCheck : public Fl_Check_Button
 {
 public:
-
-       geCheck(int x, int y, int w, int h, const char *l=0);
+       geCheck(int x, int y, int w, int h, const char* l = 0);
 
        void draw() override;
 
+       std::function<void(bool)> onChange = nullptr;
+
 private:
+       static void cb_onChange(Fl_Widget* w, void* p);
+       void        cb_onChange();
 
        bool hasMultilineText() const;
 };
 
-
 #endif
index 91b62cb2ea58c7762cfc1bd196afb2245cefc992..a9c418238f03e3ab3488575bf3a60be4dbeede4e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <string>
-#include <FL/fl_draw.H>
+#include "choice.h"
 #include "core/const.h"
 #include "utils/gui.h"
 #include "utils/vector.h"
-#include "choice.h"
-
+#include <FL/fl_draw.H>
+#include <cassert>
+#include <string>
 
-namespace giada {
-namespace v 
+namespace giada::v
 {
 geChoice::geChoice(int x, int y, int w, int h, const char* l, bool ang)
 : Fl_Choice(x, y, w, h, l)
-, angle    (ang)
+, m_angle(ang)
 {
        labelsize(G_GUI_FONT_SIZE_BASE);
        labelcolor(G_COLOR_LIGHT_2);
@@ -48,71 +46,70 @@ geChoice::geChoice(int x, int y, int w, int h, const char* l, bool ang)
        color(G_COLOR_GREY_2);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChoice::cb_onChange(Fl_Widget* /*w*/, void* p) { (static_cast<geChoice*>(p))->cb_onChange(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChoice::cb_onChange()
 {
-       if (onChange != nullptr) onChange(getSelectedId());
+       if (onChange != nullptr)
+               onChange(getSelectedId());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChoice::draw()
 {
-       fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2);              // bg
-       fl_rect(x(), y(), w(), h(), (Fl_Color) G_COLOR_GREY_4);    // border
-       if (angle)
-               fl_polygon(x()+w()-8, y()+h()-1, x()+w()-1, y()+h()-8, x()+w()-1, y()+h()-1);
+       fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2);                       // bg
+       fl_rect(x(), y(), w(), h(), static_cast<Fl_Color>(G_COLOR_GREY_4)); // border
+       if (m_angle)
+               fl_polygon(x() + w() - 8, y() + h() - 1, x() + w() - 1, y() + h() - 8, x() + w() - 1, y() + h() - 1);
 
        /* pick up the text() from the selected item (value()) and print it in
         * the box and avoid overflows */
 
        fl_color(!active() ? G_COLOR_GREY_4 : G_COLOR_LIGHT_2);
-       if (value() != -1) 
-               fl_draw(u::gui::truncate(text(value()), w()-16).c_str(), x(), y(), w(), h(), FL_ALIGN_CENTER);
+       if (value() != -1)
+               fl_draw(u::gui::truncate(text(value()), w() - 16).c_str(), x(), y(), w(), h(), FL_ALIGN_CENTER);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 ID geChoice::getSelectedId() const
 {
-       return value() == -1 ? 0 : ids.at(value());     
+       return value() == -1 ? -1 : m_ids.at(value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChoice::addItem(const std::string& label, ID id)
 {
+       assert(id >= 0);
+
        Fl_Choice::add(label.c_str(), 0, cb_onChange, static_cast<void*>(this));
-       ids.push_back(id);
+       m_ids.push_back(id);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
+void geChoice::showItem(const std::string& label)
+{
+       value(find_index(label.c_str()));
+}
 
-void geChoice::showItem(const char* c)
+void geChoice::showItem(ID id)
 {
-       value(find_index(c));
+       value(u::vector::indexOf(m_ids, id));
 }
 
+/* -------------------------------------------------------------------------- */
 
-void geChoice::showItem(ID id)
+void geChoice::clear()
 {
-       value(u::vector::indexOf(ids, id));
+       Fl_Choice::clear();
+       m_ids.clear();
 }
-}}
\ No newline at end of file
+
+} // namespace giada::v
\ No newline at end of file
index 40a41c8b9ca6433b35ac3830cdce92765a777659..ea979747b31dd49a242fc8dfcf14c0d195d85285 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_CHOICE_H
 #define GE_CHOICE_H
 
-
+#include "core/types.h"
+#include <FL/Fl_Choice.H>
 #include <functional>
 #include <string>
 #include <vector>
-#include <FL/Fl_Choice.H>
-#include "core/types.h"
-
 
-namespace giada {
-namespace v 
+namespace giada::v
 {
 class geChoice : public Fl_Choice
 {
 public:
-
-       geChoice(int x, int y, int w, int h, const char* l=0, bool angle=true);
+       geChoice(int x, int y, int w, int h, const char* l = 0, bool angle = true);
        void draw() override;
 
        ID getSelectedId() const;
 
        void addItem(const std::string& label, ID id);
-       void showItem(const char* c);
+       void showItem(const std::string& label);
        void showItem(ID id);
+       void clear();
 
        std::function<void(ID)> onChange = nullptr;
 
 private:
+       static void cb_onChange(Fl_Widget* w, void* p);
+       void        cb_onChange();
 
-       static void cb_onChange(Fl_Widget* /*w*/, void* p);
-       void cb_onChange();
-
-       bool angle;
-       std::vector<ID> ids;
+       bool            m_angle;
+       std::vector<ID> m_ids;
 };
-}}
+} // namespace giada::v
 
 #endif
index c68cc336882b786d7dff8b61d44882eb38c31bdb..476a4580ec4411471753e9db91b4053f7a60c718 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
-#include "../../../core/const.h"
 #include "dial.h"
+#include "../../../core/const.h"
+#include <FL/fl_draw.H>
 
-
-geDial::geDial(int x, int y, int w, int h, const char *l)
+geDial::geDial(int x, int y, int w, int h, const char* l)
 : Fl_Dial(x, y, w, h, l)
 {
-  labelsize(G_GUI_FONT_SIZE_BASE);
-  labelcolor(G_COLOR_LIGHT_2);
-  align(FL_ALIGN_LEFT);
-  type(FL_FILL_DIAL);
-  angles(0, 360);
-  color(G_COLOR_GREY_2);            // background
-  selection_color(G_COLOR_GREY_4);   // selection
+       labelsize(G_GUI_FONT_SIZE_BASE);
+       labelcolor(G_COLOR_LIGHT_2);
+       align(FL_ALIGN_LEFT);
+       type(FL_FILL_DIAL);
+       angles(0, 360);
+       color(G_COLOR_GREY_2);           // background
+       selection_color(G_COLOR_GREY_4); // selection
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geDial::draw()
 {
-  double angle = (angle2()-angle1())*(value()-minimum())/(maximum()-minimum()) + angle1();
+       double angle = (angle2() - angle1()) * (value() - minimum()) / (maximum() - minimum()) + angle1();
 
-  fl_color(G_COLOR_GREY_2);
-  fl_pie(x(), y(), w(), h(), 270-angle1(), angle > angle1() ? 360+270-angle : 270-360-angle);
+       fl_color(G_COLOR_GREY_2);
+       fl_pie(x(), y(), w(), h(), 270 - angle1(), angle > angle1() ? 360 + 270 - angle : 270 - 360 - angle);
 
-  fl_color(G_COLOR_GREY_4);
-  fl_arc(x(), y(), w(), h(), 0, 360);
-  fl_pie(x(), y(), w(), h(), 270-angle, 270-angle1());
+       fl_color(G_COLOR_GREY_4);
+       fl_arc(x(), y(), w(), h(), 0, 360);
+       fl_pie(x(), y(), w(), h(), 270 - angle, 270 - angle1());
 }
index 6b207141d4569d500b8555e6afb9614dbb366326..d3a31270354db7c92ec3732ca97533d981b473bf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_DIAL_H
 #define GE_DIAL_H
 
-
 #include <FL/Fl_Dial.H>
 
-
 class geDial : public Fl_Dial
 {
 public:
-
-       geDial(int x, int y, int w, int h, const char *l=0);
+       geDial(int x, int y, int w, int h, const char* l = 0);
 
        void draw();
 };
 
-
 #endif
index d888c1fc020e5dfddfdde4d90ad1d7352e6e0250..8145715b92811b39dc85790d1f3fb708eee9fa95 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <algorithm>
 #include "group.h"
+#include <algorithm>
 
-
-namespace giada {
-namespace v 
+namespace giada
 {
-geGroup::geGroup(int x, int y) : Fl_Group(x, y, 0, 0)
+namespace v
 {
-    end();
+geGroup::geGroup(int x, int y)
+: Fl_Group(x, y, 0, 0)
+{
+       end();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::size_t geGroup::countChildren() const
 {
-    return m_widgets.size();
+       return m_widgets.size();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geGroup::add(Fl_Widget* widget)
 {
-    widget->position(widget->x() + x(), widget->y() + y());
-    
-    Fl_Group::add(widget);
-    m_widgets.push_back(widget);
+       widget->position(widget->x() + x(), widget->y() + y());
 
-    int newW = 0;
-    int newH = 0;
+       Fl_Group::add(widget);
+       m_widgets.push_back(widget);
 
-    for (const Fl_Widget* wg : m_widgets) {
-        newW = std::max(newW, (wg->x() + wg->w()) - x());
-        newH = std::max(newH, (wg->y() + wg->h()) - y());
-    }
+       int newW = 0;
+       int newH = 0;
 
-    /* Don't call size(newW, newH) as it changes widgets position. Adjust width
+       for (const Fl_Widget* wg : m_widgets)
+       {
+               newW = std::max(newW, (wg->x() + wg->w()) - x());
+               newH = std::max(newH, (wg->y() + wg->h()) - y());
+       }
+
+       /* Don't call size(newW, newH) as it changes widgets position. Adjust width
     and height manually instead. */
 
-    w(newW); h(newH);
+       w(newW);
+       h(newH);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Fl_Widget* geGroup::getChild(std::size_t i)
 {
-    return m_widgets.at(i); // Throws std::out_of_range in case
+       return m_widgets.at(i); // Throws std::out_of_range in case
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Fl_Widget* geGroup::getLastChild()
 {
-    return m_widgets.at(m_widgets.size() - 1); // Throws std::out_of_range in case
+       return m_widgets.at(m_widgets.size() - 1); // Throws std::out_of_range in case
 }
-}}
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 3bc0ae6eac5f0559c45dcb1c5a416e24420719e4..0e594454ae8dc5cccc6794da971a934da7e99090 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_GROUP_H
 #define GE_GROUP_H
 
-
-#include <vector>
 #include <FL/Fl_Group.H>
+#include <vector>
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 /* geGroup
 A group that resizes itself accoring to the content. */
@@ -45,32 +43,30 @@ A group that resizes itself accoring to the content. */
 class geGroup : public Fl_Group
 {
 public:
-
        geGroup(int x, int y);
 
-    /* countChildren
+       /* countChildren
     Returns the number of widgets contained in this group. */
-    
-    std::size_t countChildren() const;
 
-    /* add
+       std::size_t countChildren() const;
+
+       /* add
     Adds a Fl_Widget 'w' to this group. Coordinates are relative to the group,
     so origin starts at (0, 0). */
 
-    void add(Fl_Widget* w);
+       void add(Fl_Widget* w);
 
-    Fl_Widget* getChild(std::size_t i);
-    Fl_Widget* getLastChild();
+       Fl_Widget* getChild(std::size_t i);
+       Fl_Widget* getLastChild();
 
-private:
-
-    /* m_widgets 
+  private:
+       /* m_widgets 
     The internal Fl_Scroll::array_ is unreliable when inspected with the child()
     method. Let's keep track of widgets that belong to this group manually. */
 
-    std::vector<Fl_Widget*> m_widgets;    
+       std::vector<Fl_Widget*> m_widgets;
 };
-}}
-
+} // namespace v
+} // namespace giada
 
 #endif
index 3fc1909173acba701c55f3467e0071cce036de28..adfa4e2e88d4b0bf3c09943b37ba328695039e04 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "../../../core/const.h"
-#include "boxtypes.h"
 #include "input.h"
+#include "boxtypes.h"
+#include "core/const.h"
 
-
-geInput::geInput(int x, int y, int w, int h, const char *l)
-  : Fl_Input(x, y, w, h, l)
+geInput::geInput(int x, int y, int w, int h, const char* l)
+: Fl_Input(x, y, w, h, l)
 {
-  //Fl::set_boxtype(G_CUSTOM_BORDER_BOX, gDrawBox, 1, 1, 2, 2);
-  box(G_CUSTOM_BORDER_BOX);
-  labelsize(G_GUI_FONT_SIZE_BASE);
-  labelcolor(G_COLOR_LIGHT_2);
-  color(G_COLOR_BLACK);
-  textcolor(G_COLOR_LIGHT_2);
-  cursor_color(G_COLOR_LIGHT_2);
-  selection_color(G_COLOR_GREY_4);
-  textsize(G_GUI_FONT_SIZE_BASE);
+       //Fl::set_boxtype(G_CUSTOM_BORDER_BOX, gDrawBox, 1, 1, 2, 2);
+       box(G_CUSTOM_BORDER_BOX);
+       labelsize(G_GUI_FONT_SIZE_BASE);
+       labelcolor(G_COLOR_LIGHT_2);
+       color(G_COLOR_BLACK);
+       textcolor(G_COLOR_LIGHT_2);
+       cursor_color(G_COLOR_LIGHT_2);
+       selection_color(G_COLOR_GREY_4);
+       textsize(G_GUI_FONT_SIZE_BASE);
+
+       when(FL_WHEN_CHANGED);
+       callback(cb_onChange, this);
 }
+
+/* -------------------------------------------------------------------------- */
+
+void geInput::cb_onChange(Fl_Widget* /*w*/, void* p) { (static_cast<geInput*>(p))->cb_onChange(); }
+
+/* -------------------------------------------------------------------------- */
+
+void geInput::cb_onChange()
+{
+       if (onChange != nullptr)
+               onChange(value());
+}
\ No newline at end of file
index 52bfcffe9cbdc080b2b972ec45c9bae722753ffb..199d4fd24eb3e3e84db04454c8a7cffad716daa8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_INPUT_H
 #define GE_INPUT_H
 
-
 #include <FL/Fl_Input.H>
-
+#include <functional>
+#include <string>
 
 class geInput : public Fl_Input
 {
 public:
+       geInput(int x, int y, int w, int h, const char* l = 0);
+
+       std::function<void(const std::string&)> onChange = nullptr;
 
-       geInput(int x, int y, int w, int h, const char *l=0);
+private:
+       static void cb_onChange(Fl_Widget* w, void* p);
+       void        cb_onChange();
 };
 
 #endif
index 1da1f42146cf1c0f285b9621177f63459c1c28b1..9223e1e294b1b859fd029871d9c735ef735550e9 100644 (file)
@@ -9,7 +9,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/const.h"
-#include "boxtypes.h"
 #include "liquidScroll.h"
-
+#include "boxtypes.h"
+#include "core/const.h"
 
 geLiquidScroll::geLiquidScroll(int x, int y, int w, int h)
 : geScroll(x, y, w, h, Fl_Scroll::VERTICAL_ALWAYS)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geLiquidScroll::resize(int X, int Y, int W, int H)
 {
-       int nc = children()-2;               // skip hscrollbar and vscrollbar
-       for (int t=0; t<nc; t++) {           // tell children to resize to our new width
+       int nc = children() - 2; // skip hscrollbar and vscrollbar
+       for (int t = 0; t < nc; t++)
+       { // tell children to resize to our new width
                Fl_Widget* c = child(t);
-               c->resize(c->x(), c->y(), W-24, c->h());    // W-24: leave room for scrollbar
+               c->resize(c->x(), c->y(), W - 24, c->h()); // W-24: leave room for scrollbar
        }
-       init_sizes();   // tell scroll children changed in size
-       Fl_Scroll::resize(X,Y,W,H);
+       init_sizes(); // tell scroll children changed in size
+       Fl_Scroll::resize(X, Y, W, H);
 }
-
-
index 2616a625ed6b12ab32d1f5a08e16da0cc9246944..530249f4113bf6b131b9143965eecd23d241cfb2 100644 (file)
@@ -9,7 +9,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_LIQUID_SCROLL_H
 #define GE_LIQUID_SCROLL_H
 
-
+#include "core/const.h"
 #include "scroll.h"
 
-
 class geLiquidScroll : public geScroll
 {
 public:
-
        geLiquidScroll(int x, int y, int w, int h);
 
        void resize(int x, int y, int w, int h) override;
 
-    /* addWidget
+       /* addWidget
     Adds a new widget to the bottom, with proper spacing. */
-    
-    template<typename T>
-    T* addWidget(T* wg)
-    {
-        int numChildren = countChildren();
 
-        int wx = x();
-        int wy = y() - yposition() + (numChildren * (wg->h() + G_GUI_INNER_MARGIN));
-        int ww = w() - 24;
-        int wh = wg->h();
+       template <typename T>
+       T* addWidget(T* wg)
+       {
+               int numChildren = countChildren();
 
-        wg->resize(wx, wy, ww, wh);
-        add(wg);
-        redraw();    
+               int wx = x();
+               int wy = y() - yposition() + (numChildren * (wg->h() + G_GUI_INNER_MARGIN));
+               int ww = w() - 24;
+               int wh = wg->h();
 
-        return wg;
-    }   
-};
+               wg->resize(wx, wy, ww, wh);
+               add(wg);
+               redraw();
 
+               return wg;
+       }
+};
 
 #endif
index 288df569c2555d304d5d3bd8925dc00ea9dcb3bb..eaf50c4617532d5ad8de03cd8c2f96aaa53ab9a9 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/const.h"
 #include "pack.h"
+#include "core/const.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gePack::gePack(int x, int y, Direction d, int gutter)
-: geGroup    (x, y)
+: geGroup(x, y)
 , m_direction(d)
-, m_gutter   (gutter)
+, m_gutter(gutter)
 {
-    end();
+       end();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePack::add(Fl_Widget* widget)
 {
-    if (countChildren() == 0)
-        widget->position(0, 0);
-    else
-    if (m_direction == Direction::HORIZONTAL)
-        widget->position((getLastChild()->x() + getLastChild()->w() + m_gutter) - x(), 0);
-    else
-        widget->position(0, (getLastChild()->y() + getLastChild()->h() + m_gutter) - y());
-
-    geGroup::add(widget);
+       if (countChildren() == 0)
+               widget->position(0, 0);
+       else if (m_direction == Direction::HORIZONTAL)
+               widget->position((getLastChild()->x() + getLastChild()->w() + m_gutter) - x(), 0);
+       else
+               widget->position(0, (getLastChild()->y() + getLastChild()->h() + m_gutter) - y());
+
+       geGroup::add(widget);
 }
-}}
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index dda1233485e0812531e5d601eb7032d1af9a5aaa..13a60805c5d8dc2c7e18264e370ab11987d04376 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_PACK_H
 #define GE_PACK_H
 
-
 #include "core/const.h"
 #include "gui/elems/basics/group.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
+{
+enum class Direction
 {
-enum class Direction { HORIZONTAL, VERTICAL };
+       HORIZONTAL,
+       VERTICAL
+};
 
 /* gePack
 A stack of widgets that resize itself according to its content. */
@@ -47,21 +49,19 @@ A stack of widgets that resize itself according to its content. */
 class gePack : public geGroup
 {
 public:
+       gePack(int x, int y, Direction d, int gutter = G_GUI_INNER_MARGIN);
 
-       gePack(int x, int y, Direction d, int gutter=G_GUI_INNER_MARGIN);
-
-    /* add
+       /* add
     Adds a Fl_Widget 'w' to this pack. Coordinates are relative to the group,
     so origin starts at (0, 0). */
 
-    void add(Fl_Widget* w);
+       void add(Fl_Widget* w);
 
-private:
-
-    Direction m_direction;
-    int       m_gutter;
+  private:
+       Direction m_direction;
+       int       m_gutter;
 };
-}}
-
+} // namespace v
+} // namespace giada
 
 #endif
index 4544706a34ef187d5e2431baabae9f785de7b66d..ccf4350fd6e22e1a1d96c9c346a5adf97dd124f6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "progress.h"
 #include "../../../core/const.h"
 #include "boxtypes.h"
-#include "progress.h"
-
 
-geProgress::geProgress(int x, int y, int w, int h, const char *l)
+geProgress::geProgress(int x, int y, int w, int h, const charl)
 : Fl_Progress(x, y, w, h, l)
 {
-  color(G_COLOR_GREY_2, G_COLOR_GREY_4);
-  box(G_CUSTOM_BORDER_BOX);
+       color(G_COLOR_GREY_2, G_COLOR_GREY_4);
+       box(G_CUSTOM_BORDER_BOX);
 }
index fe957a232ce6fddf97a7a0e00e7275ed946f0d02..b1f87a140bea74d7f6af6266eaa82c57771b0206 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_PROGRESS_H
 #define GE_PROGRESS_H
 
-
 #include <FL/Fl_Progress.H>
 
-
 class geProgress : public Fl_Progress
 {
 public:
-
-       geProgress(int x, int y, int w, int h, const char *l=0);
+       geProgress(int x, int y, int w, int h, const char* l = 0);
 };
 
-
 #endif
diff --git a/src/gui/elems/basics/radio.cpp b/src/gui/elems/basics/radio.cpp
deleted file mode 100644 (file)
index d7c6405..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "core/const.h"
-#include "radio.h"
-
-
-geRadio::geRadio(int x, int y, int w, int h, const char *l)
-: Fl_Radio_Button(x, y, w, h, l)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geRadio::draw()
-{
-       int color = !active() ? FL_INACTIVE_COLOR : G_COLOR_GREY_4;
-
-       if (value()) {
-               fl_rect(x(), y(), 12, h(), (Fl_Color) color);
-               fl_rectf(x(), y(), 12, h(), (Fl_Color) color);
-       }
-       else {
-               fl_rectf(x(), y(), 12, h(), FL_BACKGROUND_COLOR);
-               fl_rect(x(), y(), 12, h(), (Fl_Color) color);
-       }
-
-       fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR);  // clearer
-       fl_font(FL_HELVETICA, G_GUI_FONT_SIZE_BASE);
-       fl_color(G_COLOR_LIGHT_2);
-       fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP));
-}
diff --git a/src/gui/elems/basics/radio.h b/src/gui/elems/basics/radio.h
deleted file mode 100644 (file)
index 1005e09..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_RADIO_H
-#define GE_RADIO_H
-
-
-#include <FL/Fl_Radio_Button.H>
-
-
-class geRadio : public Fl_Radio_Button
-{
-public:
-
-       geRadio(int x, int y, int w, int h, const char *l=0);
-
-       void draw() override;
-};
-
-
-#endif
index 48e03f255c75707eb7b20e5b9bb1531c02bd9a00..d3c1546174ffba321e40bd6133d302944eee25bb 100644 (file)
@@ -20,7 +20,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "resizerBar.h"
+#include "core/const.h"
 #include <FL/Fl.H>
 #include <FL/Fl_Scroll.H>
 #include <FL/fl_draw.H>
-#include "core/const.h"
-#include "resizerBar.h"
-
 
 geResizerBar::geResizerBar(int X, int Y, int W, int H, int minSize, bool type, Fl_Widget* target)
-: Fl_Box      (X, Y, W, H), 
-  m_type      (type),
-  m_minSize   (minSize),
-  m_lastPos   (0),
-  m_initialPos(0),
-  m_hover     (false),
-  m_target    (target)
+: Fl_Box(X, Y, W, H)
+, m_type(type)
+, m_minSize(minSize)
+, m_lastPos(0)
+, m_initialPos(0)
+, m_hover(false)
+, m_target(target)
 {
-       if (m_type == VERTICAL) {
+       if (m_type == VERTICAL)
+       {
                m_origSize = H;
                labelsize(H);
        }
-       else {
+       else
+       {
                m_origSize = W;
                labelsize(W);
        }
@@ -70,10 +70,8 @@ geResizerBar::geResizerBar(int X, int Y, int W, int H, int minSize, bool type, F
        visible_focus(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geResizerBar::handleDrag(int diff)
 {
        Fl_Scroll* group = static_cast<Fl_Scroll*>(parent());
@@ -84,35 +82,43 @@ void geResizerBar::handleDrag(int diff)
        // First pass: find widget directly above us with common edge
        // Possibly clamp 'diff' if widget would get too small..
 
-       for (int t = 0; t < group->children(); t++) {
+       for (int t = 0; t < group->children(); t++)
+       {
                Fl_Widget* wd = group->child(t);
-               if (m_type == VERTICAL) {
-                       if ((wd->y() + wd->h()) == top) {                            // found widget directly above?
+               if (m_type == VERTICAL)
+               {
+                       if ((wd->y() + wd->h()) == top)
+                       { // found widget directly above?
                                if ((wd->h() + diff) < m_minSize)
-                                       diff = wd->h() - m_minSize;                          // clamp
-                               wd->resize(wd->x(), wd->y(), wd->w(), wd->h() + diff);   // change height
-                               break;                                                   // done with first pass
+                                       diff = wd->h() - m_minSize;                        // clamp
+                               wd->resize(wd->x(), wd->y(), wd->w(), wd->h() + diff); // change height
+                               break;                                                 // done with first pass
                        }
                }
-               else {
-                       if ((wd->x() + wd->w()) == top) {                            // found widget directly above?
+               else
+               {
+                       if ((wd->x() + wd->w()) == top)
+                       { // found widget directly above?
                                if ((wd->w() + diff) < m_minSize)
-                                       diff = wd->w() - m_minSize;                          // clamp
-                               wd->resize(wd->x(), wd->y(), wd->w() + diff, wd->h());   // change width
-                               break;                                                   // done with first pass
+                                       diff = wd->w() - m_minSize;                        // clamp
+                               wd->resize(wd->x(), wd->y(), wd->w() + diff, wd->h()); // change width
+                               break;                                                 // done with first pass
                        }
                }
        }
 
        // Second pass: find widgets below us, move based on clamped diff
 
-       for (int t = 0; t < group->children(); t++) {
+       for (int t = 0; t < group->children(); t++)
+       {
                Fl_Widget* wd = group->child(t);
-               if (m_type == VERTICAL) {
-                       if (wd->y() >= bot)                                         // found widget below us?
-                               wd->resize(wd->x(), wd->y() + diff, wd->w(), wd->h());  // change position
+               if (m_type == VERTICAL)
+               {
+                       if (wd->y() >= bot)                                        // found widget below us?
+                               wd->resize(wd->x(), wd->y() + diff, wd->w(), wd->h()); // change position
                }
-               else {
+               else
+               {
                        if (wd->x() >= bot)
                                wd->resize(wd->x() + diff, wd->y(), wd->w(), wd->h());
                }
@@ -129,75 +135,69 @@ void geResizerBar::handleDrag(int diff)
        group->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geResizerBar::draw()
 {
        Fl_Box::draw();
        fl_rectf(x(), y(), w(), h(), m_hover ? G_COLOR_GREY_2 : G_COLOR_GREY_1);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geResizerBar::handle(int e)
 {
-       int ret = 0;
+       int ret        = 0;
        int currentPos = m_type == VERTICAL ? Fl::event_y_root() : Fl::event_x_root();
 
-       switch (e) {
-               case FL_FOCUS:
-                       ret = 1;
-                       break;
-               case FL_ENTER:
-                       ret = 1;
-                       fl_cursor(m_type == VERTICAL ? FL_CURSOR_NS : FL_CURSOR_WE);
-                       m_hover = true;
-                       redraw();
-                       break;
-               case FL_LEAVE:
-                       ret = 1;
-                       fl_cursor(FL_CURSOR_DEFAULT);
-                       m_hover = false;
-                       redraw();
-                       break;
-               case FL_PUSH:
-                       ret = 1;
-                       m_lastPos    = currentPos;
-                       m_initialPos = currentPos;
-                       break;
-               case FL_DRAG:
-                       handleDrag(currentPos - m_lastPos);
-                       m_lastPos = currentPos;
-                       ret = 1;
-                       if (onDrag != nullptr)
-                               onDrag(m_target);
-                       break;
-               case FL_RELEASE:
-                       if (m_initialPos != currentPos && onRelease != nullptr)
-                               onRelease(m_target);
-                       break;
-               default: break;
+       switch (e)
+       {
+       case FL_FOCUS:
+               ret = 1;
+               break;
+       case FL_ENTER:
+               ret = 1;
+               fl_cursor(m_type == VERTICAL ? FL_CURSOR_NS : FL_CURSOR_WE);
+               m_hover = true;
+               redraw();
+               break;
+       case FL_LEAVE:
+               ret = 1;
+               fl_cursor(FL_CURSOR_DEFAULT);
+               m_hover = false;
+               redraw();
+               break;
+       case FL_PUSH:
+               ret          = 1;
+               m_lastPos    = currentPos;
+               m_initialPos = currentPos;
+               break;
+       case FL_DRAG:
+               handleDrag(currentPos - m_lastPos);
+               m_lastPos = currentPos;
+               ret       = 1;
+               if (onDrag != nullptr)
+                       onDrag(m_target);
+               break;
+       case FL_RELEASE:
+               if (m_initialPos != currentPos && onRelease != nullptr)
+                       onRelease(m_target);
+               break;
+       default:
+               break;
        }
-       return(Fl_Box::handle(e) | ret);
+       return (Fl_Box::handle(e) | ret);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geResizerBar::getMinSize() const
-{ 
-       return m_minSize; 
-} 
-
+{
+       return m_minSize;
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 void geResizerBar::resize(int x, int y, int w, int h)
 {
        if (m_type == VERTICAL)
index 09638bdeb2f26dad1f19840cd4a56a463ce50589..a860241e66a2d3f9641dab7fb9d525a94f5eff8c 100644 (file)
@@ -20,7 +20,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_RESIZER_BAR_H
 #define GE_RESIZER_BAR_H
 
-
-#include <functional>
 #include <FL/Fl_Box.H>
-
+#include <functional>
 
 class geResizerBar : public Fl_Box
 {
 public:
-
        static const int HORIZONTAL = 0;
        static const int VERTICAL   = 1;
 
-       geResizerBar(int x, int y, int w, int h, int minSize, bool type, Fl_Widget* target=nullptr);
+       geResizerBar(int x, int y, int w, int h, int minSize, bool type, Fl_Widget* target = nullptr);
 
-       int handle(int e) override;
+       int  handle(int e) override;
        void draw() override;
        void resize(int x, int y, int w, int h) override;
 
        int getMinSize() const;
 
-       std::function<void(const Fl_Widget*)> onDrag = nullptr;
+       std::function<void(const Fl_Widget*)> onDrag    = nullptr;
        std::function<void(const Fl_Widget*)> onRelease = nullptr;
 
-private:
-
+  private:
        void handleDrag(int diff);
 
        bool m_type;
@@ -81,5 +76,4 @@ private:
        Fl_Widget* m_target;
 };
 
-
 #endif
index eb1fce098c61a82e0203063c0ea96189e2f88882..9746ea2c331a7de898d0fb46381e03c9274cbf53 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/const.h"
-#include "boxtypes.h"
 #include "scroll.h"
-
+#include "boxtypes.h"
+#include "core/const.h"
+#include <cassert>
 
 geScroll::geScroll(int x, int y, int w, int h, int t)
 : Fl_Scroll(x, y, w, h)
@@ -51,10 +49,8 @@ geScroll::geScroll(int x, int y, int w, int h, int t)
        hscrollbar.slider(G_CUSTOM_BORDER_BOX);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geScroll::countChildren() const
 {
        return children() - 2; // Exclude scrollbars
index e2cd54967fbeb3ad67d50f8c7519863805d68d4f..5963c5cd57006a997c698019c9fefb7faeba2c2b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SCROLL_H
 #define GE_SCROLL_H
 
-
 #include <FL/Fl_Scroll.H>
 
-
 class geScroll : public Fl_Scroll
 {
 public:
+       geScroll(int x, int y, int w, int h, int type = Fl_Scroll::BOTH);
 
-       geScroll(int x, int y, int w, int h, int type=Fl_Scroll::BOTH);
-
-    int countChildren() const;
+       int countChildren() const;
 };
 
-
 #endif
index 364cbffa44915ce38158778ac0633affc27f1dd6..9917e2f901e4459622f0c657d5689da3915ecf24 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "core/const.h"
-#include "boxtypes.h"
 #include "scrollPack.h"
+#include "boxtypes.h"
+#include "core/const.h"
+#include <cassert>
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geScrollPack::geScrollPack(int x, int y, int w, int h, int type, Direction dir,
     int gutter)
-: geScroll   (x, y, w, h, type)
+: geScroll(x, y, w, h, type)
 , m_direction(dir)
-, m_gutter   (gutter)
+, m_gutter(gutter)
 {
-    end();
+       end();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::size_t geScrollPack::countChildren() const
 {
-    return m_widgets.size();
+       return m_widgets.size();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geScrollPack::add(Fl_Widget* w)
 {
-    if (countChildren() == 0)
-        w->position(x(), y());
-    else
-    if (m_direction == Direction::HORIZONTAL)
-        w->position((getLastChild()->x() + getLastChild()->w() + m_gutter), y());
-    else
-        w->position(x(), (getLastChild()->y() + getLastChild()->h() + m_gutter));
-
-    geScroll::add(w);
-    m_widgets.push_back(w);
+       if (countChildren() == 0)
+               w->position(x(), y());
+       else if (m_direction == Direction::HORIZONTAL)
+               w->position((getLastChild()->x() + getLastChild()->w() + m_gutter), y());
+       else
+               w->position(x(), (getLastChild()->y() + getLastChild()->h() + m_gutter));
+
+       geScroll::add(w);
+       m_widgets.push_back(w);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 Fl_Widget* geScrollPack::getChild(std::size_t i)
 {
-    return m_widgets.at(i); // Throws std::out_of_range in case
+       return m_widgets.at(i); // Throws std::out_of_range in case
 }
 
 /* -------------------------------------------------------------------------- */
 
-
 Fl_Widget* geScrollPack::getLastChild()
 {
-    return m_widgets.at(m_widgets.size() - 1); // Throws std::out_of_range in case
+       return m_widgets.at(m_widgets.size() - 1); // Throws std::out_of_range in case
 }
-}}
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 64de3b6ae35062b94e0e4efb694c894f38cf0c55..f855532bfaacc135cb0d009b11bfb979dc5f8402 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SCROLL_PACK_H
 #define GE_SCROLL_PACK_H
 
-
-#include "gui/elems/basics/scroll.h"
 #include "gui/elems/basics/pack.h"
+#include "gui/elems/basics/scroll.h"
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 /* geScrollPack
 A scrollable viewport that contains packed widgets. */
@@ -42,32 +40,30 @@ A scrollable viewport that contains packed widgets. */
 class geScrollPack : public geScroll
 {
 public:
+       geScrollPack(int x, int y, int w, int h, int type = Fl_Scroll::BOTH,
+           Direction d = Direction::HORIZONTAL, int gutter = G_GUI_INNER_MARGIN);
 
-       geScrollPack(int x, int y, int w, int h, int type=Fl_Scroll::BOTH, 
-        Direction d=Direction::HORIZONTAL, int gutter=G_GUI_INNER_MARGIN);
-
-    /* countChildren
+       /* countChildren
     Returns the number of widgets contained in this group. */
-    
-    std::size_t countChildren() const;
-    
-    void add(Fl_Widget* w);
 
-    Fl_Widget* getChild(std::size_t i);
-    Fl_Widget* getLastChild();
+       std::size_t countChildren() const;
 
-private:
+       void add(Fl_Widget* w);
 
-    /* m_widgets 
+       Fl_Widget* getChild(std::size_t i);
+       Fl_Widget* getLastChild();
+
+  private:
+       /* m_widgets 
     The internal Fl_Scroll::array_ is unreliable when inspected with the child()
     method. Let's keep track of widgets that belong to this group manually. */
 
-    std::vector<Fl_Widget*> m_widgets;  
+       std::vector<Fl_Widget*> m_widgets;
 
-    Direction m_direction;
-    int       m_gutter;
+       Direction m_direction;
+       int       m_gutter;
 };
-}}
-
+} // namespace v
+} // namespace giada
 
 #endif
index ed767d7cea57238e197642af71f9019641c9bc35..b41cae6e225bf444a637a1ff6f6f6e5ca39cee21 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "slider.h"
 #include "../../../core/const.h"
 #include "boxtypes.h"
-#include "slider.h"
-
 
-geSlider::geSlider(int x, int y, int w, int h, const char *l)
- : Fl_Slider(x, y, w, h, l)
+geSlider::geSlider(int x, int y, int w, int h, const charl)
+: Fl_Slider(x, y, w, h, l)
 {
- type(FL_HOR_FILL_SLIDER);
      type(FL_HOR_FILL_SLIDER);
 
- labelsize(G_GUI_FONT_SIZE_BASE);
- align(FL_ALIGN_LEFT);
- labelcolor(G_COLOR_LIGHT_2);
      labelsize(G_GUI_FONT_SIZE_BASE);
      align(FL_ALIGN_LEFT);
      labelcolor(G_COLOR_LIGHT_2);
 
- box(G_CUSTOM_BORDER_BOX);
- color(G_COLOR_GREY_2);
- selection_color(G_COLOR_GREY_4);
      box(G_CUSTOM_BORDER_BOX);
      color(G_COLOR_GREY_2);
      selection_color(G_COLOR_GREY_4);
 }
index 29d0b0730f61ee7f0b5b270aa971d9b9261436e6..7e1d41eb5e7c2af4d7450efcd91c21302217cab1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SLIDER_H
 #define GE_SLIDER_H
 
-
 #include <FL/Fl_Slider.H>
 
-
 class geSlider : public Fl_Slider
 {
 public:
+       geSlider(int x, int y, int w, int h, const char* l = 0);
 
-  geSlider(int x, int y, int w, int h, const char *l=0);
-
-  int id;
+       int id;
 };
 
-
 #endif
index 43c073ea2950f7df3e013d6c4eb50bbe09510a0c..7f554fe1559bf74bafe6360d1ed422b3f2edb176 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
-#include "core/const.h"
 #include "statusButton.h"
+#include "core/const.h"
+#include <FL/fl_draw.H>
 
-
+namespace giada::v
+{
 geStatusButton::geStatusButton(int x, int y, int w, int h, const char** imgOff,
-       const char** imgOn, const char** imgDisabled)
-: geButton(x, y, w, h, "", imgOff, imgOn, imgDisabled),
-  m_status(false)
+    const char** imgOn, const char** imgDisabled)
+: geButton(x, y, w, h, "", imgOff, imgOn, imgDisabled)
+, m_status(false)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geStatusButton::draw()
 {
        if (active())
-               if (m_status) geButton::draw(imgOn,  bgColor1, txtColor);
-               else          geButton::draw(imgOff, bgColor0, txtColor);
+               if (m_status)
+                       geButton::draw(imgOn, bgColor1, txtColor);
+               else
+                       geButton::draw(imgOff, bgColor0, txtColor);
        else
                geButton::draw(imgDisabled, bgColor0, bdColor);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geStatusButton::setStatus(bool s)
 {
-    m_status = s;
-    redraw();
+       m_status = s;
+       redraw();
 }
 
-
 bool geStatusButton::getStatus() const
 {
-    return m_status;
+       return m_status;
 }
+} // namespace giada::v
\ No newline at end of file
index 469df4126bd92dc5e398e9d652883df54cae7db9..3805aac8235573143cb7fedbdcd147f3d126cb81 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_STATUS_BUTTON_H
 #define GE_STATUS_BUTTON_H
 
-
 #include "button.h"
 
-
+namespace giada::v
+{
 class geStatusButton : public geButton
 {
-public:
-
-       geStatusButton(int x, int y, int w, int h, const char** imgOff=nullptr,
-    const char** imgOn=nullptr, const char** imgDisabled=nullptr);
+  public:
+       geStatusButton(int x, int y, int w, int h, const char** imgOff = nullptr,
+           const char** imgOn = nullptr, const char** imgDisabled = nullptr);
 
        void draw() override;
 
-    bool getStatus() const;
-
-    void setStatus(bool s);
+       bool getStatus() const;
 
-private:
+       void setStatus(bool s);
 
+  private:
        bool m_status;
 };
-
+} // namespace giada::v
 
 #endif
index 659e896322d8632499063f4d6cd737bcfac69366..30a878b546cbd56928496811e88bcecef2d85c56 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "browser.h"
+#include "basics/boxtypes.h"
 #include "core/const.h"
-#include "utils/string.h"
-#include "utils/fs.h"
 #include "gui/dialogs/browser/browserBase.h"
-#include "basics/boxtypes.h"
-#include "browser.h"
-
+#include "utils/fs.h"
+#include "utils/string.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geBrowser::geBrowser(int x, int y, int w, int h)
-: Fl_File_Browser  (x, y, w, h),
-  m_showHiddenFiles(false)
+: Fl_File_Browser(x, y, w, h)
+, m_showHiddenFiles(false)
 {
        box(G_CUSTOM_BORDER_BOX);
        textsize(G_GUI_FONT_SIZE_BASE);
@@ -57,23 +56,19 @@ geBrowser::geBrowser(int x, int y, int w, int h)
        this->hscrollbar.labelcolor(G_COLOR_LIGHT_1);
        this->hscrollbar.slider(G_CUSTOM_BORDER_BOX);
 
-       take_focus();  // let it have focus on startup
+       take_focus(); // let it have focus on startup
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBrowser::toggleHiddenFiles()
 {
        m_showHiddenFiles = !m_showHiddenFiles;
        loadDir(m_currentDir);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBrowser::loadDir(const std::string& dir)
 {
        m_currentDir = dir;
@@ -82,7 +77,8 @@ void geBrowser::loadDir(const std::string& dir)
        /* Clean up unwanted elements. Hide "../" first, it just screws up things.
        Also remove hidden files, if requested. */
 
-       for (int i=size(); i>=0; i--) {
+       for (int i = size(); i >= 0; i--)
+       {
                if (text(i) == nullptr)
                        continue;
                if (strcmp(text(i), "../") == 0 || (!m_showHiddenFiles && strncmp(text(i), ".", 1) == 0))
@@ -90,69 +86,66 @@ void geBrowser::loadDir(const std::string& dir)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
 int geBrowser::handle(int e)
 {
        int ret = Fl_File_Browser::handle(e);
-       switch (e) {
-               case FL_FOCUS:
-               case FL_UNFOCUS:
-                       ret = 1;                        // enables receiving Keyboard events
-                       break;
-               case FL_KEYDOWN:  // keyboard
-                       if (Fl::event_key(FL_Down))
-                               select(value() + 1);
-                       else
-                       if (Fl::event_key(FL_Up))
-                               select(value() - 1);
-                       else
-                       if (Fl::event_key(FL_Enter))
-                               static_cast<v::gdBrowserBase*>(parent())->fireCallback();
-                       ret = 1;
-                       break;
-               case FL_PUSH:    // mouse
-                       if (Fl::event_clicks() > 0)  // double click
-                               static_cast<v::gdBrowserBase*>(parent())->fireCallback();
-                       ret = 1;
-                       break;
-               case FL_RELEASE: // mouse
-                       /* nasty trick to keep the selection on mouse release */
-                       if (value() > 1) {
-                               select(value() - 1);
-                               select(value() + 1);
-                       }
-                       else {
-                               select(value() + 1);
-                               select(value() - 1);
-                       }
-                       ret = 1;
-                       break;
+       switch (e)
+       {
+       case FL_FOCUS:
+       case FL_UNFOCUS:
+               ret = 1; // enables receiving Keyboard events
+               break;
+       case FL_KEYDOWN: // keyboard
+               if (Fl::event_key(FL_Down))
+                       select(value() + 1);
+               else if (Fl::event_key(FL_Up))
+                       select(value() - 1);
+               else if (Fl::event_key(FL_Enter))
+                       static_cast<v::gdBrowserBase*>(parent())->fireCallback();
+               ret = 1;
+               break;
+       case FL_PUSH:                   // mouse
+               if (Fl::event_clicks() > 0) // double click
+                       static_cast<v::gdBrowserBase*>(parent())->fireCallback();
+               ret = 1;
+               break;
+       case FL_RELEASE: // mouse
+               /* nasty trick to keep the selection on mouse release */
+               if (value() > 1)
+               {
+                       select(value() - 1);
+                       select(value() + 1);
+               }
+               else
+               {
+                       select(value() + 1);
+                       select(value() - 1);
+               }
+               ret = 1;
+               break;
        }
        return ret;
 }
 
 /* -------------------------------------------------------------------------- */
 
-
 std::string geBrowser::getCurrentDir()
 {
        return normalize(u::fs::getRealPath(m_currentDir));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string geBrowser::getSelectedItem(bool fullPath)
 {
-       if (!fullPath)     // no full path requested? return the selected text
+       if (!fullPath) // no full path requested? return the selected text
                return normalize(text(value()));
-       else
-       if (value() == 0)  // no rows selected? return current directory
+       else if (value() == 0) // no rows selected? return current directory
                return normalize(m_currentDir);
-       else {
+       else
+       {
 #ifdef G_OS_WINDOWS
                std::string sep = m_currentDir != "" ? G_SLASH_STR : "";
 #else
@@ -162,20 +155,16 @@ std::string geBrowser::getSelectedItem(bool fullPath)
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBrowser::preselect(int pos, int line)
 {
        position(pos);
        select(line);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string geBrowser::normalize(const std::string& s)
 {
        std::string out = s;
@@ -185,7 +174,8 @@ std::string geBrowser::normalize(const std::string& s)
 
        //if (out.back() == G_SLASH && out.length() > 1)
        if (out.back() == G_SLASH && !u::fs::isRootDir(s))
-               out = out.substr(0, out.size()-1);
+               out = out.substr(0, out.size() - 1);
        return out;
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index a9bed3b3072dca00a19847697db1862bcc8f5a05..7fcfe8fe1574a2a48c9144d8f70bb0edf2ccfd06 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BROWSER_H
 #define GE_BROWSER_H
 
-
-#include <string>
 #include <FL/Fl_File_Browser.H>
+#include <string>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geBrowser : public Fl_File_Browser
 {
 public:
-
        geBrowser(int x, int y, int w, int h);
 
        void toggleHiddenFiles();
@@ -55,7 +52,7 @@ public:
        Returns the full path or just the displayed name of the i-th selected item.
        Always with the trailing slash! */
 
-       std::string getSelectedItem(bool fullPath=true);
+       std::string getSelectedItem(bool fullPath = true);
 
        std::string getCurrentDir();
 
@@ -63,17 +60,16 @@ public:
 
        int handle(int e);
 
-private:
-
+  private:
        /* normalize
        Makes sure the std::string never ends with a trailing slash. */
 
        std::string normalize(const std::string& s);
 
        std::string m_currentDir;
-       bool m_showHiddenFiles;
+       bool        m_showHiddenFiles;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index b23924972bd3e2a1540deab6399f88b4d3cd2ba3..0705c4d0fea5b91fc80f740bca84a8b706b4c350 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <string>
-#include "deps/rtaudio/RtAudio.h"
+#include "tabAudio.h"
 #include "core/const.h"
-#include "core/conf.h"
 #include "core/kernelAudio.h"
-#include "utils/string.h"
-#include "gui/dialogs/devInfo.h"
+#include "deps/rtaudio/RtAudio.h"
 #include "gui/elems/basics/box.h"
-#include "gui/elems/basics/choice.h"
+#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/input.h"
-#include "gui/elems/basics/button.h"
-#include "tabAudio.h"
-
+#include "utils/string.h"
+#include <string>
 
-namespace giada {
-namespace v
+namespace giada::v
 {
-geTabAudio::geTabAudio(int X, int Y, int W, int H)
-: Fl_Group(X, Y, W, H, "Sound System")
+geTabAudio::geDeviceMenu::geDeviceMenu(int x, int y, int w, int h, const char* l, const std::vector<c::config::AudioDeviceData>& devices)
+: geChoice(x, y, w, h, l)
 {
-       begin();
-       soundsys        = new geChoice(x()+114, y()+9,  250, 20, "System");
-       buffersize      = new geChoice(x()+114, y()+37, 55,  20, "Buffer size");
-       samplerate      = new geChoice(x()+304, y()+37, 60,  20, "Sample rate");
-       sounddevOut     = new geChoice(x()+114, y()+65, 222, 20, "Output device");
-       devOutInfo      = new geButton(x()+344, y()+65, 20,  20, "?");
-       channelsOut     = new geChoice(x()+114, y()+93, 55,  20, "Output channels");
-       limitOutput     = new geCheck (x()+177, y()+93, 55,  20, "Limit output");
-       sounddevIn      = new geChoice(x()+114, y()+121, 222, 20, "Input device");
-       devInInfo       = new geButton(x()+344, y()+121, 20,  20, "?");
-       channelsIn      = new geChoice(x()+114, y()+149, 55,  20, "Input channels");
-       recTriggerLevel = new geInput (x()+309, y()+149, 55,  20, "Rec threshold (dB)");
-       rsmpQuality     = new geChoice(x()+114, y()+177, 250, 20, "Resampling");
-                      new geBox(x(), rsmpQuality->y()+rsmpQuality->h()+8, w(), 92, "Restart Giada for the changes to take effect.");
-       end();
-
-       labelsize(G_GUI_FONT_SIZE_BASE);
-       selection_color(G_COLOR_GREY_4);
-
-       soundsys->add("(none)");
-
-#if defined(__linux__)
-
-       if (m::kernelAudio::hasAPI(RtAudio::LINUX_ALSA))
-               soundsys->add("ALSA");
-       if (m::kernelAudio::hasAPI(RtAudio::UNIX_JACK))
-               soundsys->add("Jack");
-       if (m::kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
-               soundsys->add("PulseAudio");
-
-       switch (m::conf::conf.soundSystem) {
-               case G_SYS_API_NONE:
-                       soundsys->showItem("(none)");
-                       break;
-               case G_SYS_API_ALSA:
-                       soundsys->showItem("ALSA");
-                       break;
-               case G_SYS_API_JACK:
-                       soundsys->showItem("Jack");
-                       buffersize->deactivate();
-                       samplerate->deactivate();
-                       break;
-               case G_SYS_API_PULSE:
-                       soundsys->showItem("PulseAudio");
-                       break;
-       }
-
-#elif defined(__FreeBSD__)
-
-       if (m::kernelAudio::hasAPI(RtAudio::UNIX_JACK))
-               soundsys->add("Jack");
-       if (m::kernelAudio::hasAPI(RtAudio::LINUX_PULSE))
-               soundsys->add("PulseAudio");
-
-       switch (m::conf::conf.soundSystem) {
-               case G_SYS_API_NONE:
-                       soundsys->showItem("(none)");
-                       break;
-               case G_SYS_API_JACK:
-                       soundsys->showItem("Jack");
-                       buffersize->deactivate();
-                       samplerate->deactivate();
-                       break;
-               case G_SYS_API_PULSE:
-                       soundsys->showItem("PulseAudio");
-                       break;
-       }
-
-#elif defined(_WIN32)
-
-       if (m::kernelAudio::hasAPI(RtAudio::WINDOWS_DS))
-               soundsys->add("DirectSound");
-       if (m::kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO))
-               soundsys->add("ASIO");
-       if (m::kernelAudio::hasAPI(RtAudio::WINDOWS_WASAPI))
-               soundsys->add("WASAPI");
-
-       switch (m::conf::conf.soundSystem) {
-               case G_SYS_API_NONE:
-                       soundsys->showItem("(none)");
-                       break;
-               case G_SYS_API_DS:
-                       soundsys->showItem("DirectSound");
-                       break;
-               case G_SYS_API_ASIO:
-                       soundsys->showItem("ASIO");
-                       break;
-               case G_SYS_API_WASAPI:
-                       soundsys->showItem("WASAPI");
-                       break;
-       }
-
-#elif defined(__APPLE__)
-
-       if (m::kernelAudio::hasAPI(RtAudio::MACOSX_CORE))
-               soundsys->add("CoreAudio");
-
-       switch (m::conf::conf.soundSystem) {
-               case G_SYS_API_NONE:
-                       soundsys->showItem("(none)");
-                       break;
-               case G_SYS_API_CORE:
-                       soundsys->showItem("CoreAudio");
-                       break;
-       }
-
-#endif
-
-       soundsysInitValue = soundsys->value();
-
-       soundsys->callback(cb_deactivate_sounddev, (void*)this);
-
-       sounddevIn->callback(cb_fetchInChans, this);
-       sounddevOut->callback(cb_fetchOutChans, this);
-
-       devOutInfo->callback(cb_showOutputInfo, this);
-       devInInfo->callback(cb_showInputInfo, this);
-
-       if (m::conf::conf.soundSystem != G_SYS_API_NONE) {
-               fetchSoundDevs();
-               fetchOutChans();
-               fetchInChans(sounddevIn->value());
-
-               /* fill frequency dropdown menu */
-               /* TODO - add fetchFrequencies() */
-
-               int nfreq = m::kernelAudio::getTotalFreqs(sounddevOut->value());
-               for (int i=0; i<nfreq; i++) {
-                       int freq = m::kernelAudio::getFreq(sounddevOut->value(), i);
-                       samplerate->add(u::string::iToString(freq).c_str());
-                       if (freq == m::conf::conf.samplerate)
-                               samplerate->value(i);
-               }
-       }
-       else {
-               sounddevIn->deactivate();
-               sounddevOut->deactivate();
-               channelsIn->deactivate();
-               channelsOut->deactivate();
-               devOutInfo->deactivate();
-               devInInfo->deactivate();
-               samplerate->deactivate();
+       if (devices.size() == 0)
+       {
+               addItem("-- no devices found --", 0);
+               showItem(0);
+               return;
        }
 
-       buffersize->add("8");
-       buffersize->add("16");
-       buffersize->add("32");
-       buffersize->add("64");
-       buffersize->add("128");
-       buffersize->add("256");
-       buffersize->add("512");
-       buffersize->add("1024");
-       buffersize->add("2048");
-       buffersize->add("4096");
-       buffersize->showItem(std::to_string(m::conf::conf.buffersize).c_str());
-
-       rsmpQuality->add("Sinc best quality (very slow)");
-       rsmpQuality->add("Sinc medium quality (slow)");
-       rsmpQuality->add("Sinc basic quality (medium)");
-       rsmpQuality->add("Zero Order Hold (fast)");
-       rsmpQuality->add("Linear (very fast)");
-       rsmpQuality->value(m::conf::conf.rsmpQuality);
-
-       recTriggerLevel->value(u::string::fToString(m::conf::conf.recTriggerLevel, 1).c_str());
-
-       limitOutput->value(m::conf::conf.limitOutput);
+       for (const c::config::AudioDeviceData& device : devices)
+               addItem(device.name, device.index);
 }
 
-
 /* -------------------------------------------------------------------------- */
-
-
-void geTabAudio::cb_deactivate_sounddev(Fl_Widget* /*w*/, void* p) { ((geTabAudio*)p)->cb_deactivate_sounddev(); }
-void geTabAudio::cb_fetchInChans(Fl_Widget* /*w*/, void* p)        { ((geTabAudio*)p)->cb_fetchInChans(); }
-void geTabAudio::cb_fetchOutChans(Fl_Widget* /*w*/, void* p)       { ((geTabAudio*)p)->cb_fetchOutChans(); }
-void geTabAudio::cb_showInputInfo(Fl_Widget* /*w*/, void* p)       { ((geTabAudio*)p)->cb_showInputInfo(); }
-void geTabAudio::cb_showOutputInfo(Fl_Widget* /*w*/, void* p)      { ((geTabAudio*)p)->cb_showOutputInfo(); }
-
-
 /* -------------------------------------------------------------------------- */
-
-
-void geTabAudio::cb_fetchInChans()
-{
-       fetchInChans(sounddevIn->value());
-       channelsIn->value(0);
-}
-
-
 /* -------------------------------------------------------------------------- */
 
-
-void geTabAudio::cb_fetchOutChans()
+geTabAudio::geChannelMenu::geChannelMenu(int x, int y, int w, int h, const char* l, c::config::AudioDeviceData& data)
+: geChoice(x, y, w, h, l)
+, m_data(data)
 {
-       fetchOutChans();
-       channelsOut->value(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geTabAudio::cb_showInputInfo()
+int geTabAudio::geChannelMenu::getChannelsCount() const
 {
-       unsigned dev = m::kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       new v::gdDevInfo(dev);
+       return getSelectedId() < STEREO_OFFSET ? 1 : 2;
 }
 
-
-/* -------------------------------------------------------------------------- */
-
-
-void geTabAudio::cb_showOutputInfo()
+int geTabAudio::geChannelMenu::getChannelsStart() const
 {
-       unsigned dev = m::kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       new v::gdDevInfo(dev);
+       if (m_data.channelsCount == 1)
+               return getSelectedId();
+       return getSelectedId() < STEREO_OFFSET ? getSelectedId() : getSelectedId() - STEREO_OFFSET;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geTabAudio::cb_deactivate_sounddev()
+void geTabAudio::geChannelMenu::rebuild(c::config::AudioDeviceData& data)
 {
-       /* if the user changes sound system (eg ALSA->JACK) device menu deactivates.
-        * If it returns to the original sound system, we re-fill the list by
-        * querying m::kernelAudio. Watch out if soundsysInitValue == 0: you don't want
-        * to query m::kernelAudio for '(none)' soundsystem! */
+       m_data = data;
 
-       if (soundsysInitValue == soundsys->value() && soundsysInitValue != 0) {
-               sounddevOut->clear();
-               sounddevIn->clear();
+       clear();
 
-               fetchSoundDevs();
-
-               /* the '?' button is added by fetchSoundDevs */
+       if (m_data.index == -1)
+       {
+               addItem("none", 0);
+               showItem(0);
+               return;
+       }
 
-               fetchOutChans();
-               sounddevOut->activate();
-               channelsOut->activate();
+       if (m_data.type == c::config::DeviceType::INPUT)
+               for (int i = 0; i < m_data.channelsMax; i++)
+                       addItem(std::to_string(i + 1), i);
 
-               /* chan menus and '?' button are activated by fetchInChans(...) */
+       /* Dirty trick for stereo channels: they start at STEREO_OFFSET. */
 
-               fetchInChans(sounddevIn->value());
-               sounddevIn->activate();
-               samplerate->activate();
-       }
-       else {
-               sounddevOut->deactivate();
-               sounddevOut->clear();
-               sounddevOut->add("-- restart to fetch device(s) --");
-               sounddevOut->value(0);
-               channelsOut->deactivate();
-               devOutInfo->deactivate();
-               samplerate->deactivate();
+       for (int i = 0; i < m_data.channelsMax; i += 2)
+               addItem(std::to_string(i + 1) + "-" + std::to_string(i + 2), i + STEREO_OFFSET);
 
-               sounddevIn->deactivate();
-               sounddevIn->clear();
-               sounddevIn->add("-- restart to fetch device(s) --");
-               sounddevIn->value(0);
-               channelsIn->deactivate();
-               devInInfo->deactivate();
-       }
+       if (m_data.channelsCount == 1)
+               showItem(m_data.channelsStart);
+       else
+               showItem(m_data.channelsStart + STEREO_OFFSET);
 }
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
-void geTabAudio::fetchInChans(int menuItem)
+geTabAudio::geTabAudio(int X, int Y, int W, int H)
+: Fl_Group(X, Y, W, H, "Sound System")
+, m_data(c::config::getAudioData())
+, m_initialApi(m_data.api)
 {
-       /* if menuItem==0 device in input is disabled. */
-
-       if (menuItem == 0) {
-               devInInfo->deactivate();
-               channelsIn->deactivate();
-               recTriggerLevel->deactivate();
-               return;
-       }
-
-       devInInfo->activate();
-       channelsIn->activate();
-       recTriggerLevel->activate();
-
-       channelsIn->clear();
+       begin();
+       soundsys        = new geChoice(x() + 114, y() + 9, 250, 20, "System");
+       buffersize      = new geChoice(x() + 114, y() + 37, 55, 20, "Buffer size");
+       samplerate      = new geChoice(x() + 304, y() + 37, 60, 20, "Sample rate");
+       sounddevOut     = new geDeviceMenu(x() + 114, y() + 65, 250, 20, "Output device", m_data.outputDevices);
+       channelsOut     = new geChannelMenu(x() + 114, y() + 93, 55, 20, "Output channels", m_data.outputDevice);
+       limitOutput     = new geCheck(x() + 177, y() + 93, 100, 20, "Limit output");
+       sounddevIn      = new geDeviceMenu(x() + 114, y() + 121, 234, 20, "Input device", m_data.inputDevices);
+       enableIn        = new geCheck(sounddevIn->x() + sounddevIn->w() + 4, sounddevIn->y(), 12, 20);
+       channelsIn      = new geChannelMenu(x() + 114, y() + 149, 55, 20, "Input channels", m_data.inputDevice);
+       recTriggerLevel = new geInput(x() + 309, y() + 149, 55, 20, "Rec threshold (dB)");
+       rsmpQuality     = new geChoice(x() + 114, y() + 177, 250, 20, "Resampling");
+       new geBox(x(), rsmpQuality->y() + rsmpQuality->h() + 8, w(), 92, "Restart Giada for the changes to take effect.");
+       end();
 
-       unsigned dev = m::kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       unsigned chs = m::kernelAudio::getMaxInChans(dev);
+       labelsize(G_GUI_FONT_SIZE_BASE);
+       selection_color(G_COLOR_GREY_4);
 
-       if (chs == 0) {
-               channelsIn->add("none");
-               channelsIn->value(0);
-               return;
-       }
+       for (const auto& [key, value] : m_data.apis)
+               soundsys->addItem(value.c_str(), key);
+       soundsys->showItem(m_data.api);
+       soundsys->onChange = [this](ID id) { m_data.api = id; invalidate(); };
+
+       samplerate->onChange = [this](ID id) { m_data.sampleRate = id; };
+
+       sounddevOut->showItem(m_data.outputDevice.index);
+       sounddevOut->onChange = [this](ID id) { m_data.setOutputDevice(id); fetch(); };
+
+       sounddevIn->showItem(m_data.inputDevice.index);
+       sounddevIn->onChange = [this](ID id) { m_data.setInputDevice(id); fetch(); };
+
+       enableIn->copy_tooltip("Enable Input");
+       enableIn->value(m_data.inputDevice.index != -1);
+       enableIn->onChange = [this](bool b) { m_data.setInputDevice(b ? 0 : -1); fetch(); };
+
+       channelsOut->onChange = [this](ID) {
+               m_data.outputDevice.channelsCount = channelsOut->getChannelsCount();
+               m_data.outputDevice.channelsStart = channelsOut->getChannelsStart();
+       };
+
+       channelsIn->onChange = [this](ID) {
+               m_data.inputDevice.channelsCount = channelsIn->getChannelsCount();
+               m_data.inputDevice.channelsStart = channelsIn->getChannelsStart();
+       };
+
+       limitOutput->value(m_data.limitOutput);
+       limitOutput->onChange = [this](bool v) { m_data.limitOutput = v; };
+
+       buffersize->addItem("8", 8);
+       buffersize->addItem("16", 16);
+       buffersize->addItem("32", 32);
+       buffersize->addItem("64", 64);
+       buffersize->addItem("128", 128);
+       buffersize->addItem("256", 256);
+       buffersize->addItem("512", 512);
+       buffersize->addItem("1024", 1024);
+       buffersize->addItem("2048", 2048);
+       buffersize->addItem("4096", 4096);
+       buffersize->showItem(m_data.bufferSize);
+       buffersize->onChange = [this](ID id) { m_data.bufferSize = id; };
+
+       rsmpQuality->addItem("Sinc best quality (very slow)", 0);
+       rsmpQuality->addItem("Sinc medium quality (slow)", 1);
+       rsmpQuality->addItem("Sinc basic quality (medium)", 2);
+       rsmpQuality->addItem("Zero Order Hold (fast)", 3);
+       rsmpQuality->addItem("Linear (very fast)", 4);
+       rsmpQuality->showItem(m_data.resampleQuality);
+       rsmpQuality->onChange = [this](ID id) { m_data.resampleQuality = id; };
+
+       recTriggerLevel->value(u::string::fToString(m_data.recTriggerLevel, 1).c_str());
+       recTriggerLevel->onChange = [this](const std::string& s) { m_data.recTriggerLevel = std::stof(s); };
+
+       if (m_data.api == G_SYS_API_NONE)
+               deactivateAll();
+       else
+               fetch();
+}
 
-       /* Dirty trick for stereo inputs: indexes start from 1000. */
+/* -------------------------------------------------------------------------- */
 
-       for (unsigned i = 0; i < chs; i++) 
-               channelsIn->addItem(std::to_string(i + 1).c_str(), i + 1);
-       for (unsigned i = 0; i < chs; i += 2)
-               channelsIn->addItem((std::to_string(i + 1) + "-" + std::to_string(i + 2)).c_str(), i + 1001);
+void geTabAudio::invalidate()
+{
+       /* If the user changes sound system (e.g. ALSA->JACK), deactivate all widgets. */
 
-       if (m::conf::conf.channelsInCount == 1)
-               channelsIn->showItem(m::conf::conf.channelsInStart + 1);
+       if (m_initialApi == m_data.api && m_initialApi != -1 && m_data.api != G_SYS_API_NONE)
+               activateAll();
        else
-               channelsIn->showItem(m::conf::conf.channelsInStart + 1001);
+               deactivateAll();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geTabAudio::fetchOutChans()
+void geTabAudio::fetch()
 {
-       channelsOut->clear();
+       for (int sampleRate : m_data.outputDevice.sampleRates)
+               samplerate->addItem(std::to_string(sampleRate), sampleRate);
+       samplerate->showItem(m_data.sampleRate);
 
-       unsigned dev = m::kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       unsigned chs = m::kernelAudio::getMaxOutChans(dev);
+       channelsOut->rebuild(m_data.outputDevice);
+       m_data.outputDevice.channelsCount = channelsOut->getChannelsCount();
+       m_data.outputDevice.channelsStart = channelsOut->getChannelsStart();
 
-       if (chs == 0) {
-               channelsOut->add("none");
-               channelsOut->value(0);
-               return;
+       if (m_data.api == G_SYS_API_JACK)
+               buffersize->deactivate();
+       else
+               buffersize->activate();
+
+       if (m_data.inputDevice.index != -1)
+       {
+               channelsIn->rebuild(m_data.inputDevice);
+               m_data.inputDevice.channelsCount = channelsIn->getChannelsCount();
+               m_data.inputDevice.channelsStart = channelsIn->getChannelsStart();
+               sounddevIn->activate();
+               channelsIn->activate();
+               recTriggerLevel->activate();
        }
-       for (unsigned i=0; i<chs; i+=2) {
-               std::string tmp = u::string::iToString(i+1) + "-" + u::string::iToString(i+2);
-               channelsOut->add(tmp.c_str());
+       else
+       {
+               sounddevIn->deactivate();
+               channelsIn->deactivate();
+               recTriggerLevel->deactivate();
        }
-       channelsOut->value(m::conf::conf.channelsOut);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-int geTabAudio::findMenuDevice(geChoice *m, int device)
+void geTabAudio::deactivateAll()
 {
-       if (device == -1 || !m::kernelAudio::isReady())
-               return 0;
-
-       for (int i=0; i<m->size(); i++) {
-               if (m::kernelAudio::getDeviceName(device) == "")
-                       continue;
-               if (m->text(i) == nullptr)
-                       continue;
-               if (m->text(i) == m::kernelAudio::getDeviceName(device))
-                       return i;
-       }
-
-       return 0;
+       buffersize->deactivate();
+       limitOutput->deactivate();
+       sounddevOut->deactivate();
+       channelsOut->deactivate();
+       samplerate->deactivate();
+       sounddevIn->deactivate();
+       channelsIn->deactivate();
+       recTriggerLevel->deactivate();
+       rsmpQuality->deactivate();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geTabAudio::fetchSoundDevs()
+void geTabAudio::activateAll()
 {
-       if (m::kernelAudio::countDevices() == 0) {
-               sounddevOut->add("-- no devices found --");
-               sounddevOut->value(0);
-               sounddevIn->add("-- no devices found --");
-               sounddevIn->value(0);
-               devInInfo ->deactivate();
-               devOutInfo->deactivate();
-       }
-       else {
-
-               devInInfo ->activate();
-               devOutInfo->activate();
-
-               /* input device may be disabled: now device number -1 is the disabled
-                * one. KernelAudio knows how to handle it. */
-
-               sounddevIn->add("(disabled)");
-
-               for (unsigned i=0; i<m::kernelAudio::countDevices(); i++) {
-
-                       /* escaping '/', very dangerous in FLTK (it creates a submenu) */
-
-                       std::string tmp = m::kernelAudio::getDeviceName(i);
-                       for (unsigned k=0; k<tmp.size(); k++)
-                               if (tmp[k] == '/' || tmp[k] == '|' || tmp[k] == '&' || tmp[k] == '_')
-                                       tmp[k] = '-';
-
-                       /* add to list devices with at least 1 channel available. In this
-                        * way we can filter devices only for input or output, e.g. an input
-                        * devices has 0 output channels. */
-
-                       if (m::kernelAudio::getMaxOutChans(i) > 0)
-                               sounddevOut->add(tmp.c_str());
-
-                       if (m::kernelAudio::getMaxInChans(i) > 0)
-                               sounddevIn->add(tmp.c_str());
-               }
-
-               /* we show the device saved in the configuration file. */
-
-               if (sounddevOut->size() == 0) {
-                       sounddevOut->add("-- no devices found --");
-                       sounddevOut->value(0);
-                       devOutInfo->deactivate();
-               }
-               else {
-                       int outMenuValue = findMenuDevice(sounddevOut, m::conf::conf.soundDeviceOut);
-                       sounddevOut->value(outMenuValue);
-               }
-
-               if (sounddevIn->size() == 0) {
-                       sounddevIn->add("-- no devices found --");
-                       sounddevIn->value(0);
-                       devInInfo->deactivate();
-               }
-               else {
-                       int inMenuValue = findMenuDevice(sounddevIn, m::conf::conf.soundDeviceIn);
-                       sounddevIn->value(inMenuValue);
-               }
+       buffersize->activate();
+       limitOutput->activate();
+       sounddevOut->activate();
+       channelsOut->activate();
+       samplerate->activate();
+       rsmpQuality->activate();
+       if (m_data.inputDevice.index != -1)
+       {
+               sounddevIn->activate();
+               channelsIn->activate();
+               recTriggerLevel->activate();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabAudio::save()
 {
-       std::string text = soundsys->text(soundsys->value());
-
-       if (text == "(none)") {
-               m::conf::conf.soundSystem = G_SYS_API_NONE;
-               return;
-       }
-
-#if defined(__linux__)
-
-       else if (text == "ALSA")
-               m::conf::conf.soundSystem = G_SYS_API_ALSA;
-       else if (text == "Jack")
-               m::conf::conf.soundSystem = G_SYS_API_JACK;
-       else if (text == "PulseAudio")
-               m::conf::conf.soundSystem = G_SYS_API_PULSE;
-
-#elif defined(__FreeBSD__)
-
-       else if (text == "Jack")
-               m::conf::conf.soundSystem = G_SYS_API_JACK;
-       else if (text == "PulseAudio")
-               m::conf::conf.soundSystem = G_SYS_API_PULSE;
-
-#elif defined(_WIN32)
-
-       else if (text == "DirectSound")
-               m::conf::conf.soundSystem = G_SYS_API_DS;
-       else if (text == "ASIO")
-               m::conf::conf.soundSystem = G_SYS_API_ASIO;
-       else if (text == "WASAPI")
-               m::conf::conf.soundSystem = G_SYS_API_WASAPI;
-
-#elif defined(__APPLE__)
-
-       else if (text == "CoreAudio")
-               m::conf::conf.soundSystem = G_SYS_API_CORE;
-
-#endif
-
-       /* use the device name to search into the drop down menu's */
-
-       m::conf::conf.soundDeviceOut  = m::kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value()));
-       m::conf::conf.soundDeviceIn   = m::kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value()));
-       m::conf::conf.channelsOut     = channelsOut->value();
-       m::conf::conf.channelsInCount = channelsIn->getSelectedId() < 1000 ? 1 : 2;
-       m::conf::conf.channelsInStart = channelsIn->getSelectedId() - (m::conf::conf.channelsInCount == 1 ? 1 : 1001);
-       m::conf::conf.limitOutput     = limitOutput->value();
-       m::conf::conf.rsmpQuality     = rsmpQuality->value();
-
-       /* If sounddevOut is disabled because of system change e.g. alsa -> jack, 
-       soundDeviceOut and channelsOut are == -1. Change them! */
-
-       if (m::conf::conf.soundDeviceOut == -1) {
-               m::conf::conf.soundDeviceOut = 0;
-               m::conf::conf.channelsOut    = 0;
-       }
-
-       m::conf::conf.buffersize      = std::atoi(buffersize->text());
-       m::conf::conf.recTriggerLevel = std::atof(recTriggerLevel->value());
-
-       const Fl_Menu_Item* i = nullptr;
-       i = samplerate->mvalue(); // mvalue() returns a pointer to the last menu item that was picked
-       if (i != nullptr)
-               m::conf::conf.samplerate = std::atoi(i->label());
+       c::config::save(m_data);
 }
-}} // giada::v::
+} // namespace giada::v
\ No newline at end of file
index fdc53832589206930f736da2a3c9273199f32a09..a3591937bd40fb05c5e9ec56e370703d0f3ce5a1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_TAB_AUDIO_H
 #define GE_TAB_AUDIO_H
 
-
+#include "glue/config.h"
+#include "gui/elems/basics/choice.h"
 #include <FL/Fl_Group.H>
 
-
 class geCheck;
 class geButton;
 class geInput;
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
-class geChoice;
 class geTabAudio : public Fl_Group
 {
 public:
+       struct geDeviceMenu : public geChoice
+       {
+               geDeviceMenu(int x, int y, int w, int h, const char* l, const std::vector<c::config::AudioDeviceData>&);
+       };
+
+       struct geChannelMenu : public geChoice
+       {
+               geChannelMenu(int x, int y, int w, int h, const char* l, c::config::AudioDeviceData&);
+
+               int getChannelsCount() const;
+               int getChannelsStart() const;
+
+               void rebuild(c::config::AudioDeviceData&);
+
+       private:
+               static constexpr int STEREO_OFFSET = 1000;
+
+               c::config::AudioDeviceData& m_data;
+       };
 
        geTabAudio(int x, int y, int w, int h);
 
        void save();
 
-       geChoice* soundsys;
-       geChoice* buffersize;
-       geChoice* samplerate;
-       geChoice* sounddevOut;
-       geButton* devOutInfo;
-       geChoice* channelsOut;
-       geCheck*  limitOutput;
-       geChoice* sounddevIn;
-       geButton* devInInfo;
-       geChoice* channelsIn;
-       geInput*  recTriggerLevel;
-       geChoice* rsmpQuality;
+       geChoice*      soundsys;
+       geChoice*      buffersize;
+       geChoice*      samplerate;
+       geDeviceMenu*  sounddevOut;
+       geChannelMenu* channelsOut;
+       geCheck*       limitOutput;
+       geDeviceMenu*  sounddevIn;
+       geCheck*       enableIn;
+       geChannelMenu* channelsIn;
+       geInput*       recTriggerLevel;
+       geChoice*      rsmpQuality;
 
 private:
+       void invalidate();
+       void fetch();
+       void deactivateAll();
+       void activateAll();
 
-       static void cb_deactivate_sounddev(Fl_Widget* /*w*/, void* p);
-       static void cb_fetchInChans       (Fl_Widget* /*w*/, void* p);
-       static void cb_fetchOutChans      (Fl_Widget* /*w*/, void* p);
-       static void cb_showInputInfo      (Fl_Widget* /*w*/, void* p);
-       static void cb_showOutputInfo     (Fl_Widget* /*w*/, void* p);
-       void cb_deactivate_sounddev();
-       void cb_fetchInChans();
-       void cb_fetchOutChans();
-       void cb_showInputInfo();
-       void cb_showOutputInfo();
-
-       void fetchSoundDevs();
-       void fetchInChans(int menuItem);
-       void fetchOutChans();
-       int  findMenuDevice(geChoice* m, int device);
-
-       int soundsysInitValue;
-};
-}} // giada::v::
+       c::config::AudioData m_data;
 
+       int m_initialApi;
+};
+} // namespace giada::v
 
 #endif
index c14437cdf762f39eeae3d05d3c6cbb8b3a0a6d44..ddcced24692cf6e81a325bbce95d939cf119b738 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl_Pack.H>
-#include "core/const.h"
+#include "tabBehaviors.h"
 #include "core/conf.h"
+#include "core/const.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/check.h"
-#include "tabBehaviors.h"
-
+#include <FL/Fl_Pack.H>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
-geTabBehaviors::geTabBehaviors(int X, int Y, int W, int H) 
-: Fl_Group                    (X, Y, W, H)
-, m_container                 (X, Y + G_GUI_OUTER_MARGIN, Direction::VERTICAL, G_GUI_OUTER_MARGIN)
-, m_chansStopOnSeqHalt        (0, 0, 280, 30, "Dynamic channels stop immediately when the sequencer\nis halted")
-, m_treatRecsAsLoops          (0, 0, 280, 20, "Treat one shot channels with actions as loops")
-, m_inputMonitorDefaultOn     (0, 0, 280, 20, "New sample channels have input monitor on by default")
+geTabBehaviors::geTabBehaviors(int X, int Y, int W, int H)
+: Fl_Group(X, Y, W, H)
+, m_container(X, Y + G_GUI_OUTER_MARGIN, Direction::VERTICAL, G_GUI_OUTER_MARGIN)
+, m_chansStopOnSeqHalt(0, 0, 280, 30, "Dynamic channels stop immediately when the sequencer\nis halted")
+, m_treatRecsAsLoops(0, 0, 280, 20, "Treat one shot channels with actions as loops")
+, m_inputMonitorDefaultOn(0, 0, 280, 20, "New sample channels have input monitor on by default")
 , m_overdubProtectionDefaultOn(0, 0, 280, 30, "New sample channels have overdub protection on\nby default")
 {
        end();
@@ -63,15 +62,14 @@ geTabBehaviors::geTabBehaviors(int X, int Y, int W, int H)
        m_overdubProtectionDefaultOn.value(m::conf::conf.overdubProtectionDefaultOn);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabBehaviors::save()
 {
-       m::conf::conf.chansStopOnSeqHalt = m_chansStopOnSeqHalt.value();
-       m::conf::conf.treatRecsAsLoops = m_treatRecsAsLoops.value();
-       m::conf::conf.inputMonitorDefaultOn = m_inputMonitorDefaultOn.value();
+       m::conf::conf.chansStopOnSeqHalt         = m_chansStopOnSeqHalt.value();
+       m::conf::conf.treatRecsAsLoops           = m_treatRecsAsLoops.value();
+       m::conf::conf.inputMonitorDefaultOn      = m_inputMonitorDefaultOn.value();
        m::conf::conf.overdubProtectionDefaultOn = m_overdubProtectionDefaultOn.value();
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 84f73cf143980c507dfd088adb63093e8508ea0c..22785aecb2608a6fc3620fa43384a838d26f5ab1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_TAB_BEHAVIORS_H
 #define GE_TAB_BEHAVIORS_H
 
-
-#include <FL/Fl_Group.H>
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/check.h"
+#include "gui/elems/basics/pack.h"
+#include <FL/Fl_Group.H>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geTabBehaviors : public Fl_Group
 {
 public:
-
        geTabBehaviors(int x, int y, int w, int h);
 
        void save();
 
-private:
-
+  private:
        gePack  m_container;
        geCheck m_chansStopOnSeqHalt;
        geCheck m_treatRecsAsLoops;
        geCheck m_inputMonitorDefaultOn;
        geCheck m_overdubProtectionDefaultOn;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index ff393e558741dc02a012fc812352be273be5dbab..2fefe2d4db7fde06861ade25b72c3e00bac260c1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <RtMidi.h>
-#include <string>
-#include "core/const.h"
+#include "tabMidi.h"
 #include "core/conf.h"
-#include "core/midiMapConf.h"
+#include "core/const.h"
 #include "core/kernelMidi.h"
-#include "utils/gui.h"
+#include "core/midiMapConf.h"
 #include "gui/elems/basics/box.h"
-#include "gui/elems/basics/choice.h"
 #include "gui/elems/basics/check.h"
-#include "tabMidi.h"
-
+#include "gui/elems/basics/choice.h"
+#include "utils/gui.h"
+#include <RtMidi.h>
+#include <string>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geTabMidi::geTabMidi(int X, int Y, int W, int H)
 : Fl_Group(X, Y, W, H, "MIDI")
 {
        begin();
-       system  = new geChoice(x()+w()-250, y()+9, 250, 20, "System");
-       portOut = new geChoice(x()+w()-250, system->y()+system->h()+8, 250, 20, "Output port");
-       portIn  = new geChoice(x()+w()-250, portOut->y()+portOut->h()+8, 250, 20, "Input port");
-       midiMap = new geChoice(x()+w()-250, portIn->y()+portIn->h()+8, 250, 20, "Output Midi Map");
-       sync    = new geChoice(x()+w()-250, midiMap->y()+midiMap->h()+8, 250, 20, "Sync");
-       new geBox(x(), sync->y()+sync->h()+8, w(), h()-150, "Restart Giada for the changes to take effect.");
+       system  = new geChoice(x() + w() - 250, y() + 9, 250, 20, "System");
+       portOut = new geChoice(x() + w() - 250, system->y() + system->h() + 8, 250, 20, "Output port");
+       portIn  = new geChoice(x() + w() - 250, portOut->y() + portOut->h() + 8, 250, 20, "Input port");
+       midiMap = new geChoice(x() + w() - 250, portIn->y() + portIn->h() + 8, 250, 20, "Output Midi Map");
+       sync    = new geChoice(x() + w() - 250, midiMap->y() + midiMap->h() + 8, 250, 20, "Sync");
+       new geBox(x(), sync->y() + sync->h() + 8, w(), h() - 150, "Restart Giada for the changes to take effect.");
        end();
 
        labelsize(G_GUI_FONT_SIZE_BASE);
@@ -66,7 +65,7 @@ geTabMidi::geTabMidi(int X, int Y, int W, int H)
        sync->add("(disabled)");
        sync->add("MIDI Clock (master)");
        sync->add("MTC (master)");
-       if      (m::conf::conf.midiSync == MIDI_SYNC_NONE)
+       if (m::conf::conf.midiSync == MIDI_SYNC_NONE)
                sync->value(0);
        else if (m::conf::conf.midiSync == MIDI_SYNC_CLOCK_M)
                sync->value(1);
@@ -76,64 +75,65 @@ geTabMidi::geTabMidi(int X, int Y, int W, int H)
        systemInitValue = system->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::fetchOutPorts()
 {
-       if (m::kernelMidi::countOutPorts() == 0) {
+       if (m::kernelMidi::countOutPorts() == 0)
+       {
                portOut->add("-- no ports found --");
                portOut->value(0);
                portOut->deactivate();
        }
-       else {
+       else
+       {
 
                portOut->add("(disabled)");
 
-               for (unsigned i=0; i<m::kernelMidi::countOutPorts(); i++)
+               for (unsigned i = 0; i < m::kernelMidi::countOutPorts(); i++)
                        portOut->add(u::gui::removeFltkChars(m::kernelMidi::getOutPortName(i)).c_str());
 
-               portOut->value(m::conf::conf.midiPortOut+1);    // +1 because midiPortOut=-1 is '(disabled)'
+               portOut->value(m::conf::conf.midiPortOut + 1); // +1 because midiPortOut=-1 is '(disabled)'
        }
 }
 
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::fetchInPorts()
 {
-       if (m::kernelMidi::countInPorts() == 0) {
+       if (m::kernelMidi::countInPorts() == 0)
+       {
                portIn->add("-- no ports found --");
                portIn->value(0);
                portIn->deactivate();
        }
-       else {
+       else
+       {
 
                portIn->add("(disabled)");
 
-               for (unsigned i=0; i<m::kernelMidi::countInPorts(); i++)
+               for (unsigned i = 0; i < m::kernelMidi::countInPorts(); i++)
                        portIn->add(u::gui::removeFltkChars(m::kernelMidi::getInPortName(i)).c_str());
 
-               portIn->value(m::conf::conf.midiPortIn+1);    // +1 because midiPortIn=-1 is '(disabled)'
+               portIn->value(m::conf::conf.midiPortIn + 1); // +1 because midiPortIn=-1 is '(disabled)'
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::fetchMidiMaps()
 {
-       if (m::midimap::maps.size() == 0) {
+       if (m::midimap::maps.size() == 0)
+       {
                midiMap->add("(no MIDI maps available)");
                midiMap->value(0);
                midiMap->deactivate();
                return;
        }
 
-       for (unsigned i=0; i<m::midimap::maps.size(); i++) {
-               const char *imap = m::midimap::maps.at(i).c_str();
+       for (unsigned i = 0; i < m::midimap::maps.size(); i++)
+       {
+               const char* imap = m::midimap::maps.at(i).c_str();
                midiMap->add(imap);
                if (m::conf::conf.midiMapPath == imap)
                        midiMap->value(i);
@@ -145,15 +145,13 @@ void geTabMidi::fetchMidiMaps()
                midiMap->value(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::save()
 {
        std::string text = system->text(system->value());
 
-       if      (text == "ALSA")
+       if (text == "ALSA")
                m::conf::conf.midiSystem = RtMidi::LINUX_ALSA;
        else if (text == "Jack")
                m::conf::conf.midiSystem = RtMidi::UNIX_JACK;
@@ -162,11 +160,11 @@ void geTabMidi::save()
        else if (text == "OSX Core MIDI")
                m::conf::conf.midiSystem = RtMidi::MACOSX_CORE;
 
-       m::conf::conf.midiPortOut = portOut->value()-1;   // -1 because midiPortOut=-1 is '(disabled)'
-       m::conf::conf.midiPortIn  = portIn->value()-1;    // -1 because midiPortIn=-1 is '(disabled)'
+       m::conf::conf.midiPortOut = portOut->value() - 1; // -1 because midiPortOut=-1 is '(disabled)'
+       m::conf::conf.midiPortIn  = portIn->value() - 1;  // -1 because midiPortIn=-1 is '(disabled)'
        m::conf::conf.midiMapPath = m::midimap::maps.size() == 0 ? "" : midiMap->text(midiMap->value());
 
-       if      (sync->value() == 0)
+       if (sync->value() == 0)
                m::conf::conf.midiSync = MIDI_SYNC_NONE;
        else if (sync->value() == 1)
                m::conf::conf.midiSync = MIDI_SYNC_CLOCK_M;
@@ -174,10 +172,8 @@ void geTabMidi::save()
                m::conf::conf.midiSync = MIDI_SYNC_MTC_M;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::fetchSystems()
 {
 #if defined(__linux__)
@@ -197,38 +193,46 @@ void geTabMidi::fetchSystems()
        if (m::kernelMidi::hasAPI(RtMidi::WINDOWS_MM))
                system->add("Multimedia MIDI");
 
-#elif defined (__APPLE__)
+#elif defined(__APPLE__)
 
        system->add("OSX Core MIDI");
 
 #endif
 
-       switch (m::conf::conf.midiSystem) {
-               case RtMidi::LINUX_ALSA:  system->showItem("ALSA"); break;
-               case RtMidi::UNIX_JACK:   system->showItem("Jack"); break;
-               case RtMidi::WINDOWS_MM:  system->showItem("Multimedia MIDI"); break;
-               case RtMidi::MACOSX_CORE: system->showItem("OSX Core MIDI"); break;
-               default: system->value(0); break;
+       switch (m::conf::conf.midiSystem)
+       {
+       case RtMidi::LINUX_ALSA:
+               system->showItem("ALSA");
+               break;
+       case RtMidi::UNIX_JACK:
+               system->showItem("Jack");
+               break;
+       case RtMidi::WINDOWS_MM:
+               system->showItem("Multimedia MIDI");
+               break;
+       case RtMidi::MACOSX_CORE:
+               system->showItem("OSX Core MIDI");
+               break;
+       default:
+               system->value(0);
+               break;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::cb_changeSystem(Fl_Widget* /*w*/, void* p) { ((geTabMidi*)p)->cb_changeSystem(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabMidi::cb_changeSystem()
 {
        /* if the user changes MIDI device (eg ALSA->JACK) device menu deactivates.
         * If it returns to the original system, we re-fill the list by
         * querying m::kernelMidi. */
 
-       if (systemInitValue == system->value()) {
+       if (systemInitValue == system->value())
+       {
                portOut->clear();
                fetchOutPorts();
                portOut->activate();
@@ -237,7 +241,8 @@ void geTabMidi::cb_changeSystem()
                portIn->activate();
                sync->activate();
        }
-       else {
+       else
+       {
                portOut->deactivate();
                portOut->clear();
                portOut->add("-- restart to fetch device(s) --");
@@ -249,4 +254,5 @@ void geTabMidi::cb_changeSystem()
                sync->deactivate();
        }
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace v
+} // namespace giada
\ No newline at end of file
index 3b1cccfc49418c7754770fa20c9b25db0595ba6e..658bc5ac1a7c6729f4d33ab0b3b0d1ff4c9b4b2d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_TAB_MIDI_H
 #define GE_TAB_MIDI_H
 
-
 #include <FL/Fl_Group.H>
 
-
 class geCheck;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geChoice;
 class geTabMidi : public Fl_Group
 {
 public:
-
        geTabMidi(int x, int y, int w, int h);
 
        void save();
@@ -53,19 +49,18 @@ public:
        geChoice* midiMap;
        geChoice* sync;
 
-private:
-
+  private:
        void fetchSystems();
        void fetchOutPorts();
        void fetchInPorts();
        void fetchMidiMaps();
 
        static void cb_changeSystem(Fl_Widget* /*w*/, void* p);
-       void cb_changeSystem();
+       void        cb_changeSystem();
 
        int systemInitValue;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index b1d2d5d4903a5c566dea15bf100ba431269f4554..b6917fa3f34787889181f260263cb63d98c4f047 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/const.h"
-#include "core/conf.h"
-#include "gui/elems/basics/choice.h"
 #include "tabMisc.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include <FL/Fl_Tooltip.H>
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 geTabMisc::geTabMisc(int X, int Y, int W, int H)
-: Fl_Group(X, Y, W, H, "Misc")
+: geGroup(X, Y)
+, m_debugMsg(W - 230, 9, 230, 20, "Debug messages")
+, m_tooltips(W - 230, 37, 230, 20, "Tooltips")
 {
-       begin();
-       debugMsg = new geChoice(x()+w()-230, y()+9, 230, 20, "Debug messages");
-       end();
+       add(&m_debugMsg);
+       add(&m_tooltips);
 
-       debugMsg->add("(disabled)");
-       debugMsg->add("To standard output");
-       debugMsg->add("To file");
+       m_debugMsg.add("Disabled");
+       m_debugMsg.add("To standard output");
+       m_debugMsg.add("To file");
 
-       labelsize(G_GUI_FONT_SIZE_BASE);
-       selection_color(G_COLOR_GREY_4);
+       m_tooltips.add("Disabled");
+       m_tooltips.add("Enabled");
 
-       switch (m::conf::conf.logMode) {
-               case LOG_MODE_MUTE:
-                       debugMsg->value(0);
-                       break;
-               case LOG_MODE_STDOUT:
-                       debugMsg->value(1);
-                       break;
-               case LOG_MODE_FILE:
-                       debugMsg->value(2);
-                       break;
+       switch (m::conf::conf.logMode)
+       {
+       case LOG_MODE_MUTE:
+               m_debugMsg.value(0);
+               break;
+       case LOG_MODE_STDOUT:
+               m_debugMsg.value(1);
+               break;
+       case LOG_MODE_FILE:
+               m_debugMsg.value(2);
+               break;
        }
-}
 
+       m_tooltips.value(m::conf::conf.showTooltips);
 
-/* -------------------------------------------------------------------------- */
+       copy_label("Misc");
+       labelsize(G_GUI_FONT_SIZE_BASE);
+       selection_color(G_COLOR_GREY_4);
+}
 
+/* -------------------------------------------------------------------------- */
 
 void geTabMisc::save()
 {
-       switch(debugMsg->value()) {
-               case 0:
-                       m::conf::conf.logMode = LOG_MODE_MUTE;
-                       break;
-               case 1:
-                       m::conf::conf.logMode = LOG_MODE_STDOUT;
-                       break;
-               case 2:
-                       m::conf::conf.logMode = LOG_MODE_FILE;
-                       break;
+       switch (m_debugMsg.value())
+       {
+       case 0:
+               m::conf::conf.logMode = LOG_MODE_MUTE;
+               break;
+       case 1:
+               m::conf::conf.logMode = LOG_MODE_STDOUT;
+               break;
+       case 2:
+               m::conf::conf.logMode = LOG_MODE_FILE;
+               break;
        }
+
+       m::conf::conf.showTooltips = m_tooltips.value();
+       Fl_Tooltip::enable(m_tooltips.value());
 }
-}} // giada::v::
\ No newline at end of file
+} // namespace giada::v
\ No newline at end of file
index 4c119ee79ba9afdd255fa50ffb6f591c1d23a504..9f0058c1c747339e0db0e850e321b046d9c7b3c0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_TAB_MISC_H
 #define GE_TAB_MISC_H
 
+#include "gui/elems/basics/choice.h"
+#include "gui/elems/basics/group.h"
 
-#include <FL/Fl_Group.H>
-
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 class geChoice;
-class geTabMisc : public Fl_Group
+class geTabMisc : public geGroup
 {
 public:
-
        geTabMisc(int x, int y, int w, int h);
 
        void save();
 
-       geChoice* debugMsg;
+  private:
+       geChoice m_debugMsg;
+       geChoice m_tooltips;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 453fbe6d55d723a8b1e98ebc7eb746b3e9f62196..b2c4fa156e3bb1f23404c6ed59f4dd8296f906ea 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <functional>
-#include <FL/Fl.H>
-#include "core/const.h"
+#include "tabPlugins.h"
 #include "core/conf.h"
+#include "core/const.h"
 #include "core/graphics.h"
 #include "core/plugins/pluginManager.h"
 #include "glue/plugin.h"
-#include "utils/string.h"
-#include "utils/fs.h"
-#include "utils/gui.h"
-#include "gui/dialogs/window.h"
-#include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/browser/browserDir.h"
+#include "gui/dialogs/mainWindow.h"
+#include "gui/dialogs/window.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/check.h"
 #include "gui/elems/basics/input.h"
-#include "gui/elems/basics/button.h"
-#include "tabPlugins.h"
-
+#include "utils/fs.h"
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
+#include <functional>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geTabPlugins::geTabPlugins(int X, int Y, int W, int H)
-       : Fl_Group(X, Y, W, H, "Plugins")
+: Fl_Group(X, Y, W, H, "Plugins")
 {
-       m_browse     = new geButton(x()+w()-G_GUI_UNIT, y()+9, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
-       m_folderPath = new geInput(m_browse->x()-258, y()+9, 250, G_GUI_UNIT);
-       m_scanButton = new geButton(x()+w()-150, m_folderPath->y()+m_folderPath->h()+8, 150, G_GUI_UNIT);
-       m_info       = new geBox(x(), m_scanButton->y()+m_scanButton->h()+8, w(), 240);
+       m_browse     = new geButton(x() + w() - G_GUI_UNIT, y() + 9, G_GUI_UNIT, G_GUI_UNIT, "", zoomInOff_xpm, zoomInOn_xpm);
+       m_folderPath = new geInput(m_browse->x() - 258, y() + 9, 250, G_GUI_UNIT);
+       m_scanButton = new geButton(x() + w() - 150, m_folderPath->y() + m_folderPath->h() + 8, 150, G_GUI_UNIT);
+       m_info       = new geBox(x(), m_scanButton->y() + m_scanButton->h() + 8, w(), 240);
 
        end();
 
@@ -73,51 +70,42 @@ geTabPlugins::geTabPlugins(int X, int Y, int W, int H)
        m_folderPath->value(m::conf::conf.pluginPath.c_str());
        m_folderPath->label("Plugins folder");
 
-       m_browse->callback(cb_browse, (void*) this);
+       m_browse->callback(cb_browse, (void*)this);
 
-       m_scanButton->callback(cb_scan, (void*) this);
+       m_scanButton->callback(cb_scan, (void*)this);
 
        refreshCount();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabPlugins::refreshCount()
 {
        std::string scanLabel = "Scan (" + std::to_string(m::pluginManager::countAvailablePlugins()) + " found)";
        m_scanButton->copy_label(scanLabel.c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabPlugins::cb_scan(Fl_Widget* /*w*/, void* p) { ((geTabPlugins*)p)->cb_scan(); }
 void geTabPlugins::cb_browse(Fl_Widget* /*w*/, void* p) { ((geTabPlugins*)p)->cb_browse(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabPlugins::cb_browse()
 {
-       v::gdBrowserDir* browser = new v::gdBrowserDir("Add plug-ins directory", 
-               m::conf::conf.patchPath, c::plugin::setPluginPathCb);
+       v::gdBrowserDir* browser = new v::gdBrowserDir("Add plug-ins directory",
+           m::conf::conf.patchPath, c::plugin::setPluginPathCb);
 
        static_cast<v::gdWindow*>(top_window())->addSubWindow(browser);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabPlugins::cb_scan()
 {
-       std::function<void(float)> callback = [this] (float progress) 
-       {
-               std::string l = "Scan in progress (" + std::to_string((int)(progress*100)) + "%). Please wait...";
+       std::function<void(float)> callback = [this](float progress) {
+               std::string l = "Scan in progress (" + std::to_string((int)(progress * 100)) + "%). Please wait...";
                m_info->label(l.c_str());
                Fl::wait();
        };
@@ -129,25 +117,21 @@ void geTabPlugins::cb_scan()
        refreshCount();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabPlugins::save()
 {
        m::conf::conf.pluginPath = m_folderPath->value();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geTabPlugins::refreshVstPath()
 {
        m_folderPath->value(m::conf::conf.pluginPath.c_str());
        m_folderPath->redraw();
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // WITH_VST
index 83318de2e9aaabafb0cfad7bb90ca17eff2b3ce1..f1af634e6ee29c4e0285dc15b6621d58ab580604 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_TAB_PLUGINS_H
 #define GE_TAB_PLUGINS_H
 
-
 #ifdef WITH_VST
 
-
 #include <FL/Fl_Group.H>
 
-
 class geInput;
 class geButton;
 class geBox;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geTabPlugins : public Fl_Group
 {
 public:
-
        geTabPlugins(int x, int y, int w, int h);
 
        void save();
        void refreshVstPath();
 
-private:
-
+  private:
        static void cb_scan(Fl_Widget* /*w*/, void* p);
        static void cb_browse(Fl_Widget* /*w*/, void* p);
-       void cb_scan();
-       void cb_browse();
+       void        cb_scan();
+       void        cb_browse();
 
        void refreshCount();
 
@@ -66,10 +60,9 @@ private:
        geButton* m_scanButton;
        geBox*    m_info;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // WITH_VST
 
-
 #endif
diff --git a/src/gui/elems/mainWindow/beatMeter.cpp b/src/gui/elems/mainWindow/beatMeter.cpp
deleted file mode 100644 (file)
index a22bee9..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * beatMeter
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#include <FL/fl_draw.H>
-#include "core/const.h"
-#include "core/recManager.h"
-#include "core/mixer.h"
-#include "core/clock.h"
-#include "utils/gui.h"
-#include "beatMeter.h"
-
-
-namespace giada {
-namespace v
-{
-geBeatMeter::geBeatMeter(int x, int y, int w, int h)
-: Fl_Box(x, y, w, h)
-{
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-Fl_Color geBeatMeter::getCursorColor()
-{
-       if (m::clock::getStatus() == ClockStatus::WAITING && u::gui::shouldBlink())
-               return FL_BACKGROUND_COLOR;
-       return G_COLOR_LIGHT_1;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geBeatMeter::refresh()
-{
-       redraw();
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void geBeatMeter::draw()
-{
-       using namespace giada::m;
-
-       int cursorW = w() / G_MAX_BEATS;
-       int greyX   = clock::getBeats() * cursorW;
-
-       /* Border and background. */
-       
-       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);
-       fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR);
-
-       /* Cursor. */
-
-       fl_rectf(x() + (clock::getCurrentBeat() * cursorW) + 3, y() + 3, cursorW - 5, h() - 6, getCursorColor());       
-
-       /* Beat cells. */
-
-       fl_color(G_COLOR_GREY_4);
-       for (int i=1; i<=clock::getBeats(); i++)
-               fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2);
-
-       /* Bar line. */
-
-       fl_color(G_COLOR_LIGHT_1);
-       int delta = clock::getBeats() / clock::getBars();
-       for (int i=1; i<clock::getBars(); i++)
-               fl_line(x()+cursorW*(i*delta), y()+1, x()+cursorW*(i*delta), y()+h()-2);
-
-       /* Unused grey area. */
-
-       fl_rectf(x()+greyX+1, y()+1, w()-greyX-1,  h()-2, G_COLOR_GREY_4);
-}
-}} // giada::v::
diff --git a/src/gui/elems/mainWindow/beatMeter.h b/src/gui/elems/mainWindow/beatMeter.h
deleted file mode 100644 (file)
index d157ddf..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * Giada - Your Hardcore Loopmachine
- *
- * beatMeter
- *
- * -----------------------------------------------------------------------------
- *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
- *
- * This file is part of Giada - Your Hardcore Loopmachine.
- *
- * Giada - Your Hardcore Loopmachine is free software: you can
- * redistribute it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * Giada - Your Hardcore Loopmachine is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Giada - Your Hardcore Loopmachine. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * -------------------------------------------------------------------------- */
-
-
-#ifndef GE_BEAT_METER_H
-#define GE_BEAT_METER_H
-
-
-#include <FL/Fl_Box.H>
-
-
-namespace giada {
-namespace v
-{
-class geBeatMeter : public Fl_Box
-{
-public:
-
-       geBeatMeter(int x, int y, int w, int h);
-       
-       void draw() override;
-
-       void refresh();
-
-private:
-
-    Fl_Color getCursorColor();
-};
-}} // giada::v::
-
-
-#endif
index 4247866c23f7a122027d8d256d8cfdfc495673db..9d80c4b27753745af7420a1debd02b68d9b070ea 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include <FL/fl_draw.H>
-#include "core/model/model.h"
+#include "glue/channel.h"
+#include "channel.h"
+#include "channelButton.h"
+#include "channelStatus.h"
+#include "column.h"
 #include "core/const.h"
 #include "core/graphics.h"
+#include "core/model/model.h"
 #include "core/plugins/pluginHost.h"
-#include "utils/gui.h"
-#include "glue/channel.h"
 #include "glue/events.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/pluginList.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/statusButton.h"
-#include "column.h"
-#include "channelStatus.h"
-#include "channelButton.h"
-#include "channel.h"
-
+#include "utils/gui.h"
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 geChannel::geChannel(int X, int Y, int W, int H, c::channel::Data d)
-: Fl_Group (X, Y, W, H)
+: Fl_Group(X, Y, W, H)
 , m_channel(d)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::draw()
 {
        const int ny = y() + (h() / 2) - (G_GUI_UNIT / 2);
@@ -76,29 +70,28 @@ void geChannel::draw()
 
        fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_1_5);
 
-       Fl_Group::draw();       
+       Fl_Group::draw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::cb_arm(Fl_Widget* /*w*/, void* p) { ((geChannel*)p)->cb_arm(); }
 void geChannel::cb_mute(Fl_Widget* /*w*/, void* p) { ((geChannel*)p)->cb_mute(); }
 void geChannel::cb_solo(Fl_Widget* /*w*/, void* p) { ((geChannel*)p)->cb_solo(); }
 void geChannel::cb_changeVol(Fl_Widget* /*w*/, void* p) { ((geChannel*)p)->cb_changeVol(); }
 #ifdef WITH_VST
-void geChannel::cb_openFxWindow(Fl_Widget* /*w*/, void* p) { ((geChannel*)p)->cb_openFxWindow(); }
+void geChannel::cb_openFxWindow(Fl_Widget* /*w*/, void* p)
+{
+       ((geChannel*)p)->cb_openFxWindow();
+}
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::refresh()
 {
-       ChannelStatus playStatus = m_channel.a_getPlayStatus(); 
-       ChannelStatus recStatus  = m_channel.a_getRecStatus(); 
+       ChannelStatus playStatus = m_channel.getPlayStatus();
+       ChannelStatus recStatus  = m_channel.getRecStatus();
 
        if (mainButton->visible())
                mainButton->refresh();
@@ -107,50 +100,40 @@ void geChannel::refresh()
                blink();
 
        playButton->setStatus(playStatus == ChannelStatus::PLAY || playStatus == ChannelStatus::ENDING);
-       mute->setStatus(m_channel.a_getMute());
-       solo->setStatus(m_channel.a_getSolo());
+       mute->setStatus(m_channel.getMute());
+       solo->setStatus(m_channel.getSolo());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::cb_arm()
 {
        c::events::toggleArmChannel(m_channel.id, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::cb_mute()
 {
        c::events::toggleMuteChannel(m_channel.id, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::cb_solo()
 {
        c::events::toggleSoloChannel(m_channel.id, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::cb_changeVol()
 {
        c::events::setChannelVolume(m_channel.id, vol->value(), Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 void geChannel::cb_openFxWindow()
 {
@@ -158,20 +141,15 @@ void geChannel::cb_openFxWindow()
 }
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
-
 int geChannel::getColumnId()
 {
        return static_cast<geColumn*>(parent())->id;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::blink()
 {
        if (u::gui::shouldBlink())
@@ -180,31 +158,32 @@ void geChannel::blink()
                mainButton->setDefaultMode();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannel::packWidgets()
 {
        /* Count visible widgets and resize mainButton according to how many widgets
        are visible. */
 
        int visibles = 0;
-       for (int i = 0; i < children(); i++) {
-               child(i)->size(MIN_ELEM_W, child(i)->h());  // also normalize widths
+       for (int i = 0; i < children(); i++)
+       {
+               child(i)->size(MIN_ELEM_W, child(i)->h()); // also normalize widths
                if (child(i)->visible())
                        visibles++;
        }
-       mainButton->size(w() - ((visibles - 1) * (MIN_ELEM_W + G_GUI_INNER_MARGIN)),   // -1: exclude itself
-               mainButton->h());
+       mainButton->size(w() - ((visibles - 1) * (MIN_ELEM_W + G_GUI_INNER_MARGIN)), // -1: exclude itself
+           mainButton->h());
 
        /* Reposition everything else */
 
-       for (int i = 1, p = 0; i < children(); i++) {
+       for (int i = 1, p = 0; i < children(); i++)
+       {
                if (!child(i)->visible())
                        continue;
                for (int k = i - 1; k >= 0; k--) // Get the first visible item prior to i
-                       if (child(k)->visible()) {
+                       if (child(k)->visible())
+                       {
                                p = k;
                                break;
                        }
@@ -214,22 +193,22 @@ void geChannel::packWidgets()
        init_sizes(); // Resets the internal array of widget sizes and positions
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geChannel::handleKey(int e)
 {
-       if (Fl::event_key() != m_channel.key) 
+       if (Fl::event_key() != m_channel.key)
                return false;
 
-       if (e == FL_KEYDOWN && !playButton->value()) {  // Key not already pressed
-               playButton->take_focus();                   // Move focus to this playButton
+       if (e == FL_KEYDOWN && !playButton->value())
+       {                             // Key not already pressed
+               playButton->take_focus(); // Move focus to this playButton
                playButton->value(1);
                return true;
        }
 
-       if (e == FL_KEYUP) {
+       if (e == FL_KEYUP)
+       {
                playButton->value(0);
                return true;
        }
@@ -237,12 +216,10 @@ bool geChannel::handleKey(int e)
        return false;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 const c::channel::Data& geChannel::getData() const
 {
        return m_channel;
 }
-}} // giada::v::
+} // namespace giada::v
index 6b14e4c5e8d29f4cb14d4464672de063673d5c22..e3d53024c6dfb976942fb41d82b414b5da77672f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_CHANNEL_H
 #define GE_CHANNEL_H
 
-
-#include <FL/Fl_Group.H>
-#include "glue/channel.h"
 #include "core/types.h"
+#include "glue/channel.h"
+#include <FL/Fl_Group.H>
 
-
-class geChannelStatus;
 class geButton;
 class geDial;
-class geStatusButton;
-
 
-namespace giada {
-namespace v
+namespace giada::v
 {
+class geChannelStatus;
+class geStatusButton;
 class geChannelButton;
 class geChannel : public Fl_Group
 {
 public:
-
        geChannel(int x, int y, int w, int h, c::channel::Data d);
 
        void draw() override;
@@ -72,7 +66,7 @@ public:
        Returns a reference to the internal data. Read-only. */
 
        const c::channel::Data& getData() const;
+
        geStatusButton*  playButton;
        geButton*        arm;
        geChannelStatus* status;
@@ -81,11 +75,10 @@ public:
        geStatusButton*  solo;
        geDial*          vol;
 #ifdef WITH_VST
-       geStatusButton*  fx;
+       geStatusButton* fx;
 #endif
 
 protected:
-
        /* Define some breakpoints for dynamic resize. BREAK_DELTA: base amount of
        pixels to shrink sampleButton. */
 
@@ -132,7 +125,6 @@ protected:
 
        c::channel::Data m_channel;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index c8e7f255ffa70f2db76baa20e8bc2094659bbda9..ed8dd566979f105c601a920ac48bdea1d5aabb87 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
+#include "channelButton.h"
 #include "core/channels/channel.h"
-#include "core/model/model.h"
 #include "core/const.h"
+#include "core/model/model.h"
 #include "core/recorder.h"
 #include "glue/channel.h"
 #include "utils/string.h"
-#include "channelButton.h"
-
+#include <FL/fl_draw.H>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geChannelButton::geChannelButton(int x, int y, int w, int h, const c::channel::Data& d)
-: geButton (x, y, w, h)
+: geButton(x, y, w, h)
 , m_channel(d)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::refresh()
 {
-       switch (m_channel.a_getPlayStatus()) {
-               case ChannelStatus::OFF:
-               case ChannelStatus::EMPTY:
-                       setDefaultMode(); break;
-               case ChannelStatus::PLAY:
-                       setPlayMode(); break;
-               case ChannelStatus::ENDING:
-                       setEndingMode(); break;
-               default: break;
-       }       
-       switch (m_channel.a_getRecStatus()) {
-               case ChannelStatus::ENDING:
-                       setEndingMode(); break;
-               default: break;
+       switch (m_channel.getPlayStatus())
+       {
+       case ChannelStatus::OFF:
+       case ChannelStatus::EMPTY:
+               setDefaultMode();
+               break;
+       case ChannelStatus::PLAY:
+               setPlayMode();
+               break;
+       case ChannelStatus::ENDING:
+               setEndingMode();
+               break;
+       default:
+               break;
+       }
+       switch (m_channel.getRecStatus())
+       {
+       case ChannelStatus::ENDING:
+               setEndingMode();
+               break;
+       default:
+               break;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::draw()
 {
        geButton::draw();
@@ -80,7 +83,7 @@ void geChannelButton::draw()
 
        /* draw background */
 
-       fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0);
+       fl_rectf(x() + 1, y() + 1, 18, h() - 2, bgColor0);
 
        /* draw m_key */
 
@@ -89,29 +92,23 @@ void geChannelButton::draw()
        fl_draw(std::string(1, static_cast<wchar_t>(m_channel.key)).c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::setInputRecordMode()
 {
        bgColor0 = G_COLOR_RED;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::setActionRecordMode()
 {
        bgColor0 = G_COLOR_BLUE;
        txtColor = G_COLOR_LIGHT_2;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::setDefaultMode(const char* l)
 {
        bgColor0 = G_COLOR_GREY_2;
@@ -121,10 +118,8 @@ void geChannelButton::setDefaultMode(const char* l)
                label(l);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::setPlayMode()
 {
        bgColor0 = G_COLOR_LIGHT_1;
@@ -132,12 +127,11 @@ void geChannelButton::setPlayMode()
        txtColor = G_COLOR_GREY_1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelButton::setEndingMode()
 {
        bgColor0 = G_COLOR_GREY_4;
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index a648d4ed8449735caa736601c4ec7090426d5440..bfc8c389c72c06fa0e749144e678cec2d8cb9b3d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_CHANNEL_BUTTON_H
 #define GE_CHANNEL_BUTTON_H
 
-
 #include "gui/elems/basics/button.h"
 
-
-namespace giada {
-namespace c {
+namespace giada
+{
+namespace c
+{
 namespace channel
 {
 struct Data;
-}}
+}
+} // namespace c
 namespace v
 {
 class geChannelButton : public geButton
 {
 public:
-
        geChannelButton(int x, int y, int w, int h, const c::channel::Data& d);
 
        virtual void refresh();
 
        void draw() override;
-  
+
        void setPlayMode();
        void setEndingMode();
-       void setDefaultMode(const char* l=0);
+       void setDefaultMode(const char* l = 0);
        void setInputRecordMode();
        void setActionRecordMode();
 
-protected:
-
-    const c::channel::Data& m_channel;
+  protected:
+       const c::channel::Data& m_channel;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 4422e4fc26416577d00b63bf46f5d01f190cf4b4..b0a7351608efe2e3f771468e3c7d424614d95ad4 100644 (file)
@@ -1,4 +1,4 @@
- /* -----------------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
  *
  * Giada - Your Hardcore Loopmachine
  *
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/fl_draw.H>
-#include "utils/gui.h"
+#include "channelMode.h"
 #include "core/channels/channel.h"
 #include "core/channels/samplePlayer.h"
-#include "core/model/model.h"
-#include "core/graphics.h"
 #include "core/const.h"
+#include "core/graphics.h"
+#include "core/model/model.h"
 #include "glue/channel.h"
 #include "gui/elems/basics/boxtypes.h"
-#include "channelMode.h"
-
+#include "utils/gui.h"
+#include <FL/fl_draw.H>
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geChannelMode::geChannelMode(int x, int y, int w, int h, c::channel::Data& d)
-: Fl_Menu_Button(x, y, w, h) 
-, m_channel     (d)
+: Fl_Menu_Button(x, y, w, h)
+, m_channel(d)
 {
        box(G_CUSTOM_BORDER_BOX);
        textsize(G_GUI_FONT_SIZE_BASE);
        textcolor(G_COLOR_LIGHT_2);
        color(G_COLOR_GREY_2);
 
-       add("Loop . basic",      0, cb_changeMode, (void*) SamplePlayerMode::LOOP_BASIC);
-       add("Loop . once",       0, cb_changeMode, (void*) SamplePlayerMode::LOOP_ONCE);
-       add("Loop . once . bar", 0, cb_changeMode, (void*) SamplePlayerMode::LOOP_ONCE_BAR);
-       add("Loop . repeat",     0, cb_changeMode, (void*) SamplePlayerMode::LOOP_REPEAT);
-       add("Oneshot . basic",   0, cb_changeMode, (void*) SamplePlayerMode::SINGLE_BASIC);
-       add("Oneshot . press",   0, cb_changeMode, (void*) SamplePlayerMode::SINGLE_PRESS);
-       add("Oneshot . retrig",  0, cb_changeMode, (void*) SamplePlayerMode::SINGLE_RETRIG);
-       add("Oneshot . endless", 0, cb_changeMode, (void*) SamplePlayerMode::SINGLE_ENDLESS);
+       add("Loop . basic", 0, cb_changeMode, (void*)SamplePlayerMode::LOOP_BASIC);
+       add("Loop . once", 0, cb_changeMode, (void*)SamplePlayerMode::LOOP_ONCE);
+       add("Loop . once . bar", 0, cb_changeMode, (void*)SamplePlayerMode::LOOP_ONCE_BAR);
+       add("Loop . repeat", 0, cb_changeMode, (void*)SamplePlayerMode::LOOP_REPEAT);
+       add("Oneshot . basic", 0, cb_changeMode, (void*)SamplePlayerMode::SINGLE_BASIC);
+       add("Oneshot . press", 0, cb_changeMode, (void*)SamplePlayerMode::SINGLE_PRESS);
+       add("Oneshot . retrig", 0, cb_changeMode, (void*)SamplePlayerMode::SINGLE_RETRIG);
+       add("Oneshot . endless", 0, cb_changeMode, (void*)SamplePlayerMode::SINGLE_ENDLESS);
 
        value(static_cast<int>(m_channel.sample->mode));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geChannelMode::draw() 
+void geChannelMode::draw()
 {
-       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);    // border
-
-       switch (m_channel.sample->mode) {
-               case SamplePlayerMode::LOOP_BASIC:
-                       fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::LOOP_ONCE:
-                       fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::LOOP_ONCE_BAR:
-                       fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::LOOP_REPEAT:
-                       fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::SINGLE_BASIC:
-                       fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::SINGLE_PRESS:
-                       fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::SINGLE_RETRIG:
-                       fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1);
-                       break;
-               case SamplePlayerMode::SINGLE_ENDLESS:
-                       fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1);
-                       break;
+       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border
+
+       switch (m_channel.sample->mode)
+       {
+       case SamplePlayerMode::LOOP_BASIC:
+               fl_draw_pixmap(loopBasic_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::LOOP_ONCE:
+               fl_draw_pixmap(loopOnce_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::LOOP_ONCE_BAR:
+               fl_draw_pixmap(loopOnceBar_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::LOOP_REPEAT:
+               fl_draw_pixmap(loopRepeat_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::SINGLE_BASIC:
+               fl_draw_pixmap(oneshotBasic_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::SINGLE_PRESS:
+               fl_draw_pixmap(oneshotPress_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::SINGLE_RETRIG:
+               fl_draw_pixmap(oneshotRetrig_xpm, x() + 1, y() + 1);
+               break;
+       case SamplePlayerMode::SINGLE_ENDLESS:
+               fl_draw_pixmap(oneshotEndless_xpm, x() + 1, y() + 1);
+               break;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelMode::cb_changeMode(Fl_Widget* w, void* p) { ((geChannelMode*)w)->cb_changeMode((intptr_t)p); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelMode::cb_changeMode(int mode)
 {
        c::channel::setSamplePlayerMode(m_channel.id, static_cast<SamplePlayerMode>(mode));
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index a3d2534c6050e1fa7e9d780fbb6b97f2e5af3878..125d868e57ba3706572c176b52848234d60ac10d 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_CHANNEL_MODE_H
 #define GE_CHANNEL_MODE_H
 
-
 #include <FL/Fl_Menu_Button.H>
 
-
-namespace giada {
-namespace v
+namespace giada::c::channel
+{
+struct Data;
+}
+namespace giada::v
 {
 class geChannelMode : public Fl_Menu_Button
 {
 public:
-
        geChannelMode(int x, int y, int w, int h, c::channel::Data& d);
 
        void draw() override;
 
-private:
-
-    static void cb_changeMode(Fl_Widget* /*w*/, void* p);
-    void cb_changeMode(int mode);
+  private:
+       static void cb_changeMode(Fl_Widget* /*w*/, void* p);
+       void        cb_changeMode(int mode);
 
-    c::channel::Data& m_channel;
+       c::channel::Data& m_channel;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 616708a4a3063f071925c158cfb51a027e336b05..6d9c25094c532eab6fb7e75c9974acd8c1752745 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/fl_draw.H>
+#include "channelStatus.h"
 #include "core/const.h"
 #include "glue/channel.h"
-#include "channelStatus.h"
-
+#include <FL/fl_draw.H>
 
-namespace giada {
-namespace v
+namespace giada::v
 {
 geChannelStatus::geChannelStatus(int x, int y, int w, int h, c::channel::Data& d)
-: Fl_Box   (x, y, w, h)
+: Fl_Box(x, y, w, h)
 , m_channel(d)
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geChannelStatus::draw()
 {
-       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);              // reset border
-       fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);     // reset background
+       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);                  // reset border
+       fl_rectf(x() + 1, y() + 1, w() - 2, h() - 2, G_COLOR_GREY_2); // reset background
 
-       ChannelStatus playStatus = m_channel.a_getPlayStatus();
-       ChannelStatus recStatus  = m_channel.a_getRecStatus();
+       ChannelStatus playStatus = m_channel.getPlayStatus();
+       ChannelStatus recStatus  = m_channel.getRecStatus();
        Pixel         pos        = 0;
 
-       if (playStatus == ChannelStatus::WAIT    || 
-           playStatus == ChannelStatus::ENDING  ||
-           recStatus  == ChannelStatus::WAIT    || 
-           recStatus  == ChannelStatus::ENDING)
+       if (playStatus == ChannelStatus::WAIT ||
+           playStatus == ChannelStatus::ENDING ||
+           recStatus == ChannelStatus::WAIT ||
+           recStatus == ChannelStatus::ENDING)
        {
                fl_rect(x(), y(), w(), h(), G_COLOR_LIGHT_1);
        }
-       else
-       if (playStatus == ChannelStatus::PLAY) {
+       else if (playStatus == ChannelStatus::PLAY)
+       {
                /* Equation for the progress bar: 
                ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */
-               Frame tracker = m_channel.sample->a_getTracker();
-               Frame begin   = m_channel.sample->a_getBegin();
-               Frame end     = m_channel.sample->a_getEnd();
-               pos = ((tracker - begin) * (w() - 1)) / ((end - begin));
+               Frame tracker = m_channel.sample->getTracker();
+               Frame begin   = m_channel.sample->getBegin();
+               Frame end     = m_channel.sample->getEnd();
+               pos           = ((tracker - begin) * (w() - 1)) / ((end - begin));
                fl_rect(x(), y(), w(), h(), G_COLOR_LIGHT_1);
        }
        else
-               fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);  // status empty
+               fl_rectf(x() + 1, y() + 1, w() - 2, h() - 2, G_COLOR_GREY_2); // status empty
 
        if (pos != 0)
-               fl_rectf(x()+1, y()+1, pos, h()-2, G_COLOR_LIGHT_1);
+               fl_rectf(x() + 1, y() + 1, pos, h() - 2, G_COLOR_LIGHT_1);
 }
-
-}} // giada::v::
+} // namespace giada::v
\ No newline at end of file
index 90e0dbb13843abe3dcf4df9b60741e9817f50558..4db44b29847954b78e644143a4e8822f6ec64349 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_CHANNEL_STATUS_H
 #define GE_CHANNEL_STATUS_H
 
-
 #include <FL/Fl_Box.H>
 
-
-namespace giada {
-namespace c {
-namespace channel
+namespace giada::c::channel
 {
 struct Data;
-}}
-namespace v
+}
+namespace giada::v
 {
 class geChannelStatus : public Fl_Box
 {
 public:
-
        geChannelStatus(int x, int y, int w, int h, c::channel::Data& d);
 
        void draw() override;
 
 private:
-
        c::channel::Data& m_channel;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 85a41d25a3d4b28988e66fb271cd801b050937e7..1074deed4e8f8161fd0af05de116532838bf87c9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/fl_draw.H>
-#include <FL/Fl_Menu_Button.H>
-#include "core/channels/state.h"
+#include "column.h"
 #include "core/model/model.h"
 #include "glue/channel.h"
-#include "utils/log.h"
-#include "utils/fs.h"
-#include "utils/string.h"
 #include "gui/dialogs/warnings.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/resizerBar.h"
 #include "keyboard.h"
-#include "sampleChannel.h"
 #include "midiChannel.h"
-#include "column.h"
-
+#include "sampleChannel.h"
+#include "utils/fs.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include <FL/Fl_Menu_Button.H>
+#include <FL/fl_draw.H>
+#include <cassert>
 
-namespace giada {
-namespace v
+namespace giada::v
 {
 geColumn::geColumn(int X, int Y, int W, int H, ID id, geResizerBar* b)
-: Fl_Group  (X, Y, W, H), 
-  id        (id),
-  resizerBar(b)
+: Fl_Group(X, Y, W, H)
+, id(id)
+, resizerBar(b)
 {
        end();
        init();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geColumn::refresh()
 {
        for (geChannel* c : m_channels)
                c->refresh();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geColumn::cb_addChannel(Fl_Widget* /*w*/, void* p) { ((geColumn*)p)->cb_addChannel(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geChannel* geColumn::addChannel(c::channel::Data d)
 {
        geChannel* gch  = nullptr;
@@ -83,24 +73,21 @@ geChannel* geColumn::addChannel(c::channel::Data d)
        if (d.type == ChannelType::SAMPLE)
                gch = new geSampleChannel(x(), last->y() + last->h() + G_GUI_INNER_MARGIN, w(), d.height, d);
        else
-               gch = new geMidiChannel  (x(), last->y() + last->h() + G_GUI_INNER_MARGIN, w(), d.height, d);
+               gch = new geMidiChannel(x(), last->y() + last->h() + G_GUI_INNER_MARGIN, w(), d.height, d);
 
-       geResizerBar* bar = new geResizerBar(x(), gch->y() + gch->h(), w(), 
-               G_GUI_INNER_MARGIN, G_GUI_UNIT, geResizerBar::VERTICAL, gch);
+       geResizerBar* bar = new geResizerBar(x(), gch->y() + gch->h(), w(),
+           G_GUI_INNER_MARGIN, G_GUI_UNIT, geResizerBar::VERTICAL, gch);
 
        /* Update the column height while dragging the resizer bar. */
 
-       bar->onDrag = [this](const Fl_Widget* /*w*/)
-       {
-               resizable(nullptr);     
+       bar->onDrag = [this](const Fl_Widget* /*w*/) {
+               resizable(nullptr);
                size(this->w(), (child(children() - 1)->y() - y()) + G_GUI_INNER_MARGIN);
-               
-       };      
+       };
 
        /* Store the channel height in model when the resizer bar is released. */
 
-       bar->onRelease = [channelId = d.id, this](const Fl_Widget* w)
-       {
+       bar->onRelease = [channelId = d.id, this](const Fl_Widget* w) {
                resizable(this);
                c::channel::setHeight(channelId, w->h());
        };
@@ -109,7 +96,7 @@ geChannel* geColumn::addChannel(c::channel::Data d)
 
        /* Temporarily disable the resizability, add new stuff, resize the group and 
        bring the resizability back. This is needed to prevent weird vertical 
-       stretching on existing content. */ 
+       stretching on existing content. */
 
        resizable(nullptr);
        add(gch);
@@ -121,20 +108,17 @@ geChannel* geColumn::addChannel(c::channel::Data d)
        return gch;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geColumn::cb_addChannel()
 {
        u::log::print("[geColumn::cb_addChannel] id = %d\n", id);
 
        Fl_Menu_Item menu[] = {
-               {"Add Sample channel"},
-               {"Add MIDI channel"},
-               {"Remove"},
-               {0}
-       };
+           {"Add Sample channel"},
+           {"Add MIDI channel"},
+           {"Remove"},
+           {0}};
 
        if (countChannels() > 0)
                menu[2].deactivate();
@@ -146,22 +130,19 @@ void geColumn::cb_addChannel()
        b.color(G_COLOR_GREY_2);
 
        const Fl_Menu_Item* m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, &b);
-       if (m == nullptr) return;
+       if (m == nullptr)
+               return;
 
        if (strcmp(m->label(), "Add Sample channel") == 0)
                c::channel::addChannel(id, ChannelType::SAMPLE);
-       else
-       if (strcmp(m->label(), "Add MIDI channel") == 0)
+       else if (strcmp(m->label(), "Add MIDI channel") == 0)
                c::channel::addChannel(id, ChannelType::MIDI);
        else
                static_cast<geKeyboard*>(parent())->deleteColumn(id);
-               
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geChannel* geColumn::getChannel(ID channelId) const
 {
        for (geChannel* c : m_channels)
@@ -170,10 +151,8 @@ geChannel* geColumn::getChannel(ID channelId) const
        return nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geColumn::init()
 {
        Fl_Group::clear();
@@ -185,29 +164,23 @@ void geColumn::init()
        add(m_addChannelBtn);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geColumn::forEachChannel(std::function<void(geChannel& c)> f) const
 {
        for (geChannel* c : m_channels)
                f(*c);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geColumn::countChannels() const
 {
        return m_channels.size();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geColumn::computeHeight() const
 {
        int out = 0;
@@ -215,4 +188,4 @@ int geColumn::computeHeight() const
                out += c->h() + G_GUI_INNER_MARGIN;
        return out + m_addChannelBtn->h() + G_GUI_INNER_MARGIN;
 }
-}} // giada::v::
+} // namespace giada::v
\ No newline at end of file
index 0ca3fc35013d1b1eb84bcd2bb6a8324ae8809149..43ebdf225141d50ba565566568b525ef6f125bb1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_COLUMN_H
 #define GE_COLUMN_H
 
-
+#include "core/types.h"
+#include "glue/channel.h"
+#include <FL/Fl_Group.H>
 #include <functional>
 #include <vector>
-#include <FL/Fl_Group.H>
-#include "glue/channel.h"
-#include "core/types.h"
-
 
 class geButton;
 class geResizerBar;
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 class geKeyboard;
 class geChannel;
 class geColumn : public Fl_Group
 {
 public:
-
        geColumn(int x, int y, int w, int h, ID id, geResizerBar* b);
 
        geChannel* getChannel(ID channelId) const;
-       
+
        /* addChannel
        Adds a new channel in this column. */
 
@@ -63,18 +57,17 @@ public:
 
        void refresh();
 
-       void init(); 
+       void init();
 
        void forEachChannel(std::function<void(geChannel& c)> f) const;
-       
+
        ID id;
 
        geResizerBar* resizerBar;
 
-private:
-
+  private:
        static void cb_addChannel(Fl_Widget* /*w*/, void* p);
-       void cb_addChannel();
+       void        cb_addChannel();
 
        int countChannels() const;
        int computeHeight() const;
@@ -83,7 +76,6 @@ private:
 
        geButton* m_addChannelBtn;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 26a9cde3905b89dae8e1404ad75bdb5b22b54078..c94af88d57f7aea418a48afb4ae9849ecb4aa127 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/fl_draw.H>
-#include "glue/io.h"
+#include "keyboard.h"
+#include "channelButton.h"
+#include "column.h"
 #include "glue/channel.h"
-#include "utils/fs.h"
-#include "utils/log.h"
-#include "utils/vector.h"
-#include "utils/string.h"
-#include "gui/dispatcher.h"
+#include "glue/io.h"
 #include "gui/dialogs/warnings.h"
+#include "gui/dispatcher.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/resizerBar.h"
-#include "column.h"
 #include "sampleChannel.h"
-#include "channelButton.h"
-#include "keyboard.h"
-
+#include "utils/fs.h"
+#include "utils/log.h"
+#include "utils/string.h"
+#include "utils/vector.h"
+#include <FL/fl_draw.H>
+#include <cassert>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geKeyboard::geKeyboard(int X, int Y, int W, int H)
-: geScroll      (X, Y, W, H, Fl_Scroll::BOTH_ALWAYS)
+: geScroll(X, Y, W, H, Fl_Scroll::BOTH_ALWAYS)
 , m_addColumnBtn(nullptr)
 {
        end();
        init();
+       rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::init()
 {
        m_columnId = m::IdManager();
@@ -75,104 +73,95 @@ void geKeyboard::init()
        layout.push_back({6, G_DEFAULT_COLUMN_WIDTH});
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::rebuild()
 {
        /* Wipe out all columns and add them according to the current layout. */
 
        deleteAllColumns();
-       
+
        for (ColumnLayout c : layout)
                addColumn(c.width, c.id);
 
        for (const c::channel::Data& ch : c::channel::getChannels())
                getColumn(ch.columnId)->addChannel(ch);
-       
+
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::deleteColumn(ID id)
 {
        u::vector::removeIf(layout, [=](const ColumnLayout& c) { return c.id == id; });
        rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::deleteAllColumns()
 {
        Fl_Scroll::clear();
        m_columns.clear();
 
        m_addColumnBtn = new geButton(8, y(), 200, 20, "Add new column");
-       m_addColumnBtn->callback(cb_addColumn, (void*) this);
+       m_addColumnBtn->callback(cb_addColumn, (void*)this);
        add(m_addColumnBtn);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::cb_addColumn(Fl_Widget* /*w*/, void* p)
 {
        ((geKeyboard*)p)->cb_addColumn();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::refresh()
 {
        for (geColumn* c : m_columns)
                c->refresh();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geKeyboard::handle(int e)
 {
-       switch (e) {
-               case FL_FOCUS:
-               case FL_UNFOCUS: {
-                       return 1;               // Enables receiving Keyboard events
-               }
-               case FL_SHORTCUT:           // In case widget that isn't ours has focus
-               case FL_KEYDOWN:            // Keyboard key pushed
-               case FL_KEYUP: {            // Keyboard key released
-                       dispatcher::dispatchKey(e);
-                       return 1;
-               }
-               case FL_DND_ENTER:          // return(1) for these events to 'accept' dnd
-               case FL_DND_DRAG:
-               case FL_DND_RELEASE: {
-                       return 1;
-               }
-               case FL_PASTE: {            // handle actual drop (paste) operation
-                       const geColumn* c = getColumnAtCursor(Fl::event_x());
-                       if (c != nullptr)
-                               c::channel::addAndLoadChannels(c->id, getDroppedFilePaths());
-                       return 1;
-               }
+       switch (e)
+       {
+       case FL_FOCUS:
+       case FL_UNFOCUS:
+       {
+               return 1; // Enables receiving Keyboard events
+       }
+       case FL_SHORTCUT: // In case widget that isn't ours has focus
+       case FL_KEYDOWN:  // Keyboard key pushed
+       case FL_KEYUP:
+       { // Keyboard key released
+               dispatcher::dispatchKey(e);
+               return 1;
        }
-       return Fl_Group::handle(e);     // Assume the buttons won't handle the Keyboard events
+       case FL_DND_ENTER: // return(1) for these events to 'accept' dnd
+       case FL_DND_DRAG:
+       case FL_DND_RELEASE:
+       {
+               return 1;
+       }
+       case FL_PASTE:
+       { // handle actual drop (paste) operation
+               const geColumn* c = getColumnAtCursor(Fl::event_x());
+               if (c != nullptr)
+                       c::channel::addAndLoadChannels(c->id, getDroppedFilePaths());
+               return 1;
+       }
+       }
+       return Fl_Group::handle(e); // Assume the buttons won't handle the Keyboard events
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::draw()
 {
        Fl_Scroll::draw();
@@ -182,10 +171,10 @@ void geKeyboard::draw()
        fl_color(G_COLOR_GREY_1_5);
 
        fl_push_clip(
-               x(), 
-               y(), 
-               w() - scrollbar_size() - (G_GUI_OUTER_MARGIN * 2), 
-               h() - scrollbar_size() - (G_GUI_OUTER_MARGIN * 2));
+           x(),
+           y(),
+           w() - scrollbar_size() - (G_GUI_OUTER_MARGIN * 2),
+           h() - scrollbar_size() - (G_GUI_OUTER_MARGIN * 2));
 
        for (const geColumn* c : m_columns)
                fl_rectf(c->x(), c->y() + c->h(), c->w(), h() + yposition());
@@ -193,23 +182,19 @@ void geKeyboard::draw()
        fl_pop_clip();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::cb_addColumn()
 {
        addColumn();
        storeLayout();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::addColumn(int width, ID id)
 {
-       int colx = x() - xposition();  // Mind the x-scroll offset with xposition()
+       int colx = x() - xposition(); // Mind the x-scroll offset with xposition()
 
        /* If this is not the first column... */
 
@@ -223,12 +208,11 @@ void geKeyboard::addColumn(int width, ID id)
        /* Add a new column + a new resizer bar. */
 
        geResizerBar* bar    = new geResizerBar(colx + width, y(), COLUMN_GAP, h(), G_MIN_COLUMN_WIDTH, geResizerBar::HORIZONTAL);
-       geColumn*     column = new geColumn(colx, y(), width, G_GUI_UNIT, m_columnId.get(id), bar);
+       geColumn*     column = new geColumn(colx, y(), width, G_GUI_UNIT, m_columnId.generate(id), bar);
 
        /* Store the column width in layout when the resizer bar is released. */
 
-       bar->onRelease = [=](const Fl_Widget* /*w*/)
-       {
+       bar->onRelease = [=](const Fl_Widget* /*w*/) {
                storeLayout();
        };
 
@@ -243,37 +227,31 @@ void geKeyboard::addColumn(int width, ID id)
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::forEachChannel(std::function<void(geChannel& c)> f) const
 {
-       for (geColumn* column : m_columns) 
+       for (geColumn* column : m_columns)
                column->forEachChannel(f);
 }
 
-
 void geKeyboard::forEachColumn(std::function<void(const geColumn& c)> f) const
 {
-       for (geColumn* column : m_columns) 
+       for (geColumn* column : m_columns)
                f(*column);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geColumn* geKeyboard::getColumn(ID id)
 {
-       for (geColumn* c : m_columns) 
+       for (geColumn* c : m_columns)
                if (c->id == id)
                        return c;
        assert(false);
        return nullptr;
 }
 
-
 geColumn* geKeyboard::getColumnAtCursor(Pixel px)
 {
        px += xposition();
@@ -283,42 +261,38 @@ geColumn* geKeyboard::getColumnAtCursor(Pixel px)
        return nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geChannel* geKeyboard::getChannel(ID channelId)
 {
-       for (geColumn* column : m_columns) {
+       for (geColumn* column : m_columns)
+       {
                geChannel* c = column->getChannel(channelId);
-               if (c != nullptr) 
+               if (c != nullptr)
                        return c;
        }
        assert(false);
        return nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::vector<std::string> geKeyboard::getDroppedFilePaths() const
-{                      
+{
        std::vector<std::string> paths = u::string::split(Fl::event_text(), "\n");
-               for (std::string& p : paths)
-                       p = u::fs::stripFileUrl(p);
+       for (std::string& p : paths)
+               p = u::fs::stripFileUrl(p);
        return paths;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geKeyboard::storeLayout()
 {
        layout.clear();
        for (const geColumn* c : m_columns)
-               layout.push_back({ c->id, c->w() });
+               layout.push_back({c->id, c->w()});
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index a1d3219b4bc2db2edb5c8b892aeaddd30ec6bf4d..d9326cb97e6af93290c564db89c444691a44ea37 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_KEYBOARD_H
 #define GE_KEYBOARD_H
 
-
-#include <vector>
-#include <functional>
-#include "gui/elems/basics/scroll.h"
-#include "core/idManager.h"
 #include "core/const.h"
-
+#include "core/idManager.h"
+#include "gui/elems/basics/scroll.h"
+#include <functional>
+#include <vector>
 
 class geButton;
 class geResizerBar;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geColumn;
@@ -48,16 +45,15 @@ class geChannel;
 class geKeyboard : public geScroll
 {
 public:
-
        struct ColumnLayout
        {
-               ID id;
+               ID  id;
                int width;
        };
 
        geKeyboard(int X, int Y, int W, int H);
 
-       int handle(int e) override;
+       int  handle(int e) override;
        void draw() override;
 
        /* rebuild
@@ -72,7 +68,7 @@ public:
 
        /* deleteColumn
        Deletes column by id. */
-       
+
        void deleteColumn(ID id);
 
        /* deleteAllColumns
@@ -98,14 +94,13 @@ public:
 
        std::vector<ColumnLayout> layout;
 
-private:
-
+  private:
        static constexpr int COLUMN_GAP = 20;
 
        static void cb_addColumn(Fl_Widget* /*w*/, void* p);
-       void cb_addColumn();
+       void        cb_addColumn();
 
-       void addColumn(int width=G_DEFAULT_COLUMN_WIDTH, ID id=0);
+       void addColumn(int width = G_DEFAULT_COLUMN_WIDTH, ID id = 0);
 
        /* getDroppedFilePaths
        Returns a vector of audio file paths after a drag-n-drop from desktop
@@ -125,15 +120,15 @@ private:
 
        /* storeLayout
        Stores the current column layout into the layout vector. */
-       
+
        void storeLayout();
 
-       m::IdManager m_columnId;
+       m::IdManager           m_columnId;
        std::vector<geColumn*> m_columns;
 
        geButton* m_addColumnBtn;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index d2148ce5179ca563f4b1f02004fa0275f5be2296..dcb3307f773afa0693eb5388e70249923989b00a 100644 (file)
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl_Menu_Button.H>
+#include "midiChannel.h"
+#include "column.h"
 #include "core/const.h"
 #include "core/graphics.h"
 #include "core/model/model.h"
 #include "core/recorder.h"
-#include "utils/gui.h"
-#include "utils/string.h"
 #include "glue/channel.h"
 #include "glue/io.h"
 #include "glue/recorder.h"
-#include "gui/dispatcher.h"
-#include "gui/dialogs/mainWindow.h"
+#include "gui/dialogs/actionEditor/midiActionEditor.h"
 #include "gui/dialogs/channelNameInput.h"
-#include "gui/dialogs/warnings.h"
 #include "gui/dialogs/keyGrabber.h"
-#include "gui/dialogs/pluginList.h"
-#include "gui/dialogs/actionEditor/midiActionEditor.h"
+#include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/midiIO/midiInputChannel.h"
 #include "gui/dialogs/midiIO/midiOutputMidiCh.h"
+#include "gui/dialogs/pluginList.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/dispatcher.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/basics/statusButton.h"
 #include "gui/elems/basics/dial.h"
-#include "column.h"
+#include "gui/elems/basics/statusButton.h"
 #include "midiChannelButton.h"
-#include "midiChannel.h"
-
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <FL/Fl_Menu_Button.H>
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 namespace
@@ -76,55 +74,51 @@ enum class Menu
        DELETE_CHANNEL
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void menuCallback(Fl_Widget* w, void* v)
 {
        const geMidiChannel*    gch  = static_cast<geMidiChannel*>(w);
        const c::channel::Data& data = gch->getData();
 
-       switch ((Menu) (intptr_t) v)
+       switch ((Menu)(intptr_t)v)
        {
-               case Menu::CLEAR_ACTIONS:
-               case Menu::__END_CLEAR_ACTION_SUBMENU__:
-                       break;
-               case Menu::EDIT_ACTIONS:
-                       u::gui::openSubWindow(G_MainWin, new v::gdMidiActionEditor(data.id), WID_ACTION_EDITOR);
-                       break;
-               case Menu::CLEAR_ACTIONS_ALL:
-                       c::recorder::clearAllActions(data.id);
-                       break;
-               case Menu::SETUP_KEYBOARD_INPUT:
-                       u::gui::openSubWindow(G_MainWin, new gdKeyGrabber(data), WID_KEY_GRABBER);
-                       break;
-               case Menu::SETUP_MIDI_INPUT:
-                       u::gui::openSubWindow(G_MainWin, new gdMidiInputChannel(data.id), WID_MIDI_INPUT);
-                       break;
-               case Menu::SETUP_MIDI_OUTPUT:
-                       u::gui::openSubWindow(G_MainWin, new gdMidiOutputMidiCh(data.id), WID_MIDI_OUTPUT);
-                       break;
-               case Menu::CLONE_CHANNEL:
-                       c::channel::cloneChannel(data.id);
-                       break;          
-               case Menu::RENAME_CHANNEL:
-                       u::gui::openSubWindow(G_MainWin, new gdChannelNameInput(data), WID_SAMPLE_NAME);
-                       break;
-               case Menu::DELETE_CHANNEL:
-                       c::channel::deleteChannel(data.id);
-                       break;
+       case Menu::CLEAR_ACTIONS:
+       case Menu::__END_CLEAR_ACTION_SUBMENU__:
+               break;
+       case Menu::EDIT_ACTIONS:
+               u::gui::openSubWindow(G_MainWin, new v::gdMidiActionEditor(data.id), WID_ACTION_EDITOR);
+               break;
+       case Menu::CLEAR_ACTIONS_ALL:
+               c::recorder::clearAllActions(data.id);
+               break;
+       case Menu::SETUP_KEYBOARD_INPUT:
+               u::gui::openSubWindow(G_MainWin, new gdKeyGrabber(data), WID_KEY_GRABBER);
+               break;
+       case Menu::SETUP_MIDI_INPUT:
+               u::gui::openSubWindow(G_MainWin, new gdMidiInputChannel(data.id), WID_MIDI_INPUT);
+               break;
+       case Menu::SETUP_MIDI_OUTPUT:
+               u::gui::openSubWindow(G_MainWin, new gdMidiOutputMidiCh(data.id), WID_MIDI_OUTPUT);
+               break;
+       case Menu::CLONE_CHANNEL:
+               c::channel::cloneChannel(data.id);
+               break;
+       case Menu::RENAME_CHANNEL:
+               u::gui::openSubWindow(G_MainWin, new gdChannelNameInput(data), WID_SAMPLE_NAME);
+               break;
+       case Menu::DELETE_CHANNEL:
+               c::channel::deleteChannel(data.id);
+               break;
        }
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 
-
 geMidiChannel::geMidiChannel(int X, int Y, int W, int H, c::channel::Data d)
 : geChannel(X, Y, W, H, d)
-, m_data   (d)
+, m_data(d)
 {
 #if defined(WITH_VST)
        constexpr int delta = 6 * (G_GUI_UNIT + G_GUI_INNER_MARGIN);
@@ -132,31 +126,40 @@ geMidiChannel::geMidiChannel(int X, int Y, int W, int H, c::channel::Data d)
        constexpr int delta = 5 * (G_GUI_UNIT + G_GUI_INNER_MARGIN);
 #endif
 
-       playButton = new geStatusButton     (x(), y(), G_GUI_UNIT, G_GUI_UNIT, channelStop_xpm, channelPlay_xpm);
-       arm        = new geButton           (playButton->x() + playButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
+       playButton = new geStatusButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, channelStop_xpm, channelPlay_xpm);
+       arm        = new geButton(playButton->x() + playButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm);
        mainButton = new geMidiChannelButton(arm->x() + arm->w() + G_GUI_INNER_MARGIN, y(), w() - delta, H, m_channel);
-       mute       = new geStatusButton     (mainButton->x() + mainButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, muteOff_xpm, muteOn_xpm);
-       solo       = new geStatusButton     (mute->x() + mute->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, soloOff_xpm, soloOn_xpm);
+       mute       = new geStatusButton(mainButton->x() + mainButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, muteOff_xpm, muteOn_xpm);
+       solo       = new geStatusButton(mute->x() + mute->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, soloOff_xpm, soloOn_xpm);
 #if defined(WITH_VST)
-       fx         = new geStatusButton     (solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
-       vol        = new geDial             (fx->x() + fx->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
+       fx  = new geStatusButton(solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
+       vol = new geDial(fx->x() + fx->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
 #else
-       vol        = new geDial             (solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
+       vol                 = new geDial(solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
 #endif
 
        end();
 
        resizable(mainButton);
 
+       playButton->copy_tooltip("Play/stop");
+       arm->copy_tooltip("Arm for recording");
+       mute->copy_tooltip("Mute");
+       solo->copy_tooltip("Solo");
+#if defined(WITH_VST)
+       fx->copy_tooltip("Plug-ins");
+#endif
+       vol->copy_tooltip("Volume");
+
 #ifdef WITH_VST
-       fx->setStatus(m_channel.pluginIds.size() > 0);
+       fx->setStatus(m_channel.plugins.size() > 0);
 #endif
 
        playButton->callback(cb_playButton, (void*)this);
-       playButton->when(FL_WHEN_CHANGED);   // On keypress && on keyrelease
+       playButton->when(FL_WHEN_CHANGED); // On keypress && on keyrelease
 
        arm->type(FL_TOGGLE_BUTTON);
-       arm->value(m_channel.a_isArmed());
+       arm->value(m_channel.isArmed());
        arm->callback(cb_arm, (void*)this);
 
 #ifdef WITH_VST
@@ -177,41 +180,34 @@ geMidiChannel::geMidiChannel(int X, int Y, int W, int H, c::channel::Data d)
        size(w(), h()); // Force responsiveness
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiChannel::cb_playButton(Fl_Widget* /*w*/, void* p) { ((geMidiChannel*)p)->cb_playButton(); }
 void geMidiChannel::cb_openMenu(Fl_Widget* /*w*/, void* p) { ((geMidiChannel*)p)->cb_openMenu(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiChannel::cb_playButton()
 {
        v::dispatcher::dispatchTouch(*this, playButton->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiChannel::cb_openMenu()
 {
        Fl_Menu_Item rclick_menu[] = {
-               {"Edit actions...", 0, menuCallback, (void*) Menu::EDIT_ACTIONS},
-               {"Clear actions",   0, menuCallback, (void*) Menu::CLEAR_ACTIONS, FL_SUBMENU},
-                       {"All",         0, menuCallback, (void*) Menu::CLEAR_ACTIONS_ALL},
-                       {0},
-               {"Setup keyboard input...", 0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
-               {"Setup MIDI input...",     0, menuCallback, (void*) Menu::SETUP_MIDI_INPUT},
-               {"Setup MIDI output...",    0, menuCallback, (void*) Menu::SETUP_MIDI_OUTPUT},
-               {"Rename", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
-               {"Clone",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
-               {"Delete", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
-               {0}
-       };
+           {"Edit actions...", 0, menuCallback, (void*)Menu::EDIT_ACTIONS},
+           {"Clear actions", 0, menuCallback, (void*)Menu::CLEAR_ACTIONS, FL_SUBMENU},
+           {"All", 0, menuCallback, (void*)Menu::CLEAR_ACTIONS_ALL},
+           {0},
+           {"Setup keyboard input...", 0, menuCallback, (void*)Menu::SETUP_KEYBOARD_INPUT},
+           {"Setup MIDI input...", 0, menuCallback, (void*)Menu::SETUP_MIDI_INPUT},
+           {"Setup MIDI output...", 0, menuCallback, (void*)Menu::SETUP_MIDI_OUTPUT},
+           {"Rename", 0, menuCallback, (void*)Menu::RENAME_CHANNEL},
+           {"Clone", 0, menuCallback, (void*)Menu::CLONE_CHANNEL},
+           {"Delete", 0, menuCallback, (void*)Menu::DELETE_CHANNEL},
+           {0}};
 
        /* No 'clear actions' if there are no actions. */
 
@@ -230,10 +226,8 @@ void geMidiChannel::cb_openMenu()
        return;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiChannel::resize(int X, int Y, int W, int H)
 {
        geChannel::resize(X, Y, W, H);
@@ -253,4 +247,5 @@ void geMidiChannel::resize(int X, int Y, int W, int H)
        packWidgets();
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 4a12c8b00c386b01f12530dfbe1934e7627b7555..33326d293641102b560fe5b6f4cf78b8d7677cae 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MIDI_CHANNEL_H
 #define GE_MIDI_CHANNEL_H
 
-
 #include "channel.h"
 #include "channelButton.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geMidiChannel : public geChannel
 {
 public:
+       geMidiChannel(int x, int y, int w, int h, c::channel::Data d);
 
-    geMidiChannel(int x, int y, int w, int h, c::channel::Data d);
-
-    void resize(int x, int y, int w, int h) override;
-
-private:
+       void resize(int x, int y, int w, int h) override;
 
+  private:
        static void cb_playButton(Fl_Widget* /*w*/, void* p);
        static void cb_openMenu(Fl_Widget* /*w*/, void* p);
-       void cb_playButton();
-       void cb_openMenu();
+       void        cb_playButton();
+       void        cb_openMenu();
 
        c::channel::Data m_data;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 41372023d16a7e7564322f4b8ca01e62dd22c0a0..789751c67e7d79811bddaacd986ae38693ff5801 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "utils/string.h"
-#include "glue/channel.h"
 #include "midiChannelButton.h"
+#include "glue/channel.h"
+#include "utils/string.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const c::channel::Data& d)
@@ -38,33 +37,30 @@ geMidiChannelButton::geMidiChannelButton(int x, int y, int w, int h, const c::ch
 {
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiChannelButton::refresh()
 {
        geChannelButton::refresh();
 
        refreshLabel();
 
-       if (m_channel.a_isRecordingAction() && m_channel.a_isArmed())
+       if (m_channel.isRecordingAction() && m_channel.isArmed())
                setActionRecordMode();
-       
+
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiChannelButton::refreshLabel()
 {
-    std::string l = m_channel.name.empty() ? "-- MIDI --" : m_channel.name; 
+       std::string l = m_channel.name.empty() ? "-- MIDI --" : m_channel.name;
 
-       if (m_channel.midi->a_isOutputEnabled())
-               l += " (ch " + std::to_string(m_channel.midi->a_getFilter() + 1) + " out)";
+       if (m_channel.midi->isOutputEnabled())
+               l += " (ch " + std::to_string(m_channel.midi->getFilter() + 1) + " out)";
 
        copy_label(l.c_str());
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 45c702afbce56cd35cdd9843070ac42e2e7845e4..ba145c2e80989148eb742c5abfddf4ef9da54335 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MIDI_CHANNEL_BUTTON_H
 #define GE_MIDI_CHANNEL_BUTTON_H
 
-
 #include "channelButton.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geMidiChannelButton : public geChannelButton
 {
 public:
-
        geMidiChannelButton(int x, int y, int w, int h, const c::channel::Data& d);
-       
-       void refresh() override;
 
-private:
+       void refresh() override;
 
+  private:
        void refreshLabel();
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 3db66bea9e29ea08eeb78e55cc7a2c5c5a491556..690220a0cc111cf7dfa1d8e862443c08a29db18a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
+#include "sampleChannel.h"
+#include "channelMode.h"
+#include "channelStatus.h"
+#include "column.h"
 #include "core/channels/channel.h"
 #include "core/channels/samplePlayer.h"
-#include "core/model/model.h"
-#include "core/mixer.h"
-#include "core/conf.h"
 #include "core/clock.h"
+#include "core/conf.h"
 #include "core/graphics.h"
-#include "core/wave.h"
-#include "core/recorder.h"
+#include "core/mixer.h"
+#include "core/model/model.h"
 #include "core/recManager.h"
-#include "glue/io.h"
+#include "core/recorder.h"
+#include "core/wave.h"
 #include "glue/channel.h"
 #include "glue/events.h"
+#include "glue/io.h"
 #include "glue/recorder.h"
 #include "glue/storage.h"
-#include "utils/gui.h"
-#include "gui/dispatcher.h"
-#include "gui/dialogs/mainWindow.h"
-#include "gui/dialogs/keyGrabber.h"
-#include "gui/dialogs/sampleEditor.h"
-#include "gui/dialogs/channelNameInput.h"
-#include "gui/dialogs/warnings.h"
 #include "gui/dialogs/actionEditor/sampleActionEditor.h"
-#include "gui/dialogs/browser/browserSave.h"
 #include "gui/dialogs/browser/browserLoad.h"
-#include "gui/dialogs/midiIO/midiOutputSampleCh.h"
+#include "gui/dialogs/browser/browserSave.h"
+#include "gui/dialogs/channelNameInput.h"
+#include "gui/dialogs/keyGrabber.h"
+#include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/midiIO/midiInputChannel.h"
+#include "gui/dialogs/midiIO/midiOutputSampleCh.h"
+#include "gui/dialogs/sampleEditor.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/dispatcher.h"
 #include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
-#include "gui/elems/basics/statusButton.h"
 #include "gui/elems/basics/dial.h"
-#include "channelStatus.h"
-#include "channelMode.h"
-#include "sampleChannelButton.h"
+#include "gui/elems/basics/statusButton.h"
 #include "keyboard.h"
-#include "column.h"
-#include "sampleChannel.h"
-
+#include "sampleChannelButton.h"
+#include "utils/gui.h"
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 namespace
@@ -95,103 +93,116 @@ enum class Menu
        DELETE_CHANNEL
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void menuCallback(Fl_Widget* w, void* v)
 {
        const geSampleChannel*  gch  = static_cast<geSampleChannel*>(w);
        const c::channel::Data& data = gch->getData();
 
-       switch ((Menu) (intptr_t) v) {
-               case Menu::INPUT_MONITOR: {
-                       c::channel::setInputMonitor(data.id, !data.sample->a_getInputMonitor());
-                       break;
-               }
-               case Menu::OVERDUB_PROTECTION: {
-                       c::channel::setOverdubProtection(data.id, !data.sample->a_getOverdubProtection());
-                       break;
-               }
-               case Menu::LOAD_SAMPLE: {
-                       gdWindow* w = new gdBrowserLoad("Browse sample", 
-                               m::conf::conf.samplePath.c_str(), c::storage::loadSample, data.id);
-                       u::gui::openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
-                       break;
-               }
-               case Menu::EXPORT_SAMPLE: {
-                       gdWindow* w = new gdBrowserSave("Save sample", 
-                               m::conf::conf.samplePath.c_str(), "", c::storage::saveSample, data.id);
-                       u::gui::openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
-                       break;
-               }
-               case Menu::SETUP_KEYBOARD_INPUT: {
-                       u::gui::openSubWindow(G_MainWin, new gdKeyGrabber(data), 
-                               WID_KEY_GRABBER);
-                       break;
-               }
-               case Menu::SETUP_MIDI_INPUT: {
-                       u::gui::openSubWindow(G_MainWin, new gdMidiInputChannel(data.id), 
-                               WID_MIDI_INPUT);
-                       break;
-               }
-               case Menu::SETUP_MIDI_OUTPUT: {
-                       u::gui::openSubWindow(G_MainWin, new gdMidiOutputSampleCh(data.id), 
-                               WID_MIDI_OUTPUT);
-                       break;
-               }
-               case Menu::EDIT_SAMPLE: {
-                       u::gui::openSubWindow(G_MainWin, new gdSampleEditor(data.id),
-                               WID_SAMPLE_EDITOR);
-                       break;
-               }
-               case Menu::EDIT_ACTIONS: {
-                       u::gui::openSubWindow(G_MainWin, new gdSampleActionEditor(data.id), 
-                               WID_ACTION_EDITOR);
-                       break;
-               }
-               case Menu::CLEAR_ACTIONS:
-               case Menu::__END_CLEAR_ACTIONS_SUBMENU__:
-                       break;
-               case Menu::CLEAR_ACTIONS_ALL: {
-                       c::recorder::clearAllActions(data.id);
-                       break;
-               }
-               case Menu::CLEAR_ACTIONS_VOLUME: {
-                       c::recorder::clearVolumeActions(data.id);
-                       break;
-               }
-               case Menu::CLEAR_ACTIONS_START_STOP: {
-                       c::recorder::clearStartStopActions(data.id);
-                       break;
-               }
-               case Menu::CLONE_CHANNEL: {
-                       c::channel::cloneChannel(data.id);
-                       break;
-               }
-               case Menu::RENAME_CHANNEL: {
-                       u::gui::openSubWindow(G_MainWin, new gdChannelNameInput(data), 
-                               WID_SAMPLE_NAME);
-                       break;
-               }
-               case Menu::FREE_CHANNEL: {
-                       c::channel::freeChannel(data.id);
-                       break;
-               }
-               case Menu::DELETE_CHANNEL: {
-                       c::channel::deleteChannel(data.id);
-                       break;
-               }
+       switch ((Menu)(intptr_t)v)
+       {
+       case Menu::INPUT_MONITOR:
+       {
+               c::channel::setInputMonitor(data.id, !data.sample->getInputMonitor());
+               break;
+       }
+       case Menu::OVERDUB_PROTECTION:
+       {
+               c::channel::setOverdubProtection(data.id, !data.sample->getOverdubProtection());
+               break;
+       }
+       case Menu::LOAD_SAMPLE:
+       {
+               gdWindow* w = new gdBrowserLoad("Browse sample",
+                   m::conf::conf.samplePath.c_str(), c::storage::loadSample, data.id);
+               u::gui::openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+               break;
+       }
+       case Menu::EXPORT_SAMPLE:
+       {
+               gdWindow* w = new gdBrowserSave("Save sample",
+                   m::conf::conf.samplePath.c_str(), "", c::storage::saveSample, data.id);
+               u::gui::openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
+               break;
+       }
+       case Menu::SETUP_KEYBOARD_INPUT:
+       {
+               u::gui::openSubWindow(G_MainWin, new gdKeyGrabber(data),
+                   WID_KEY_GRABBER);
+               break;
+       }
+       case Menu::SETUP_MIDI_INPUT:
+       {
+               u::gui::openSubWindow(G_MainWin, new gdMidiInputChannel(data.id),
+                   WID_MIDI_INPUT);
+               break;
+       }
+       case Menu::SETUP_MIDI_OUTPUT:
+       {
+               u::gui::openSubWindow(G_MainWin, new gdMidiOutputSampleCh(data.id),
+                   WID_MIDI_OUTPUT);
+               break;
+       }
+       case Menu::EDIT_SAMPLE:
+       {
+               u::gui::openSubWindow(G_MainWin, new gdSampleEditor(data.id),
+                   WID_SAMPLE_EDITOR);
+               break;
+       }
+       case Menu::EDIT_ACTIONS:
+       {
+               u::gui::openSubWindow(G_MainWin, new gdSampleActionEditor(data.id),
+                   WID_ACTION_EDITOR);
+               break;
+       }
+       case Menu::CLEAR_ACTIONS:
+       case Menu::__END_CLEAR_ACTIONS_SUBMENU__:
+               break;
+       case Menu::CLEAR_ACTIONS_ALL:
+       {
+               c::recorder::clearAllActions(data.id);
+               break;
+       }
+       case Menu::CLEAR_ACTIONS_VOLUME:
+       {
+               c::recorder::clearVolumeActions(data.id);
+               break;
+       }
+       case Menu::CLEAR_ACTIONS_START_STOP:
+       {
+               c::recorder::clearStartStopActions(data.id);
+               break;
+       }
+       case Menu::CLONE_CHANNEL:
+       {
+               c::channel::cloneChannel(data.id);
+               break;
+       }
+       case Menu::RENAME_CHANNEL:
+       {
+               u::gui::openSubWindow(G_MainWin, new gdChannelNameInput(data),
+                   WID_SAMPLE_NAME);
+               break;
+       }
+       case Menu::FREE_CHANNEL:
+       {
+               c::channel::freeChannel(data.id);
+               break;
+       }
+       case Menu::DELETE_CHANNEL:
+       {
+               c::channel::deleteChannel(data.id);
+               break;
+       }
        }
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 geSampleChannel::geSampleChannel(int X, int Y, int W, int H, c::channel::Data d)
 : geChannel(X, Y, W, H, d)
 {
@@ -201,34 +212,47 @@ geSampleChannel::geSampleChannel(int X, int Y, int W, int H, c::channel::Data d)
        constexpr int delta = 8 * (G_GUI_UNIT + G_GUI_INNER_MARGIN);
 #endif
 
-       playButton  = new geStatusButton       (x(), y(), G_GUI_UNIT, G_GUI_UNIT, channelStop_xpm, channelPlay_xpm);
-       arm         = new geButton             (playButton->x() + playButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm, armDisabled_xpm);
-       status      = new geChannelStatus      (arm->x() + arm->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, H, m_channel);
+       playButton  = new geStatusButton(x(), y(), G_GUI_UNIT, G_GUI_UNIT, channelStop_xpm, channelPlay_xpm);
+       arm         = new geButton(playButton->x() + playButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, "", armOff_xpm, armOn_xpm, armDisabled_xpm);
+       status      = new geChannelStatus(arm->x() + arm->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, H, m_channel);
        mainButton  = new geSampleChannelButton(status->x() + status->w() + G_GUI_INNER_MARGIN, y(), w() - delta, H, m_channel);
-       readActions = new geStatusButton       (mainButton->x() + mainButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, readActionOff_xpm, readActionOn_xpm, readActionDisabled_xpm);
-       modeBox     = new geChannelMode        (readActions->x() + readActions->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, m_channel);
-       mute        = new geStatusButton       (modeBox->x() + modeBox->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, muteOff_xpm, muteOn_xpm);
-       solo        = new geStatusButton       (mute->x() + mute->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, soloOff_xpm, soloOn_xpm);
+       readActions = new geStatusButton(mainButton->x() + mainButton->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, readActionOff_xpm, readActionOn_xpm, readActionDisabled_xpm);
+       modeBox     = new geChannelMode(readActions->x() + readActions->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, m_channel);
+       mute        = new geStatusButton(modeBox->x() + modeBox->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, muteOff_xpm, muteOn_xpm);
+       solo        = new geStatusButton(mute->x() + mute->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, soloOff_xpm, soloOn_xpm);
 #if defined(WITH_VST)
-       fx          = new geStatusButton       (solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
-       vol         = new geDial               (fx->x() + fx->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
+       fx  = new geStatusButton(solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm);
+       vol = new geDial(fx->x() + fx->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
 #else
-       vol         = new geDial               (solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);       
+       vol                 = new geDial(solo->x() + solo->w() + G_GUI_INNER_MARGIN, y(), G_GUI_UNIT, G_GUI_UNIT);
 #endif
 
        end();
 
        resizable(mainButton);
 
+       playButton->copy_tooltip("Play/stop");
+       arm->copy_tooltip("Arm for recording");
+       status->copy_tooltip("Progress bar");
+       readActions->copy_tooltip("Read actions\n\nToggles playback of pre-recorded "
+                                 "actions (key press, key release, ...).");
+       modeBox->copy_tooltip("Mode");
+       mute->copy_tooltip("Mute");
+       solo->copy_tooltip("Solo");
+#if defined(WITH_VST)
+       fx->copy_tooltip("Plug-ins");
+#endif
+       vol->copy_tooltip("Volume");
+
 #ifdef WITH_VST
-       fx->setStatus(m_channel.pluginIds.size() > 0);
+       fx->setStatus(m_channel.plugins.size() > 0);
 #endif
 
        playButton->callback(cb_playButton, (void*)this);
-       playButton->when(FL_WHEN_CHANGED);   // On keypress && on keyrelease
+       playButton->when(FL_WHEN_CHANGED); // On keypress && on keyrelease
 
        arm->type(FL_TOGGLE_BUTTON);
-       arm->value(m_channel.a_isArmed());
+       arm->value(m_channel.isArmed());
        arm->callback(cb_arm, (void*)this);
 
 #ifdef WITH_VST
@@ -251,27 +275,21 @@ geSampleChannel::geSampleChannel(int X, int Y, int W, int H, c::channel::Data d)
        size(w(), h()); // Force responsiveness
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleChannel::cb_playButton (Fl_Widget* /*w*/, void* p) { ((geSampleChannel*)p)->cb_playButton(); }
-void geSampleChannel::cb_openMenu   (Fl_Widget* /*w*/, void* p) { ((geSampleChannel*)p)->cb_openMenu(); }
+void geSampleChannel::cb_playButton(Fl_Widget* /*w*/, void* p) { ((geSampleChannel*)p)->cb_playButton(); }
+void geSampleChannel::cb_openMenu(Fl_Widget* /*w*/, void* p) { ((geSampleChannel*)p)->cb_openMenu(); }
 void geSampleChannel::cb_readActions(Fl_Widget* /*w*/, void* p) { ((geSampleChannel*)p)->cb_readActions(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleChannel::cb_playButton()
 {
        v::dispatcher::dispatchTouch(*this, playButton->value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleChannel::cb_openMenu()
 {
        /* If you're recording (input or actions) no menu is allowed; you can't do
@@ -281,44 +299,44 @@ void geSampleChannel::cb_openMenu()
                return;
 
        Fl_Menu_Item rclick_menu[] = {
-               {"Input monitor",            0, menuCallback, (void*) Menu::INPUT_MONITOR,
-                       FL_MENU_TOGGLE | (m_channel.sample->a_getInputMonitor() ? FL_MENU_VALUE : 0)},
-               {"Overdub protection",       0, menuCallback, (void*) Menu::OVERDUB_PROTECTION,
-                       FL_MENU_TOGGLE | FL_MENU_DIVIDER | (m_channel.sample->a_getOverdubProtection() ? FL_MENU_VALUE : 0)},
-               {"Load new sample...",       0, menuCallback, (void*) Menu::LOAD_SAMPLE},
-               {"Export sample to file...", 0, menuCallback, (void*) Menu::EXPORT_SAMPLE},
-               {"Setup keyboard input...",  0, menuCallback, (void*) Menu::SETUP_KEYBOARD_INPUT},
-               {"Setup MIDI input...",      0, menuCallback, (void*) Menu::SETUP_MIDI_INPUT},
-               {"Setup MIDI output...",     0, menuCallback, (void*) Menu::SETUP_MIDI_OUTPUT},
-               {"Edit sample...",           0, menuCallback, (void*) Menu::EDIT_SAMPLE},
-               {"Edit actions...",          0, menuCallback, (void*) Menu::EDIT_ACTIONS},
-               {"Clear actions",            0, menuCallback, (void*) Menu::CLEAR_ACTIONS, FL_SUBMENU},
-                       {"All",        0, menuCallback, (void*) Menu::CLEAR_ACTIONS_ALL},
-                       {"Volume",     0, menuCallback, (void*) Menu::CLEAR_ACTIONS_VOLUME},
-                       {"Start/Stop", 0, menuCallback, (void*) Menu::CLEAR_ACTIONS_START_STOP},
-                       {0},
-               {"Rename", 0, menuCallback, (void*) Menu::RENAME_CHANNEL},
-               {"Clone",  0, menuCallback, (void*) Menu::CLONE_CHANNEL},
-               {"Free",   0, menuCallback, (void*) Menu::FREE_CHANNEL},
-               {"Delete", 0, menuCallback, (void*) Menu::DELETE_CHANNEL},
-               {0}
-       };
-
-       if (m_channel.sample->waveId == 0) {
-               rclick_menu[(int) Menu::EXPORT_SAMPLE].deactivate();
-               rclick_menu[(int) Menu::EDIT_SAMPLE].deactivate();
-               rclick_menu[(int) Menu::FREE_CHANNEL].deactivate();
-               rclick_menu[(int) Menu::RENAME_CHANNEL].deactivate();
+           {"Input monitor", 0, menuCallback, (void*)Menu::INPUT_MONITOR,
+               FL_MENU_TOGGLE | (m_channel.sample->getInputMonitor() ? FL_MENU_VALUE : 0)},
+           {"Overdub protection", 0, menuCallback, (void*)Menu::OVERDUB_PROTECTION,
+               FL_MENU_TOGGLE | FL_MENU_DIVIDER | (m_channel.sample->getOverdubProtection() ? FL_MENU_VALUE : 0)},
+           {"Load new sample...", 0, menuCallback, (void*)Menu::LOAD_SAMPLE},
+           {"Export sample to file...", 0, menuCallback, (void*)Menu::EXPORT_SAMPLE},
+           {"Setup keyboard input...", 0, menuCallback, (void*)Menu::SETUP_KEYBOARD_INPUT},
+           {"Setup MIDI input...", 0, menuCallback, (void*)Menu::SETUP_MIDI_INPUT},
+           {"Setup MIDI output...", 0, menuCallback, (void*)Menu::SETUP_MIDI_OUTPUT},
+           {"Edit sample...", 0, menuCallback, (void*)Menu::EDIT_SAMPLE},
+           {"Edit actions...", 0, menuCallback, (void*)Menu::EDIT_ACTIONS},
+           {"Clear actions", 0, menuCallback, (void*)Menu::CLEAR_ACTIONS, FL_SUBMENU},
+           {"All", 0, menuCallback, (void*)Menu::CLEAR_ACTIONS_ALL},
+           {"Volume", 0, menuCallback, (void*)Menu::CLEAR_ACTIONS_VOLUME},
+           {"Start/Stop", 0, menuCallback, (void*)Menu::CLEAR_ACTIONS_START_STOP},
+           {0},
+           {"Rename", 0, menuCallback, (void*)Menu::RENAME_CHANNEL},
+           {"Clone", 0, menuCallback, (void*)Menu::CLONE_CHANNEL},
+           {"Free", 0, menuCallback, (void*)Menu::FREE_CHANNEL},
+           {"Delete", 0, menuCallback, (void*)Menu::DELETE_CHANNEL},
+           {0}};
+
+       if (m_channel.sample->waveId == 0)
+       {
+               rclick_menu[(int)Menu::EXPORT_SAMPLE].deactivate();
+               rclick_menu[(int)Menu::EDIT_SAMPLE].deactivate();
+               rclick_menu[(int)Menu::FREE_CHANNEL].deactivate();
+               rclick_menu[(int)Menu::RENAME_CHANNEL].deactivate();
        }
 
        if (!m_channel.hasActions)
-               rclick_menu[(int) Menu::CLEAR_ACTIONS].deactivate();
+               rclick_menu[(int)Menu::CLEAR_ACTIONS].deactivate();
 
        /* No 'clear start/stop actions' for those channels in loop mode: they cannot
        have start/stop actions. */
 
        if (m_channel.sample->isLoop)
-               rclick_menu[(int) Menu::CLEAR_ACTIONS_START_STOP].deactivate();
+               rclick_menu[(int)Menu::CLEAR_ACTIONS_START_STOP].deactivate();
 
        Fl_Menu_Button b(0, 0, 100, 50);
        b.box(G_CUSTOM_BORDER_BOX);
@@ -332,10 +350,8 @@ void geSampleChannel::cb_openMenu()
        return;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleChannel::cb_readActions()
 {
        if (Fl::event_shift())
@@ -344,35 +360,33 @@ void geSampleChannel::cb_readActions()
                c::events::toggleReadActionsChannel(m_channel.id, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleChannel::refresh()
 {
        geChannel::refresh();
 
-       if (m_channel.sample->waveId != 0) {
+       if (m_channel.sample->waveId != 0)
+       {
                status->redraw();
-               if (m_channel.sample->a_getOverdubProtection())
+               if (m_channel.sample->getOverdubProtection())
                        arm->deactivate();
                else
                        arm->activate();
        }
 
-       if (m_channel.hasActions) {
+       if (m_channel.hasActions)
+       {
                readActions->activate();
-               readActions->setStatus(m_channel.a_getReadActions());           
+               readActions->setStatus(m_channel.getReadActions());
        }
        else
                readActions->deactivate();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geSampleChannel::draw() 
+void geSampleChannel::draw()
 {
        const int ny = y() + (h() / 2) - (G_GUI_UNIT / 2);
 
@@ -383,10 +397,8 @@ void geSampleChannel::draw()
        geChannel::draw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleChannel::resize(int X, int Y, int W, int H)
 {
        geChannel::resize(X, Y, W, H);
@@ -397,7 +409,7 @@ void geSampleChannel::resize(int X, int Y, int W, int H)
 #ifdef WITH_VST
        fx->hide();
 #endif
-       
+
        if (w() > BREAK_ARM)
                arm->show();
 #ifdef WITH_VST
@@ -411,4 +423,5 @@ void geSampleChannel::resize(int X, int Y, int W, int H)
 
        packWidgets();
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index c0d7db382c1bcb7079e641e08670f1816dd262fe..3b0ec91fdd6c30e79144a09bda41d2f7472273e6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SAMPLE_CHANNEL_H
 #define GE_SAMPLE_CHANNEL_H
 
-
-#include "glue/channel.h"
 #include "channel.h"
+#include "glue/channel.h"
 
-
-class geStatusButton;
-
-
-namespace giada {
-namespace v
+namespace giada::v
 {
+class geStatusButton;
 class geChannelMode;
 class geSampleChannel : public geChannel
 {
 public:
-
        geSampleChannel(int x, int y, int w, int h, c::channel::Data d);
 
        void resize(int x, int y, int w, int h) override;
        void draw() override;
 
-
        void refresh() override;
 
        geChannelMode*  modeBox;
        geStatusButton* readActions;
 
-private:
-
+  private:
        static void cb_playButton(Fl_Widget* /*w*/, void* p);
        static void cb_openMenu(Fl_Widget* /*w*/, void* p);
        static void cb_readActions(Fl_Widget* /*w*/, void* p);
-       void cb_playButton();
-       void cb_openMenu();
-       void cb_readActions();
+       void        cb_playButton();
+       void        cb_openMenu();
+       void        cb_readActions();
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index d7d08cc3c6c683e8f5bcff74c7a9b901a5ef4708..e8c163e9153f9de654489ee99120a205d8be33ba 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include "utils/string.h"
-#include "utils/fs.h"
+#include "sampleChannelButton.h"
 #include "glue/channel.h"
 #include "gui/dialogs/mainWindow.h"
-#include "sampleChannel.h"
 #include "keyboard.h"
-#include "sampleChannelButton.h"
-
+#include "sampleChannel.h"
+#include "utils/fs.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geSampleChannelButton::geSampleChannelButton(int x, int y, int w, int h, const c::channel::Data& d)
 : geChannelButton(x, y, w, h, d)
 {
-       switch (m_channel.a_getPlayStatus()) {
-               case ChannelStatus::MISSING:
-               case ChannelStatus::WRONG:
-                       label("* file not found! *");
-                       break;
-               default:
-                       label(m_channel.sample->waveId == 0 ? "-- no sample --" : m_channel.name.c_str());
-                       break;
+       switch (m_channel.getPlayStatus())
+       {
+       case ChannelStatus::MISSING:
+       case ChannelStatus::WRONG:
+               label("* file not found! *");
+               break;
+       default:
+               label(m_channel.sample->waveId == 0 ? "-- no sample --" : m_channel.name.c_str());
+               break;
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geSampleChannelButton::refresh()
 {
        geChannelButton::refresh();
 
-       if (m_channel.a_isRecordingInput() && m_channel.a_isArmed())
+       if (m_channel.isRecordingInput() && m_channel.isArmed())
                setInputRecordMode();
-       else
-       if (m_channel.a_isRecordingAction() && m_channel.sample->waveId != 0 && !m_channel.sample->isLoop)
+       else if (m_channel.isRecordingAction() && m_channel.sample->waveId != 0 && !m_channel.sample->isLoop)
                setActionRecordMode();
 
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geSampleChannelButton::handle(int e)
 {
        int ret = geButton::handle(e);
-       switch (e) {
-               case FL_DND_ENTER:
-               case FL_DND_DRAG:
-               case FL_DND_RELEASE: {
-                       ret = 1;
-                       break;
-               }
-               case FL_PASTE: {
-                       c::channel::loadChannel(m_channel.id, u::string::trim(u::fs::stripFileUrl(Fl::event_text())));
-                       ret = 1;
-                       break;
-               }
+       switch (e)
+       {
+       case FL_DND_ENTER:
+       case FL_DND_DRAG:
+       case FL_DND_RELEASE:
+       {
+               ret = 1;
+               break;
+       }
+       case FL_PASTE:
+       {
+               c::channel::loadChannel(m_channel.id, u::string::trim(u::fs::stripFileUrl(Fl::event_text())));
+               ret = 1;
+               break;
+       }
        }
        return ret;
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 01b36e723f4796decbcd01f5db354a7a37982738..7f77d0a61347e6a52ca2bb0912cb6a97901fc0ff 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SAMPLE_CHANNEL_BUTTON_H
 #define GE_SAMPLE_CHANNEL_BUTTON_H
 
-
 #include "channelButton.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geSampleChannelButton : public geChannelButton
 {
 public:
-
        geSampleChannelButton(int x, int y, int w, int h, const c::channel::Data& d);
-       
-    int handle(int e) override;
 
-    void refresh() override;
-};
-}} // giada::v::
+       int handle(int e) override;
 
+       void refresh() override;
+};
+} // namespace v
+} // namespace giada
 
 #endif
index 6e44030852ea86bac14f498a4cdd86e2fe5ba43d..f89f8b334b561c0c531b3c455db1d5110fc45d8a 100644 (file)
@@ -4,7 +4,7 @@
 *
 * ------------------------------------------------------------------------------
 *
-* Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+* Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
 *
 * This file is part of Giada - Your Hardcore Loopmachine.
 *
 *
 * --------------------------------------------------------------------------- */
 
-
+#include "mainIO.h"
 #include "core/const.h"
 #include "core/graphics.h"
+#include "glue/channel.h"
 #include "glue/events.h"
 #include "glue/main.h"
-#include "glue/channel.h"
-#include "utils/gui.h"
-#include "gui/elems/soundMeter.h"
-#include "gui/elems/basics/statusButton.h"
-#include "gui/elems/basics/dial.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/pluginList.h"
-#include "mainIO.h"
-
+#include "gui/elems/basics/dial.h"
+#include "gui/elems/basics/statusButton.h"
+#include "gui/elems/soundMeter.h"
+#include "utils/gui.h"
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geMainIO::geMainIO(int x, int y)
-: gePack     (x, y, Direction::HORIZONTAL)
-, outMeter   (0, 0, 140, G_GUI_UNIT)
-, inMeter    (0, 0, 140, G_GUI_UNIT)
-, outVol     (0, 0, G_GUI_UNIT, G_GUI_UNIT)
-, inVol      (0, 0, G_GUI_UNIT, G_GUI_UNIT)
-, inToOut    (0, 0, 12, G_GUI_UNIT, "")
+: gePack(x, y, Direction::HORIZONTAL)
+, outMeter(0, 0, 140, G_GUI_UNIT)
+, inMeter(0, 0, 140, G_GUI_UNIT)
+, outVol(0, 0, G_GUI_UNIT, G_GUI_UNIT)
+, inVol(0, 0, G_GUI_UNIT, G_GUI_UNIT)
+, inToOut(0, 0, 12, G_GUI_UNIT, "")
 #ifdef WITH_VST
 , masterFxOut(0, 0, G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm)
-, masterFxIn (0, 0, G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm)
+, masterFxIn(0, 0, G_GUI_UNIT, G_GUI_UNIT, fxOff_xpm, fxOn_xpm)
 #endif
 {
 #ifdef WITH_VST
@@ -69,7 +67,17 @@ geMainIO::geMainIO(int x, int y)
        add(&masterFxOut);
 #endif
 
-       resizable(nullptr);   // don't resize any widget
+       resizable(nullptr); // don't resize any widget
+
+       outMeter.copy_tooltip("Main output meter");
+       inMeter.copy_tooltip("Main input meter");
+       outVol.copy_tooltip("Main output volume");
+       inVol.copy_tooltip("Main input volume");
+       inToOut.copy_tooltip("Stream linker\n\nConnects input to output to enable \"hear what you're playing\" mode.");
+#ifdef WITH_VST
+       masterFxOut.copy_tooltip("Main output plug-ins");
+       masterFxIn.copy_tooltip("Main input plug-ins");
+#endif
 
        outVol.callback(cb_outVol, (void*)this);
        inVol.callback(cb_inVol, (void*)this);
@@ -83,34 +91,31 @@ geMainIO::geMainIO(int x, int y)
 #endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geMainIO::cb_outVol     (Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_outVol(); }
-void geMainIO::cb_inVol      (Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_inVol(); }
-void geMainIO::cb_inToOut    (Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_inToOut(); }
+void geMainIO::cb_outVol(Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_outVol(); }
+void geMainIO::cb_inVol(Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_inVol(); }
+void geMainIO::cb_inToOut(Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_inToOut(); }
 #ifdef WITH_VST
-void geMainIO::cb_masterFxOut(Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_masterFxOut(); }
-void geMainIO::cb_masterFxIn (Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_masterFxIn(); }
+void geMainIO::cb_masterFxOut(Fl_Widget* /*w*/, void* p)
+{
+       ((geMainIO*)p)->cb_masterFxOut();
+}
+void geMainIO::cb_masterFxIn(Fl_Widget* /*w*/, void* p) { ((geMainIO*)p)->cb_masterFxIn(); }
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainIO::cb_outVol()
 {
        c::events::setMasterOutVolume(outVol.value(), Thread::MAIN);
 }
 
-
 void geMainIO::cb_inVol()
 {
        c::events::setMasterInVolume(inVol.value(), Thread::MAIN);
 }
 
-
 void geMainIO::cb_inToOut()
 {
        c::main::setInToOut(inToOut.value());
@@ -118,7 +123,6 @@ void geMainIO::cb_inToOut()
 
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 void geMainIO::cb_masterFxOut()
@@ -126,7 +130,6 @@ void geMainIO::cb_masterFxOut()
        u::gui::openSubWindow(G_MainWin, new v::gdPluginList(m::mixer::MASTER_OUT_CHANNEL_ID), WID_FX_LIST);
 }
 
-
 void geMainIO::cb_masterFxIn()
 {
        u::gui::openSubWindow(G_MainWin, new v::gdPluginList(m::mixer::MASTER_IN_CHANNEL_ID), WID_FX_LIST);
@@ -134,25 +137,20 @@ void geMainIO::cb_masterFxIn()
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainIO::setOutVol(float v)
 {
        outVol.value(v);
 }
 
-
 void geMainIO::setInVol(float v)
 {
        inVol.value(v);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
 void geMainIO::setMasterFxOutFull(bool v)
@@ -160,7 +158,6 @@ void geMainIO::setMasterFxOutFull(bool v)
        masterFxOut.setStatus(v);
 }
 
-
 void geMainIO::setMasterFxInFull(bool v)
 {
        masterFxIn.setStatus(v);
@@ -168,22 +165,18 @@ void geMainIO::setMasterFxInFull(bool v)
 
 #endif
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainIO::refresh()
 {
-       outMeter.mixerPeak = m_io.a_getMasterOutPeak(); 
-       inMeter.mixerPeak  = m_io.a_getMasterInPeak();
+       outMeter.mixerPeak = m_io.getMasterOutPeak();
+       inMeter.mixerPeak  = m_io.getMasterInPeak();
        outMeter.redraw();
        inMeter.redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainIO::rebuild()
 {
        m_io = c::main::getIO();
@@ -196,4 +189,5 @@ void geMainIO::rebuild()
        inToOut.value(m_io.inToOut);
 #endif
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index f393498010f036dd363fda15c617bc49984db8d4..589bd9938b7ee5a43459ec5577bd23cb9ce37558 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MAIN_IO_H
 #define GE_MAIN_IO_H
 
-
-#include "gui/elems/soundMeter.h"
-#include "gui/elems/basics/pack.h"
-#include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/dial.h"
+#include "gui/elems/basics/pack.h"
+#include "gui/elems/soundMeter.h"
 #ifdef WITH_VST
 #include "gui/elems/basics/statusButton.h"
 #endif
 #include "glue/main.h"
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geMainIO : public gePack
 {
 public:
-
        geMainIO(int x, int y);
 
        void refresh();
        void rebuild();
 
        void setOutVol(float v);
-       void setInVol (float v);
+       void setInVol(float v);
 #ifdef WITH_VST
        void setMasterFxOutFull(bool v);
        void setMasterFxInFull(bool v);
 #endif
 
-private:
-
-       static void cb_outVol (Fl_Widget* /*w*/, void* p);
-       static void cb_inVol  (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_outVol(Fl_Widget* /*w*/, void* p);
+       static void cb_inVol(Fl_Widget* /*w*/, void* p);
        static void cb_inToOut(Fl_Widget* /*w*/, void* p);
-       void cb_outVol();
-       void cb_inVol();
-       void cb_inToOut();
+       void        cb_outVol();
+       void        cb_inVol();
+       void        cb_inToOut();
 #ifdef WITH_VST
        static void cb_masterFxOut(Fl_Widget* /*w*/, void* p);
-       static void cb_masterFxIn (Fl_Widget* /*w*/, void* p);
-       void cb_masterFxOut();
-       void cb_masterFxIn();
+       static void cb_masterFxIn(Fl_Widget* /*w*/, void* p);
+       void        cb_masterFxOut();
+       void        cb_masterFxIn();
 #endif
 
        c::main::IO m_io;
 
-       geSoundMeter   outMeter;
-       geSoundMeter   inMeter;
-       geDial         outVol;
-       geDial         inVol;
-       geButton       inToOut;
+       geSoundMeter outMeter;
+       geSoundMeter inMeter;
+       geDial       outVol;
+       geDial       inVol;
+       geButton     inToOut;
 #ifdef WITH_VST
        geStatusButton masterFxOut;
        geStatusButton masterFxIn;
 #endif
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index dfdedf4ea00c289537c0e961eabe66f4896047af..501555159a109aef254010ffb8112917b9b5e33d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl_Menu_Button.H>
-#include "core/model/model.h"
+#include "mainMenu.h"
+#include "core/conf.h"
 #include "core/const.h"
 #include "core/mixer.h"
 #include "core/mixerHandler.h"
-#include "core/conf.h"
+#include "core/model/model.h"
 #include "core/patch.h"
-#include "utils/gui.h"
-#include "glue/storage.h"
 #include "glue/main.h"
-#include "gui/elems/basics/boxtypes.h"
-#include "gui/elems/basics/button.h"
-#include "gui/dialogs/mainWindow.h"
+#include "glue/storage.h"
 #include "gui/dialogs/about.h"
-#include "gui/dialogs/config.h"
-#include "gui/dialogs/warnings.h"
 #include "gui/dialogs/browser/browserLoad.h"
 #include "gui/dialogs/browser/browserSave.h"
+#include "gui/dialogs/config.h"
+#include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/midiIO/midiInputMaster.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/elems/basics/boxtypes.h"
+#include "gui/elems/basics/button.h"
 #include "keyboard/keyboard.h"
-#include "mainMenu.h"
-
+#include "utils/gui.h"
+#include <FL/Fl_Menu_Button.H>
+#include <cassert>
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 geMainMenu::geMainMenu(int x, int y)
@@ -67,30 +65,26 @@ geMainMenu::geMainMenu(int x, int y)
        add(config);
        add(about);
 
-       resizable(nullptr);   // don't resize any widget
+       resizable(nullptr); // don't resize any widget
 
        file->callback(cb_file, (void*)this);
        edit->callback(cb_edit, (void*)this);
 
-       about->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       about->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                u::gui::openSubWindow(G_MainWin, new gdAbout(), WID_ABOUT);
        });
-       config->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       config->callback([](Fl_Widget* /*w*/, void* /*v*/) {
                u::gui::openSubWindow(G_MainWin, new gdConfig(400, 370), WID_CONFIG);
        });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainMenu::cb_file(Fl_Widget* /*w*/, void* p) { ((geMainMenu*)p)->cb_file(); }
 void geMainMenu::cb_edit(Fl_Widget* /*w*/, void* p) { ((geMainMenu*)p)->cb_edit(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainMenu::cb_file()
 {
        using namespace giada::m;
@@ -98,15 +92,14 @@ void geMainMenu::cb_file()
        /* An Fl_Menu_Button is made of many Fl_Menu_Item */
 
        Fl_Menu_Item menu[] = {
-               {"Open project..."},
-               {"Save project..."},
-               {"Close project"},
+           {"Open project..."},
+           {"Save project..."},
+           {"Close project"},
 #ifndef NDEBUG
-               {"Debug stats"},
+           {"Debug stats"},
 #endif
-               {"Quit Giada"},
-               {0}
-       };
+           {"Quit Giada"},
+           {0}};
 
        Fl_Menu_Button b(0, 0, 100, 50);
        b.box(G_CUSTOM_BORDER_BOX);
@@ -114,54 +107,55 @@ void geMainMenu::cb_file()
        b.textcolor(G_COLOR_LIGHT_2);
        b.color(G_COLOR_GREY_2);
 
-       const Fl_Menu_Item* m = menu->popup(Fl::event_x(),      Fl::event_y(), 0, 0, &b);
-       if (!m) return;
+       const Fl_Menu_Item* m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, &b);
+       if (!m)
+               return;
 
-       if (strcmp(m->label(), "Open project...") == 0) {
-               gdWindow* childWin = new gdBrowserLoad("Open project", 
-                       conf::conf.patchPath, c::storage::loadProject, 0);
+       if (strcmp(m->label(), "Open project...") == 0)
+       {
+               gdWindow* childWin = new gdBrowserLoad("Open project",
+                   conf::conf.patchPath, c::storage::loadProject, 0);
                u::gui::openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
        }
-       else
-       if (strcmp(m->label(), "Save project...") == 0) {
-               gdWindow* childWin = new gdBrowserSave("Save project", conf::conf.patchPath, 
-                       patch::patch.name, c::storage::saveProject, 0);
+       else if (strcmp(m->label(), "Save project...") == 0)
+       {
+               gdWindow* childWin = new gdBrowserSave("Save project", conf::conf.patchPath,
+                   patch::patch.name, c::storage::saveProject, 0);
                u::gui::openSubWindow(G_MainWin, childWin, WID_FILE_BROWSER);
        }
-       else
-       if (strcmp(m->label(), "Close project") == 0) {
+       else if (strcmp(m->label(), "Close project") == 0)
+       {
                c::main::closeProject();
        }
 #ifndef NDEBUG
-       else
-       if (strcmp(m->label(), "Debug stats") == 0) {
+       else if (strcmp(m->label(), "Debug stats") == 0)
+       {
                m::model::debug();
        }
 #endif
-       else
-       if (strcmp(m->label(), "Quit Giada") == 0) {
+       else if (strcmp(m->label(), "Quit Giada") == 0)
+       {
                G_MainWin->do_callback();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainMenu::cb_edit()
 {
        Fl_Menu_Item menu[] = {
-               {"Free all Sample channels"},
-               {"Clear all actions"},
-               {"Setup global MIDI input..."},
-               {0}
-       };
+           {"Free all Sample channels"},
+           {"Clear all actions"},
+           {"Setup global MIDI input..."},
+           {0}};
 
        menu[0].deactivate();
        menu[1].deactivate();
 
-       if (m::mh::hasAudioData()) menu[0].activate();
-       if (m::mh::hasActions())   menu[1].activate();
+       if (m::mh::hasAudioData())
+               menu[0].activate();
+       if (m::mh::hasActions())
+               menu[1].activate();
 
        Fl_Menu_Button b(0, 0, 100, 50);
        b.box(G_CUSTOM_BORDER_BOX);
@@ -170,16 +164,16 @@ void geMainMenu::cb_edit()
        b.color(G_COLOR_GREY_2);
 
        const Fl_Menu_Item* m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, &b);
-       if (!m) return;
+       if (!m)
+               return;
 
-       if (strcmp(m->label(), "Free all Sample channels") == 0) 
+       if (strcmp(m->label(), "Free all Sample channels") == 0)
                c::main::clearAllSamples();
-       else
-       if (strcmp(m->label(), "Clear all actions") == 0) 
+       else if (strcmp(m->label(), "Clear all actions") == 0)
                c::main::clearAllActions();
-       else
-       if (strcmp(m->label(), "Setup global MIDI input...") == 0) 
+       else if (strcmp(m->label(), "Setup global MIDI input...") == 0)
                u::gui::openSubWindow(G_MainWin, new gdMidiInputMaster(), WID_MIDI_INPUT);
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 9983aabc2d6767b4ae29822b6d96c1a3c43f2811..c6a317ed97ffe1255f9f2e81472fb97f13e77df8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MAIN_MENU_H
 #define GE_MAIN_MENU_H
 
-
 #include "gui/elems/basics/pack.h"
 
-
 class geButton;
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geMainMenu : public gePack
 {
 public:
-
        geMainMenu(int x, int y);
 
-private:
-
+  private:
        static void cb_file(Fl_Widget* /*w*/, void* p);
        static void cb_edit(Fl_Widget* /*w*/, void* p);
-       void cb_file();
-       void cb_edit();
+       void        cb_file();
+       void        cb_edit();
 
        geButton* file;
        geButton* edit;
        geButton* config;
        geButton* about;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 644b50529831359ad24c8c92a19882079c7e99a6..3faef6126929e7bc868e0b72ba3d5ebfb159b608 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "mainTimer.h"
+#include "core/clock.h"
 #include "core/const.h"
 #include "core/graphics.h"
-#include "core/clock.h"
-#include "glue/main.h"
 #include "glue/events.h"
-#include "utils/gui.h"
-#include "utils/string.h"
+#include "glue/main.h"
+#include "gui/dialogs/beatsInput.h"
+#include "gui/dialogs/bpmInput.h"
+#include "gui/dialogs/mainWindow.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
-#include "gui/dialogs/mainWindow.h"
-#include "gui/dialogs/bpmInput.h"
-#include "gui/dialogs/beatsInput.h"
-#include "mainTimer.h"
-
+#include "utils/gui.h"
+#include "utils/string.h"
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 geMainTimer::geMainTimer(int x, int y)
-: gePack      (x, y, Direction::HORIZONTAL)
-, m_bpm       (0, 0, 60, G_GUI_UNIT)
-, m_meter     (0, 0, 60, G_GUI_UNIT)
-, m_quantizer (0, 0, 60, G_GUI_UNIT, "", false)
+: gePack(x, y, Direction::HORIZONTAL)
+, m_bpm(0, 0, 60, G_GUI_UNIT)
+, m_meter(0, 0, 60, G_GUI_UNIT)
+, m_quantizer(0, 0, 60, G_GUI_UNIT, "", false)
 , m_multiplier(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", multiplyOff_xpm, multiplyOn_xpm)
-, m_divider   (0, 0, G_GUI_UNIT, G_GUI_UNIT, "", divideOff_xpm, divideOn_xpm)
+, m_divider(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", divideOff_xpm, divideOn_xpm)
 {
        add(&m_quantizer);
        add(&m_bpm);
@@ -60,11 +56,17 @@ geMainTimer::geMainTimer(int x, int y)
        add(&m_multiplier);
        add(&m_divider);
 
-       resizable(nullptr);   // don't resize any widget
+       resizable(nullptr); // don't resize any widget
+
+       m_bpm.copy_tooltip("Beats per minute (BPM)");
+       m_meter.copy_tooltip("Beats and bars");
+       m_quantizer.copy_tooltip("Live quantizer");
+       m_multiplier.copy_tooltip("Beat multiplier");
+       m_divider.copy_tooltip("Beat divider");
 
        m_bpm.callback(cb_bpm, (void*)this);
        m_meter.callback(cb_meter, (void*)this);
-       m_multiplier.callback(cb_multiplier, (void*)this);      
+       m_multiplier.callback(cb_multiplier, (void*)this);
        m_divider.callback(cb_divider, (void*)this);
 
        m_quantizer.add("off", 0, cb_quantizer, (void*)this);
@@ -77,95 +79,73 @@ geMainTimer::geMainTimer(int x, int y)
        m_quantizer.value(0); //  "off" by default
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geMainTimer::cb_bpm       (Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_bpm(); }
-void geMainTimer::cb_meter     (Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_meter(); }
-void geMainTimer::cb_quantizer (Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_quantizer(); }
+void geMainTimer::cb_bpm(Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_bpm(); }
+void geMainTimer::cb_meter(Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_meter(); }
+void geMainTimer::cb_quantizer(Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_quantizer(); }
 void geMainTimer::cb_multiplier(Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_multiplier(); }
-void geMainTimer::cb_divider   (Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_divider(); }
-
+void geMainTimer::cb_divider(Fl_Widget* /*w*/, void* p) { ((geMainTimer*)p)->cb_divider(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::cb_bpm()
 {
        u::gui::openSubWindow(G_MainWin, new gdBpmInput(m_bpm.label()), WID_BPM);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::cb_meter()
 {
        u::gui::openSubWindow(G_MainWin, new gdBeatsInput(), WID_BEATS);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::cb_quantizer()
 {
        c::main::quantize(m_quantizer.value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::cb_multiplier()
 {
        c::events::multiplyBeats();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::cb_divider()
 {
        c::events::divideBeats();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::refresh()
 {
        m_timer = c::main::getTimer();
 
-       if (m_timer.isRecordingInput) {
+       if (m_timer.isRecordingInput)
+       {
                m_bpm.deactivate();
                m_meter.deactivate();
                m_multiplier.deactivate();
                m_divider.deactivate();
        }
-       else {
-#if defined(G_OS_LINUX) || defined(G_OS_FREEBSD)
-               /* Don't reactivate m_bpm when using JACK. It must stay disabled. */
-               if (m_timer.isUsingJack)
-                       m_bpm.deactivate();
-               else
-                       m_bpm.activate();
-#else
+       else
+       {
                m_bpm.activate();
-#endif
-               m_meter.activate();     
+               m_meter.activate();
                m_multiplier.activate();
-               m_divider.activate();   
+               m_divider.activate();
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::rebuild()
 {
        m_timer = c::main::getTimer();
@@ -173,66 +153,52 @@ void geMainTimer::rebuild()
        setBpm(m_timer.bpm);
        setMeter(m_timer.beats, m_timer.bars);
        setQuantizer(m_timer.quantize);
-
-#if defined(G_OS_LINUX) || defined(G_OS_FREEBSD)
-       /* Can't change m_bpm from within Giada when using JACK. */
-       if (m_timer.isUsingJack)
-               m_bpm.deactivate();
-#endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::setBpm(const char* v)
 {
        m_bpm.copy_label(v);
 }
 
-
 void geMainTimer::setBpm(float v)
 {
-       m_bpm.copy_label(u::string::fToString((float) v, 1).c_str()); // Only 1 decimal place (e.g. 120.0)
+       m_bpm.copy_label(u::string::fToString(v, 1).c_str()); // Only 1 decimal place (e.g. 120.0)
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::setLock(bool v)
 {
-  if (v) {
-    m_bpm.deactivate();
-    m_meter.deactivate();
-    m_multiplier.deactivate();
-    m_divider.deactivate();
-  }
-  else {
-    m_bpm.activate();
-    m_meter.activate();
-    m_multiplier.activate();
-    m_divider.activate();
-  }
+       if (v)
+       {
+               m_bpm.deactivate();
+               m_meter.deactivate();
+               m_multiplier.deactivate();
+               m_divider.deactivate();
+       }
+       else
+       {
+               m_bpm.activate();
+               m_meter.activate();
+               m_multiplier.activate();
+               m_divider.activate();
+       }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::setQuantizer(int q)
 {
        m_quantizer.value(q);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTimer::setMeter(int beats, int bars)
 {
        std::string s = std::to_string(beats) + "/" + std::to_string(bars);
        m_meter.copy_label(s.c_str());
 }
-
-}} // giada::v::
+} // namespace giada::v
index 06df513c2af229b5cff968562e8d09cb5de7d112..f92feb3c1c8e4f8c691decdd42d021bee2364e82 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MAIN_TIMER_H
 #define GE_MAIN_TIMER_H
 
-
 #include "glue/main.h"
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
-
+#include "gui/elems/basics/pack.h"
 
 class geButton;
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 class geChoice;
 class geMainTimer : public gePack
 {
 public:
-
        geMainTimer(int x, int y);
-       
+
        void refresh();
        void rebuild();
 
@@ -61,18 +55,17 @@ public:
 
        void setLock(bool v);
 
-private:
-
-       static void cb_bpm       (Fl_Widget* /*w*/, void* p);
-       static void cb_meter     (Fl_Widget* /*w*/, void* p);
-       static void cb_quantizer (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_bpm(Fl_Widget* /*w*/, void* p);
+       static void cb_meter(Fl_Widget* /*w*/, void* p);
+       static void cb_quantizer(Fl_Widget* /*w*/, void* p);
        static void cb_multiplier(Fl_Widget* /*w*/, void* p);
-       static void cb_divider   (Fl_Widget* /*w*/, void* p);
-       void cb_bpm();
-       void cb_meter();
-       void cb_quantizer();
-       void cb_multiplier();
-       void cb_divider();
+       static void cb_divider(Fl_Widget* /*w*/, void* p);
+       void        cb_bpm();
+       void        cb_meter();
+       void        cb_quantizer();
+       void        cb_multiplier();
+       void        cb_divider();
 
        c::main::Timer m_timer;
 
@@ -82,7 +75,6 @@ private:
        geButton m_multiplier;
        geButton m_divider;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 3f1bdce93e52474c51e151f1fb0a1e8aa2db8dc5..441aa7a7efca7b388ff414ca8b20e3f373282ea5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include "core/graphics.h"
-#include "core/conf.h"
+#include "mainTransport.h"
 #include "core/clock.h"
-#include "core/sequencer.h"
+#include "core/conf.h"
+#include "core/const.h"
+#include "core/graphics.h"
 #include "core/mixer.h"
 #include "core/mixerHandler.h"
 #include "core/recManager.h"
-#include "core/conf.h"
-#include "core/const.h"
-#include "glue/main.h"
+#include "core/sequencer.h"
 #include "glue/events.h"
-#include "gui/elems/basics/button.h"
+#include "glue/main.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/statusButton.h"
-#include "mainTransport.h"
-
 
-namespace giada {
-namespace v
+namespace giada::v
 {
 geMainTransport::geMainTransport(int x, int y)
 : gePack(x, y, Direction::HORIZONTAL)
+, m_rewind(0, 0, 25, 25, "", rewindOff_xpm, rewindOn_xpm)
+, m_play(0, 0, 25, 25, play_xpm, pause_xpm)
+, m_spacer1(0, 0, 10, 25)
+, m_recTriggerMode(0, 0, 15, 25, recTriggerModeOff_xpm, recTriggerModeOn_xpm)
+, m_recAction(0, 0, 25, 25, recOff_xpm, recOn_xpm)
+, m_recInput(0, 0, 25, 25, inputRecOff_xpm, inputRecOn_xpm)
+, m_inputRecMode(0, 0, 15, 25, freeInputRecOff_xpm, freeInputRecOn_xpm)
+, m_spacer2(0, 0, 10, 25)
+, m_metronome(0, 0, 15, 25, metronomeOff_xpm, metronomeOn_xpm)
 {
-       rewind         = new geButton      (0, 0, 25, 25, "", rewindOff_xpm, rewindOn_xpm);
-       play           = new geStatusButton(0, 0, 25, 25, play_xpm, pause_xpm);
-       spacer1        = new geBox         (0, 0, 10, 25);
-       recTriggerMode = new geStatusButton(0, 0, 15, 25, recTriggerModeOff_xpm, recTriggerModeOn_xpm);
-       recAction      = new geStatusButton(0, 0, 25, 25, recOff_xpm, recOn_xpm);
-       recInput       = new geStatusButton(0, 0, 25, 25, inputRecOff_xpm, inputRecOn_xpm);
-       spacer2        = new geBox         (0, 0, 10, 25);
-       metronome      = new geStatusButton(0, 0, 15, 25, metronomeOff_xpm, metronomeOn_xpm);
-       add(rewind);
-       add(play);
-       add(spacer1);
-       add(recTriggerMode);
-       add(recAction);
-       add(recInput);
-       add(spacer2);
-       add(metronome);
-       
-       rewind->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       add(&m_rewind);
+       add(&m_play);
+       add(&m_spacer1);
+       add(&m_recTriggerMode);
+       add(&m_recAction);
+       add(&m_recInput);
+       add(&m_inputRecMode);
+       add(&m_spacer2);
+       add(&m_metronome);
+
+       m_rewind.copy_tooltip("Rewind");
+       m_play.copy_tooltip("Play/Stop");
+       m_recTriggerMode.copy_tooltip("Record-on-signal mode\n\nIf enabled, action "
+                                     "and audio recording will start only when a signal (key press or audio) "
+                                     "is detected.");
+       m_recAction.copy_tooltip("Record actions");
+       m_recInput.copy_tooltip("Record audio");
+       m_inputRecMode.copy_tooltip("Free loop-length mode\n\nIf enabled, the sequencer "
+                                   "will adjust to the length of your first audio recording. "
+                                   "Available only if there are no other audio samples in the "
+                                   "project.");
+       m_metronome.copy_tooltip("Metronome");
+
+       m_rewind.callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::rewindSequencer(Thread::MAIN);
        });
 
-       play->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       m_play.callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleSequencer(Thread::MAIN);
        });
 
-       recAction->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       m_recAction.callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleActionRecording();
        });
 
-       recInput->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       m_recInput.callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleInputRecording();
        });
 
-       recTriggerMode->callback([](Fl_Widget* /*w*/, void* /*v*/) { 
+       m_recTriggerMode.callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::main::toggleRecOnSignal();
        });
 
-       metronome->type(FL_TOGGLE_BUTTON);
-       metronome->callback([](Fl_Widget* /*w*/, void* /*v*/) {
+       m_inputRecMode.callback([](Fl_Widget* /*w*/, void* /*v*/) {
+               c::main::toggleFreeInputRec();
+       });
+
+       m_metronome.type(FL_TOGGLE_BUTTON);
+       m_metronome.callback([](Fl_Widget* /*w*/, void* /*v*/) {
                c::events::toggleMetronome();
        });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMainTransport::refresh()
 {
-       play->setStatus(m::clock::isRunning());
-       recAction->setStatus(m::recManager::isRecordingAction());
-       recInput->setStatus(m::recManager::isRecordingInput());
-       metronome->setStatus(m::sequencer::isMetronomeOn());
-       recTriggerMode->setStatus(m::conf::conf.recTriggerMode == RecTriggerMode::SIGNAL);
+       m_play.setStatus(m::clock::isRunning());
+       m_recAction.setStatus(m::recManager::isRecordingAction());
+       m_recInput.setStatus(m::recManager::isRecordingInput());
+       m_metronome.setStatus(m::sequencer::isMetronomeOn());
+       m_recTriggerMode.setStatus(m::conf::conf.recTriggerMode == RecTriggerMode::SIGNAL);
+       m_inputRecMode.setStatus(m::conf::conf.inputRecMode == InputRecMode::FREE);
 }
-}} // giada::v::
+} // namespace giada::v
index 063f206a839f7a64b7fe5e0b469cbb5bc0d67470..730f4506df42f5e0a6cb2605440ee92a2706a96a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MAIN_TRANSPORT_H
 #define GE_MAIN_TRANSPORT_H
 
-
+#include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/pack.h"
+#include "gui/elems/basics/statusButton.h"
 
-
-class geButton;
-class geBox;
-class geStatusButton;
-
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 class geMainTransport : public gePack
 {
 public:
-
        geMainTransport(int x, int y);
 
        void refresh();
 
 private:
-
-       geButton* rewind;
-       geStatusButton* play;
-       geBox* spacer1; 
-       geStatusButton* recTriggerMode;
-       geStatusButton* recAction;
-       geStatusButton* recInput;
-       geBoxspacer2;
-       geStatusButtonmetronome;
+       geButton       m_rewind;
+       geStatusButton m_play;
+       geBox          m_spacer1;
+       geStatusButton m_recTriggerMode;
+       geStatusButton m_recAction;
+       geStatusButton m_recInput;
+       geStatusButton m_inputRecMode;
+       geBox          m_spacer2;
+       geStatusButton m_metronome;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
diff --git a/src/gui/elems/mainWindow/sequencer.cpp b/src/gui/elems/mainWindow/sequencer.cpp
new file mode 100644 (file)
index 0000000..3c25100
--- /dev/null
@@ -0,0 +1,127 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * beatMeter
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "sequencer.h"
+#include "core/const.h"
+#include "gui/drawing.h"
+#include "utils/math.h"
+#include <FL/fl_draw.H>
+
+namespace giada::v
+{
+geSequencer::geSequencer(int x, int y, int w, int h)
+: Fl_Box(x, y, w, h)
+{
+       copy_tooltip("Main sequencer");
+}
+
+/* -------------------------------------------------------------------------- */
+
+void geSequencer::refresh()
+{
+       m_data = c::main::getSequencer();
+       redraw();
+}
+
+/* -------------------------------------------------------------------------- */
+
+void geSequencer::draw()
+{
+       m_background = geompp::Rect(x(), y(), w(), h());
+       m_cell       = geompp::Rect(x(), y(), w() / G_MAX_BEATS, h()).reduced(0, REC_BARS_H);
+
+       /* Cleanup */
+       drawRectf(m_background, FL_BACKGROUND_COLOR);
+
+       if (m_data.isFreeModeInputRec)
+               drawRecBars();
+
+       drawBody();
+       drawCursor();
+}
+
+/* -------------------------------------------------------------------------- */
+
+void geSequencer::drawBody() const
+{
+       const geompp::Rect body = m_background.reduced(0, REC_BARS_H);
+       const geompp::Line line = m_cell.getHeightAsLine();
+
+       /* Background and borders. */
+
+       drawRectf(body, FL_BACKGROUND_COLOR);
+       drawRect(body, G_COLOR_GREY_4);
+
+       /* Beat lines. */
+
+       for (int i = 1; i <= m_data.beats; i++)
+               drawLine(line.withShiftedX(m_cell.w * i), G_COLOR_GREY_4);
+
+       /* Bar lines. */
+
+       const int delta = m_data.beats / m_data.bars;
+       for (int i = 1; i < m_data.bars; i++)
+               drawLine(line.withShiftedX(m_cell.w * i * delta), G_COLOR_LIGHT_1);
+
+       /* Unused grey area. */
+
+       drawRectf(body.withTrimmedLeft(m_data.beats * m_cell.w), G_COLOR_GREY_4);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void geSequencer::drawRecBars() const
+{
+       int length = u::math::map(m_data.recPosition, m_data.recMaxLength, w());
+
+       drawRectf(geompp::Rect(x(), y(), length, h()), G_COLOR_LIGHT_1);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void geSequencer::drawCursor(int beat, Fl_Color color) const
+{
+       // TODO withW(...): FLTK glitch?
+       drawRectf(m_cell.withShiftedX(beat * m_cell.w).reduced(CURSOR_PAD).withW(m_cell.w - CURSOR_PAD - 2), color);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void geSequencer::drawCursor() const
+{
+       Fl_Color color = m_data.shouldBlink ? FL_BACKGROUND_COLOR : G_COLOR_LIGHT_1;
+
+       if (m_data.isFreeModeInputRec)
+       {
+               for (int i = 0; i < m_data.beats; i++)
+                       drawCursor(i, color);
+       }
+       else
+               drawCursor(m_data.currentBeat, color);
+}
+} // namespace giada::v
diff --git a/src/gui/elems/mainWindow/sequencer.h b/src/gui/elems/mainWindow/sequencer.h
new file mode 100644 (file)
index 0000000..a91d4bb
--- /dev/null
@@ -0,0 +1,64 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * beatMeter
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of Giada - Your Hardcore Loopmachine.
+ *
+ * Giada - Your Hardcore Loopmachine is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Giada - Your Hardcore Loopmachine is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Giada - Your Hardcore Loopmachine. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef GE_SEQUENCER_H
+#define GE_SEQUENCER_H
+
+#include "core/types.h"
+#include "deps/geompp/src/rect.hpp"
+#include "glue/main.h"
+#include <FL/Fl_Box.H>
+
+namespace giada::v
+{
+class geSequencer : public Fl_Box
+{
+public:
+       geSequencer(int x, int y, int w, int h);
+
+       void draw() override;
+
+       void refresh();
+
+private:
+       static constexpr int REC_BARS_H = 3;
+       static constexpr int CURSOR_PAD = 3;
+
+       void drawBody() const;
+       void drawCursor() const;
+       void drawCursor(int beat, Fl_Color col) const;
+       void drawRecBars() const;
+
+       c::main::Sequencer m_data;
+
+       geompp::Rect<int> m_background;
+       geompp::Rect<int> m_cell;
+};
+} // namespace giada::v
+
+#endif
index 17070a07a86def3082a3d8162833eff3bcf303dc..6093aa51e9637ece4be1e1f83e410edbe47647d8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include "utils/string.h"
-#include "gui/elems/basics/boxtypes.h"
+#include "midiLearner.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/button.h"
-#include "midiLearner.h"
-
+#include "utils/string.h"
+#include <cassert>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geMidiLearner::geMidiLearner(int x, int y, std::string l, int param)
-: gePack      (x, y, Direction::HORIZONTAL)
+: gePack(x, y, Direction::HORIZONTAL)
 , onStartLearn(nullptr)
-, onStopLearn (nullptr)
+, onStopLearn(nullptr)
 , onClearLearn(nullptr)
-, m_param     (param)
-, m_text      (0, 0, 146, 20, l.c_str())
-, m_valueBtn  (0, 0, 80, 20)
-, m_button    (0, 0, 50, 20, "learn")
+, m_param(param)
+, m_text(0, 0, 146, 20, l.c_str())
+, m_valueBtn(0, 0, 80, 20)
+, m_button(0, 0, 50, 20, "learn")
 {
        add(&m_text);
        add(&m_valueBtn);
@@ -60,35 +59,30 @@ geMidiLearner::geMidiLearner(int x, int y, std::string l, int param)
        m_button.callback(cb_button, (void*)this);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearner::cb_button(Fl_Widget* /*w*/, void* p) { ((geMidiLearner*)p)->onLearn(); }
-void geMidiLearner::cb_value(Fl_Widget* /*w*/, void* p)  { ((geMidiLearner*)p)->onReset(); }
-
+void geMidiLearner::cb_value(Fl_Widget* /*w*/, void* p) { ((geMidiLearner*)p)->onReset(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearner::update(uint32_t value)
 {
        std::string tmp = "(not set)";
-       
-       if (value != 0x0) {
+
+       if (value != 0x0)
+       {
                tmp = "0x" + u::string::iToString(value, /*hex=*/true);
-               tmp.pop_back();  // Remove last two digits, useless in MIDI messages
-               tmp.pop_back();  // Remove last two digits, useless in MIDI messages
+               tmp.pop_back(); // Remove last two digits, useless in MIDI messages
+               tmp.pop_back(); // Remove last two digits, useless in MIDI messages
        }
 
        m_valueBtn.copy_label(tmp.c_str());
-       m_button.value(0);      
+       m_button.value(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearner::activate()
 {
        Fl_Group::activate();
@@ -96,7 +90,6 @@ void geMidiLearner::activate()
        m_button.activate();
 }
 
-
 void geMidiLearner::deactivate()
 {
        Fl_Group::deactivate();
@@ -104,10 +97,8 @@ void geMidiLearner::deactivate()
        m_button.deactivate();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearner::onLearn() const
 {
        assert(onStartLearn != nullptr);
@@ -119,15 +110,14 @@ void geMidiLearner::onLearn() const
                onStopLearn();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearner::onReset() const
 {
        assert(onClearLearn != nullptr);
 
        if (Fl::event_button() == FL_RIGHT_MOUSE)
-               onClearLearn(m_param);  
+               onClearLearn(m_param);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index e2d6b3f9a993700480a407ba2fc2c93c3907b9bf..4e919c1fb617dfb6292bb35e7446ab3660f437a9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_MIDI_LEARNER_H
 #define GE_MIDI_LEARNER_H
 
-
-#include <functional>
-#include <string>
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
-
+#include "gui/elems/basics/pack.h"
+#include <functional>
+#include <string>
 
 class geBox;
 class geButton;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geMidiLearner : public gePack
 {
 public:
-
        geMidiLearner(int x, int y, std::string l, int param);
 
        /* update
@@ -61,8 +57,7 @@ public:
        std::function<void()>         onStopLearn;
        std::function<void(uint32_t)> onClearLearn;
 
-protected:
-
+  protected:
        /* m_param
        Parameter index to be learnt. */
 
@@ -72,16 +67,14 @@ protected:
        geButton m_valueBtn;
        geButton m_button;
 
-private:
-
+  private:
        static void cb_button(Fl_Widget* /*w*/, void* p);
-       static void cb_value (Fl_Widget* /*w*/, void* p);
+       static void cb_value(Fl_Widget* /*w*/, void* p);
 
        void onLearn() const;
        void onReset() const;
-
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index af8653c1c86b7f54b1ffbc8d367c57899000fffc..a62a60f328c1753a302897f76840afe2626401d0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
+#include "midiLearnerPack.h"
 #include "core/const.h"
 #include "glue/io.h"
 #include "gui/elems/basics/box.h"
-#include "midiLearnerPack.h"
-
+#include <cassert>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 constexpr int LEARNER_WIDTH = 284;
 
-
 /* -------------------------------------------------------------------------- */
 
-
 geMidiLearnerPack::geMidiLearnerPack(int X, int Y, std::string title)
 : gePack(X, Y, Direction::VERTICAL)
 {
        end();
 
-       if (title != "") {
+       if (title != "")
+       {
                geBox* header = new geBox(0, 0, LEARNER_WIDTH, G_GUI_UNIT, title.c_str());
                header->box(FL_BORDER_BOX);
                add(header);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearnerPack::setCallbacks(std::function<void(uint32_t)> s, std::function<void(uint32_t)> c)
 {
-    m_onStartLearn = s;
-    m_onClearLearn = c;
+       m_onStartLearn = s;
+       m_onClearLearn = c;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearnerPack::addMidiLearner(std::string label, int param, bool visible)
 {
        geMidiLearner* l = new geMidiLearner(0, 0, label, param);
-       
+
        l->onStartLearn = m_onStartLearn;
        l->onClearLearn = m_onClearLearn;
-       l->onStopLearn = [] () { c::io::stopMidiLearn(); };
+       l->onStopLearn  = []() { c::io::stopMidiLearn(); };
 
        add(l);
-       if (!visible) l->hide();
+       if (!visible)
+               l->hide();
        learners.push_back(l);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geMidiLearnerPack::setEnabled(bool v)
 {
-       if (v) for (auto* l : learners) l->activate();
-       else   for (auto* l : learners) l->deactivate();
+       if (v)
+               for (auto* l : learners)
+                       l->activate();
+       else
+               for (auto* l : learners)
+                       l->deactivate();
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 228a06ca0e8145cdd271f855453011c814e20193..078598025ad96222ccf89f02818606af46c3b6b8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_LEARNER_PACK_H
 #define GE_LEARNER_PACK_H
 
-
-#include <string>
-#include <vector>
 #include "gui/elems/basics/pack.h"
 #include "gui/elems/midiIO/midiLearner.h"
+#include <string>
+#include <vector>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class geMidiLearnerPack : public gePack
 {
 public:
+       geMidiLearnerPack(int x, int y, std::string title = "");
 
-       geMidiLearnerPack(int x, int y, std::string title="");
-
-    void setCallbacks(std::function<void(uint32_t)>, std::function<void(uint32_t)>);
-    void addMidiLearner(std::string label, int param, bool visible=true); 
-    void setEnabled(bool v);
+       void setCallbacks(std::function<void(uint32_t)>, std::function<void(uint32_t)>);
+       void addMidiLearner(std::string label, int param, bool visible = true);
+       void setEnabled(bool v);
 
-    std::vector<geMidiLearner*> learners;
+       std::vector<geMidiLearner*> learners;
 
-private:
-
-    std::function<void(uint32_t)> m_onStartLearn;
-    std::function<void(uint32_t)> m_onClearLearn;
+  private:
+       std::function<void(uint32_t)> m_onStartLearn;
+       std::function<void(uint32_t)> m_onClearLearn;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 49ab33dea5eb697f1dc88d28377e7f80be9a2191..890c9b6cedb9ce078d5aeffc703636d0870de30a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <FL/fl_draw.H>
-#include "core/plugins/plugin.h"
+#include "pluginBrowser.h"
 #include "core/const.h"
-#include "core/plugins/pluginManager.h"
+#include "core/plugins/plugin.h"
 #include "core/plugins/pluginHost.h"
+#include "core/plugins/pluginManager.h"
 #include "gui/elems/basics/boxtypes.h"
-#include "pluginBrowser.h"
-
+#include <FL/fl_draw.H>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gePluginBrowser::gePluginBrowser(int x, int y, int w, int h)
-       : Fl_Browser(x, y, w, h)
+: Fl_Browser(x, y, w, h)
 {
        box(G_CUSTOM_BORDER_BOX);
        textsize(G_GUI_FONT_SIZE_BASE);
@@ -64,17 +62,15 @@ gePluginBrowser::gePluginBrowser(int x, int y, int w, int h)
        computeWidths();
 
        column_widths(widths);
-       column_char('\t');       // tabs as column delimiters
+       column_char('\t'); // tabs as column delimiters
 
        refresh();
 
        end();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginBrowser::refresh()
 {
        clear();
@@ -82,35 +78,39 @@ void gePluginBrowser::refresh()
        add("NAME\tMANUFACTURER\tCATEGORY\tFORMAT\tUID");
        add("---\t---\t---\t---\t---");
 
-       for (int i=0; i<m::pluginManager::countAvailablePlugins(); i++) {
+       for (int i = 0; i < m::pluginManager::countAvailablePlugins(); i++)
+       {
                m::pluginManager::PluginInfo pi = m::pluginManager::getAvailablePluginInfo(i);
-               std::string m = m::pluginManager::doesPluginExist(pi.uid) ? "" : "@-";
-               std::string s = m + pi.name + "\t" + m + pi.manufacturerName + "\t" + m +
-                       pi.category +   "\t" + m + pi.format + "\t" + m + pi.uid;
+               std::string                  m  = m::pluginManager::doesPluginExist(pi.uid) ? "" : "@-";
+               std::string                  s  = m + pi.name + "\t" + m + pi.manufacturerName + "\t" + m +
+                               pi.category + "\t" + m + pi.format + "\t" + m + pi.uid;
                add(s.c_str());
        }
 
-       for (int i = 0; i < m::pluginManager::countUnknownPlugins(); i++) {
+       for (int i = 0; i < m::pluginManager::countUnknownPlugins(); i++)
+       {
                std::string s = "?\t?\t?\t?\t? " + m::pluginManager::getUnknownPluginInfo(i) + " ?";
                add(s.c_str());
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginBrowser::computeWidths()
 {
        int w0, w1, w3;
-       for (int i = 0; i < m::pluginManager::countAvailablePlugins(); i++) {
+       for (int i = 0; i < m::pluginManager::countAvailablePlugins(); i++)
+       {
                m::pluginManager::PluginInfo pi = m::pluginManager::getAvailablePluginInfo(i);
-               w0 = (int) fl_width(pi.name.c_str());
-               w1 = (int) fl_width(pi.manufacturerName.c_str());
-               w3 = (int) fl_width(pi.format.c_str());
-               if (w0 > widths[0]) widths[0] = w0;
-               if (w1 > widths[1]) widths[1] = w1;
-               if (w3 > widths[3]) widths[3] = w3;
+               w0                              = (int)fl_width(pi.name.c_str());
+               w1                              = (int)fl_width(pi.manufacturerName.c_str());
+               w3                              = (int)fl_width(pi.format.c_str());
+               if (w0 > widths[0])
+                       widths[0] = w0;
+               if (w1 > widths[1])
+                       widths[1] = w1;
+               if (w3 > widths[3])
+                       widths[3] = w3;
        }
        widths[0] += 60;
        widths[1] += 60;
@@ -118,7 +118,7 @@ void gePluginBrowser::computeWidths()
        widths[3] += 60;
        widths[4] = 0;
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index 3fa9e51477e7f9fd239c1c80060f99135d8d615a..c40fd27a6b3493168c93b6b283ccebb0499459e2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef GE_PLUGIN_BROWSER_H
 #define GE_PLUGIN_BROWSER_H
 
-
 #include <FL/Fl_Browser.H>
 
-
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class gePluginBrowser : public Fl_Browser
 {
 public:
-
        gePluginBrowser(int x, int y, int w, int h);
 
        void refresh();
 
-private:
+  private:
+       void computeWidths();
 
-    void computeWidths();
-
-    int widths[5] = {0};
+       int widths[5] = {0};
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
 
index b85e52b107916885364c2d44a846f41a5b63ff96..ce8caa472574ce0afa3db9eb93f381f4118c105c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
-#include <cassert>
-#include <string>
+#include "pluginElement.h"
 #include "core/graphics.h"
-#include "core/plugins/pluginHost.h"
 #include "core/plugins/plugin.h"
-#include "utils/gui.h"
-#include "utils/log.h"
+#include "core/plugins/pluginHost.h"
 #include "glue/plugin.h"
-#include "gui/elems/basics/button.h"
-#include "gui/elems/basics/choice.h"
 #include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/pluginList.h"
-#include "gui/dialogs/pluginWindowGUI.h"
 #include "gui/dialogs/pluginWindow.h"
-#include "pluginElement.h"
-
+#include "gui/dialogs/pluginWindowGUI.h"
+#include "gui/elems/basics/button.h"
+#include "gui/elems/basics/choice.h"
+#include "utils/gui.h"
+#include "utils/log.h"
+#include <cassert>
+#include <string>
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gePluginElement::gePluginElement(int x, int y, c::plugin::Plugin data)
-: gePack   (x, y, Direction::HORIZONTAL) 
-, button   (0, 0, 196, G_GUI_UNIT)
-, program  (0, 0, 132, G_GUI_UNIT)
-, bypass   (0, 0, G_GUI_UNIT, G_GUI_UNIT)
-, shiftUp  (0, 0, G_GUI_UNIT, G_GUI_UNIT, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm)
+: gePack(x, y, Direction::HORIZONTAL)
+, button(0, 0, 196, G_GUI_UNIT)
+, program(0, 0, 132, G_GUI_UNIT)
+, bypass(0, 0, G_GUI_UNIT, G_GUI_UNIT)
+, shiftUp(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm)
 , shiftDown(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", fxShiftDownOff_xpm, fxShiftDownOn_xpm)
-, remove   (0, 0, G_GUI_UNIT, G_GUI_UNIT, "", fxRemoveOff_xpm, fxRemoveOn_xpm)
-, m_plugin (data)
+, remove(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", fxRemoveOff_xpm, fxRemoveOn_xpm)
+, m_plugin(data)
 {
        add(&button);
        add(&program);
@@ -69,7 +67,8 @@ gePluginElement::gePluginElement(int x, int y, c::plugin::Plugin data)
 
        remove.callback(cb_removePlugin, (void*)this);
 
-       if (!m_plugin.valid) {
+       if (!m_plugin.valid)
+       {
                button.copy_label(m_plugin.uniqueId.c_str());
                button.deactivate();
                bypass.deactivate();
@@ -86,7 +85,8 @@ gePluginElement::gePluginElement(int x, int y, c::plugin::Plugin data)
        for (const auto& p : m_plugin.programs)
                program.add(u::gui::removeFltkChars(p.name).c_str());
 
-       if (program.size() == 0) {
+       if (program.size() == 0)
+       {
                program.add("-- no programs --\0");
                program.deactivate();
        }
@@ -101,66 +101,59 @@ gePluginElement::gePluginElement(int x, int y, c::plugin::Plugin data)
        shiftDown.callback(cb_shiftDown, (void*)this);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 ID gePluginElement::getPluginId() const
 {
        return m_plugin.id;
 }
 
+const m::Plugin& gePluginElement::getPluginRef() const
+{
+       return m_plugin.getPluginRef();
+}
 
 /* -------------------------------------------------------------------------- */
 
-
-void gePluginElement::cb_removePlugin    (Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_removePlugin(); }
+void gePluginElement::cb_removePlugin(Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_removePlugin(); }
 void gePluginElement::cb_openPluginWindow(Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_openPluginWindow(); }
-void gePluginElement::cb_setBypass       (Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_setBypass(); }
-void gePluginElement::cb_shiftUp         (Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_shiftUp(); }
-void gePluginElement::cb_shiftDown       (Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_shiftDown(); }
-void gePluginElement::cb_setProgram      (Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_setProgram(); }
-
+void gePluginElement::cb_setBypass(Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_setBypass(); }
+void gePluginElement::cb_shiftUp(Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_shiftUp(); }
+void gePluginElement::cb_shiftDown(Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_shiftDown(); }
+void gePluginElement::cb_setProgram(Fl_Widget* /*w*/, void* p) { ((gePluginElement*)p)->cb_setProgram(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginElement::cb_shiftUp()
 {
        const gdPluginList* parent = static_cast<const gdPluginList*>(window());
 
-       c::plugin::swapPlugins(m_plugin.id, parent->getPrevElement(*this).getPluginId(), m_plugin.channelId);
+       c::plugin::swapPlugins(m_plugin.getPluginRef(), parent->getPrevElement(*this).getPluginRef(), m_plugin.channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginElement::cb_shiftDown()
 {
        const gdPluginList* parent = static_cast<const gdPluginList*>(window());
 
-       c::plugin::swapPlugins(m_plugin.id, parent->getNextElement(*this).getPluginId(), m_plugin.channelId);
+       c::plugin::swapPlugins(m_plugin.getPluginRef(), parent->getNextElement(*this).getPluginRef(), m_plugin.channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginElement::cb_removePlugin()
 {
        /* Any subwindow linked to the plugin must be destroyed first. The 
        pluginWindow has id = id_plugin + 1, because id=0 is reserved for the parent 
        window 'add plugin'.*/
-       
+
        static_cast<gdWindow*>(window())->delSubWindow(m_plugin.id + 1);
-       c::plugin::freePlugin(m_plugin.id, m_plugin.channelId);
+       c::plugin::freePlugin(m_plugin.getPluginRef(), m_plugin.channelId);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginElement::cb_openPluginWindow()
 {
        /* The new pluginWindow has id = id_plugin + 1, because id=0 is reserved for 
@@ -171,37 +164,35 @@ void gePluginElement::cb_openPluginWindow()
        gdWindow* parent = static_cast<gdWindow*>(window());
        gdWindow* child  = parent->getChild(pwid);
 
-       if (child != nullptr) {
-               child->show();  // Raise it to top
+       if (child != nullptr)
+       {
+               child->show(); // Raise it to top
        }
-       else {
+       else
+       {
                if (m_plugin.hasEditor)
                        child = new gdPluginWindowGUI(m_plugin);
-               else 
+               else
                        child = new gdPluginWindow(m_plugin);
                child->setId(pwid);
                parent->addSubWindow(child);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginElement::cb_setBypass()
 {
        c::plugin::toggleBypass(m_plugin.id);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginElement::cb_setProgram()
 {
        c::plugin::setProgram(m_plugin.id, program.value());
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // #ifdef WITH_VST
index ed8b0dad3f36bf0170d1038ea1f9c2fdf2e1507d..b43cbe97d06ad99bc0d7e91cbdca6386c30a7bd6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef GE_PLUGIN_ELEMENT_H
 #define GE_PLUGIN_ELEMENT_H
 
-
-#include "gui/elems/basics/pack.h"
+#include "glue/plugin.h"
 #include "gui/elems/basics/button.h"
 #include "gui/elems/basics/choice.h"
-#include "glue/plugin.h"
-
+#include "gui/elems/basics/pack.h"
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 class gePluginElement : public gePack
 {
 public:
-
        gePluginElement(int x, int y, c::plugin::Plugin);
 
-       ID getPluginId() const;
+       ID               getPluginId() const;
+       const m::Plugin& getPluginRef() const;
 
        geButton button;
        geChoice program;
@@ -56,25 +53,24 @@ public:
        geButton shiftDown;
        geButton remove;
 
-private:
-
+  private:
        static void cb_removePlugin(Fl_Widget* /*w*/, void* p);
        static void cb_openPluginWindow(Fl_Widget* /*w*/, void* p);
        static void cb_setBypass(Fl_Widget* /*w*/, void* p);
        static void cb_shiftUp(Fl_Widget* /*w*/, void* p);
        static void cb_shiftDown(Fl_Widget* /*w*/, void* p);
        static void cb_setProgram(Fl_Widget* /*w*/, void* p);
-       void cb_removePlugin();
-       void cb_openPluginWindow();
-       void cb_setBypass();
-       void cb_shiftUp();
-       void cb_shiftDown();
-       void cb_setProgram();
+       void        cb_removePlugin();
+       void        cb_openPluginWindow();
+       void        cb_setBypass();
+       void        cb_shiftUp();
+       void        cb_shiftDown();
+       void        cb_setProgram();
 
        c::plugin::Plugin m_plugin;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
 
index a3c42dd907b06fd8a4ec44ba6d502dea6b5fe5ad..684e273bc614d97036e75cab3dcd5cd2080c8945 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
+#include "pluginParameter.h"
 #include "core/const.h"
-#include "glue/plugin.h"
 #include "glue/events.h"
-#include "gui/elems/basics/boxtypes.h"
+#include "glue/plugin.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/boxtypes.h"
 #include "gui/elems/basics/slider.h"
-#include "pluginParameter.h"
-
 
-namespace giada {
+namespace giada
+{
 namespace v
 {
 gePluginParameter::gePluginParameter(int X, int Y, int W, int labelWidth, const c::plugin::Param p)
-: Fl_Group  (X, Y, W, G_GUI_UNIT)
-, m_param   (p)
+: Fl_Group(X, Y, W, G_GUI_UNIT)
+, m_param(p)
 {
        begin();
 
-               const int VALUE_WIDTH = 100;
+       const int VALUE_WIDTH = 100;
+
+       m_label = new geBox(x(), y(), labelWidth, G_GUI_UNIT);
+       m_label->copy_label(m_param.name.c_str());
 
-               m_label = new geBox(x(), y(), labelWidth, G_GUI_UNIT);
-               m_label->copy_label(m_param.name.c_str());
+       m_slider = new geSlider(m_label->x() + m_label->w() + G_GUI_OUTER_MARGIN, y(),
+           w() - (m_label->x() + m_label->w() + G_GUI_OUTER_MARGIN) - VALUE_WIDTH, G_GUI_UNIT);
+       m_slider->value(m_param.value);
+       m_slider->callback(cb_setValue, (void*)this);
 
-               m_slider = new geSlider(m_label->x()+m_label->w()+G_GUI_OUTER_MARGIN, y(), 
-                       w()-(m_label->x()+m_label->w()+G_GUI_OUTER_MARGIN)-VALUE_WIDTH, G_GUI_UNIT);
-               m_slider->value(m_param.value);
-               m_slider->callback(cb_setValue, (void*)this);
+       m_value = new geBox(m_slider->x() + m_slider->w() + G_GUI_OUTER_MARGIN, y(), VALUE_WIDTH, G_GUI_UNIT);
+       m_value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
+       m_value->box(G_CUSTOM_BORDER_BOX);
 
-               m_value = new geBox(m_slider->x()+m_slider->w()+G_GUI_OUTER_MARGIN, y(), VALUE_WIDTH, G_GUI_UNIT);
-               m_value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
-               m_value->box(G_CUSTOM_BORDER_BOX);
-               
        end();
 
        resizable(m_slider);
        update(m_param, false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginParameter::cb_setValue(Fl_Widget* /*w*/, void* p) { ((gePluginParameter*)p)->cb_setValue(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginParameter::cb_setValue()
 {
-       c::events::setPluginParameter(m_param.pluginId, m_param.index, m_slider->value(), 
-               /*gui=*/true);
+       c::events::setPluginParameter(m_param.pluginId, m_param.index,
+           m_slider->value(), /*gui=*/true);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePluginParameter::update(const c::plugin::Param& p, bool changeSlider)
 {
        m_value->copy_label(std::string(p.text + " " + p.label).c_str());
        if (changeSlider)
                m_slider->value(p.value);
 }
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif // #ifdef WITH_VST
index 3934f19da2dac60e373acc1c80463873e871a19d..4e5fe7db9f5c0de64f6f0f9d6ef2a9d52530d8e5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifdef WITH_VST
 
-
 #ifndef GE_PLUGIN_PARAMETER_H
 #define GE_PLUGIN_PARAMETER_H
 
-
-#include <FL/Fl_Group.H>
 #include "core/types.h"
-
+#include "glue/plugin.h"
+#include <FL/Fl_Group.H>
 
 class geBox;
 class geSlider;
 
-
-namespace giada {
-namespace c {
-namespace plugin
-{
-struct Param;
-}}
-namespace v
+namespace giada::v
 {
 class gePluginParameter : public Fl_Group
 {
 public:
-
        gePluginParameter(int x, int y, int w, int labelWidth, const c::plugin::Param);
 
        void update(const c::plugin::Param& p, bool changeSlider);
 
-private:
-
+  private:
        static void cb_setValue(Fl_Widget* /*w*/, void* p);
-       void cb_setValue();
+       void        cb_setValue();
 
-       const c::plugin::Param m_param; 
+       const c::plugin::Param m_param;
 
        geBox*    m_label;
        geSlider* m_slider;
        geBox*    m_value;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
 
index 9b79e4b5b5cb1ed495b0369060f1f67b393ab0d9..8bfc636f964a94ce9ccba430ea45277c9ec4415c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
+#include "boostTool.h"
 #include "core/const.h"
-#include "core/waveFx.h"  
+#include "core/waveFx.h"
 #include "glue/channel.h"
-#include "utils/gui.h"
-#include "utils/string.h"
-#include "utils/math.h"
 #include "gui/dialogs/sampleEditor.h"
-#include "gui/elems/basics/dial.h"
-#include "gui/elems/basics/input.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/dial.h"
+#include "gui/elems/basics/input.h"
+#include "utils/gui.h"
+#include "utils/math.h"
+#include "utils/string.h"
 #include "waveTools.h"
-#include "boostTool.h"
-
+#include <FL/Fl.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geBoostTool::geBoostTool(int X, int Y)
 : Fl_Pack(X, Y, 220, G_GUI_UNIT)
@@ -51,10 +50,10 @@ geBoostTool::geBoostTool(int X, int Y)
        spacing(G_GUI_INNER_MARGIN);
 
        begin();
-               label     = new geBox   (0, 0, u::gui::getStringWidth("Boost"), G_GUI_UNIT, "Boost", FL_ALIGN_RIGHT);
-               dial      = new geDial  (0, 0, G_GUI_UNIT, G_GUI_UNIT);
-               input     = new geInput (0, 0, 70, G_GUI_UNIT);
-               normalize = new geButton(0, 0, 70, G_GUI_UNIT, "Normalize");
+       label     = new geBox(0, 0, u::gui::getStringWidth("Boost"), G_GUI_UNIT, "Boost", FL_ALIGN_RIGHT);
+       dial      = new geDial(0, 0, G_GUI_UNIT, G_GUI_UNIT);
+       input     = new geInput(0, 0, 70, G_GUI_UNIT);
+       normalize = new geButton(0, 0, 70, G_GUI_UNIT, "Normalize");
        end();
 
        dial->range(1.0f, 10.0f);
@@ -66,10 +65,8 @@ geBoostTool::geBoostTool(int X, int Y)
        normalize->callback(cb_normalize, (void*)this);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBoostTool::rebuild()
 {
        /*
@@ -80,18 +77,14 @@ void geBoostTool::rebuild()
        dial->value(ch->getBoost() <= 10.0f ? ch->getBoost() : 10.0f);*/
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geBoostTool::cb_setBoost   (Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_setBoost(); }
+void geBoostTool::cb_setBoost(Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_setBoost(); }
 void geBoostTool::cb_setBoostNum(Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_setBoostNum(); }
-void geBoostTool::cb_normalize  (Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_normalize(); }
-
+void geBoostTool::cb_normalize(Fl_Widget* /*w*/, void* p) { ((geBoostTool*)p)->cb_normalize(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void geBoostTool::cb_setBoost()
 {
        /*const m::SampleChannel* ch = static_cast<gdSampleEditor*>(window())->ch;
@@ -99,10 +92,8 @@ void geBoostTool::cb_setBoost()
        c::channel::setBoost(ch->id, dial->value());*/
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBoostTool::cb_setBoostNum()
 {
        /*const m::SampleChannel* ch = static_cast<gdSampleEditor*>(window())->ch;
@@ -110,12 +101,11 @@ void geBoostTool::cb_setBoostNum()
        c::channel::setBoost(ch->id, u::math::dBtoLinear(atof(input->value())));*/
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geBoostTool::cb_normalize()
 {
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 790763c8ee644a82621a13a68eb62990e7bbfb61..93f1edf62204e9a4597f9aadaa9076074d32cea6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_BOOST_TOOL_H
 #define GE_BOOST_TOOL_H
 
-
 #include <FL/Fl_Pack.H>
 
-
 class geDial;
 class geInput;
 class geButton;
 class geBox;
 
-
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 class geBoostTool : public Fl_Pack
 {
 public:
-
        geBoostTool(int x, int y);
 
        void rebuild();
 
-private:
-
+  private:
        static void cb_setBoost(Fl_Widget* /*w*/, void* p);
        static void cb_setBoostNum(Fl_Widget* /*w*/, void* p);
        static void cb_normalize(Fl_Widget* /*w*/, void* p);
-       void cb_setBoost();
-       void cb_setBoostNum();
-       void cb_normalize();
+       void        cb_setBoost();
+       void        cb_setBoostNum();
+       void        cb_normalize();
 
        geBox*    label;
        geDial*   dial;
        geInput*  input;
        geButton* normalize;
 };
-}} // giada::v::
-
+} // namespace v
+} // namespace giada
 
 #endif
index bbb66a82bd10654218db742f0596ca159bd07046..3baf277f034eef3225177767eccb6b05b6a4df49 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include "core/model/model.h"
+#include "panTool.h"
 #include "core/const.h"
-#include "core/waveFx.h"  
+#include "core/model/model.h"
+#include "core/waveFx.h"
 #include "glue/events.h"
+#include "gui/dialogs/sampleEditor.h"
 #include "utils/gui.h"
 #include "utils/math.h"
 #include "utils/string.h"
-#include "gui/dialogs/sampleEditor.h"
 #include "waveTools.h"
-#include "panTool.h"
-
+#include <FL/Fl.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gePanTool::gePanTool(const c::sampleEditor::Data& d, int x, int y)
-: gePack (x, y, Direction::HORIZONTAL)
-, m_data (nullptr)
+: gePack(x, y, Direction::HORIZONTAL)
+, m_data(nullptr)
 , m_label(0, 0, 60, G_GUI_UNIT, "Pan", FL_ALIGN_LEFT)
-, m_dial (0, 0, G_GUI_UNIT, G_GUI_UNIT)
+, m_dial(0, 0, G_GUI_UNIT, G_GUI_UNIT)
 , m_input(0, 0, 70, G_GUI_UNIT)
 , m_reset(0, 0, 70, G_GUI_UNIT, "Reset")
 {
        add(&m_label);
-       add(&m_dial); 
+       add(&m_dial);
        add(&m_input);
        add(&m_reset);
 
@@ -66,61 +65,51 @@ gePanTool::gePanTool(const c::sampleEditor::Data& d, int x, int y)
        rebuild(d);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePanTool::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
        update(m_data->pan);
-
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePanTool::update(float v)
 {
        m_dial.value(v);
 
-       if (v < 0.5f) {
-               std::string tmp = u::string::iToString((int) ((-v * 200.0f) + 100.0f)) + " L";
+       if (v < 0.5f)
+       {
+               std::string tmp = u::string::iToString((int)((-v * 200.0f) + 100.0f)) + " L";
                m_input.value(tmp.c_str());
        }
-       else 
-       if (v == 0.5)
+       else if (v == 0.5)
                m_input.value("C");
-       else {
-               std::string tmp = u::string::iToString((int) ((v * 200.0f) - 100.0f)) + " R";
+       else
+       {
+               std::string tmp = u::string::iToString((int)((v * 200.0f) - 100.0f)) + " R";
                m_input.value(tmp.c_str());
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gePanTool::cb_panning (Fl_Widget* /*w*/, void* p) { ((gePanTool*)p)->cb_panning(); }
+void gePanTool::cb_panning(Fl_Widget* /*w*/, void* p) { ((gePanTool*)p)->cb_panning(); }
 void gePanTool::cb_panReset(Fl_Widget* /*w*/, void* p) { ((gePanTool*)p)->cb_panReset(); }
 
-
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePanTool::cb_panning()
 {
        c::events::sendChannelPan(m_data->channelId, m_dial.value());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePanTool::cb_panReset()
 {
        c::events::sendChannelPan(m_data->channelId, 0.5f);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 609b5bb00b7df22e1f2196fc9afa141d9c1ad6ae..2c23ff3f595ff0712242b279a9529bc10665247f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_PAN_TOOL_H
 #define GE_PAN_TOOL_H
 
-
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/input.h"
-#include "gui/elems/basics/button.h"
-
+#include "gui/elems/basics/pack.h"
 
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class gePanTool : public gePack
 {
 public:
-
        gePanTool(const c::sampleEditor::Data& d, int x, int y);
 
        void rebuild(const c::sampleEditor::Data& d);
        void update(float v);
 
-private:
-
-       static void cb_panning (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_panning(Fl_Widget* /*w*/, void* p);
        static void cb_panReset(Fl_Widget* /*w*/, void* p);
-       void cb_panning();
-       void cb_panReset();
+       void        cb_panning();
+       void        cb_panReset();
 
        const c::sampleEditor::Data* m_data;
 
@@ -62,7 +60,6 @@ private:
        geInput  m_input;
        geButton m_reset;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 756ef163338aaecf5b79beaa57d0308e53bf5497..023f5575faaef15c745345bbb2e316ff053249e9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
-#include "core/model/model.h"
-#include "core/const.h"
-#include "core/graphics.h"  
+#include "pitchTool.h"
 #include "core/clock.h"
+#include "core/const.h"
+#include "core/graphics.h"
+#include "core/model/model.h"
 #include "glue/events.h"
-#include "utils/gui.h"
-#include "utils/string.h"
 #include "gui/dialogs/sampleEditor.h"
-#include "gui/elems/basics/dial.h"
-#include "gui/elems/basics/input.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/button.h"
-#include "pitchTool.h"
-
+#include "gui/elems/basics/dial.h"
+#include "gui/elems/basics/input.h"
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <FL/Fl.H>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 gePitchTool::gePitchTool(const c::sampleEditor::Data& d, int x, int y)
-: gePack       (x, y, Direction::HORIZONTAL)
-, m_data       (nullptr)
-, m_label      (0, 0, 60, G_GUI_UNIT, "Pitch", FL_ALIGN_LEFT)
-, m_dial       (0, 0, G_GUI_UNIT, G_GUI_UNIT)
-, m_input      (0, 0, 70, G_GUI_UNIT)
-, m_pitchToBar (0, 0, 70, G_GUI_UNIT, "To bar")
+: gePack(x, y, Direction::HORIZONTAL)
+, m_data(nullptr)
+, m_label(0, 0, 60, G_GUI_UNIT, "Pitch", FL_ALIGN_LEFT)
+, m_dial(0, 0, G_GUI_UNIT, G_GUI_UNIT)
+, m_input(0, 0, 70, G_GUI_UNIT)
+, m_pitchToBar(0, 0, 70, G_GUI_UNIT, "To bar")
 , m_pitchToSong(0, 0, 70, G_GUI_UNIT, "To song")
-, m_pitchHalf  (0, 0, G_GUI_UNIT, G_GUI_UNIT, "", divideOff_xpm, divideOn_xpm)
+, m_pitchHalf(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", divideOff_xpm, divideOn_xpm)
 , m_pitchDouble(0, 0, G_GUI_UNIT, G_GUI_UNIT, "", multiplyOff_xpm, multiplyOn_xpm)
-, m_pitchReset (0, 0, 70, G_GUI_UNIT, "Reset")
+, m_pitchReset(0, 0, 70, G_GUI_UNIT, "Reset")
 {
        add(&m_label);
        add(&m_dial);
@@ -83,20 +82,16 @@ gePitchTool::gePitchTool(const c::sampleEditor::Data& d, int x, int y)
        rebuild(d);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
        update(m_data->pitch, /*isDial=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::update(float v, bool isDial)
 {
        m_input.value(u::string::fToString(v, 4).c_str()); // 4 digits
@@ -104,80 +99,65 @@ void gePitchTool::update(float v, bool isDial)
                m_dial.value(v);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void gePitchTool::cb_setPitch      (Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitch(); }
-void gePitchTool::cb_setPitchToBar (Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchToBar(); }
+void gePitchTool::cb_setPitch(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitch(); }
+void gePitchTool::cb_setPitchToBar(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchToBar(); }
 void gePitchTool::cb_setPitchToSong(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchToSong(); }
-void gePitchTool::cb_setPitchHalf  (Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchHalf(); }
+void gePitchTool::cb_setPitchHalf(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchHalf(); }
 void gePitchTool::cb_setPitchDouble(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchDouble(); }
-void gePitchTool::cb_resetPitch    (Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_resetPitch(); }
-void gePitchTool::cb_setPitchNum   (Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchNum(); }
-
+void gePitchTool::cb_resetPitch(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_resetPitch(); }
+void gePitchTool::cb_setPitchNum(Fl_Widget* /*w*/, void* p) { ((gePitchTool*)p)->cb_setPitchNum(); }
 
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_setPitch()
 {
        c::events::setChannelPitch(m_data->channelId, m_dial.value(), Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_setPitchNum()
 {
-       c::events::setChannelPitch(m_data->channelId, atof(m_input.value()), Thread::MAIN);     
+       c::events::setChannelPitch(m_data->channelId, atof(m_input.value()), Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_setPitchHalf()
 {
-       c::events::setChannelPitch(m_data->channelId, m_dial.value() / 2, Thread::MAIN);        
+       c::events::setChannelPitch(m_data->channelId, m_dial.value() / 2, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_setPitchDouble()
 {
-       c::events::setChannelPitch(m_data->channelId, m_dial.value() * 2, Thread::MAIN);        
+       c::events::setChannelPitch(m_data->channelId, m_dial.value() * 2, Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_setPitchToBar()
 {
-       c::events::setChannelPitch(m_data->channelId, m_data->end / (float) m::clock::getFramesInBar(), 
-               Thread::MAIN);  
+       c::events::setChannelPitch(m_data->channelId, m_data->end / (float)m::clock::getFramesInBar(),
+           Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_setPitchToSong()
 {
-       c::events::setChannelPitch(m_data->channelId, m_data->end / (float) m::clock::getFramesInLoop(), 
-               Thread::MAIN);  
+       c::events::setChannelPitch(m_data->channelId, m_data->end / (float)m::clock::getFramesInLoop(),
+           Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void gePitchTool::cb_resetPitch()
 {
-       c::events::setChannelPitch(m_data->channelId, G_DEFAULT_PITCH, Thread::MAIN);   
+       c::events::setChannelPitch(m_data->channelId, G_DEFAULT_PITCH, Thread::MAIN);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index bc2ab586c3e8e7693f17a001b129217a86d383e1..9a0da80179aa0990baaa993f4f59941534c8959b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_PITCH_TOOL_H
 #define GE_PITCH_TOOL_H
 
-
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/box.h"
+#include "gui/elems/basics/button.h"
 #include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/input.h"
-#include "gui/elems/basics/button.h"
-
+#include "gui/elems/basics/pack.h"
 
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class gePitchTool : public gePack
 {
 public:
-
        gePitchTool(const c::sampleEditor::Data& d, int x, int y);
 
        void rebuild(const c::sampleEditor::Data& d);
-       void update(float v, bool isDial=false);
+       void update(float v, bool isDial = false);
 
-private:
-
-       static void cb_setPitch      (Fl_Widget* /*w*/, void* p);
-       static void cb_setPitchToBar (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_setPitch(Fl_Widget* /*w*/, void* p);
+       static void cb_setPitchToBar(Fl_Widget* /*w*/, void* p);
        static void cb_setPitchToSong(Fl_Widget* /*w*/, void* p);
-       static void cb_setPitchHalf  (Fl_Widget* /*w*/, void* p);
+       static void cb_setPitchHalf(Fl_Widget* /*w*/, void* p);
        static void cb_setPitchDouble(Fl_Widget* /*w*/, void* p);
-       static void cb_resetPitch    (Fl_Widget* /*w*/, void* p);
-       static void cb_setPitchNum   (Fl_Widget* /*w*/, void* p);
-       void cb_setPitch();
-       void cb_setPitchToBar();
-       void cb_setPitchToSong();
-       void cb_setPitchHalf();
-       void cb_setPitchDouble();
-       void cb_resetPitch();
-       void cb_setPitchNum();
+       static void cb_resetPitch(Fl_Widget* /*w*/, void* p);
+       static void cb_setPitchNum(Fl_Widget* /*w*/, void* p);
+       void        cb_setPitch();
+       void        cb_setPitchToBar();
+       void        cb_setPitchToSong();
+       void        cb_setPitchHalf();
+       void        cb_setPitchDouble();
+       void        cb_resetPitch();
+       void        cb_setPitchNum();
 
        const c::sampleEditor::Data* m_data;
 
@@ -76,7 +74,6 @@ private:
        geButton m_pitchDouble;
        geButton m_pitchReset;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 4c11c46b588a8443ddf14452d8844717fa68fe39..20e8a6b1df37bb3f88d06dcd33fe6f5241df5e3e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <FL/Fl.H>
+#include "rangeTool.h"
 #include "core/model/model.h"
 #include "core/wave.h"
 #include "glue/channel.h"
 #include "glue/sampleEditor.h"
+#include "gui/dialogs/sampleEditor.h"
 #include "utils/gui.h"
 #include "utils/string.h"
-#include "gui/dialogs/sampleEditor.h"
 #include "waveTools.h"
-#include "rangeTool.h"
-
+#include <FL/Fl.H>
+#include <cassert>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geRangeTool::geRangeTool(const c::sampleEditor::Data& d, int x, int y)
-: gePack (x, y, Direction::HORIZONTAL)
-, m_data (nullptr)
+: gePack(x, y, Direction::HORIZONTAL)
+, m_data(nullptr)
 , m_label(0, 0, 60, G_GUI_UNIT, "Range", FL_ALIGN_LEFT)
 , m_begin(0, 0, 70, G_GUI_UNIT)
-, m_end  (0, 0, 70, G_GUI_UNIT)
+, m_end(0, 0, 70, G_GUI_UNIT)
 , m_reset(0, 0, 70, G_GUI_UNIT, "Reset")
 {
        add(&m_label);
@@ -57,7 +56,7 @@ geRangeTool::geRangeTool(const c::sampleEditor::Data& d, int x, int y)
        m_begin.type(FL_INT_INPUT);
        m_begin.when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
        m_begin.callback(cb_setChanPos, this);
-       
+
        m_end.type(FL_INT_INPUT);
        m_end.when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
        m_end.callback(cb_setChanPos, this);
@@ -67,20 +66,16 @@ geRangeTool::geRangeTool(const c::sampleEditor::Data& d, int x, int y)
        rebuild(d);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geRangeTool::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
        update(m_data->begin, m_data->end);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geRangeTool::update(Frame begin, Frame end)
 {
        m_begin.value(std::to_string(begin).c_str());
@@ -89,26 +84,22 @@ void geRangeTool::update(Frame begin, Frame end)
 
 /* -------------------------------------------------------------------------- */
 
-
-void geRangeTool::cb_setChanPos   (Fl_Widget* /*w*/, void* p) { ((geRangeTool*)p)->cb_setChanPos(); }
+void geRangeTool::cb_setChanPos(Fl_Widget* /*w*/, void* p) { ((geRangeTool*)p)->cb_setChanPos(); }
 void geRangeTool::cb_resetStartEnd(Fl_Widget* /*w*/, void* p) { ((geRangeTool*)p)->cb_resetStartEnd(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geRangeTool::cb_setChanPos()
 {
        c::sampleEditor::setBeginEnd(m_data->channelId, atoi(m_begin.value()), atoi(m_end.value()));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geRangeTool::cb_resetStartEnd()
 {
        c::sampleEditor::setBeginEnd(m_data->channelId, 0, m_data->waveSize - 1);
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 65d07dc40bab8b7eb228b39fdc9ca04568fe1112..71500bf0c17d25e924a62076264fe7b860da354e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_RANGE_TOOL_H
 #define GE_RANGE_TOOL_H
 
-
-#include "gui/elems/basics/pack.h"
+#include "core/types.h"
 #include "gui/elems/basics/box.h"
-#include "gui/elems/basics/input.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/input.h"
+#include "gui/elems/basics/pack.h"
 
-
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class geRangeTool : public gePack
 {
 public:
-
        geRangeTool(const c::sampleEditor::Data& d, int x, int y);
 
        void rebuild(const c::sampleEditor::Data& d);
        void update(Frame begin, Frame end);
 
-private:
-
-       static void cb_setChanPos   (Fl_Widget* /*w*/, void* p);
+  private:
+       static void cb_setChanPos(Fl_Widget* /*w*/, void* p);
        static void cb_resetStartEnd(Fl_Widget* /*w*/, void* p);
-       void cb_setChanPos();
-       void cb_resetStartEnd();
+       void        cb_setChanPos();
+       void        cb_resetStartEnd();
 
        const c::sampleEditor::Data* m_data;
 
@@ -61,7 +60,6 @@ private:
        geInput  m_end;
        geButton m_reset;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 6cbf480f72e35328a0413ceef5954b266bf001a8..956568296700e9f32d7ba0daa6c80cbbc3f25e50 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <cstdlib>
-#include "core/model/model.h"
+#include "shiftTool.h"
 #include "core/const.h"
-#include "utils/gui.h"
-#include "utils/string.h"
+#include "core/model/model.h"
 #include "glue/sampleEditor.h"
-#include "gui/dialogs/warnings.h"
 #include "gui/dialogs/sampleEditor.h"
-#include "shiftTool.h"
-
+#include "gui/dialogs/warnings.h"
+#include "utils/gui.h"
+#include "utils/string.h"
+#include <cassert>
+#include <cstdlib>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geShiftTool::geShiftTool(const c::sampleEditor::Data& d, int x, int y)
-: gePack (x, y, Direction::HORIZONTAL)
-, m_data (nullptr)
+: gePack(x, y, Direction::HORIZONTAL)
+, m_data(nullptr)
 , m_label(0, 0, 60, G_GUI_UNIT, "Shift", FL_ALIGN_LEFT)
 , m_shift(0, 0, 70, G_GUI_UNIT)
 , m_reset(0, 0, 70, G_GUI_UNIT, "Reset")
@@ -60,56 +59,45 @@ geShiftTool::geShiftTool(const c::sampleEditor::Data& d, int x, int y)
        rebuild(d);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geShiftTool::cb_setShift(Fl_Widget* /*w*/, void* p) { ((geShiftTool*)p)->cb_setShift(); }
 void geShiftTool::cb_reset(Fl_Widget* /*w*/, void* p) { ((geShiftTool*)p)->cb_reset(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geShiftTool::cb_setShift()
 {
        shift(atoi(m_shift.value()));
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geShiftTool::cb_reset()
 {
        shift(0);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geShiftTool::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
        update(m_data->shift);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geShiftTool::update(Frame shift)
 {
        m_shift.value(std::to_string(shift).c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geShiftTool::shift(int f)
 {
-       c::sampleEditor::shift(m_data->channelId, m_data->waveId, f);
+       c::sampleEditor::shift(m_data->channelId, f);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index dbd74f356b6c52c78ab3a0f78fc2d6d274b106d6..7fd1b7ac77f5c7bbe320216dad669b784f10d6cd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SHIFT_TOOL_H
 #define GE_SHIFT_TOOL_H
 
-
-#include "gui/elems/basics/pack.h"
+#include "core/types.h"
 #include "gui/elems/basics/box.h"
-#include "gui/elems/basics/input.h"
 #include "gui/elems/basics/button.h"
+#include "gui/elems/basics/input.h"
+#include "gui/elems/basics/pack.h"
 
-
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class geShiftTool : public gePack
 {
 public:
-
        geShiftTool(const c::sampleEditor::Data& d, int x, int y);
 
        void rebuild(const c::sampleEditor::Data& d);
        void update(Frame shift);
 
-private:
-
+  private:
        static void cb_setShift(Fl_Widget* /*w*/, void* p);
        static void cb_reset(Fl_Widget* /*w*/, void* p);
-       void cb_setShift();
-       void cb_reset();
+       void        cb_setShift();
+       void        cb_reset();
 
        void shift(int f);
 
        const c::sampleEditor::Data* m_data;
-       
+
        geBox    m_label;
        geInput  m_shift;
        geButton m_reset;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 14416862a8a67a04f089d8413156764470f2cbc5..4d27e8c822807b40cf54841925d5544faf9edbd2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
-#include <cstdlib>
-#include <FL/Fl_Pack.H>
+#include "volumeTool.h"
 #include "core/const.h"
 #include "glue/events.h"
+#include "gui/dialogs/sampleEditor.h"
+#include "gui/elems/mainWindow/keyboard/channel.h"
 #include "utils/gui.h"
 #include "utils/math.h"
 #include "utils/string.h"
-#include "gui/dialogs/sampleEditor.h"
-#include "gui/elems/mainWindow/keyboard/channel.h"
-#include "volumeTool.h"
-
+#include <FL/Fl_Pack.H>
+#include <cmath>
+#include <cstdlib>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geVolumeTool::geVolumeTool(const c::sampleEditor::Data& d, int x, int y)
-: gePack (x, y, Direction::HORIZONTAL)
-, m_data (nullptr)
+: gePack(x, y, Direction::HORIZONTAL)
+, m_data(nullptr)
 , m_label(0, 0, 60, G_GUI_UNIT, "Volume", FL_ALIGN_LEFT)
-, m_dial (0, 0, G_GUI_UNIT, G_GUI_UNIT)
+, m_dial(0, 0, G_GUI_UNIT, G_GUI_UNIT)
 , m_input(0, 0, 70, G_GUI_UNIT)
-{              
+{
        add(&m_label);
        add(&m_dial);
        add(&m_input);
@@ -60,54 +59,45 @@ geVolumeTool::geVolumeTool(const c::sampleEditor::Data& d, int x, int y)
        rebuild(d);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geVolumeTool::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
        update(m_data->volume, /*isDial=*/false);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geVolumeTool::update(float v, bool isDial)
 {
        std::string tmp = "-inf";
-       float dB = u::math::linearToDB(v);
-       if (dB > -INFINITY) 
-               tmp = u::string::fToString(dB, 2);  // 2 digits
+       float       dB  = u::math::linearToDB(v);
+       if (dB > -INFINITY)
+               tmp = u::string::fToString(dB, 2); // 2 digits
        m_input.value(tmp.c_str());
        if (!isDial)
                m_dial.value(v);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
-void geVolumeTool::cb_setVolume   (Fl_Widget* /*w*/, void* p) { ((geVolumeTool*)p)->cb_setVolume(); }
+void geVolumeTool::cb_setVolume(Fl_Widget* /*w*/, void* p) { ((geVolumeTool*)p)->cb_setVolume(); }
 void geVolumeTool::cb_setVolumeNum(Fl_Widget* /*w*/, void* p) { ((geVolumeTool*)p)->cb_setVolumeNum(); }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geVolumeTool::cb_setVolume()
 {
        c::events::setChannelVolume(m_data->channelId, m_dial.value(), Thread::MAIN);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geVolumeTool::cb_setVolumeNum()
 {
-       c::events::setChannelVolume(m_data->channelId, u::math::dBtoLinear(atof(m_input.value())), 
-               Thread::MAIN);
+       c::events::setChannelVolume(m_data->channelId, u::math::dBtoLinear(atof(m_input.value())),
+           Thread::MAIN);
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 7ab23d97268fba9633d6988428d10913e15a1e82..20e179fbf04e9a7f871681b5eacb2838190a09c2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_VOLUME_TOOL_H
 #define GE_VOLUME_TOOL_H
 
-
-#include "gui/elems/basics/pack.h"
 #include "gui/elems/basics/box.h"
 #include "gui/elems/basics/dial.h"
 #include "gui/elems/basics/input.h"
+#include "gui/elems/basics/pack.h"
 
-
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class geVolumeTool : public gePack
 {
 public:
-
        geVolumeTool(const c::sampleEditor::Data& d, int x, int y);
 
        void rebuild(const c::sampleEditor::Data& d);
-       void update(float v, bool isDial=false);
-       
-private:
+       void update(float v, bool isDial = false);
 
+  private:
        static void cb_setVolume(Fl_Widget* /*w*/, void* p);
        static void cb_setVolumeNum(Fl_Widget* /*w*/, void* p);
-       void cb_setVolume();
-       void cb_setVolumeNum();
+       void        cb_setVolume();
+       void        cb_setVolumeNum();
 
        const c::sampleEditor::Data* m_data;
 
        geBox   m_label;
        geDial  m_dial;
        geInput m_input;
-
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index f568281eeab06d433d713da95ff2cee0b01be963..4f06c068a3ef83ff83799ec64efcdc5c76131a37 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cstdint>
-#include <FL/Fl_Menu_Item.H>
-#include <FL/Fl_Menu_Button.H>
+#include "waveTools.h"
+#include "core/const.h"
 #include "core/model/model.h"
 #include "core/waveFx.h"
-#include "core/const.h"
 #include "glue/sampleEditor.h"
-#include "gui/elems/basics/boxtypes.h"
 #include "gui/dialogs/sampleEditor.h"
+#include "gui/elems/basics/boxtypes.h"
 #include "waveform.h"
-#include "waveTools.h"
-
+#include <FL/Fl_Menu_Button.H>
+#include <FL/Fl_Menu_Item.H>
+#include <cstdint>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 namespace
 {
@@ -59,71 +58,67 @@ enum class Menu
        TO_NEW_CHANNEL
 };
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void menuCallback_(Fl_Widget* w, void* v)
 {
        const geWaveTools* wt = static_cast<geWaveTools*>(w);
-       
-       ID   channelId = wt->getChannelData().channelId;
-       ID   waveId    = wt->getChannelData().waveId;
-       Menu selectedItem = (Menu) (intptr_t) v;
-
-       int a = wt->waveform->getSelectionA();
-       int b = wt->waveform->getSelectionB();
-
-       switch (selectedItem) {
-               case Menu::CUT:
-                       c::sampleEditor::cut(channelId, waveId, a, b);
-                       break;          
-               case Menu::COPY:
-                       c::sampleEditor::copy(waveId, a, b);
-                       break;          
-               case Menu::PASTE:
-                       c::sampleEditor::paste(channelId, waveId, a);
-                       break;
-               case Menu::TRIM:
-                       c::sampleEditor::trim(channelId, waveId, a, b);
-                       break;
-               case Menu::SILENCE:
-                       c::sampleEditor::silence(channelId, waveId, a, b);
-                       break;    
-               case Menu::REVERSE:
-                       c::sampleEditor::reverse(channelId, waveId, a, b);
-                       break;                  
-               case Menu::NORMALIZE:
-                       c::sampleEditor::normalize(channelId, waveId, a, b);
-                       break;  
-               case Menu::FADE_IN:
-                       c::sampleEditor::fade(channelId, waveId, a, b, m::wfx::Fade::IN);
-                       break;
-               case Menu::FADE_OUT:
-                       c::sampleEditor::fade(channelId, waveId, a, b, m::wfx::Fade::OUT);
-                       break;
-               case Menu::SMOOTH_EDGES:
-                       c::sampleEditor::smoothEdges(channelId, waveId, a, b);
-                       break;
-               case Menu::SET_BEGIN_END:
-                       c::sampleEditor::setBeginEnd(channelId, a, b);
-                       break;          
-               case Menu::TO_NEW_CHANNEL:
-                       c::sampleEditor::toNewChannel(channelId, waveId, a, b);
-                       break;
+
+       ID   channelId    = wt->getChannelData().channelId;
+       Menu selectedItem = (Menu)(intptr_t)v;
+
+       Frame a = wt->waveform->getSelectionA();
+       Frame b = wt->waveform->getSelectionB();
+
+       switch (selectedItem)
+       {
+       case Menu::CUT:
+               c::sampleEditor::cut(channelId, a, b);
+               break;
+       case Menu::COPY:
+               c::sampleEditor::copy(channelId, a, b);
+               break;
+       case Menu::PASTE:
+               c::sampleEditor::paste(channelId, a);
+               break;
+       case Menu::TRIM:
+               c::sampleEditor::trim(channelId, a, b);
+               break;
+       case Menu::SILENCE:
+               c::sampleEditor::silence(channelId, a, b);
+               break;
+       case Menu::REVERSE:
+               c::sampleEditor::reverse(channelId, a, b);
+               break;
+       case Menu::NORMALIZE:
+               c::sampleEditor::normalize(channelId, a, b);
+               break;
+       case Menu::FADE_IN:
+               c::sampleEditor::fade(channelId, a, b, m::wfx::Fade::IN);
+               break;
+       case Menu::FADE_OUT:
+               c::sampleEditor::fade(channelId, a, b, m::wfx::Fade::OUT);
+               break;
+       case Menu::SMOOTH_EDGES:
+               c::sampleEditor::smoothEdges(channelId, a, b);
+               break;
+       case Menu::SET_BEGIN_END:
+               c::sampleEditor::setBeginEnd(channelId, a, b);
+               break;
+       case Menu::TO_NEW_CHANNEL:
+               c::sampleEditor::toNewChannel(channelId, a, b);
+               break;
        }
 }
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 geWaveTools::geWaveTools(int x, int y, int w, int h)
 : Fl_Scroll(x, y, w, h, nullptr)
-, m_data   (nullptr)
+, m_data(nullptr)
 {
        type(Fl_Scroll::HORIZONTAL_ALWAYS);
        hscrollbar.color(G_COLOR_GREY_2);
@@ -131,40 +126,34 @@ geWaveTools::geWaveTools(int x, int y, int w, int h)
        hscrollbar.labelcolor(G_COLOR_LIGHT_1);
        hscrollbar.slider(G_CUSTOM_BORDER_BOX);
 
-       waveform = new v::geWaveform(x, y, w, h-24);
+       waveform = new v::geWaveform(x, y, w, h - 24);
 }
 
-
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveTools::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
        waveform->rebuild(d);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveTools::refresh()
 {
        if (m_data->a_getPreviewStatus() == ChannelStatus::PLAY)
                waveform->redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveTools::resize(int x, int y, int w, int h)
 {
        Fl_Widget::resize(x, y, w, h);
 
-       if (this->w() == w || (this->w() != w && this->h() != h)) {   // vertical or both resize
-               waveform->resize(x, y, waveform->w(), h-24);
+       if (this->w() == w || (this->w() != w && this->h() != h))
+       { // vertical or both resize
+               waveform->resize(x, y, waveform->w(), h - 24);
                waveform->rebuild(*m_data);
        }
 
@@ -173,67 +162,68 @@ void geWaveTools::resize(int x, int y, int w, int h)
 
        int offset = waveform->x() + waveform->w() - this->w() - this->x();
        if (offset < 0)
-               waveform->position(waveform->x()-offset, this->y());
+               waveform->position(waveform->x() - offset, this->y());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveTools::handle(int e)
 {
-       switch (e) {
-               case FL_MOUSEWHEEL: {
-                       waveform->setZoom(Fl::event_dy() == 1 ? geWaveform::Zoom::OUT : geWaveform::Zoom::IN);
-                       redraw();
+       switch (e)
+       {
+       case FL_MOUSEWHEEL:
+       {
+               waveform->setZoom(Fl::event_dy() == 1 ? geWaveform::Zoom::OUT : geWaveform::Zoom::IN);
+               redraw();
+               return 1;
+       }
+       case FL_PUSH:
+       {
+               if (Fl::event_button3()) // right button
+               {
+                       openMenu();
                        return 1;
                }
-               case FL_PUSH: {
-                       if (Fl::event_button3()) {  // right button
-                               openMenu();
-                               return 1;
-                       }
-                       Fl::focus(waveform);
-               }
-               default:
-                       return Fl_Group::handle(e);
+               Fl::focus(waveform);
+               return Fl_Group::handle(e);
+       }
+       default:
+               return Fl_Group::handle(e);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveTools::openMenu()
 {
        Fl_Menu_Item menu[] = {
-               {"Cut",                 0, menuCallback_, (void*) Menu::CUT},
-               {"Copy",                0, menuCallback_, (void*) Menu::COPY},
-               {"Paste",               0, menuCallback_, (void*) Menu::PASTE},
-               {"Trim",                0, menuCallback_, (void*) Menu::TRIM},
-               {"Silence",             0, menuCallback_, (void*) Menu::SILENCE},
-               {"Reverse",             0, menuCallback_, (void*) Menu::REVERSE},
-               {"Normalize",           0, menuCallback_, (void*) Menu::NORMALIZE},
-               {"Fade in",             0, menuCallback_, (void*) Menu::FADE_IN},
-               {"Fade out",            0, menuCallback_, (void*) Menu::FADE_OUT},
-               {"Smooth edges",        0, menuCallback_, (void*) Menu::SMOOTH_EDGES},
-               {"Set begin/end here",  0, menuCallback_, (void*) Menu::SET_BEGIN_END},
-               {"Copy to new channel", 0, menuCallback_, (void*) Menu::TO_NEW_CHANNEL},
-               {0}
-       };
-
-       if (!waveform->isSelected()) {
+           {"Cut", 0, menuCallback_, (void*)Menu::CUT, 0, 0, 0, 0, 0},
+           {"Copy", 0, menuCallback_, (void*)Menu::COPY, 0, 0, 0, 0, 0},
+           {"Paste", 0, menuCallback_, (void*)Menu::PASTE, 0, 0, 0, 0, 0},
+           {"Trim", 0, menuCallback_, (void*)Menu::TRIM, 0, 0, 0, 0, 0},
+           {"Silence", 0, menuCallback_, (void*)Menu::SILENCE, 0, 0, 0, 0, 0},
+           {"Reverse", 0, menuCallback_, (void*)Menu::REVERSE, 0, 0, 0, 0, 0},
+           {"Normalize", 0, menuCallback_, (void*)Menu::NORMALIZE, 0, 0, 0, 0, 0},
+           {"Fade in", 0, menuCallback_, (void*)Menu::FADE_IN, 0, 0, 0, 0, 0},
+           {"Fade out", 0, menuCallback_, (void*)Menu::FADE_OUT, 0, 0, 0, 0, 0},
+           {"Smooth edges", 0, menuCallback_, (void*)Menu::SMOOTH_EDGES, 0, 0, 0, 0, 0},
+           {"Set begin/end here", 0, menuCallback_, (void*)Menu::SET_BEGIN_END, 0, 0, 0, 0, 0},
+           {"Copy to new channel", 0, menuCallback_, (void*)Menu::TO_NEW_CHANNEL, 0, 0, 0, 0, 0},
+           {0}};
+
+       if (!waveform->isSelected())
+       {
                menu[(int)Menu::CUT].deactivate();
-               menu[(int)Menu::COPY].deactivate();             
-               menu[(int)Menu::TRIM].deactivate();             
-               menu[(int)Menu::SILENCE].deactivate();          
-               menu[(int)Menu::REVERSE].deactivate();          
-               menu[(int)Menu::NORMALIZE].deactivate();                
-               menu[(int)Menu::FADE_IN].deactivate();          
-               menu[(int)Menu::FADE_OUT].deactivate();         
-               menu[(int)Menu::SMOOTH_EDGES].deactivate();             
-               menu[(int)Menu::SET_BEGIN_END].deactivate();            
-               menu[(int)Menu::TO_NEW_CHANNEL].deactivate();           
+               menu[(int)Menu::COPY].deactivate();
+               menu[(int)Menu::TRIM].deactivate();
+               menu[(int)Menu::SILENCE].deactivate();
+               menu[(int)Menu::REVERSE].deactivate();
+               menu[(int)Menu::NORMALIZE].deactivate();
+               menu[(int)Menu::FADE_IN].deactivate();
+               menu[(int)Menu::FADE_OUT].deactivate();
+               menu[(int)Menu::SMOOTH_EDGES].deactivate();
+               menu[(int)Menu::SET_BEGIN_END].deactivate();
+               menu[(int)Menu::TO_NEW_CHANNEL].deactivate();
        }
 
        Fl_Menu_Button b(0, 0, 100, 50);
@@ -249,4 +239,5 @@ void geWaveTools::openMenu()
        return;
 }
 
-}} // giada::v::
+} // namespace v
+} // namespace giada
index d920137bb65820fc2e40ed18a3779a373b915474..53387fda7e84e954fb859bd1fdb9d16750f6dcd5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_WAVE_TOOLS_H
 #define GE_WAVE_TOOLS_H
 
-
 #include <FL/Fl_Scroll.H>
 
-
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class geWaveform;
 class geWaveTools : public Fl_Scroll
 {
 public:
-
        geWaveTools(int x, int y, int w, int h);
 
        void resize(int x, int y, int w, int h) override;
@@ -59,16 +58,14 @@ public:
        void refresh();
 
        const c::sampleEditor::Data& getChannelData() const { return *m_data; }
-       
-       v::geWaveform* waveform;
 
-private:
+       v::geWaveform* waveform;
 
+  private:
        void openMenu();
 
        const c::sampleEditor::Data* m_data;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index aec4f9ae167e9d190a009a4e627567d225efee43..c92f48cce620b97dae1c9034231e817652292757 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cassert>
-#include <cmath>
-#include <FL/fl_draw.H>
-#include <FL/Fl_Menu_Button.H>
-#include "core/model/model.h"
-#include "core/wave.h"
+#include "waveform.h"
 #include "core/conf.h"
 #include "core/const.h"
 #include "core/mixer.h"
+#include "core/model/model.h"
+#include "core/wave.h"
 #include "core/waveFx.h"
 #include "glue/channel.h"
 #include "glue/sampleEditor.h"
-#include "utils/log.h"
 #include "gui/dialogs/sampleEditor.h"
 #include "gui/elems/basics/boxtypes.h"
+#include "utils/log.h"
 #include "waveTools.h"
-#include "waveform.h"
-
+#include <FL/Fl_Menu_Button.H>
+#include <FL/fl_draw.H>
+#include <cassert>
+#include <cmath>
 
-namespace giada {
-namespace v 
+namespace giada
+{
+namespace v
 {
 geWaveform::geWaveform(int x, int y, int w, int h)
-: Fl_Widget     (x, y, w, h, nullptr)
-, m_selection   {}
-, m_data        (nullptr)
-, m_chanStart   (0)
+: Fl_Widget(x, y, w, h, nullptr)
+, m_selection{}
+, m_data(nullptr)
+, m_chanStart(0)
 , m_chanStartLit(false)
-, m_chanEnd     (0)
-, m_chanEndLit  (false)
-, m_pushed      (false)
-, m_dragged     (false)
-, m_resizedA    (false)
-, m_resizedB    (false)
-, m_ratio       (0.0f)
+, m_chanEnd(0)
+, m_chanEndLit(false)
+, m_pushed(false)
+, m_dragged(false)
+, m_resizedA(false)
+, m_resizedB(false)
+, m_ratio(0.0f)
 {
        m_waveform.size = w;
 
@@ -67,10 +66,8 @@ geWaveform::geWaveform(int x, int y, int w, int h)
        m_grid.level = m::conf::conf.sampleEditorGridVal;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::clearData()
 {
        m_waveform.sup.clear();
@@ -79,24 +76,20 @@ void geWaveform::clearData()
        m_grid.points.clear();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveform::alloc(int datasize, bool force)
 {
-       /* TODO - geWaveform needs better isolation from m::. Refactoring needed. */
-       
-       m::model::WavesLock l(m::model::waves);
-       const m::Wave& wave = m::model::get(m::model::waves, m_data->waveId);
+       const m::Wave& wave = m_data->getWaveRef();
 
-       m_ratio = wave.getSize() / (float) datasize;
+       m_ratio = wave.getBuffer().countFrames() / (float)datasize;
 
        /* Limit 1:1 drawing (to avoid sub-frame drawing) by keeping m_ratio >= 1. */
 
-       if (m_ratio < 1) {  
-               datasize = wave.getSize();
-               m_ratio = 1;
+       if (m_ratio < 1)
+       {
+               datasize = wave.getBuffer().countFrames();
+               m_ratio  = 1;
        }
 
        if (datasize == m_waveform.size && !force)
@@ -116,42 +109,46 @@ int geWaveform::alloc(int datasize, bool force)
        /* Frid frequency: store a grid point every 'gridFreq' frame (if grid is
        enabled). TODO - this will cause round off errors, since gridFreq is integer. */
 
-       int gridFreq = m_grid.level != 0 ? wave.getSize() / m_grid.level : 0;
+       int gridFreq = m_grid.level != 0 ? wave.getBuffer().countFrames() / m_grid.level : 0;
 
        /* Resampling the waveform, hardcore way. Many thanks to 
        http://fourier.eng.hmc.edu/e161/lectures/resize/node3.html */
 
-       for (int i = 0; i < m_waveform.size; i++) {
-               
+       for (int i = 0; i < m_waveform.size; i++)
+       {
+
                /* Scan the original waveform in chunks [pc, pn]. */
 
-               int pc = i     * m_ratio;  // current point TODO - int until we switch to uint32_t for Wave size...
-               int pn = (i+1) * m_ratio;  // next point    TODO - int until we switch to uint32_t for Wave size...
+               int pc = i * m_ratio;       // current point TODO - int until we switch to uint32_t for Wave size...
+               int pn = (i + 1) * m_ratio; // next point    TODO - int until we switch to uint32_t for Wave size...
 
                float peaksup = 0.0f;
                float peakinf = 0.0f;
 
-               for (int k = pc; k < pn; k++) { // TODO - int until we switch to uint32_t for Wave size...
+               for (int k = pc; k < pn; k++)
+               { // TODO - int until we switch to uint32_t for Wave size...
 
-                       if (k >= wave.getSize())
+                       if (k >= wave.getBuffer().countFrames())
                                continue;
 
                        /* Compute average of stereo signal. */
 
-                       float avg = 0.0f;
-                       float* frame = wave.getFrame(k);
-                       for (int j = 0; j < wave.getChannels(); j++)
+                       float  avg   = 0.0f;
+                       float* frame = wave.getBuffer()[k];
+                       for (int j = 0; j < wave.getBuffer().countChannels(); j++)
                                avg += frame[j];
-                       avg /= wave.getChannels();
-                       
+                       avg /= wave.getBuffer().countChannels();
+
                        /* Find peaks (greater and lower). */
 
-                       if      (avg > peaksup)  peaksup = avg;
-                       else if (avg <= peakinf) peakinf = avg;
+                       if (avg > peaksup)
+                               peaksup = avg;
+                       else if (avg <= peakinf)
+                               peakinf = avg;
 
                        /* Fill up grid vector. */
 
-                       if (gridFreq != 0 && (int) k % gridFreq == 0 && k != 0)
+                       if (gridFreq != 0 && (int)k % gridFreq == 0 && k != 0)
                                m_grid.points.push_back(k);
                }
 
@@ -160,31 +157,29 @@ int geWaveform::alloc(int datasize, bool force)
 
                // avoid window overflow
 
-               if (m_waveform.sup[i] < y())       m_waveform.sup[i] = y();
-               if (m_waveform.inf[i] > y()+h()-1) m_waveform.inf[i] = y()+h()-1;
+               if (m_waveform.sup[i] < y())
+                       m_waveform.sup[i] = y();
+               if (m_waveform.inf[i] > y() + h() - 1)
+                       m_waveform.inf[i] = y() + h() - 1;
        }
 
        recalcPoints();
        return 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::recalcPoints()
 {
        m_chanStart = m_data->begin;
        m_chanEnd   = m_data->end;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::drawSelection()
 {
-       if (!isSelected()) 
+       if (!isSelected())
                return;
 
        int a = frameToPixel(m_selection.a) + x();
@@ -196,90 +191,88 @@ void geWaveform::drawSelection()
                b = w() + BORDER;
 
        if (a < b)
-               fl_rectf(a, y(), b-a, h(), G_COLOR_GREY_4);
+               fl_rectf(a, y(), b - a, h(), G_COLOR_GREY_4);
        else
-               fl_rectf(b, y(), a-b, h(), G_COLOR_GREY_4);
+               fl_rectf(b, y(), a - b, h(), G_COLOR_GREY_4);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::drawWaveform(int from, int to)
 {
        int zero = y() + (h() / 2); // zero amplitude (-inf dB)
 
        fl_color(G_COLOR_BLACK);
-       for (int i=from; i<to; i++) {
+       for (int i = from; i < to; i++)
+       {
                if (i >= m_waveform.size)
                        break;
-               fl_line(i+x(), zero, i+x(), m_waveform.sup[i]);
-               fl_line(i+x(), zero, i+x(), m_waveform.inf[i]);
+               fl_line(i + x(), zero, i + x(), m_waveform.sup[i]);
+               fl_line(i + x(), zero, i + x(), m_waveform.inf[i]);
        }
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::drawGrid(int from, int to)
 {
        fl_color(G_COLOR_GREY_3);
        fl_line_style(FL_DASH, 1, nullptr);
 
-       for (int pf : m_grid.points) {
+       for (int pf : m_grid.points)
+       {
                int pp = frameToPixel(pf);
                if (pp > from && pp < to)
-                       fl_line(pp+x(), y(), pp+x(), y()+h());
+                       fl_line(pp + x(), y(), pp + x(), y() + h());
        }
 
        fl_line_style(FL_SOLID, 0, nullptr);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::drawStartEndPoints()
 {
        /* print m_chanStart */
 
        int lineX = frameToPixel(m_chanStart) + x();
 
-       if (m_chanStartLit) fl_color(G_COLOR_LIGHT_2);
-       else                fl_color(G_COLOR_LIGHT_1);
+       if (m_chanStartLit)
+               fl_color(G_COLOR_LIGHT_2);
+       else
+               fl_color(G_COLOR_LIGHT_1);
 
        /* vertical line */
 
-       fl_line(lineX, y()+1, lineX, y()+h()-2);
+       fl_line(lineX, y() + 1, lineX, y() + h() - 2);
 
        /* print flag and avoid overflow */
 
-       if (lineX+FLAG_WIDTH > w()+x()-2)
-               fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT);
+       if (lineX + FLAG_WIDTH > w() + x() - 2)
+               fl_rectf(lineX, y() + h() - FLAG_HEIGHT - 1, w() - lineX + x() - 1, FLAG_HEIGHT);
        else
-               fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT);
+               fl_rectf(lineX, y() + h() - FLAG_HEIGHT - 1, FLAG_WIDTH, FLAG_HEIGHT);
 
        /* print m_chanEnd */
 
        lineX = frameToPixel(m_chanEnd) + x() - 1;
-       if (m_chanEndLit) fl_color(G_COLOR_LIGHT_2);
-       else            fl_color(G_COLOR_LIGHT_1);
+       if (m_chanEndLit)
+               fl_color(G_COLOR_LIGHT_2);
+       else
+               fl_color(G_COLOR_LIGHT_1);
 
        /* vertical line */
 
-       fl_line(lineX, y()+1, lineX, y()+h()-2);
+       fl_line(lineX, y() + 1, lineX, y() + h() - 2);
 
-       if (lineX-FLAG_WIDTH < x())
-               fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT);
+       if (lineX - FLAG_WIDTH < x())
+               fl_rectf(x() + 1, y() + 1, lineX - x(), FLAG_HEIGHT);
        else
-               fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT);
+               fl_rectf(lineX - FLAG_WIDTH, y() + 1, FLAG_WIDTH, FLAG_HEIGHT);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::drawPlayHead()
 {
        int p = frameToPixel(m_data->a_getPreviewTracker()) + x();
@@ -287,22 +280,20 @@ void geWaveform::drawPlayHead()
        fl_line(p, y() + 1, p, y() + h() - 2);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::draw()
 {
        assert(m_waveform.sup.size() > 0);
        assert(m_waveform.inf.size() > 0);
 
-       fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2);  // blank canvas
+       fl_rectf(x(), y(), w(), h(), G_COLOR_GREY_2); // blank canvas
 
        /* Draw things from 'from' (offset driven by the scrollbar) to 'to' (width of 
        parent window). We don't draw the entire waveform, only the visibile part. */
 
        int from = abs(x() - parent()->x());
-       int to = from + parent()->w();
+       int to   = from + parent()->w();
        if (x() + w() < parent()->w())
                to = x() + w() - BORDER;
 
@@ -311,198 +302,202 @@ void geWaveform::draw()
        drawGrid(from, to);
        drawPlayHead();
 
-       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4);   // border box
-       
+       fl_rect(x(), y(), w(), h(), G_COLOR_GREY_4); // border box
+
        drawStartEndPoints();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveform::handle(int e)
 {
-       /* TODO - geWaveform needs better isolation from m::. Refactoring needed. */
-
-       m::model::WavesLock l(m::model::waves);
-       const m::Wave& wave = m::model::get(m::model::waves, m_data->waveId);
+       const m::Wave& wave = m_data->getWaveRef();
 
        m_mouseX = pixelToFrame(Fl::event_x() - x());
        m_mouseY = pixelToFrame(Fl::event_y() - y());
 
-       switch (e) {
+       switch (e)
+       {
 
-               case FL_KEYDOWN: {
-                       if (Fl::event_key() == ' ')
-                               static_cast<v::gdSampleEditor*>(window())->cb_togglePreview();
-                       else
-                       if (Fl::event_key() == FL_BackSpace)
-                               c::sampleEditor::setPreviewTracker(m_data->begin);
+       case FL_KEYDOWN:
+       {
+               if (Fl::event_key() == ' ')
+                       static_cast<v::gdSampleEditor*>(window())->cb_togglePreview();
+               else if (Fl::event_key() == FL_BackSpace)
+                       c::sampleEditor::setPreviewTracker(m_data->begin);
+               return 1;
+       }
+
+       case FL_PUSH:
+       {
+
+               if (Fl::event_clicks() > 0)
+               {
+                       selectAll();
                        return 1;
                }
 
-               case FL_PUSH: {
+               m_pushed = true;
 
-                       if (Fl::event_clicks() > 0) {
-                               selectAll();
-                               return 1;
-                       }
-
-                       m_pushed = true;
-
-                       if (!mouseOnEnd() && !mouseOnStart()) {
-                               if (Fl::event_button3())  // let the parent (waveTools) handle this
-                                       return 0;
-                               if (mouseOnSelectionA())
-                                       m_resizedA = true;
-                               else
-                               if(mouseOnSelectionB())
-                                       m_resizedB = true;
-                               else {
-                                       m_dragged = true;
-                                       m_selection.a = m_mouseX;
-                                       m_selection.b = m_mouseX;
-                               }
+               if (!mouseOnEnd() && !mouseOnStart())
+               {
+                       if (Fl::event_button3()) // let the parent (waveTools) handle this
+                               return 0;
+                       if (mouseOnSelectionA())
+                               m_resizedA = true;
+                       else if (mouseOnSelectionB())
+                               m_resizedB = true;
+                       else
+                       {
+                               m_dragged     = true;
+                               m_selection.a = m_mouseX;
+                               m_selection.b = m_mouseX;
                        }
-                       return 1;
                }
+               return 1;
+       }
 
-               case FL_RELEASE: {
+       case FL_RELEASE:
+       {
 
-                       c::sampleEditor::setPreviewTracker(m_mouseX);
+               c::sampleEditor::setPreviewTracker(m_mouseX);
 
-                       /* If selection has been done (m_dragged or resized), make sure that point A 
+               /* If selection has been done (m_dragged or resized), make sure that point A 
                        is always lower than B. */
 
-                       if (m_dragged || m_resizedA || m_resizedB)
-                               fixSelection();
+               if (m_dragged || m_resizedA || m_resizedB)
+                       fixSelection();
 
-                       /* Handle begin/end markers interaction. */
+               /* Handle begin/end markers interaction. */
 
-                       if (m_chanStartLit || m_chanEndLit)
-                               c::sampleEditor::setBeginEnd(m_data->channelId, m_chanStart, m_chanEnd);
+               if (m_chanStartLit || m_chanEndLit)
+                       c::sampleEditor::setBeginEnd(m_data->channelId, m_chanStart, m_chanEnd);
 
-                       m_pushed   = false;
-                       m_dragged  = false;
-                       m_resizedA = false;
-                       m_resizedB = false;
+               m_pushed   = false;
+               m_dragged  = false;
+               m_resizedA = false;
+               m_resizedB = false;
 
-                       redraw();
-                       return 1;
-               }
+               redraw();
+               return 1;
+       }
 
-               case FL_ENTER: {  // enables FL_DRAG
-                       return 1;
-               }
+       case FL_ENTER:
+       { // enables FL_DRAG
+               return 1;
+       }
 
-               case FL_LEAVE: {
-                       if (m_chanStartLit || m_chanEndLit) {
-                               m_chanStartLit = false;
-                               m_chanEndLit   = false;
-                               redraw();
-                       }
-                       return 1;
+       case FL_LEAVE:
+       {
+               if (m_chanStartLit || m_chanEndLit)
+               {
+                       m_chanStartLit = false;
+                       m_chanEndLit   = false;
+                       redraw();
                }
+               return 1;
+       }
 
-               case FL_MOVE: {
+       case FL_MOVE:
+       {
 
-                       if (mouseOnStart()) {
-                               m_chanStartLit = true;
-                               redraw();
-                       }
-                       else
-                       if (m_chanStartLit) {
-                               m_chanStartLit = false;
-                               redraw();
-                       }
-
-                       if (mouseOnEnd()) {
-                               m_chanEndLit = true;
-                               redraw();
-                       }
-                       else
-                       if (m_chanEndLit) {
-                               m_chanEndLit = false;
-                               redraw();
-                       }
-
-                       if (mouseOnSelectionA() && isSelected())
-                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                       else
-                       if (mouseOnSelectionB() && isSelected())
-                               fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
-                       else
-                               fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
+               if (mouseOnStart())
+               {
+                       m_chanStartLit = true;
+                       redraw();
+               }
+               else if (m_chanStartLit)
+               {
+                       m_chanStartLit = false;
+                       redraw();
+               }
 
-                       return 1;
+               if (mouseOnEnd())
+               {
+                       m_chanEndLit = true;
+                       redraw();
+               }
+               else if (m_chanEndLit)
+               {
+                       m_chanEndLit = false;
+                       redraw();
                }
 
-               case FL_DRAG: {
+               if (mouseOnSelectionA() && isSelected())
+                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+               else if (mouseOnSelectionB() && isSelected())
+                       fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK);
+               else
+                       fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
 
-                       /* here the mouse is on the m_chanStart tool */
+               return 1;
+       }
 
-                       if (m_chanStartLit && m_pushed) {
-                               m_chanStart = snap(m_mouseX);
+       case FL_DRAG:
+       {
 
-                               if (m_chanStart < 0)
-                                       m_chanStart = 0;
-                               else
-                               if (m_chanStart >= m_chanEnd)
-                                       m_chanStart = m_chanEnd - 2;
+               /* here the mouse is on the m_chanStart tool */
 
-                               redraw();
-                       }
-                       else
-                       if (m_chanEndLit && m_pushed) {
+               if (m_chanStartLit && m_pushed)
+               {
+                       m_chanStart = snap(m_mouseX);
 
-                               m_chanEnd = snap(m_mouseX);
+                       if (m_chanStart < 0)
+                               m_chanStart = 0;
+                       else if (m_chanStart >= m_chanEnd)
+                               m_chanStart = m_chanEnd - 2;
 
-                               if (m_chanEnd > wave.getSize())
-                                       m_chanEnd = wave.getSize();
-                               else
-                               if (m_chanEnd <= m_chanStart)
-                                       m_chanEnd = m_chanStart + 2;
+                       redraw();
+               }
+               else if (m_chanEndLit && m_pushed)
+               {
 
-                               redraw();
-                       }
+                       m_chanEnd = snap(m_mouseX);
 
-                       /* Here the mouse is on the waveform, i.e. a new selection has started. */
+                       if (m_chanEnd > wave.getBuffer().countFrames())
+                               m_chanEnd = wave.getBuffer().countFrames();
+                       else if (m_chanEnd <= m_chanStart)
+                               m_chanEnd = m_chanStart + 2;
 
-                       else
-                       if (m_dragged) {
-                               m_selection.b = snap(m_mouseX);
-                               redraw();
-                       }
+                       redraw();
+               }
 
-                       /* here the mouse is on a selection boundary i.e. resize */
+               /* Here the mouse is on the waveform, i.e. a new selection has started. */
 
-                       else
-                       if (m_resizedA || m_resizedB) {
-                               int pos = snap(m_mouseX);
-                               m_resizedA ? m_selection.a = pos : m_selection.b = pos;
-                               redraw();
-                       }
+               else if (m_dragged)
+               {
+                       m_selection.b = snap(m_mouseX);
+                       redraw();
+               }
 
-                       return 1;
+               /* here the mouse is on a selection boundary i.e. resize */
+
+               else if (m_resizedA || m_resizedB)
+               {
+                       int pos                    = snap(m_mouseX);
+                       m_resizedA ? m_selection.a = pos : m_selection.b = pos;
+                       redraw();
                }
 
-               default:
-                       return Fl_Widget::handle(e);
+               return 1;
        }
-}
 
+       default:
+               return Fl_Widget::handle(e);
+       }
+}
 
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveform::snap(int pos)
 {
        // TODO use math::quantize
        if (!m_grid.snap)
                return pos;
-       for (int pf : m_grid.points) {
+       for (int pf : m_grid.points)
+       {
                if (pos >= pf - pixelToFrame(SNAPPING) &&
-                               pos <= pf + pixelToFrame(SNAPPING))
+                   pos <= pf + pixelToFrame(SNAPPING))
                {
                        return pf;
                }
@@ -510,38 +505,32 @@ int geWaveform::snap(int pos)
        return pos;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geWaveform::mouseOnStart() const
 {
        int mouseXp    = frameToPixel(m_mouseX);
        int mouseYp    = frameToPixel(m_mouseY);
        int chanStartP = frameToPixel(m_chanStart);
-       return mouseXp - (FLAG_WIDTH / 2) >  chanStartP - BORDER              &&
-                                mouseXp - (FLAG_WIDTH / 2) <= chanStartP - BORDER + FLAG_WIDTH &&
-                                mouseYp > h() - FLAG_HEIGHT;
+       return mouseXp - (FLAG_WIDTH / 2) > chanStartP - BORDER &&
+              mouseXp - (FLAG_WIDTH / 2) <= chanStartP - BORDER + FLAG_WIDTH &&
+              mouseYp > h() - FLAG_HEIGHT;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geWaveform::mouseOnEnd() const
 {
        int mouseXp  = frameToPixel(m_mouseX);
        int mouseYp  = frameToPixel(m_mouseY);
        int chanEndP = frameToPixel(m_chanEnd);
        return mouseXp - (FLAG_WIDTH / 2) >= chanEndP - BORDER - FLAG_WIDTH &&
-                                mouseXp - (FLAG_WIDTH / 2) <= chanEndP - BORDER              &&
-                                mouseYp <= FLAG_HEIGHT + 1;
+              mouseXp - (FLAG_WIDTH / 2) <= chanEndP - BORDER &&
+              mouseYp <= FLAG_HEIGHT + 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geWaveform::mouseOnSelectionA() const
 {
        int mouseXp = frameToPixel(m_mouseX);
@@ -549,7 +538,6 @@ bool geWaveform::mouseOnSelectionA() const
        return mouseXp >= selAp - (FLAG_WIDTH / 2) && mouseXp <= selAp + (FLAG_WIDTH / 2);
 }
 
-
 bool geWaveform::mouseOnSelectionB() const
 {
        int mouseXp = frameToPixel(m_mouseX);
@@ -557,10 +545,8 @@ bool geWaveform::mouseOnSelectionB() const
        return mouseXp >= selBp - (FLAG_WIDTH / 2) && mouseXp <= selBp + (FLAG_WIDTH / 2);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveform::pixelToFrame(int p) const
 {
        if (p <= 0)
@@ -570,19 +556,15 @@ int geWaveform::pixelToFrame(int p) const
        return p * m_ratio;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveform::frameToPixel(int p) const
 {
        return ceil(p / m_ratio);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::fixSelection()
 {
        if (m_selection.a > m_selection.b) // inverted m_selection
@@ -591,29 +573,25 @@ void geWaveform::fixSelection()
        c::sampleEditor::setPreviewTracker(m_selection.a);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::clearSelection()
 {
        m_selection.a = 0;
-       m_selection.b = 0;  
+       m_selection.b = 0;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::setZoom(Zoom z)
 {
-       if (!alloc(z == Zoom::IN ? m_waveform.size * G_GUI_ZOOM_FACTOR : m_waveform.size / G_GUI_ZOOM_FACTOR)) 
+       if (!alloc(z == Zoom::IN ? m_waveform.size * G_GUI_ZOOM_FACTOR : m_waveform.size / G_GUI_ZOOM_FACTOR))
                return;
 
        size(m_waveform.size, h());
 
        /* Zoom to cursor. */
-       
+
        int newX = -frameToPixel(m_mouseX) + Fl::event_x();
        if (newX > BORDER)
                newX = BORDER;
@@ -630,7 +608,7 @@ void geWaveform::setZoom(Zoom z)
                |-------------]   | offset < 0, smaller = false  */
 
        int parentW = parent()->w();
-       int thisW   = x() + w() - BORDER;           // visible width, not full width
+       int thisW   = x() + w() - BORDER; // visible width, not full width
 
        if (thisW < parentW)
                position(x() + parentW - thisW, y());
@@ -640,10 +618,8 @@ void geWaveform::setZoom(Zoom z)
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::stretchToWindow()
 {
        int s = parent()->w();
@@ -652,10 +628,8 @@ void geWaveform::stretchToWindow()
        size(s, h());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::rebuild(const c::sampleEditor::Data& d)
 {
        m_data = &d;
@@ -664,19 +638,15 @@ void geWaveform::rebuild(const c::sampleEditor::Data& d)
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geWaveform::smaller() const
 {
        return w() < parent()->w();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::setGridLevel(int l)
 {
        m_grid.points.clear();
@@ -685,35 +655,29 @@ void geWaveform::setGridLevel(int l)
        redraw();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool geWaveform::isSelected() const
 {
        return m_selection.a != m_selection.b;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void geWaveform::setSnap(bool v) { m_grid.snap = v; }
 bool geWaveform::getSnap() const { return m_grid.snap; }
-int geWaveform::getSize() const { return m_waveform.size; }
-
+int  geWaveform::getSize() const { return m_waveform.size; }
 
 /* -------------------------------------------------------------------------- */
 
-
 int geWaveform::getSelectionA() const { return m_selection.a; }
 int geWaveform::getSelectionB() const { return m_selection.b; }
 
-
 void geWaveform::selectAll()
 {
        m_selection.a = 0;
        m_selection.b = m_data->waveSize - 1;
        redraw();
 }
-}} // giada::v::
+} // namespace v
+} // namespace giada
index 82f311d497c1b59de1ab4b168b7196b6b3256453..b184747c49eeed5618010ed1831f7c01d0f20cdf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_WAVEFORM_H
 #define GE_WAVEFORM_H
 
-
-#include <vector>
-#include <FL/Fl_Widget.H>
 #include "core/const.h"
+#include "core/types.h"
+#include <FL/Fl_Widget.H>
+#include <vector>
 
-
-namespace giada {
-namespace v 
+namespace giada::c::sampleEditor
+{
+struct Data;
+}
+namespace giada::v
 {
 class geWaveform : public Fl_Widget
 {
 public:
-
 #ifdef G_OS_WINDOWS
-       /* Fuck... */
-       #undef IN
-       #undef OUT
+/* Fuck... */
+#undef IN
+#undef OUT
 #endif
-       enum class Zoom { IN, OUT };
+       enum class Zoom
+       {
+               IN,
+               OUT
+       };
 
        geWaveform(int x, int y, int w, int h);
 
@@ -62,7 +66,7 @@ public:
        int getSelectionB() const;
 
        bool getSnap() const;
-       int getSize() const;
+       int  getSize() const;
 
        /* recalcPoints
        Recomputes m_chanStart, m_chanEnd, ... */
@@ -99,13 +103,12 @@ public:
        /* setWaveId
        Call this when the Wave ID has changed (e.g. after a reload). */
 
-       void setWaveId(ID /*id*/ ) { /* TODO m_waveId = id;*/};
-
-private:
+       void setWaveId(ID /*id*/){/* TODO m_waveId = id;*/};
 
+  private:
        static const int FLAG_WIDTH  = 20;
        static const int FLAG_HEIGHT = 20;
-       static const int BORDER      = 8;  // window border <-> widget border
+       static const int BORDER      = 8; // window border <-> widget border
        static const int SNAPPING    = 16;
 
        /* selection
@@ -122,18 +125,18 @@ private:
 
        struct
        {
-               std::vector<int> sup;   // upper part of the waveform
-               std::vector<int> inf;   // lower part of the waveform
-               int  size;  // width of the waveform to draw (in pixel)
+               std::vector<int> sup;  // upper part of the waveform
+               std::vector<int> inf;  // lower part of the waveform
+               int              size; // width of the waveform to draw (in pixel)
        } m_waveform;
 
        struct
        {
-               bool snap;
-               int level;
+               bool             snap;
+               int              level;
                std::vector<int> points;
        } m_grid;
-       
+
        /* mouseOnStart/end
        Is mouse on start or end flag? */
 
@@ -151,8 +154,8 @@ private:
 
        bool smaller() const;
 
-       int pixelToFrame(int p) const;  // TODO - move these to utils::, will be needed in actionEditor 
-       int frameToPixel(int f) const;  // TODO - move these to utils::, will be needed in actionEditor 
+       int pixelToFrame(int p) const; // TODO - move these to utils::, will be needed in actionEditor
+       int frameToPixel(int f) const; // TODO - move these to utils::, will be needed in actionEditor
 
        /* fixSelection
        Helper function which flattens the selection if it was made from right to left 
@@ -186,7 +189,7 @@ private:
        Allocates memory for the picture. It's smart enough not to reallocate if 
        datasize hasn't changed, but it can be forced otherwise. */
 
-       int alloc(int datasize, bool force=false);
+       int alloc(int datasize, bool force = false);
 
        const c::sampleEditor::Data* m_data;
 
@@ -202,7 +205,6 @@ private:
        int   m_mouseX;
        int   m_mouseY;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 44646afbff1e3005db0463b77a868743b85f5353..05777afebc1e045f8a661f55dcf15606bc991181 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
-#include <FL/fl_draw.H>
+#include "soundMeter.h"
 #include "core/const.h"
 #include "core/kernelAudio.h"
+#include "core/types.h"
 #include "utils/math.h"
-#include "soundMeter.h"
-
+#include <FL/fl_draw.H>
+#include <algorithm>
+#include <cmath>
 
-namespace giada {
-namespace v
+namespace giada::v
 {
-geSoundMeter::geSoundMeter(int x, int y, int w, int h, const char* l)
-: Fl_Box      (x, y, w, h, l),
-  mixerPeak   (0.0f),
-  m_dbLevelCur(0.0f),
-  m_dbLevelOld(0.0f)
+namespace
 {
+Pixel dbToPx_(float db, Pixel max)
+{
+       const float maxf = max;
+       return std::clamp(u::math::map(db, -G_MIN_DB_SCALE, 0.0f, 0.0f, maxf), 0.0f, maxf);
 }
+} // namespace
 
-
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
+geSoundMeter::geSoundMeter(int x, int y, int w, int h, const char* l)
+: Fl_Box(x, y, w, h, l)
+, mixerPeak(0.0f)
+, m_dbLevelOld(0.0f)
+{
+}
+
+/* -------------------------------------------------------------------------- */
 
 void geSoundMeter::draw()
 {
@@ -54,22 +63,22 @@ void geSoundMeter::draw()
 
        /* Compute peak level on 0.0 -> 1.0 scale. 1.0 is considered clip. */
 
-       bool clip = std::fabs(mixerPeak) >= 1.0f ? true : false;
+       const bool clip = std::fabs(mixerPeak) >= 1.0f ? true : false;
 
        /*  dBFS (full scale) calculation, plus decay of -2dB per frame. */
 
-       m_dbLevelCur = u::math::linearToDB(std::fabs(mixerPeak));
+       float dbLevelCur = u::math::linearToDB(std::fabs(mixerPeak));
 
-       if (m_dbLevelCur < m_dbLevelOld && m_dbLevelOld > -G_MIN_DB_SCALE)
-               m_dbLevelCur = m_dbLevelOld - 2.0f;
+       if (dbLevelCur < m_dbLevelOld && m_dbLevelOld > -G_MIN_DB_SCALE)
+               dbLevelCur = m_dbLevelOld - 2.0f;
 
-       m_dbLevelOld = m_dbLevelCur;
+       m_dbLevelOld = dbLevelCur;
 
        /* Paint the meter on screen. */
 
-       float pxLevel = ((w()/G_MIN_DB_SCALE) * m_dbLevelCur) + w();
+       const int bodyCol = clip || !m::kernelAudio::isReady() ? G_COLOR_RED_ALERT : G_COLOR_GREY_4;
 
-       fl_rectf(x()+1, y()+1, w()-2, h()-2, G_COLOR_GREY_2);
-       fl_rectf(x()+1, y()+1, (int) pxLevel, h()-2, clip || !m::kernelAudio::isReady() ? G_COLOR_RED_ALERT : G_COLOR_GREY_4);
+       fl_rectf(x() + 1, y() + 1, w() - 2, h() - 2, G_COLOR_GREY_2);
+       fl_rectf(x() + 1, y() + 1, dbToPx_(dbLevelCur, w()), h() - 2, bodyCol);
 }
-}} // giada::v::
+} // namespace giada::v
\ No newline at end of file
index 118bbf8e972e81e525a83868e921e72219754e60..4669326ebe2865cf922e755f01a263a881eaa0c4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef GE_SOUND_METER_H
 #define GE_SOUND_METER_H
 
-
 #include <FL/Fl_Box.H>
 
-
-namespace giada {
-namespace v
+namespace giada::v
 {
 class geSoundMeter : public Fl_Box
 {
 public:
-
-       geSoundMeter(int x, int y, int w, int h, const char* l=0);
+       geSoundMeter(int x, int y, int w, int h, const char* l = 0);
 
        void draw() override;
 
-    float mixerPeak;    // peak from mixer
+       float mixerPeak; // peak from mixer
 
 private:
-
-       float m_dbLevelCur;
        float m_dbLevelOld;
 };
-}} // giada::v::
-
+} // namespace giada::v
 
 #endif
index 3ebc2c1a84f31d11948e338d94e9bfe985a68780..ba216382f0a6cd2df4f4b8fde4445069d345fef2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "model.h"
 #include "core/patch.h"
-#include "utils/log.h"
 #include "gui/dialogs/mainWindow.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/elems/mainWindow/keyboard/column.h"
 #include "gui/elems/mainWindow/keyboard/channel.h"
-#include "model.h"
-
+#include "gui/elems/mainWindow/keyboard/column.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
+#include "utils/log.h"
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace v {
-namespace model
+namespace giada::v::model
 {
 void store(m::patch::Patch& patch)
 {
-    G_MainWin->keyboard->forEachColumn([&](const geColumn& c)
-    {
-        patch.columns.push_back({ c.id, c.w() });
-    });
+       G_MainWin->keyboard->forEachColumn([&](const geColumn& c) {
+               patch.columns.push_back({c.id, c.w()});
+       });
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void load(const m::patch::Patch& patch)
 {
-    G_MainWin->keyboard->layout.clear();
-    for (const m::patch::Column& col : patch.columns)
-        G_MainWin->keyboard->layout.push_back({ col.id, col.width });
+       G_MainWin->keyboard->layout.clear();
+       for (const m::patch::Column& col : patch.columns)
+               G_MainWin->keyboard->layout.push_back({col.id, col.width});
 }
-}}} // giada::v::model
+} // namespace giada::v::model
index 198f8ad6a32454fe30ef600bb8dbe55ea746a87e..97e4986d64c1539c0313f4d193fb8ea80cd189e9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_V_MODEL_H
 #define G_V_MODEL_H
 
-
-namespace giada {
-namespace m { namespace patch
+namespace giada::m::patch
 {
 struct Patch;
-}}
-namespace v {
-namespace model
+}
+namespace giada::v::model
 {
 void store(m::patch::Patch& patch);
 void load(const m::patch::Patch& patch);
-}}} // giada::v::model
-
+} // namespace giada::v::model
 
 #endif
\ No newline at end of file
index bf698ee6bbcae614408ad9ec9c919348a7420723..3ecdc767da0cb591f7150673102448ffd0e9e873 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
+#include "updater.h"
 #include "core/const.h"
 #include "core/model/model.h"
 #include "utils/gui.h"
-#include "updater.h"
-
+#include <FL/Fl.H>
 
-namespace giada {
-namespace v {
-namespace updater
+namespace giada::v::updater
 {
-void update(void* /*p*/)
+void init()
 {
-       if (m::model::waves.changed.load()    == true ||
-               m::model::actions.changed.load()  == true ||
-               m::model::channels.changed.load()  == true)
-       {
-               u::gui::rebuild();
-               m::model::waves.changed.store(false);
-               m::model::actions.changed.store(false);
-               m::model::channels.changed.store(false);
-       }
-       else
-               u::gui::refresh();
+       m::model::onSwap([](m::model::SwapType type) {
+               if (type == m::model::SwapType::NONE)
+                       return;
+
+               /* This callback is fired by the updater thread, so it requires
+               synchronization with the main one. */
+
+               Fl::lock();
+               type == m::model::SwapType::HARD ? u::gui::rebuild() : u::gui::refresh();
+               Fl::unlock();
+       });
 
        Fl::add_timeout(G_GUI_REFRESH_RATE, update, nullptr);
 }
-}}} // giada::v::updater
+
+/* -------------------------------------------------------------------------- */
+
+void update(void* /*p*/)
+{
+       u::gui::refresh();
+       Fl::add_timeout(G_GUI_REFRESH_RATE, update, nullptr);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void close()
+{
+       Fl::remove_timeout(update);
+}
+} // namespace giada::v::updater
index 3c028bcc164b2709b944c79fcc0b5461ba199055..d2dca2c8d61d55ce38127320bd353f137108f5d0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_V_UPDATER_H
 #define G_V_UPDATER_H
 
-
-namespace giada {
-namespace v {
-namespace updater
+namespace giada::v::updater
 {
+void init();
 void update(void* p);
-}}} // giada::v::updater
-
+void close();
+} // namespace giada::v::updater
 
 #endif
\ No newline at end of file
index 7bfcbe5bd4ed13354250750329addb0ecb5675c0..b7bf05b404461d83e54b53d5a5ebf0643e6f3e16 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <FL/Fl.H>
 #include "core/init.h"
 #include "gui/dialogs/mainWindow.h"
+#include <FL/Fl.H>
 #ifdef WITH_TESTS
-       #define CATCH_CONFIG_RUNNER
-       #include <vector>
-       #include <string>
-       #include <catch2/catch.hpp>
-       #include "tests/audioBuffer.cpp"
-       #include "tests/rcuList.cpp"
-       #include "tests/recorder.cpp"
-       #include "tests/utils.cpp"
-       #include "tests/wave.cpp"
-       #include "tests/waveFx.cpp"
-       #include "tests/waveManager.cpp"
+#define CATCH_CONFIG_RUNNER
+#include "tests/audioBuffer.cpp"
+#include "tests/recorder.cpp"
+#include "tests/utils.cpp"
+#include "tests/wave.cpp"
+#include "tests/waveFx.cpp"
+#include "tests/waveManager.cpp"
+#include <catch2/catch.hpp>
+#include <string>
+#include <vector>
 #endif
 
-
 class giada::v::gdMainWindow* G_MainWin = nullptr;
 
-
 int main(int argc, char** argv)
 {
 #ifdef WITH_TESTS
@@ -56,6 +52,7 @@ int main(int argc, char** argv)
 
        giada::m::init::startup(argc, argv);
 
+       Fl::lock(); // Enable multithreading in FLTK
        int ret = Fl::run();
 
        giada::m::init::shutdown();
index 4b4f96d650081c76f274b85e9d1d7fcf81c7cd29..155eb6bd843a02c0b9360af2b9c6c90c607a4db7 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_COCOA_H
 #define G_UTILS_COCOA_H
 
-
 /* fl_xid() from FLTK returns a pointer to NSWindow, but plugins on OS X want a
 pointer to NSView. The function does the hard conversion. */
 
@@ -42,5 +40,4 @@ TODO temporarily disabled: it does not work. */
 
 //void cocoa_setWindowSize(void *p, int w, int h);
 
-
 #endif
index 9eac2520aae9322a7ea260d905d5ddd1c9447f60..beb22ab9242d4fce4d52ddd5a3de766a41175591 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #include <filesystem>
-#if defined(_WIN32)                    // getcwd (unix) or __getcwd (win)
-       #include <direct.h>
-       #include <windows.h>
+#if defined(_WIN32) // getcwd (unix) or __getcwd (win)
+#include <direct.h>
+#include <windows.h>
 #else
-       #include <unistd.h>
+#include <unistd.h>
 #endif
+#include <climits>
 #include <cstdarg>
-#include <sys/stat.h>       // stat (fs::dirExists)
-#include <errno.h>
-#include <cstdlib>
 #include <cstdint>
-#include <string>
+#include <cstdlib>
 #include <cstring>
-#include <climits>
+#include <errno.h>
+#include <string>
+#include <sys/stat.h> // stat (fs::dirExists)
 #ifdef __APPLE__
-       #include <libgen.h>     // basename unix
-       #include <pwd.h>        // getpwuid
+#include <libgen.h> // basename unix
+#include <pwd.h>    // getpwuid
 #endif
 #include "core/const.h"
-#include "utils/string.h"
-#include "utils/log.h"
 #include "utils/fs.h"
+#include "utils/log.h"
+#include "utils/string.h"
 
+namespace stdfs = std::filesystem;
 
-namespace giada {
-namespace u     {
-namespace fs 
+namespace giada::u::fs
 {
 bool fileExists(const std::string& s)
 {
-       return std::filesystem::exists(s);
+       return stdfs::exists(s);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isDir(const std::string& s)
 {
-       return std::filesystem::is_directory(s) && !isProject(s);
+       return stdfs::is_directory(s) && !isProject(s);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool dirExists(const std::string& s)
-{ 
-       return std::filesystem::exists(s);
+{
+       return stdfs::exists(s);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool mkdir(const std::string& s)
 {
-       return dirExists(s) ? true : std::filesystem::create_directory(s);
+       return dirExists(s) ? true : stdfs::create_directory(s);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getRealPath(const std::string& s)
 {
-       return s.empty() ? "" : std::filesystem::canonical(s).string();
+       return s.empty() || !stdfs::exists(s) ? "" : stdfs::canonical(s).string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string basename(const std::string& s)
 {
-       return std::filesystem::path(s).filename().string();
+       return stdfs::path(s).filename().string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string dirname(const std::string& s)
 {
-       return std::filesystem::path(s).parent_path().string();
+       return stdfs::path(s).parent_path().string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getCurrentPath()
 {
-       return std::filesystem::current_path().string();
+       return stdfs::current_path().string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getExt(const std::string& s)
 {
-       return std::filesystem::path(s).extension().string();
+       return stdfs::path(s).extension().string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string stripExt(const std::string& s)
 {
-       return std::filesystem::path(s).replace_extension("").string();
+       return stdfs::path(s).replace_extension("").string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isProject(const std::string& s)
 {
        /** TODO - checks too weak. */
        return getExt(s) == ".gprj";
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string stripFileUrl(const std::string& s)
 {
        std::string out = s;
-       out = u::string::replace(out, "file://", "");
-       out = u::string::replace(out, "%20", " ");
+       out             = u::string::replace(out, "file://", "");
+       out             = u::string::replace(out, "%20", " ");
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getHomePath()
 {
 #if defined(G_OS_LINUX) || defined(G_OS_FREEBSD)
@@ -182,9 +156,10 @@ std::string getHomePath()
 
 #elif defined(G_OS_MAC)
 
-       char buf[PATH_MAX];
+       char           buf[PATH_MAX];
        struct passwd* pwd = getpwuid(getuid());
-       if (pwd == nullptr) {
+       if (pwd == nullptr)
+       {
                log::print("[getHomePath] unable to fetch user infos\n");
                return "";
        }
@@ -193,32 +168,28 @@ std::string getHomePath()
 
 #endif
 
-       return std::filesystem::path(buf).string();
+       return stdfs::path(buf).string();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool isRootDir(const std::string& s)
 {
-       return std::filesystem::current_path().root_directory() == s;
+       return stdfs::current_path().root_directory() == s;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getUpDir(const std::string& s)
 {
 #ifdef G_OS_WINDOWS
 
-       // If root, let the user browse the drives list by returning "". 
+       // If root, let the user browse the drives list by returning "".
        if (isRootDir(s))
                return "";
 
 #endif
 
-       return std::filesystem::path(s).parent_path().string();
+       return stdfs::path(s).parent_path().string();
 }
-}}}  // giada::u::fs::
\ No newline at end of file
+} // namespace giada::u::fs
\ No newline at end of file
index 16fae9470437358e4156851edb9b75ee254bdf2c..9161ad48b397f550650934faff0477dfedb16281 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_FS_H
 #define G_UTILS_FS_H
 
-
 #include <string>
 
-
-namespace giada {
-namespace u {
-namespace fs 
+namespace giada::u::fs
 {
 bool fileExists(const std::string& s);
 bool dirExists(const std::string& s);
@@ -47,8 +42,8 @@ Tells whether 's' is '/' on Unix or '[X]:\' on Windows. */
 
 bool isRootDir(const std::string& s);
 
-bool isProject(const std::string& s);
-bool mkdir(const std::string& s);
+bool        isProject(const std::string& s);
+bool        mkdir(const std::string& s);
 std::string getCurrentPath();
 std::string getHomePath();
 
@@ -85,7 +80,6 @@ Returns the upper directory:
 /path/to/my/directory -> /path/to/my/ */
 
 std::string getUpDir(const std::string& s);
-}}}  // giada::u::fs::
-
+} // namespace giada::u::fs
 
 #endif
index 72fa1b8623eb69d7f0536f6114f636815e84cd29..6d6b31eda84a9e0bd88c446932247cb8583a2066 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <string>
 #include <FL/Fl.H>
 #include <FL/fl_draw.H>
+#include <string>
 #if defined(_WIN32)
-       #include "../ext/resource.h"
+#include "../ext/resource.h"
 #elif defined(__linux__) || defined(__FreeBSD__)
-       #include <X11/xpm.h>
+#include <X11/xpm.h>
 #endif
-#include "core/mixer.h"
-#include "core/mixerHandler.h"
 #include "core/clock.h"
-#include "core/plugins/pluginHost.h"
 #include "core/conf.h"
 #include "core/graphics.h"
-#include "gui/dialogs/warnings.h"
-#include "gui/dialogs/mainWindow.h"
+#include "core/mixer.h"
+#include "core/mixerHandler.h"
+#include "core/plugins/pluginHost.h"
+#include "gui.h"
 #include "gui/dialogs/actionEditor/baseActionEditor.h"
-#include "gui/dialogs/window.h"
+#include "gui/dialogs/mainWindow.h"
 #include "gui/dialogs/sampleEditor.h"
+#include "gui/dialogs/warnings.h"
+#include "gui/dialogs/window.h"
+#include "gui/elems/mainWindow/sequencer.h"
+#include "gui/elems/mainWindow/keyboard/channel.h"
+#include "gui/elems/mainWindow/keyboard/keyboard.h"
 #include "gui/elems/mainWindow/mainIO.h"
 #include "gui/elems/mainWindow/mainTimer.h"
 #include "gui/elems/mainWindow/mainTransport.h"
-#include "gui/elems/mainWindow/beatMeter.h"
-#include "gui/elems/mainWindow/keyboard/keyboard.h"
-#include "gui/elems/mainWindow/keyboard/channel.h"
 #include "gui/elems/sampleEditor/waveTools.h"
 #include "log.h"
 #include "string.h"
-#include "gui.h"
-
 
 extern giada::v::gdMainWindow* G_MainWin;
 
-
-namespace giada {
-namespace u {
-namespace gui 
+namespace giada
+{
+namespace u
+{
+namespace gui
 {
 namespace
 {
 int blinker_ = 0;
-} // {anonymous}
-
+} // namespace
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
-
 void rebuildSubWindow(int wid)
 {
        v::gdWindow* w = getSubwindow(G_MainWin, wid);
-       if(w != nullptr)  // If its open
-               w->rebuild();   
+       if (w != nullptr) // If its open
+               w->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void refreshSubWindow(int wid)
 {
        v::gdWindow* w = getSubwindow(G_MainWin, wid);
-       if(w != nullptr)  // If its open
-               w->refresh();           
+       if (w != nullptr) // If its open
+               w->refresh();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void refresh()
 {
        /* Update dynamic elements inside main window: in and out meters, beat meter
@@ -112,10 +105,8 @@ void refresh()
        refreshSubWindow(WID_SAMPLE_EDITOR);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void rebuild()
 {
        G_MainWin->rebuild();
@@ -124,19 +115,15 @@ void rebuild()
        rebuildSubWindow(WID_ACTION_EDITOR);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 bool shouldBlink()
 {
        return blinker_ > 6;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateStaticWidgets()
 {
        using namespace giada::m;
@@ -146,9 +133,9 @@ void updateStaticWidgets()
 
 #ifdef WITH_VST
 
-//     G_MainWin->mainIO->setMasterFxOutFull(pluginHost::getStack(pluginHost::StackType::MASTER_OUT).plugins.size() > 0);
-//     G_MainWin->mainIO->setMasterFxInFull(pluginHost::getStack(pluginHost::StackType::MASTER_IN).plugins.size() > 0);
-       
+       //      G_MainWin->mainIO->setMasterFxOutFull(pluginHost::getStack(pluginHost::StackType::MASTER_OUT).plugins.size() > 0);
+       //      G_MainWin->mainIO->setMasterFxInFull(pluginHost::getStack(pluginHost::StackType::MASTER_IN).plugins.size() > 0);
+
 #endif
 
        G_MainWin->mainTimer->setMeter(clock::getBeats(), clock::getBars());
@@ -156,20 +143,16 @@ void updateStaticWidgets()
        G_MainWin->mainTimer->setQuantizer(clock::getQuantizerValue());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void updateMainWinLabel(const std::string& s)
 {
        std::string out = std::string(G_APP_NAME) + " - " + s;
        G_MainWin->copy_label(out.c_str());
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void setFavicon(v::gdWindow* w)
 {
 #if defined(__linux__) || defined(__FreeBSD__)
@@ -177,23 +160,22 @@ void setFavicon(v::gdWindow* w)
        fl_open_display();
        Pixmap p, mask;
        XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display),
-               (char **) giada_icon, &p, &mask, nullptr);
-       w->icon((char *)p);
+           (char**)giada_icon, &p, &mask, nullptr);
+       w->icon((char*)p);
 
 #elif defined(_WIN32)
 
-       w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1)));
+       w->icon((char*)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1)));
 
 #endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void openSubWindow(v::gdWindow* parent, v::gdWindow* child, int id)
 {
-       if (parent->hasWindow(id)) {
+       if (parent->hasWindow(id))
+       {
                u::log::print("[GU] parent has subwindow with id=%d, deleting\n", id);
                parent->delSubWindow(id);
        }
@@ -201,10 +183,8 @@ void openSubWindow(v::gdWindow* parent, v::gdWindow* child, int id)
        parent->addSubWindow(child);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void refreshActionEditor()
 {
        v::gdBaseActionEditor* ae = static_cast<v::gdBaseActionEditor*>(G_MainWin->getChild(WID_ACTION_EDITOR));
@@ -212,10 +192,8 @@ void refreshActionEditor()
                ae->rebuild();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 v::gdWindow* getSubwindow(v::gdWindow* parent, int id)
 {
        if (parent->hasWindow(id))
@@ -224,10 +202,8 @@ v::gdWindow* getSubwindow(v::gdWindow* parent, int id)
                return nullptr;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void closeAllSubwindows()
 {
        /* don't close WID_FILE_BROWSER, because it's the caller of this
@@ -239,10 +215,8 @@ void closeAllSubwindows()
        G_MainWin->delSubWindow(WID_FX);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int getStringWidth(const std::string& s)
 {
        int w = 0;
@@ -251,32 +225,29 @@ int getStringWidth(const std::string& s)
        return w;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string removeFltkChars(const std::string& s)
 {
        std::string out = u::string::replace(s, "/", "-");
-       out = u::string::replace(out, "|", "-");
-       out = u::string::replace(out, "&", "-");
-       out = u::string::replace(out, "_", "-");
+       out             = u::string::replace(out, "|", "-");
+       out             = u::string::replace(out, "&", "-");
+       out             = u::string::replace(out, "_", "-");
        return out;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string truncate(const std::string& s, Pixel width)
 {
-       if (s.empty() || getStringWidth(s) <= width) 
+       if (s.empty() || getStringWidth(s) <= width)
                return s;
-       
+
        std::string tmp  = s;
        std::size_t size = tmp.size();
 
-       while (getStringWidth(tmp + "...") > width) {
+       while (getStringWidth(tmp + "...") > width)
+       {
                if (size == 0)
                        return "";
                tmp.resize(--size);
@@ -287,15 +258,15 @@ std::string truncate(const std::string& s, Pixel width)
 
 /* -------------------------------------------------------------------------- */
 
-
 int centerWindowX(int w)
 {
        return (Fl::w() / 2) - (w / 2);
 }
 
-
 int centerWindowY(int h)
 {
        return (Fl::h() / 2) - (h / 2);
 }
-}}} // giada::u::gui::
+} // namespace gui
+} // namespace u
+} // namespace giada
index 323b53412ccedb2d52a0ce737ddd172990bfd198..36dc54465769012e76a1911a7dddff20d28ebce7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_GUI_H
 #define G_UTILS_GUI_H
 
-
-#include <string>
 #include "core/types.h"
-
+#include <string>
 
 namespace giada
 {
@@ -39,8 +36,9 @@ namespace v
 {
 class gdWindow;
 }
-namespace u {
-namespace gui 
+namespace u
+{
+namespace gui
 {
 /* refresh
 Repaints some dynamic GUI elements. */
@@ -113,7 +111,8 @@ std::string truncate(const std::string& s, Pixel width);
 int centerWindowX(int w);
 int centerWindowY(int h);
 
-}}} // giada::u::gui::
-
+} // namespace gui
+} // namespace u
+} // namespace giada
 
 #endif
index 457d34f375e335c1d70e77845dc0757e33b10756..1c90f51b4341002a76477186fae920eb8d21218b 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "log.h"
 #include <cstdio>
 #include <string>
-#include "log.h"
-
 
 namespace giada::u::log
 {
@@ -38,10 +36,12 @@ int init(int m)
 {
        mode = m;
        stat = true;
-       if (mode == LOG_MODE_FILE) {
+       if (mode == LOG_MODE_FILE)
+       {
                std::string fpath = fs::getHomePath() + G_SLASH + "giada.log";
-               f = std::fopen(fpath.c_str(), "a");
-               if (!f) {
+               f                 = std::fopen(fpath.c_str(), "a");
+               if (!f)
+               {
                        stat = false;
                        return 0;
                }
@@ -49,13 +49,11 @@ int init(int m)
        return 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 void close()
 {
        if (mode == LOG_MODE_FILE)
                std::fclose(f);
 }
-}  // giada::u::log
+} // namespace giada::u::log
index e7c43795c1cf3f8d87fa6f56484e9709651fb30f..0b9cfc7302fc6a4fb70c71bced9a2cf06e80747f 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_LOG_H
 #define G_UTILS_LOG_H
 
-
+#include "core/const.h"
+#include "utils/fs.h"
 #include <cstdio>
 #include <string>
 #include <type_traits>
 #include <utility>
-#include "utils/fs.h"
-#include "core/const.h"
-
 
-namespace giada::u::log 
+namespace giada::u::log
 {
 inline FILE* f;
 inline int   mode;
@@ -57,14 +54,13 @@ void close();
 Internal utility function for string transformation. Uses forwarding references
 (&&) to avoid useless string copy. */
 
-static constexpr auto string_to_c_str = [] (auto&& s) 
-{
+static constexpr auto string_to_c_str = [](auto&& s) {
        /* Remove any reference and const-ness, since the function can handle 
        l-value and r-value, const or not. TODO - Use std::remove_cvref instead, 
        when switching to C++20. */
        if constexpr (std::is_same_v<std::remove_const_t<std::remove_reference_t<
-               decltype(s)>>,
-               std::string>)
+                                        decltype(s)>>,
+                         std::string>)
                // If the argument is a std::string return an old-style C-string
                return s.c_str();
        else
@@ -77,12 +73,13 @@ A variadic printf-like logging function. Any `std::string` argument will be
 automatically transformed into a C-string. */
 
 template <typename... Args>
-static void print(const char* format, Args&&... args) 
+static void print(const char* format, Args&&... args)
 {
        if (mode == LOG_MODE_MUTE)
                return;
 
-       if (mode == LOG_MODE_FILE && stat == true) {
+       if (mode == LOG_MODE_FILE && stat == true)
+       {
                // Replace any std::string in the arguments by its C-string
                std::fprintf(f, format, string_to_c_str(std::forward<Args>(args))...);
 #ifdef _WIN32
@@ -92,7 +89,6 @@ static void print(const char* format, Args&&... args)
        else
                std::printf(format, string_to_c_str(std::forward<Args>(args))...);
 }
-} // giada::u::log
-
+} // namespace giada::u::log
 
 #endif
index 16fb71f7807ef3354608ab2391d1045a04ef6dea..ef7e1841b39ae49fc6fc3034f0d5cddb4de05b07 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <cmath>
 #include "math.h"
+#include <cmath>
 
-
-namespace giada {
-namespace u     {
-namespace math 
+namespace giada
+{
+namespace u
+{
+namespace math
 {
 float linearToDB(float f)
 {
        return 20 * std::log10(f);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 int quantize(int x, int step)
 {
        /* Source:
        https://en.wikipedia.org/wiki/Quantization_(signal_processing)#Rounding_example */
-       return step * std::floor((x / (float) step) + 0.5f);
+       return step * std::floor((x / (float)step) + 0.5f);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 float dBtoLinear(float f)
 {
-       return std::pow(10, f/20.0f); 
+       return std::pow(10, f / 20.0f);
 }
 
-}}}  // giada::u::math::
\ No newline at end of file
+} // namespace math
+} // namespace u
+} // namespace giada
\ No newline at end of file
index 612d0a41a77f345abf915c11add1a943eeddea4f..906b2f08710845dc37c179babfea9b9295809411 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_MATH_H
 #define G_UTILS_MATH_H
 
-
 #include <type_traits>
 
-
-namespace giada {
-namespace u     {
-namespace math 
+namespace giada::u::math
 {
 float linearToDB(float f);
 float dBtoLinear(float f);
-int quantize(int x, int step);
-
+int   quantize(int x, int step);
 
 /* -------------------------------------------------------------------------- */
 
@@ -52,10 +46,9 @@ TO map(TI x, TI a, TI b, TO w, TO z)
 {
        static_assert(std::is_arithmetic_v<TI>);
        static_assert(std::is_arithmetic_v<TO>);
-       
-       return (((x - a) / (double) (b - a)) * (z - w)) + w;
-}
 
+       return (((x - a) / (double)(b - a)) * (z - w)) + w;
+}
 
 /* map (2)
 Maps 'x' in range [0, b) to a new range [0, z]. */
@@ -63,12 +56,8 @@ Maps 'x' in range [0, b) to a new range [0, z]. */
 template <typename TI, typename TO>
 TO map(TI x, TI b, TO z)
 {
-       static_assert(std::is_arithmetic_v<TI>);
-       static_assert(std::is_arithmetic_v<TO>);
-       
-       return static_cast<TO>((x / (double) b) * z);
+       return map(x, static_cast<TI>(0), b, static_cast<TO>(0), z);
 }
-}}}  // giada::u::math::
-
+} // namespace giada::u::math
 
 #endif
index 2620d162ccc7cbb9db8366e6eea20db64c835b09..4c7abb58f66170ae0b4f8c333b370695658a0ea4 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <iomanip>
-#include <cstdarg>
-#include <climits>
-#include "core/const.h"
 #include "string.h"
+#include "core/const.h"
+#include <climits>
+#include <cstdarg>
+#include <iomanip>
 
-
-namespace giada {
-namespace u     {
-namespace string 
+namespace giada
+{
+namespace u
+{
+namespace string
 {
 /* TODO - use std::to_string() */
 
@@ -47,35 +47,30 @@ std::string fToString(float f, int precision)
        return out.str();
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string trim(const std::string& s)
 {
        std::size_t first = s.find_first_not_of(" \n\t");
        std::size_t last  = s.find_last_not_of(" \n\t");
-       return s.substr(first, last-first+1);
+       return s.substr(first, last - first + 1);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string replace(std::string in, const std::string& search, const std::string& replace)
 {
        std::size_t pos = 0;
-       while ((pos = in.find(search, pos)) != std::string::npos) {
+       while ((pos = in.find(search, pos)) != std::string::npos)
+       {
                in.replace(pos, search.length(), replace);
                pos += replace.length();
        }
        return in;
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string format(const char* format, ...)
 {
        va_list args;
@@ -86,7 +81,7 @@ std::string format(const char* format, ...)
        va_start(args, format);
        std::size_t size = vsnprintf(nullptr, 0, format, args) + 1;
        va_end(args);
-       
+
        /* Create a new temporary char array to hold the new expanded std::string. */
 
        std::unique_ptr<char[]> tmp(new char[size]);
@@ -100,26 +95,26 @@ std::string format(const char* format, ...)
        return std::string(tmp.get(), tmp.get() + size - 1);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::vector<std::string> split(std::string in, std::string sep)
 {
        std::vector<std::string> out;
-       std::string full  = in;
-       std::string token = "";
-       std::size_t curr = 0;
-       std::size_t next = -1;
-       do {
+       std::string              full  = in;
+       std::string              token = "";
+       std::size_t              curr  = 0;
+       std::size_t              next  = -1;
+       do
+       {
                curr  = next + 1;
                next  = full.find_first_of(sep, curr);
                token = full.substr(curr, next - curr);
                if (token != "")
                        out.push_back(token);
-       }
-       while (next != std::string::npos);
+       } while (next != std::string::npos);
        return out;
 }
 
-}}} // giada::u::string
+} // namespace string
+} // namespace u
+} // namespace giada
index d2ab13233e82ce3a1e62d640305938cc62ce0874..7105c5c4b99157df4a448fc165cb88ded68eb476 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_STRING_H
 #define G_UTILS_STRING_H
 
-
+#include <sstream>
 #include <string>
 #include <vector>
-#include <sstream>
 
-
-namespace giada {
-namespace u     {
-namespace string 
+namespace giada
+{
+namespace u
+{
+namespace string
 {
 template <typename T>
-std::string iToString(T t, bool hex=false)
+std::string iToString(T t, bool hex = false)
 {
        std::stringstream out;
        if (hex)
                out << std::hex << std::uppercase << t;
        else
                out << t;
-       return out.str();       
+       return out.str();
 }
 
 std::string replace(std::string in, const std::string& search,
-  const std::string& replace);
+    const std::string& replace);
 
 std::string trim(const std::string& s);
 
@@ -62,6 +61,8 @@ std::string fToString(float f, int precision);
 
 std::string format(const char* format, ...);
 
-}}} // giada::u::string
+} // namespace string
+} // namespace u
+} // namespace giada
 
 #endif
index a2b886049bc4e5df22bc4d7b3cc38a466a62cd02..bd9ebf46e6b86647f89eb48ccb8ba0bbfdbebc18 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
+#include "time.h"
 #include <chrono>
 #include <thread>
-#include "time.h"
 
-
-namespace giada {
-namespace u     {
-namespace time 
+namespace giada
+{
+namespace u
+{
+namespace time
 {
 void sleep(int millisecs)
 {
        std::this_thread::sleep_for(std::chrono::milliseconds(millisecs));
 }
-}}}  // giada::u::time::
+} // namespace time
+} // namespace u
+} // namespace giada
index b2f29c63ef1782ab1814ff0f753471807745a4c3..2562514e6c04a3da9fab5733955637fb6898b86c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_TIME_H
 #define G_UTILS_TIME_H
 
-
-namespace giada {
-namespace u     {
-namespace time 
+namespace giada
+{
+namespace u
+{
+namespace time
 {
 void sleep(int millisecs);
-}}}
-
+}
+} // namespace u
+} // namespace giada
 
 #endif
\ No newline at end of file
index 894d17e9ae60361d9dab4483270674d80389e901..acfe6c61787c77304680e8fcd9a7512a6ad9f203 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_VECTOR_H
 #define G_UTILS_VECTOR_H
 
-
-#include <vector>
 #include <algorithm>
 #include <functional>
+#include <vector>
 
-
-namespace giada {
-namespace u {
-namespace vector 
+namespace giada::u::vector
 {
 template <typename T, typename P>
 std::size_t indexOf(T& v, const P& p)
@@ -44,22 +39,43 @@ std::size_t indexOf(T& v, const P& p)
        return std::distance(v.begin(), std::find(v.begin(), v.end(), p));
 }
 
+/* -------------------------------------------------------------------------- */
+
+template <typename T, typename F>
+auto findIf(T& v, F&& func)
+{
+       return std::find_if(v.begin(), v.end(), func);
+}
 
 /* -------------------------------------------------------------------------- */
 
+template <typename T, typename F>
+bool has(T& v, F&& func)
+{
+       return findIf(v, func) != v.end();
+}
+
+/* -------------------------------------------------------------------------- */
 
 template <typename T, typename F>
 void removeIf(T& v, F&& func)
 {
-    v.erase(std::remove_if(v.begin(), v.end(), func), v.end());
+       v.erase(std::remove_if(v.begin(), v.end(), func), v.end());
 }
 
-
 template <typename T, typename V>
-void remove(T& v, V val)
+void remove(T& v, const V& o)
+{
+       v.erase(std::remove(v.begin(), v.end(), o), v.end());
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <typename T, typename I>
+std::vector<T> cast(const I& i)
 {
-    v.erase(std::remove(v.begin(), v.end(), val), v.end());
+       return {i.begin(), i.end()};
 }
-}}}  // giada::u::vector::
+} // namespace giada::u::vector
 
 #endif
index c60ba9b63daea1eda445011f8d7cb3cd25fe8ba9..449b763ae12c50c22252ca9c769d73bb764e1953 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
-#include <RtMidi.h>
+#include "ver.h"
 #include "core/const.h"
-#include <sndfile.h>
 #include "deps/rtaudio/RtAudio.h"
-#include "ver.h"
-
+#include <RtMidi.h>
+#include <sndfile.h>
 
-namespace giada {
-namespace u {
-namespace ver  
+namespace giada
+{
+namespace u
+{
+namespace ver
 {
 std::string getLibsndfileVersion()
 {
@@ -43,10 +43,8 @@ std::string getLibsndfileVersion()
        return std::string(buffer);
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getRtAudioVersion()
 {
 #ifdef TESTS
@@ -56,10 +54,8 @@ std::string getRtAudioVersion()
 #endif
 }
 
-
 /* -------------------------------------------------------------------------- */
 
-
 std::string getRtMidiVersion()
 {
 #ifdef TESTS
@@ -68,4 +64,6 @@ std::string getRtMidiVersion()
        return RtMidi::getVersion();
 #endif
 }
-}}}  // giada::u::ver::
+} // namespace ver
+} // namespace u
+} // namespace giada
index 2640147f292c37a1cf3b7a158f947a3deada85e8..6b8b0a825c5d8753e7832f4e266e151291b62ffd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2021 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  *
  * -------------------------------------------------------------------------- */
 
-
 #ifndef G_UTILS_VER_H
 #define G_UTILS_VER_H
 
-
 #include <string>
 
-
-namespace giada {
-namespace u     {
-namespace ver 
+namespace giada
+{
+namespace u
+{
+namespace ver
 {
 std::string getLibsndfileVersion();
 std::string getRtAudioVersion();
 std::string getRtMidiVersion();
-}}}  // giada::u::ver::
-
+} // namespace ver
+} // namespace u
+} // namespace giada
 
 #endif
index 5ab5f1fafdaa32f92c748effbf1a8f50455a8aaa..28b1f607e8c20e02362e1dc6c9b6dc7329517897 100644 (file)
@@ -1,7 +1,6 @@
-#include <memory>
 #include "../src/core/audioBuffer.h"
 #include <catch2/catch.hpp>
-
+#include <memory>
 
 TEST_CASE("AudioBuffer")
 {
@@ -14,7 +13,7 @@ TEST_CASE("AudioBuffer")
 
        AudioBuffer buffer;
        buffer.alloc(BUFFER_SIZE, 2);
-       
+
        SECTION("test allocation")
        {
                SECTION("test mono")
@@ -23,14 +22,14 @@ TEST_CASE("AudioBuffer")
                        REQUIRE(buffer.countFrames() == BUFFER_SIZE);
                        REQUIRE(buffer.countSamples() == BUFFER_SIZE);
                        REQUIRE(buffer.countChannels() == 1);
-               }               
+               }
 
                SECTION("test stereo")
                {
                        REQUIRE(buffer.countFrames() == BUFFER_SIZE);
                        REQUIRE(buffer.countSamples() == BUFFER_SIZE * 2);
                        REQUIRE(buffer.countChannels() == 2);
-               }               
+               }
 
                buffer.free();
 
@@ -40,45 +39,45 @@ TEST_CASE("AudioBuffer")
        }
 
        SECTION("test clear all")
-       {       
+       {
                buffer.clear();
-               for (int i=0; i<buffer.countFrames(); i++)
-                       for (int k=0; k<buffer.countChannels(); k++)
+               for (int i = 0; i < buffer.countFrames(); i++)
+                       for (int k = 0; k < buffer.countChannels(); k++)
                                REQUIRE(buffer[i][k] == 0.0f);
                buffer.free();
        }
 
        SECTION("test clear range")
-       {       
-               for (int i=0; i<buffer.countFrames(); i++)
-                       for (int k=0; k<buffer.countChannels(); k++)
-                                       buffer[i][k] = 1.0f;
+       {
+               for (int i = 0; i < buffer.countFrames(); i++)
+                       for (int k = 0; k < buffer.countChannels(); k++)
+                               buffer[i][k] = 1.0f;
 
                buffer.clear(5, 6);
 
-               for (int k=0; k<buffer.countChannels(); k++)
+               for (int k = 0; k < buffer.countChannels(); k++)
                        REQUIRE(buffer[5][k] == 0.0f);
 
                buffer.free();
        }
 
        SECTION("test copy")
-       {       
-               int size = BUFFER_SIZE * 2;
-               float* data = new float[size];
-               for (int i=0; i<size; i++)
-                       data[i] = (float) i;
+       {
+               AudioBuffer other(BUFFER_SIZE, 2);
+
+               for (int i = 0; i < other.countFrames(); i++)
+                       for (int k = 0; k < other.countChannels(); k++)
+                               other[i][k] = (float)i;
 
                SECTION("test full copy")
-               {       
-                       buffer.copyData(data, BUFFER_SIZE);
+               {
+                       buffer.set(other, 1.0f);
 
-                       REQUIRE(buffer[0][0]    == 0.0f);
-                       REQUIRE(buffer[16][0]   == 32.0f);
-                       REQUIRE(buffer[32][0]   == 64.0f);
-                       REQUIRE(buffer[1024][0] == 2048.0f);
+                       REQUIRE(buffer[0][0] == 0.0f);
+                       REQUIRE(buffer[16][0] == 16.0f);
+                       REQUIRE(buffer[128][0] == 128.0f);
+                       REQUIRE(buffer[1024][0] == 1024.0f);
+                       REQUIRE(buffer[BUFFER_SIZE - 1][0] == (float)BUFFER_SIZE - 1);
                }
-
-               delete[] data;
        }
 }
diff --git a/tests/rcuList.cpp b/tests/rcuList.cpp
deleted file mode 100644 (file)
index cb1cba6..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#include "../src/core/rcuList.h"
-#include "../src/core/types.h"
-#include <catch2/catch.hpp>
-
-
-using namespace giada;
-using namespace giada::m;
-
-
-TEST_CASE("RCUList")
-{
-       struct Object
-       {
-               Object(ID id) : id(id) {}
-               ID id;
-       };
-
-       RCUList<Object> list;
-
-    REQUIRE(list.size() == 0);
-    REQUIRE(list.changed == false);
-
-       SECTION("test push")
-       {
-               list.push(std::make_unique<Object>(1));
-               list.push(std::make_unique<Object>(2));
-               list.push(std::make_unique<Object>(3));
-
-       REQUIRE(list.size() == 3);
-       REQUIRE(list.changed == true);
-
-               SECTION("test retrieval")
-               {
-                       RCUList<Object>::Lock l(list);
-
-                       REQUIRE(list.get(0)->id == 1);
-                       REQUIRE(list.get(1)->id == 2);
-                       REQUIRE(list.get(2)->id == 3);
-                       REQUIRE(list[0]->id == 1);
-                       REQUIRE(list[1]->id == 2);
-                       REQUIRE(list[2]->id == 3);
-                       REQUIRE(list.back()->id == 3);
-               }
-
-               SECTION("test iterator")
-               {
-                       RCUList<Object>::Lock l(list);
-
-                       ID id = 1;
-                       for (Object* o : list)
-                               REQUIRE(o->id == id++);
-               }
-               
-               SECTION("test const iterator")
-               {
-                       RCUList<Object>::Lock l(list);
-
-                       ID id = 1;
-                       for (const Object* o : list)
-                               REQUIRE(o->id == id++);
-               }
-
-               SECTION("test pop")
-               {
-                       list.pop(0);
-
-                       REQUIRE(list.size() == 2);
-                       REQUIRE(list.changed == true);
-               }
-
-               SECTION("test clear")
-               {
-                       list.clear();
-
-                       REQUIRE(list.size() == 0);
-                       REQUIRE(list.changed == true);
-               }
-       }
-
-       SECTION("test swap")
-       {
-               list.push(std::make_unique<Object>(1));
-
-               list.swap(std::make_unique<Object>(16));
-
-               REQUIRE(list.size() == 1);
-               REQUIRE(list.changed == true);
-
-               RCUList<Object>::Lock l(list);
-               
-               REQUIRE(list.get(0)->id == 16);
-       }
-}
index 402efd7fb0cc7bf157abd29458876ab3fa60bf4d..8f6ec2fa5430937745cdb2ab9ccd3994f3f2be77 100644 (file)
@@ -1,10 +1,9 @@
 #include "../src/core/recorder.h"
+#include "../src/core/action.h"
 #include "../src/core/const.h"
 #include "../src/core/types.h"
-#include "../src/core/action.h"
 #include <catch2/catch.hpp>
 
-
 TEST_CASE("recorder")
 {
        using namespace giada;
@@ -45,7 +44,7 @@ TEST_CASE("recorder")
                        recorder::rec(ch, f2, e2);
 
                        recorder::clearChannel(/*channel=*/0);
-                       
+
                        REQUIRE(recorder::hasActions(/*channel=*/0) == false);
                        REQUIRE(recorder::hasActions(/*channel=*/1) == true);
                }
@@ -54,11 +53,10 @@ TEST_CASE("recorder")
                {
                        recorder::clearActions(/*channel=*/0, MidiEvent::NOTE_ON);
                        recorder::clearActions(/*channel=*/0, MidiEvent::NOTE_OFF);
-                       
+
                        REQUIRE(recorder::hasActions(/*channel=*/0) == false);
                }
 
-
                SECTION("Test clear all")
                {
                        recorder::clearAll();
index 2ef9e4c9ae293d3692c1fc0ba335b6a773b8f89f..4ec2a26e07bb7640d89a8d9265a3b6ac05240a6e 100644 (file)
@@ -1,9 +1,8 @@
 #include "../src/utils/fs.h"
-#include "../src/utils/string.h"
 #include "../src/utils/math.h"
+#include "../src/utils/string.h"
 #include <catch2/catch.hpp>
 
-
 TEST_CASE("u::fs")
 {
        using namespace giada::u;
@@ -19,11 +18,11 @@ TEST_CASE("u::fs")
        REQUIRE(fs::getExt("tests/utils.cpp") == ".cpp");
        REQUIRE(fs::stripExt("tests/utils.cpp") == "tests/utils");
 #if defined(_WIN32)
-       REQUIRE(fs::isRootDir("C:\\") == true);
+       REQUIRE(fs::isRootDir("\\") == true);
        REQUIRE(fs::isRootDir("C:\\path\\to\\something") == false);
-       REQUIRE(fs::getUpDir("C:\\path\\to\\something") == "C:\\path\\to\\");
+       REQUIRE(fs::getUpDir("C:\\path\\to\\something") == "C:\\path\\to");
        REQUIRE(fs::getUpDir("C:\\path") == "C:\\");
-       REQUIRE(fs::getUpDir("C:\\") == "");
+       REQUIRE(fs::getUpDir("C:\\") == "C:\\");
 #else
        REQUIRE(fs::isRootDir("/") == true);
        REQUIRE(fs::isRootDir("/path/to/something") == false);
@@ -33,7 +32,6 @@ TEST_CASE("u::fs")
 #endif
 }
 
-
 TEST_CASE("u::string")
 {
        using namespace giada::u;
@@ -52,12 +50,15 @@ TEST_CASE("u::string")
        REQUIRE(v.at(2) == "cool");
 }
 
-
 TEST_CASE("::math")
 {
        using namespace giada::u;
 
-       REQUIRE(math::map( 0.0f, 0.0f, 30.0f, 0.0f, 1.0f) == 0.0f);
+       REQUIRE(math::map(0.0f, 0.0f, 30.0f, 0.0f, 1.0f) == 0.0f);
        REQUIRE(math::map(30.0f, 0.0f, 30.0f, 0.0f, 1.0f) == 1.0f);
        REQUIRE(math::map(15.0f, 0.0f, 30.0f, 0.0f, 1.0f) == Approx(0.5f));
+
+       REQUIRE(math::map(0.0f, 30.0f, 1.0f) == 0.0f);
+       REQUIRE(math::map(30.0f, 30.0f, 1.0f) == 1.0f);
+       REQUIRE(math::map(15.0f, 30.0f, 1.0f) == Approx(0.5f));
 }
index 535001a16a1747bc011ed29f108db3ea4e218481..0a622f80730e50018ed709564db92f0b189afc0d 100644 (file)
@@ -1,7 +1,6 @@
-#include <memory>
 #include "../src/core/wave.h"
 #include <catch2/catch.hpp>
-
+#include <memory>
 
 TEST_CASE("Wave")
 {
@@ -9,13 +8,12 @@ TEST_CASE("Wave")
 
        static const int SAMPLE_RATE = 44100;
        static const int BUFFER_SIZE = 4096;
-       static const int CHANNELS = 2;
-       static const int BIT_DEPTH = 32;
+       static const int CHANNELS    = 2;
+       static const int BIT_DEPTH   = 32;
 
        /* Each SECTION the TEST_CASE is executed from the start. Any code between 
        this comment and the first SECTION macro is executed before each SECTION. */
 
-
        SECTION("test allocation")
        {
                m::Wave wave(1);
@@ -37,7 +35,7 @@ TEST_CASE("Wave")
                        wave.setPath("path/is/now/different.mp3", 5);
 
                        REQUIRE(wave.getPath() == "path/is/now/different-5.mp3");
-               }  
+               }
 
                SECTION("test change name")
                {
index 456d6feeb3d1d38bd0a78612f163ceaa72974263..f045846f5394f4647b7e1633ec113aebf17eff60 100644 (file)
@@ -1,57 +1,41 @@
-#include <memory>
-#include "../src/core/model/model.h"
-#include "../src/core/const.h"
-#include "../src/core/wave.h"
 #include "../src/core/waveFx.h"
+#include "../src/core/const.h"
 #include "../src/core/types.h"
+#include "../src/core/wave.h"
 #include <catch2/catch.hpp>
-
+#include <memory>
 
 using namespace giada;
 using namespace giada::m;
 
-
-Wave& getWave(ID id)
+TEST_CASE("waveFx")
 {
-       model::WavesLock l(model::waves);
-       return model::get(model::waves, id);
-}
+       static const int SAMPLE_RATE = 44100;
+       static const int BUFFER_SIZE = 4000;
+       static const int BIT_DEPTH   = 32;
 
+       Wave waveMono(0);
+       Wave waveStereo(0);
 
-TEST_CASE("waveFx")
-{
-       static const ID  WAVE_MONO_ID   = 1;
-       static const ID  WAVE_STEREO_ID = 2;
-       static const int SAMPLE_RATE    = 44100;
-       static const int BUFFER_SIZE    = 4000;
-       static const int BIT_DEPTH      = 32;
-
-       std::unique_ptr<Wave> waveMono   = std::make_unique<Wave>(WAVE_MONO_ID);
-       std::unique_ptr<Wave> waveStereo = std::make_unique<Wave>(WAVE_STEREO_ID);
-
-       waveMono->alloc(BUFFER_SIZE, 1, SAMPLE_RATE, BIT_DEPTH, "path/to/sample-mono.wav");
-       waveStereo->alloc(BUFFER_SIZE, 2, SAMPLE_RATE, BIT_DEPTH, "path/to/sample-stereo.wav");
-       
-       model::waves.clear();
-       model::waves.push(std::move(waveMono));
-       model::waves.push(std::move(waveStereo));
+       waveMono.alloc(BUFFER_SIZE, 1, SAMPLE_RATE, BIT_DEPTH, "path/to/sample-mono.wav");
+       waveStereo.alloc(BUFFER_SIZE, 2, SAMPLE_RATE, BIT_DEPTH, "path/to/sample-stereo.wav");
 
        SECTION("test mono->stereo conversion")
        {
-               int prevSize = getWave(WAVE_MONO_ID).getSize();
+               int prevSize = waveMono.getBuffer().countFrames();
 
-               REQUIRE(wfx::monoToStereo(getWave(WAVE_MONO_ID)) == G_RES_OK);
-               REQUIRE(getWave(WAVE_MONO_ID).getSize() == prevSize);  // size does not change, channels do
-               REQUIRE(getWave(WAVE_MONO_ID).getChannels() == 2);
+               REQUIRE(wfx::monoToStereo(waveMono) == G_RES_OK);
+               REQUIRE(waveMono.getBuffer().countFrames() == prevSize); // size does not change, channels do
+               REQUIRE(waveMono.getBuffer().countChannels() == 2);
 
                SECTION("test mono->stereo conversion for already stereo wave")
                {
                        /* Should do nothing. */
-                       int prevSize = getWave(WAVE_STEREO_ID).getSize();
+                       int prevSize = waveStereo.getBuffer().countFrames();
 
-                       REQUIRE(wfx::monoToStereo(getWave(WAVE_STEREO_ID)) == G_RES_OK);
-                       REQUIRE(getWave(WAVE_STEREO_ID).getSize() == prevSize);
-                       REQUIRE(getWave(WAVE_STEREO_ID).getChannels() == 2);
+                       REQUIRE(wfx::monoToStereo(waveStereo) == G_RES_OK);
+                       REQUIRE(waveStereo.getBuffer().countFrames() == prevSize);
+                       REQUIRE(waveStereo.getBuffer().countChannels() == 2);
                }
        }
 
@@ -59,34 +43,34 @@ TEST_CASE("waveFx")
        {
                int a = 20;
                int b = 57;
-               wfx::silence(getWave(WAVE_STEREO_ID).id, a, b);
+               wfx::silence(waveStereo, a, b);
 
-               for (int i=a; i<b; i++)
-                       for (int k=0; k<getWave(WAVE_STEREO_ID).getChannels(); k++)
-                               REQUIRE(getWave(WAVE_STEREO_ID)[i][k] == 0.0f);
+               for (int i = a; i < b; i++)
+                       for (int k = 0; k < waveStereo.getBuffer().countChannels(); k++)
+                               REQUIRE(waveStereo.getBuffer()[i][k] == 0.0f);
        }
 
        SECTION("test cut")
        {
-               int a = 47;
-               int b = 210;
-               int range = b - a;
-               int prevSize = getWave(WAVE_STEREO_ID).getSize();
+               int a        = 47;
+               int b        = 210;
+               int range    = b - a;
+               int prevSize = waveStereo.getBuffer().countFrames();
 
-               wfx::cut(getWave(WAVE_STEREO_ID).id, a, b);
+               wfx::cut(waveStereo, a, b);
 
-               REQUIRE(getWave(WAVE_STEREO_ID).getSize() == prevSize - range);
+               REQUIRE(waveStereo.getBuffer().countFrames() == prevSize - range);
        }
 
        SECTION("test trim")
        {
-               int a = 47;
-               int b = 210;
+               int a    = 47;
+               int b    = 210;
                int area = b - a;
 
-               wfx::trim(getWave(WAVE_STEREO_ID).id, a, b);
+               wfx::trim(waveStereo, a, b);
 
-               REQUIRE(getWave(WAVE_STEREO_ID).getSize() == area);
+               REQUIRE(waveStereo.getBuffer().countFrames() == area);
        }
 
        SECTION("test fade")
@@ -94,13 +78,13 @@ TEST_CASE("waveFx")
                int a = 47;
                int b = 500;
 
-               wfx::fade(getWave(WAVE_STEREO_ID).id, a, b, wfx::Fade::IN);
-               wfx::fade(getWave(WAVE_STEREO_ID).id, a, b, wfx::Fade::OUT);
+               wfx::fade(waveStereo, a, b, wfx::Fade::IN);
+               wfx::fade(waveStereo, a, b, wfx::Fade::OUT);
 
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(a)[0] == 0.0f);
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(a)[1] == 0.0f);
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(b)[0] == 0.0f);
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(b)[1] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[a][0] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[a][1] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[b][0] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[b][1] == 0.0f);
        }
 
        SECTION("test smooth")
@@ -108,11 +92,11 @@ TEST_CASE("waveFx")
                int a = 11;
                int b = 79;
 
-               wfx::smooth(getWave(WAVE_STEREO_ID).id, a, b);
+               wfx::smooth(waveStereo, a, b);
 
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(a)[0] == 0.0f);
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(a)[1] == 0.0f);
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(b)[0] == 0.0f);
-               REQUIRE(getWave(WAVE_STEREO_ID).getFrame(b)[1] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[a][0] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[a][1] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[b][0] == 0.0f);
+               REQUIRE(waveStereo.getBuffer()[b][1] == 0.0f);
        }
 }
index 6414284e2ba7d176be5ec0b4371d5fd296ffa903..94c3270f2cd4d0ac539916534ef913ef0e0240b7 100644 (file)
@@ -1,20 +1,17 @@
-#include <memory>
-#include <samplerate.h>
 #include "../src/core/waveManager.h"
-#include "../src/core/wave.h"
 #include "../src/core/const.h"
+#include "../src/core/wave.h"
 #include <catch2/catch.hpp>
-
+#include <memory>
+#include <samplerate.h>
 
 using std::string;
 using namespace giada::m;
 
-
 #define G_SAMPLE_RATE 44100
 #define G_BUFFER_SIZE 4096
 #define G_CHANNELS 2
 
-
 TEST_CASE("waveManager")
 {
        /* Each SECTION the TEST_CASE is executed from the start. Any code between 
@@ -23,23 +20,23 @@ TEST_CASE("waveManager")
        SECTION("test creation")
        {
                waveManager::Result res = waveManager::createFromFile(TEST_RESOURCES_DIR "test.wav",
-                       /*ID=*/0, /*sampleRate=*/G_SAMPLE_RATE, /*quality=*/SRC_LINEAR);
+                   /*ID=*/0, /*sampleRate=*/G_SAMPLE_RATE, /*quality=*/SRC_LINEAR);
 
                REQUIRE(res.status == G_RES_OK);
                REQUIRE(res.wave->getRate() == G_SAMPLE_RATE);
-               REQUIRE(res.wave->getChannels() == G_CHANNELS);
+               REQUIRE(res.wave->getBuffer().countChannels() == G_CHANNELS);
                REQUIRE(res.wave->isLogical() == false);
                REQUIRE(res.wave->isEdited() == false);
        }
 
        SECTION("test recording")
        {
-               std::unique_ptr<Wave> wave = waveManager::createEmpty(G_BUFFER_SIZE, 
-                       G_MAX_IO_CHANS, G_SAMPLE_RATE, "test.wav");
+               std::unique_ptr<Wave> wave = waveManager::createEmpty(G_BUFFER_SIZE,
+                   G_MAX_IO_CHANS, G_SAMPLE_RATE, "test.wav");
 
                REQUIRE(wave->getRate() == G_SAMPLE_RATE);
-               REQUIRE(wave->getSize() == G_BUFFER_SIZE);
-               REQUIRE(wave->getChannels() == G_CHANNELS);
+               REQUIRE(wave->getBuffer().countFrames() == G_BUFFER_SIZE);
+               REQUIRE(wave->getBuffer().countChannels() == G_CHANNELS);
                REQUIRE(wave->isLogical() == true);
                REQUIRE(wave->isEdited() == false);
        }
@@ -47,14 +44,14 @@ TEST_CASE("waveManager")
        SECTION("test resampling")
        {
                waveManager::Result res = waveManager::createFromFile(TEST_RESOURCES_DIR "test.wav",
-                       /*ID=*/0, /*sampleRate=*/G_SAMPLE_RATE, /*quality=*/SRC_LINEAR);
+                   /*ID=*/0, /*sampleRate=*/G_SAMPLE_RATE, /*quality=*/SRC_LINEAR);
 
-               int oldSize = res.wave->getSize();
+               int oldSize = res.wave->getBuffer().countFrames();
                waveManager::resample(*res.wave.get(), 1, G_SAMPLE_RATE * 2);
-               
+
                REQUIRE(res.wave->getRate() == G_SAMPLE_RATE * 2);
-               REQUIRE(res.wave->getSize() == oldSize * 2);
-               REQUIRE(res.wave->getChannels() == G_CHANNELS);
+               REQUIRE(res.wave->getBuffer().countFrames() == oldSize * 2);
+               REQUIRE(res.wave->getBuffer().countChannels() == G_CHANNELS);
                REQUIRE(res.wave->isLogical() == false);
                REQUIRE(res.wave->isEdited() == false);
        }