From 89ba29f1c5b51978e4e80daeac971e358d14d2ec Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jarom=C3=ADr=20Mike=C5=A1?= Date: Tue, 16 Jan 2018 07:06:13 +0100 Subject: [PATCH] New upstream version 0.14.5~dfsg1 --- .travis/after_success.sh | 17 + .travis/before_install.sh | 12 + .travis/before_script.sh | 13 + .travis/install.sh | 89 ++ .travis/script.sh | 5 + ChangeLog | 15 + Makefile.am | 240 +++-- README.md | 2 +- configure.ac | 56 +- src/core/channel.cpp | 49 +- src/core/channel.h | 31 +- src/core/clock.cpp | 2 +- src/core/clock.h | 2 +- src/core/conf.cpp | 20 +- src/core/conf.h | 10 +- src/core/const.h | 60 +- src/core/graphics.cpp | 2 +- src/core/graphics.h | 2 +- src/core/init.cpp | 4 +- src/core/init.h | 2 +- src/core/kernelAudio.cpp | 33 +- src/core/kernelAudio.h | 4 +- src/core/kernelMidi.cpp | 280 +---- src/core/kernelMidi.h | 8 +- src/core/midiChannel.cpp | 55 +- src/core/midiChannel.h | 4 +- src/core/midiDispatcher.cpp | 276 +++++ src/core/midiDispatcher.h | 53 + src/core/midiEvent.cpp | 132 +++ src/core/midiEvent.h | 78 ++ src/core/midiMapConf.cpp | 4 +- src/core/midiMapConf.h | 2 +- src/core/mixer.cpp | 30 +- src/core/mixer.h | 12 +- src/core/mixerHandler.cpp | 13 +- src/core/mixerHandler.h | 2 +- src/core/patch.cpp | 8 +- src/core/patch.h | 3 +- src/core/plugin.cpp | 5 +- src/core/plugin.h | 2 +- src/core/pluginHost.cpp | 26 +- src/core/pluginHost.h | 42 +- src/core/recorder.cpp | 71 +- src/core/recorder.h | 33 +- src/core/sampleChannel.cpp | 2 +- src/core/sampleChannel.h | 2 +- src/core/storager.cpp | 2 +- src/core/storager.h | 2 +- src/core/wave.cpp | 4 +- src/core/wave.h | 2 +- src/core/waveFx.cpp | 2 +- src/core/waveFx.h | 2 +- src/core/waveManager.cpp | 2 +- src/core/waveManager.h | 2 +- src/glue/channel.cpp | 2 +- src/glue/channel.h | 2 +- src/glue/io.cpp | 12 +- src/glue/io.h | 2 +- src/glue/main.cpp | 4 +- src/glue/main.h | 2 +- src/glue/plugin.cpp | 87 +- src/glue/plugin.h | 9 +- src/glue/recorder.cpp | 167 ++- src/glue/recorder.h | 32 +- src/glue/sampleEditor.cpp | 2 +- src/glue/sampleEditor.h | 4 +- src/glue/storage.cpp | 4 +- src/glue/storage.h | 2 +- src/glue/transport.cpp | 2 +- src/glue/transport.h | 2 +- src/gui/dialogs/beatsInput.cpp | 6 +- src/gui/dialogs/beatsInput.h | 2 +- src/gui/dialogs/bpmInput.cpp | 4 +- src/gui/dialogs/bpmInput.h | 2 +- src/gui/dialogs/browser/browserBase.cpp | 24 +- src/gui/dialogs/browser/browserBase.h | 15 +- src/gui/dialogs/browser/browserDir.cpp | 85 ++ src/gui/dialogs/browser/browserDir.h | 54 + src/gui/dialogs/browser/browserLoad.cpp | 2 +- src/gui/dialogs/browser/browserLoad.h | 9 +- src/gui/dialogs/browser/browserSave.cpp | 4 +- src/gui/dialogs/browser/browserSave.h | 10 +- src/gui/dialogs/channelNameInput.cpp | 2 +- src/gui/dialogs/channelNameInput.h | 2 +- src/gui/dialogs/gd_about.cpp | 12 +- src/gui/dialogs/gd_about.h | 2 +- src/gui/dialogs/gd_actionEditor.cpp | 9 +- src/gui/dialogs/gd_actionEditor.h | 2 +- src/gui/dialogs/gd_config.cpp | 26 +- src/gui/dialogs/gd_config.h | 28 +- src/gui/dialogs/gd_devInfo.cpp | 12 +- src/gui/dialogs/gd_devInfo.h | 2 +- src/gui/dialogs/gd_keyGrabber.cpp | 17 +- src/gui/dialogs/gd_keyGrabber.h | 2 +- src/gui/dialogs/gd_mainWindow.cpp | 2 +- src/gui/dialogs/gd_mainWindow.h | 2 +- src/gui/dialogs/gd_warnings.cpp | 2 +- src/gui/dialogs/gd_warnings.h | 2 +- src/gui/dialogs/midiIO/midiInputBase.cpp | 44 +- src/gui/dialogs/midiIO/midiInputBase.h | 19 +- src/gui/dialogs/midiIO/midiInputChannel.cpp | 173 ++-- src/gui/dialogs/midiIO/midiInputChannel.h | 33 +- src/gui/dialogs/midiIO/midiInputMaster.cpp | 98 +- src/gui/dialogs/midiIO/midiInputMaster.h | 16 +- src/gui/dialogs/midiIO/midiOutputBase.cpp | 11 +- src/gui/dialogs/midiIO/midiOutputBase.h | 2 +- src/gui/dialogs/midiIO/midiOutputMidiCh.cpp | 16 +- src/gui/dialogs/midiIO/midiOutputMidiCh.h | 2 +- src/gui/dialogs/midiIO/midiOutputSampleCh.cpp | 13 +- src/gui/dialogs/midiIO/midiOutputSampleCh.h | 2 +- src/gui/dialogs/pluginChooser.cpp | 2 +- src/gui/dialogs/pluginChooser.h | 2 +- src/gui/dialogs/pluginList.cpp | 43 +- src/gui/dialogs/pluginList.h | 30 +- src/gui/dialogs/pluginWindow.cpp | 10 +- src/gui/dialogs/pluginWindow.h | 3 +- src/gui/dialogs/pluginWindowGUI.cpp | 2 +- src/gui/dialogs/pluginWindowGUI.h | 2 +- src/gui/dialogs/sampleEditor.cpp | 12 +- src/gui/dialogs/sampleEditor.h | 2 +- src/gui/dialogs/window.cpp | 2 +- src/gui/dialogs/window.h | 2 +- src/gui/elems/actionEditor/action.cpp | 2 +- src/gui/elems/actionEditor/action.h | 2 +- src/gui/elems/actionEditor/actionEditor.cpp | 2 +- src/gui/elems/actionEditor/actionEditor.h | 2 +- .../elems/actionEditor/baseActionEditor.cpp | 2 +- src/gui/elems/actionEditor/baseActionEditor.h | 2 +- src/gui/elems/actionEditor/basePianoItem.cpp | 2 +- src/gui/elems/actionEditor/basePianoItem.h | 2 +- src/gui/elems/actionEditor/envelopeEditor.cpp | 2 +- src/gui/elems/actionEditor/envelopeEditor.h | 2 +- src/gui/elems/actionEditor/gridTool.cpp | 2 +- src/gui/elems/actionEditor/gridTool.h | 2 +- src/gui/elems/actionEditor/muteEditor.cpp | 2 +- src/gui/elems/actionEditor/muteEditor.h | 2 +- src/gui/elems/actionEditor/noteEditor.cpp | 2 +- src/gui/elems/actionEditor/noteEditor.h | 2 +- src/gui/elems/actionEditor/pianoItem.cpp | 142 +-- src/gui/elems/actionEditor/pianoItem.h | 75 +- .../elems/actionEditor/pianoItemOrphaned.cpp | 10 +- .../elems/actionEditor/pianoItemOrphaned.h | 4 +- src/gui/elems/actionEditor/pianoRoll.cpp | 193 ++-- src/gui/elems/actionEditor/pianoRoll.h | 25 +- src/gui/elems/basics/baseButton.cpp | 2 +- src/gui/elems/basics/baseButton.h | 2 +- src/gui/elems/basics/box.cpp | 2 +- src/gui/elems/basics/box.h | 2 +- src/gui/elems/basics/boxtypes.cpp | 2 +- src/gui/elems/basics/boxtypes.h | 2 +- src/gui/elems/basics/button.cpp | 2 +- src/gui/elems/basics/button.h | 2 +- src/gui/elems/basics/check.cpp | 2 +- src/gui/elems/basics/check.h | 2 +- src/gui/elems/basics/choice.cpp | 2 +- src/gui/elems/basics/choice.h | 2 +- src/gui/elems/basics/dial.cpp | 2 +- src/gui/elems/basics/dial.h | 2 +- src/gui/elems/basics/idButton.cpp | 2 +- src/gui/elems/basics/idButton.h | 2 +- src/gui/elems/basics/input.cpp | 2 +- src/gui/elems/basics/input.h | 2 +- src/gui/elems/basics/liquidScroll.cpp | 2 +- src/gui/elems/basics/liquidScroll.h | 2 +- src/gui/elems/basics/progress.cpp | 2 +- src/gui/elems/basics/progress.h | 2 +- src/gui/elems/basics/radio.cpp | 2 +- src/gui/elems/basics/radio.h | 2 +- src/gui/elems/basics/resizerBar.cpp | 2 +- src/gui/elems/basics/resizerBar.h | 4 +- src/gui/elems/basics/scroll.cpp | 2 +- src/gui/elems/basics/scroll.h | 2 +- src/gui/elems/basics/slider.cpp | 2 +- src/gui/elems/basics/slider.h | 2 +- src/gui/elems/basics/statusButton.cpp | 2 +- src/gui/elems/basics/statusButton.h | 2 +- src/gui/elems/browser.cpp | 2 +- src/gui/elems/browser.h | 2 +- src/gui/elems/config/tabAudio.cpp | 18 +- src/gui/elems/config/tabAudio.h | 2 +- src/gui/elems/config/tabBehaviors.cpp | 2 +- src/gui/elems/config/tabBehaviors.h | 2 +- src/gui/elems/config/tabMidi.cpp | 8 +- src/gui/elems/config/tabMidi.h | 2 +- src/gui/elems/config/tabMisc.cpp | 2 +- src/gui/elems/config/tabMisc.h | 2 +- src/gui/elems/config/tabPlugins.cpp | 80 +- src/gui/elems/config/tabPlugins.h | 21 +- src/gui/elems/mainWindow/beatMeter.cpp | 2 +- src/gui/elems/mainWindow/beatMeter.h | 2 +- src/gui/elems/mainWindow/keyboard/channel.cpp | 2 +- src/gui/elems/mainWindow/keyboard/channel.h | 2 +- .../mainWindow/keyboard/channelButton.cpp | 10 +- .../elems/mainWindow/keyboard/channelButton.h | 4 +- .../elems/mainWindow/keyboard/channelMode.cpp | 2 +- .../elems/mainWindow/keyboard/channelMode.h | 2 +- .../mainWindow/keyboard/channelStatus.cpp | 2 +- .../elems/mainWindow/keyboard/channelStatus.h | 2 +- src/gui/elems/mainWindow/keyboard/column.cpp | 2 +- src/gui/elems/mainWindow/keyboard/column.h | 2 +- .../elems/mainWindow/keyboard/keyboard.cpp | 2 +- src/gui/elems/mainWindow/keyboard/keyboard.h | 2 +- .../elems/mainWindow/keyboard/midiChannel.cpp | 6 +- .../elems/mainWindow/keyboard/midiChannel.h | 2 +- .../mainWindow/keyboard/midiChannelButton.cpp | 2 +- .../mainWindow/keyboard/midiChannelButton.h | 2 +- .../mainWindow/keyboard/sampleChannel.cpp | 32 +- .../elems/mainWindow/keyboard/sampleChannel.h | 5 +- .../keyboard/sampleChannelButton.cpp | 2 +- .../mainWindow/keyboard/sampleChannelButton.h | 2 +- src/gui/elems/mainWindow/mainIO.cpp | 2 +- src/gui/elems/mainWindow/mainIO.h | 2 +- src/gui/elems/mainWindow/mainMenu.cpp | 2 +- src/gui/elems/mainWindow/mainMenu.h | 2 +- src/gui/elems/mainWindow/mainTimer.cpp | 20 +- src/gui/elems/mainWindow/mainTimer.h | 2 +- src/gui/elems/mainWindow/mainTransport.cpp | 2 +- src/gui/elems/mainWindow/mainTransport.h | 2 +- src/gui/elems/midiLearner.cpp | 38 +- src/gui/elems/midiLearner.h | 43 +- src/gui/elems/plugin/pluginBrowser.cpp | 2 +- src/gui/elems/plugin/pluginBrowser.h | 2 +- src/gui/elems/plugin/pluginParameter.cpp | 2 +- src/gui/elems/plugin/pluginParameter.h | 2 +- src/gui/elems/sampleEditor/boostTool.cpp | 10 +- src/gui/elems/sampleEditor/boostTool.h | 2 +- src/gui/elems/sampleEditor/panTool.cpp | 16 +- src/gui/elems/sampleEditor/panTool.h | 2 +- src/gui/elems/sampleEditor/pitchTool.cpp | 7 +- src/gui/elems/sampleEditor/pitchTool.h | 2 +- src/gui/elems/sampleEditor/rangeTool.cpp | 6 +- src/gui/elems/sampleEditor/rangeTool.h | 2 +- src/gui/elems/sampleEditor/shiftTool.cpp | 7 +- src/gui/elems/sampleEditor/shiftTool.h | 2 +- src/gui/elems/sampleEditor/volumeTool.cpp | 15 +- src/gui/elems/sampleEditor/volumeTool.h | 2 +- src/gui/elems/sampleEditor/waveTools.cpp | 2 +- src/gui/elems/sampleEditor/waveTools.h | 2 +- src/gui/elems/sampleEditor/waveform.cpp | 2 +- src/gui/elems/sampleEditor/waveform.h | 2 +- src/gui/elems/soundMeter.cpp | 2 +- src/gui/elems/soundMeter.h | 2 +- src/main.cpp | 2 +- src/utils/cocoa.h | 2 +- src/utils/cocoa.mm | 2 +- src/utils/deps.cpp | 9 +- src/utils/deps.h | 2 +- src/utils/fs.cpp | 2 +- src/utils/fs.h | 2 +- src/utils/gui.cpp | 2 +- src/utils/gui.h | 2 +- src/utils/log.cpp | 2 +- src/utils/log.h | 2 +- src/utils/math.cpp | 2 +- src/utils/math.h | 2 +- src/utils/string.cpp | 49 +- src/utils/string.h | 21 +- src/utils/time.cpp | 2 +- src/utils/time.h | 2 +- tests/recorder.cpp | 962 +++++++++--------- tests/utils.cpp | 6 +- 261 files changed, 3101 insertions(+), 2011 deletions(-) create mode 100755 .travis/after_success.sh create mode 100755 .travis/before_install.sh create mode 100755 .travis/before_script.sh create mode 100755 .travis/install.sh create mode 100755 .travis/script.sh create mode 100644 src/core/midiDispatcher.cpp create mode 100644 src/core/midiDispatcher.h create mode 100644 src/core/midiEvent.cpp create mode 100644 src/core/midiEvent.h create mode 100644 src/gui/dialogs/browser/browserDir.cpp create mode 100644 src/gui/dialogs/browser/browserDir.h diff --git a/.travis/after_success.sh b/.travis/after_success.sh new file mode 100755 index 0000000..64612e1 --- /dev/null +++ b/.travis/after_success.sh @@ -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 index 0000000..17d5a97 --- /dev/null +++ b/.travis/before_install.sh @@ -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 index 0000000..73e0df2 --- /dev/null +++ b/.travis/before_script.sh @@ -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 index 0000000..066b194 --- /dev/null +++ b/.travis/install.sh @@ -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 index 0000000..49f67c4 --- /dev/null +++ b/.travis/script.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +make -j 2 +make rename +make check -j 2 \ No newline at end of file diff --git a/ChangeLog b/ChangeLog index cf11e2b..dbca39f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,21 @@ -------------------------------------------------------------------------------- +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 diff --git a/Makefile.am b/Makefile.am index e008f62..3c2f529 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 ------------------------------------------------------------------ diff --git a/README.md b/README.md index 9da5e2a..1fa51c3 100644 --- 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. diff --git a/configure.ac b/configure.ac index c518a2c..bc80952 100644 --- a/configure.ac +++ b/configure.ac @@ -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 # ------------------------------------------------------------------------------ diff --git a/src/core/channel.cpp b/src/core/channel.cpp index 95aa43e..b11f82c 100644 --- a/src/core/channel.cpp +++ b/src/core/channel.cpp @@ -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_t& msg) { 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; jsetParameter(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; +} + + /* -------------------------------------------------------------------------- */ diff --git a/src/core/channel.h b/src/core/channel.h index 72e6f2d..a43b157 100644 --- a/src/core/channel.h +++ b/src/core/channel.h @@ -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 #include #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 diff --git a/src/core/clock.cpp b/src/core/clock.cpp index 1a7e5d5..a62d0b0 100644 --- a/src/core/clock.cpp +++ b/src/core/clock.cpp @@ -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. * diff --git a/src/core/clock.h b/src/core/clock.h index fd39f46..de2972d 100644 --- a/src/core/clock.h +++ b/src/core/clock.h @@ -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. * diff --git a/src/core/conf.cpp b/src/core/conf.cpp index e32c289..0914d96 100644 --- a/src/core/conf.cpp +++ b/src/core/conf.cpp @@ -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)); diff --git a/src/core/conf.h b/src/core/conf.h index 024c734..b881d6d 100644 --- a/src/core/conf.h +++ b/src/core/conf.h @@ -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; diff --git a/src/core/const.h b/src/core/const.h index 7e48358..78b8b9e 100644 --- a/src/core/const.h +++ b/src/core/const.h @@ -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,10 +46,10 @@ /* -- 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" @@ -140,31 +140,32 @@ #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" diff --git a/src/core/graphics.cpp b/src/core/graphics.cpp index f9be05a..c6be10f 100644 --- a/src/core/graphics.cpp +++ b/src/core/graphics.cpp @@ -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. * diff --git a/src/core/graphics.h b/src/core/graphics.h index b137786..a09cdb7 100644 --- a/src/core/graphics.h +++ b/src/core/graphics.h @@ -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. * diff --git a/src/core/init.cpp b/src/core/init.cpp index 6104874..86fcf89 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -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, diff --git a/src/core/init.h b/src/core/init.h index 19833d4..b670580 100644 --- a/src/core/init.h +++ b/src/core/init.h @@ -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. * diff --git a/src/core/kernelAudio.cpp b/src/core/kernelAudio.cpp index d9fe65c..15bb1eb 100644 --- a/src/core/kernelAudio.cpp +++ b/src/core/kernelAudio.cpp @@ -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); diff --git a/src/core/kernelAudio.h b/src/core/kernelAudio.h index 21358c4..6dacf29 100644 --- a/src/core/kernelAudio.h +++ b/src/core/kernelAudio.h @@ -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(); diff --git a/src/core/kernelMidi.cpp b/src/core/kernelMidi.cpp index 8a19181..22331e5 100644 --- a/src/core/kernelMidi.cpp +++ b/src/core/kernelMidi.cpp @@ -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,24 +25,15 @@ * -------------------------------------------------------------------------- */ -#include -#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 +#else + #include #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* plugins. */ - - vector* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch); - - for (Plugin* plugin : *plugins) { - for (unsigned k=0; kmidiInParams.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(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* 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; isize(); i++) @@ -231,32 +64,7 @@ static void callback(double t, std::vector* 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* msg, void* data) void sendMidiLightningInitMsgs() { - for(unsigned i=0; igetPortCount(); - gu_log("[KM] %d output MIDI ports found\n", numOutPorts); - for (unsigned i=0; igetPortCount(); - gu_log("[KM] %d input MIDI ports found\n", numInPorts); - for (unsigned i=0; i msg(1, getB1(data)); - msg.push_back(getB2(data)); - msg.push_back(getB3(data)); + vector 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); } diff --git a/src/core/kernelMidi.h b/src/core/kernelMidi.h index 700a78a..d1c8e86 100644 --- a/src/core/kernelMidi.h +++ b/src/core/kernelMidi.h @@ -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. * @@ -35,18 +35,12 @@ #include #endif #include -#include 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); diff --git a/src/core/midiChannel.cpp b/src/core/midiChannel.cpp index fe58e7f..695fb3c 100644 --- a/src/core/midiChannel.cpp +++ b/src/core/midiChannel.cpp @@ -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; + } } diff --git a/src/core/midiChannel.h b/src/core/midiChannel.h index 8b2cd56..4617c45 100644 --- a/src/core/midiChannel.h +++ b/src/core/midiChannel.h @@ -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 index 0000000..c8a9d94 --- /dev/null +++ b/src/core/midiDispatcher.cpp @@ -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 + * . + * + * -------------------------------------------------------------------------- */ + + +#include +#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* plugins. */ + + vector* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch); + + for (Plugin* plugin : *plugins) { + for (unsigned k=0; kmidiInParams.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(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 index 0000000..395622e --- /dev/null +++ b/src/core/midiDispatcher.h @@ -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 + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef G_MIDI_DISPATCHER_H +#define G_MIDI_DISPATCHER_H + + +#ifdef __APPLE__ // our Clang still doesn't know about cstdint (c++11 stuff) + #include +#else + #include +#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 index 0000000..ae11319 --- /dev/null +++ b/src/core/midiEvent.cpp @@ -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 + * . + * + * -------------------------------------------------------------------------- */ + + +#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 index 0000000..fb31369 --- /dev/null +++ b/src/core/midiEvent.h @@ -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 + * . + * + * -------------------------------------------------------------------------- */ + + +#ifndef G_MIDI_EVENT_H +#define G_MIDI_EVENT_H + + +#include + + +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 diff --git a/src/core/midiMapConf.cpp b/src/core/midiMapConf.cpp index 5d28774..9c13008 100644 --- a/src/core/midiMapConf.cpp +++ b/src/core/midiMapConf.cpp @@ -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; diff --git a/src/core/midiMapConf.h b/src/core/midiMapConf.h index 7080705..0e73e7d 100644 --- a/src/core/midiMapConf.h +++ b/src/core/midiMapConf.h @@ -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. * diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index 350769a..f5ac5c8 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -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; iclear(); + 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; irewind(); + for (Channel* ch : channels) + ch->rewind(); } @@ -538,12 +538,14 @@ void rewind() void mergeVirtualInput() { - for (unsigned i=0; itype == CHANNEL_MIDI) + assert(vChanInput != nullptr); + + for (Channel* ch : channels) { + if (ch->type == CHANNEL_MIDI) continue; - SampleChannel *ch = static_cast(channels.at(i)); - if (ch->isArmed()) - memcpy(ch->wave->getData(), vChanInput, clock::getTotalFrames() * sizeof(float)); + SampleChannel* sch = static_cast(ch); + if (sch->isArmed()) + memcpy(sch->wave->getData(), vChanInput, clock::getTotalFrames() * sizeof(float)); } memset(vChanInput, 0, clock::getTotalFrames() * sizeof(float)); // clear vchan } diff --git a/src/core/mixer.h b/src/core/mixer.h index e1709dc..87aef5e 100644 --- a/src/core/mixer.h +++ b/src/core/mixer.h @@ -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(); diff --git a/src/core/mixerHandler.cpp b/src/core/mixerHandler.cpp index 40220a7..119f95e 100644 --- a/src/core/mixerHandler.cpp +++ b/src/core/mixerHandler.cpp @@ -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 " diff --git a/src/core/mixerHandler.h b/src/core/mixerHandler.h index 18b0283..c1cd2ba 100644 --- a/src/core/mixerHandler.h +++ b/src/core/mixerHandler.h @@ -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. * diff --git a/src/core/patch.cpp b/src/core/patch.cpp index b70ea9e..d954ffb 100644 --- a/src/core/patch.cpp +++ b/src/core/patch.cpp @@ -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* 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)); diff --git a/src/core/patch.h b/src/core/patch.h index bfc757e..28b11d0 100644 --- a/src/core/patch.h +++ b/src/core/patch.h @@ -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; diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index ce2b58e..d6b32fa 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -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()); } diff --git a/src/core/plugin.h b/src/core/plugin.h index 8091d8e..988c20a 100644 --- a/src/core/plugin.h +++ b/src/core/plugin.h @@ -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. * diff --git a/src/core/pluginHost.cpp b/src/core/pluginHost.cpp index 6ca0006..f7faccb 100644 --- a/src/core/pluginHost.cpp +++ b/src/core/pluginHost.cpp @@ -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& 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 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()); diff --git a/src/core/pluginHost.h b/src/core/pluginHost.h index f36bf41..a98cb02 100644 --- a/src/core/pluginHost.h +++ b/src/core/pluginHost.h @@ -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 #include #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& 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. */ diff --git a/src/core/recorder.cpp b/src/core/recorder.cpp index c760ae1..ff319ad 100644 --- a/src/core/recorder.cpp +++ b/src/core/recorder.cpp @@ -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; + action* next = 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(Channel* ch, 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_t* mixerMutex, 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_t* mixerMutex) { sortActions(); vector 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 (; ichan == 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; itype == 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(ch); + if (sch->mode & (LOOP_ANY) && sch->status == STATUS_OFF && sch->isArmed()) + sch->start(clock::getCurrentFrame(), true, clock::getQuantize(), clock::isRunning(), true, true); } diff --git a/src/glue/io.h b/src/glue/io.h index 110d5f2..3377be9 100644 --- a/src/glue/io.h +++ b/src/glue/io.h @@ -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. * diff --git a/src/glue/main.cpp b/src/glue/main.cpp index 2067261..6de32a7 100644 --- a/src/glue/main.cpp +++ b/src/glue/main.cpp @@ -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()); } diff --git a/src/glue/main.h b/src/glue/main.h index 8357e28..3644f93 100644 --- a/src/glue/main.h +++ b/src/glue/main.h @@ -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. * diff --git a/src/glue/plugin.cpp b/src/glue/plugin.cpp index c7928d6..20a0f8b 100644 --- a/src/glue/plugin.cpp +++ b/src/glue/plugin.cpp @@ -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,10 +33,14 @@ #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(gu_getSubwindow(G_MainWin, WID_FX_LIST)); + if (parent == nullptr) + return nullptr; + return static_cast(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(gu_getSubwindow(G_MainWin, WID_FX_LIST)); - gdPluginWindow* child = static_cast(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(gu_getSubwindow(G_MainWin, WID_CONFIG)); + configWin->refreshVstPath(); } }}}; // giada::c::plugin:: diff --git a/src/glue/plugin.h b/src/glue/plugin.h index 72041ff..d581fe2 100644 --- a/src/glue/plugin.h +++ b/src/glue/plugin.h @@ -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:: diff --git a/src/glue/recorder.cpp b/src/glue/recorder.cpp index 2bab39c..9e0a333 100644 --- a/src/glue/recorder.cpp +++ b/src/glue/recorder.cpp @@ -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. * @@ -29,24 +29,32 @@ #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(geChannel* gch) { - gch->ch->hasActions = recorder::hasActions(gch->ch->index); - if (gch->ch->type == CHANNEL_SAMPLE && !gch->ch->hasActions) - static_cast(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(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 getMidiActions(int chan, int frameLimit) +{ + vector out; + + m::recorder::sortActions(); + + for (unsigned i=0; i frameLimit) + continue; + + for (unsigned j=0; jiValue); + + /* 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 diff --git a/src/glue/recorder.h b/src/glue/recorder.h index 390f7fb..811e002 100644 --- a/src/glue/recorder.h +++ b/src/glue/recorder.h @@ -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. * @@ -29,13 +29,35 @@ #define G_GLUE_RECORDER_H +#include +#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 getMidiActions(int channel, + int frameLimit); +}}} // giada::c::recorder:: #endif diff --git a/src/glue/sampleEditor.cpp b/src/glue/sampleEditor.cpp index f5b037e..bd4e9f0 100644 --- a/src/glue/sampleEditor.cpp +++ b/src/glue/sampleEditor.cpp @@ -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. * diff --git a/src/glue/sampleEditor.h b/src/glue/sampleEditor.h index e6d1221..b38cbb2 100644 --- a/src/glue/sampleEditor.h +++ b/src/glue/sampleEditor.h @@ -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. */ diff --git a/src/glue/storage.cpp b/src/glue/storage.cpp index c9db5ee..726918e 100644 --- a/src/glue/storage.cpp +++ b/src/glue/storage.cpp @@ -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(); } diff --git a/src/glue/storage.h b/src/glue/storage.h index 83f9291..9a3e568 100644 --- a/src/glue/storage.h +++ b/src/glue/storage.h @@ -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. * diff --git a/src/glue/transport.cpp b/src/glue/transport.cpp index c3bf56e..f735f7e 100644 --- a/src/glue/transport.cpp +++ b/src/glue/transport.cpp @@ -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. * diff --git a/src/glue/transport.h b/src/glue/transport.h index 24fff6f..3b10ead 100644 --- a/src/glue/transport.h +++ b/src/glue/transport.h @@ -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. * diff --git a/src/gui/dialogs/beatsInput.cpp b/src/gui/dialogs/beatsInput.cpp index 3d77b6f..3f134bf 100644 --- a/src/gui/dialogs/beatsInput.cpp +++ b/src/gui/dialogs/beatsInput.cpp @@ -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); diff --git a/src/gui/dialogs/beatsInput.h b/src/gui/dialogs/beatsInput.h index b1d0bb8..938bd71 100644 --- a/src/gui/dialogs/beatsInput.h +++ b/src/gui/dialogs/beatsInput.h @@ -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. * diff --git a/src/gui/dialogs/bpmInput.cpp b/src/gui/dialogs/bpmInput.cpp index f76c629..b5ea70f 100644 --- a/src/gui/dialogs/bpmInput.cpp +++ b/src/gui/dialogs/bpmInput.cpp @@ -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. */ diff --git a/src/gui/dialogs/bpmInput.h b/src/gui/dialogs/bpmInput.h index 3a994ef..492ae35 100644 --- a/src/gui/dialogs/bpmInput.h +++ b/src/gui/dialogs/bpmInput.h @@ -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. * diff --git a/src/gui/dialogs/browser/browserBase.cpp b/src/gui/dialogs/browser/browserBase.cpp index 5903962..ed1f72b 100644 --- a/src/gui/dialogs/browser/browserBase.cpp +++ b/src/gui/dialogs/browser/browserBase.cpp @@ -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); +} diff --git a/src/gui/dialogs/browser/browserBase.h b/src/gui/dialogs/browser/browserBase.h index 9ca486a..ccc2485 100644 --- a/src/gui/dialogs/browser/browserBase.h +++ b/src/gui/dialogs/browser/browserBase.h @@ -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 index 0000000..daddec9 --- /dev/null +++ b/src/gui/dialogs/browser/browserDir.cpp @@ -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 + * . + * + * -------------------------------------------------------------------------- */ + + +#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 index 0000000..0c97065 --- /dev/null +++ b/src/gui/dialogs/browser/browserDir.h @@ -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 + * . + * + * -------------------------------------------------------------------------- */ + + +#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 diff --git a/src/gui/dialogs/browser/browserLoad.cpp b/src/gui/dialogs/browser/browserLoad.cpp index d8e9dd1..266c4f3 100644 --- a/src/gui/dialogs/browser/browserLoad.cpp +++ b/src/gui/dialogs/browser/browserLoad.cpp @@ -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. * diff --git a/src/gui/dialogs/browser/browserLoad.h b/src/gui/dialogs/browser/browserLoad.h index e361484..e132a34 100644 --- a/src/gui/dialogs/browser/browserLoad.h +++ b/src/gui/dialogs/browser/browserLoad.h @@ -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. * @@ -29,17 +29,10 @@ #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 diff --git a/src/gui/dialogs/browser/browserSave.cpp b/src/gui/dialogs/browser/browserSave.cpp index ad765b9..b1559a8 100644 --- a/src/gui/dialogs/browser/browserSave.cpp +++ b/src/gui/dialogs/browser/browserSave.cpp @@ -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(); } diff --git a/src/gui/dialogs/browser/browserSave.h b/src/gui/dialogs/browser/browserSave.h index 53cb61b..acfa0d6 100644 --- a/src/gui/dialogs/browser/browserSave.h +++ b/src/gui/dialogs/browser/browserSave.h @@ -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. * @@ -29,17 +29,11 @@ #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; }; diff --git a/src/gui/dialogs/channelNameInput.cpp b/src/gui/dialogs/channelNameInput.cpp index a0bd3bc..dca6fca 100644 --- a/src/gui/dialogs/channelNameInput.cpp +++ b/src/gui/dialogs/channelNameInput.cpp @@ -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. * diff --git a/src/gui/dialogs/channelNameInput.h b/src/gui/dialogs/channelNameInput.h index 86f03d5..7e4a113 100644 --- a/src/gui/dialogs/channelNameInput.h +++ b/src/gui/dialogs/channelNameInput.h @@ -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. * diff --git a/src/gui/dialogs/gd_about.cpp b/src/gui/dialogs/gd_about.cpp index 527e32c..eb9228e 100644 --- a/src/gui/dialogs/gd_about.cpp +++ b/src/gui/dialogs/gd_about.cpp @@ -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. * @@ -35,12 +35,14 @@ #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 diff --git a/src/gui/dialogs/gd_about.h b/src/gui/dialogs/gd_about.h index eeb11d2..aa93094 100644 --- a/src/gui/dialogs/gd_about.h +++ b/src/gui/dialogs/gd_about.h @@ -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. * diff --git a/src/gui/dialogs/gd_actionEditor.cpp b/src/gui/dialogs/gd_actionEditor.cpp index 723763f..becac71 100644 --- a/src/gui/dialogs/gd_actionEditor.cpp +++ b/src/gui/dialogs/gd_actionEditor.cpp @@ -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 #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); diff --git a/src/gui/dialogs/gd_actionEditor.h b/src/gui/dialogs/gd_actionEditor.h index efe3e0e..f82a6f7 100644 --- a/src/gui/dialogs/gd_actionEditor.h +++ b/src/gui/dialogs/gd_actionEditor.h @@ -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. * diff --git a/src/gui/dialogs/gd_config.cpp b/src/gui/dialogs/gd_config.cpp index 6e26b91..ce4ee29 100644 --- a/src/gui/dialogs/gd_config.cpp +++ b/src/gui/dialogs/gd_config.cpp @@ -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_Tabs* tabs = new Fl_Tabs(8, 8, w-16, h-44); tabs->box(G_CUSTOM_BORDER_BOX); tabs->labelcolor(G_COLOR_LIGHT_2); tabs->begin(); @@ -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 diff --git a/src/gui/dialogs/gd_config.h b/src/gui/dialogs/gd_config.h index 5af49f6..989f560 100644 --- a/src/gui/dialogs/gd_config.h +++ b/src/gui/dialogs/gd_config.h @@ -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; }; diff --git a/src/gui/dialogs/gd_devInfo.cpp b/src/gui/dialogs/gd_devInfo.cpp index c7c074d..2521274 100644 --- a/src/gui/dialogs/gd_devInfo.cpp +++ b/src/gui/dialogs/gd_devInfo.cpp @@ -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; icopy_label(body.c_str()); diff --git a/src/gui/dialogs/gd_devInfo.h b/src/gui/dialogs/gd_devInfo.h index f5d10d0..e65deea 100644 --- a/src/gui/dialogs/gd_devInfo.h +++ b/src/gui/dialogs/gd_devInfo.h @@ -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. * diff --git a/src/gui/dialogs/gd_keyGrabber.cpp b/src/gui/dialogs/gd_keyGrabber.cpp index f7bbd97..ea861b7 100644 --- a/src/gui/dialogs/gd_keyGrabber.cpp +++ b/src/gui/dialogs/gd_keyGrabber.cpp @@ -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(key); else - sprintf(tmp2, "Press a key.\n\nCurrent binding: [none]"); - text->copy_label(tmp2); + tmp += "[none]"; + text->copy_label(tmp.c_str()); } diff --git a/src/gui/dialogs/gd_keyGrabber.h b/src/gui/dialogs/gd_keyGrabber.h index 736fc78..d66a403 100644 --- a/src/gui/dialogs/gd_keyGrabber.h +++ b/src/gui/dialogs/gd_keyGrabber.h @@ -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. * diff --git a/src/gui/dialogs/gd_mainWindow.cpp b/src/gui/dialogs/gd_mainWindow.cpp index d3620b6..1066099 100644 --- a/src/gui/dialogs/gd_mainWindow.cpp +++ b/src/gui/dialogs/gd_mainWindow.cpp @@ -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. * diff --git a/src/gui/dialogs/gd_mainWindow.h b/src/gui/dialogs/gd_mainWindow.h index c7dbae8..64a6733 100644 --- a/src/gui/dialogs/gd_mainWindow.h +++ b/src/gui/dialogs/gd_mainWindow.h @@ -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. * diff --git a/src/gui/dialogs/gd_warnings.cpp b/src/gui/dialogs/gd_warnings.cpp index 99b9b13..fc013f8 100644 --- a/src/gui/dialogs/gd_warnings.cpp +++ b/src/gui/dialogs/gd_warnings.cpp @@ -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. * diff --git a/src/gui/dialogs/gd_warnings.h b/src/gui/dialogs/gd_warnings.h index cd770d4..fb96a8a 100644 --- a/src/gui/dialogs/gd_warnings.h +++ b/src/gui/dialogs/gd_warnings.h @@ -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. * diff --git a/src/gui/dialogs/midiIO/midiInputBase.cpp b/src/gui/dialogs/midiIO/midiInputBase.cpp index 5ec70b4..d461166 100644 --- a/src/gui/dialogs/midiIO/midiInputBase.cpp +++ b/src/gui/dialogs/midiIO/midiInputBase.cpp @@ -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 char* title) : 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(geMidiLearner* learner) { - 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, void* d) { - 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(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(); } diff --git a/src/gui/dialogs/midiIO/midiInputBase.h b/src/gui/dialogs/midiIO/midiInputBase.h index 54b09f8..646bc44 100644 --- a/src/gui/dialogs/midiIO/midiInputBase.h +++ b/src/gui/dialogs/midiIO/midiInputBase.h @@ -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 char* title); ~gdMidiInputBase(); }; diff --git a/src/gui/dialogs/midiIO/midiInputChannel.cpp b/src/gui/dialogs/midiIO/midiInputChannel.cpp index 2f02c2e..4992bb4 100644 --- a/src/gui/dialogs/midiIO/midiInputChannel.cpp +++ b/src/gui/dialogs/midiIO/midiInputChannel.cpp @@ -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,18 +27,20 @@ #include #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(Channel* ch) : 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(ch))->midiInPitch, ch); + new geMidiLearner(0, 0, LEARNER_WIDTH, "read actions", cb_learn, + &(static_cast(ch))->midiInReadActions, ch); + } + + pack->end(); } @@ -137,25 +172,25 @@ void gdMidiInputChannel::addChannelLearners() void gdMidiInputChannel::addPluginLearners() { - vector *plugins = pluginHost::getStack(pluginHost::CHANNEL, ch); - for (unsigned i=0; isize(); i++) { + vector* plugins = pluginHost::getStack(pluginHost::CHANNEL, ch); + for (unsigned i=0; isize(); 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; kgetNumParameters(); k++) - new geMidiLearner(0, 0, LEARNER_WIDTH, plugin->getParameterName(k).c_str(), - cb_learn, &plugin->midiInParams.at(k)); + for (int k=0; kgetNumParameters(); 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()); +} + diff --git a/src/gui/dialogs/midiIO/midiInputChannel.h b/src/gui/dialogs/midiIO/midiInputChannel.h index f2e9d33..523ab66 100644 --- a/src/gui/dialogs/midiIO/midiInputChannel.h +++ b/src/gui/dialogs/midiIO/midiInputChannel.h @@ -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. * @@ -34,34 +34,39 @@ #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 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(); }; diff --git a/src/gui/dialogs/midiIO/midiInputMaster.cpp b/src/gui/dialogs/midiIO/midiInputMaster.cpp index 694f585..f583bcf 100644 --- a/src/gui/dialogs/midiIO/midiInputMaster.cpp +++ b/src/gui/dialogs/midiIO/midiInputMaster.cpp @@ -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,10 +25,14 @@ * -------------------------------------------------------------------------- */ +#include #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; +} + diff --git a/src/gui/dialogs/midiIO/midiInputMaster.h b/src/gui/dialogs/midiIO/midiInputMaster.h index 52bd546..1a0bec6 100644 --- a/src/gui/dialogs/midiIO/midiInputMaster.h +++ b/src/gui/dialogs/midiIO/midiInputMaster.h @@ -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. * @@ -34,8 +34,22 @@ #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(); diff --git a/src/gui/dialogs/midiIO/midiOutputBase.cpp b/src/gui/dialogs/midiIO/midiOutputBase.cpp index e293d58..f6c3da0 100644 --- a/src/gui/dialogs/midiIO/midiOutputBase.cpp +++ b/src/gui/dialogs/midiIO/midiOutputBase.cpp @@ -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,10 +26,12 @@ #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()); } diff --git a/src/gui/dialogs/midiIO/midiOutputBase.h b/src/gui/dialogs/midiIO/midiOutputBase.h index 13a0375..343aa89 100644 --- a/src/gui/dialogs/midiIO/midiOutputBase.h +++ b/src/gui/dialogs/midiIO/midiOutputBase.h @@ -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. * diff --git a/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp b/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp index be4bfd0..ad425a5 100644 --- a/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp +++ b/src/gui/dialogs/midiIO/midiOutputMidiCh.cpp @@ -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(MidiChannel* ch) : 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"); diff --git a/src/gui/dialogs/midiIO/midiOutputMidiCh.h b/src/gui/dialogs/midiIO/midiOutputMidiCh.h index b6e9694..93fff1f 100644 --- a/src/gui/dialogs/midiIO/midiOutputMidiCh.h +++ b/src/gui/dialogs/midiIO/midiOutputMidiCh.h @@ -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. * diff --git a/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp b/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp index ad68978..e02c1a6 100644 --- a/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp +++ b/src/gui/dialogs/midiIO/midiOutputSampleCh.cpp @@ -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,15 +33,18 @@ #include "midiOutputSampleCh.h" -gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch) +gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel* ch) : 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); diff --git a/src/gui/dialogs/midiIO/midiOutputSampleCh.h b/src/gui/dialogs/midiIO/midiOutputSampleCh.h index 7050c95..3b956d3 100644 --- a/src/gui/dialogs/midiIO/midiOutputSampleCh.h +++ b/src/gui/dialogs/midiIO/midiOutputSampleCh.h @@ -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. * diff --git a/src/gui/dialogs/pluginChooser.cpp b/src/gui/dialogs/pluginChooser.cpp index b7adc89..21e5170 100644 --- a/src/gui/dialogs/pluginChooser.cpp +++ b/src/gui/dialogs/pluginChooser.cpp @@ -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. * diff --git a/src/gui/dialogs/pluginChooser.h b/src/gui/dialogs/pluginChooser.h index f74c374..cd8f483 100644 --- a/src/gui/dialogs/pluginChooser.h +++ b/src/gui/dialogs/pluginChooser.h @@ -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. * diff --git a/src/gui/dialogs/pluginList.cpp b/src/gui/dialogs/pluginList.cpp index 8b4cfb9..9ba36c2 100644 --- a/src/gui/dialogs/pluginList.cpp +++ b/src/gui/dialogs/pluginList.cpp @@ -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()); } diff --git a/src/gui/dialogs/pluginList.h b/src/gui/dialogs/pluginList.h index c8e88ce..94e49cd 100644 --- a/src/gui/dialogs/pluginList.h +++ b/src/gui/dialogs/pluginList.h @@ -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: diff --git a/src/gui/dialogs/pluginWindow.cpp b/src/gui/dialogs/pluginWindow.cpp index ede116e..51b4c28 100644 --- a/src/gui/dialogs/pluginWindow.cpp +++ b/src/gui/dialogs/pluginWindow.cpp @@ -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; igetNumParameters(); i++) { + static_cast(m_list->child(i))->update(changeSlider); + } +} + + /* -------------------------------------------------------------------------- */ diff --git a/src/gui/dialogs/pluginWindow.h b/src/gui/dialogs/pluginWindow.h index 1e0f922..49f753e 100644 --- a/src/gui/dialogs/pluginWindow.h +++ b/src/gui/dialogs/pluginWindow.h @@ -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); }; diff --git a/src/gui/dialogs/pluginWindowGUI.cpp b/src/gui/dialogs/pluginWindowGUI.cpp index ed11987..60b560c 100644 --- a/src/gui/dialogs/pluginWindowGUI.cpp +++ b/src/gui/dialogs/pluginWindowGUI.cpp @@ -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. * diff --git a/src/gui/dialogs/pluginWindowGUI.h b/src/gui/dialogs/pluginWindowGUI.h index 54731a3..d563aee 100644 --- a/src/gui/dialogs/pluginWindowGUI.h +++ b/src/gui/dialogs/pluginWindowGUI.h @@ -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. * diff --git a/src/gui/dialogs/sampleEditor.cpp b/src/gui/dialogs/sampleEditor.cpp index ea80d9f..9e98a71 100644 --- a/src/gui/dialogs/sampleEditor.cpp +++ b/src/gui/dialogs/sampleEditor.cpp @@ -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()); } diff --git a/src/gui/dialogs/sampleEditor.h b/src/gui/dialogs/sampleEditor.h index 43ac556..2d12054 100644 --- a/src/gui/dialogs/sampleEditor.h +++ b/src/gui/dialogs/sampleEditor.h @@ -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. * diff --git a/src/gui/dialogs/window.cpp b/src/gui/dialogs/window.cpp index 5797feb..a8c8ce0 100644 --- a/src/gui/dialogs/window.cpp +++ b/src/gui/dialogs/window.cpp @@ -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. * diff --git a/src/gui/dialogs/window.h b/src/gui/dialogs/window.h index 698f512..888e898 100644 --- a/src/gui/dialogs/window.h +++ b/src/gui/dialogs/window.h @@ -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. * diff --git a/src/gui/elems/actionEditor/action.cpp b/src/gui/elems/actionEditor/action.cpp index cb1b99a..8516970 100644 --- a/src/gui/elems/actionEditor/action.cpp +++ b/src/gui/elems/actionEditor/action.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/action.h b/src/gui/elems/actionEditor/action.h index cd9823f..f681d56 100644 --- a/src/gui/elems/actionEditor/action.h +++ b/src/gui/elems/actionEditor/action.h @@ -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. * diff --git a/src/gui/elems/actionEditor/actionEditor.cpp b/src/gui/elems/actionEditor/actionEditor.cpp index a9f5003..db60c35 100644 --- a/src/gui/elems/actionEditor/actionEditor.cpp +++ b/src/gui/elems/actionEditor/actionEditor.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/actionEditor.h b/src/gui/elems/actionEditor/actionEditor.h index deaf7c4..5870cca 100644 --- a/src/gui/elems/actionEditor/actionEditor.h +++ b/src/gui/elems/actionEditor/actionEditor.h @@ -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. * diff --git a/src/gui/elems/actionEditor/baseActionEditor.cpp b/src/gui/elems/actionEditor/baseActionEditor.cpp index 56aa786..0f11b31 100644 --- a/src/gui/elems/actionEditor/baseActionEditor.cpp +++ b/src/gui/elems/actionEditor/baseActionEditor.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/baseActionEditor.h b/src/gui/elems/actionEditor/baseActionEditor.h index f907b57..d0862de 100644 --- a/src/gui/elems/actionEditor/baseActionEditor.h +++ b/src/gui/elems/actionEditor/baseActionEditor.h @@ -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. * diff --git a/src/gui/elems/actionEditor/basePianoItem.cpp b/src/gui/elems/actionEditor/basePianoItem.cpp index 11c3806..439c91a 100644 --- a/src/gui/elems/actionEditor/basePianoItem.cpp +++ b/src/gui/elems/actionEditor/basePianoItem.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/basePianoItem.h b/src/gui/elems/actionEditor/basePianoItem.h index ade2fb2..41d7de4 100644 --- a/src/gui/elems/actionEditor/basePianoItem.h +++ b/src/gui/elems/actionEditor/basePianoItem.h @@ -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. * diff --git a/src/gui/elems/actionEditor/envelopeEditor.cpp b/src/gui/elems/actionEditor/envelopeEditor.cpp index 206a290..0615b7f 100644 --- a/src/gui/elems/actionEditor/envelopeEditor.cpp +++ b/src/gui/elems/actionEditor/envelopeEditor.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/envelopeEditor.h b/src/gui/elems/actionEditor/envelopeEditor.h index c9675ea..b2218ab 100644 --- a/src/gui/elems/actionEditor/envelopeEditor.h +++ b/src/gui/elems/actionEditor/envelopeEditor.h @@ -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. * diff --git a/src/gui/elems/actionEditor/gridTool.cpp b/src/gui/elems/actionEditor/gridTool.cpp index c697cd8..a481fb3 100644 --- a/src/gui/elems/actionEditor/gridTool.cpp +++ b/src/gui/elems/actionEditor/gridTool.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/gridTool.h b/src/gui/elems/actionEditor/gridTool.h index 8c56be3..2ca3eac 100644 --- a/src/gui/elems/actionEditor/gridTool.h +++ b/src/gui/elems/actionEditor/gridTool.h @@ -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. * diff --git a/src/gui/elems/actionEditor/muteEditor.cpp b/src/gui/elems/actionEditor/muteEditor.cpp index c8591e4..cba778f 100644 --- a/src/gui/elems/actionEditor/muteEditor.cpp +++ b/src/gui/elems/actionEditor/muteEditor.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/muteEditor.h b/src/gui/elems/actionEditor/muteEditor.h index 90ad87b..d70bdd8 100644 --- a/src/gui/elems/actionEditor/muteEditor.h +++ b/src/gui/elems/actionEditor/muteEditor.h @@ -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. * diff --git a/src/gui/elems/actionEditor/noteEditor.cpp b/src/gui/elems/actionEditor/noteEditor.cpp index dea9810..b0608b2 100644 --- a/src/gui/elems/actionEditor/noteEditor.cpp +++ b/src/gui/elems/actionEditor/noteEditor.cpp @@ -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. * diff --git a/src/gui/elems/actionEditor/noteEditor.h b/src/gui/elems/actionEditor/noteEditor.h index 2a63c0d..26fbaf0 100644 --- a/src/gui/elems/actionEditor/noteEditor.h +++ b/src/gui/elems/actionEditor/noteEditor.h @@ -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. * diff --git a/src/gui/elems/actionEditor/pianoItem.cpp b/src/gui/elems/actionEditor/pianoItem.cpp index 1cc5b42..acb6442 100644 --- a/src/gui/elems/actionEditor/pianoItem.cpp +++ b/src/gui/elems/actionEditor/pianoItem.cpp @@ -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,38 +41,17 @@ 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(parent()); + geNoteEditor* noteEditor = static_cast(parent()); - for (int i=0; ichildren(); i++) { + for (int i=0; ichildren(); i++) { - gePianoItem *pItem = static_cast(pPiano->child(i)); + gePianoItem* pItem = static_cast(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(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(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(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(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(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(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(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(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(); } diff --git a/src/gui/elems/actionEditor/pianoItem.h b/src/gui/elems/actionEditor/pianoItem.h index 9f3418c..a3a3f3a 100644 --- a/src/gui/elems/actionEditor/pianoItem.h +++ b/src/gui/elems/actionEditor/pianoItem.h @@ -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, + gdActionEditor* pParent); + void draw() override; int handle(int e) override; void reposition(int pianoRollX) override; - void record(); - void remove(); + void removeAction(); }; diff --git a/src/gui/elems/actionEditor/pianoItemOrphaned.cpp b/src/gui/elems/actionEditor/pianoItemOrphaned.cpp index 00ffa14..fc32909 100644 --- a/src/gui/elems/actionEditor/pianoItemOrphaned.cpp +++ b/src/gui/elems/actionEditor/pianoItemOrphaned.cpp @@ -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()); diff --git a/src/gui/elems/actionEditor/pianoItemOrphaned.h b/src/gui/elems/actionEditor/pianoItemOrphaned.h index d89abdc..b7d214c 100644 --- a/src/gui/elems/actionEditor/pianoItemOrphaned.h +++ b/src/gui/elems/actionEditor/pianoItemOrphaned.h @@ -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; diff --git a/src/gui/elems/actionEditor/pianoRoll.cpp b/src/gui/elems/actionEditor/pianoRoll.cpp index 90b4a10..e28656b 100644 --- a/src/gui/elems/actionEditor/pianoRoll.cpp +++ b/src/gui/elems/actionEditor/pianoRoll.cpp @@ -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" @@ -40,100 +42,60 @@ #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 clock::getTotalFrames()) // don't show actions > gray area - continue; - - for (unsigned j=0; jchan != 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 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(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(parent()); + geNoteEditor* prc = static_cast(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; kvalue()); for (int i=0; ivalue(), 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; iadd(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; iadd(str); + string tmp = gu_iToString(i+1) + "-" + gu_iToString(i+2); + channelsOut->add(tmp.c_str()); } channelsOut->value(conf::channelsOut); } diff --git a/src/gui/elems/config/tabAudio.h b/src/gui/elems/config/tabAudio.h index 9907666..bb3e918 100644 --- a/src/gui/elems/config/tabAudio.h +++ b/src/gui/elems/config/tabAudio.h @@ -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. * diff --git a/src/gui/elems/config/tabBehaviors.cpp b/src/gui/elems/config/tabBehaviors.cpp index e29b5f4..4c50efc 100644 --- a/src/gui/elems/config/tabBehaviors.cpp +++ b/src/gui/elems/config/tabBehaviors.cpp @@ -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. * diff --git a/src/gui/elems/config/tabBehaviors.h b/src/gui/elems/config/tabBehaviors.h index d5b2802..d0a3ece 100644 --- a/src/gui/elems/config/tabBehaviors.h +++ b/src/gui/elems/config/tabBehaviors.h @@ -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. * diff --git a/src/gui/elems/config/tabMidi.cpp b/src/gui/elems/config/tabMidi.cpp index 3107899..dbe3e6a 100644 --- a/src/gui/elems/config/tabMidi.cpp +++ b/src/gui/elems/config/tabMidi.cpp @@ -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,8 +26,12 @@ #include -#include #include "../../../core/const.h" +#ifdef G_OS_MAC + #include +#else + #include +#endif #include "../../../core/conf.h" #include "../../../core/midiMapConf.h" #include "../../../core/kernelMidi.h" diff --git a/src/gui/elems/config/tabMidi.h b/src/gui/elems/config/tabMidi.h index e2249d8..8f0ee70 100644 --- a/src/gui/elems/config/tabMidi.h +++ b/src/gui/elems/config/tabMidi.h @@ -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. * diff --git a/src/gui/elems/config/tabMisc.cpp b/src/gui/elems/config/tabMisc.cpp index 875e54a..7f1ab07 100644 --- a/src/gui/elems/config/tabMisc.cpp +++ b/src/gui/elems/config/tabMisc.cpp @@ -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. * diff --git a/src/gui/elems/config/tabMisc.h b/src/gui/elems/config/tabMisc.h index 63bb8b0..bf900bf 100644 --- a/src/gui/elems/config/tabMisc.h +++ b/src/gui/elems/config/tabMisc.h @@ -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. * diff --git a/src/gui/elems/config/tabPlugins.cpp b/src/gui/elems/config/tabPlugins.cpp index ee9b77e..96b3acb 100644 --- a/src/gui/elems/config/tabPlugins.cpp +++ b/src/gui/elems/config/tabPlugins.cpp @@ -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. * @@ -28,12 +28,19 @@ #ifdef WITH_VST +#include #include #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(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 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(); } diff --git a/src/gui/elems/config/tabPlugins.h b/src/gui/elems/config/tabPlugins.h index 3bdddc3..cc8ffd9 100644 --- a/src/gui/elems/config/tabPlugins.h +++ b/src/gui/elems/config/tabPlugins.h @@ -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(); }; diff --git a/src/gui/elems/mainWindow/beatMeter.cpp b/src/gui/elems/mainWindow/beatMeter.cpp index 38ac667..d10efed 100644 --- a/src/gui/elems/mainWindow/beatMeter.cpp +++ b/src/gui/elems/mainWindow/beatMeter.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/beatMeter.h b/src/gui/elems/mainWindow/beatMeter.h index c5cdf42..d1e5a11 100644 --- a/src/gui/elems/mainWindow/beatMeter.h +++ b/src/gui/elems/mainWindow/beatMeter.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/channel.cpp b/src/gui/elems/mainWindow/keyboard/channel.cpp index a74eda4..36c7140 100644 --- a/src/gui/elems/mainWindow/keyboard/channel.cpp +++ b/src/gui/elems/mainWindow/keyboard/channel.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/channel.h b/src/gui/elems/mainWindow/keyboard/channel.h index 7314a36..8a3b6bf 100644 --- a/src/gui/elems/mainWindow/keyboard/channel.h +++ b/src/gui/elems/mainWindow/keyboard/channel.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/channelButton.cpp b/src/gui/elems/mainWindow/keyboard/channelButton.cpp index c70371e..a93dee5 100644 --- a/src/gui/elems/mainWindow/keyboard/channelButton.cpp +++ b/src/gui/elems/mainWindow/keyboard/channelButton.cpp @@ -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 #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(k); // FIXME - What about unicode/utf-8? } diff --git a/src/gui/elems/mainWindow/keyboard/channelButton.h b/src/gui/elems/mainWindow/keyboard/channelButton.h index b2cef9e..4a59589 100644 --- a/src/gui/elems/mainWindow/keyboard/channelButton.h +++ b/src/gui/elems/mainWindow/keyboard/channelButton.h @@ -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); diff --git a/src/gui/elems/mainWindow/keyboard/channelMode.cpp b/src/gui/elems/mainWindow/keyboard/channelMode.cpp index 07c6f33..045be52 100644 --- a/src/gui/elems/mainWindow/keyboard/channelMode.cpp +++ b/src/gui/elems/mainWindow/keyboard/channelMode.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/channelMode.h b/src/gui/elems/mainWindow/keyboard/channelMode.h index 2bbdcd0..349474f 100644 --- a/src/gui/elems/mainWindow/keyboard/channelMode.h +++ b/src/gui/elems/mainWindow/keyboard/channelMode.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/channelStatus.cpp b/src/gui/elems/mainWindow/keyboard/channelStatus.cpp index 49accc3..509df92 100644 --- a/src/gui/elems/mainWindow/keyboard/channelStatus.cpp +++ b/src/gui/elems/mainWindow/keyboard/channelStatus.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/channelStatus.h b/src/gui/elems/mainWindow/keyboard/channelStatus.h index 5063c9d..ec12d29 100644 --- a/src/gui/elems/mainWindow/keyboard/channelStatus.h +++ b/src/gui/elems/mainWindow/keyboard/channelStatus.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/column.cpp b/src/gui/elems/mainWindow/keyboard/column.cpp index 18a88bc..70c178c 100644 --- a/src/gui/elems/mainWindow/keyboard/column.cpp +++ b/src/gui/elems/mainWindow/keyboard/column.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/column.h b/src/gui/elems/mainWindow/keyboard/column.h index b6ea1d4..47f31be 100644 --- a/src/gui/elems/mainWindow/keyboard/column.h +++ b/src/gui/elems/mainWindow/keyboard/column.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/keyboard.cpp b/src/gui/elems/mainWindow/keyboard/keyboard.cpp index e5e0f3c..9872c66 100644 --- a/src/gui/elems/mainWindow/keyboard/keyboard.cpp +++ b/src/gui/elems/mainWindow/keyboard/keyboard.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/keyboard.h b/src/gui/elems/mainWindow/keyboard/keyboard.h index 432364e..8446877 100644 --- a/src/gui/elems/mainWindow/keyboard/keyboard.h +++ b/src/gui/elems/mainWindow/keyboard/keyboard.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/midiChannel.cpp b/src/gui/elems/mainWindow/keyboard/midiChannel.cpp index 7c4a113..5f17b2f 100644 --- a/src/gui/elems/mainWindow/keyboard/midiChannel.cpp +++ b/src/gui/elems/mainWindow/keyboard/midiChannel.cpp @@ -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()); diff --git a/src/gui/elems/mainWindow/keyboard/midiChannel.h b/src/gui/elems/mainWindow/keyboard/midiChannel.h index 881c610..b3bfcd4 100644 --- a/src/gui/elems/mainWindow/keyboard/midiChannel.h +++ b/src/gui/elems/mainWindow/keyboard/midiChannel.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp b/src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp index b1ed9b4..0bfdcd0 100644 --- a/src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp +++ b/src/gui/elems/mainWindow/keyboard/midiChannelButton.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/midiChannelButton.h b/src/gui/elems/mainWindow/keyboard/midiChannelButton.h index f1bf9dd..c461ff1 100644 --- a/src/gui/elems/mainWindow/keyboard/midiChannelButton.h +++ b/src/gui/elems/mainWindow/keyboard/midiChannelButton.h @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp b/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp index 26a839c..c96b2eb 100644 --- a/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp +++ b/src/gui/elems/mainWindow/keyboard/sampleChannel.cpp @@ -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(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) diff --git a/src/gui/elems/mainWindow/keyboard/sampleChannel.h b/src/gui/elems/mainWindow/keyboard/sampleChannel.h index 0e070bc..4cb99d0 100644 --- a/src/gui/elems/mainWindow/keyboard/sampleChannel.h +++ b/src/gui/elems/mainWindow/keyboard/sampleChannel.h @@ -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. */ diff --git a/src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp b/src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp index 9e504df..8ec528c 100644 --- a/src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp +++ b/src/gui/elems/mainWindow/keyboard/sampleChannelButton.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/keyboard/sampleChannelButton.h b/src/gui/elems/mainWindow/keyboard/sampleChannelButton.h index eb47071..b814fa8 100644 --- a/src/gui/elems/mainWindow/keyboard/sampleChannelButton.h +++ b/src/gui/elems/mainWindow/keyboard/sampleChannelButton.h @@ -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. * diff --git a/src/gui/elems/mainWindow/mainIO.cpp b/src/gui/elems/mainWindow/mainIO.cpp index 67bc074..e246dd8 100644 --- a/src/gui/elems/mainWindow/mainIO.cpp +++ b/src/gui/elems/mainWindow/mainIO.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/mainIO.h b/src/gui/elems/mainWindow/mainIO.h index e65579c..5debc8e 100644 --- a/src/gui/elems/mainWindow/mainIO.h +++ b/src/gui/elems/mainWindow/mainIO.h @@ -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. * diff --git a/src/gui/elems/mainWindow/mainMenu.cpp b/src/gui/elems/mainWindow/mainMenu.cpp index 2d7269b..572842a 100644 --- a/src/gui/elems/mainWindow/mainMenu.cpp +++ b/src/gui/elems/mainWindow/mainMenu.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/mainMenu.h b/src/gui/elems/mainWindow/mainMenu.h index 879e8f1..c6dde20 100644 --- a/src/gui/elems/mainWindow/mainMenu.h +++ b/src/gui/elems/mainWindow/mainMenu.h @@ -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. * diff --git a/src/gui/elems/mainWindow/mainTimer.cpp b/src/gui/elems/mainWindow/mainTimer.cpp index ac19b4f..7a4bf3f 100644 --- a/src/gui/elems/mainWindow/mainTimer.cpp +++ b/src/gui/elems/mainWindow/mainTimer.cpp @@ -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()); } diff --git a/src/gui/elems/mainWindow/mainTimer.h b/src/gui/elems/mainWindow/mainTimer.h index 3db0151..c3fe661 100644 --- a/src/gui/elems/mainWindow/mainTimer.h +++ b/src/gui/elems/mainWindow/mainTimer.h @@ -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. * diff --git a/src/gui/elems/mainWindow/mainTransport.cpp b/src/gui/elems/mainWindow/mainTransport.cpp index 354fb06..057ce67 100644 --- a/src/gui/elems/mainWindow/mainTransport.cpp +++ b/src/gui/elems/mainWindow/mainTransport.cpp @@ -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. * diff --git a/src/gui/elems/mainWindow/mainTransport.h b/src/gui/elems/mainWindow/mainTransport.h index 26821ef..7461df3 100644 --- a/src/gui/elems/mainWindow/mainTransport.h +++ b/src/gui/elems/mainWindow/mainTransport.h @@ -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. * diff --git a/src/gui/elems/midiLearner.cpp b/src/gui/elems/midiLearner.cpp index 5da78b4..0085d6c 100644 --- a/src/gui/elems/midiLearner.cpp +++ b/src/gui/elems/midiLearner.cpp @@ -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,19 +25,23 @@ * -------------------------------------------------------------------------- */ +#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 char* l, + 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(parent()); // parent = gdMidiInput cbData.learner = this; - kernelMidi::startMidiLearn(callback, (void*)&cbData); + cbData.channel = ch; + midiDispatcher::startMidiLearn(callback, (void*)&cbData); } else - kernelMidi::stopMidiLearn(); + midiDispatcher::stopMidiLearn(); } diff --git a/src/gui/elems/midiLearner.h b/src/gui/elems/midiLearner.h index 9b7e89a..5b226a2 100644 --- a/src/gui/elems/midiLearner.h +++ b/src/gui/elems/midiLearner.h @@ -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,10 +30,11 @@ #include -#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_t* param; - 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 char* l, + giada::m::midiDispatcher::cb_midiLearn* cb, uint32_t* param, Channel* ch); void updateValue(); }; diff --git a/src/gui/elems/plugin/pluginBrowser.cpp b/src/gui/elems/plugin/pluginBrowser.cpp index 11d0882..adfb907 100644 --- a/src/gui/elems/plugin/pluginBrowser.cpp +++ b/src/gui/elems/plugin/pluginBrowser.cpp @@ -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. * diff --git a/src/gui/elems/plugin/pluginBrowser.h b/src/gui/elems/plugin/pluginBrowser.h index 4e2287e..e442af2 100644 --- a/src/gui/elems/plugin/pluginBrowser.h +++ b/src/gui/elems/plugin/pluginBrowser.h @@ -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. * diff --git a/src/gui/elems/plugin/pluginParameter.cpp b/src/gui/elems/plugin/pluginParameter.cpp index 5a6916b..edc804d 100644 --- a/src/gui/elems/plugin/pluginParameter.cpp +++ b/src/gui/elems/plugin/pluginParameter.cpp @@ -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. * diff --git a/src/gui/elems/plugin/pluginParameter.h b/src/gui/elems/plugin/pluginParameter.h index 268b7e6..140ab15 100644 --- a/src/gui/elems/plugin/pluginParameter.h +++ b/src/gui/elems/plugin/pluginParameter.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/boostTool.cpp b/src/gui/elems/sampleEditor/boostTool.cpp index e189525..f633afc 100644 --- a/src/gui/elems/sampleEditor/boostTool.cpp +++ b/src/gui/elems/sampleEditor/boostTool.cpp @@ -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); } diff --git a/src/gui/elems/sampleEditor/boostTool.h b/src/gui/elems/sampleEditor/boostTool.h index f1e7875..d3ce340 100644 --- a/src/gui/elems/sampleEditor/boostTool.h +++ b/src/gui/elems/sampleEditor/boostTool.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/panTool.cpp b/src/gui/elems/sampleEditor/panTool.cpp index 59eb792..9c638d4 100644 --- a/src/gui/elems/sampleEditor/panTool.cpp +++ b/src/gui/elems/sampleEditor/panTool.cpp @@ -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()); } } diff --git a/src/gui/elems/sampleEditor/panTool.h b/src/gui/elems/sampleEditor/panTool.h index c90ca66..e9d0cf6 100644 --- a/src/gui/elems/sampleEditor/panTool.h +++ b/src/gui/elems/sampleEditor/panTool.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/pitchTool.cpp b/src/gui/elems/sampleEditor/pitchTool.cpp index 80e2319..a9b7dfb 100644 --- a/src/gui/elems/sampleEditor/pitchTool.cpp +++ b/src/gui/elems/sampleEditor/pitchTool.cpp @@ -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 } diff --git a/src/gui/elems/sampleEditor/pitchTool.h b/src/gui/elems/sampleEditor/pitchTool.h index fd3f7ae..7ff9562 100644 --- a/src/gui/elems/sampleEditor/pitchTool.h +++ b/src/gui/elems/sampleEditor/pitchTool.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/rangeTool.cpp b/src/gui/elems/sampleEditor/rangeTool.cpp index 2125294..88aa05d 100644 --- a/src/gui/elems/sampleEditor/rangeTool.cpp +++ b/src/gui/elems/sampleEditor/rangeTool.cpp @@ -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()); } diff --git a/src/gui/elems/sampleEditor/rangeTool.h b/src/gui/elems/sampleEditor/rangeTool.h index 0480388..17dcf7f 100644 --- a/src/gui/elems/sampleEditor/rangeTool.h +++ b/src/gui/elems/sampleEditor/rangeTool.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/shiftTool.cpp b/src/gui/elems/sampleEditor/shiftTool.cpp index 83e9afe..bbcf127 100644 --- a/src/gui/elems/sampleEditor/shiftTool.cpp +++ b/src/gui/elems/sampleEditor/shiftTool.cpp @@ -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 #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()); } diff --git a/src/gui/elems/sampleEditor/shiftTool.h b/src/gui/elems/sampleEditor/shiftTool.h index 17aee46..794ddc3 100644 --- a/src/gui/elems/sampleEditor/shiftTool.h +++ b/src/gui/elems/sampleEditor/shiftTool.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/volumeTool.cpp b/src/gui/elems/sampleEditor/volumeTool.cpp index 3cd7048..9fb8b46 100644 --- a/src/gui/elems/sampleEditor/volumeTool.cpp +++ b/src/gui/elems/sampleEditor/volumeTool.cpp @@ -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,12 +26,14 @@ #include +#include #include #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()); } diff --git a/src/gui/elems/sampleEditor/volumeTool.h b/src/gui/elems/sampleEditor/volumeTool.h index e6f98c1..c526511 100644 --- a/src/gui/elems/sampleEditor/volumeTool.h +++ b/src/gui/elems/sampleEditor/volumeTool.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/waveTools.cpp b/src/gui/elems/sampleEditor/waveTools.cpp index 7bfdb18..84a2824 100644 --- a/src/gui/elems/sampleEditor/waveTools.cpp +++ b/src/gui/elems/sampleEditor/waveTools.cpp @@ -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. * diff --git a/src/gui/elems/sampleEditor/waveTools.h b/src/gui/elems/sampleEditor/waveTools.h index 6c891c9..d352d38 100644 --- a/src/gui/elems/sampleEditor/waveTools.h +++ b/src/gui/elems/sampleEditor/waveTools.h @@ -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. * diff --git a/src/gui/elems/sampleEditor/waveform.cpp b/src/gui/elems/sampleEditor/waveform.cpp index dc4c980..806356f 100644 --- a/src/gui/elems/sampleEditor/waveform.cpp +++ b/src/gui/elems/sampleEditor/waveform.cpp @@ -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. * diff --git a/src/gui/elems/sampleEditor/waveform.h b/src/gui/elems/sampleEditor/waveform.h index bfddf6e..05faaea 100644 --- a/src/gui/elems/sampleEditor/waveform.h +++ b/src/gui/elems/sampleEditor/waveform.h @@ -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. * diff --git a/src/gui/elems/soundMeter.cpp b/src/gui/elems/soundMeter.cpp index 29f9aa9..b078fea 100644 --- a/src/gui/elems/soundMeter.cpp +++ b/src/gui/elems/soundMeter.cpp @@ -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. * diff --git a/src/gui/elems/soundMeter.h b/src/gui/elems/soundMeter.h index 0b3768b..649f106 100644 --- a/src/gui/elems/soundMeter.h +++ b/src/gui/elems/soundMeter.h @@ -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. * diff --git a/src/main.cpp b/src/main.cpp index 9e265a4..e168a5f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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. * diff --git a/src/utils/cocoa.h b/src/utils/cocoa.h index 99a6ad1..7e8bb19 100644 --- a/src/utils/cocoa.h +++ b/src/utils/cocoa.h @@ -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. * diff --git a/src/utils/cocoa.mm b/src/utils/cocoa.mm index 6c6f4b5..69519e9 100644 --- a/src/utils/cocoa.mm +++ b/src/utils/cocoa.mm @@ -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. * diff --git a/src/utils/deps.cpp b/src/utils/deps.cpp index a732be8..fc58378 100644 --- a/src/utils/deps.cpp +++ b/src/utils/deps.cpp @@ -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,12 @@ * -------------------------------------------------------------------------- */ -#include +#include "../core/const.h" +#ifdef G_OS_MAC + #include +#else + #include +#endif #include #include "../deps/rtaudio-mod/RtAudio.h" #include "deps.h" diff --git a/src/utils/deps.h b/src/utils/deps.h index ff3f331..e978b3b 100644 --- a/src/utils/deps.h +++ b/src/utils/deps.h @@ -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. * diff --git a/src/utils/fs.cpp b/src/utils/fs.cpp index 53c166a..4cbfba1 100644 --- a/src/utils/fs.cpp +++ b/src/utils/fs.cpp @@ -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. * diff --git a/src/utils/fs.h b/src/utils/fs.h index 3e84fff..27b0d2e 100644 --- a/src/utils/fs.h +++ b/src/utils/fs.h @@ -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. * diff --git a/src/utils/gui.cpp b/src/utils/gui.cpp index 9752b12..8af7901 100644 --- a/src/utils/gui.cpp +++ b/src/utils/gui.cpp @@ -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. * diff --git a/src/utils/gui.h b/src/utils/gui.h index 00a7994..d69ca37 100644 --- a/src/utils/gui.h +++ b/src/utils/gui.h @@ -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. * diff --git a/src/utils/log.cpp b/src/utils/log.cpp index 067d8bd..8cfdf8f 100644 --- a/src/utils/log.cpp +++ b/src/utils/log.cpp @@ -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. * diff --git a/src/utils/log.h b/src/utils/log.h index c7e2afc..5f4e8e6 100644 --- a/src/utils/log.h +++ b/src/utils/log.h @@ -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. * diff --git a/src/utils/math.cpp b/src/utils/math.cpp index e89a21c..402b164 100644 --- a/src/utils/math.cpp +++ b/src/utils/math.cpp @@ -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. * diff --git a/src/utils/math.h b/src/utils/math.h index 890e3bc..668c9f7 100644 --- a/src/utils/math.h +++ b/src/utils/math.h @@ -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. * diff --git a/src/utils/string.cpp b/src/utils/string.cpp index e19c235..fda5839 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -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 +#include #include -#include #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 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* v) { string full = in; diff --git a/src/utils/string.h b/src/utils/string.h index 17b446c..e59937e 100644 --- a/src/utils/string.h +++ b/src/utils/string.h @@ -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. * @@ -33,8 +33,21 @@ #include #include +#include +#include "../core/const.h" +template +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* v); +std::string gu_fToString(float f, int precision); + +std::string gu_format(const char* format, ...); + #endif diff --git a/src/utils/time.cpp b/src/utils/time.cpp index 3318258..ec3faa5 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -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. * diff --git a/src/utils/time.h b/src/utils/time.h index 5ebd453..4afdc47 100644 --- a/src/utils/time.h +++ b/src/utils/time.h @@ -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. * diff --git a/tests/recorder.cpp b/tests/recorder.cpp index eda8ec8..49a988e 100644 --- a/tests/recorder.cpp +++ b/tests/recorder.cpp @@ -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); + } } diff --git a/tests/utils.cpp b/tests/utils.cpp index 852b77a..07fb31c 100644 --- a/tests/utils.cpp +++ b/tests/utils.cpp @@ -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 v; gu_split("Giada is cool", " ", &v); -- 2.30.2