New upstream version 0.14.5~dfsg1
authorJaromír Mikeš <mira.mikes@seznam.cz>
Tue, 16 Jan 2018 06:06:13 +0000 (07:06 +0100)
committerJaromír Mikeš <mira.mikes@seznam.cz>
Tue, 16 Jan 2018 06:06:13 +0000 (07:06 +0100)
261 files changed:
.travis/after_success.sh [new file with mode: 0755]
.travis/before_install.sh [new file with mode: 0755]
.travis/before_script.sh [new file with mode: 0755]
.travis/install.sh [new file with mode: 0755]
.travis/script.sh [new file with mode: 0755]
ChangeLog
Makefile.am
README.md
configure.ac
src/core/channel.cpp
src/core/channel.h
src/core/clock.cpp
src/core/clock.h
src/core/conf.cpp
src/core/conf.h
src/core/const.h
src/core/graphics.cpp
src/core/graphics.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/midiChannel.cpp
src/core/midiChannel.h
src/core/midiDispatcher.cpp [new file with mode: 0644]
src/core/midiDispatcher.h [new file with mode: 0644]
src/core/midiEvent.cpp [new file with mode: 0644]
src/core/midiEvent.h [new file with mode: 0644]
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/patch.cpp
src/core/patch.h
src/core/plugin.cpp
src/core/plugin.h
src/core/pluginHost.cpp
src/core/pluginHost.h
src/core/recorder.cpp
src/core/recorder.h
src/core/sampleChannel.cpp
src/core/sampleChannel.h
src/core/storager.cpp
src/core/storager.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/glue/channel.cpp
src/glue/channel.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/glue/transport.cpp
src/glue/transport.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 [new file with mode: 0644]
src/gui/dialogs/browser/browserDir.h [new file with mode: 0644]
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/gd_about.cpp
src/gui/dialogs/gd_about.h
src/gui/dialogs/gd_actionEditor.cpp
src/gui/dialogs/gd_actionEditor.h
src/gui/dialogs/gd_config.cpp
src/gui/dialogs/gd_config.h
src/gui/dialogs/gd_devInfo.cpp
src/gui/dialogs/gd_devInfo.h
src/gui/dialogs/gd_keyGrabber.cpp
src/gui/dialogs/gd_keyGrabber.h
src/gui/dialogs/gd_mainWindow.cpp
src/gui/dialogs/gd_mainWindow.h
src/gui/dialogs/gd_warnings.cpp
src/gui/dialogs/gd_warnings.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/window.cpp
src/gui/dialogs/window.h
src/gui/elems/actionEditor/action.cpp
src/gui/elems/actionEditor/action.h
src/gui/elems/actionEditor/actionEditor.cpp
src/gui/elems/actionEditor/actionEditor.h
src/gui/elems/actionEditor/baseActionEditor.cpp
src/gui/elems/actionEditor/baseActionEditor.h
src/gui/elems/actionEditor/basePianoItem.cpp
src/gui/elems/actionEditor/basePianoItem.h
src/gui/elems/actionEditor/envelopeEditor.cpp
src/gui/elems/actionEditor/envelopeEditor.h
src/gui/elems/actionEditor/gridTool.cpp
src/gui/elems/actionEditor/gridTool.h
src/gui/elems/actionEditor/muteEditor.cpp
src/gui/elems/actionEditor/muteEditor.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/pianoItemOrphaned.cpp
src/gui/elems/actionEditor/pianoItemOrphaned.h
src/gui/elems/actionEditor/pianoRoll.cpp
src/gui/elems/actionEditor/pianoRoll.h
src/gui/elems/basics/baseButton.cpp
src/gui/elems/basics/baseButton.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/idButton.cpp
src/gui/elems/basics/idButton.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/progress.cpp
src/gui/elems/basics/progress.h
src/gui/elems/basics/radio.cpp
src/gui/elems/basics/radio.h
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/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
src/gui/elems/mainWindow/beatMeter.h
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/midiLearner.cpp
src/gui/elems/midiLearner.h
src/gui/elems/plugin/pluginBrowser.cpp
src/gui/elems/plugin/pluginBrowser.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/main.cpp
src/utils/cocoa.h
src/utils/cocoa.mm
src/utils/deps.cpp
src/utils/deps.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
tests/recorder.cpp
tests/utils.cpp

diff --git a/.travis/after_success.sh b/.travis/after_success.sh
new file mode 100755 (executable)
index 0000000..64612e1
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+mkdir build
+
+if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
+
+  cp giada_osx ./build
+  upx --best ./build/giada_osx
+
+elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
+
+       : # null command - nothing to do 
+       
+       # TODO  
+  # cp giada_lin ./build
+
+fi
\ No newline at end of file
diff --git a/.travis/before_install.sh b/.travis/before_install.sh
new file mode 100755 (executable)
index 0000000..17d5a97
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
+
+       echo ""
+
+elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
+
+  sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y # for gcc 6
+  sudo apt-get update -qq
+
+fi
\ No newline at end of file
diff --git a/.travis/before_script.sh b/.travis/before_script.sh
new file mode 100755 (executable)
index 0000000..73e0df2
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
+
+  ./autogen.sh
+  ./configure --target=osx --enable-vst
+
+elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
+
+  ./autogen.sh
+  ./configure --target=linux #--enable-vst
+
+fi
\ No newline at end of file
diff --git a/.travis/install.sh b/.travis/install.sh
new file mode 100755 (executable)
index 0000000..066b194
--- /dev/null
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+
+if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
+
+  brew update
+  brew install rtmidi
+  brew install jansson
+  brew install libsamplerate
+  brew install fltk
+  brew install libsndfile
+  brew install upx
+
+  #ls Remove dynamic libraries to force static linking.
+
+  rm -rf /usr/local/lib/librtmidi.dylib
+  rm -rf /usr/local/lib/librtmidi.4.dylib
+  rm -rf /usr/local/lib/libjansson.dylib
+  rm -rf /usr/local/lib/libjansson.4.dylib
+  rm -rf /usr/local/lib/libsamplerate.dylib
+  rm -rf /usr/local/lib/libsamplerate.0.dylib
+  rm -rf /usr/local/lib/libfltk.1.3.dylib
+  rm -rf /usr/local/lib/libfltk.dylib
+  rm -rf /usr/local/lib/libfltk_forms.1.3.dylib
+  rm -rf /usr/local/lib/libfltk_forms.dylib
+  rm -rf /usr/local/lib/libfltk_forms.dylib
+  rm -rf /usr/local/lib/libfltk_gl.1.3.dylib
+  rm -rf /usr/local/lib/libfltk_gl.dylib 
+  rm -rf /usr/local/lib/libfltk_images.1.3.dylib
+  rm -rf /usr/local/lib/libfltk_images.dylib 
+  rm -rf /usr/local/lib/libsndfile.1.dylib 
+  rm -rf /usr/local/lib/libsndfile.dylib 
+  rm -rf /usr/local/lib/libFLAC++.6.dylib
+  rm -rf /usr/local/lib/libFLAC++.dylib
+  rm -rf /usr/local/lib/libFLAC.8.dylib
+  rm -rf /usr/local/lib/libFLAC.dylib
+  rm -rf /usr/local/lib/libogg.0.dylib
+  rm -rf /usr/local/lib/libogg.dylib
+  rm -rf /usr/local/lib/libvorbis.0.dylib
+  rm -rf /usr/local/lib/libvorbis.dylib
+  rm -rf /usr/local/lib/libvorbisenc.2.dylib
+  rm -rf /usr/local/lib/libvorbisenc.dylib
+
+  # TODO - what about midimaps?
+
+elif [[ $TRAVIS_OS_NAME == 'linux' ]]; then
+
+  sudo apt-get install -y gcc-6 g++-6 libsndfile1-dev libsamplerate0-dev \
+       libfltk1.3-dev libasound2-dev libxpm-dev libpulse-dev libjack-dev \
+       libxrandr-dev libx11-dev libxinerama-dev libxcursor-dev
+
+  # Symlink gcc in order to use the latest version
+
+  sudo ln -f -s /usr/bin/g++-6 /usr/bin/g++
+
+  # Download and build latest version of RtMidi
+
+  wget https://github.com/thestk/rtmidi/archive/master.zip
+  unzip master.zip
+  cd rtmidi-master && ./autogen.sh && ./configure --with-jack --with-alsa && make && sudo make install || true
+  cd ..
+
+  #wget http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-2.1.1.tar.gz
+  #tar -xvf rtmidi-2.1.1.tar.gz
+  #cd rtmidi-2.1.1 && ./configure --with-jack --with-alsa && make && sudo make install || true
+  #cd ..
+
+  # Download and install latest version of Jansson
+  # TODO - no longer needed! Use apt instead
+
+  wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz
+  tar -xvf jansson-2.7.tar.gz
+  cd jansson-2.7 && ./configure && make && sudo make install || true
+  sudo ldconfig
+  cd ..
+
+  # Download midimaps package for testing purposes
+
+  wget https://github.com/monocasual/giada-midimaps/archive/master.zip -O giada-midimaps-master.zip
+  unzip giada-midimaps-master.zip
+  mkdir -p $HOME/.giada/midimaps
+  cp giada-midimaps-master/midimaps/* $HOME/.giada/midimaps
+
+  # Download vst plugin for testing purposes
+
+  #- wget http://www.discodsp.com/download/?id=18 -O bliss-linux.zip
+  #- unzip bliss-linux.zip -d bliss-linux
+  #- cp bliss-linux/64-bit/Bliss64Demo.so .
+
+fi
\ No newline at end of file
diff --git a/.travis/script.sh b/.travis/script.sh
new file mode 100755 (executable)
index 0000000..49f67c4
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+make -j 2
+make rename
+make check -j 2
\ No newline at end of file
index cf11e2be3df9e436b89057961a7c29102bc1f11a..dbca39f6812cfaa370ffcc6eb4b8f12647367ee8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 --------------------------------------------------------------------------------
 
 
+0.14.5 --- 2018 . 01 . 15
+- OS X builds on Travis CI
+- AppImage executable for Linux
+- Support for multiple plug-in directories
+- New directory browser for adding plug-in directories
+- Update plug-in's parameters on program change in plug-in's window
+- Improved MIDI action management in Piano Roll
+- Simplified conditional rules in Makefile.am 
+- Fix crash on MIDI learn for plug-in parameters
+- Fix crash in MIDI input window if MIDI in params are 0
+- Fix unwanted new action when dragging piano items in Piano Roll
+- Fix crash while recording on existing project (GitHub #161) 
+- Fix crash on startup in Windows build
+
+
 0.14.4 --- 2017 . 10 . 28
 - Renameable channels
 - Portable VST path
index e008f6201671cb22ebc21a6090bb2592faccc71d..3c2f529662e1090555c209947e21348434538c57 100644 (file)
@@ -1,5 +1,102 @@
 AUTOMAKE_OPTIONS = foreign
 
+# Define conditional variables -------------------------------------------------
+# WITH_VST, LINUX, WINDOWS and OSX are varibles defined via AM_CONDITIONAL 
+# inside configure.ac.
+
+extraSources = 
+cppFlags =
+cxxFlags = -std=c++11 -Wall -Werror
+ldAdd =
+ldFlags =
+
+if WITH_VST
+
+extraSources += \
+       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./src/deps/juce/modules                \
+  -I./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 WINDOWS
+
+extraSources += \
+       src/deps/rtaudio-mod/include/asio.h                    \
+       src/deps/rtaudio-mod/include/asio.cpp                  \
+       src/deps/rtaudio-mod/include/asiolist.h                \
+       src/deps/rtaudio-mod/include/asiolist.cpp              \
+       src/deps/rtaudio-mod/include/asiodrivers.h             \
+       src/deps/rtaudio-mod/include/asiodrivers.cpp           \
+       src/deps/rtaudio-mod/include/iasiothiscallresolver.h   \
+       src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp \
+       resource.rc
+
+cppFlags += \
+       -I./src/deps/rtaudio-mod/include \
+       -D__WINDOWS_ASIO__               \
+       -D__WINDOWS_WASAPI__             \
+       -D__WINDOWS_DS__
+
+cxxFlags += -Wno-error
+
+ldAdd += -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 -lshell32 -lvfw32 \
+  -lrpcrt4 -luuid -lcomctl32 -lole32 -lws2_32 -lsndfile -lsamplerate -lrtmidi \
+  -lwinmm -lsetupapi -lksuser -ljansson -limm32 -lglu32 -lshell32 -lversion \
+  -lopengl32 -loleaut32 -lshlwapi -lcomdlg32
+
+# 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__
+
+# Don't stop on JUCE's unused functions.
+cxxFlags += -Wno-error=unused-function
+
+ldAdd += -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \
+  -lpthread -ldl -lpulse-simple -lpulse -lsamplerate -lrtmidi -ljansson \
+  -lfreetype
+
+endif
+
+if OSX
+
+extraSources += src/utils/cocoa.mm src/utils/cocoa.h
+
+# -ObjC++: Juce requires to build some Objective C code
+cxxFlags += -ObjC++ -Wno-auto-var-id
+
+ldAdd += -lsndfile -lfltk -lrtmidi -lsamplerate -ljansson -lm -lpthread \
+  -lFLAC -logg -lvorbis -lvorbisenc
+
+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
@@ -11,10 +108,14 @@ src/core/channel.h                     \
 src/core/channel.cpp                   \
 src/core/sampleChannel.h               \
 src/core/sampleChannel.cpp             \
+src/core/midiDispatcher.h              \
+src/core/midiDispatcher.cpp            \
 src/core/midiChannel.h                 \
 src/core/midiChannel.cpp               \
 src/core/midiMapConf.h                 \
 src/core/midiMapConf.cpp               \
+src/core/midiEvent.h                   \
+src/core/midiEvent.cpp                 \
 src/core/conf.h                        \
 src/core/conf.cpp                      \
 src/core/kernelAudio.h                 \
@@ -97,6 +198,8 @@ src/gui/dialogs/pluginChooser.h        \
 src/gui/dialogs/pluginChooser.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           \
@@ -247,103 +350,24 @@ src/utils/fs.cpp                       \
 src/utils/deps.h                       \
 src/utils/deps.cpp                     \
 src/utils/string.h                     \
-src/utils/string.cpp
-
-if WITH_VST
-giada_SOURCES +=                                              \
-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
-endif
+src/utils/string.cpp                   \
+src/deps/rtaudio-mod/RtAudio.h         \
+src/deps/rtaudio-mod/RtAudio.cpp
 
-# Check for environment: WITH_VST, LINUX, WINDOWS and OSX are varibles defined
-# via AM_CONDITIONAL inside configure.ac.
-# Note: CPPFLAGS = C preprocessor flags, CXXFLAGS = C++ compiler flags.
-
-giada_CXXFLAGS = -std=c++11 -Wall -Werror
-giada_CPPFLAGS =
-
-# TODO - these are flags for Linux only!
-# Also, JUCE makes GCC complain if compiled with optimization set to -O2.
-# Call configure script as follows:
-#
-# ./configure CXXFLAGS='-g -O1 -pedantic' --target=linux --enable-vst
-#
-
-if WITH_VST
-giada_CPPFLAGS +=                          \
-  -I./src/deps/juce/modules                \
-  -I./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 LINUX
-giada_SOURCES += src/deps/rtaudio-mod/RtAudio.h src/deps/rtaudio-mod/RtAudio.cpp
-# -Wno-error=unused-function: don't stop on JUCE's unused functions
-giada_CXXFLAGS += -Wno-error=unused-function
-giada_CPPFLAGS += -D__LINUX_ALSA__ -D__LINUX_PULSE__ -D__UNIX_JACK__
-giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm -ljack -lasound \
-  -lpthread -ldl -lpulse-simple -lpulse -lsamplerate -lrtmidi -ljansson \
-  -lfreetype
-endif
-
-if WINDOWS
-giada_SOURCES +=                                      \
-src/deps/rtaudio-mod/RtAudio.h                        \
-src/deps/rtaudio-mod/RtAudio.cpp                      \
-src/deps/rtaudio-mod/include/asio.h                   \
-src/deps/rtaudio-mod/include/asio.cpp                 \
-src/deps/rtaudio-mod/include/asiolist.h               \
-src/deps/rtaudio-mod/include/asiolist.cpp             \
-src/deps/rtaudio-mod/include/asiodrivers.h            \
-src/deps/rtaudio-mod/include/asiodrivers.cpp          \
-src/deps/rtaudio-mod/include/iasiothiscallresolver.h  \
-src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp
-giada_CXXFLAGS += -Wno-error
-giada_CPPFLAGS +=                \
--I./src/deps/rtaudio-mod/include \
--D__WINDOWS_ASIO__               \
--D__WINDOWS_WASAPI__             \
--D__WINDOWS_DS__
-giada_LDADD = -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \
-  -lshell32 -lvfw32 -lrpcrt4 -luuid -lcomctl32 -lole32 -lws2_32 -lsndfile \
-  -lsamplerate -lrtmidi -lwinmm -lsetupapi -lksuser -ljansson \
-  -limm32 -lglu32 -lshell32 -lversion -lopengl32 -loleaut32 -lshlwapi -lcomdlg32
-giada_LDFLAGS = -mwindows -static
-giada_SOURCES += resource.rc
-endif
-
-if OSX
-giada_SOURCES += src/utils/cocoa.mm src/utils/cocoa.h
-# -ObjC++: Juce requires to build some Objective C code
-giada_CXXFLAGS += -ObjC++ -Wno-auto-var-id
-giada_LDADD = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \
-       -lsamplerate -ljansson
-giada_LDFLAGS = -framework CoreAudio -framework Cocoa -framework Carbon \
-  -framework CoreMIDI -framework CoreFoundation -framework Accelerate \
-  -framework WebKit -framework QuartzCore -framework IOKit
-endif
-
-# used only under MinGW to compile the resource.rc file (program icon)
+giada_SOURCES += $(extraSources)
+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 test --------------------------------------------------------------------
+# make check -------------------------------------------------------------------
 
 TESTS = giada_tests
+
 check_PROGRAMS = giada_tests
 giada_tests_SOURCES =        \
 tests/main.cpp               \
@@ -370,37 +394,11 @@ src/utils/string.cpp         \
 src/utils/time.cpp           \
 src/utils/log.cpp
 
-if WITH_VST
-giada_tests_SOURCES +=                                        \
-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
-endif
-
-giada_tests_LDADD = -ljansson -lsndfile -lsamplerate -lfltk -lXext -lX11 -lXft \
-  -lXpm -lm -ljack -lasound -lpthread -ldl -lpulse-simple -lpulse -lrtmidi \
-  -lfreetype
-
-giada_tests_CXXFLAGS = -std=c++11
-
-if WITH_VST
-giada_tests_CPPFLAGS =                     \
-  -I./src/deps/juce/modules                \
-  -I./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
+giada_tests_SOURCES += $(extraSources)
+giada_tests_CPPFLAGS = $(cppFlags)
+giada_tests_CXXFLAGS = $(cxxFlags)
+giada_tests_LDADD = $(ldAdd)
+giada_tests_LDFLAGS = $(ldFlags)
 
 # make rename ------------------------------------------------------------------
 
index 9da5e2a5b32e917e75cca92d4067206f24d6ec0c..1fa51c3f98cbe6d21f25a2000e547719e4ca5119 100644 (file)
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ http://www.giadamusic.com/forum
 
 ## Copyright
 
-Giada is Copyright (C) 2010-2017 by Giovanni A. Zuliani | Monocasual
+Giada is Copyright (C) 2010-2018 by Giovanni A. Zuliani | Monocasual
 
 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.
 
index c518a2cc4b50ca48cc2c0c11e14056abfd992358..bc80952a66bcf05aeb3cf1c7b2cec84d551f8d19 100644 (file)
@@ -118,13 +118,24 @@ AC_CHECK_HEADER(
 )
 AC_LANG_POP
 
-AC_LANG_PUSH([C++])
-AC_CHECK_HEADER(
-       [rtmidi/RtMidi.h],
-       [],
-       [AC_MSG_ERROR([library 'rtMidi' 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(
@@ -150,31 +161,14 @@ AC_LANG_POP
 #~ )
 #~ AC_LANG_POP
 
-# brutal and temporary hack for OS X: don't use pkg-config
+AC_LANG_PUSH([C++])
+AC_CHECK_HEADER(
+       [samplerate.h],
+       [],
+       [AC_MSG_ERROR([library 'samplerate' not found!])]
+)
+AC_LANG_POP
 
-if test "x$os" = "xosx"; then
-       AC_LANG_PUSH([C++])
-       AC_CHECK_HEADER(
-               [samplerate.h],
-               [],
-               [AC_MSG_ERROR([library 'samplerate' not found!])]
-       )
-       AC_LANG_POP
-else
-#      PKG_CHECK_MODULES(
-#              SAMPLERATE,
-#              samplerate >= 0.1.8,
-#              [],
-#              AC_MSG_ERROR([library 'libsamplerate' not found!])
-#      )
-       AC_LANG_PUSH([C++])
-       AC_CHECK_HEADER(
-               [samplerate.h],
-               [],
-               [AC_MSG_ERROR([library 'samplerate' not found!])]
-       )
-       AC_LANG_POP
-fi
 
 
 # ------------------------------------------------------------------------------
index 95aa43ef61773df7d46a9f04398c84f7797ae709..b11f82cbcafe76f90a9b4b71e36fcf87dab0bab4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -51,7 +51,7 @@ using namespace giada::m;
 
 Channel::Channel(int type, int status, int bufferSize)
 : bufferSize     (bufferSize),
-       midiFilter     (-1),
+       midiInFilter   (-1),
        previewMode    (G_PREVIEW_NONE),
        pan            (0.5f),
        armed          (false),
@@ -166,7 +166,7 @@ void Channel::copy(const Channel *src, pthread_mutex_t *pluginMutex)
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::sendMidiLmessage(uint32_t learn, const midimap::message_t &msg)
+void Channel::sendMidiLmessage(uint32_t learn, const midimap::message_tmsg)
 {
        gu_log("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n",
                learn, msg.channel, msg.value, msg.offset);
@@ -218,6 +218,7 @@ int Channel::writePatch(int i, bool isProject)
        pch.midiInArm       = midiInArm;
        pch.midiInVolume    = midiInVolume;
        pch.midiInMute      = midiInMute;
+       pch.midiInFilter    = midiInFilter;
        pch.midiInSolo      = midiInSolo;
        pch.midiOutL        = midiOutL;
        pch.midiOutLplaying = midiOutLplaying;
@@ -285,6 +286,7 @@ int Channel::readPatch(const string& path, int i, pthread_mutex_t* pluginMutex,
        midiInKill      = pch->midiInKill;
        midiInVolume    = pch->midiInVolume;
        midiInMute      = pch->midiInMute;
+       midiInFilter    = pch->midiInFilter;
        midiInSolo      = pch->midiInSolo;
        midiOutL        = pch->midiOutL;
        midiOutLplaying = pch->midiOutLplaying;
@@ -299,18 +301,29 @@ int Channel::readPatch(const string& path, int i, pthread_mutex_t* pluginMutex,
 #ifdef WITH_VST
 
        for (const patch::plugin_t& ppl : pch->plugins) {
+               
                Plugin* plugin = pluginHost::addPlugin(ppl.path, pluginHost::CHANNEL,
                        pluginMutex, this);
+               
                if (plugin == nullptr) {
                        ret &= 0;
                        continue;
                }
+
                plugin->setBypass(ppl.bypass);
+               
                for (unsigned j=0; j<ppl.params.size(); j++)
                        plugin->setParameter(j, ppl.params.at(j));
-               plugin->midiInParams.clear();
-               for (uint32_t midiInParam : ppl.midiInParams)
-                       plugin->midiInParams.push_back(midiInParam);
+               
+               /* Don't fill Channel::midiInParam if Patch::midiInParams are 0: it would
+               wipe out the current default 0x0 values. */
+
+               if (!ppl.midiInParams.empty()) {
+                       plugin->midiInParams.clear();
+                       for (uint32_t midiInParam : ppl.midiInParams)
+                               plugin->midiInParams.push_back(midiInParam);
+               }
+
                ret &= 1;
        }
 
@@ -374,10 +387,32 @@ void Channel::sendMidiLplay()
 /* -------------------------------------------------------------------------- */
 
 
-void Channel::receiveMidi(uint32_t msg)
+void Channel::receiveMidi(const MidiEvent& midiEvent)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void Channel::setMidiInFilter(int c)
 {
+       midiInFilter = c;
 }
 
+
+int Channel::getMidiInFilter() const
+{
+       return midiInFilter;
+}
+
+
+bool Channel::isMidiInAllowed(int c) const
+{
+       return midiInFilter == -1 || midiInFilter == c;
+}
+
+
 /* -------------------------------------------------------------------------- */
 
 
index 72e6f2d6b8072d66211504f3dde85b788e77be95..a43b15782d7654cb5abdb68e56ce2b1c8def96d9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -33,6 +33,7 @@
 #include <string>
 #include <pthread.h>
 #include "midiMapConf.h"
+#include "midiEvent.h"
 #include "recorder.h"
 
 #ifdef WITH_VST
@@ -75,11 +76,11 @@ protected:
 
        int bufferSize;
 
-  /* midiFilter
+  /* midiInFilter
   Which MIDI channel should be filtered out when receiving MIDI messages. -1
   means 'all'. */
 
-  int midiFilter;
+  int midiInFilter;
 
        /* previewMode
        Whether the channel is in audio preview mode or not. */
@@ -208,7 +209,7 @@ public:
        /* receiveMidi
        Receives and processes midi messages from external devices. */
 
-       virtual void receiveMidi(uint32_t msg);
+       virtual void receiveMidi(const giada::m::MidiEvent& midiEvent);
 
        /* allocBuffers
        Mandatory method to allocate memory for internal buffers. Call it after the
@@ -216,10 +217,18 @@ public:
 
        virtual bool allocBuffers();
 
-       /* isPlaying
-        * tell wether the channel is playing or is stopped. */
-
        bool isPlaying() const;
+       float getPan() const;
+       bool isArmed() const;
+       std::string getName() const;
+       bool isPreview() const;
+       int getMidiInFilter() const;
+
+       /* isMidiAllowed
+       Given a MIDI channel 'c' tells whether this channel should be allowed to receive
+       and process MIDI events on MIDI channel 'c'. */
+
+       bool isMidiInAllowed(int c) const;
 
        /* sendMidiL*
         * send MIDI lightning events to a physical device. */
@@ -229,16 +238,10 @@ public:
        void sendMidiLplay();
 
        void setPan(float v);
-       float getPan() const;
-
        void setArmed(bool b);
-       bool isArmed() const;
-
-       std::string getName() const;
        void setName(const std::string& s);
-
        void setPreviewMode(int m);
-       bool isPreview() const;
+       void setMidiInFilter(int c);
 
 #ifdef WITH_VST
 
index 1a7e5d503f25cfd00d35d9392edebeb8e031eed4..a62d0b04ff7015c7eb53df4af991072550313adf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index fd39f4630e1c871077ad952c544e74e9d1115526..de2972d24d92786331c7db80c1d8f0a612fa261a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e32c28951bb9d317d6cb99aff75cd6a329df6331..0914d96c7eaf8151ba784fb6201a0347f0a45944 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -167,6 +167,8 @@ string lastFileMap = "";
 int    midiSync    = MIDI_SYNC_NONE;
 float  midiTCfps   = 25.0f;
 
+bool midiIn               = false;
+int midiInFilter          = -1;
 uint32_t midiInRewind     = 0x0;
 uint32_t midiInStartStop  = 0x0;
 uint32_t midiInActionRec  = 0x0;
@@ -277,6 +279,15 @@ void init()
 /* -------------------------------------------------------------------------- */
 
 
+bool isMidiInAllowed(int c)
+{
+       return midiInFilter == -1 || midiInFilter == c;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 int read()
 {
        init();
@@ -314,7 +325,9 @@ int read()
        if (!storager::setString(jRoot, CONF_KEY_LAST_MIDIMAP, lastFileMap)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_MIDI_SYNC, midiSync)) return 0;
        if (!storager::setFloat(jRoot, CONF_KEY_MIDI_TC_FPS, midiTCfps)) return 0;
-       if (!storager::setUint32(jRoot, CONF_KEY_MIDI_IN_REWIND, midiInRewind)) return 0;
+       if (!storager::setBool(jRoot, CONF_KEY_MIDI_IN, midiIn)) return 0; 
+       if (!storager::setInt(jRoot, CONF_KEY_MIDI_IN_FILTER, midiInFilter)) return 0; 
+       if (!storager::setUint32(jRoot, CONF_KEY_MIDI_IN_REWIND, midiInRewind)) return 0; 
        if (!storager::setUint32(jRoot, CONF_KEY_MIDI_IN_START_STOP, midiInStartStop)) return 0;
        if (!storager::setUint32(jRoot, CONF_KEY_MIDI_IN_ACTION_REC, midiInActionRec)) return 0;
        if (!storager::setUint32(jRoot, CONF_KEY_MIDI_IN_INPUT_REC, midiInInputRec)) return 0;
@@ -331,7 +344,6 @@ int read()
        if (!storager::setString(jRoot, CONF_KEY_PLUGINS_PATH, pluginPath)) return 0;
        if (!storager::setString(jRoot, CONF_KEY_PATCHES_PATH, patchPath)) return 0;
        if (!storager::setString(jRoot, CONF_KEY_SAMPLES_PATH, samplePath)) return 0;
-
        if (!storager::setInt(jRoot, CONF_KEY_MAIN_WINDOW_X, mainWindowX)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_MAIN_WINDOW_Y, mainWindowY)) return 0;
        if (!storager::setInt(jRoot, CONF_KEY_MAIN_WINDOW_W, mainWindowW)) return 0;
@@ -423,6 +435,8 @@ int write()
        json_object_set_new(jRoot, CONF_KEY_LAST_MIDIMAP,              json_string(lastFileMap.c_str()));
        json_object_set_new(jRoot, CONF_KEY_MIDI_SYNC,                 json_integer(midiSync));
        json_object_set_new(jRoot, CONF_KEY_MIDI_TC_FPS,               json_real(midiTCfps));
+       json_object_set_new(jRoot, CONF_KEY_MIDI_IN,                   json_boolean(midiIn));
+       json_object_set_new(jRoot, CONF_KEY_MIDI_IN_FILTER,            json_integer(midiInFilter));
        json_object_set_new(jRoot, CONF_KEY_MIDI_IN_REWIND,            json_integer(midiInRewind));
        json_object_set_new(jRoot, CONF_KEY_MIDI_IN_START_STOP,        json_integer(midiInStartStop));
        json_object_set_new(jRoot, CONF_KEY_MIDI_IN_ACTION_REC,            json_integer(midiInActionRec));
index 024c734d45882b02151d178c18c061cff0e42a79..b881d6de37893be029fed26d271481c9bfa7ac0d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -40,6 +40,12 @@ void init();
 int read();
 int write();
 
+/* isMidiAllowed
+Given a MIDI channel 'c' tells whether this channel should be allowed to receive
+and process MIDI events on MIDI channel 'c'. */
+
+bool isMidiInAllowed(int c);
+
 extern std::string header;
 
 extern int  logMode;
@@ -63,6 +69,8 @@ extern std::string lastFileMap;
 extern int   midiSync;  // see const.h
 extern float midiTCfps;
 
+extern bool midiIn;
+extern int midiInFilter;
 extern uint32_t midiInRewind;
 extern uint32_t midiInStartStop;
 extern uint32_t midiInActionRec;
index 7e48358f4d56fc28d507a64f960ae399a6b83575..78b8b9e33ed04dd5d01c0861d074855bfc77b2b1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 /* -- version --------------------------------------------------------------- */
 #define G_APP_NAME      "Giada"
-#define G_VERSION_STR   "0.14.4"
+#define G_VERSION_STR   "0.14.5"
 #define G_VERSION_MAJOR 0
 #define G_VERSION_MINOR 14
-#define G_VERSION_PATCH 4
+#define G_VERSION_PATCH 5
 
 #define CONF_FILENAME "giada.conf"
 
        #define G_DEFAULT_SOUNDSYS      G_SYS_API_CORE
 #endif
 
-#define G_DEFAULT_SOUNDDEV_OUT    0      // FIXME - please override with rtAudio::getDefaultDevice (or similar)
-#define G_DEFAULT_SOUNDDEV_IN    -1      // no recording by default: input disabled
-#define G_DEFAULT_MIDI_SYSTEM     0
-#define G_DEFAULT_MIDI_PORT_IN   -1
-#define G_DEFAULT_MIDI_PORT_OUT  -1
-#define G_DEFAULT_SAMPLERATE      44100
-#define G_DEFAULT_BUFSIZE         1024
-#define G_DEFAULT_DELAYCOMP       0
-#define G_DEFAULT_BIT_DEPTH       32     // float
-#define G_DEFAULT_AUDIO_CHANS     2      // stereo for internal processing
-#define G_DEFAULT_VOL             1.0f
-#define G_DEFAULT_PITCH           1.0f
-#define G_DEFAULT_BOOST           1.0f
-#define G_DEFAULT_OUT_VOL         1.0f
-#define G_DEFAULT_IN_VOL          1.0f
-#define G_DEFAULT_CHANMODE       SINGLE_BASIC
-#define G_DEFAULT_BPM             120.0f
-#define G_DEFAULT_BEATS           4
-#define G_DEFAULT_BARS            1
-#define G_DEFAULT_QUANTIZE        0      // quantizer off
-#define G_DEFAULT_FADEOUT_STEP    0.01f  // micro-fadeout speed
-#define G_DEFAULT_COLUMN_WIDTH    380
-#define G_DEFAULT_PATCH_NAME      "(default patch)"
-#define G_DEFAULT_MIDI_INPUT_UI_W 300
-#define G_DEFAULT_MIDI_INPUT_UI_H 350
+#define G_DEFAULT_SOUNDDEV_OUT     0      // FIXME - please override with rtAudio::getDefaultDevice (or similar)
+#define G_DEFAULT_SOUNDDEV_IN     -1      // no recording by default: input disabled
+#define G_DEFAULT_MIDI_SYSTEM      0
+#define G_DEFAULT_MIDI_PORT_IN    -1
+#define G_DEFAULT_MIDI_PORT_OUT   -1
+#define G_DEFAULT_SAMPLERATE       44100
+#define G_DEFAULT_BUFSIZE          1024
+#define G_DEFAULT_DELAYCOMP        0
+#define G_DEFAULT_BIT_DEPTH        32     // float
+#define G_DEFAULT_AUDIO_CHANS      2      // stereo for internal processing
+#define G_DEFAULT_VOL              1.0f
+#define G_DEFAULT_PITCH            1.0f
+#define G_DEFAULT_BOOST            1.0f
+#define G_DEFAULT_OUT_VOL          1.0f
+#define G_DEFAULT_IN_VOL           1.0f
+#define G_DEFAULT_CHANMODE         SINGLE_BASIC
+#define G_DEFAULT_BPM              120.0f
+#define G_DEFAULT_BEATS            4
+#define G_DEFAULT_BARS             1
+#define G_DEFAULT_QUANTIZE         0      // quantizer off
+#define G_DEFAULT_FADEOUT_STEP     0.01f  // micro-fadeout speed
+#define G_DEFAULT_COLUMN_WIDTH     380
+#define G_DEFAULT_PATCH_NAME       "(default patch)"
+#define G_DEFAULT_MIDI_INPUT_UI_W  300
+#define G_DEFAULT_MIDI_INPUT_UI_H  350
+#define G_DEFAULT_MIDI_ACTION_SIZE 8192   // frames
 
 
 
@@ -374,6 +375,7 @@ const int MIDI_CHANS[16] = {
 #define PATCH_KEY_CHANNEL_MIDI_IN_ARM          "midi_in_arm"
 #define PATCH_KEY_CHANNEL_MIDI_IN_VOLUME       "midi_in_volume"
 #define PATCH_KEY_CHANNEL_MIDI_IN_MUTE         "midi_in_mute"
+#define PATCH_KEY_CHANNEL_MIDI_IN_FILTER       "midi_in_filter"
 #define PATCH_KEY_CHANNEL_MIDI_IN_SOLO         "midi_in_solo"
 #define PATCH_KEY_CHANNEL_MIDI_OUT_L           "midi_out_l"
 #define PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING   "midi_out_l_playing"
@@ -429,6 +431,8 @@ const int MIDI_CHANS[16] = {
 #define CONF_KEY_LAST_MIDIMAP             "last_midimap"
 #define CONF_KEY_MIDI_SYNC                "midi_sync"
 #define CONF_KEY_MIDI_TC_FPS              "midi_tc_fps"
+#define CONF_KEY_MIDI_IN                  "midi_in"
+#define CONF_KEY_MIDI_IN_FILTER           "midi_in_filter"
 #define CONF_KEY_MIDI_IN_REWIND           "midi_in_rewind"
 #define CONF_KEY_MIDI_IN_START_STOP       "midi_in_start_stop"
 #define CONF_KEY_MIDI_IN_ACTION_REC       "midi_in_action_rec"
index f9be05a94053c3d659ba1c09732c2237c6cc1c9d..c6be10f20bc2547b3001313fe841e12e1d9bf36b 100644 (file)
@@ -6,7 +6,7 @@
  *
  * ---------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b1377864029ece6c0ad810ee5c9188cff4068f69..a09cdb7d5159b2b79519e915a6b5c34083f1130e 100644 (file)
@@ -6,7 +6,7 @@
  *
  * ---------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 610487492a34dbaa66132f2c116d99f6d2b35fd2..86fcf89bb6df5f738c1c10f619b85f2397fdb77e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -129,7 +129,7 @@ void init_prepareMidiMap()
 /* -------------------------------------------------------------------------- */
 
 
-void init_startGUI(int argc, char **argv)
+void init_startGUI(int argc, char** argv)
 {
        G_MainWin = new gdMainWindow(G_GUI_WIDTH, G_GUI_HEIGHT, "", argc, argv);
        G_MainWin->resize(conf::mainWindowX, conf::mainWindowY, conf::mainWindowW,
index 19833d4e39b20440f3da644cbbf06e3538a2073f..b67058038068f43dd5186c9d74ea67c13ca54b4c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index d9fe65ce02765b43d4105353c900de8e371a0204..15bb1ebd829404da431cdc2f89e17fad1a282eb9 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -46,12 +46,12 @@ namespace kernelAudio
 {
 namespace
 {
-RtAudio *rtSystem;
-bool status;
-unsigned numDevs;
-bool inputEnabled;
-unsigned realBufsize;          // reale bufsize from the soundcard
-int api;
+RtAudio *rtSystem = nullptr;
+bool status = false;
+unsigned numDevs = 0;
+bool inputEnabled = false;
+unsigned realBufsize = 0;              // reale bufsize from the soundcard
+int api = 0;
 
 #ifdef __linux__
 
@@ -71,19 +71,6 @@ jack_client_t *jackGetHandle()
 /* -------------------------------------------------------------------------- */
 
 
-void init()
-{
-  rtSystem     = nullptr;
-  numDevs      = 0;
-  inputEnabled = 0;
-  realBufsize  = 0;
-  api          = 0;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 bool getStatus()
 {
   return status;
@@ -96,7 +83,7 @@ bool getStatus()
 int openDevice()
 {
        api = conf::soundSystem;
-       gu_log("[KA] using rtSystem 0x%x\n", api);
+       gu_log("[KA] using system 0x%x\n", api);
 
 #if defined(__linux__)
 
@@ -127,8 +114,10 @@ int openDevice()
 
 #endif
 
-       else
+       else {
+               gu_log("[KA] No API available, nothing to do!\n");
                return 0;
+       }
 
        gu_log("[KA] Opening devices %d (out), %d (in), f=%d...\n",
     conf::soundDeviceOut, conf::soundDeviceIn, conf::samplerate);
index 21358c4a403454bc7ea6addefa2e3918a77ede8e..6dacf2944959096979bf4a0e320b43368016bf59 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -56,8 +56,6 @@ struct JackState
 
 #endif
 
-void init();
-
 int openDevice();
 int closeDevice();
 int startStream();
index 8a19181fef830cf29a1c7fcae16422c34d898352..22331e594a712cfde96f26a974d2c18176e212e7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  * -------------------------------------------------------------------------- */
 
 
-#include <rtmidi/RtMidi.h>
-#include "../utils/log.h"
-#include "../glue/channel.h"
-#include "../glue/plugin.h"
-#include "../glue/main.h"
-#include "../glue/transport.h"
-#include "../glue/io.h"
-#include "mixer.h"
 #include "const.h"
-#include "channel.h"
-#include "sampleChannel.h"
-#include "midiChannel.h"
-#include "conf.h"
-#include "midiMapConf.h"
-#ifdef WITH_VST
-  #include "pluginHost.h"
-  #include "plugin.h"
+#ifdef G_OS_MAC
+       #include <RtMidi.h>
+#else
+       #include <rtmidi/RtMidi.h>
 #endif
+#include "../utils/log.h"
+#include "midiDispatcher.h"
+#include "midiMapConf.h"
 #include "kernelMidi.h"
 
 
@@ -63,167 +54,9 @@ RtMidiIn*  midiIn  = nullptr;
 unsigned numOutPorts = 0;
 unsigned numInPorts  = 0;
 
-/* cb_learn
- * callback prepared by the gdMidiGrabber window and called by
- * kernelMidi. It contains things to do once the midi message has been
- * stored. */
-
-cb_midiLearn* cb_learn = nullptr;
-void* cb_data = nullptr;
-
-
-/* -------------------------------------------------------------------------- */
-
-
-#ifdef WITH_VST
-
-void processPlugins(Channel* ch, uint32_t pure, uint32_t value)
-{
-  /* Plugins' parameters layout reflects the structure of the matrix
-  Channel::midiInPlugins. It is safe to assume then that i (i.e. Plugin*) and k 
-  indexes match both the structure of Channel::midiInPlugins and 
-  vector<Plugin*>* plugins. */
-
-  vector<Plugin*>* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
-
-  for (Plugin* plugin : *plugins) {
-    for (unsigned k=0; k<plugin->midiInParams.size(); k++) {
-      uint32_t midiInParam = plugin->midiInParams.at(k);
-      if (pure != midiInParam)
-        continue;
-      float vf = (value >> 8) / 127.0f;
-      c::plugin::setParameter(plugin, k, vf, false); // false: not from GUI
-      gu_log("  >>> [plugin %d parameter %d] ch=%d (pure=0x%X, value=%d, float=%f)\n",
-        plugin->getId(), k, ch->index, pure, value >> 8, vf);
-    }
-  }
-}
-
-#endif
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void processChannels(uint32_t pure, uint32_t value)
-{
-       for (Channel* ch : mixer::channels) {
-
-               if (!ch->midiIn)
-                       continue;
-
-               if      (pure == ch->midiInKeyPress) {
-                       gu_log("  >>> keyPress, ch=%d (pure=0x%X)\n", ch->index, pure);
-                       glue_keyPress(ch, false, false);
-               }
-               else if (pure == ch->midiInKeyRel) {
-                       gu_log("  >>> keyRel ch=%d (pure=0x%X)\n", ch->index, pure);
-                       glue_keyRelease(ch, false, false);
-               }
-               else if (pure == ch->midiInMute) {
-                       gu_log("  >>> mute ch=%d (pure=0x%X)\n", ch->index, pure);
-                       glue_toggleMute(ch, false);
-               }               
-               else if (pure == ch->midiInKill) {
-                       gu_log("  >>> kill ch=%d (pure=0x%X)\n", ch->index, pure);
-                       glue_kill(ch);
-               }               
-               else if (pure == ch->midiInArm) {
-                       gu_log("  >>> arm ch=%d (pure=0x%X)\n", ch->index, pure);
-                       glue_toggleArm(ch, false);
-               }
-               else if (pure == ch->midiInSolo) {
-                       gu_log("  >>> solo ch=%d (pure=0x%X)\n", ch->index, pure);
-                       glue_toggleSolo(ch, false);
-               }
-               else if (pure == ch->midiInVolume) {
-                       float vf = (value >> 8)/127.0f;
-                       gu_log("  >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n",
-                               ch->index, pure, value >> 8, vf);
-                       glue_setVolume(ch, vf, false);
-               }
-               else {
-                       SampleChannel* sch = static_cast<SampleChannel*>(ch);
-                       if (pure == sch->midiInPitch) {
-                               float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0-4.0]
-                               gu_log("  >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n",
-                                       sch->index, pure, value >> 8, vf);
-                               glue_setPitch(sch, vf);
-                       }
-                       else 
-                       if (pure == sch->midiInReadActions) {
-                               gu_log("  >>> toggle read actions ch=%d (pure=0x%X)\n", sch->index, pure);
-                               glue_toggleReadingRecs(sch, false);
-                       }
-               }
-
-#ifdef WITH_VST
-    processPlugins(ch, pure, value); // Process plugins' parameters
-#endif
-
-               /* Redirect full midi message (pure + value) to plugins. */
-
-               ch->receiveMidi(pure | value);
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void processMaster(uint32_t pure, uint32_t value)
-{
-  if      (pure == conf::midiInRewind) {
-               gu_log("  >>> rewind (master) (pure=0x%X)\n", pure);
-               glue_rewindSeq(false);
-       }
-       else if (pure == conf::midiInStartStop) {
-               gu_log("  >>> startStop (master) (pure=0x%X)\n", pure);
-               glue_startStopSeq(false);
-       }
-       else if (pure == conf::midiInActionRec) {
-               gu_log("  >>> actionRec (master) (pure=0x%X)\n", pure);
-               glue_startStopActionRec(false);
-       }
-       else if (pure == conf::midiInInputRec) {
-               gu_log("  >>> inputRec (master) (pure=0x%X)\n", pure);
-               glue_startStopInputRec(false);
-       }
-       else if (pure == conf::midiInMetronome) {
-               gu_log("  >>> metronome (master) (pure=0x%X)\n", pure);
-               glue_startStopMetronome(false);
-       }
-       else if (pure == conf::midiInVolumeIn) {
-               float vf = (value >> 8)/127.0f;
-               gu_log("  >>> input volume (master) (pure=0x%X, value=%d, float=%f)\n",
-                       pure, value >> 8, vf);
-               glue_setInVol(vf, false);
-       }
-       else if (pure == conf::midiInVolumeOut) {
-               float vf = (value >> 8)/127.0f;
-               gu_log("  >>> output volume (master) (pure=0x%X, value=%d, float=%f)\n",
-                       pure, value >> 8, vf);
-               glue_setOutVol(vf, false);
-       }
-       else if (pure == conf::midiInBeatDouble) {
-               gu_log("  >>> sequencer x2 (master) (pure=0x%X)\n", pure);
-               glue_beatsMultiply();
-       }
-       else if (pure == conf::midiInBeatHalf) {
-               gu_log("  >>> sequencer /2 (master) (pure=0x%X)\n", pure);
-               glue_beatsDivide();
-       }
-}
-
-
-/* -------------------------------------------------------------------------- */
-
 
 static void callback(double t, std::vector<unsigned char>* msg, void* data)
 {
-  /* 0.8.0 - for now we handle other MIDI signals (common and real-time 
-  messages) as unknown, for debugging purposes. */
-
        if (msg->size() < 3) {
                //gu_log("[KM] MIDI received - unknown signal - size=%d, value=0x", (int) msg->size());
                //for (unsigned i=0; i<msg->size(); i++)
@@ -231,32 +64,7 @@ static void callback(double t, std::vector<unsigned char>* msg, void* data)
                //gu_log("\n");
                return;
        }
-
-       /* Here we want to catch two things: a) note on/note off from a keyboard and 
-       b) knob/wheel/slider movements from a controller. */
-
-       uint32_t input = getIValue(msg->at(0), msg->at(1), msg->at(2));
-       uint32_t chan  = input & 0x0F000000;
-       uint32_t value = input & 0x0000FF00;
-       uint32_t pure  = 0x00;
-       if (!conf::noNoteOff)
-               pure = input & 0xFFFF0000;   // input without 'value' (i.e. velocity) byte
-       else
-               pure = input & 0xFFFFFF00;   // input with 'value' (i.e. velocity) byte
-
-       gu_log("[KM] MIDI received - 0x%X (chan %d)\n", input, chan >> 24);
-
-       /* Start dispatcher. If midi learn is on don't parse channels, just learn 
-       incoming MIDI signal. Otherwise process master events first, then each channel 
-       in the stack. This way incoming signals don't get processed by glue_* when 
-       MIDI learning is on. */
-
-       if (cb_learn)
-               cb_learn(pure, cb_data);
-       else {
-               processMaster(pure, value);
-               processChannels(pure, value);
-       }
+       midiDispatcher::dispatch(msg->at(0), msg->at(1), msg->at(2));
 }
 
 
@@ -265,7 +73,7 @@ static void callback(double t, std::vector<unsigned char>* msg, void* data)
 
 void sendMidiLightningInitMsgs()
 {
-  for(unsigned i=0; i<midimap::initCommands.size(); i++) {
+       for(unsigned i=0; i<midimap::initCommands.size(); i++) {
                midimap::message_t msg = midimap::initCommands.at(i);
                if (msg.value != 0x0 && msg.channel != -1) {
                        gu_log("[KM] MIDI send (init) - Channel %x - Event 0x%X\n", msg.channel, msg.value);
@@ -282,26 +90,6 @@ void sendMidiLightningInitMsgs()
 /* -------------------------------------------------------------------------- */
 
 
-void startMidiLearn(cb_midiLearn *cb, void *data)
-{
-       cb_learn = cb;
-       cb_data  = data;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void stopMidiLearn()
-{
-       cb_learn = nullptr;
-       cb_data  = nullptr;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 void setApi(int _api)
 {
        api = _api;
@@ -317,18 +105,18 @@ int openOutDevice(int port)
        try {
                midiOut = new RtMidiOut((RtMidi::Api) api, "Giada MIDI Output");
                status = true;
-  }
-  catch (RtMidiError &error) {
-    gu_log("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
-    status = false;
-    return 0;
-  }
+       }
+       catch (RtMidiError &error) {
+               gu_log("[KM] MIDI out device error: %s\n", error.getMessage().c_str());
+               status = false;
+               return 0;
+       }
 
        /* print output ports */
 
        numOutPorts = midiOut->getPortCount();
-  gu_log("[KM] %d output MIDI ports found\n", numOutPorts);
-  for (unsigned i=0; i<numOutPorts; i++)
+       gu_log("[KM] %d output MIDI ports found\n", numOutPorts);
+       for (unsigned i=0; i<numOutPorts; i++)
                gu_log("  %d) %s\n", i, getOutPortName(i).c_str());
 
        /* try to open a port, if enabled */
@@ -363,18 +151,18 @@ int openInDevice(int port)
        try {
                midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input");
                status = true;
-  }
-  catch (RtMidiError &error) {
-    gu_log("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
-    status = false;
-    return 0;
-  }
+       }
+       catch (RtMidiError &error) {
+               gu_log("[KM] MIDI in device error: %s\n", error.getMessage().c_str());
+               status = false;
+               return 0;
+       }
 
        /* print input ports */
 
        numInPorts = midiIn->getPortCount();
-  gu_log("[KM] %d input MIDI ports found\n", numInPorts);
-  for (unsigned i=0; i<numInPorts; i++)
+       gu_log("[KM] %d input MIDI ports found\n", numInPorts);
+       for (unsigned i=0; i<numInPorts; i++)
                gu_log("  %d) %s\n", i, getInPortName(i).c_str());
 
        /* try to open a port, if enabled */
@@ -436,9 +224,9 @@ void send(uint32_t data)
        if (!status)
                return;
 
-  vector<unsigned char> msg(1, getB1(data));
-  msg.push_back(getB2(data));
-  msg.push_back(getB3(data));
+       vector<unsigned char> msg(1, getB1(data));
+       msg.push_back(getB2(data));
+       msg.push_back(getB3(data));
 
        midiOut->sendMessage(&msg);
        gu_log("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]);
@@ -470,13 +258,13 @@ void send(int b1, int b2, int b3)
 
 unsigned countInPorts()
 {
-  return numInPorts;
+       return numInPorts;
 }
 
 
 unsigned countOutPorts()
 {
-  return numOutPorts;
+       return numOutPorts;
 }
 
 
@@ -490,7 +278,7 @@ 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);
+       return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00);
 }
 
 
@@ -499,8 +287,8 @@ uint32_t getIValue(int b1, int b2, int b3)
 
 uint32_t setChannel(uint32_t iValue, int channel)
 {
-  uint32_t chanMask = 0xF << 24;
-  return (iValue & (~chanMask)) | (channel << 24);
+       uint32_t chanMask = 0xF << 24;
+       return (iValue & (~chanMask)) | (channel << 24);
 }
 
 
index 700a78aac692e01e955d135a1806b6ca379cecea..d1c8e866b0387cd81988377e7accdbde30158753 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
        #include <cstdint>
 #endif
 #include <string>
-#include <vector>
 
 
 namespace giada {
 namespace m {
 namespace kernelMidi
 {
-typedef void (cb_midiLearn) (uint32_t, void *);
-
-void startMidiLearn(cb_midiLearn *cb, void *data);
-void stopMidiLearn();
-
 int getB1(uint32_t iValue);
 int getB2(uint32_t iValue);
 int getB3(uint32_t iValue);
index fe58e7f34773c797bcec509e5ceff4536d14f479..695fb3c1240073f5f31e78687bff4e98f6718176 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -34,7 +34,7 @@
 #include "conf.h"
 #include "mixer.h"
 #ifdef WITH_VST
-  #include "pluginHost.h"
+       #include "pluginHost.h"
 #endif
 #include "kernelMidi.h"
 
@@ -45,8 +45,8 @@ using namespace giada::m;
 
 MidiChannel::MidiChannel(int bufferSize)
        : Channel    (CHANNEL_MIDI, STATUS_OFF, bufferSize),
-         midiOut    (false),
-         midiOutChan(MIDI_CHANS[0])
+               midiOut    (false),
+               midiOutChan(MIDI_CHANS[0])
 {
 }
 
@@ -315,44 +315,35 @@ int MidiChannel::writePatch(int i, bool isProject)
 /* -------------------------------------------------------------------------- */
 
 
-void MidiChannel::receiveMidi(uint32_t msg)
+void MidiChannel::receiveMidi(const MidiEvent& midiEvent)
 {
-  if (!armed)
-    return;
+       if (!armed)
+               return;
 
-  /* Filter time, based on MIDI channel. If midiFilter == -1, all messages
-  are taken into account. */
-  /* TODO - actual MIDI filtering not yet implemented. */
+       /* 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. */
 
-  if (midiFilter != -1)
-  {
-    gu_log("[Channel::processMidi] MIDI channel filtering not yet implemented\n");
-    return;
-  }
-
-  /* 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. */
-
-  msg = kernelMidi::setChannel(msg, 0);
+       MidiEvent midiEventFlat(midiEvent);
+       midiEventFlat.setChannel(0);
 
 #ifdef WITH_VST
 
-  while (true) {
-    if (pthread_mutex_trylock(&pluginHost::mutex_midi) != 0)
-      continue;
-    gu_log("[Channel::processMidi] msg=%X\n", msg);
-    addVstMidiEvent(msg, 0);
-    pthread_mutex_unlock(&pluginHost::mutex_midi);
-    break;
-  }
+       while (true) {
+               if (pthread_mutex_trylock(&pluginHost::mutex_midi) != 0)
+                       continue;
+               gu_log("[Channel::processMidi] msg=%X\n", midiEventFlat.getRaw());
+               addVstMidiEvent(midiEventFlat.getRaw(), 0);
+               pthread_mutex_unlock(&pluginHost::mutex_midi);
+               break;
+       }
 
 #endif
 
        if (recorder::canRec(this, clock::isRunning(), mixer::recording)) {
-               recorder::rec(index, G_ACTION_MIDI, clock::getCurrentFrame(), msg);
-    hasActions = true;
-  }
+               recorder::rec(index, G_ACTION_MIDI, clock::getCurrentFrame(), midiEventFlat.getRaw());
+               hasActions = true;
+       }
 }
 
 
index 8b2cd56b73ac5353177109dab65944c3c2f58a8e..4617c457b89b839f0a060dc097a0cd063b6ddcb0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -70,7 +70,7 @@ public:
        void onBar(int frame) override;
        void parseAction(giada::m::recorder::action* a, int localFrame, int globalFrame,
                int quantize, bool mixerIsRunning) override;
-       void receiveMidi(uint32_t msg) override;
+       void receiveMidi(const giada::m::MidiEvent& midiEvent) override;
        bool canInputRec() override;
 
        /* sendMidi
diff --git a/src/core/midiDispatcher.cpp b/src/core/midiDispatcher.cpp
new file mode 100644 (file)
index 0000000..c8a9d94
--- /dev/null
@@ -0,0 +1,276 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 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 <vector>
+#include "../glue/plugin.h"
+#include "../glue/io.h"
+#include "../glue/channel.h"
+#include "../glue/transport.h"
+#include "../glue/main.h"
+#include "../utils/log.h"
+#include "channel.h"
+#include "sampleChannel.h"
+#include "midiChannel.h"
+#include "conf.h"
+#include "mixer.h"
+#include "pluginHost.h"
+#include "plugin.h"
+#include "midiDispatcher.h"
+
+
+using std::vector;
+
+
+namespace giada {
+namespace m {
+namespace midiDispatcher
+{
+namespace
+{
+/* cb_midiLearn, cb_data
+Callback prepared by the gdMidiGrabber window and called by midiDispatcher. It 
+contains things to do once the midi message has been stored. */
+
+cb_midiLearn* cb_learn = nullptr;
+void* cb_data = nullptr;       
+
+
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef WITH_VST
+
+void processPlugins(Channel* ch, const MidiEvent& midiEvent)
+{
+       /* Pure value: if 'noNoteOff' in global config, get the raw value with the
+       'velocy' byte. Otherwise strip it off. */
+
+       uint32_t pure = midiEvent.getRaw(conf::noNoteOff);
+
+       /* Plugins' parameters layout reflects the structure of the matrix
+       Channel::midiInPlugins. It is safe to assume then that i (i.e. Plugin*) and k 
+       indexes match both the structure of Channel::midiInPlugins and 
+       vector<Plugin*>* plugins. */
+
+       vector<Plugin*>* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
+
+       for (Plugin* plugin : *plugins) {
+               for (unsigned k=0; k<plugin->midiInParams.size(); k++) {
+                       uint32_t midiInParam = plugin->midiInParams.at(k);
+                       if (pure != midiInParam)
+                               continue;
+                       float vf = midiEvent.getVelocity() / 127.0f;
+                       c::plugin::setParameter(plugin, k, vf, false); // false: not from GUI
+                       gu_log("  >>> [plugin %d parameter %d] ch=%d (pure=0x%X, value=%d, float=%f)\n",
+                               plugin->getId(), k, ch->index, pure, midiEvent.getVelocity(), vf);
+               }
+       }
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void processChannels(const MidiEvent& midiEvent)
+{
+       /* Pure value: if 'noNoteOff' in global config, get the raw value with the
+       'velocy' byte. Otherwise strip it off. */
+
+       uint32_t pure = midiEvent.getRaw(conf::noNoteOff);
+
+       for (Channel* ch : mixer::channels) {
+
+               /* Do nothing on this channel if MIDI in is disabled or filtered out for
+               the current MIDI channel. */
+
+               if (!ch->midiIn || !ch->isMidiInAllowed(midiEvent.getChannel()))
+                       continue;
+
+               if      (pure == ch->midiInKeyPress) {
+                       gu_log("  >>> keyPress, ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_keyPress(ch, false, false);
+               }
+               else if (pure == ch->midiInKeyRel) {
+                       gu_log("  >>> keyRel ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_keyRelease(ch, false, false);
+               }
+               else if (pure == ch->midiInMute) {
+                       gu_log("  >>> mute ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_toggleMute(ch, false);
+               }               
+               else if (pure == ch->midiInKill) {
+                       gu_log("  >>> kill ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_kill(ch);
+               }               
+               else if (pure == ch->midiInArm) {
+                       gu_log("  >>> arm ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_toggleArm(ch, false);
+               }
+               else if (pure == ch->midiInSolo) {
+                       gu_log("  >>> solo ch=%d (pure=0x%X)\n", ch->index, pure);
+                       glue_toggleSolo(ch, false);
+               }
+               else if (pure == ch->midiInVolume) {
+                       float vf = midiEvent.getVelocity() / 127.0f;
+                       gu_log("  >>> volume ch=%d (pure=0x%X, value=%d, float=%f)\n",
+                               ch->index, pure, midiEvent.getVelocity(), vf);
+                       glue_setVolume(ch, vf, false);
+               }
+               else {
+                       SampleChannel* sch = static_cast<SampleChannel*>(ch);
+                       if (pure == sch->midiInPitch) {
+                               float vf = midiEvent.getVelocity() / (127/4.0f); // [0-127] ~> [0.0-4.0]
+                               gu_log("  >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)\n",
+                                       sch->index, pure, midiEvent.getVelocity(), vf);
+                               glue_setPitch(sch, vf);
+                       }
+                       else 
+                       if (pure == sch->midiInReadActions) {
+                               gu_log("  >>> toggle read actions ch=%d (pure=0x%X)\n", sch->index, pure);
+                               glue_toggleReadingRecs(sch, false);
+                       }
+               }
+
+#ifdef WITH_VST
+               processPlugins(ch, midiEvent); // Process plugins' parameters
+#endif
+
+               /* Redirect full midi message (pure + velocity) to plugins. */
+
+               ch->receiveMidi(midiEvent.getRaw());
+       }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void processMaster(const MidiEvent& midiEvent)
+{
+       /* Pure value: if 'noNoteOff' in global config, get the raw value with the
+       'velocy' byte. Otherwise strip it off. */
+
+       uint32_t pure = midiEvent.getRaw(conf::noNoteOff);
+
+       if      (pure == conf::midiInRewind) {
+               gu_log("  >>> rewind (master) (pure=0x%X)\n", pure);
+               glue_rewindSeq(false);
+       }
+       else if (pure == conf::midiInStartStop) {
+               gu_log("  >>> startStop (master) (pure=0x%X)\n", pure);
+               glue_startStopSeq(false);
+       }
+       else if (pure == conf::midiInActionRec) {
+               gu_log("  >>> actionRec (master) (pure=0x%X)\n", pure);
+               glue_startStopActionRec(false);
+       }
+       else if (pure == conf::midiInInputRec) {
+               gu_log("  >>> inputRec (master) (pure=0x%X)\n", pure);
+               glue_startStopInputRec(false);
+       }
+       else if (pure == conf::midiInMetronome) {
+               gu_log("  >>> metronome (master) (pure=0x%X)\n", pure);
+               glue_startStopMetronome(false);
+       }
+       else if (pure == conf::midiInVolumeIn) {
+               float vf = midiEvent.getVelocity() / 127.0f;
+               gu_log("  >>> input volume (master) (pure=0x%X, value=%d, float=%f)\n",
+                       pure, midiEvent.getVelocity(), vf);
+               glue_setInVol(vf, false);
+       }
+       else if (pure == conf::midiInVolumeOut) {
+               float vf = midiEvent.getVelocity() / 127.0f;
+               gu_log("  >>> output volume (master) (pure=0x%X, value=%d, float=%f)\n",
+                       pure, midiEvent.getVelocity(), vf);
+               glue_setOutVol(vf, false);
+       }
+       else if (pure == conf::midiInBeatDouble) {
+               gu_log("  >>> sequencer x2 (master) (pure=0x%X)\n", pure);
+               glue_beatsMultiply();
+       }
+       else if (pure == conf::midiInBeatHalf) {
+               gu_log("  >>> sequencer /2 (master) (pure=0x%X)\n", pure);
+               glue_beatsDivide();
+       }
+}
+
+} // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
+void startMidiLearn(cb_midiLearn* cb, void* data)
+{
+       cb_learn = cb;
+       cb_data  = data;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void stopMidiLearn()
+{
+       cb_learn = nullptr;
+       cb_data  = nullptr;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void dispatch(int byte1, int byte2, int byte3)
+{
+       /* Here we want to catch two things: a) note on/note off from a keyboard and 
+       b) knob/wheel/slider movements from a controller. */
+
+       MidiEvent midiEvent(byte1, byte2, byte3);
+
+       gu_log("[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: if 'noNoteOff' 
+       in global config, get the raw value with the 'velocy' byte. Otherwise strip it 
+       off. If midi learn is off process master events first, then each channel 
+       in the stack. This way incoming signals don't get processed by glue_* when 
+       MIDI learning is on. */
+
+       if (cb_learn)
+               cb_learn(midiEvent.getRaw(conf::noNoteOff), cb_data);
+       else {
+               processMaster(midiEvent);
+               processChannels(midiEvent);
+       }       
+}
+}}}; // giada::m::midiDispatcher::
+
diff --git a/src/core/midiDispatcher.h b/src/core/midiDispatcher.h
new file mode 100644 (file)
index 0000000..395622e
--- /dev/null
@@ -0,0 +1,53 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 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_MIDI_DISPATCHER_H
+#define G_MIDI_DISPATCHER_H
+
+
+#ifdef __APPLE__  // our Clang still doesn't know about cstdint (c++11 stuff)
+       #include <stdint.h>
+#else
+       #include <cstdint>
+#endif
+
+
+namespace giada {
+namespace m {
+namespace midiDispatcher
+{
+typedef void (cb_midiLearn) (uint32_t, void*);
+
+void startMidiLearn(cb_midiLearn* cb, void* data);
+void stopMidiLearn();
+
+void dispatch(int byte1, int byte2, int byte3);
+
+}}}; // giada::m::midiDispatcher::
+
+
+#endif
diff --git a/src/core/midiEvent.cpp b/src/core/midiEvent.cpp
new file mode 100644 (file)
index 0000000..ae11319
--- /dev/null
@@ -0,0 +1,132 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 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 "midiEvent.h"
+
+
+namespace giada {
+namespace m
+{
+MidiEvent::MidiEvent()
+       : m_raw     (0x0),
+         m_status  (0),
+         m_channel (0),
+         m_note    (0),
+         m_velocity(0),
+         m_delta   (0)
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+MidiEvent::MidiEvent(uint32_t raw)
+       : m_raw     (raw),
+         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
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+MidiEvent::MidiEvent(int byte1, int byte2, int byte3)
+       : MidiEvent((byte1 << 24) | (byte2 << 16) | (byte3 << 8) | (0x00))
+{
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiEvent::resetDelta()
+{
+       m_delta = 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void MidiEvent::setChannel(int c)
+{
+       m_channel = c;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+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;
+}      
+
+
+bool MidiEvent::isNoteOnOff() const
+{
+       return m_status == NOTE_ON || m_status == NOTE_OFF;
+}
+
+
+int MidiEvent::getDelta() const
+{
+       return m_delta;
+}
+
+
+uint32_t MidiEvent::getRaw(bool velocity) const
+{
+       if (!velocity)
+               return m_raw & 0xFFFF0000;
+       return m_raw;
+}
+
+
+}} // giada::m::
\ No newline at end of file
diff --git a/src/core/midiEvent.h b/src/core/midiEvent.h
new file mode 100644 (file)
index 0000000..fb31369
--- /dev/null
@@ -0,0 +1,78 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 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_MIDI_EVENT_H
+#define G_MIDI_EVENT_H
+
+
+#include <cstdint>
+
+
+namespace giada {
+namespace m
+{
+class MidiEvent
+{
+public:
+
+       static const int NOTE_ON = 0x90;
+       static const int NOTE_OFF = 0x80;
+
+       MidiEvent();
+       MidiEvent(uint32_t raw);
+       MidiEvent(int byte1, int byte2, int byte3);
+
+       int getStatus() const;  
+       int getChannel() const; 
+       int getNote() const;    
+       int getVelocity() const;        
+       bool isNoteOnOff() const;       
+       int getDelta() const;
+
+       /* getRaw
+       Returns the raw message. If 'velocity' is false, velocity byte is stripped
+       out. */
+
+       uint32_t getRaw(bool velocity=true) const;
+
+       void resetDelta();
+       void setChannel(int c);
+
+private:
+
+       uint32_t m_raw;
+       int m_status;
+       int m_channel;
+       int m_note;
+       int m_velocity;
+       int m_delta;
+};
+
+}} // giada::m::
+
+
+#endif
\ No newline at end of file
index 5d28774c65c3f5830873cee2fe03fbd9ef0df246..9c130088f07d010e6f6febc87316be85f6a990fb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -57,7 +57,7 @@ bool readInitCommands(json_t *jContainer)
        json_t *jInitCommand;
        json_array_foreach(jInitCommands, commandIndex, jInitCommand) {
 
-               string indexStr = "init command " + gu_toString(commandIndex);
+               string indexStr = "init command " + gu_iToString(commandIndex);
                if (!storager::checkObject(jInitCommand, indexStr.c_str()))
                        return 0;
 
index 7080705e7c9f32a47a664ebfc9647b979795ad92..0e73e7ded38be9ad24ddcc9ff7483cc40c402e40 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 350769a758e3a8b575c543ea14299f27f2deb337..f5ac5c8ae9d2f965d8a088677135b901452af047 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -137,8 +137,8 @@ void clearAllBuffers(float* outBuf, unsigned bufferSize)
        memset(vChanInToOut, 0, sizeof(float) * bufferSize);   // inToOut vChan
 
        pthread_mutex_lock(&mutex_chans);
-       for (unsigned i=0; i<channels.size(); i++)
-               channels.at(i)->clear();
+       for (Channel* channel : channels)
+               channel->clear();
        pthread_mutex_unlock(&mutex_chans);
 }
 
@@ -497,12 +497,12 @@ int close()
        while (channels.size() > 0)
                mh::deleteChannel(channels.at(0));
 
-       if (vChanInput) {
-               free(vChanInput);
+       if (vChanInput != nullptr) {
+               delete[] vChanInput;
                vChanInput = nullptr;
        }
-       if (vChanInToOut) {
-               free(vChanInToOut);
+       if (vChanInToOut != nullptr) {
+               delete[] vChanInToOut;
                vChanInToOut = nullptr;
        }
        return 1;
@@ -528,8 +528,8 @@ void rewind()
 {
        clock::rewind();
        if (clock::isRunning())
-               for (unsigned i=0; i<channels.size(); i++)
-                       channels.at(i)->rewind();
+               for (Channel* ch : channels)
+                       ch->rewind();
 }
 
 
@@ -538,12 +538,14 @@ void rewind()
 
 void mergeVirtualInput()
 {
-       for (unsigned i=0; i<channels.size(); i++) {
-               if (channels.at(i)->type == CHANNEL_MIDI)
+       assert(vChanInput != nullptr);
+
+       for (Channel* ch : channels) {
+               if (ch->type == CHANNEL_MIDI)
                        continue;
-               SampleChannel *ch = static_cast<SampleChannel*>(channels.at(i));
-               if (ch->isArmed())
-                       memcpy(ch->wave->getData(), vChanInput, clock::getTotalFrames() * sizeof(float));
+               SampleChannel* sch = static_cast<SampleChannel*>(ch);
+               if (sch->isArmed())
+                       memcpy(sch->wave->getData(), vChanInput, clock::getTotalFrames() * sizeof(float));
        }
        memset(vChanInput, 0, clock::getTotalFrames() * sizeof(float)); // clear vchan
 }
index e1709dc364caba50f3fe47dd7b95d3279eb80aa0..87aef5ea56f29244e6b840c5a948bda9a9acb353 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -52,24 +52,24 @@ void allocVirtualInput(int frames);
 int close();
 
 /* masterPlay
- * core method (callback) */
+Core method (callback) */
 
 int masterPlay(void *outBuf, void *inBuf, unsigned bufferSize, double streamTime,
   RtAudioStreamStatus status, void *userData);
 
 /* isSilent
- * is mixer silent? */
+Is mixer silent? */
 
 bool isSilent();
 
 /* rewind
- * rewind sequencer to sample 0. */
+Rewinds sequencer to frame 0. */
 
 void rewind();
 
 /* mergeVirtualInput
- * memcpy the virtual channel input in the channel designed for input
- * recording. Called by mixerHandler on stopInputRec() */
+Copies the virtual channel input in the channels designed for input recording. 
+Called by mixerHandler on stopInputRec(). */
 
 void mergeVirtualInput();
 
index 40220a733f8541f609ffc75eadba25cdd82c5467..119f95ee28b3a2c0ec53318d8f5089f062276564 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -274,6 +274,7 @@ void readPatch()
        clock::setBars(patch::bars);
        clock::setBeats(patch::beats);
        clock::setQuantize(patch::quantize);
+       clock::updateFrameBars();
        mixer::metronome = patch::metronome;
 
 #ifdef WITH_VST
@@ -283,10 +284,12 @@ void readPatch()
 
 #endif
 
-       /* rewind and update frames in Mixer (it's essential) */
+       /* Rewind and update frames in Mixer. Also alloc new space in the virtual
+       input buffer, in case the patch has a sequencer size != default one (which is
+       very likely). */
 
        mixer::rewind();
-       clock::updateFrameBars();
+       mixer::allocVirtualInput(clock::getTotalFrames());
        mixer::ready = true;
 }
 
@@ -321,7 +324,7 @@ bool startInputRec()
 
                Wave* wave = nullptr;
                int result = waveManager::createEmpty(clock::getTotalFrames(), 
-                       conf::samplerate, string("TAKE-" + gu_toString(patch::lastTakeId)), &wave); 
+                       conf::samplerate, string("TAKE-" + gu_iToString(patch::lastTakeId)), &wave); 
                if (result != G_RES_OK) {
                        gu_log("[startInputRec] unable to allocate new Wave in chan %d!\n",
                                ch->index);
@@ -329,7 +332,7 @@ bool startInputRec()
                }
 
                ch->pushWave(wave);
-               ch->setName("TAKE-" + gu_toString(patch::lastTakeId++)); // Increase lastTakeId 
+               ch->setName("TAKE-" + gu_iToString(patch::lastTakeId++)); // Increase lastTakeId 
                channelsReady++;
 
                gu_log("[startInputRec] start input recs using chan %d with size %d "
index 18b02831a6a7c758fadb73844c3f5325ce760aa0..c1cd2baec91a5154d644851c9b846f02ce337b1d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b70ea9e3877b99850f213373b57e1bcac2786bd4..d954ffb641b67b2f01d3e008dfcbc84a024e8e9a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -199,7 +199,7 @@ bool readChannels(json_t* jContainer)
   json_t* jChannel;
   json_array_foreach(jChannels, channelIndex, jChannel) {
 
-    string channelIndexStr = "channel " + gu_toString(channelIndex);
+    string channelIndexStr = "channel " + gu_iToString(channelIndex);
     if (!storager::checkObject(jChannel, channelIndexStr.c_str()))
       return 0;
 
@@ -223,6 +223,7 @@ bool readChannels(json_t* jContainer)
     if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       channel.midiInVolume)) return 0;
     if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         channel.midiInMute)) return 0;
     if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         channel.midiInSolo)) return 0;
+    if (!storager::setInt   (jChannel, PATCH_KEY_CHANNEL_MIDI_IN_FILTER,       channel.midiInFilter)) return 0;
     if (!storager::setBool  (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L,           channel.midiOutL)) return 0;
     if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING,   channel.midiOutLplaying)) return 0;
     if (!storager::setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE,      channel.midiOutLmute)) return 0;
@@ -266,7 +267,7 @@ bool readColumns(json_t* jContainer)
   json_t* jColumn;
   json_array_foreach(jColumns, columnIndex, jColumn) {
 
-    string columnIndexStr = "column " + gu_toString(columnIndex);
+    string columnIndexStr = "column " + gu_iToString(columnIndex);
     if (!storager::checkObject(jColumn, columnIndexStr.c_str()))
       return 0;
 
@@ -399,6 +400,7 @@ void writeChannels(json_t* jContainer, vector<channel_t>* channels)
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_ARM,          json_integer(channel.midiInArm));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME,       json_integer(channel.midiInVolume));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE,         json_integer(channel.midiInMute));
+    json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_FILTER,       json_integer(channel.midiInFilter));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO,         json_integer(channel.midiInSolo));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L,           json_boolean(channel.midiOutL));
     json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING,   json_integer(channel.midiOutLplaying));
index bfc757eded016d0e7d67ef88abaf66e941fa652b..28b11d0533da736bfdc0f70cbd5af6c5364838ed 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -80,6 +80,7 @@ struct channel_t
        uint32_t    midiInVolume;
        uint32_t    midiInMute;
        uint32_t    midiInSolo;
+       int         midiInFilter;
        bool        midiOutL;
        uint32_t    midiOutLplaying;
        uint32_t    midiOutLmute;
index ce2b58e9936b37a236c525fb4a99fdb19fac37ea..d6b32fa1a4a3fd8bd995ba36a18426ea41420187 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -60,7 +60,8 @@ Plugin::Plugin(juce::AudioPluginInstance *plugin, double samplerate,
        
        plugin->prepareToPlay(samplerate, buffersize);
 
-       gu_log("[Plugin] plugin initialized and ready\n");
+       gu_log("[Plugin] plugin initialized and ready. MIDI input params: %lu\n",
+               midiInParams.size());
 }
 
 
index 8091d8ea11ab4a42ac66afb42b3ca2a26d215c2c..988c20a718f01798fcc7adcce35669025b35bb5c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 6ca000676b13ef9c869c74933c9a50c0b7ae3e32..f7faccb74188712e6b116b983d83405c36b1f1b0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -166,26 +166,28 @@ void init(int _buffersize, int _samplerate)
 /* -------------------------------------------------------------------------- */
 
 
-int scanDir(const string& dirpath, void (*callback)(float progress, void* p),
-               void* p)
+int scanDirs(const string& dirs, const std::function<void(float)>& cb)
 {
-       gu_log("[pluginHost::scanDir] requested directory: '%s'\n", dirpath.c_str());
+       gu_log("[pluginHost::scanDir] requested directories: '%s'\n", dirs.c_str());
        gu_log("[pluginHost::scanDir] current plugins: %d\n", knownPluginList.getNumTypes());
 
        knownPluginList.clear();   // clear up previous plugins
 
+       vector<string> dirVec;
+       gu_split(dirs, ";", &dirVec);
+
        juce::VSTPluginFormat format;
-       juce::FileSearchPath path(dirpath);
-       juce::PluginDirectoryScanner scanner(knownPluginList, format, path,
-                       true, juce::File::nonexistent); // true: recursive
+       juce::FileSearchPath searchPath;
+       for (const string& dir : dirVec)
+               searchPath.add(juce::File(dir));
+
+       juce::PluginDirectoryScanner scanner(knownPluginList, format, searchPath, 
+               true, juce::File::nonexistent); // true: recursive
 
-       bool cont = true;
        juce::String name;
-       while (cont) {
+       while (scanner.scanNextFile(false, name)) {
                gu_log("[pluginHost::scanDir]   scanning '%s'\n", name.toRawUTF8());
-               cont = scanner.scanNextFile(false, name);
-               if (callback)
-                       callback(scanner.getProgress(), p);
+               cb(scanner.getProgress());
        }
 
        gu_log("[pluginHost::scanDir] %d plugin(s) found\n", knownPluginList.getNumTypes());
index f36bf41715e2ca518f74783c88ed2f8ddcd6435b..a98cb02f02842be72c850392dc415e4dd93d1cfe 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -31,6 +31,7 @@
 #define G_PLUGIN_HOST_H
 
 
+#include <functional>
 #include <pthread.h>
 #include "../deps/juce-config.h"
 
@@ -52,32 +53,31 @@ enum stackType
 
 enum sortMethod
 {
-  NAME,
-  CATEGORY,
-  MANUFACTURER,
-  FORMAT
+       NAME,
+       CATEGORY,
+       MANUFACTURER,
+       FORMAT
 };
 
 struct PluginInfo
 {
-  std::string uid;
-  std::string name;
-  std::string category;
-  std::string manufacturerName;
-  std::string format;
-  bool isInstrument;
+       std::string uid;
+       std::string name;
+       std::string category;
+       std::string manufacturerName;
+       std::string format;
+       bool isInstrument;
 };
 
 void init(int bufSize, int frequency);
 void close();
 
-/* scanDir
- * Parse plugin directory and store list in knownPluginList. The callback is
- * called on each plugin found. Used to update the main window from the GUI
- * thread. */
+/* scanDirs
+Parses plugin directories (semicolon-separated) and store list in 
+knownPluginList. The callback is called on each plugin found. Used to update the 
+main window from the GUI thread. */
 
-int scanDir(const std::string& path, void (*callback)(float progress, void* p)=nullptr,
-    void* p=nullptr);
+int scanDirs(const std::string& paths, const std::function<void(float)>& cb);
 
 /* (save|load)List
  * (Save|Load) knownPluginList (in|from) an XML file. */
@@ -96,9 +96,9 @@ int loadList(const std::string& path);
  * ch - if stackType == CHANNEL. */
 
 Plugin* addPlugin(const std::string& fid, int stackType, pthread_mutex_t* mutex,
-  Channel* ch=nullptr);
+       Channel* ch=nullptr);
 Plugin *addPlugin(int index, int stackType, pthread_mutex_t* mutex,
-  Channel* ch=nullptr);
+       Channel* ch=nullptr);
 
 /* countPlugins
  * Return size of 'stackType'. */
@@ -150,13 +150,13 @@ int getPluginIndex(int id, int stackType, Channel* ch=nullptr);
 /* swapPlugin */
 
 void swapPlugin(unsigned indexA, unsigned indexB, int stackType,
-  pthread_mutex_t* mutex, Channel* ch=nullptr);
+       pthread_mutex_t* mutex, Channel* ch=nullptr);
 
 /* freePlugin.
 Returns the internal stack index of the deleted plugin. */
 
 int freePlugin(int id, int stackType, pthread_mutex_t *mutex,
-  Channel* ch=nullptr);
+       Channel* ch=nullptr);
 
 /* runDispatchLoop
  * Wakes up plugins' GUI manager for N milliseconds. */
index c760ae143332360524c7a96f365ffd5a223241f1..ff319ad5d649561e9f176981d04610aa6007e2f0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -42,15 +42,11 @@ namespace recorder
 {
 namespace
 {
-/* composite
-A group of two actions (keypress+keyrel, muteon+muteoff) used during the overdub
+/* Composite
+A group of two actions (keypress+keyrel, muteon+muteoff) used during the overdub 
 process. */
 
-struct composite
-{
-       action a1;
-       action a2;
-} cmp;
+Composite cmp;
 
 
 /* -------------------------------------------------------------------------- */
@@ -62,9 +58,9 @@ Fixes underlying action truncation when overdubbing over a longer action. I.e.:
   Overdub:     ---|#######|---
   fix:         |#||#######|--- */
 
-void fixOverdubTruncation(const composite &comp, pthread_mutex_t *mixerMutex)
+void fixOverdubTruncation(const Composite& comp, pthread_mutex_t* mixerMutex)
 {
-  action *next = nullptr;
+  actionnext = nullptr;
   int res = getNextAction(comp.a2.chan, comp.a1.type | comp.a2.type, comp.a2.frame,
     &next);
   if (res != 1 || next->type != comp.a2.type)
@@ -104,7 +100,7 @@ void init()
 /* -------------------------------------------------------------------------- */
 
 
-bool canRec(Channel *ch, bool clockRunning, bool mixerRecording)
+bool canRec(Channelch, bool clockRunning, bool mixerRecording)
 {
        /* NO recording if:
         * recorder is inactive
@@ -242,7 +238,7 @@ void clearAction(int index, char act)
 
 
 void deleteAction(int chan, int frame, char type, bool checkValues,
-       pthread_mutex_t *mixerMutex, uint32_t iValue, float fValue)
+       pthread_mutex_tmixerMutex, uint32_t iValue, float fValue)
 {
        /* make sure frame is even */
 
@@ -299,7 +295,7 @@ void deleteAction(int chan, int frame, char type, bool checkValues,
 
 
 void deleteActions(int chan, int frame_a, int frame_b, char type,
-  pthread_mutex_t *mixerMutex)
+  pthread_mutex_tmixerMutex)
 {
        sortActions();
        vector<int> dels;
@@ -530,29 +526,44 @@ bool hasActions(int chanIndex)
 /* -------------------------------------------------------------------------- */
 
 
-int getNextAction(int chan, char type, int frame, action **out,
-       uint32_t iValue)
+int getNextAction(int chan, char type, int fromFrame, action** out, 
+       uint32_t iValue, uint32_t mask)
 {
        sortActions();  // mandatory
 
-       unsigned i=0;
-       while (i < frames.size() && frames.at(i) <= frame) i++;
+       /* Increase 'i' until it reaches 'fromFrame'. That's the point where to start
+       to look for the next action. */
+
+       unsigned i = 0;
+       while (i < frames.size() && frames.at(i) <= fromFrame) i++;
+
+       /* No other actions past 'fromFrame': there are no more actions to look for.
+       Return -1. */
 
-       if (i == frames.size())   // no further actions past 'frame'
+       if (i == frames.size())
                return -1;
 
-       for (; i<global.size(); i++)
+       for (; i<global.size(); i++) {
+
                for (unsigned j=0; j<global.at(i).size(); j++) {
-                       action *a = global.at(i).at(j);
-                       if (a->chan == chan && (type & a->type) == a->type) {
-                               //if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) {
-                               if (iValue == 0 || (iValue != 0 && (iValue & a->iValue) == a->iValue )) {
-                                       *out = global.at(i).at(j);
-                                       return 1;
-                               }
+
+                       action* a = global.at(i).at(j);
+
+                       /* If the requested channel and type don't match, continue. */
+
+                       if (a->chan != chan || (type & a->type) != a->type) 
+                               continue;
+
+                       /* If no iValue has been specified (iValue == 0), then the next action has 
+                       been found, return it. Otherwise, make sure the iValue matches the 
+                       action's iValue, according to the mask provided. */
+
+                       if (iValue == 0 || (iValue != 0 && (a->iValue | mask) == (iValue | mask))) {
+                               *out = global.at(i).at(j);
+                               return 1;
                        }
                }
-
+       }
        return -2;   // no 'type' actions found
 }
 
@@ -560,7 +571,7 @@ int getNextAction(int chan, char type, int frame, action **out,
 /* -------------------------------------------------------------------------- */
 
 
-int getAction(int chan, char action, int frame, struct action **out)
+int getAction(int chan, char action, int frame, struct action** out)
 {
        for (unsigned i=0; i<global.size(); i++)
                for (unsigned j=0; j<global.at(i).size(); j++)
@@ -617,7 +628,7 @@ void startOverdub(int index, char actionMask, int frame, unsigned bufferSize)
 /* -------------------------------------------------------------------------- */
 
 
-void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t *mixerMutex)
+void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_tmixerMutex)
 {
        cmp.a2.frame  = currentFrame;
        bool ringLoop = false;
@@ -663,6 +674,4 @@ void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t *mixerMutex)
        rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame);
   fixOverdubTruncation(cmp, mixerMutex);
 }
-
-
 }}}; // giada::m::recorder::
index eecf52f9189fd18b35d6a4edebd10b65f77e2681..49a43a24c1c46ed03f988cbef443f8c03c084720 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -59,6 +59,15 @@ struct action
        uint32_t iValue;  // used only for MIDI events
 };
 
+/* Composite
+A group of two actions (keypress+keyrel, muteon+muteoff). */
+
+struct Composite
+{
+       action a1;
+       action a2;
+};
+
 /* frames
 Frame counter sentinel. It tells which frames contain actions. E.g.:
   frames[0] = 155   // some actions on frame 155
@@ -151,19 +160,22 @@ void expand(int old_fpb, int new_fpb);
 void shrink(int new_fpb);
 
 /* getNextAction
- * Return the nearest action in chan 'chan' of type 'action' starting
- * from 'frame'. Action can be a bitmask. If iValue != 0 search for
- * next action with iValue == iValue: useful for MIDI key_release. iValue
- * can be a bitmask. */
+Returns the nearest action in chan 'chan' of type 'action' starting from 
+'frame'. Action can be a bitmask. If iValue != 0 search for next action with 
+iValue == iValue with 'mask' to ignore bytes. Useful for MIDI key_release. 
+Mask example:
+
+       iValue = 0x803D3F00
+       mask   = 0x0000FF00  // ignore byte 3
+       action = 0x803D3200  // <--- this action will be found */
 
-int getNextAction(int chan, char action, int frame, struct action **out,
-       uint32_t iValue=0);
+int getNextAction(int chan, char action, int frame, struct action** out,
+       uint32_t iValue=0, uint32_t mask=0);
 
 /* getAction
- * return a pointer to action in chan 'chan' of type 'action' at frame
- * 'frame'. */
+Returns a pointer to action in chan 'chan' of type 'action' at frame 'frame'. */
 
-int getAction(int chan, char action, int frame, struct action **out);
+int getAction(int chan, char action, int frame, struct action** out);
 
 /* start/stopOverdub
 These functions are used when you overwrite existing actions. For example:
@@ -171,7 +183,6 @@ pressing Mute button on a channel with some existing mute actions. */
 
 void startOverdub(int chan, char action, int frame, unsigned bufferSize);
 void stopOverdub(int currentFrame, int totalFrames, pthread_mutex_t *mixerMutex);
-
 }}}; // giada::m::recorder::
 
 #endif
index 38dad90975272a3850cb37340e113165d3a4e9bb..b875eebd817d15ae9ee95fcdd98cb0d340bef637 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 783c9aea1c1bbb243b565445e5a5fecae7ac23bb..54162b05c5026e4eb87b47535ec3665c25bc9414 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 6c72e6b91dd8522557cd33b6a5f6d0256de6cff4..bf08fdd4314cd48e9176f5d94e1efed23b040856 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 395c0a5d879e83db77cbd3c835c441aca7fd3e58..58a17566cbd005b1e3aaeb87022d70409f8153af 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index f1a6c42e0ff398a51078f2d941fc9080668744aa..849932406c1dad73c0ec7b0e681b49d7228fa479 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -183,7 +183,7 @@ void Wave::setPath(const string& p, int id)
        if (id == -1)
                m_path = p; 
        else 
-               m_path = gu_stripExt(p) + "-" + gu_toString(id) + "." + gu_getExt(p);
+               m_path = gu_stripExt(p) + "-" + gu_iToString(id) + "." + gu_getExt(p);
 
 
 }
index 19f7ea83e7264d0d19b931e688bb8c4ce05ffa94..300a43d1529d879eea9505a73d6f85691cb2b4e6 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 7f278adbd38c66f39157ff451725736d12aaad93..e50fe70d23c32216a1a7feda682030d5675bdf57 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 918795c25a8adcbdf76feb7c8262735abdc13a99..b0ac02ca664200d9014587f2a51f004ee3400f3e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index becf115927ce25e2306733fbd331af29e17ae8ea..2b3b3941e6e697ba66555e8aa1ea1d3912772021 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2772b5916001cebc82d009b15a0523874af8da49..50da3726d5fa7528ef1c09ffd0838741b7b7dffb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index edebcf5ddfbb91458103c9adc116fe123928f7c5..a2b0e6e3da570653689eaea09cbfe87377203628 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e3b9468588bec0a6850ccc4b942c143c8746d3fc..6eac90d51cd73007a1bb159f240d01aae981c642 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 0171457d6d2a4f75d29be2622b348a669dfe05da..2f51a4ea5f2ee5876ba2ecee1230c4193ad2e68f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -316,12 +316,12 @@ int glue_stopInputRec(bool gui)
   they must start playing right away at the current frame, not at the next first
   beat. */
 
-       for (unsigned i=0; i<mixer::channels.size(); i++) {
-               if (mixer::channels.at(i)->type == CHANNEL_MIDI)
+       for (Channel* ch : mixer::channels) {
+               if (ch->type == CHANNEL_MIDI)
                        continue;
-               SampleChannel *ch = (SampleChannel*) mixer::channels.at(i);
-               if (ch->mode & (LOOP_ANY) && ch->status == STATUS_OFF && ch->isArmed())
-                       ch->start(clock::getCurrentFrame(), true, clock::getQuantize(),
+               SampleChannel* sch = static_cast<SampleChannel*>(ch);
+               if (sch->mode & (LOOP_ANY) && sch->status == STATUS_OFF && sch->isArmed())
+                       sch->start(clock::getCurrentFrame(), true, clock::getQuantize(),
         clock::isRunning(), true, true);
        }
 
index 110d5f239dcdf9a0319d2468f86dbcda702fbace..3377be979783480afa679c4af0967feb6ed901b2 100644 (file)
@@ -11,7 +11,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 206726100d6310336ba92e695aa966672bc11359..6de32a7baefe6a43d5e5db18068d95968a9802ec 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -101,7 +101,7 @@ void glue_setBpm(float v)
        double fPpart = modf(v, &fIpart);
        int iIpart = fIpart;
        int iPpart = ceilf(fPpart);
-       glue_setBpm(gu_toString(iIpart).c_str(), gu_toString(iPpart).c_str());
+       glue_setBpm(gu_iToString(iIpart).c_str(), gu_iToString(iPpart).c_str());
 }
 
 
index 8357e28e38d3d9183785dff060da88f2869d742e..3644f9383550b0dbb62b61a75313a2eb0bdf4739 100644 (file)
@@ -11,7 +11,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c7928d614cfd824edf574d2298e6618cf6e7821f..20a0f8bad9d591d70f77fb0937e3784fa7bee444 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #include "../core/plugin.h"
 #include "../core/channel.h"
 #include "../core/const.h"
+#include "../core/conf.h"
 #include "../utils/gui.h"
 #include "../gui/dialogs/gd_mainWindow.h"
 #include "../gui/dialogs/pluginWindow.h"
 #include "../gui/dialogs/pluginList.h"
+#include "../gui/dialogs/gd_warnings.h"
+#include "../gui/dialogs/gd_config.h"
+#include "../gui/dialogs/browser/browserDir.h"
 #include "plugin.h"
 
 
@@ -50,6 +54,30 @@ namespace giada {
 namespace c     {
 namespace plugin 
 {
+namespace
+{
+/* getPluginWindow
+Returns the plugInWindow (GUI-less one) with the parameter list. It might be 
+nullptr if there is no plug-in window shown on screen. */
+
+gdPluginWindow* getPluginWindow(const Plugin* p)
+{
+       /* Get the parent window first: the plug-in list. Then, if it exists, get
+       the child window - the actual pluginWindow. */
+
+       gdPluginList* parent = static_cast<gdPluginList*>(gu_getSubwindow(G_MainWin, WID_FX_LIST));
+       if (parent == nullptr)
+               return nullptr;
+       return static_cast<gdPluginWindow*>(gu_getSubwindow(parent, p->getId() + 1));
+}
+} // {anonymous}
+
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
+
 Plugin* addPlugin(Channel* ch, int index, int stackType)
 {
   if (index >= pluginHost::countAvailablePlugins())
@@ -80,6 +108,28 @@ void freePlugin(Channel* ch, int index, int stackType)
 /* -------------------------------------------------------------------------- */
 
 
+void setProgram(Plugin* p, int index)
+{
+       p->setCurrentProgram(index);
+
+       /* No need to update plug-in editor if it has one: the plug-in's editor takes
+       care of it on its own. Conversely, update the specific parameter for UI-less 
+       plug-ins. */
+
+       if (p->hasEditor())
+               return;
+
+       gdPluginWindow* child = getPluginWindow(p);
+       if (child == nullptr) 
+               return;
+       
+       child->updateParameters(true);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void setParameter(Plugin* p, int index, float value, bool gui)
 {
        p->setParameter(index, value);
@@ -91,13 +141,36 @@ void setParameter(Plugin* p, int index, float value, bool gui)
        if (p->hasEditor())
                return;
 
-       gdPluginList* parent = static_cast<gdPluginList*>(gu_getSubwindow(G_MainWin, WID_FX_LIST));
-       gdPluginWindow* child = static_cast<gdPluginWindow*>(gu_getSubwindow(parent, p->getId() + 1));
-       if (child != nullptr) {
-               Fl::lock();
-               child->updateParameter(index, !gui);
-               Fl::unlock();
+       gdPluginWindow* child = getPluginWindow(p);
+       if (child == nullptr) 
+               return;
+
+       Fl::lock();
+       child->updateParameter(index, !gui);
+       Fl::unlock();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void setPluginPathCb(void* data)
+{
+       gdBrowserDir* browser = (gdBrowserDir*) data;
+
+       if (browser->getCurrentPath() == "") {
+               gdAlert("Invalid path.");
+               return;
        }
+
+       if (!conf::pluginPath.empty() && conf::pluginPath.back() != ';')
+               conf::pluginPath += ";";
+       conf::pluginPath += browser->getCurrentPath();
+
+       browser->do_callback();
+
+       gdConfig* configWin = static_cast<gdConfig*>(gu_getSubwindow(G_MainWin, WID_CONFIG));
+       configWin->refreshVstPath();
 }
 
 }}}; // giada::c::plugin::
index 72041ff039d61f666b8d2576fbed4d05453f7502..d581fe2cc5604b7889db5fffb1e0a22e80699212 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -47,6 +47,13 @@ Plugin* addPlugin(Channel* ch, int index, int stackType);
 void swapPlugins(Channel* ch, int indexP1, int indexP2, int stackType);
 void freePlugin(Channel* ch, int index, int stackType);
 void setParameter(Plugin* p, int index, float value, bool gui=true); 
+void setProgram(Plugin* p, int index);
+
+/* setPluginPathCb
+Callback attached to the DirBrowser for adding new Plug-in search paths in the
+configuration window. */
+
+void setPluginPathCb(void* data);
 }}}; // giada::c::plugin::
 
 
index 2bab39cfb5591c5a903c27e58609f488118e6f1d..9e0a33323cfd882a4932af4b13f9b8f9e79da14d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #include "../gui/elems/mainWindow/keyboard/channel.h"
 #include "../gui/elems/mainWindow/keyboard/sampleChannel.h"
 #include "../core/const.h"
+#include "../core/clock.h"
+#include "../core/kernelMidi.h"
 #include "../core/channel.h"
 #include "../core/recorder.h"
 #include "../utils/gui.h"
+#include "../utils/log.h"
 #include "recorder.h"
 
 
-using namespace giada::m;
+using std::vector;
+using namespace giada;
 
 
+namespace giada {
+namespace c     {
+namespace recorder 
+{
 namespace
 {
-void updateChannel(geChannel *gch)
+void updateChannel(geChannelgch)
 {
-  gch->ch->hasActions = recorder::hasActions(gch->ch->index);
-  if (gch->ch->type == CHANNEL_SAMPLE && !gch->ch->hasActions)
-    static_cast<geSampleChannel*>(gch)->hideActionButton();
-  /* TODO - set mute=false */
-  gu_refreshActionEditor(); // refresh a.editor window, it could be open
+       gch->ch->hasActions = m::recorder::hasActions(gch->ch->index);
+       if (gch->ch->type == CHANNEL_SAMPLE && !gch->ch->hasActions)
+               static_cast<geSampleChannel*>(gch)->hideActionButton();
+       /* TODO - set mute=false */
+       gu_refreshActionEditor(); // refresh a.editor window, it could be open
 }
 }; // {namespace}
 
@@ -54,46 +62,149 @@ void updateChannel(geChannel *gch)
 /* -------------------------------------------------------------------------- */
 
 
-void glue_clearAllActions(geChannel *gch)
+void clearAllActions(geChannel* gch)
 {
-  if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
-    return;
-  recorder::clearChan(gch->ch->index);
-  updateChannel(gch);
+       if (!gdConfirmWin("Warning", "Clear all actions: are you sure?"))
+               return;
+       m::recorder::clearChan(gch->ch->index);
+       updateChannel(gch);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void glue_clearVolumeActions(geChannel *gch)
+void clearVolumeActions(geChannel* gch)
 {
-  if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
-    return;
-  recorder::clearAction(gch->ch->index, G_ACTION_VOLUME);
-  updateChannel(gch);
+       if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?"))
+               return;
+       m::recorder::clearAction(gch->ch->index, G_ACTION_VOLUME);
+       updateChannel(gch);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void glue_clearStartStopActions(geChannel *gch)
+void clearStartStopActions(geChannel* gch)
 {
-  if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
-    return;
-  recorder::clearAction(gch->ch->index, G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL);
-  updateChannel(gch);
+       if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?"))
+               return;
+       m::recorder::clearAction(gch->ch->index, G_ACTION_KEYPRESS | G_ACTION_KEYREL | G_ACTION_KILL);
+       updateChannel(gch);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void glue_clearMuteActions(geChannel *gch)
+void clearMuteActions(geChannel* gch)
 {
-  if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
-    return;
-  recorder::clearAction(gch->ch->index, G_ACTION_MUTEON | G_ACTION_MUTEOFF);
-  updateChannel(gch);
+       if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?"))
+               return;
+       m::recorder::clearAction(gch->ch->index, G_ACTION_MUTEON | G_ACTION_MUTEOFF);
+       updateChannel(gch);
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void recordMidiAction(int chan, int note, int frame_a, int frame_b)
+{
+       if (frame_b == 0)
+               frame_b = frame_a + G_DEFAULT_MIDI_ACTION_SIZE;
+
+       /* Avoid frame overflow. */
+
+       int overflow = frame_b - m::clock::getTotalFrames();
+       if (overflow > 0) {
+               frame_b -= overflow;
+               frame_a -= overflow;
+       }
+
+       /* Prepare MIDI events, with maximum velocity (0x3F) for now. */
+
+       m::MidiEvent event_a = m::MidiEvent(m::MidiEvent::NOTE_ON,  note, 0x3F);
+       m::MidiEvent event_b = m::MidiEvent(m::MidiEvent::NOTE_OFF, note, 0x3F);
+
+       /* Avoid overlapping actions. Find the next action past frame_a and compare 
+       its frame: if smaller than frame_b, an overlap occurs. Shrink the new action
+       accordingly. */
+
+       m::recorder::action* next = nullptr;
+       m::recorder::getNextAction(chan, G_ACTION_MIDI, frame_a, &next, event_a.getRaw(), 
+               0x0000FF00);
+
+       if (next != nullptr && next->frame <= frame_b) {
+               frame_b = next->frame - 2;
+               gu_log("[recorder::recordMidiAction] Shrink new action, due to overlap\n");
+       }
+
+       m::recorder::rec(chan, G_ACTION_MIDI, frame_a, event_a.getRaw());
+       m::recorder::rec(chan, G_ACTION_MIDI, frame_b, event_b.getRaw());               
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+vector<m::recorder::Composite> getMidiActions(int chan, int frameLimit)
+{
+       vector<m::recorder::Composite> out;
+
+       m::recorder::sortActions();
+
+       for (unsigned i=0; i<m::recorder::frames.size(); i++) {
+
+               if (m::recorder::frames.at(i) > frameLimit)
+                       continue;
+
+               for (unsigned j=0; j<m::recorder::global.at(i).size(); j++) {
+
+                       m::recorder::action* a1 = m::recorder::global.at(i).at(j);
+                       m::recorder::action* a2 = nullptr;
+
+                       m::MidiEvent a1midi(a1->iValue);
+
+                       /* Skip action if:
+                               - does not belong to this channel
+                               - is not a MIDI action (we only want MIDI things here)
+                               - is not a MIDI Note On type. We don't want any other kind of action here */
+
+                       if (a1->chan != chan || a1->type != G_ACTION_MIDI || 
+                                 a1midi.getStatus() != m::MidiEvent::NOTE_ON)
+                               continue;
+
+                       /* Prepare the composite action. Action 1 exists for sure, so fill it up
+                       right away. */
+
+                       m::recorder::Composite cmp; 
+                       cmp.a1 = *a1;
+
+                       /* Search for the next action. Must have: same channel, G_ACTION_MIDI,
+                       greater than a1->frame and with MIDI properties of note_off (0x80), same
+                       note of a1 and random velocity: we don't care about it (and so we mask it
+                       with 0x0000FF00). */
+
+                       m::MidiEvent a2midi(m::MidiEvent::NOTE_OFF, a1midi.getNote(), 0x0);
+
+                       m::recorder::getNextAction(chan, G_ACTION_MIDI, a1->frame, &a2, 
+                               a2midi.getRaw(), 0x0000FF00);
+
+                       /* If action 2 has been found, add it to the composite duo. Otherwise
+                       set the action 2 frame to -1: it should be intended as "orphaned". */
+
+                       if (a2 != nullptr)
+                               cmp.a2 = *a2;
+                       else
+                               cmp.a2.frame = -1;
+
+                       out.push_back(cmp);
+               }
+       }
+
+       return out;
+}
+
+}}} // giada::c::recorder::
\ No newline at end of file
index 390f7fbec7e8240a7bc723bc37b22d0ea1ca4622..811e002e6f086c8ef76f17da7a9217e19ad1e899 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #define G_GLUE_RECORDER_H
 
 
+#include <vector>
+#include "../core/recorder.h"
+
+
 class geChannel;
 
 
-void glue_clearAllActions(geChannel *gch);
-void glue_clearMuteActions(geChannel *gch);
-void glue_clearVolumeActions(geChannel *gch);
-void glue_clearStartStopActions(geChannel *gch);
+namespace giada {
+namespace c     {
+namespace recorder 
+{
+void clearAllActions(geChannel *gch);
+void clearMuteActions(geChannel *gch);
+void clearVolumeActions(geChannel *gch);
+void clearStartStopActions(geChannel *gch);
+
+/* recordMidiAction
+Records a new MIDI action at frame_a. If frame_b == 0, uses the default action
+size. This function is designed for the Piano Roll (not for live recording). */
+
+void recordMidiAction(int chan, int note, int frame_a, int frame_b=0);
+
+/* getMidiActions
+Returns a list of Composite actions, ready to be displayed in a MIDI note
+editor as pairs of NoteOn+NoteOff. */
+
+std::vector<giada::m::recorder::Composite> getMidiActions(int channel, 
+       int frameLimit);
 
+}}} // giada::c::recorder::
 
 #endif
index f5b037e1017d49e529a58cfd89a8cee8c6868e1f..bd4e9f014b57c71352b6ff86a23add6694a3b8bb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e6d1221dba5ea45b2a92825a09cad607a87259e0..b38cbb2a6ae0a7318f5616cd545622516e9061ca 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -37,8 +37,6 @@ namespace giada {
 namespace c     {
 namespace sampleEditor 
 {
-
-
 /* setBeginEnd
 Sets start/end points in the sample editor. */
 
index c9db5eeeb08958c63e8be87af6e034e8fdd5b66e..726918e1d37d17723e575cfed3ab288da4d8b0b6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -171,7 +171,7 @@ static bool glue_savePatch__(const string &fullPath, const string &name,
 
 static string glue_makeSamplePath__(const string& base, const Wave* w, int k)
 {
-       return base + G_SLASH + w->getBasename(false) + "-" + gu_toString(k) + "." +  w->getExtension();
+       return base + G_SLASH + w->getBasename(false) + "-" + gu_iToString(k) + "." +  w->getExtension();
 } 
 
 
index 83f92911fe5bd579a63c8663fe5251010e481923..9a3e568b0d17587897ec00ef96ed5c0f22f3cf4e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c3bf56e9f0c20faf8bc9e495e5a33909a10f0f14..f735f7e071f280f5090a1b03d738388328932b9d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 24fff6f60c11a9886063c08f13b604dd7e480f20..3b10eadede49e6f2ea3d21b3bca44e8b36369c29 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 3d77b6fb76f0ac2461897c1ff30f4af8d05c5687..3f134bff7b215b6a1fb33597a46dde0f4765097d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -61,11 +61,11 @@ gdBeatsInput::gdBeatsInput()
        end();
 
        beats->maximum_size(2);
-       beats->value(gu_toString(clock::getBeats()).c_str());
+       beats->value(gu_iToString(clock::getBeats()).c_str());
        beats->type(FL_INT_INPUT);
        
        bars->maximum_size(2);
-       bars->value(gu_toString(clock::getBars()).c_str());
+       bars->value(gu_iToString(clock::getBars()).c_str());
        bars->type(FL_INT_INPUT);
        
        ok->shortcut(FL_Enter);
index b1d0bb8838495b9c9ea12aaaef0ca9d2a7a343d0..938bd71319ae995d4ec2d7f2860b7a17fd3462eb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index f76c629ddb5d957151834a0398df7e46bd4654fc..b5ea70f48433288c701a4b41ced4be038f43090a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -62,7 +62,7 @@ gdBpmInput::gdBpmInput(const char* label)
 
        input_a->maximum_size(3);
        input_a->type(FL_INT_INPUT);
-       input_a->value(gu_toString(clock::getBpm()).c_str());
+       input_a->value(gu_fToString(clock::getBpm(), 0).c_str());
 
        /* Use the decimal value from the string label. */
 
index 3a994ef4674f2341218f13942e92b826602219ef..492ae35d059649533ac2b30f975d1bd5988b1d30 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5903962866b5c39eb7810d5ce76a35906f1c444a..ed1f72b64e4d55f1fc26d0e6f874fbff7ab1289f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -187,16 +187,28 @@ void gdBrowserBase::hideStatusBar()
 /* -------------------------------------------------------------------------- */
 
 
-string gdBrowserBase::getCurrentPath()
-{
-  return where->value();
+string gdBrowserBase::getCurrentPath() const 
+{ 
+       return where->value(); 
 }
 
 
-/* -------------------------------------------------------------------------- */
+Channel* gdBrowserBase::getChannel() const 
+{ 
+       return channel; 
+}
 
 
-string gdBrowserBase::getSelectedItem()
+string gdBrowserBase::getSelectedItem() const 
 {
        return browser->getSelectedItem();
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowserBase::fireCallback() const
+{ 
+       callback((void*) this); 
+}
index 9ca486a735cbd0ff67bfc7f173c411006bdb3440..ccc2485ebf91c5a84967e0c2130177d655bb045f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -32,8 +32,8 @@
 #include "../window.h"
 
 
-class Channel;
 class Fl_Group;
+class Channel;
 class geCheck;
 class geBrowser;
 class geButton;
@@ -69,7 +69,7 @@ protected:
        void (*callback)(void*);
 
        gdBrowserBase(int x, int y, int w, int h, const std::string& title,
-                       const std::string& path, void (*callback)(void*));
+               const std::string& path, void (*callback)(void*));
 
 public:
 
@@ -78,8 +78,12 @@ public:
        /* getSelectedItem
         * Return the full path of the selected file. */
 
-       std::string getSelectedItem();
+       std::string getSelectedItem() const;
 
+       std::string getCurrentPath() const;
+       Channel* getChannel() const;
+       void fireCallback() const;
+       
        /* setStatusBar
         * Increment status bar for progress tracking. */
 
@@ -87,10 +91,7 @@ public:
 
        void showStatusBar();
        void hideStatusBar();
-       std::string getCurrentPath();
 
-       Channel* getChannel() { return channel; }
-       void fireCallback()   { callback((void*) this); }
 };
 
 
diff --git a/src/gui/dialogs/browser/browserDir.cpp b/src/gui/dialogs/browser/browserDir.cpp
new file mode 100644 (file)
index 0000000..daddec9
--- /dev/null
@@ -0,0 +1,85 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 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 "../../../utils/fs.h"
+#include "../../elems/browser.h"
+#include "../../elems/basics/button.h"
+#include "../../elems/basics/input.h"
+#include "browserDir.h"
+
+
+using std::string;
+
+
+gdBrowserDir::gdBrowserDir(int x, int y, int w, int h, const string& title,
+               const string& path, void (*callback)(void*))
+       :       gdBrowserBase(x, y, w, h, title, path, callback)
+{
+       where->size(groupTop->w()-updir->w()-8, 20);
+
+       browser->callback(cb_down, (void*) this);
+
+       ok->label("Select");
+       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()
+{
+       callback((void*) this);
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdBrowserDir::cb_down()
+{
+       string path = browser->getSelectedItem();
+
+       if (path.empty() || !gu_isDir(path)) // when click on an empty area or not a dir
+               return;
+
+       browser->loadDir(path);
+       where->value(browser->getCurrentDir().c_str());
+}
diff --git a/src/gui/dialogs/browser/browserDir.h b/src/gui/dialogs/browser/browserDir.h
new file mode 100644 (file)
index 0000000..0c97065
--- /dev/null
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------------
+ *
+ * Giada - Your Hardcore Loopmachine
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010-2018 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_BROWSER_DIR_H
+#define GD_BROWSER_DIR_H
+
+
+#include "browserBase.h"
+
+
+class Channel;
+
+
+class gdBrowserDir : public gdBrowserBase
+{
+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();
+
+public:
+
+       gdBrowserDir(int x, int y, int w, int h, const std::string& title,
+               const std::string& path, void (*callback)(void*));
+};
+
+
+#endif
index d8e9dd13a3d23cdc742c97718ca6356295204848..266c4f3065e30803c8fca71854584903dd3a113e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e361484a6b0eeb49d6a6f3860242f17a1a74b476..e132a34ca0a2068ab5c0b367cfa579d2b0eb64af 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #define GD_BROWSER_LOAD_H
 
 
-#include "../window.h"
 #include "browserBase.h"
 
 
 class Channel;
-class Fl_Group;
-class geCheck;
-class geBrowser;
-class geButton;
-class geInput;
-class geProgress;
 
 
 class gdBrowserLoad : public gdBrowserBase
index ad765b9912554386b3d1638827eb60ccf38ee58e..b1559a8922df3ab93f4c26bf37621dd7ddfcbd5d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -93,7 +93,7 @@ void gdBrowserSave::cb_down()
 /* -------------------------------------------------------------------------- */
 
 
-string gdBrowserSave::getName()
+string gdBrowserSave::getName() const
 {
   return name->value();
 }
index 53cb61b0e31a77087448cb32e25c681738e03465..acfa0d6f21eb4dad71a9f52992523630f0964327 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #define GD_BROWSER_SAVE_H
 
 
-#include "../window.h"
 #include "browserBase.h"
 
 
 class Channel;
-class Fl_Group;
-class geCheck;
-class geBrowser;
-class geButton;
 class geInput;
-class geProgress;
 
 
 class gdBrowserSave : public gdBrowserBase
@@ -59,7 +53,7 @@ public:
                        const std::string& path, const std::string& name, void (*callback)(void*),
                        Channel* ch);
 
-       std::string getName();
+       std::string getName() const;
 };
 
 
index a0bd3bce2dfde6aac923d736b1ead102f8ec9e06..dca6fcaff70f18a140bb0f10971bdb286563ad5a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 86f03d5eebdd0975859d7cfe567609c66d287f92..7e4a11365288c3829f01faab25a95ef2aebefb35 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 527e32c6e8f6c242e9b72c0d9846afcaaecd4e2a..eb9228ef0e850bf4236fec30e85c3d5ff37258f2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
   #include "../../deps/juce-config.h"
 #endif
 #include "../../utils/gui.h"
+#include "../../utils/string.h"
 #include "../../utils/deps.h"
 #include "../elems/basics/button.h"
 #include "../elems/basics/box.h"
 #include "gd_about.h"
 
 
+using std::string;
 using namespace giada::m;
 using namespace giada::u;
 
@@ -69,9 +71,7 @@ gdAbout::gdAbout()
        logo->image(new Fl_Pixmap(giada_logo_xpm));
        text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP);
 
-       char message[512];
-       sprintf(
-         message,
+       string message = gu_format(
          "Version " G_VERSION_STR " (" BUILD_DATE ")\n\n"
                "Developed by Monocasual Laboratories\n"
                "Based on FLTK (%d.%d.%d), RtAudio (%s),\n"
@@ -97,8 +97,8 @@ gdAbout::gdAbout()
 
        int tw = 0;
        int th = 0;
-       fl_measure(message, tw, th);
-       text->copy_label(message);
+       fl_measure(message.c_str(), tw, th);
+       text->copy_label(message.c_str());
        text->size(text->w(), th);
 
 #ifdef WITH_VST
index eeb11d27f355fb193966471e8b0b11a07c99e920..aa930944b940de7751c3dd2ba990e3be5769d1a7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 723763ff605ad3193d8743f801a62a2ba52a07cc..becac71f1195941ac2ba5a6f19f583805d00ca2e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -27,6 +27,7 @@
 
 #include <cmath>
 #include "../../utils/gui.h"
+#include "../../utils/string.h"
 #include "../../core/graphics.h"
 #include "../../core/conf.h"
 #include "../../core/const.h"
@@ -45,6 +46,7 @@
 #include "gd_actionEditor.h"
 
 
+using std::string;
 using namespace giada::m;
 
 
@@ -137,9 +139,8 @@ gdActionEditor::gdActionEditor(Channel *chan)
 
        gu_setFavicon(this);
 
-       char buf[256];
-       sprintf(buf, "Edit Actions in Channel %d", chan->index+1);
-       label(buf);
+       string buf = "Edit Actions in Channel " + gu_iToString(chan->index+1);
+       label(buf.c_str());
 
        set_non_modal();
        size_range(640, 284);
index efe3e0e95f4616c9158c9842c96a84031263890d..f82a6f72afed081f5a90c2de5bc6bc6688114f46 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 6e26b91c9a4b4ac5ac49a89ec8437fba657a4d95..ce4ee299fca16c7ace50bf5a60c5a4832856caf9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -44,12 +44,10 @@ using namespace giada::m;
 
 gdConfig::gdConfig(int w, int h) : gdWindow(w, h, "Configuration")
 {
-       set_modal();
-
        if (conf::configX)
                resize(conf::configX, conf::configY, this->w(), this->h());
 
-       Fl_Tabs *tabs = new Fl_Tabs(8, 8, w-16, h-44);
+       Fl_Tabstabs = new Fl_Tabs(8, 8, w-16, h-44);
   tabs->box(G_CUSTOM_BORDER_BOX);
   tabs->labelcolor(G_COLOR_LIGHT_2);
   tabs->begin();
@@ -91,14 +89,14 @@ gdConfig::~gdConfig()
 /* -------------------------------------------------------------------------- */
 
 
-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_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_save_config()
+void gdConfig::cb_save_config()
 {
        tabAudio->save();
        tabBehaviors->save();
@@ -114,7 +112,19 @@ void gdConfig::__cb_save_config()
 /* -------------------------------------------------------------------------- */
 
 
-void gdConfig::__cb_cancel()
+void gdConfig::cb_cancel()
 {
        do_callback();
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef WITH_VST
+
+void gdConfig::refreshVstPath()
+{
+       tabPlugins->refreshVstPath();
+}
+
+#endif
\ No newline at end of file
index 5af49f6fe2c85bdadb0b15473d7efd60d3b7c59d..989f5603c140d35288932abcf9804a128cc1a898 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -51,25 +51,29 @@ class gdConfig : public gdWindow
 {
 private:
 
-       static void cb_save_config(Fl_Widget *w, void *p);
-       static void cb_cancel     (Fl_Widget *w, void *p);
-       inline void __cb_save_config();
-       inline void __cb_cancel();
+       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();
 
 public:
 
+       geTabAudio* tabAudio;
+       geTabBehaviors* tabBehaviors;
+       geTabMidi* tabMidi;
+       geTabMisc* tabMisc;
+#ifdef WITH_VST
+       geTabPlugins* tabPlugins;
+#endif
+       geButton* save;
+       geButton* cancel;
+
        gdConfig(int w, int h);
        ~gdConfig();
 
-       geTabAudio     *tabAudio;
-       geTabBehaviors *tabBehaviors;
-       geTabMidi      *tabMidi;
-       geTabMisc      *tabMisc;
 #ifdef WITH_VST
-       geTabPlugins   *tabPlugins;
+       void refreshVstPath();
 #endif
-       geButton            *save;
-       geButton            *cancel;
 };
 
 
index c7c074dcfdd376ce2fc6b618c4809a17f6ec843f..2521274fee50f0e7f239a33ca2209c6b69154150 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -52,21 +52,21 @@ gdDevInfo::gdDevInfo(unsigned dev)
        int    lines = 7;
 
        body  = "Device name: " + kernelAudio::getDeviceName(dev) + "\n";
-       body += "Total output(s): " + gu_toString(kernelAudio::getMaxOutChans(dev)) + "\n";
-       body += "Total intput(s): " + gu_toString(kernelAudio::getMaxInChans(dev)) + "\n";
-       body += "Duplex channel(s): " + gu_toString(kernelAudio::getDuplexChans(dev)) + "\n";
+       body += "Total output(s): " + gu_iToString(kernelAudio::getMaxOutChans(dev)) + "\n";
+       body += "Total intput(s): " + gu_iToString(kernelAudio::getMaxInChans(dev)) + "\n";
+       body += "Duplex channel(s): " + gu_iToString(kernelAudio::getDuplexChans(dev)) + "\n";
        body += "Default output: " + string(kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n";
        body += "Default input: " + string(kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n";
 
        int totalFreq = kernelAudio::getTotalFreqs(dev);
-       body += "Supported frequencies: " + gu_toString(totalFreq);
+       body += "Supported frequencies: " + gu_iToString(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 += gu_toString( kernelAudio::getFreq(dev, i)) + "  ";
+               body += gu_iToString( kernelAudio::getFreq(dev, i)) + "  ";
        }
 
        text->copy_label(body.c_str());
index f5d10d044c04dadc98e273017f13b23463421867..e65deea8ccd166d7b387602868fb4d371b5e0cf5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index f7bbd9706a8a866ae377466148aed8231118f1d8..ea861b71e27d0fcb5310b61ae100d08d6397d1c6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -26,6 +26,7 @@
 
 
 #include "../../utils/gui.h"
+#include "../../utils/string.h"
 #include "../../core/conf.h"
 #include "../../core/channel.h"
 #include "../../core/sampleChannel.h"
@@ -43,6 +44,9 @@
 extern gdMainWindow *mainWin;
 
 
+using std::string;
+
+
 gdKeyGrabber::gdKeyGrabber(Channel *ch)
        : gdWindow(300, 126, "Key configuration"), ch(ch)
 {
@@ -93,8 +97,7 @@ void gdKeyGrabber::__cb_clear()
 
 void gdKeyGrabber::setButtonLabel(int key)
 {
-       char tmp[2]; sprintf(tmp, "%c", key);
-       ch->guiChannel->mainButton->setKey(tmp);
+       ch->guiChannel->mainButton->setKey(key);
        ch->key = key;
 }
 
@@ -103,12 +106,12 @@ void gdKeyGrabber::setButtonLabel(int key)
 
 void gdKeyGrabber::updateText(int key)
 {
-       char tmp2[64];
+       string tmp = "Press a key.\n\nCurrent binding: ";
        if (key != 0)
-               sprintf(tmp2, "Press a key.\n\nCurrent binding: %c", key);
+               tmp += static_cast<char>(key);
        else
-               sprintf(tmp2, "Press a key.\n\nCurrent binding: [none]");
-       text->copy_label(tmp2);
+               tmp += "[none]";
+       text->copy_label(tmp.c_str());
 }
 
 
index 736fc7803d7578cf37fac684d14ce40fb73572dd..d66a4034f2f3c0d5711b6431caecf3044c00f23c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index d3620b61ed18a3f9650d1ef29f7c9b6f75ed80f4..1066099809a285bee0f7fc086e1ebdd411e944d7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c7dbae80bd0abc0cc2cc08d80e8b25acc450a3dc..64a6733106f9eb4b90cf5980e00691416e4ddd13 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 99b9b13ecbeeda77641cfb903379e93183c61fbf..fc013f8818e563d2586e782151f14587d6f0d584 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index cd770d48bee09bd9a38e1c5f1cb27a3d8a1d31be..fb96a8aa82ef5628c0c66f4765c619acdb57197a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5ec70b42d4377399caeeb11d66f25c26888be620..d461166e7425e466734cd48665184988435d859d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -25,7 +25,9 @@
  * -------------------------------------------------------------------------- */
 
 
-#include "../../../core/kernelMidi.h"
+#include "../../../core/midiDispatcher.h"
+#include "../../../core/channel.h"
+#include "../../../core/conf.h"
 #include "../../../utils/log.h"
 #include "../../elems/midiLearner.h"
 #include "midiInputBase.h"
@@ -35,7 +37,7 @@ using std::string;
 using namespace giada::m;
 
 
-gdMidiInputBase::gdMidiInputBase(int x, int y, int w, int h, const char *title)
+gdMidiInputBase::gdMidiInputBase(int x, int y, int w, int h, const chartitle)
        : gdWindow(x, y, w, h, title)
 {
 }
@@ -46,16 +48,16 @@ gdMidiInputBase::gdMidiInputBase(int x, int y, int w, int h, const char *title)
 
 gdMidiInputBase::~gdMidiInputBase()
 {
-       kernelMidi::stopMidiLearn();
+       midiDispatcher::stopMidiLearn();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputBase::stopMidiLearn(geMidiLearner *learner)
+void gdMidiInputBase::stopMidiLearn(geMidiLearnerlearner)
 {
-       kernelMidi::stopMidiLearn();
+       midiDispatcher::stopMidiLearn();
        learner->updateValue();
 }
 
@@ -63,7 +65,7 @@ void gdMidiInputBase::stopMidiLearn(geMidiLearner *learner)
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputBase::__cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l)
+void gdMidiInputBase::cb_learn(uint32_t* param, uint32_t msg, geMidiLearner* l)
 {
        *param = msg;
        stopMidiLearn(l);
@@ -74,26 +76,38 @@ void gdMidiInputBase::__cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputBase::cb_learn(uint32_t msg, void *d)
+void gdMidiInputBase::cb_learn(uint32_t msg, voidd)
 {
-       geMidiLearner::cbData_t *data = (geMidiLearner::cbData_t *) d;
-       gdMidiInputBase *window  = (gdMidiInputBase*) data->window;
-       geMidiLearner   *learner = data->learner;
-       uint32_t        *param   = learner->param;
-       window->__cb_learn(param, msg, learner);
+
+       geMidiLearner::cbData_t* data = (geMidiLearner::cbData_t*) d;
+       geMidiLearner* learner = data->learner;
+       Channel* channel = data->channel;
+       uint32_t* param = learner->param;
+       int midiChannel = (*param & 0x0F000000) >> 24; // Brutally extract channel
+
+       /* No MIDI learning if we are learning a Channel (channel != nullptr) and 
+       the selected MIDI channel is filtered OR if we are learning a global parameter
+       (channel == nullptr) and the selected MIDI channel is filtered. */
+
+       if ((channel != nullptr && !channel->isMidiInAllowed(midiChannel)) ||
+           (channel == nullptr && !conf::isMidiInAllowed(midiChannel)))
+                       return;
+
+       gdMidiInputBase* window  = static_cast<gdMidiInputBase*>(data->window);
+       window->cb_learn(param, msg, learner);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputBase::cb_close(Fl_Widget *w, void *p)  { ((gdMidiInputBase*)p)->__cb_close(); }
+void gdMidiInputBase::cb_close(Fl_Widget* w, void* p)  { ((gdMidiInputBase*)p)->cb_close(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputBase::__cb_close()
+void gdMidiInputBase::cb_close()
 {
        do_callback();
 }
index 54b09f825c11a3905985930c62736a351a1f244f..646bc4462ef585dbe719e79058909ed92b62e68d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -40,22 +40,23 @@ class gdMidiInputBase : public gdWindow
 {
 protected:
 
-       geButton *ok;
+       static const int LEARNER_WIDTH = 284;
 
-       void stopMidiLearn(geMidiLearner *l);
+       geButton* ok;
+
+       void stopMidiLearn(geMidiLearner* l);
 
        /* cb_learn
         * callback attached to kernelMidi to learn various actions. */
 
-       static void cb_learn  (uint32_t msg, void *data);
-       inline void __cb_learn(uint32_t *param, uint32_t msg, geMidiLearner *l);
-
-       static void cb_close  (Fl_Widget *w, void *p);
-       inline void __cb_close();
+       static void cb_learn(uint32_t msg, void* data);
+       static void cb_close(Fl_Widget* w, void* p);
+       void cb_learn(uint32_t* param, uint32_t msg, geMidiLearner* l);
+       void cb_close();
 
 public:
 
-       gdMidiInputBase(int x, int y, int w, int h, const char *title);
+       gdMidiInputBase(int x, int y, int w, int h, const chartitle);
        ~gdMidiInputBase();
 };
 
index 2f02c2ee57a196bae8738379011dc97114c27b0f..4992bb4ce779ffced4fde538c6ad885ba420f3b9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 #include <FL/Fl_Pack.H>
 #include "../../../utils/gui.h"
+#include "../../../utils/log.h"
 #include "../../../core/const.h"
 #include "../../../core/conf.h"
 #include "../../../core/sampleChannel.h"
 #ifdef WITH_VST
-  #include "../../../core/pluginHost.h"
-  #include "../../../core/plugin.h"
+       #include "../../../core/pluginHost.h"
+       #include "../../../core/plugin.h"
 #endif
 #include "../../../utils/string.h"
 #include "../../elems/midiLearner.h"
 #include "../../elems/basics/scroll.h"
 #include "../../elems/basics/box.h"
 #include "../../elems/basics/button.h"
+#include "../../elems/basics/choice.h"
 #include "../../elems/basics/check.h"
 #include "midiInputChannel.h"
 
@@ -48,45 +50,76 @@ using std::vector;
 using namespace giada::m;
 
 
-gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
+gdMidiInputChannel::gdMidiInputChannel(Channelch)
        :       gdMidiInputBase(conf::midiInputX, conf::midiInputY, conf::midiInputW,
-      conf::midiInputH, "MIDI Input Setup"),
+                       conf::midiInputH, "MIDI Input Setup"),
                ch(ch)
 {
-  string title = "MIDI Input Setup (channel " + gu_toString(ch->index+1) + ")";
+       string title = "MIDI Input Setup (channel " + gu_iToString(ch->index+1) + ")";
        label(title.c_str());
-  size_range(G_DEFAULT_MIDI_INPUT_UI_W, G_DEFAULT_MIDI_INPUT_UI_H);
+       size_range(G_DEFAULT_MIDI_INPUT_UI_W, G_DEFAULT_MIDI_INPUT_UI_H);
 
-       enable = new geCheck(8, 8, 120, 20, "enable MIDI input");
+       Fl_Group* groupHeader = new Fl_Group(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w(), 20);
+       groupHeader->begin();
 
-  container = new geScroll(8, enable->y()+enable->h()+4, w()-16, h()-68);
-  container->begin();
+               enable = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 120, G_GUI_UNIT, 
+                       "enable MIDI input");
+               channel = new geChoice(enable->x()+enable->w()+44, G_GUI_OUTER_MARGIN, 120, G_GUI_UNIT);
 
-    addChannelLearners();
+       groupHeader->resizable(nullptr);
+       groupHeader->end();
+
+       container = new geScroll(G_GUI_OUTER_MARGIN, enable->y()+enable->h()+G_GUI_OUTER_MARGIN, 
+               w()-16, h()-76);
+       container->begin();
+
+               addChannelLearners();
 #ifdef WITH_VST
-    addPluginLearners();
+               addPluginLearners();
 #endif
 
-  container->end();
+       container->end();
 
-  Fl_Group *groupButtons = new Fl_Group(8, container->y()+container->h()+8, container->w(), 20);
-  groupButtons->begin();
+       Fl_Group* groupButtons = new Fl_Group(8, container->y()+container->h()+8, container->w(), 20);
+       groupButtons->begin();
 
-    geBox *spacer = new geBox(groupButtons->x(), groupButtons->y(), 100, 20);  // spacer window border <-> buttons
-         ok = new geButton(w()-88, groupButtons->y(), 80, 20, "Close");
+               geBox* spacer = new geBox(groupButtons->x(), groupButtons->y(), 100, 20);       // spacer window border <-> buttons
+               ok = new geButton(w()-88, groupButtons->y(), 80, 20, "Close");
 
-  groupButtons->resizable(spacer);
-  groupButtons->end();
+       groupButtons->resizable(spacer);
+       groupButtons->end();
 
-  ok->callback(cb_close, (void*)this);
+       ok->callback(cb_close, (void*)this);
 
-  enable->value(ch->midiIn);
+       enable->value(ch->midiIn);
        enable->callback(cb_enable, (void*)this);
 
-  resizable(container);
-
-  gu_setFavicon(this);
-  set_modal();
+       channel->add("Channel (any)");
+       channel->add("Channel 1");
+       channel->add("Channel 2");
+       channel->add("Channel 3");
+       channel->add("Channel 4");
+       channel->add("Channel 5");
+       channel->add("Channel 6");
+       channel->add("Channel 7");
+       channel->add("Channel 8");
+       channel->add("Channel 9");
+       channel->add("Channel 10");
+       channel->add("Channel 11");
+       channel->add("Channel 12");
+       channel->add("Channel 13");
+       channel->add("Channel 14");
+       channel->add("Channel 15");
+       channel->add("Channel 16");
+       channel->value(ch->getMidiInFilter() == -1 ? 0 : ch->getMidiInFilter() + 1);
+       channel->callback(cb_setChannel, (void*)this);
+
+       resizable(container);
+
+       end();
+
+       gu_setFavicon(this);
+       set_modal();
        show();
 }
 
@@ -96,8 +129,8 @@ gdMidiInputChannel::gdMidiInputChannel(Channel *ch)
 
 gdMidiInputChannel::~gdMidiInputChannel()
 {
-  conf::midiInputX = x();
-  conf::midiInputY = y();
+       conf::midiInputX = x();
+       conf::midiInputY = y();
        conf::midiInputW = w();
        conf::midiInputH = h();
 }
@@ -108,25 +141,27 @@ gdMidiInputChannel::~gdMidiInputChannel()
 
 void gdMidiInputChannel::addChannelLearners()
 {
-  Fl_Pack *pack = new Fl_Pack(container->x(), container->y(), LEARNER_WIDTH, 200);
-  pack->spacing(4);
-  pack->begin();
-
-    geBox *header = new geBox(0, 0, LEARNER_WIDTH, 20, "channel");
-    header->box(FL_BORDER_BOX);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "key press",   cb_learn, &ch->midiInKeyPress);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "key release", cb_learn, &ch->midiInKeyRel);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "key kill",    cb_learn, &ch->midiInKill);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "arm",         cb_learn, &ch->midiInArm);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "mute",        cb_learn, &ch->midiInMute);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "solo",        cb_learn, &ch->midiInSolo);
-    new geMidiLearner(0, 0, LEARNER_WIDTH, "volume",      cb_learn, &ch->midiInVolume);
-    if (ch->type == CHANNEL_SAMPLE) {
-      new geMidiLearner(0, 0, LEARNER_WIDTH, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch);
-      new geMidiLearner(0, 0, LEARNER_WIDTH, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions);
-    }
-
-  pack->end();
+       Fl_Pack* pack = new Fl_Pack(container->x(), container->y(), LEARNER_WIDTH, 200);
+       pack->spacing(4);
+       pack->begin();
+
+               geBox *header = new geBox(0, 0, LEARNER_WIDTH, 20, "channel");
+               header->box(FL_BORDER_BOX);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "key press",   cb_learn, &ch->midiInKeyPress, ch);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "key release", cb_learn, &ch->midiInKeyRel, ch);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "key kill",    cb_learn, &ch->midiInKill, ch);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "arm",         cb_learn, &ch->midiInArm, ch);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "mute",        cb_learn, &ch->midiInMute, ch);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "solo",        cb_learn, &ch->midiInSolo, ch);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "volume",      cb_learn, &ch->midiInVolume, ch);
+               if (ch->type == CHANNEL_SAMPLE) {
+                       new geMidiLearner(0, 0, LEARNER_WIDTH, "pitch", cb_learn, 
+                               &(static_cast<SampleChannel*>(ch))->midiInPitch, ch);
+                       new geMidiLearner(0, 0, LEARNER_WIDTH, "read actions", cb_learn, 
+                               &(static_cast<SampleChannel*>(ch))->midiInReadActions, ch);
+               }
+
+       pack->end();
 }
 
 
@@ -137,25 +172,25 @@ void gdMidiInputChannel::addChannelLearners()
 
 void gdMidiInputChannel::addPluginLearners()
 {
-  vector <Plugin *> *plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
-  for (unsigned i=0; i<plugins->size(); i++) {
+       vector<Plugin*>* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch);
+       for (unsigned i=0; i<plugins->size(); i++) {
 
-    Fl_Pack *pack = new Fl_Pack(container->x() + ((i + 1) * (LEARNER_WIDTH + 8)),
-      container->y(), LEARNER_WIDTH, 200);
-    pack->spacing(4);
-    pack->begin();
+               Fl_Pack* pack = new Fl_Pack(container->x() + ((i + 1) * (LEARNER_WIDTH + 8)),
+                       container->y(), LEARNER_WIDTH, 200);
+               pack->spacing(4);
+               pack->begin();
 
-      Plugin *plugin = plugins->at(i);
+                       Plugin* plugin = plugins->at(i);
 
-      geBox *header = new geBox(0, 0, LEARNER_WIDTH, 20, plugin->getName().c_str());
-      header->box(FL_BORDER_BOX);
+                       geBox* header = new geBox(0, 0, LEARNER_WIDTH, 20, plugin->getName().c_str());
+                       header->box(FL_BORDER_BOX);
 
-      for (int k=0; k<plugin->getNumParameters(); k++)
-        new geMidiLearner(0, 0, LEARNER_WIDTH, plugin->getParameterName(k).c_str(),
-          cb_learn, &plugin->midiInParams.at(k));
+                       for (int k=0; k<plugin->getNumParameters(); k++)
+                               new geMidiLearner(0, 0, LEARNER_WIDTH, plugin->getParameterName(k).c_str(),
+                                       cb_learn, &plugin->midiInParams.at(k), ch);
 
-    pack->end();
-  }
+               pack->end();
+       }
 }
 
 #endif
@@ -164,13 +199,27 @@ void gdMidiInputChannel::addPluginLearners()
 /* -------------------------------------------------------------------------- */
 
 
-void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p)  { ((gdMidiInputChannel*)p)->__cb_enable(); }
+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_enable()
+void gdMidiInputChannel::cb_enable()
 {
        ch->midiIn = enable->value();
+       enable->value() ? channel->activate() : channel->deactivate();
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInputChannel::cb_setChannel()
+{
+       ch->setMidiInFilter(channel->value() == 0 ? -1 : channel->value() - 1);
+       gu_log("[gdMidiInputChannel] Set MIDI channel to %d\n", 
+               ch->getMidiInFilter());
+}
+
index f2e9d33febbba0b639010c69501252814144faa1..523ab66807a2a4f9ac094e2f818494de52a8db81 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #include "midiInputBase.h"
 
 
+class Channel;
+class geScroll;
+class geCheck;
+class geChoice;
+
+
 class gdMidiInputChannel : public gdMidiInputBase
 {
 private:
 
-  static const int LEARNER_WIDTH = 284;
-
-       class Channel *ch;
-
-  class geScroll *container;
-       class geCheck   *enable;
+       Channel* ch;
 
-       //gVector <geMidiLearner *> items; // plugins parameters
+       geScroll* container;
+       geCheck*  enable;
+       geChoice* channel;
 
-       static void cb_enable  (Fl_Widget *w, void *p);
-       inline void __cb_enable();
+       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 addChannelLearners();
+       void addChannelLearners();
 
 #ifdef WITH_VST
 
-  void addPluginLearners();
+       void addPluginLearners();
 
 #endif
 
 public:
 
-       gdMidiInputChannel(class Channel *ch);
-  ~gdMidiInputChannel();
+       gdMidiInputChannel(Channel* ch);
+       ~gdMidiInputChannel();
 };
 
 
index 694f585c5b9e33d44aab557d712d8f35407df4c3..f583bcf072d7299e767ec1c6896b479c2d42dd8f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  * -------------------------------------------------------------------------- */
 
 
+#include <FL/Fl_Pack.H>
 #include "../../../utils/gui.h"
 #include "../../../core/conf.h"
+#include "../../../core/const.h"
 #include "../../elems/midiLearner.h"
 #include "../../elems/basics/button.h"
+#include "../../elems/basics/check.h"
+#include "../../elems/basics/choice.h"
 #include "midiInputMaster.h"
 
 
@@ -36,23 +40,93 @@ using namespace giada::m;
 
 
 gdMidiInputMaster::gdMidiInputMaster()
-       : gdMidiInputBase(0, 0, 300, 256, "MIDI Input Setup (global)")
+       : gdMidiInputBase(0, 0, 300, 284, "MIDI Input Setup (global)")
 {
        set_modal();
 
-       new geMidiLearner(8,   8, w()-16, "rewind",           &cb_learn, &conf::midiInRewind);
-       new geMidiLearner(8,  32, w()-16, "play/stop",        &cb_learn, &conf::midiInStartStop);
-       new geMidiLearner(8,  56, w()-16, "action recording", &cb_learn, &conf::midiInActionRec);
-       new geMidiLearner(8,  80, w()-16, "input recording",  &cb_learn, &conf::midiInInputRec);
-       new geMidiLearner(8, 104, w()-16, "metronome",        &cb_learn, &conf::midiInMetronome);
-       new geMidiLearner(8, 128, w()-16, "input volume",     &cb_learn, &conf::midiInVolumeIn);
-       new geMidiLearner(8, 152, w()-16, "output volume",    &cb_learn, &conf::midiInVolumeOut);
-       new geMidiLearner(8, 176, w()-16, "sequencer ×2",     &cb_learn, &conf::midiInBeatDouble);
-       new geMidiLearner(8, 200, w()-16, "sequencer ÷2",     &cb_learn, &conf::midiInBeatHalf);
-       ok = new geButton(w()-88, 228, 80, 20, "Close");
+       Fl_Group* groupHeader = new Fl_Group(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, w(), 20);
+       groupHeader->begin();
+
+               enable = new geCheck(G_GUI_OUTER_MARGIN, G_GUI_OUTER_MARGIN, 120, G_GUI_UNIT, 
+                       "enable MIDI input");
+               channel = new geChoice(enable->x()+enable->w()+44, G_GUI_OUTER_MARGIN, 120, G_GUI_UNIT);
+
+       groupHeader->resizable(nullptr);
+       groupHeader->end();
+
+       Fl_Pack* pack = new Fl_Pack(G_GUI_OUTER_MARGIN, groupHeader->y()+groupHeader->h()+G_GUI_OUTER_MARGIN, 
+               LEARNER_WIDTH, 212);
+       pack->spacing(G_GUI_INNER_MARGIN);
+       pack->begin();
+
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "rewind",           &cb_learn, &conf::midiInRewind, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "play/stop",        &cb_learn, &conf::midiInStartStop, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "action recording", &cb_learn, &conf::midiInActionRec, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "input recording",  &cb_learn, &conf::midiInInputRec, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "metronome",        &cb_learn, &conf::midiInMetronome, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "input volume",     &cb_learn, &conf::midiInVolumeIn, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "output volume",    &cb_learn, &conf::midiInVolumeOut, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "sequencer ×2",     &cb_learn, &conf::midiInBeatDouble, nullptr);
+               new geMidiLearner(0, 0, LEARNER_WIDTH, "sequencer ÷2",     &cb_learn, &conf::midiInBeatHalf, nullptr);
+
+       pack->end();
+
+       ok = new geButton(w()-88, pack->y()+pack->h()+G_GUI_OUTER_MARGIN, 80, G_GUI_UNIT, "Close");
+
+       end();
 
        ok->callback(cb_close, (void*)this);
 
+       enable->value(conf::midiIn);
+       enable->callback(cb_enable, (void*)this);
+
+       channel->add("Channel (any)");
+       channel->add("Channel 1");
+       channel->add("Channel 2");
+       channel->add("Channel 3");
+       channel->add("Channel 4");
+       channel->add("Channel 5");
+       channel->add("Channel 6");
+       channel->add("Channel 7");
+       channel->add("Channel 8");
+       channel->add("Channel 9");
+       channel->add("Channel 10");
+       channel->add("Channel 11");
+       channel->add("Channel 12");
+       channel->add("Channel 13");
+       channel->add("Channel 14");
+       channel->add("Channel 15");
+       channel->add("Channel 16");
+       channel->value(conf::midiInFilter -1 ? 0 : conf::midiInFilter + 1);
+       channel->callback(cb_setChannel, (void*)this);
+
        gu_setFavicon(this);
        show();
 }
+
+
+/* -------------------------------------------------------------------------- */
+
+
+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()
+{
+       conf::midiIn = enable->value();
+       enable->value() ? channel->activate() : channel->deactivate();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void gdMidiInputMaster::cb_setChannel()
+{
+       conf::midiInFilter = channel->value() == 0 ? -1 : channel->value() - 1;
+}
+
index 52bd54666940119c2bcf70f4530cfdbb50318524..1a0bec65cfe5566a5c9826188bd4f9369d78de36 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #include "midiInputBase.h"
 
 
+class geCheck;
+class geChoice;
+
+
 class gdMidiInputMaster : public gdMidiInputBase
 {
+private:
+
+       geCheck*  enable;
+       geChoice* channel;
+
+       static void cb_enable(Fl_Widget* w, void* p);
+       static void cb_setChannel(Fl_Widget* w, void* p);
+       void cb_enable();
+       void cb_setChannel();
+
 public:
 
        gdMidiInputMaster();
index e293d5862774da82fba60c66f6dc283e503836fe..f6c3da046f0ebf09ace17ac616968b7f08ef8547 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 
 #include "../../../utils/log.h"
+#include "../../../utils/string.h"
 #include "../../elems/midiLearner.h"
 #include "midiOutputBase.h"
 
 
+using std::string;
 using namespace giada::m;
 
 
@@ -44,7 +46,7 @@ gdMidiOutputBase::gdMidiOutputBase(int w, int h)
 
 void gdMidiOutputBase::stopMidiLearn(geMidiLearner *learner)
 {
-       kernelMidi::stopMidiLearn();
+       midiDispatcher::stopMidiLearn();
        learner->updateValue();
 }
 
@@ -108,7 +110,6 @@ void gdMidiOutputBase::__cb_enableLightning() {}
 
 void gdMidiOutputBase::setTitle(int chanNum)
 {
-       char title[64];
-       sprintf(title, "MIDI Output Setup (channel %d)", chanNum);
-       copy_label(title);
+       string tmp = "MIDI Output Setup (channel " + gu_iToString(chanNum) + ")"; 
+       copy_label(tmp.c_str());
 }
index 13a037503a549695920b1b143cabd6ab990f7802..343aa8901668a987c9893f8e63daacd497778c20 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index be4bfd0583a10848fedbed15024fbc6216bf5265..ad425a5c7ee0a7c122ed22d062e38302a42bf325 100644 (file)
@@ -1,10 +1,11 @@
+
 /* -----------------------------------------------------------------------------
  *
- * Giada - Your Hardcore Loopmachine
+, ch * Giada - Your Hardcore Loopmachine
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -35,7 +36,7 @@
 #include "midiOutputMidiCh.h"
 
 
-gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch)
+gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannelch)
        : gdMidiOutputBase(300, 168), ch(ch)
 {
        setTitle(ch->index+1);
@@ -45,9 +46,12 @@ gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch)
        chanListOut = new geChoice(w()-108, y()+8, 100, 20);
 
        enableLightning = new geCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output");
-       new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+8,  w()-16, "playing", cb_learn, &ch->midiOutLplaying);
-       new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute",    cb_learn, &ch->midiOutLmute);
-       new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo",    cb_learn, &ch->midiOutLsolo);
+       new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+8,  w()-16, "playing", 
+               cb_learn, &ch->midiOutLplaying, ch);
+       new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute",    
+               cb_learn, &ch->midiOutLmute, ch);
+       new geMidiLearner(x()+8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo",    
+               cb_learn, &ch->midiOutLsolo, ch);
 
        close = new geButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
 
index b6e9694a21367a1e28d58adf21e3dba16d0decc3..93fff1f21e5a41292df249ae196af072e4131277 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index ad68978b0ee67f3f3b099e28fa23f5b0691cbff3..e02c1a63421f15d12e8a62bb43b03551d6f3c196 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 #include "midiOutputSampleCh.h"
 
 
-gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch)
+gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannelch)
        : gdMidiOutputBase(300, 140), ch(ch)
 {
        setTitle(ch->index+1);
 
        enableLightning = new geCheck(8, 8, 120, 20, "Enable MIDI lightning output");
-       new geMidiLearner(8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying);
-       new geMidiLearner(8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute",   cb_learn, &ch->midiOutLmute);
-       new geMidiLearner(8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo",   cb_learn, &ch->midiOutLsolo);
+       new geMidiLearner(8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", 
+               cb_learn, &ch->midiOutLplaying, ch);
+       new geMidiLearner(8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute",   
+               cb_learn, &ch->midiOutLmute, ch);
+       new geMidiLearner(8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo",   
+               cb_learn, &ch->midiOutLsolo, ch);
 
        close = new geButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close");
        close->callback(cb_close, (void*)this);
index 7050c95d7503e29686839231054b6c1304f77333..3b956d319bc4aad1025a7e85255e0055b3c8208e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b7adc89805bd65bbf5218585578cbe14bc91844c..21e5170b251843b5cd2bf2fa1ae563d791127221 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index f74c374bc2af2513538945d8ee6ff435ceaa1600..cd8f483cd3751800aa2f2c82cd1bd041cf2bfe40 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 8b4cfb9765cf6f81759e2f0ad51f17fdd9fa7fed..9ba36c230f5a322c43dfc23b3d5a8a0de8d46a2e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -90,7 +90,7 @@ gdPluginList::gdPluginList(int stackType, Channel* ch)
        if (stackType == pluginHost::MASTER_IN)
                label("Master In Plugins");
        else {
-               string l = "Channel " + gu_toString(ch->index+1) + " Plugins";
+               string l = "Channel " + gu_iToString(ch->index+1) + " Plugins";
                copy_label(l.c_str());
        }
 
@@ -112,7 +112,7 @@ gdPluginList::~gdPluginList()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPluginList::cb_addPlugin(Fl_Widget* v, void* p)   { ((gdPluginList*)p)->__cb_addPlugin(); }
+void gdPluginList::cb_addPlugin(Fl_Widget* v, void* p) { ((gdPluginList*)p)->cb_addPlugin(); }
 
 
 /* -------------------------------------------------------------------------- */
@@ -140,7 +140,7 @@ void gdPluginList::cb_refreshList(Fl_Widget* v, void* p)
 /* -------------------------------------------------------------------------- */
 
 
-void gdPluginList::__cb_addPlugin()
+void gdPluginList::cb_addPlugin()
 {
        /* the usual callback that gdWindow adds to each subwindow in this case
         * is not enough, because when we close the browser the plugin list
@@ -260,18 +260,18 @@ gdPlugin::gdPlugin(gdPluginList* gdp, Plugin* p, int X, int Y, int W)
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::cb_removePlugin    (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_removePlugin(); }
-void gdPlugin::cb_openPluginWindow(Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_openPluginWindow(); }
-void gdPlugin::cb_setBypass       (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_setBypass(); }
-void gdPlugin::cb_shiftUp         (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_shiftUp(); }
-void gdPlugin::cb_shiftDown       (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_shiftDown(); }
-void gdPlugin::cb_setProgram      (Fl_Widget* v, void* p) { ((gdPlugin*)p)->__cb_setProgram(); }
+void gdPlugin::cb_removePlugin    (Fl_Widget* v, void* p) { ((gdPlugin*)p)->cb_removePlugin(); }
+void gdPlugin::cb_openPluginWindow(Fl_Widget* v, void* p) { ((gdPlugin*)p)->cb_openPluginWindow(); }
+void gdPlugin::cb_setBypass       (Fl_Widget* v, void* p) { ((gdPlugin*)p)->cb_setBypass(); }
+void gdPlugin::cb_shiftUp         (Fl_Widget* v, void* p) { ((gdPlugin*)p)->cb_shiftUp(); }
+void gdPlugin::cb_shiftDown       (Fl_Widget* v, void* p) { ((gdPlugin*)p)->cb_shiftDown(); }
+void gdPlugin::cb_setProgram      (Fl_Widget* v, void* p) { ((gdPlugin*)p)->cb_setProgram(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::__cb_shiftUp()
+void gdPlugin::cb_shiftUp()
 {
        /*nothing to do if there's only one plugin */
 
@@ -292,7 +292,7 @@ void gdPlugin::__cb_shiftUp()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::__cb_shiftDown()
+void gdPlugin::cb_shiftDown()
 {
        /*nothing to do if there's only one plugin */
 
@@ -313,7 +313,7 @@ void gdPlugin::__cb_shiftDown()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::__cb_removePlugin()
+void gdPlugin::cb_removePlugin()
 {
        /* any subwindow linked to the plugin must be destroyed first */
 
@@ -326,7 +326,7 @@ void gdPlugin::__cb_removePlugin()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::__cb_openPluginWindow()
+void gdPlugin::cb_openPluginWindow()
 {
        /* the new pluginWindow has id = id_plugin + 1, because id=0 is reserved
        * for the parent window 'add plugin'. */
@@ -343,11 +343,11 @@ void gdPlugin::__cb_openPluginWindow()
                gu_log("[gdPlugin::__cb_openPluginWindow] Plug-in has editor, window id=%d\n", pwid);
                w = new gdPluginWindowGUI(pPlugin);
        }
-       else
+       else {
                w = new gdPluginWindow(pPlugin);
-
-       gu_log("[gdPlugin::__cb_openPluginWindow] Plug-in has no editor, window id=%d\n", pwid);
-
+               gu_log("[gdPlugin::__cb_openPluginWindow] Plug-in has no editor, window id=%d\n", pwid);
+       }
+       
        if (pParent->hasWindow(pwid))
                pParent->delSubWindow(pwid);
        w->setId(pwid);
@@ -358,7 +358,7 @@ void gdPlugin::__cb_openPluginWindow()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::__cb_setBypass()
+void gdPlugin::cb_setBypass()
 {
        pPlugin->toggleBypass();
 }
@@ -367,9 +367,10 @@ void gdPlugin::__cb_setBypass()
 /* -------------------------------------------------------------------------- */
 
 
-void gdPlugin::__cb_setProgram()
+void gdPlugin::cb_setProgram()
 {
-       pPlugin->setCurrentProgram(program->value());
+       //pPlugin->setCurrentProgram(program->value());
+       plugin::setProgram(pPlugin, program->value());
 }
 
 
index c8e88ce1b5e7057fccc9983cc7716ca1e521639c..94e49cd039bdc310138c42003c6eca2f95c15e86 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -50,8 +50,8 @@ private:
   geButton  *addPlugin;
        Fl_Scroll *list;
 
-       static void cb_addPlugin  (Fl_Widget *v, void *p);
-       inline void __cb_addPlugin();
+       static void cb_addPlugin(Fl_Widget *v, void *p);
+       void cb_addPlugin();
 
 public:
 
@@ -80,18 +80,18 @@ private:
   gdPluginList *pParent;
   Plugin       *pPlugin;
 
-       static void cb_removePlugin       (Fl_Widget *v, void *p);
-       static void cb_openPluginWindow   (Fl_Widget *v, void *p);
-       static void cb_setBypass          (Fl_Widget *v, void *p);
-       static void cb_shiftUp            (Fl_Widget *v, void *p);
-       static void cb_shiftDown          (Fl_Widget *v, void *p);
-       static void cb_setProgram         (Fl_Widget *v, void *p);
-       inline void __cb_removePlugin     ();
-       inline void __cb_openPluginWindow ();
-       inline void __cb_setBypass        ();
-       inline void __cb_shiftUp          ();
-       inline void __cb_shiftDown        ();
-       inline void __cb_setProgram       ();
+       static void cb_removePlugin(Fl_Widget *v, void *p);
+       static void cb_openPluginWindow(Fl_Widget *v, void *p);
+       static void cb_setBypass(Fl_Widget *v, void *p);
+       static void cb_shiftUp(Fl_Widget *v, void *p);
+       static void cb_shiftDown(Fl_Widget *v, void *p);
+       static void cb_setProgram(Fl_Widget *v, void *p);
+       void cb_removePlugin();
+       void cb_openPluginWindow();
+       void cb_setBypass();
+       void cb_shiftUp();
+       void cb_shiftDown();
+       void cb_setProgram();
 
 public:
 
index ede116e0c103b7e5ec62cc71234f35b8d84b6b16..51b4c284e53d4da95792d950e0341e7bd76a125b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -77,6 +77,14 @@ void gdPluginWindow::updateParameter(int index, bool changeSlider)
 }
 
 
+void gdPluginWindow::updateParameters(bool changeSlider)
+{
+       for (int i=0; i<m_plugin->getNumParameters(); i++) {
+               static_cast<gePluginParameter*>(m_list->child(i))->update(changeSlider);
+       }
+}
+
+
 /* -------------------------------------------------------------------------- */
 
 
index 1e0f922d908e58f5f297b70c0065e6d621d99ad6..49f753ede25374225bb99ead6b22f761741d6439 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -55,6 +55,7 @@ public:
        gdPluginWindow(Plugin* p);
 
        void updateParameter(int index, bool changeSlider=false);
+       void updateParameters(bool changeSlider=false);
 };
 
 
index ed119879d51be1f4075a8a66febcca76dc3d83a3..60b560c8f06c17de8c0855c3673fae676f4af632 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 54731a392f353092d004843e273180fcfdd86345..d563aee6c127d7f55e7cc9ba80377d7c8f46627b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index ea80d9f341660b482354a54371eb4afb51958340..9e98a716558774d08cffe558096fe624071e4e2d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -138,7 +138,7 @@ Fl_Group* gdSampleEditor::createUpperBar()
   if (conf::sampleEditorGridVal == 0)
     grid->value(0);
   else 
-    grid->value(grid->find_item(gu_toString(conf::sampleEditorGridVal).c_str()));
+    grid->value(grid->find_item(gu_iToString(conf::sampleEditorGridVal).c_str()));
   grid->callback(cb_changeGrid, (void*)this);
 
   snap->value(conf::sampleEditorGridOn);
@@ -349,12 +349,12 @@ void gdSampleEditor::cb_changeGrid()
 
 void gdSampleEditor::updateInfo()
 {
-       string bitDepth = ch->wave->getBits() != 0 ? gu_toString(ch->wave->getBits()) : "(unknown)";
+       string bitDepth = ch->wave->getBits() != 0 ? gu_iToString(ch->wave->getBits()) : "(unknown)";
        string infoText = 
                "File: "  + ch->wave->getPath() + "\n"
-               "Size: " + gu_toString(ch->wave->getSize()) + " frames\n"
-               "Duration: " + gu_toString(ch->wave->getDuration()) + " seconds\n"
+               "Size: " + gu_iToString(ch->wave->getSize()) + " frames\n"
+               "Duration: " + gu_iToString(ch->wave->getDuration()) + " seconds\n"
                "Bit depth: " + bitDepth + "\n"
-               "Frequency: " + gu_toString(ch->wave->getRate()) + " Hz\n";
+               "Frequency: " + gu_iToString(ch->wave->getRate()) + " Hz\n";
        info->copy_label(infoText.c_str());
 }
index 43ac55678898fc0ff1de3be10635ef3905e808bb..2d120541712b1a8632d686682c16115c7c20dbee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5797feba16e73426542045a3d87555b87d140d0a..a8c8ce0a21e139958d0e680d855b27f791fae725 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 698f51237f39554d7ba60e078737e075a584cd5b..888e898fb71b2a7bdc9192269ce608372ccac06f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index cb1b99a8c25c9d13e5f10ab8d5c743fff5bfe8c3..85169707f2072e71065e6c776db89fc9d7723061 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index cd9823fa32c7eb844e557e1ab453534c019b3ea3..f681d56161152bb5f4fe003a5c522e3576de584f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index a9f50034166598bd59d100772b093fc80aef4414..db60c350baa038a20fc20cc5e3506d6ffb48bc90 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index deaf7c401931323a66bff231d27cd576c95276f5..5870ccabf89a2f68452582f837606bd73f833430 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 56aa786a7838a99ec669fb70dded3222e7a600f6..0f11b318ffdea2fa76572375df63a2b48917906a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index f907b57dc968e7451cfd4c4b58811ab292b0ffce..d0862de336bc5421eec596b53bff19179df51566 100644 (file)
@@ -8,7 +8,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 11c380620d5c4ace10b2a90dd5f287327140c55b..439c91aad60a44af77b395e12bf22664aed79a2d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index ade2fb2e3a7abbede2d4112170136238e366aaca..41d7de4f8f29fc7c8838256a62016fc95f5e27f2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 206a2901813d908d979567692b8082f42f98c9ea..0615b7f49100a6c6475f4e67123a253b178d36a1 100644 (file)
@@ -9,7 +9,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c9675eafe7a2de36e5b3dc04c241c436206e58f3..b2218abbe592de78c24fbe3233d7e73323dfaf1f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * ---------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c697cd8957c5fb11d700bf987fe7e42c1b93859a..a481fb333439010e821fe39bb117d54ecaaa988b 100644 (file)
@@ -4,7 +4,7 @@
 *
 * ------------------------------------------------------------------------------
 *
-* Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+* Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
 *
 * This file is part of Giada - Your Hardcore Loopmachine.
 *
index 8c56be3e0d81305f55c0280e63053df9ec3338c0..2ca3eacb3a4b7b549799fd5a3d82e0816e67d9c5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c8591e4ed6f32e743299ef5e25951bf61a6b55aa..cba778f82943beb2c2b1ffab2c3c0f457566dcb9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 90ad87b9abf7115e5b81d2e93c5a8b052f00e38a..d70bdd880844a07bc55e94823949177dbd68703a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index dea981060f3d807b618dcdce9068438019cabf3b..b0608b2898e2de12fb401581aff2b9808d845913 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2a63c0d0d2f6276abd757bea15ca2d8fee1c3d12..26fbaf08482887a560e14d3f4e0c6624b65d57bd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 1cc5b4258226c98bd3919c0c707330f69cb78145..acb6442199305d2b6d847b026b5bf0924c58d529 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 using namespace giada::m;
 
 
-gePianoItem::gePianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *_a,
-  recorder::action *_b, gdActionEditor *pParent)
+gePianoItem::gePianoItem(int X, int Y, int rel_x, int rel_y, recorder::action a,
+       recorder::action b, gdActionEditor* pParent)
        : geBasePianoItem(X, Y, MIN_WIDTH, pParent),
-         a              (_a),
-         b              (_b),
-               event_a        (0x00),
-               event_b        (0x00),
+               a              (a),
+               b              (b),
                changed        (false)
 {
-       /* a is a pointer: action exists, needs to be displayed */
-
-       if (a) {
-               note    = kernelMidi::getB2(a->iValue);
-               frame_a = a->frame;
-               frame_b = b->frame;
-               event_a = a->iValue;
-               event_b = b->iValue;
-               int newX = rel_x + (frame_a / pParent->zoom);
-               int newY = rel_y + getY(note);
-               int newW = (frame_b - frame_a) / pParent->zoom;
-               resize(newX, newY, newW, h());
-       }
-
-       /* a is null: action needs to be recorded from scratch */
-
-       else {
-               note    = getNote(rel_y);
-               frame_a = rel_x * pParent->zoom;
-               frame_b = (rel_x + 20) * pParent->zoom;
-               record();
-               size((frame_b - frame_a) / pParent->zoom, h());
-       }
+       int newX = rel_x + (a.frame / pParent->zoom);
+       int newY = rel_y + getY(kernelMidi::getB2(a.iValue));
+       int newW = (b.frame - a.frame) / pParent->zoom;
+       resize(newX, newY, newW, h());
 }
 
 
@@ -81,12 +60,12 @@ gePianoItem::gePianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *_
 
 void gePianoItem::reposition(int pianoRollX)
 {
-  int newX = pianoRollX + (frame_a / pParent->zoom);
-  int newW = ((frame_b - frame_a) / pParent->zoom);
-  if (newW < MIN_WIDTH)
-    newW = MIN_WIDTH;
-  resize(newX, y(), newW, h());
-  redraw();
+       int newX = pianoRollX + (a.frame / pParent->zoom);
+       int newW = ((b.frame - a.frame) / pParent->zoom);
+       if (newW < MIN_WIDTH)
+               newW = MIN_WIDTH;
+       resize(newX, y(), newW, h());
+       redraw();
 }
 
 
@@ -100,11 +79,11 @@ bool gePianoItem::overlap()
         * end   = the lowest value between the two ending points
         * if start < end then there's an overlap of end-start pixels. */
 
-       geNoteEditor *pPiano = static_cast<geNoteEditor*>(parent());
+       geNoteEditor* noteEditor = static_cast<geNoteEditor*>(parent());
 
-       for (int i=0; i<pPiano->children(); i++) {
+       for (int i=0; i<noteEditor->children(); i++) {
 
-               gePianoItem *pItem = static_cast<gePianoItem*>(pPiano->child(i));
+               gePianoItem* pItem = static_cast<gePianoItem*>(noteEditor->child(i));
 
                /* don't check against itself and with different y positions */
 
@@ -134,49 +113,19 @@ void gePianoItem::draw()
 /* -------------------------------------------------------------------------- */
 
 
-void gePianoItem::record()
+void gePianoItem::removeAction()
 {
-       /* avoid frame overflow */
-
-       int overflow = frame_b - clock::getTotalFrames();
-       if (overflow > 0) {
-               frame_b -= overflow;
-               frame_a -= overflow;
-       }
-
-       event_a |= (MIDI_NOTE_ON);
-       event_a |= (note << 16);   // note value
-       event_a |= (MIDI_VELOCITY);
-       event_a |= (0x00);
-
-       event_b |= (MIDI_NOTE_OFF);
-       event_b |= (note << 16);   // note value
-       event_b |= (MIDI_VELOCITY);
-       event_b |= (0x00);
-
-       recorder::rec(pParent->chan->index, G_ACTION_MIDI, frame_a, event_a);
-       recorder::rec(pParent->chan->index, G_ACTION_MIDI, frame_b, event_b);
-  pParent->chan->hasActions = true;
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
-void gePianoItem::remove()
-{
-  MidiChannel *ch = static_cast<MidiChannel*>(pParent->chan);
-       recorder::deleteAction(ch->index, frame_a, G_ACTION_MIDI, true,
-    &mixer::mutex_recs, event_a, 0.0);
-       recorder::deleteAction(ch->index, frame_b, G_ACTION_MIDI, true,
-    &mixer::mutex_recs, event_b, 0.0);
+       MidiChannel* ch = static_cast<MidiChannel*>(pParent->chan);
+       recorder::deleteAction(ch->index, a.frame, G_ACTION_MIDI, true,
+               &mixer::mutex_recs, a.iValue, 0.0);
+       recorder::deleteAction(ch->index, b.frame, G_ACTION_MIDI, true,
+               &mixer::mutex_recs, b.iValue, 0.0);
 
        /* Send a note-off in case we are deleting it in a middle of a key_on/key_off
-  sequence. */
+       sequence. */
 
-       ch->sendMidi(event_b);
-  ch->hasActions = recorder::hasActions(ch->index);
-  static_cast<gePianoRoll*>(parent())->cursorOnItem = false;
+       ch->sendMidi(b.iValue);
+       ch->hasActions = recorder::hasActions(ch->index);
 }
 
 
@@ -190,7 +139,6 @@ int gePianoItem::handle(int e)
        switch (e) {
 
                case FL_ENTER: {
-      static_cast<gePianoRoll*>(parent())->cursorOnItem = true;
                        selected = true;
                        ret = 1;
                        redraw();
@@ -199,7 +147,6 @@ int gePianoItem::handle(int e)
 
                case FL_LEAVE: {
                        fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-      static_cast<gePianoRoll*>(parent())->cursorOnItem = false;
                        selected = false;
                        ret = 1;
                        redraw();
@@ -227,14 +174,13 @@ int gePianoItem::handle(int e)
                }
 
                case FL_PUSH: {
-
                        push_x = Fl::event_x() - x();
                        old_x  = x();
                        old_w  = w();
 
                        if (Fl::event_button3()) {
                                fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK);
-                               remove();
+                               removeAction();
                                hide();   // for Windows
                                Fl::delete_widget(this);
                                static_cast<geNoteEditor*>(parent())->redraw();
@@ -302,8 +248,11 @@ int gePianoItem::handle(int e)
 
                case FL_RELEASE: {
 
-                       /* delete & record the action, only if it doesn't overlap with
-                        * another one */
+
+                       gePianoRoll* pianoRoll = static_cast<gePianoRoll*>(parent());
+
+                       /* Delete and record the action, only if it doesn't overlap with another 
+                       existing one. */
 
                        if (overlap()) {
                                resize(old_x, y(), old_w, h());
@@ -311,15 +260,15 @@ int gePianoItem::handle(int e)
                        }
                        else
                        if (changed) {
-                               remove();
-                               note    = getNote(getRelY());
-                               frame_a = getRelX() * pParent->zoom;
-                               frame_b = (getRelX()+w()) * pParent->zoom;
-                               record();
+                               removeAction();
+                               int note    = pianoRoll->yToNote(getRelY());
+                               int frame_a = getRelX() * pParent->zoom;
+                               int frame_b = (getRelX()+w()) * pParent->zoom;
+                               pianoRoll->recordAction(note, frame_a, frame_b);
                                changed = false;
                        }
 
-                       static_cast<geNoteEditor*>(parent())->redraw();
+                       pianoRoll->redraw();
 
                        ret = 1;
                        break;
@@ -332,18 +281,9 @@ int gePianoItem::handle(int e)
 /* -------------------------------------------------------------------------- */
 
 
-int gePianoItem::getNote(int rel_y)
-{
-  return gePianoRoll::MAX_KEYS - (rel_y / gePianoRoll::CELL_H);
-}
-
-
-/* -------------------------------------------------------------------------- */
-
-
 int gePianoItem::getRelY()
 {
-  return y() - parent()->y();
+       return y() - parent()->y();
 }
 
 
@@ -352,5 +292,5 @@ int gePianoItem::getRelY()
 
 int gePianoItem::getRelX()
 {
-  return x() - parent()->x();
+       return x() - parent()->x();
 }
index 9f3418c35a0b97e6c25b0dd4e0c5a08537c1c095..a3a3f3abc44492920c72cb0ae272855ba5edb5fc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -30,6 +30,7 @@
 
 
 #include "../../../core/recorder.h"
+#include "../../../core/midiEvent.h"
 #include "basePianoItem.h"
 
 
@@ -40,75 +41,55 @@ class gePianoItem : public geBasePianoItem
 {
 private:
 
-       /* getRelX/Y
-        * return x/y point of this item, relative to piano roll (and not to
-        * entire screen) */
-
-       int getRelY();
-       int getRelX();
-
-       /* getNote
-        * from a relative_y return the real MIDI note, range 0-127. 15 is
-        * the hardcoded value for note height in pixels */
-
-       int getNote(int rel_y);
-
-       /* overlap
-        * check if this item don't overlap with another one. */
-
-       bool overlap();
-
-       struct giada::m::recorder::action *a;
-       struct giada::m::recorder::action *b;
-
-       int  push_x;
-
-       /* MIDI note, start frame, end frame - Used only if it's a newly added
-        * action */ /** FIXME - is it true? */
+       struct giada::m::recorder::action a;
+       struct giada::m::recorder::action b;
 
-       int  note;
-       int  frame_a;
-       int  frame_b;
+       int push_x;
 
-       /* event - bitmasked MIDI events, generated by record() or by ctor if
-        * not newly added action */
-
-       int event_a;
-       int event_b;
-
-       /* changed - if Item has been moved or resized: re-recording needed */
+       /* changed
+       If Item has been moved or resized: re-recording needed. */
 
        bool changed;
 
-       /* onLeft,RightEdge - if cursor is on a widget's edge */
+       /* onLeft, RightEdge
+       If cursor is on a widget's edge. */
 
        bool onLeftEdge;
        bool onRightEdge;
 
-       /* old_x, old_w - store previous width and position while dragging
-        * and moving, in order to restore it if overlap */
+       /* old_x, old_w
+       Store previous width and position while dragging and moving, in order to 
+       restore it if overlap. */
 
        int old_x, old_w;
 
+       /* getRelX/Y
+       Returns x/y point of this item, relative to piano roll (and not to entire 
+       screen). */
+
+       int getRelY();
+       int getRelX();
+
+       /* overlap
+       Checks if this item don't overlap with another one. */
+
+       bool overlap();
+
 public:
 
        static const int MIN_WIDTH    = 10;
        static const int HANDLE_WIDTH = 5;
 
-       /* pianoItem ctor
-        * if action *a == nullptr, record a new action */
-
        gePianoItem(int x, int y, int rel_x, int rel_y, 
-               struct giada::m::recorder::action *a, struct giada::m::recorder::action *b, 
-               gdActionEditor *pParent);
-
+               struct giada::m::recorder::action a, struct giada::m::recorder::action b, 
+               gdActionEditorpParent);
        void draw() override;
        int handle(int e) override;
 
   void reposition(int pianoRollX) override;
 
-       void record();
-       void remove();
+       void removeAction();
 };
 
 
index 00ffa14c2c8a151d5c4ad23be2dba3b7b0c09d6d..fc3290969afbecc5d475320931f7f82eeb80a606 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -41,12 +41,12 @@ using namespace giada::m;
 
 
 gePianoItemOrphaned::gePianoItemOrphaned(int x, int y, int xRel, int yRel,
-  recorder::action *action, gdActionEditor *pParent)
+  recorder::action action, gdActionEditor* pParent)
   : geBasePianoItem(x, y, WIDTH, pParent)
 {
-  note  = kernelMidi::getB2(action->iValue);
-  frame = action->frame;
-  event = action->iValue;
+  note  = kernelMidi::getB2(action.iValue);
+  frame = action.frame;
+  event = action.iValue;
   int newX = xRel + (frame / pParent->zoom);
   int newY = yRel + getY(note);
   resize(newX, newY, w(), h());
index d89abdc6481228f2503dfb6a08286dd994087bd6..b7d214c00b25560f359a09b895dadf87afaf53c9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -49,7 +49,7 @@ public:
   static const int WIDTH = 12;
 
   gePianoItemOrphaned(int x, int y, int xRel, int yRel,
-    struct giada::m::recorder::action *action, gdActionEditor *pParent);
+    struct giada::m::recorder::action action, gdActionEditor* pParent);
 
   void draw() override;
   int handle(int e) override;
index 90b4a100ff81c16fe0b1d84770d2589d5a0b4de7..e28656b0f15249ea777dc6f3d1c7c17394732480 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -33,6 +33,8 @@
 #include "../../../core/recorder.h"
 #include "../../../core/kernelMidi.h"
 #include "../../../utils/log.h"
+#include "../../../utils/string.h"
+#include "../../../glue/recorder.h"
 #include "../../dialogs/gd_actionEditor.h"
 #include "pianoItem.h"
 #include "pianoItemOrphaned.h"
 #include "pianoRoll.h"
 
 
-using namespace giada::m;
+using std::string;
+using std::vector;
+using namespace giada;
 
 
-gePianoRoll::gePianoRoll(int X, int Y, int W, gdActionEditor *pParent)
-  : geBaseActionEditor(X, Y, W, 40, pParent),
-    cursorOnItem      (false)
+gePianoRoll::gePianoRoll(int X, int Y, int W, gdActionEditor* pParent)
+       : geBaseActionEditor(X, Y, W, 40, pParent)
 {
+
        resizable(nullptr);                   // don't resize children (i.e. pianoItem)
        size(W, (MAX_KEYS+1) * CELL_H);      // 128 MIDI channels * CELL_H height
 
-       if (conf::pianoRollY == -1)
+       if (m::conf::pianoRollY == -1)
                position(x(), y()-(h()/2));  // center
        else
-               position(x(), conf::pianoRollY);
+               position(x(), m::conf::pianoRollY);
 
        drawSurface1();
        drawSurface2();
 
-       /* Add actions when the window is opened. Position is zoom-based. MIDI actions
-  come always in pair: noteOn + noteOff. */
-
-       recorder::sortActions();
-
-       recorder::action *a2   = nullptr;
-       recorder::action *prev = nullptr;
-
-       for (unsigned i=0; i<recorder::frames.size(); i++) {
-
-    if (recorder::frames.at(i) > clock::getTotalFrames()) // don't show actions > gray area
-      continue;
-
-    for (unsigned j=0; j<recorder::global.at(i).size(); j++) {
-
-                       recorder::action *a1 = recorder::global.at(i).at(j);
-
-      /* Skip action if:
-        - does not belong to this channel
-        - is not a MIDI action (we only want MIDI things here)
-        - is the previous one (we have already checked it)
-        - (later on) is not a MIDI Note On type. We don't want any other kind of
-          action here */
-
-      if (a1->chan != pParent->chan->index)
-                               continue;
-      if (a1->type != G_ACTION_MIDI)
-        continue;
-                       if (a1 == prev)
-                               continue;
-
-                       /* Extract MIDI infos from a1: if is note off skip it, we are looking for
-      noteOn only. */
-
-                       int a1_type = kernelMidi::getB1(a1->iValue);
-                       int a1_note = kernelMidi::getB2(a1->iValue);
-
-      /* If two same notes are found (noteOn-noteOn, noteOff-noteOff) or the
-      very first action is a noteOff, add orphaned item.*/
-
-      if ((prev && a1_type == prev->type) || a1_type == 0x80) {
-        gu_log("[geNoteEditor] invalid note pair! Add orphaned item\n");
-        new gePianoItemOrphaned(0, 0, x(), y(), a1, pParent);
-        a2 = nullptr;
-        continue;
-      }
-
-      /* Now skip anything that is not a noteOn. */
-
-                       if (a1_type != 0x90)
-                               continue;
+       build();
+}
 
-                       /* Search for the next action. Must have: same channel, G_ACTION_MIDI,
-      greater than a1->frame and with MIDI properties of note_off (0x80), same
-      note of a1, any velocity value (0xFF) because we just don't care about the
-      velocity of a note_off. */
 
-                       recorder::getNextAction(a1->chan, G_ACTION_MIDI, a1->frame, &a2,
-                                       kernelMidi::getIValue(0x80, a1_note, 0xFF));
+/* -------------------------------------------------------------------------- */
 
-                       /* Next action note_off found: add a new gePianoItem to piano roll. Add
-      an orphaned piano item otherwise.  */
 
-                       if (a2) {
-                               new gePianoItem(0, 0, x(), y(), a1, a2, pParent);
-                               prev = a2;
-                               a2 = nullptr;
-                       }
-                       else {
-        gu_log("[geNoteEditor] noteOff not found! Add orphaned item\n");
-        new gePianoItemOrphaned(0, 0, x(), y(), a1, pParent);
-      }
-         }
+void gePianoRoll::build()
+{
+       using namespace m::recorder;
+       
+       clear();
+
+       int channel  = pParent->chan->index;
+       int maxFrame = m::clock::getTotalFrames();
+
+       vector<Composite> actions = c::recorder::getMidiActions(channel, maxFrame); 
+       for (Composite composite : actions)
+       {
+               m::MidiEvent e1 = composite.a1.iValue;
+               m::MidiEvent e2 = composite.a2.iValue;
+
+               gu_log("[gePianoRoll] ((0x%X, 0x%X, f=%d) - (0x%X, 0x%X, f=%d))\n", 
+                       e1.getStatus(), e1.getNote(), composite.a1.frame,
+                       e2.getStatus(), e2.getNote(), composite.a2.frame
+               );
+
+               if (composite.a2.frame != -1)
+                       add(new gePianoItem(0, 0, x(), y(), composite.a1, composite.a2, pParent));
+               else
+                       add(new gePianoItemOrphaned(0, 0, x(), y(), composite.a1, pParent));
        }
 
-       end();
+       redraw();
 }
 
 
@@ -159,57 +121,57 @@ void gePianoRoll::drawSurface1()
 
                /* print key note label. C C# D D# E F F# G G# A A# B */
 
-               char note[6];
+               string note = gu_iToString(octave);
                switch (i % KEYS) {
                        case (int) Notes::G:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%d G", octave);
+                               note += " G"; 
                                break;
                        case (int) Notes::FS:
-                               sprintf(note, "%d F#", octave);
+                               note += " F#";
                                break;
                        case (int) Notes::F:
-                               sprintf(note, "%d F", octave);
+                               note += " F";
                                break;
                        case (int) Notes::E:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%d E", octave);
+                               note += " E";
                                break;
                        case (int) Notes::DS:
-                               sprintf(note, "%d D#", octave);
+                               note += " D#";
                                break;
                        case (int) Notes::D:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%d D", octave);
+                               note += " D";
                                break;
                        case (int) Notes::CS:
-                               sprintf(note, "%d C#", octave);
+                               note += " C#";
                                break;
                        case (int) Notes::C:
-                               sprintf(note, "%d C", octave);
+                               note += " C";
                                octave--;
                                break;
                        case (int) Notes::B:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%d B", octave);
+                               note += " B";
                                break;
                        case (int) Notes::AS:
-                               sprintf(note, "%d A#", octave);
+                               note += " A#";
                                break;
                        case (int) Notes::A:
                                fl_rectf(0, i*CELL_H, CELL_W, CELL_H, G_COLOR_GREY_2);
-                               sprintf(note, "%d A", octave);
+                               note += " A";
                                break;
                        case (int) Notes::GS:
-                               sprintf(note, "%d G#", octave);
+                               note += " G#";
                                break;
                }
 
-    /* Print note name */
+               /* Print note name */
 
                fl_color(G_COLOR_GREY_3);
-               fl_draw(note, 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 */
 
@@ -278,7 +240,6 @@ void gePianoRoll::draw()
 int gePianoRoll::handle(int e)
 {
        int ret = Fl_Group::handle(e);
-
        switch (e) {
                case FL_PUSH:   {
 
@@ -289,41 +250,35 @@ int gePianoRoll::handle(int e)
                                break;
                        }
 
-
                        push_y = Fl::event_y() - y();
 
                        if (Fl::event_button1()) {
 
-                               /* ax is driven by grid, ay by the height in px of each note */
+                               /* ax is driven by grid, ay by the height in px of each note. */
 
                                int ax = Fl::event_x();
                                int ay = Fl::event_y();
 
-                               /* vertical snap */
+                               /* Vertical snap. */
 
                                int edge = (ay-y()) % CELL_H;
                                if (edge != 0) ay -= edge;
 
-                               /* if no overlap, add new piano item. Also check that it doesn't
-                                * overflow on the grey area, by shifting it to the left if
-                                * necessary. */
-
-        if (!cursorOnItem) {
-                                       int greyover = ax+20 - pParent->coverX-x();
-                                       if (greyover > 0)
-                                               ax -= greyover;
-                                       add(new gePianoItem(ax, ay, ax-x(), ay-y(), nullptr, nullptr, pParent));
-                                       redraw();
-                               }
+                               /* If there are no pianoItems below the mouse, add a new one. */
+
+                               gePianoItem* pianoItem = dynamic_cast<gePianoItem*>(Fl::belowmouse());
+                               if (pianoItem == nullptr)
+                                       recordAction(yToNote(ay-y()), (ax-x()) * pParent->zoom);
                        }
                        ret = 1;
                        break;
                }
+
                case FL_DRAG:   {
 
                        if (Fl::event_button3()) {
 
-                               geNoteEditor *prc = static_cast<geNoteEditor*>(parent());
+                               geNoteEditorprc = static_cast<geNoteEditor*>(parent());
                                position(x(), Fl::event_y() - push_y);
 
                                if (y() > prc->y())
@@ -337,6 +292,7 @@ int gePianoRoll::handle(int e)
                        ret = 1;
                        break;
                }
+
                case FL_MOUSEWHEEL: {   // nothing to do, just avoid small internal scroll
                        ret = 1;
                        break;
@@ -349,6 +305,25 @@ int gePianoRoll::handle(int e)
 /* -------------------------------------------------------------------------- */
 
 
+void gePianoRoll::recordAction(int note, int frame_a, int frame_b)
+{
+       c::recorder::recordMidiAction(pParent->chan->index, note, frame_a, frame_b);
+       pParent->chan->hasActions = true;
+       build();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+int gePianoRoll::yToNote(int y)
+{
+       return gePianoRoll::MAX_KEYS - (y / gePianoRoll::CELL_H);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
 void gePianoRoll::updateActions()
 {
        for (int k=0; k<children(); k++)
index 0f78ef829ccf4863078b09911271559756bcdd5f..59cf2193b9a11e716659cfcf34df981ac914fb53 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -46,6 +46,11 @@ private:
                A = 11, GS = 0
        };
 
+       int push_y;
+
+       Fl_Offscreen surface1;  // notes, no repeat
+       Fl_Offscreen surface2;  // lines, x-repeat
+
        /* drawSurface*
        Generates a complex drawing in memory first and copy it to the screen at a
        later point in time. Fl_Offscreen surface holds the necessary data.     The first
@@ -57,10 +62,8 @@ private:
        void drawSurface1();
        void drawSurface2();
 
-       int push_y;
 
-       Fl_Offscreen surface1;  // notes, no repeat
-       Fl_Offscreen surface2;  // lines, x-repeat
+       void build();
 
 public:
 
@@ -70,21 +73,19 @@ public:
        static const int CELL_H      = 18;
        static const int CELL_W      = 40;
 
-       gePianoRoll(int x, int y, int w, gdActionEditor *pParent);
+       gePianoRoll(int x, int y, int w, gdActionEditorpParent);
 
-       void draw();
-       int  handle(int e);
+       void draw() override;
+       int  handle(int e) override;
 
   /* updateActions
   Repositions existing actions after a zoom gesture. */
   
-       void updateActions();
+       void updateActions() override;
 
-       /* cursorOnItem
-       Defines wheter the cursor is over a piano item. This value is updated by each
-       gePianoItem sub-widget. */
+       void recordAction(int note, int frame_a, int frame_b=0);
 
-       bool cursorOnItem;
+       int yToNote(int y);
 };
 
 
index 6aa636ed57e61c009820b5239e7cc20dffa386b9..ca8c84c9ae50b411b9a02aa41398e01c0b6abfef 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e628cca30e489993e214cf07fad66b3743154b90..f2dffeda7ab0dd2c3fe046a4ba500291e32d19a2 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 42f448472ceabaca54974bfd26b300fb1eebaaa1..6b15e1a15e43360964a42614c06967c6fbbd741d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 8b96a72a6302dfde6ece624914caf349e1b84869..c73a8ebece4c87a4e6822b7d6063d21f0c70f993 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 90a6f7866d77db62deab17c4abfe944f13a038d5..d22510da1538f5cdd77c15df39a26b6c204d6ef0 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 71d72c07c1185ae972a503dc501768721154ee5c..b4ae0ce9f385782ae2a27b149c862f27ba0a2c3a 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 73be138ad76e3a39e2bb0655d0cd8a0174fa1ef2..eb874004ec6b2f2200483e138cd176fa25582dcb 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 4d9a0858536f8e2e85de6357ea817e913e7a6d69..ce33ed12fe39944e50293a06a32f05a4220dd5e9 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5902f1d5202da206c118ec53337dabd8b94edccf..daed5493b8c4ee8dabfab2b8ed647f5640ba12a2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2d31446509590249679e661f31d25a6a1cfd7c05..4d845569368b9892b234cab609f5d99d599003a4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2a2cb93b820342a08d7f8b8136603b5b09591c1a..b0f52b3934efd80295623375c1e6c1540839bb41 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 31bd15c787a717b11d1866395b9a59c84cdf11a5..ef37938d03846327454eae3576b27efdabdc3258 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index d8f83b6a3a1fd9ec5adcaac5b8bdb03a4e3abeb3..5f65e9fa8968737811217356fcd50371fbf4a234 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 3da6030a120d1d0e51f7ba52630a55c137e55f4b..f0b93ac6297a74efcdb1bb65b0c192fc48892209 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 0da67cac329017ffed388757c324d0163a765774..3f2ffafbd2fd10f118a70dd84ef8581312a9f36f 100644 (file)
@@ -8,7 +8,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 4d37e3a7c6725b9f9a13197679f40e412ade9007..312930d076af45eaf4043c6502574cfc1721f13a 100644 (file)
@@ -8,7 +8,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 7fb318d7b278cf0bdca5fdfa577f9fd1add1aa87..6466a15a60220e75d8ff78c2c817e6d21f0c1180 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 8072ae4c244d520bbff9d90e7a0ed3e6bc0c0c5d..bef8ef898edab76f8a4b7b67fc7d29ac87646f7f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 6640377ab2040baedc020a053886c27fd7c0205f..b66a8f228777056eb8237d0d15fd7281f9a5bd0e 100644 (file)
@@ -9,7 +9,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index cdc52e13d516e657c6aa8124fb6b7c617a946636..56386845ba92a55798bf6731be8f8707d09c633c 100644 (file)
@@ -9,7 +9,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index fcde80cbbfd319e967686b881ab4ad58b1f301f7..b1a1e23d024c6ea1e38b298fadb0b9738a17d498 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5a6a68cc9706a8ae970001196c7e31b77574ccf7..d884ac99051aba62464eee2607dcecc224059bd4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index a4edf439b7d71a5ef813be0e217cf6aeb8d9f7ad..dbc40fe2316d3433875a5e75079990f000d03604 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 651b0341939ad3bf8307d8c4b13b4292c9c50901..aece5efcbec50927454ed6d8ba53329fe015b175 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index a433b44282deb2ddd8a94a96d1dcd5bc99cc5e00..6717d332a656692e8f732a805997be0f201124db 100644 (file)
@@ -20,7 +20,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 4308ddbf1e961c729f35edcef51bfdd64f134651..fb208790305561c0061ba2a7b401c44a6e33cd12 100644 (file)
@@ -20,7 +20,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -69,9 +69,9 @@ public:
 
        int handle(int e) override;
        void draw() override;
+       void resize(int x, int y, int w, int h) override;
 
        int getMinSize() const;
-       void resize(int x, int y, int w, int h);
 };
 
 
index fdd5fb87c401db95e424efabde33f540bd7660a8..273a0532ed1cc3a90454624568bfa69fde5bcda2 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5f384874b247ecd29429d36ede6e35a5ff4f98c8..92262f236ebdd4e8ce4b296a05f70fdf90263658 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 0ee6457e8dca4fdcfaab8b7c8e7624af185ee355..a984a436a1f782fa34fd5e2004ab4ec083a3435f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 0103e93888f596a5662f820de1a3a0f989edbfc3..2dd0acae2cd9172f9433e148e18c1be55f91e4c9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5a656dd19a3e62dcd2406c42b046a61d41b73c46..38b9b638b71cec1bc54bc54786ec19b55f31a81b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b174a01dbdff59b26381dbf2ec1ac0b848bed822..317a5a562fe689cd72400503ad0a4f5d56baf863 100644 (file)
@@ -7,7 +7,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b6cba42d0c9af756eb14917a1f38d297e838e215..ebc8837d08faf35d23815993df071a870543508c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 03cb85f1f5220145b1c0172e1ff7e23b07b8cb9f..ef0aa07c04fd560bcce8e7889bed8ad43b4a1ec3 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 59963c20c225b5f01e991a311422e79d3ca38cb0..7c27e409cc645fb63914f73bb2301e21da99deb4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -154,7 +154,7 @@ geTabAudio::geTabAudio(int X, int Y, int W, int H)
                int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value());
                for (int i=0; i<nfreq; i++) {
                        int freq = kernelAudio::getFreq(sounddevOut->value(), i);
-                       samplerate->add(gu_toString(freq).c_str());
+                       samplerate->add(gu_iToString(freq).c_str());
                        if (freq == conf::samplerate)
                                samplerate->value(i);
                }
@@ -179,7 +179,7 @@ geTabAudio::geTabAudio(int X, int Y, int W, int H)
        buffersize->add("1024");
        buffersize->add("2048");
        buffersize->add("4096");
-       buffersize->showItem(gu_toString(conf::buffersize).c_str());
+       buffersize->showItem(gu_iToString(conf::buffersize).c_str());
 
        rsmpQuality->add("Sinc best quality (very slow)");
        rsmpQuality->add("Sinc medium quality (slow)");
@@ -188,7 +188,7 @@ geTabAudio::geTabAudio(int X, int Y, int W, int H)
        rsmpQuality->add("Linear (very fast)");
        rsmpQuality->value(conf::rsmpQuality);
 
-       delayComp->value(gu_toString(conf::delayComp).c_str());
+       delayComp->value(gu_iToString(conf::delayComp).c_str());
        delayComp->type(FL_INT_INPUT);
        delayComp->maximum_size(5);
 
@@ -321,9 +321,8 @@ void geTabAudio::fetchInChans(int menuItem)
                return;
        }
        for (unsigned i=0; i<chs; i+=2) {
-               char str[16];
-               sprintf(str, "%d-%d", (i+1), (i+2));
-               channelsIn->add(str);
+               string tmp = gu_iToString(i+1) + "-" + gu_iToString(i+2);
+               channelsIn->add(tmp.c_str());
        }
        channelsIn->value(conf::channelsIn);
 }
@@ -345,9 +344,8 @@ void geTabAudio::fetchOutChans(int menuItem)
                return;
        }
        for (unsigned i=0; i<chs; i+=2) {
-               char str[16];
-               sprintf(str, "%d-%d", (i+1), (i+2));
-               channelsOut->add(str);
+               string tmp = gu_iToString(i+1) + "-" + gu_iToString(i+2);
+               channelsOut->add(tmp.c_str());
        }
        channelsOut->value(conf::channelsOut);
 }
index 99076662486508bc1bfa94a9a42042283519e5c4..bb3e91896f1e14835aa3c14d40dee00ac6cd89dc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e29b5f481bb4b4f4aa9f610cf084826d11559d43..4c50efc0abdc7449afd74ef02b4b49dc6ab6d74b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index d5b2802c52f63f5455475464f6f1ffdeee41e1de..d0a3ecee594e2e4250900561d0e356a05cc46449 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 31078991e69884f7a0be1f9d50dc005926bc988d..dbe3e6accf2bc6cfdc39a4798243f5430a5e1655 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 
 #include <string>
-#include <rtmidi/RtMidi.h>
 #include "../../../core/const.h"
+#ifdef G_OS_MAC
+       #include <RtMidi.h>
+#else
+       #include <rtmidi/RtMidi.h>
+#endif
 #include "../../../core/conf.h"
 #include "../../../core/midiMapConf.h"
 #include "../../../core/kernelMidi.h"
index e2249d8c838c62d0d6f3403b06dca1b5fc5d4082..8f0ee708f7b3c4f0cee0072b1612a218084e7f27 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 875e54af973a8b32a9905d4031b573e328fd8e47..7f1ab07885d111cc5748dd56b0b33ec0a1720474 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 63bb8b06030ef2c9c053bf0f625d07e6a381f63f..bf900bf3efab2f64ec74c4b9c38f54413cea1b60 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index ee9b77ef1fcddfcba6129e540ab1793dc2053d80..96b3acb67689855ba0fc88a555439b672af9e43b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 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 "../../../core/conf.h"
+#include "../../../core/graphics.h"
 #include "../../../core/pluginHost.h"
+#include "../../../glue/plugin.h"
 #include "../../../utils/string.h"
 #include "../../../utils/fs.h"
+#include "../../../utils/gui.h"
+#include "../../dialogs/window.h"
+#include "../../dialogs/gd_mainWindow.h"
+#include "../../dialogs/browser/browserDir.h"
 #include "../basics/box.h"
 #include "../basics/radio.h"
 #include "../basics/check.h"
@@ -42,6 +49,9 @@
 #include "tabPlugins.h"
 
 
+extern gdMainWindow* G_MainWin;
+
+
 using std::string;
 using namespace giada::m;
 
@@ -49,63 +59,75 @@ using namespace giada::m;
 geTabPlugins::geTabPlugins(int X, int Y, int W, int H)
        : Fl_Group(X, Y, W, H, "Plugins")
 {
-       folderPath = new geInput(x()+w()-250, y()+8, 250, 20);
-       scanButton = new geButton(x()+w()-120, folderPath->y()+folderPath->h()+8, 120, 20);
-       info       = new geBox(x(), scanButton->y()+scanButton->h()+8, w(), 242);
+       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()-120, m_folderPath->y()+m_folderPath->h()+8, 120, G_GUI_UNIT);
+       m_info       = new geBox(x(), m_scanButton->y()+m_scanButton->h()+8, w(), 242);
 
        end();
 
        labelsize(G_GUI_FONT_SIZE_BASE);
 
-       info->label("Scan in progress. Please wait...");
-       info->hide();
+       m_info->label("Scan in progress. Please wait...");
+       m_info->hide();
+
+       m_folderPath->value(conf::pluginPath.c_str());
+       m_folderPath->label("Plugins folder");
 
-       folderPath->value(conf::pluginPath.c_str());
-       folderPath->label("Plugins folder");
+       m_browse->callback(cb_browse, (void*) this);
 
-       scanButton->callback(cb_scan, (void*) this);
+       m_scanButton->callback(cb_scan, (void*) this);
 
-       updateCount();
+       refreshCount();
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geTabPlugins::updateCount()
+void geTabPlugins::refreshCount()
 {
-       string scanLabel = "Scan (" + gu_toString(pluginHost::countAvailablePlugins()) + " found)";
-       scanButton->label(scanLabel.c_str());
+       string scanLabel = "Scan (" + gu_iToString(pluginHost::countAvailablePlugins()) + " found)";
+       m_scanButton->label(scanLabel.c_str());
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geTabPlugins::cb_scan(Fl_Widget *w, void *p) { ((geTabPlugins*)p)->__cb_scan(w); }
+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_onScan(float progress, void *p)
+void geTabPlugins::cb_browse()
 {
-       string l = "Scan in progress (" + gu_toString((int)(progress*100)) + "%). Please wait...";
-       ((geTabPlugins *)p)->info->label(l.c_str());
-       Fl::wait();
+       gdBrowserDir* browser = new gdBrowserDir(0, 0, 800, 600, "Add plug-ins directory", 
+               conf::patchPath, giada::c::plugin::setPluginPathCb);
+
+       static_cast<gdWindow*>(top_window())->addSubWindow(browser);
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geTabPlugins::__cb_scan(Fl_Widget *w)
+void geTabPlugins::cb_scan()
 {
-       info->show();
-       pluginHost::scanDir(folderPath->value(), cb_onScan, (void*) this);
+       std::function<void(float)> callback = [this] (float progress) 
+       {
+               string l = "Scan in progress (" + gu_iToString((int)(progress*100)) + "%). Please wait...";
+               m_info->label(l.c_str());
+               Fl::wait();
+       };
+
+       m_info->show();
+       pluginHost::scanDirs(m_folderPath->value(), callback);
        pluginHost::saveList(gu_getHomePath() + G_SLASH + "plugins.xml");
-       info->hide();
-       updateCount();
+       m_info->hide();
+       refreshCount();
 }
 
 
@@ -114,7 +136,17 @@ void geTabPlugins::__cb_scan(Fl_Widget *w)
 
 void geTabPlugins::save()
 {
-       conf::pluginPath = folderPath->value();
+       conf::pluginPath = m_folderPath->value();
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
+void geTabPlugins::refreshVstPath()
+{
+       m_folderPath->value(conf::pluginPath.c_str());
+       m_folderPath->redraw();
 }
 
 
index 3bdddc37e0c35f3197a0500c90fccf607a2aafb9..cc8ffd9f66d7078e522e37f2ded1fdce03178ddb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -44,21 +44,24 @@ class geTabPlugins : public Fl_Group
 {
 private:
 
-       static void cb_scan  (Fl_Widget *w, void *p);
-       static void cb_onScan(float progress, void *p);
-       inline void __cb_scan(Fl_Widget *w);
+       geInput* m_folderPath;
+       geButton* m_browse;
+       geButton* m_scanButton;
+       geBox* m_info;
 
-       void updateCount();
+       static void cb_scan(Fl_Widget* w, void* p);
+       static void cb_browse(Fl_Widget* w, void* p);
+       void cb_scan();
+       void cb_browse();
 
-public:
+       void refreshCount();
 
-       geInput   *folderPath;
-       geButton *scanButton;
-       geBox     *info;
+public:
 
        geTabPlugins(int x, int y, int w, int h);
 
        void save();
+       void refreshVstPath();
 };
 
 
index 38ac667dfca0754b4341d5f99c277888e412f394..d10efed396b3a4e08a6a70bf1e7b3d27a1051635 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c5cdf422695a25fabc1826663331bb4fab1997e0..d1e5a11a2e951a3a68d94d97c54695884f11e43b 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index a74eda46ca6304ae98d9b15d5a3b839271b452ad..36c71401f905ff679c42df147c748e3816b2706c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 7314a36b84947441de914a79968305eb12239358..8a3b6bf738707d790ccfd46edbdb9cd7fae90fa8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c70371ef236ddb9f563fc6adb73e169afff8a94e..a93dee5c4ef43d76cf7eaf6d090f1636999af31c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -27,6 +27,7 @@
 
 #include <FL/fl_draw.H>
 #include "../../../../core/const.h"
+#include "../../../../utils/string.h"
 #include "channelButton.h"
 
 
@@ -56,11 +57,8 @@ void geChannelButton::setKey(int k)
 {
        if (k == 0)
                m_key = "";
-       else {
-               // FIXME - this crap won't work with unicode/utf-8
-               char c = (char) k;
-               m_key = c;
-       }
+       else 
+               m_key = static_cast<char>(k); // FIXME - What about unicode/utf-8?
 }
 
 
index b2cef9edaa7eb44f5b103f0720cc358c07bad13a..4a5958923a188f94651bd9ff754237b76ada4d76 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -42,8 +42,6 @@ public:
 
        geChannelButton(int x, int y, int w, int h, const char* l=0);
 
-       virtual int handle(int e) = 0;
-
        void draw() override;
   
        void setKey(const std::string& k);
index 07c6f335392b30845c180925d187df4472e38b8d..045be52f3e0eb5a04303c1d47555c6772f07d0d7 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2bbdcd0552603f1b663558ef962d005caf21f7fe..349474ff492487d04ac4343721285707acef04d5 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 49accc334ae682625c70c4debb188af6eaf7ca0a..509df9261a2bf594b3d5e2fa44611581ac340268 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5063c9d7b0de9dfbff4147af29ab085b60627031..ec12d2935a11af02a61a3cf98b4ae9b13b5f5dec 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 18a88bc6ac784ecd773bdb6bfb58d1f6783dfd78..70c178c0c8d264f193e234520bf7828362ca384d 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b6ea1d442565abae73ff5ce62568f6d754246d51..47f31bedb7cd67a39335a3b4bd348c4ffb5793d9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e5e0f3c7ebfc825b43a8d1e94b19cc9f06becf73..9872c669b9ef6e869200e30f780fe4ff83f2c2f1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 432364ef3e05dbfaa0b708c13864f8fbc0061853..84468772d8b7965c735e250d9dc31917b090aa74 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 7c4a11312b834aa54c92e4909f3356eaeaa4669d..5f17b2f49cad8e35db057cd6485f1ea575d3fe46 100644 (file)
@@ -55,7 +55,7 @@ extern gdMainWindow* G_MainWin;
 
 
 using std::string;
-using namespace giada::m;
+using namespace giada;
 
 
 namespace
@@ -100,7 +100,7 @@ void menuCallback(Fl_Widget* w, void* v)
                        gu_openSubWindow(G_MainWin, new gdActionEditor(gch->ch), WID_ACTION_EDITOR);
                        break;
                case Menu::CLEAR_ACTIONS_ALL:
-                       glue_clearAllActions(gch);
+                       c::recorder::clearAllActions(gch);
                        break;
                case Menu::SETUP_KEYBOARD_INPUT:
                        gu_openSubWindow(G_MainWin, new gdKeyGrabber(gch->ch), 0);
@@ -295,7 +295,7 @@ void geMidiChannel::update()
                label = mch->getName().c_str();
 
        if (mch->midiOut) 
-               label += " (ch " + gu_toString(mch->midiOutChan + 1) + " out)";
+               label += " (ch " + gu_iToString(mch->midiOutChan + 1) + " out)";
 
        mainButton->label(label.c_str());
 
index 881c6102594b9de9d198558055470fa8e128e9bb..b3bfcd4e710e86f325ca70b7b78debf83c8fbaad 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index b1ed9b433403a0f7386fab65ca70abd0836a33f6..0bfdcd07975343d4249d74ef1f8c82be8da17d6b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index f1bf9dd422ae3be70ae4d7f774152d5c9d6ef3ca..c461ff1dd6e8626bfc770a16a300c24e712400b5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 26a839c1e67f4d2169eb28c3943f4ff32811135b..c96b2eb40b4847fff015d4793e8187bdb10384be 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -61,7 +61,7 @@
 extern gdMainWindow* G_MainWin;
 
 
-using namespace giada::m;
+using namespace giada;
 
 
 namespace
@@ -109,16 +109,16 @@ void menuCallback(Fl_Widget* w, void* v)
                        break;
                }
                case Menu::LOAD_SAMPLE: {
-                       gdWindow *w = new gdBrowserLoad(conf::browserX, conf::browserY,
-                               conf::browserW, conf::browserH, "Browse sample",
-                               conf::samplePath.c_str(), glue_loadSample, gch->ch);
+                       gdWindow *w = new gdBrowserLoad(m::conf::browserX, m::conf::browserY,
+                               m::conf::browserW, m::conf::browserH, "Browse sample",
+                               m::conf::samplePath.c_str(), glue_loadSample, gch->ch);
                        gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
                        break;
                }
                case Menu::EXPORT_SAMPLE: {
-                       gdWindow *w = new gdBrowserSave(conf::browserX, conf::browserY,
-                               conf::browserW, conf::browserH, "Save sample",
-                               conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
+                       gdWindow *w = new gdBrowserSave(m::conf::browserX, m::conf::browserY,
+                               m::conf::browserW, m::conf::browserH, "Save sample",
+                               m::conf::samplePath.c_str(), "", glue_saveSample, gch->ch);
                        gu_openSubWindow(G_MainWin, w, WID_FILE_BROWSER);
                        break;
                }
@@ -148,19 +148,19 @@ void menuCallback(Fl_Widget* w, void* v)
                case Menu::__END_RESIZE_SUBMENU__:
                        break;
                case Menu::CLEAR_ACTIONS_ALL: {
-                       glue_clearAllActions(gch);
+                       c::recorder::clearAllActions(gch);
                        break;
                }
                case Menu::CLEAR_ACTIONS_MUTE: {
-                       glue_clearMuteActions(gch);
+                       c::recorder::clearMuteActions(gch);
                        break;
                }
                case Menu::CLEAR_ACTIONS_VOLUME: {
-                       glue_clearVolumeActions(gch);
+                       c::recorder::clearVolumeActions(gch);
                        break;
                }
                case Menu::CLEAR_ACTIONS_START_STOP: {
-                       glue_clearStartStopActions(gch);
+                       c::recorder::clearStartStopActions(gch);
                        break;
                }
                case Menu::RESIZE_H1: {
@@ -292,7 +292,7 @@ void geSampleChannel::__cb_openMenu()
        /* If you're recording (input or actions) no menu is allowed; you can't do
        anything, especially deallocate the channel */
 
-       if (mixer::recording || recorder::active)
+       if (m::mixer::recording || m::recorder::active)
                return;
 
        Fl_Menu_Item rclick_menu[] = {
@@ -374,10 +374,10 @@ void geSampleChannel::refresh()
        setColorsByStatus(ch->status, ch->recStatus);
 
        if (static_cast<SampleChannel*>(ch)->wave != nullptr) {
-               if (mixer::recording && ch->isArmed())
+               if (m::mixer::recording && ch->isArmed())
                        mainButton->setInputRecordMode();
-               if (recorder::active) {
-                       if (recorder::canRec(ch, clock::isRunning(), mixer::recording))
+               if (m::recorder::active) {
+                       if (m::recorder::canRec(ch, m::clock::isRunning(), m::mixer::recording))
                                mainButton->setActionRecordMode();
                }
                status->redraw(); // status invisible? sampleButton too (see below)
index 0e070bc120a79aedb94500a302ef60c635c6db65..4cb99d0428f7d99889be994f6793f7a141085376 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -57,8 +57,7 @@ public:
        void reset() override;
        void update() override;
        void refresh() override;
-
-       void changeSize(int h);
+       void changeSize(int h) override;
 
        /* show/hideActionButton
        Adds or removes 'R' button when actions are available. */
index 9e504df5b956019e52b50c1908c9e65eeeb13534..8ec528cd5a71d21eaf62ca69bc9bca81973b8e3a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index eb470713be6cd526d95728246ff1d72fd8688adb..b814fa81154ebe2bb17147456ccecc58810d9a50 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 67bc074aeb26b488bdc9f8ad5336eb35516cf2d1..e246dd83bfbe1f68edf91434d84a07db02c7c416 100644 (file)
@@ -4,7 +4,7 @@
 *
 * -----------------------------------------------------------------------------
 *
-* Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+* Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
 *
 * This file is part of Giada - Your Hardcore Loopmachine.
 *
index e65579c674bf40c9376b8049b1799fa76322e6ec..5debc8e9cd6533531d6fa8f2161f299e1349ea83 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2d7269b4237567096b187853a30099767a252868..572842a0918be419f5bd99c962d4568b861ac29b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 879e8f1392dca251f85ae7ddd4aaafa0987f7599..c6dde20a051d55d64e89608c3ee9a6ebf38fcc46 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index ac19b4f9d37eaf49c395c281231992a55d39c8cb..7a4bf3fee951497b3d9dc183b55796825cf1463f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -31,6 +31,7 @@
 #include "../../../core/clock.h"
 #include "../../../glue/main.h"
 #include "../../../utils/gui.h"
+#include "../../../utils/string.h"
 #include "../../elems/basics/button.h"
 #include "../../elems/basics/choice.h"
 #include "../../dialogs/gd_mainWindow.h"
@@ -42,6 +43,7 @@
 extern gdMainWindow *G_MainWin;
 
 
+using std::string;
 using namespace giada::m;
 
 
@@ -60,12 +62,13 @@ geMainTimer::geMainTimer(int x, int y)
 
        resizable(nullptr);   // don't resize any widget
 
-       char buf[6]; snprintf(buf, 6, "%f", clock::getBpm());
-       bpm->copy_label(buf);
-
+       bpm->copy_label(gu_fToString(clock::getBpm(), 1).c_str());
        bpm->callback(cb_bpm, (void*)this);
+
        meter->callback(cb_meter, (void*)this);
+       
        multiplier->callback(cb_multiplier, (void*)this);
+       
        divider->callback(cb_divider, (void*)this);
 
        quantizer->add("off", 0, cb_quantizer, (void*)this);
@@ -145,9 +148,7 @@ void geMainTimer::setBpm(const char *v)
 
 void geMainTimer::setBpm(float v)
 {
-       char buf[6];
-       sprintf(buf, "%.01f", v);  // only 1 decimal place (e.g. 120.0)
-       bpm->copy_label(buf);
+       bpm->copy_label(gu_fToString((float) v, 1).c_str()); // Only 1 decimal place (e.g. 120.0)
 }
 
 
@@ -176,7 +177,6 @@ void geMainTimer::setLock(bool v)
 
 void geMainTimer::setMeter(int beats, int bars)
 {
-       char buf[8];
-       sprintf(buf, "%d/%d", beats, bars);
-       meter->copy_label(buf);
+       string tmp = gu_iToString(beats) + "/" + gu_iToString(bars);
+       meter->copy_label(tmp.c_str());
 }
index 3db015193c9488789fbe336ccb056a8153623c29..c3fe66168248bf2b0723d412c8cc6e0d3f2d7e03 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 354fb06a1294e07e88ff5a28fd3f25003b9cbe29..057ce67b094108bd9e9a8e0bbfdfbb0fec925c69 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 26821efdee501533538416ce53c61a1372bd5b20..7461df3a6a20c6547927780b4793de57bc8c9e58 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5da78b4917bda50415e5bc9ab0a33b4bb74dd239..0085d6c8cfdadfd04d1399b3b512d9e560ec1cc6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  * -------------------------------------------------------------------------- */
 
 
+#include "../../utils/string.h"
+#include "../dialogs/midiIO/midiInputBase.h"
 #include "basics/boxtypes.h"
 #include "basics/button.h"
 #include "basics/box.h"
 #include "midiLearner.h"
 
 
+using std::string;
 using namespace giada::m;
 
 
-geMidiLearner::geMidiLearner(int X, int Y, int W, const char *l,
-  kernelMidi::cb_midiLearn *cb, uint32_t *param)
+geMidiLearner::geMidiLearner(int X, int Y, int W, const charl,
+  midiDispatcher::cb_midiLearn* cb, uint32_t* param, Channel* ch)
        : Fl_Group(X, Y, W, 20),
                callback(cb),
+               ch      (ch),
                param   (param)
 {
        begin();
@@ -64,12 +68,15 @@ geMidiLearner::geMidiLearner(int X, int Y, int W, const char *l,
 
 void geMidiLearner::updateValue()
 {
-       char buf[16];
-       if (*param != 0x0)
-               snprintf(buf, 9, "0x%X", *param);
+       string tmp;
+       if (*param != 0x0) {
+               tmp = "0x" + gu_iToString(*param, true); // true: hex mode
+               tmp.pop_back();  // Remove last two digits, useless in MIDI messages
+               tmp.pop_back();  // Remove last two digits, useless in MIDI messages
+       }
        else
-               snprintf(buf, 16, "(not set)");
-       value->copy_label(buf);
+               tmp = "(not set)";
+       value->copy_label(tmp.c_str());
        button->value(0);
 }
 
@@ -77,14 +84,14 @@ void geMidiLearner::updateValue()
 /* -------------------------------------------------------------------------- */
 
 
-void geMidiLearner::cb_button(Fl_Widget *v, void *p) { ((geMidiLearner*)p)->__cb_button(); }
-void geMidiLearner::cb_value(Fl_Widget *v, void *p) { ((geMidiLearner*)p)->__cb_value(); }
+void geMidiLearner::cb_button(Fl_Widget* v, void* p) { ((geMidiLearner*)p)->cb_button(); }
+void geMidiLearner::cb_value(Fl_Widget* v, void* p) { ((geMidiLearner*)p)->cb_value(); }
 
 
 /* -------------------------------------------------------------------------- */
 
 
-void geMidiLearner::__cb_value()
+void geMidiLearner::cb_value()
 {
        if (Fl::event_button() == FL_RIGHT_MOUSE) {
                *param = 0x0;
@@ -97,13 +104,14 @@ void geMidiLearner::__cb_value()
 /* -------------------------------------------------------------------------- */
 
 
-void geMidiLearner::__cb_button()
+void geMidiLearner::cb_button()
 {
        if (button->value() == 1) {
-               cbData.window  = (gdMidiInput*) parent();  // parent = gdMidiInput
+               cbData.window  = static_cast<gdMidiInputBase*>(parent()); // parent = gdMidiInput
                cbData.learner = this;
-               kernelMidi::startMidiLearn(callback, (void*)&cbData);
+               cbData.channel = ch;
+               midiDispatcher::startMidiLearn(callback, (void*)&cbData);
        }
        else
-               kernelMidi::stopMidiLearn();
+               midiDispatcher::stopMidiLearn();
 }
index 9b7e89a28854dcce5a2b556d23732d7b1039ec51..5b226a2ed7b040ca2a02156ae9729582276fe750 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 
 #include <FL/Fl_Group.H>
-#include "../../core/kernelMidi.h"
+#include "../../core/midiDispatcher.h"
 
 
-class gdMidiInput;
+class Channel;
+class gdMidiInputBase;
 class geMidiLearner;
 class geBox;
 class geButton;
@@ -44,39 +45,45 @@ class geMidiLearner : public Fl_Group
 private:
 
        /* callback
-        * cb to pass to kernelMidi. Requires two parameters:
+       Callback to pass to midiDispatcher. Requires two parameters:
         * uint32_t msg - MIDI message
         * void   *data - extra data */
 
-       giada::m::kernelMidi::cb_midiLearn *callback;
+       giada::m::midiDispatcher::cb_midiLearn* callback;
 
-       geBox     *text;
-       geButton *value;
-       geButton *button;
+       /* Channel it belongs to. Might be nullptr if the learner comes from the MIDI
+       input master window. */
 
-       static void cb_button(Fl_Widget *v, void *p);
-       static void cb_value (Fl_Widget *v, void *p);
-       inline void __cb_button();
-       inline void __cb_value();
+       Channel* ch;
+
+       geBox* text;
+       geButton* value;
+       geButton* button;
+
+       static void cb_button(Fl_Widget* v, void* p);
+       static void cb_value (Fl_Widget* v, void* p);
+       void cb_button();
+       void cb_value();
 
 public:
 
   /* cbData_t
-   * struct we pass to kernelMidi as extra parameter. */
+  Struct we pass to midiDispatcher as extra parameter. */
 
   struct cbData_t
   {
-               gdMidiInput   *window;
-               geMidiLearner *learner;
+               gdMidiInputBase* window;
+               geMidiLearner*   learner;
+               Channel*         channel;
        } cbData;
 
        /* param
         * pointer to ch->midiIn[value] */
 
-       uint32_t *param;
+       uint32_tparam;
 
-       geMidiLearner(int x, int y, int w, const char *l, 
-               giada::m::kernelMidi::cb_midiLearn *cb, uint32_t *param);
+       geMidiLearner(int x, int y, int w, const charl, 
+               giada::m::midiDispatcher::cb_midiLearn* cb, uint32_t* param, Channel* ch);
 
        void updateValue();
 };
index 11d0882335d65ad3ef13abec02c1381d818e3676..adfb9072f427cb104389e86183899c1b355e8961 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 4e2287e19434ad8fc97c47caa4dfe37d899d6aca..e442af21c1c2ab6158591499dbe084bdbffc0428 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5a6916b1e13edd4ba4e8601f3b6291a4c771c857..edc804da4ef2164f84841bcb1bdec470cb7e6742 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 268b7e66c0f1216eda43cb0a71705245029424a1..140ab156449279323f612fa848c8687f33b18a72 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e189525f8689392b75e9d80cf1078d69b03bb23f..f633afcd4c9d7aa9c8c907fdc5c91a05c99436bf 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -31,6 +31,7 @@
 #include "../../../core/waveFx.h"  
 #include "../../../glue/channel.h"
 #include "../../../utils/gui.h"
+#include "../../../utils/string.h"
 #include "../../../utils/math.h"
 #include "../../dialogs/sampleEditor.h"
 #include "../basics/dial.h"
@@ -72,11 +73,8 @@ geBoostTool::geBoostTool(int X, int Y, SampleChannel *ch)
 
 void geBoostTool::refresh()
 {
-  char buf[16];
-  float dB = gu_linearToDB(ch->getBoost());
-  sprintf(buf, "%.2f", dB);
-  input->value(buf);
-  // a dial > than it's max value goes crazy
+  input->value(gu_fToString(gu_linearToDB(ch->getBoost()), 2).c_str());  // 2 digits
+  // A dial greater than it's max value goes crazy
   dial->value(ch->getBoost() <= 10.0f ? ch->getBoost() : 10.0f);
 }
 
index f1e7875a6723e7e9a03cf2060be346e5a8d96283..d3ce34028e65216590352c5435b9c32ed04f1611 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 59eb7928df6bdeb15540bb36b7615518284d3f09..9c638d4cedbabe0406f8b13bf7090bb095cda3f1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -32,6 +32,7 @@
 #include "../../../glue/channel.h"
 #include "../../../utils/gui.h"
 #include "../../../utils/math.h"
+#include "../../../utils/string.h"
 #include "../../dialogs/sampleEditor.h"
 #include "../basics/dial.h"
 #include "../basics/input.h"
@@ -41,6 +42,9 @@
 #include "panTool.h"
 
 
+using std::string;
+
+
 gePanTool::gePanTool(int x, int y, SampleChannel *ch)
   : Fl_Group(x, y, 200, 20),
     ch      (ch)
@@ -71,17 +75,17 @@ gePanTool::gePanTool(int x, int y, SampleChannel *ch)
 void gePanTool::refresh()
 {
   dial->value(ch->getPan());
-  char buf[8];
+
   if (ch->getPan() < 0.5f) {
-    sprintf(buf, "%d L", (int) ((-ch->getPan() * 200.0f) + 100.0f));
-    input->value(buf);
+    string tmp = gu_iToString((int) ((-ch->getPan() * 200.0f) + 100.0f)) + " L";
+    input->value(tmp.c_str());
   }
   else 
   if (ch->getPan() == 0.5)
     input->value("C");
   else {
-    sprintf(buf, "%d R", (int) ((ch->getPan() * 200.0f) - 100.0f));
-    input->value(buf);
+    string tmp = gu_iToString((int) ((ch->getPan() * 200.0f) - 100.0f)) + " R";
+    input->value(tmp.c_str());
   }
 }
 
index c90ca66492dda7f5354dddcef2571d882dba84aa..e9d0cf66424c158e6e707564359022462237f6ed 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 80e231968faa0b73851a571f9d8091f192f95106..a9b7dfbd935a1eb067825f2337603373ec72bb85 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -32,6 +32,7 @@
 #include "../../../core/clock.h"
 #include "../../../glue/channel.h"
 #include "../../../utils/gui.h"
+#include "../../../utils/string.h"
 #include "../../dialogs/sampleEditor.h"
 #include "../basics/dial.h"
 #include "../basics/input.h"
@@ -82,9 +83,7 @@ gePitchTool::gePitchTool(int x, int y, SampleChannel* ch)
 void gePitchTool::refresh()
 {
   dial->value(ch->getPitch());
-  char buf[16];
-  sprintf(buf, "%.4f", ch->getPitch()); // 4 digits
-  input->value(buf);
+  input->value(gu_fToString(ch->getPitch(), 4).c_str()); // 4 digits
 }
 
 
index fd3f7ae3b04135a3c8172a4d176841654542e022..7ff9562cbbd5cb466d0a7e6ab87b7377df5a64bd 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 2125294d48a5591e60ce3f5902be80b0918cad94..88aa05d33f59cffe6ac0caba4fb1ad44a8f4948b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -73,8 +73,8 @@ geRangeTool::geRangeTool(int x, int y, SampleChannel* ch)
 
 void geRangeTool::refresh()
 {
-       m_begin->value(gu_toString(m_ch->getBegin()).c_str());
-       m_end->value(gu_toString(m_ch->getEnd()).c_str());
+       m_begin->value(gu_iToString(m_ch->getBegin()).c_str());
+       m_end->value(gu_iToString(m_ch->getEnd()).c_str());
 }
 
 
index 048038835eb84ee472b14219b2cee5b1f7fe6bcc..17dcf7fc395e7ca74149a274526bc232e569fdf3 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 83e9afefc1fcffacf20aa5f5426bc343522e8b17..bbcf127a2dadbd1c5dca8e221516d26fe14c7997 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -25,6 +25,7 @@
  * -------------------------------------------------------------------------- */
 
 
+#include <cstdlib>
 #include "../../../core/const.h"
 #include "../../../core/sampleChannel.h"
 #include "../../../utils/gui.h"
@@ -52,7 +53,7 @@ geShiftTool::geShiftTool(int x, int y, SampleChannel* ch)
 
        m_shift->type(FL_INT_INPUT);
        m_shift->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); // on focus lost or enter key
-       m_shift->value(gu_toString(ch->getShift()).c_str());
+       m_shift->value(gu_iToString(ch->getShift()).c_str());
        m_shift->callback(cb_setShift, (void*)this);
 
        m_reset->callback(cb_reset, (void*)this);
@@ -91,7 +92,7 @@ void geShiftTool::cb_reset()
 
 void geShiftTool::refresh()
 {
-       m_shift->value(gu_toString(m_ch->getShift()).c_str());
+       m_shift->value(gu_iToString(m_ch->getShift()).c_str());
 }
 
 
index 17aee46d12c888cfc3e8ed9614eebc3909a4d1cb..794ddc3a88e980b4e41f305bdb12f26c51a778ee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 3cd70486183aa6cb71dd9d88ecdddaba0aaf6d35..9fb8b46b6fc1af5ff20a9ad6fd39b08383ba57d9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 
 #include <cmath>
+#include <cstdlib>
 #include <FL/Fl_Pack.H>
 #include "../../../core/sampleChannel.h"
 #include "../../../core/const.h"
 #include "../../../glue/channel.h"
 #include "../../../utils/gui.h"
 #include "../../../utils/math.h"
+#include "../../../utils/string.h"
 #include "../basics/dial.h"
 #include "../basics/input.h"
 #include "../basics/box.h"
@@ -39,6 +41,9 @@
 #include "volumeTool.h"
 
 
+using std::string;
+
+
 geVolumeTool::geVolumeTool(int X, int Y, SampleChannel *ch)
   : Fl_Group(X, Y, 150, 20),
     ch      (ch)
@@ -63,11 +68,11 @@ geVolumeTool::geVolumeTool(int X, int Y, SampleChannel *ch)
 
 void geVolumeTool::refresh()
 {
-  char buf[16];
+  string tmp;
   float dB = gu_linearToDB(ch->volume);
-  if (dB > -INFINITY) sprintf(buf, "%.2f", dB);
-  else                sprintf(buf, "-inf");
-  input->value(buf);
+  if (dB > -INFINITY) tmp = gu_fToString(dB, 2);  // 2 digits
+  else                tmp = "-inf";
+  input->value(tmp.c_str());
   dial->value(ch->guiChannel->vol->value());
 }
 
index e6f98c1dd14679e8380bf0801d69b843f93c10ab..c526511564775f1cc3792d20fcc34b9919248684 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 7bfdb183af69c065706205ea549e295d6c3fafec..84a2824d92866e5e97efb12aa24c93f1ebc8b8b8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 6c891c9e69be9ce6a173252c73e564dc9a095202..d352d388e5037afe7e7d528849498c354c2fb79f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index dc4c980abade0687fa92095d80a2e31a092ed6d4..806356f8d9966ffa669dff9f0b798a53801ad192 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index bfddf6e88f1f6e51309be7154f3a76a08741cd54..05faaea684f6c1f41433d2caee97b5fd1045b965 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 29f9aa9d91c09d69b7ef9211d18f59988e2a2978..b078fea45fe005f9593904b47fce3e1cb5d657ef 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 0b3768ba9ad4e6165a55df3012545050e91e32e7..649f106e813a6adf635a7217ac27bdf98aa4ecfc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 9e265a4dce2a9e0ec6e847c6d4dd1177af6a3101..e168a5f21ab70dea35f214f9af50c09e52a3c4b7 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 99a6ad10bb7c495d8bac3587cf80ece9f81218e3..7e8bb19d3dc88ca05731640e1bb7a08cc9b1fa64 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 6c6f4b56d3cfee9609939872f208ebbd905bbfc5..69519e9fab3b4ddca81701d93e1722d1972a15c3 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index a732be8a0cdc8ea10a9a9be461a1defa68d3fedc..fc5837865569fc196afa5226f0f8112cdd008895 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
  * -------------------------------------------------------------------------- */
 
 
-#include <rtmidi/RtMidi.h>
+#include "../core/const.h"
+#ifdef G_OS_MAC
+       #include <RtMidi.h>
+#else
+       #include <rtmidi/RtMidi.h>
+#endif
 #include <sndfile.h>
 #include "../deps/rtaudio-mod/RtAudio.h"
 #include "deps.h"
index ff3f331011f5afa1c45cb07128868e6e69fc23ab..e978b3b05ce58f7f78b8a08b70aa00469aaf9a62 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 53c166a7b3f8a8805b7cb9d559681c6396c4f323..4cbfba11c1ccc86f4087a9bfa2d23af2de32ce27 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 3e84fffe25f10190355123c02a712837a5aec5cf..27b0d2ef7bd47bda95fddb07d6049feeed642819 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 9752b12299525d887345bfb1d756b8e3323df765..8af7901f73fd74321b2e073dd451714a525656af 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 00a79945a8c5a910ffb962ef12e9967f2fceec56..d69ca371acb67208cd174d86ebdf7ab154131cf6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 067d8bd95a5e74702c79e021cc4a777c2cbfd72b..8cfdf8fc7d28688339946ceddcda2d6513d34cc8 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index c7e2afc233daaf66193a4503afd89888c65dea77..5f4e8e6c39437f848906ca91cbe618b45ed49198 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e89a21cd50a95d8d04858c9819003e25bae4ef6e..402b16432647139519a55c5af8c6f6f9dc395efb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 890e3bc677f4092ec644d60767a50184b5f19531..668c9f7862aae5b8a2a0ba3ae5ee26a6e275c6ee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index e19c235760e70774ca894566ff85b35c7b335581..fda5839af193b8fa6c8050d6c4c2e908a1476142 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
@@ -27,8 +27,9 @@
  * -------------------------------------------------------------------------- */
 
 
+#include <iomanip>
+#include <cstdarg>
 #include <climits>
-#include <sstream>
 #include "../core/const.h"
 #include "string.h"
 
@@ -62,23 +63,13 @@ string gu_getRealPath(const string& path)
 /* -------------------------------------------------------------------------- */
 
 
-string gu_toString(int i)
-{
-       /* std::to_string is the way to go. Unfortunately  it seems that it isn't 
-       available in gcc's standard library (libstdc++), it is however, available in
-       libc++ which comes with LLVM/clang. */
-
-#ifdef G_OS_MAC
+/* TODO - use std::to_string() */
 
+string gu_fToString(float f, int precision)
+{
        std::stringstream out;
-       out << i;
+       out << std::fixed << std::setprecision(precision) << f;
        return out.str();
-
-#else
-
-       return std::to_string(i);
-
-#endif
 }
 
 
@@ -110,6 +101,32 @@ string gu_replace(string in, const string& search, const string& replace)
 /* -------------------------------------------------------------------------- */
 
 
+std::string gu_format(const char* format, ...)
+{
+       va_list args;
+
+       /* Compute the size of the new expanded string (i.e. with replacement taken
+       into account). */
+
+       size_t size = vsnprintf(nullptr, 0, format, args);
+
+       /* Create a new temporary char array to hold the new expanded string. */
+
+       std::unique_ptr<char[]> tmp(new char[size]);
+
+       /* Fill the temporary string with the formatted data. */
+
+  va_start(args, format);
+       vsprintf(tmp.get(), format, args);
+  va_end(args);
+  
+       return string(tmp.get(), tmp.get() + size - 1); 
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+
 void gu_split(string in, string sep, vector<string>* v)
 {
        string full  = in;
index 17b446c627ac52065dd3d23db57c3069a7e0d63f..e59937e3ab0e79d103fabdea24844e866583ba0c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
 
 #include <string>
 #include <vector>
+#include <sstream>
+#include "../core/const.h"
 
 
+template <typename T>
+std::string gu_iToString(T t, bool hex=false)
+{
+       std::stringstream out;
+       if (hex)
+               out << std::hex << std::uppercase << t;
+       else
+               out << t;
+       return out.str();       
+}
+
 std::string gu_getRealPath(const std::string& path);
 
 std::string gu_replace(std::string in, const std::string& search,
@@ -42,9 +55,11 @@ std::string gu_replace(std::string in, const std::string& search,
 
 std::string gu_trim(const std::string& s);
 
-std::string gu_toString(int i);
-
 void gu_split(std::string in, std::string sep, std::vector<std::string>* v);
 
+std::string gu_fToString(float f, int precision);
+
+std::string gu_format(const char* format, ...);
+
 
 #endif
index 3318258b93ce630a5e79c4888b68c0f09bc0d617..ec3faa5656da61ad1ba0bc655d104bc48f4f770c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index 5ebd453bf777a4eb23a18c6727c4eea41cb0abe4..4afdc479e372c3657868b3845320cabdb0c1ce46 100644 (file)
@@ -6,7 +6,7 @@
  *
  * -----------------------------------------------------------------------------
  *
- * Copyright (C) 2010-2017 Giovanni A. Zuliani | Monocasual
+ * Copyright (C) 2010-2018 Giovanni A. Zuliani | Monocasual
  *
  * This file is part of Giada - Your Hardcore Loopmachine.
  *
index eda8ec8585506c28d4d9ca6a2dc7dc5319e2edab..49a988e48da89a84807bc8374cd938b5da84139b 100644 (file)
@@ -9,476 +9,494 @@ using namespace giada::m;
 
 TEST_CASE("Test Recorder")
 {
-  /* Each SECTION the TEST_CASE is executed from the start. The following
-  code is exectuted before each SECTION. */
-
-  pthread_mutex_t mutex;
-  pthread_mutex_init(&mutex, nullptr);
-
-  recorder::init();
-  REQUIRE(recorder::frames.size() == 0);
-  REQUIRE(recorder::global.size() == 0);
-
-  SECTION("Test record single action")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 50, 1, 0.5f);
-
-    REQUIRE(recorder::frames.size() == 1);
-    REQUIRE(recorder::frames.at(0) == 50);
-    REQUIRE(recorder::global.at(0).size() == 1);  // 1 action on frame #0
-    REQUIRE(recorder::global.at(0).at(0)->chan == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-    REQUIRE(recorder::global.at(0).at(0)->frame == 50);
-    REQUIRE(recorder::global.at(0).at(0)->iValue == 1);
-    REQUIRE(recorder::global.at(0).at(0)->fValue == 0.5f);
-  }
-
-  SECTION("Test record, two actions on same frame")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-    recorder::rec(0, G_ACTION_KEYREL,   50, 1, 0.5f);
-
-    REQUIRE(recorder::frames.size() == 1);    // same frame, frames.size must stay 1
-    REQUIRE(recorder::frames.at(0) == 50);
-    REQUIRE(recorder::global.at(0).size() == 2);  // 2 actions on frame #0
-
-    REQUIRE(recorder::global.at(0).at(0)->chan == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-    REQUIRE(recorder::global.at(0).at(0)->frame == 50);
-    REQUIRE(recorder::global.at(0).at(0)->iValue == 6);
-    REQUIRE(recorder::global.at(0).at(0)->fValue == 0.3f);
-
-    REQUIRE(recorder::global.at(0).at(1)->chan == 0);
-    REQUIRE(recorder::global.at(0).at(1)->type == G_ACTION_KEYREL);
-    REQUIRE(recorder::global.at(0).at(1)->frame == 50);
-    REQUIRE(recorder::global.at(0).at(1)->iValue == 1);
-    REQUIRE(recorder::global.at(0).at(1)->fValue == 0.5f);
-
-    SECTION("Test record, another action on a different frame")
-    {
-      recorder::rec(0, G_ACTION_KEYPRESS, 70, 1, 0.5f);
-
-      REQUIRE(recorder::frames.size() == 2);
-      REQUIRE(recorder::frames.at(1) == 70);
-      REQUIRE(recorder::global.at(0).size() == 2);  // 2 actions on frame #0
-      REQUIRE(recorder::global.at(1).size() == 1);  // 1 actions on frame #1
-      REQUIRE(recorder::global.at(1).at(0)->chan == 0);
-      REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYPRESS);
-      REQUIRE(recorder::global.at(1).at(0)->frame == 70);
-      REQUIRE(recorder::global.at(1).at(0)->iValue == 1);
-      REQUIRE(recorder::global.at(1).at(0)->fValue == 0.5f);
-    }
-  }
-
-  SECTION("Test retrieval")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-    recorder::rec(0, G_ACTION_KEYREL,   70, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-    recorder::rec(1, G_ACTION_KEYREL,   70, 1, 0.5f);
-    recorder::rec(2, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-    recorder::rec(2, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-    /* Give me action on chan 1, type G_ACTION_KEYREL, frame 70. */
-    recorder::action *action = nullptr;
-    REQUIRE(recorder::getAction(1, G_ACTION_KEYREL, 70, &action) == 1);
-
-    REQUIRE(action != nullptr);
-    REQUIRE(action->chan == 1);
-    REQUIRE(action->type == G_ACTION_KEYREL);
-    REQUIRE(action->frame == 70);
-    REQUIRE(action->iValue == 1);
-    REQUIRE(action->fValue == 0.5f);
-
-    /* Give me *next* action on chan 0, type G_ACTION_KEYREL, starting from frame 20.
-    Must be action #2 */
-
-    REQUIRE(recorder::getNextAction(0, G_ACTION_KEYREL, 20, &action) == 1);
-    REQUIRE(action != nullptr);
-    REQUIRE(action->chan == 0);
-    REQUIRE(action->type == G_ACTION_KEYREL);
-    REQUIRE(action->frame == 70);
-
-    /* Give me *next* action on chan 2, type G_ACTION_KEYPRESS, starting from
-    frame 200. You are requesting frame outside boundaries. */
-
-    REQUIRE(recorder::getNextAction(2, G_ACTION_KEYPRESS, 200, &action) == -1);
-
-    /* Give me *next* action on chan 2, type G_ACTION_KEYPRESS, starting from
-    frame 100. That action does not exist. */
-
-    REQUIRE(recorder::getNextAction(2, G_ACTION_KEYPRESS, 100, &action) == -2);
-  }
-
-  SECTION("Test deletion, single action")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-    recorder::rec(0, G_ACTION_KEYREL,   60, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 70, 6, 0.3f);
-    recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
-
-    /* Delete action #0, don't check values. */
-    recorder::deleteAction(0, 50, G_ACTION_KEYPRESS, false, &mutex);
-
-    REQUIRE(recorder::frames.size() == 3);
-    REQUIRE(recorder::global.size() == 3);
-
-    SECTION("Test deletion checked")
-    {
-      /* Delete action #1, check values. */
-      recorder::deleteAction(1, 70, G_ACTION_KEYPRESS, true, &mutex, 6, 0.3f);
-
-      REQUIRE(recorder::frames.size() == 2);
-      REQUIRE(recorder::global.size() == 2);
-    }
-  }
-
-  SECTION("Test deletion, range of actions")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
-    recorder::rec(0, G_ACTION_KEYREL,   60, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYPRESS, 70, 6, 0.3f);
-    recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-    recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-    /* Delete any action on channel 0 of types KEYPRESS | KEYREL between
-    frames 0 and 200. */
-
-    recorder::deleteActions(0, 0, 200, G_ACTION_KEYPRESS | G_ACTION_KEYREL, &mutex);
-
-    REQUIRE(recorder::frames.size() == 2);
-    REQUIRE(recorder::global.size() == 2);
-    REQUIRE(recorder::global.at(0).size() == 1);
-    REQUIRE(recorder::global.at(1).size() == 1);
-
-    REQUIRE(recorder::global.at(0).at(0)->chan == 1);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
-    REQUIRE(recorder::global.at(0).at(0)->frame == 100);
-    REQUIRE(recorder::global.at(0).at(0)->iValue == 6);
-    REQUIRE(recorder::global.at(0).at(0)->fValue == 0.3f);
-
-    REQUIRE(recorder::global.at(1).at(0)->chan == 1);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 120);
-    REQUIRE(recorder::global.at(1).at(0)->iValue == 1);
-    REQUIRE(recorder::global.at(1).at(0)->fValue == 0.5f);
-  }
-
-  SECTION("Test action presence")
-  {
-    recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-    recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-    recorder::deleteAction(0, 80, G_ACTION_KEYREL, false, &mutex);
-
-    REQUIRE(recorder::hasActions(0) == false);
-    REQUIRE(recorder::hasActions(1) == true);
-  }
-
-  SECTION("Test clear actions by channel")
-  {
-    recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-    recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-    recorder::clearChan(1);
-
-    REQUIRE(recorder::hasActions(0) == true);
-    REQUIRE(recorder::hasActions(1) == false);
-    REQUIRE(recorder::frames.size() == 1);
-    REQUIRE(recorder::global.size() == 1);
-    REQUIRE(recorder::global.at(0).size() == 1);
-  }
-
-  SECTION("Test clear actions by type")
-  {
-    recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYPRESS, 100, 6, 0.3f);
-    recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
-
-    /* Clear all actions of type KEYREL from channel 1. */
-
-    recorder::clearAction(1, G_ACTION_KEYREL);
-
-    REQUIRE(recorder::hasActions(0) == true);
-    REQUIRE(recorder::hasActions(1) == false);
-    REQUIRE(recorder::frames.size() == 1);
-    REQUIRE(recorder::global.size() == 1);
-    REQUIRE(recorder::global.at(0).size() == 1);
-  }
-
-  SECTION("Test clear all")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 0, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYREL,   100, 6, 0.3f);
-    recorder::rec(2, G_ACTION_KILL, 120, 1, 0.5f);
-
-    recorder::clearAll();
-    REQUIRE(recorder::frames.size() == 0);
-    REQUIRE(recorder::global.size() == 0);
-  }
-
-  SECTION("Test optimization")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS, 20, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYPRESS, 20, 1, 0.5f);
-    recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
-
-    /* Fake frame 80 without actions.*/
-    recorder::global.at(1).clear();
-
-    recorder::optimize();
-
-    REQUIRE(recorder::frames.size() == 1);
-    REQUIRE(recorder::global.size() == 1);
-    REQUIRE(recorder::global.at(0).size() == 2);
-  }
-
-  SECTION("Test BPM update")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS,  0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
-
-    recorder::updateBpm(60.0f, 120.0f, 44100);  // scaling up
-
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 40);
-
-    recorder::updateBpm(120.0f, 60.0f, 44100);  // scaling down
-
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 80);
-  }
-
-  SECTION("Test samplerate update")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYPRESS, 120, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,   150, 1, 0.5f);
-
-    recorder::updateSamplerate(44100, 22050); // scaling down
-
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 160);
-    REQUIRE(recorder::frames.at(2) == 240);
-    REQUIRE(recorder::frames.at(3) == 300);
-
-    recorder::updateSamplerate(22050, 44100); // scaling up
-
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 80);
-    REQUIRE(recorder::frames.at(2) == 120);
-    REQUIRE(recorder::frames.at(3) == 150);
-  }
-
-  SECTION("Test expand")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KILL,     200, 1, 0.5f);
-
-    recorder::expand(300, 600);
-
-    REQUIRE(recorder::frames.size() == 6);
-    REQUIRE(recorder::global.size() == 6);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 80);
-    REQUIRE(recorder::frames.at(2) == 200);
-    REQUIRE(recorder::frames.at(3) == 300);
-    REQUIRE(recorder::frames.at(4) == 380);
-    REQUIRE(recorder::frames.at(5) == 500);
-  }
-
-  SECTION("Test shrink")
-  {
-    recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
-    recorder::rec(0, G_ACTION_KILL,     200, 1, 0.5f);
-
-    recorder::shrink(100);
-
-    REQUIRE(recorder::frames.size() == 2);
-    REQUIRE(recorder::global.size() == 2);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 80);
-  }
-
-  SECTION("Test overdub, full overwrite")
-  {
-    recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF,  80, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEON,  200, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
-
-    /* Should delete all actions in between and keep the first one, plus a
-    new last action on frame 500. */
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 1024);
-    recorder::stopOverdub(500, 500, &mutex);
-
-    REQUIRE(recorder::frames.size() == 2);
-    REQUIRE(recorder::global.size() == 2);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 500);
-    REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 500);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
-  }
-
-  SECTION("Test overdub, left overlap")
-  {
-    recorder::rec(0, G_ACTION_MUTEON,  100, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
-
-    /* Overdub part of the leftmost part of a composite action. Expected result:
-    a new composite action.
-    Original:    ----|########|
-    Overdub:     |#######|-----
-    Result:      |#######|----- */
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 16);
-    recorder::stopOverdub(300, 500, &mutex);
-
-    REQUIRE(recorder::frames.size() == 2);
-    REQUIRE(recorder::global.size() == 2);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 300);
-
-    REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 300);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
-  }
-
-  SECTION("Test overdub, right overlap")
-  {
-    recorder::rec(0, G_ACTION_MUTEON,  000, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
-
-    /* Overdub part of the rightmost part of a composite action. Expected result:
-    a new composite action.
-    Original:    |########|------
-    Overdub:     -----|#######|--
-    Result:      |###||#######|-- */
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 100, 16);
-    recorder::stopOverdub(500, 500, &mutex);
-
-    REQUIRE(recorder::frames.size() == 4);
-    REQUIRE(recorder::global.size() == 4);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 84); // 100 - bufferSize (16)
-    REQUIRE(recorder::frames.at(2) == 100);
-    REQUIRE(recorder::frames.at(3) == 500);
-
-    REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 84);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
-
-    REQUIRE(recorder::global.at(2).at(0)->frame == 100);
-    REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(3).at(0)->frame == 500);
-    REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_MUTEOFF);
-  }
-
-  SECTION("Test overdub, hole diggin'")
-  {
-    recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
-
-    /* Overdub in the middle of a long, composite action. Expected result:
-    original action trimmed down plus anther action next to it. Total frames
-    should be 4.
-    Original:    |#############|
-    Overdub:     ---|#######|---
-    Result:      |#||#######|--- */
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 100, 16);
-    recorder::stopOverdub(300, 500, &mutex);
-
-    REQUIRE(recorder::frames.size() == 4);
-    REQUIRE(recorder::global.size() == 4);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 84); // 100 - bufferSize (16)
-    REQUIRE(recorder::frames.at(2) == 100);
-    REQUIRE(recorder::frames.at(3) == 300);
-
-    REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 84);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
-
-    REQUIRE(recorder::global.at(2).at(0)->frame == 100);
-    REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(3).at(0)->frame == 300);
-    REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_MUTEOFF);
-  }
-
-  SECTION("Test overdub, cover all")
-  {
-    recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 100, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEON,  120, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 200, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEON,  220, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 300, 1, 0.5f);
-
-    /* Overdub all existing actions. Expected result: a single composite one. */
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 16);
-    recorder::stopOverdub(500, 500, &mutex);
-
-    REQUIRE(recorder::frames.size() == 2);
-    REQUIRE(recorder::global.size() == 2);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 500);
-
-    REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 500);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
-  }
-
-  SECTION("Test overdub, null loop")
-  {
-    recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 500, 1, 0.5f);
-
-    /* A null loop is a loop that begins and ends on the very same frame. */
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 300, 16);
-    recorder::stopOverdub(300, 700, &mutex);
-
-    REQUIRE(recorder::frames.size() == 2);
-    REQUIRE(recorder::frames.at(0) == 0);
-    REQUIRE(recorder::frames.at(1) == 284);  // 300 - bufferSize (16)
-
-    REQUIRE(recorder::global.at(0).at(0)->frame == 0);
-    REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
-    REQUIRE(recorder::global.at(1).at(0)->frame == 284);
-    REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
-  }
-
-  SECTION("Test overdub, ring loop")
-  {
-    /* A ring loop occurs when you record the last action beyond the end of
-    the sequencer.
-    Original:    ---|#######|---
-    Overdub:     #####|------|##
-    Result:      ---|#######||#| */
-
-    recorder::rec(0, G_ACTION_MUTEON,  200, 1, 0.5f);
-    recorder::rec(0, G_ACTION_MUTEOFF, 300, 1, 0.5f);
-
-    recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 400, 16);
-    recorder::stopOverdub(250, 700, &mutex);
-
-    REQUIRE(recorder::frames.size() == 4);
-    REQUIRE(recorder::frames.at(0) == 200);
-    REQUIRE(recorder::frames.at(1) == 300);
-    REQUIRE(recorder::frames.at(2) == 400);
-    REQUIRE(recorder::frames.at(3) == 700);
-  }
+       /* Each SECTION the TEST_CASE is executed from the start. The following
+       code is exectuted before each SECTION. */
+
+       pthread_mutex_t mutex;
+       pthread_mutex_init(&mutex, nullptr);
+
+       recorder::init();
+       REQUIRE(recorder::frames.size() == 0);
+       REQUIRE(recorder::global.size() == 0);
+
+       SECTION("Test record single action")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 50, 1, 0.5f);
+
+               REQUIRE(recorder::frames.size() == 1);
+               REQUIRE(recorder::frames.at(0) == 50);
+               REQUIRE(recorder::global.at(0).size() == 1);  // 1 action on frame #0
+               REQUIRE(recorder::global.at(0).at(0)->chan == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
+               REQUIRE(recorder::global.at(0).at(0)->frame == 50);
+               REQUIRE(recorder::global.at(0).at(0)->iValue == 1);
+               REQUIRE(recorder::global.at(0).at(0)->fValue == 0.5f);
+       }
+
+       SECTION("Test record, two actions on same frame")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
+               recorder::rec(0, G_ACTION_KEYREL,   50, 1, 0.5f);
+
+               REQUIRE(recorder::frames.size() == 1);    // same frame, frames.size must stay 1
+               REQUIRE(recorder::frames.at(0) == 50);
+               REQUIRE(recorder::global.at(0).size() == 2);  // 2 actions on frame #0
+
+               REQUIRE(recorder::global.at(0).at(0)->chan == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
+               REQUIRE(recorder::global.at(0).at(0)->frame == 50);
+               REQUIRE(recorder::global.at(0).at(0)->iValue == 6);
+               REQUIRE(recorder::global.at(0).at(0)->fValue == 0.3f);
+
+               REQUIRE(recorder::global.at(0).at(1)->chan == 0);
+               REQUIRE(recorder::global.at(0).at(1)->type == G_ACTION_KEYREL);
+               REQUIRE(recorder::global.at(0).at(1)->frame == 50);
+               REQUIRE(recorder::global.at(0).at(1)->iValue == 1);
+               REQUIRE(recorder::global.at(0).at(1)->fValue == 0.5f);
+
+               SECTION("Test record, another action on a different frame")
+               {
+                       recorder::rec(0, G_ACTION_KEYPRESS, 70, 1, 0.5f);
+
+                       REQUIRE(recorder::frames.size() == 2);
+                       REQUIRE(recorder::frames.at(1) == 70);
+                       REQUIRE(recorder::global.at(0).size() == 2);  // 2 actions on frame #0
+                       REQUIRE(recorder::global.at(1).size() == 1);  // 1 actions on frame #1
+                       REQUIRE(recorder::global.at(1).at(0)->chan == 0);
+                       REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYPRESS);
+                       REQUIRE(recorder::global.at(1).at(0)->frame == 70);
+                       REQUIRE(recorder::global.at(1).at(0)->iValue == 1);
+                       REQUIRE(recorder::global.at(1).at(0)->fValue == 0.5f);
+               }
+       }
+
+       SECTION("Test retrieval")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
+               recorder::rec(0, G_ACTION_KEYREL,   70, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 50, 6, 0.3f);
+               recorder::rec(1, G_ACTION_KEYREL,   70, 1, 0.5f);
+               recorder::rec(2, G_ACTION_KEYPRESS, 100, 6, 0.3f);
+               recorder::rec(2, G_ACTION_KEYREL,   120, 1, 0.5f);
+
+               /* Give me action on chan 1, type G_ACTION_KEYREL, frame 70. */
+               recorder::action *action = nullptr;
+               REQUIRE(recorder::getAction(1, G_ACTION_KEYREL, 70, &action) == 1);
+
+               REQUIRE(action != nullptr);
+               REQUIRE(action->chan == 1);
+               REQUIRE(action->type == G_ACTION_KEYREL);
+               REQUIRE(action->frame == 70);
+               REQUIRE(action->iValue == 1);
+               REQUIRE(action->fValue == 0.5f);
+
+               /* Give me *next* action on chan 0, type G_ACTION_KEYREL, starting from frame 20.
+               Must be action #2 */
+
+               REQUIRE(recorder::getNextAction(0, G_ACTION_KEYREL, 20, &action) == 1);
+               REQUIRE(action != nullptr);
+               REQUIRE(action->chan == 0);
+               REQUIRE(action->type == G_ACTION_KEYREL);
+               REQUIRE(action->frame == 70);
+
+               /* Give me *next* action on chan 2, type G_ACTION_KEYPRESS, starting from
+               frame 200. You are requesting frame outside boundaries. */
+
+               REQUIRE(recorder::getNextAction(2, G_ACTION_KEYPRESS, 200, &action) == -1);
+
+               /* Give me *next* action on chan 2, type G_ACTION_KEYPRESS, starting from
+               frame 100. That action does not exist. */
+
+               REQUIRE(recorder::getNextAction(2, G_ACTION_KEYPRESS, 100, &action) == -2);
+       }
+
+       SECTION("Test retrieval MIDI")
+       {
+               recorder::rec(0, G_ACTION_MIDI, 0,    0x903C3F00, 0.0f);
+               recorder::rec(1, G_ACTION_MIDI, 0,    0x903D3F00, 0.0f);
+               recorder::rec(0, G_ACTION_MIDI, 1000, 0x803C2000, 0.0f);                
+               recorder::rec(0, G_ACTION_MIDI, 1050, 0x903C3F00, 0.0f);
+               recorder::rec(0, G_ACTION_MIDI, 2000, 0x803C3F00, 0.0f);
+               recorder::rec(1, G_ACTION_MIDI, 90,   0x803D3F00, 0.0f);                
+               recorder::rec(1, G_ACTION_MIDI, 1050, 0x903D3F00, 0.0f);
+               recorder::rec(1, G_ACTION_MIDI, 2000, 0x803D3F00, 0.0f);
+
+               recorder::action* result = nullptr;
+               recorder::getNextAction(0, G_ACTION_MIDI, 100, &result, 0x803CFF00, 0x0000FF00);
+
+               REQUIRE(result != nullptr);
+               REQUIRE(result->frame == 1000);
+       }
+
+       SECTION("Test deletion, single action")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
+               recorder::rec(0, G_ACTION_KEYREL,   60, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 70, 6, 0.3f);
+               recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
+
+               /* Delete action #0, don't check values. */
+               recorder::deleteAction(0, 50, G_ACTION_KEYPRESS, false, &mutex);
+
+               REQUIRE(recorder::frames.size() == 3);
+               REQUIRE(recorder::global.size() == 3);
+
+               SECTION("Test deletion checked")
+               {
+                       /* Delete action #1, check values. */
+                       recorder::deleteAction(1, 70, G_ACTION_KEYPRESS, true, &mutex, 6, 0.3f);
+
+                       REQUIRE(recorder::frames.size() == 2);
+                       REQUIRE(recorder::global.size() == 2);
+               }
+       }
+
+       SECTION("Test deletion, range of actions")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 50, 6, 0.3f);
+               recorder::rec(0, G_ACTION_KEYREL,   60, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS, 70, 6, 0.3f);
+               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
+               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
+
+               /* Delete any action on channel 0 of types KEYPRESS | KEYREL between
+               frames 0 and 200. */
+
+               recorder::deleteActions(0, 0, 200, G_ACTION_KEYPRESS | G_ACTION_KEYREL, &mutex);
+
+               REQUIRE(recorder::frames.size() == 2);
+               REQUIRE(recorder::global.size() == 2);
+               REQUIRE(recorder::global.at(0).size() == 1);
+               REQUIRE(recorder::global.at(1).size() == 1);
+
+               REQUIRE(recorder::global.at(0).at(0)->chan == 1);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_KEYPRESS);
+               REQUIRE(recorder::global.at(0).at(0)->frame == 100);
+               REQUIRE(recorder::global.at(0).at(0)->iValue == 6);
+               REQUIRE(recorder::global.at(0).at(0)->fValue == 0.3f);
+
+               REQUIRE(recorder::global.at(1).at(0)->chan == 1);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_KEYREL);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 120);
+               REQUIRE(recorder::global.at(1).at(0)->iValue == 1);
+               REQUIRE(recorder::global.at(1).at(0)->fValue == 0.5f);
+       }
+
+       SECTION("Test action presence")
+       {
+               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
+               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
+
+               recorder::deleteAction(0, 80, G_ACTION_KEYREL, false, &mutex);
+
+               REQUIRE(recorder::hasActions(0) == false);
+               REQUIRE(recorder::hasActions(1) == true);
+       }
+
+       SECTION("Test clear actions by channel")
+       {
+               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 100, 6, 0.3f);
+               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
+
+               recorder::clearChan(1);
+
+               REQUIRE(recorder::hasActions(0) == true);
+               REQUIRE(recorder::hasActions(1) == false);
+               REQUIRE(recorder::frames.size() == 1);
+               REQUIRE(recorder::global.size() == 1);
+               REQUIRE(recorder::global.at(0).size() == 1);
+       }
+
+       SECTION("Test clear actions by type")
+       {
+               recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS, 100, 6, 0.3f);
+               recorder::rec(1, G_ACTION_KEYREL,   120, 1, 0.5f);
+
+               /* Clear all actions of type KEYREL from channel 1. */
+
+               recorder::clearAction(1, G_ACTION_KEYREL);
+
+               REQUIRE(recorder::hasActions(0) == true);
+               REQUIRE(recorder::hasActions(1) == false);
+               REQUIRE(recorder::frames.size() == 1);
+               REQUIRE(recorder::global.size() == 1);
+               REQUIRE(recorder::global.at(0).size() == 1);
+       }
+
+       SECTION("Test clear all")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 0, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYREL,   100, 6, 0.3f);
+               recorder::rec(2, G_ACTION_KILL, 120, 1, 0.5f);
+
+               recorder::clearAll();
+               REQUIRE(recorder::frames.size() == 0);
+               REQUIRE(recorder::global.size() == 0);
+       }
+
+       SECTION("Test optimization")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS, 20, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYPRESS, 20, 1, 0.5f);
+               recorder::rec(1, G_ACTION_KEYREL,   80, 1, 0.5f);
+
+               /* Fake frame 80 without actions.*/
+               recorder::global.at(1).clear();
+
+               recorder::optimize();
+
+               REQUIRE(recorder::frames.size() == 1);
+               REQUIRE(recorder::global.size() == 1);
+               REQUIRE(recorder::global.at(0).size() == 2);
+       }
+
+       SECTION("Test BPM update")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS,  0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,   80, 1, 0.5f);
+
+               recorder::updateBpm(60.0f, 120.0f, 44100);  // scaling up
+
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 40);
+
+               recorder::updateBpm(120.0f, 60.0f, 44100);  // scaling down
+
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 80);
+       }
+
+       SECTION("Test samplerate update")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYPRESS, 120, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,   150, 1, 0.5f);
+
+               recorder::updateSamplerate(44100, 22050); // scaling down
+
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 160);
+               REQUIRE(recorder::frames.at(2) == 240);
+               REQUIRE(recorder::frames.at(3) == 300);
+
+               recorder::updateSamplerate(22050, 44100); // scaling up
+
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 80);
+               REQUIRE(recorder::frames.at(2) == 120);
+               REQUIRE(recorder::frames.at(3) == 150);
+       }
+
+       SECTION("Test expand")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KILL,     200, 1, 0.5f);
+
+               recorder::expand(300, 600);
+
+               REQUIRE(recorder::frames.size() == 6);
+               REQUIRE(recorder::global.size() == 6);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 80);
+               REQUIRE(recorder::frames.at(2) == 200);
+               REQUIRE(recorder::frames.at(3) == 300);
+               REQUIRE(recorder::frames.at(4) == 380);
+               REQUIRE(recorder::frames.at(5) == 500);
+       }
+
+       SECTION("Test shrink")
+       {
+               recorder::rec(0, G_ACTION_KEYPRESS,   0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KEYREL,    80, 1, 0.5f);
+               recorder::rec(0, G_ACTION_KILL,     200, 1, 0.5f);
+
+               recorder::shrink(100);
+
+               REQUIRE(recorder::frames.size() == 2);
+               REQUIRE(recorder::global.size() == 2);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 80);
+       }
+
+       SECTION("Test overdub, full overwrite")
+       {
+               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF,  80, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEON,  200, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+
+               /* Should delete all actions in between and keep the first one, plus a
+               new last action on frame 500. */
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 1024);
+               recorder::stopOverdub(500, 500, &mutex);
+
+               REQUIRE(recorder::frames.size() == 2);
+               REQUIRE(recorder::global.size() == 2);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 500);
+               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 500);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+       }
+
+       SECTION("Test overdub, left overlap")
+       {
+               recorder::rec(0, G_ACTION_MUTEON,  100, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+
+               /* Overdub part of the leftmost part of a composite action. Expected result:
+               a new composite action.
+               Original:    ----|########|
+               Overdub:     |#######|-----
+               Result:      |#######|----- */
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 16);
+               recorder::stopOverdub(300, 500, &mutex);
+
+               REQUIRE(recorder::frames.size() == 2);
+               REQUIRE(recorder::global.size() == 2);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 300);
+
+               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 300);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+       }
+
+       SECTION("Test overdub, right overlap")
+       {
+               recorder::rec(0, G_ACTION_MUTEON,  000, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+
+               /* Overdub part of the rightmost part of a composite action. Expected result:
+               a new composite action.
+               Original:    |########|------
+               Overdub:     -----|#######|--
+               Result:      |###||#######|-- */
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 100, 16);
+               recorder::stopOverdub(500, 500, &mutex);
+
+               REQUIRE(recorder::frames.size() == 4);
+               REQUIRE(recorder::global.size() == 4);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 84); // 100 - bufferSize (16)
+               REQUIRE(recorder::frames.at(2) == 100);
+               REQUIRE(recorder::frames.at(3) == 500);
+
+               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 84);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+
+               REQUIRE(recorder::global.at(2).at(0)->frame == 100);
+               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(3).at(0)->frame == 500);
+               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_MUTEOFF);
+       }
+
+       SECTION("Test overdub, hole diggin'")
+       {
+               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 400, 1, 0.5f);
+
+               /* Overdub in the middle of a long, composite action. Expected result:
+               original action trimmed down plus anther action next to it. Total frames
+               should be 4.
+               Original:    |#############|
+               Overdub:     ---|#######|---
+               Result:      |#||#######|--- */
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 100, 16);
+               recorder::stopOverdub(300, 500, &mutex);
+
+               REQUIRE(recorder::frames.size() == 4);
+               REQUIRE(recorder::global.size() == 4);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 84); // 100 - bufferSize (16)
+               REQUIRE(recorder::frames.at(2) == 100);
+               REQUIRE(recorder::frames.at(3) == 300);
+
+               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 84);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+
+               REQUIRE(recorder::global.at(2).at(0)->frame == 100);
+               REQUIRE(recorder::global.at(2).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(3).at(0)->frame == 300);
+               REQUIRE(recorder::global.at(3).at(0)->type == G_ACTION_MUTEOFF);
+       }
+
+       SECTION("Test overdub, cover all")
+       {
+               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 100, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEON,  120, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 200, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEON,  220, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 300, 1, 0.5f);
+
+               /* Overdub all existing actions. Expected result: a single composite one. */
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 0, 16);
+               recorder::stopOverdub(500, 500, &mutex);
+
+               REQUIRE(recorder::frames.size() == 2);
+               REQUIRE(recorder::global.size() == 2);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 500);
+
+               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 500);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+       }
+
+       SECTION("Test overdub, null loop")
+       {
+               recorder::rec(0, G_ACTION_MUTEON,    0, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 500, 1, 0.5f);
+
+               /* A null loop is a loop that begins and ends on the very same frame. */
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 300, 16);
+               recorder::stopOverdub(300, 700, &mutex);
+
+               REQUIRE(recorder::frames.size() == 2);
+               REQUIRE(recorder::frames.at(0) == 0);
+               REQUIRE(recorder::frames.at(1) == 284);  // 300 - bufferSize (16)
+
+               REQUIRE(recorder::global.at(0).at(0)->frame == 0);
+               REQUIRE(recorder::global.at(0).at(0)->type == G_ACTION_MUTEON);
+               REQUIRE(recorder::global.at(1).at(0)->frame == 284);
+               REQUIRE(recorder::global.at(1).at(0)->type == G_ACTION_MUTEOFF);
+       }
+
+       SECTION("Test overdub, ring loop")
+       {
+               /* A ring loop occurs when you record the last action beyond the end of
+               the sequencer.
+               Original:    ---|#######|---
+               Overdub:     #####|------|##
+               Result:      ---|#######||#| */
+
+               recorder::rec(0, G_ACTION_MUTEON,  200, 1, 0.5f);
+               recorder::rec(0, G_ACTION_MUTEOFF, 300, 1, 0.5f);
+
+               recorder::startOverdub(0, G_ACTION_MUTEON | G_ACTION_MUTEOFF, 400, 16);
+               recorder::stopOverdub(250, 700, &mutex);
+
+               REQUIRE(recorder::frames.size() == 4);
+               REQUIRE(recorder::frames.at(0) == 200);
+               REQUIRE(recorder::frames.at(1) == 300);
+               REQUIRE(recorder::frames.at(2) == 400);
+               REQUIRE(recorder::frames.at(3) == 700);
+       }
 }
index 852b77a86802fce6f0bb1d63121780c9a3d8dcbd..07fb31c1a9a4d769bb962f034fab2321c77a06ec 100644 (file)
@@ -25,7 +25,11 @@ TEST_CASE("Test string utils")
 {
   REQUIRE(gu_replace("Giada is cool", "cool", "hot") == "Giada is hot");
   REQUIRE(gu_trim("   Giada is cool       ") == "Giada is cool");
-  REQUIRE(gu_toString(666) == "666");
+  REQUIRE(gu_iToString(666) == "666");
+  REQUIRE(gu_iToString(0x99AABB, true) == "99AABB");
+  REQUIRE(gu_fToString(3.14159, 2) == "3.14");
+  // Catch can't handle this so far?
+  //REQUIRE(gu_format("I see %d men with %s hats", 5, "strange") == "I see 5 men with strange hats");
 
   vector<std::string> v;
   gu_split("Giada is cool", " ", &v);